aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/.gitignore1
-rw-r--r--tools/perf/Documentation/Makefile19
-rw-r--r--tools/perf/Documentation/perf-annotate.txt46
-rw-r--r--tools/perf/Documentation/perf-buildid-list.txt3
-rw-r--r--tools/perf/Documentation/perf-diff.txt21
-rw-r--r--tools/perf/Documentation/perf-evlist.txt26
-rw-r--r--tools/perf/Documentation/perf-kvm.txt8
-rw-r--r--tools/perf/Documentation/perf-list.txt40
-rw-r--r--tools/perf/Documentation/perf-lock.txt23
-rw-r--r--tools/perf/Documentation/perf-probe.txt44
-rw-r--r--tools/perf/Documentation/perf-record.txt40
-rw-r--r--tools/perf/Documentation/perf-report.txt62
-rw-r--r--tools/perf/Documentation/perf-sched.txt18
-rw-r--r--tools/perf/Documentation/perf-script-perl.txt (renamed from tools/perf/Documentation/perf-trace-perl.txt)29
-rw-r--r--tools/perf/Documentation/perf-script-python.txt (renamed from tools/perf/Documentation/perf-trace-python.txt)89
-rw-r--r--tools/perf/Documentation/perf-script.txt188
-rw-r--r--tools/perf/Documentation/perf-stat.txt55
-rw-r--r--tools/perf/Documentation/perf-test.txt2
-rw-r--r--tools/perf/Documentation/perf-timechart.txt2
-rw-r--r--tools/perf/Documentation/perf-top.txt28
-rw-r--r--tools/perf/Documentation/perf-trace.txt70
-rw-r--r--tools/perf/MANIFEST1
-rw-r--r--tools/perf/Makefile793
-rw-r--r--tools/perf/arch/s390/Makefile4
-rw-r--r--tools/perf/arch/s390/util/dwarf-regs.c22
-rw-r--r--tools/perf/bench/mem-memcpy-arch.h12
-rw-r--r--tools/perf/bench/mem-memcpy-x86-64-asm-def.h4
-rw-r--r--tools/perf/bench/mem-memcpy-x86-64-asm.S2
-rw-r--r--tools/perf/bench/mem-memcpy.c219
-rw-r--r--tools/perf/bench/sched-pipe.c2
-rw-r--r--tools/perf/builtin-annotate.c373
-rw-r--r--tools/perf/builtin-buildid-list.c6
-rw-r--r--tools/perf/builtin-diff.c32
-rw-r--r--tools/perf/builtin-evlist.c54
-rw-r--r--tools/perf/builtin-inject.c90
-rw-r--r--tools/perf/builtin-kmem.c40
-rw-r--r--tools/perf/builtin-list.c43
-rw-r--r--tools/perf/builtin-lock.c50
-rw-r--r--tools/perf/builtin-probe.c153
-rw-r--r--tools/perf/builtin-record.c588
-rw-r--r--tools/perf/builtin-report.c260
-rw-r--r--tools/perf/builtin-sched.c100
-rw-r--r--tools/perf/builtin-script.c1230
-rw-r--r--tools/perf/builtin-stat.c1075
-rw-r--r--tools/perf/builtin-test.c415
-rw-r--r--tools/perf/builtin-timechart.c152
-rw-r--r--tools/perf/builtin-top.c1125
-rw-r--r--tools/perf/builtin-trace.c734
-rw-r--r--tools/perf/builtin.h3
-rw-r--r--tools/perf/command-list.txt3
-rw-r--r--tools/perf/config/feature-tests.mak (renamed from tools/perf/feature-tests.mak)29
-rw-r--r--tools/perf/config/utilities.mak188
-rw-r--r--tools/perf/perf.c3
-rw-r--r--tools/perf/perf.h26
-rwxr-xr-xtools/perf/python/twatch.py41
-rw-r--r--tools/perf/scripts/perl/Perf-Trace-Util/Context.c2
-rw-r--r--tools/perf/scripts/perl/Perf-Trace-Util/Context.xs4
-rw-r--r--tools/perf/scripts/perl/Perf-Trace-Util/README4
-rw-r--r--tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Context.pm2
-rw-r--r--tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Core.pm4
-rw-r--r--tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Util.pm4
-rw-r--r--tools/perf/scripts/perl/bin/failed-syscalls-record2
-rw-r--r--tools/perf/scripts/perl/bin/failed-syscalls-report2
-rw-r--r--tools/perf/scripts/perl/bin/rw-by-file-record2
-rw-r--r--tools/perf/scripts/perl/bin/rw-by-file-report5
-rw-r--r--tools/perf/scripts/perl/bin/rw-by-pid-record2
-rw-r--r--tools/perf/scripts/perl/bin/rw-by-pid-report5
-rw-r--r--tools/perf/scripts/perl/bin/rwtop-record2
-rw-r--r--tools/perf/scripts/perl/bin/rwtop-report5
-rw-r--r--tools/perf/scripts/perl/bin/wakeup-latency-record2
-rw-r--r--tools/perf/scripts/perl/bin/wakeup-latency-report5
-rw-r--r--tools/perf/scripts/perl/bin/workqueue-stats-record2
-rw-r--r--tools/perf/scripts/perl/bin/workqueue-stats-report6
-rw-r--r--tools/perf/scripts/perl/check-perf-trace.pl2
-rw-r--r--tools/perf/scripts/perl/rw-by-file.pl2
-rw-r--r--tools/perf/scripts/perl/workqueue-stats.pl2
-rw-r--r--tools/perf/scripts/python/Perf-Trace-Util/Context.c2
-rw-r--r--tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py2
-rw-r--r--tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/SchedGui.py2
-rw-r--r--tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py60
-rw-r--r--tools/perf/scripts/python/bin/failed-syscalls-by-pid-record2
-rw-r--r--tools/perf/scripts/python/bin/failed-syscalls-by-pid-report2
-rw-r--r--tools/perf/scripts/python/bin/futex-contention-record2
-rw-r--r--tools/perf/scripts/python/bin/futex-contention-report4
-rw-r--r--tools/perf/scripts/python/bin/netdev-times-record8
-rw-r--r--tools/perf/scripts/python/bin/netdev-times-report5
-rw-r--r--tools/perf/scripts/python/bin/sched-migration-record2
-rw-r--r--tools/perf/scripts/python/bin/sched-migration-report2
-rw-r--r--tools/perf/scripts/python/bin/sctop-record2
-rw-r--r--tools/perf/scripts/python/bin/sctop-report2
-rw-r--r--tools/perf/scripts/python/bin/syscall-counts-by-pid-record2
-rw-r--r--tools/perf/scripts/python/bin/syscall-counts-by-pid-report2
-rw-r--r--tools/perf/scripts/python/bin/syscall-counts-record2
-rw-r--r--tools/perf/scripts/python/bin/syscall-counts-report2
-rw-r--r--tools/perf/scripts/python/check-perf-trace.py2
-rw-r--r--tools/perf/scripts/python/failed-syscalls-by-pid.py21
-rw-r--r--tools/perf/scripts/python/futex-contention.py50
-rw-r--r--tools/perf/scripts/python/netdev-times.py464
-rw-r--r--tools/perf/scripts/python/sched-migration.py2
-rw-r--r--tools/perf/scripts/python/sctop.py9
-rw-r--r--tools/perf/scripts/python/syscall-counts-by-pid.py23
-rw-r--r--tools/perf/scripts/python/syscall-counts.py7
-rwxr-xr-xtools/perf/util/PERF-VERSION-GEN7
-rw-r--r--tools/perf/util/annotate.c605
-rw-r--r--tools/perf/util/annotate.h103
-rw-r--r--tools/perf/util/build-id.c21
-rw-r--r--tools/perf/util/cache.h9
-rw-r--r--tools/perf/util/callchain.c233
-rw-r--r--tools/perf/util/callchain.h95
-rw-r--r--tools/perf/util/cgroup.c178
-rw-r--r--tools/perf/util/cgroup.h17
-rw-r--r--tools/perf/util/cpumap.c128
-rw-r--r--tools/perf/util/cpumap.h10
-rw-r--r--tools/perf/util/debug.c56
-rw-r--r--tools/perf/util/debug.h7
-rw-r--r--tools/perf/util/event.c596
-rw-r--r--tools/perf/util/event.h82
-rw-r--r--tools/perf/util/evlist.c500
-rw-r--r--tools/perf/util/evlist.h74
-rw-r--r--tools/perf/util/evsel.c440
-rw-r--r--tools/perf/util/evsel.h159
-rw-r--r--tools/perf/util/exec_cmd.c19
-rw-r--r--tools/perf/util/header.c615
-rw-r--r--tools/perf/util/header.h92
-rw-r--r--tools/perf/util/hist.c259
-rw-r--r--tools/perf/util/hist.h63
-rw-r--r--tools/perf/util/include/asm/alternative-asm.h8
-rw-r--r--tools/perf/util/include/asm/cpufeature.h9
-rw-r--r--tools/perf/util/include/asm/dwarf2.h11
-rw-r--r--tools/perf/util/include/linux/bitops.h6
-rw-r--r--tools/perf/util/include/linux/const.h1
-rw-r--r--tools/perf/util/include/linux/linkage.h13
-rw-r--r--tools/perf/util/include/linux/list.h5
-rw-r--r--tools/perf/util/map.c3
-rw-r--r--tools/perf/util/map.h10
-rw-r--r--tools/perf/util/parse-events.c388
-rw-r--r--tools/perf/util/parse-events.h22
-rw-r--r--tools/perf/util/parse-options.h4
-rw-r--r--tools/perf/util/path.c3
-rw-r--r--tools/perf/util/probe-event.c524
-rw-r--r--tools/perf/util/probe-event.h18
-rw-r--r--tools/perf/util/probe-finder.c1453
-rw-r--r--tools/perf/util/probe-finder.h37
-rw-r--r--tools/perf/util/python.c905
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c18
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c19
-rw-r--r--tools/perf/util/session.c905
-rw-r--r--tools/perf/util/session.h75
-rw-r--r--tools/perf/util/setup.py24
-rw-r--r--tools/perf/util/sort.c6
-rw-r--r--tools/perf/util/sort.h2
-rw-r--r--tools/perf/util/strfilter.c199
-rw-r--r--tools/perf/util/strfilter.h48
-rw-r--r--tools/perf/util/string.c4
-rw-r--r--tools/perf/util/svghelper.c15
-rw-r--r--tools/perf/util/symbol.c946
-rw-r--r--tools/perf/util/symbol.h118
-rw-r--r--tools/perf/util/thread.c40
-rw-r--r--tools/perf/util/thread.h1
-rw-r--r--tools/perf/util/thread_map.c64
-rw-r--r--tools/perf/util/thread_map.h15
-rw-r--r--tools/perf/util/top.c238
-rw-r--r--tools/perf/util/top.h64
-rw-r--r--tools/perf/util/trace-event-info.c30
-rw-r--r--tools/perf/util/trace-event-parse.c112
-rw-r--r--tools/perf/util/trace-event-scripting.c10
-rw-r--r--tools/perf/util/trace-event.h16
-rw-r--r--tools/perf/util/types.h10
-rw-r--r--tools/perf/util/ui/browser.c137
-rw-r--r--tools/perf/util/ui/browser.h12
-rw-r--r--tools/perf/util/ui/browsers/annotate.c195
-rw-r--r--tools/perf/util/ui/browsers/hists.c502
-rw-r--r--tools/perf/util/ui/browsers/map.c39
-rw-r--r--tools/perf/util/ui/browsers/top.c213
-rw-r--r--tools/perf/util/ui/helpline.c5
-rw-r--r--tools/perf/util/ui/libslang.h6
-rw-r--r--tools/perf/util/ui/setup.c8
-rw-r--r--tools/perf/util/ui/ui.h8
-rw-r--r--tools/perf/util/ui/util.c26
-rw-r--r--tools/perf/util/util.c17
-rw-r--r--tools/perf/util/util.h40
-rw-r--r--tools/perf/util/values.c10
-rw-r--r--tools/perf/util/xyarray.c20
-rw-r--r--tools/perf/util/xyarray.h20
-rw-r--r--tools/power/x86/turbostat/Makefile8
-rw-r--r--tools/power/x86/turbostat/turbostat.8172
-rw-r--r--tools/power/x86/turbostat/turbostat.c1044
-rw-r--r--tools/power/x86/x86_energy_perf_policy/Makefile8
-rw-r--r--tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.8104
-rw-r--r--tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c325
-rw-r--r--tools/slub/slabinfo.c1364
-rwxr-xr-xtools/testing/ktest/compare-ktest-sample.pl30
-rwxr-xr-xtools/testing/ktest/ktest.pl2264
-rw-r--r--tools/testing/ktest/sample.conf757
-rw-r--r--tools/usb/Makefile13
-rw-r--r--tools/usb/ffs-test.c4
-rw-r--r--tools/usb/hcd-tests.sh275
-rw-r--r--tools/virtio/Makefile12
-rw-r--r--tools/virtio/linux/device.h2
-rw-r--r--tools/virtio/linux/slab.h2
-rw-r--r--tools/virtio/linux/virtio.h223
-rw-r--r--tools/virtio/vhost_test/Makefile2
-rw-r--r--tools/virtio/vhost_test/vhost_test.c1
-rw-r--r--tools/virtio/virtio_test.c263
204 files changed, 21624 insertions, 6709 deletions
diff --git a/tools/perf/.gitignore b/tools/perf/.gitignore
index cb43289e447f..416684be0ad3 100644
--- a/tools/perf/.gitignore
+++ b/tools/perf/.gitignore
@@ -1,4 +1,3 @@
1PERF-BUILD-OPTIONS
2PERF-CFLAGS 1PERF-CFLAGS
3PERF-GUI-VARS 2PERF-GUI-VARS
4PERF-VERSION-FILE 3PERF-VERSION-FILE
diff --git a/tools/perf/Documentation/Makefile b/tools/perf/Documentation/Makefile
index bd498d496952..4626a398836a 100644
--- a/tools/perf/Documentation/Makefile
+++ b/tools/perf/Documentation/Makefile
@@ -178,8 +178,8 @@ install-pdf: pdf
178 $(INSTALL) -d -m 755 $(DESTDIR)$(pdfdir) 178 $(INSTALL) -d -m 755 $(DESTDIR)$(pdfdir)
179 $(INSTALL) -m 644 user-manual.pdf $(DESTDIR)$(pdfdir) 179 $(INSTALL) -m 644 user-manual.pdf $(DESTDIR)$(pdfdir)
180 180
181install-html: html 181#install-html: html
182 '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(DESTDIR)$(htmldir) 182# '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(DESTDIR)$(htmldir)
183 183
184../PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE 184../PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
185 $(QUIET_SUBDIR0)../ $(QUIET_SUBDIR1) PERF-VERSION-FILE 185 $(QUIET_SUBDIR0)../ $(QUIET_SUBDIR1) PERF-VERSION-FILE
@@ -288,15 +288,16 @@ $(patsubst %.txt,%.html,$(wildcard howto/*.txt)): %.html : %.txt
288 sed -e '1,/^$$/d' $< | $(ASCIIDOC) -b xhtml11 - >$@+ && \ 288 sed -e '1,/^$$/d' $< | $(ASCIIDOC) -b xhtml11 - >$@+ && \
289 mv $@+ $@ 289 mv $@+ $@
290 290
291install-webdoc : html 291# UNIMPLEMENTED
292 '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(WEBDOC_DEST) 292#install-webdoc : html
293# '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(WEBDOC_DEST)
293 294
294quick-install: quick-install-man 295# quick-install: quick-install-man
295 296
296quick-install-man: 297# quick-install-man:
297 '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(DOC_REF) $(DESTDIR)$(mandir) 298# '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(DOC_REF) $(DESTDIR)$(mandir)
298 299
299quick-install-html: 300#quick-install-html:
300 '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(HTML_REF) $(DESTDIR)$(htmldir) 301# '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(HTML_REF) $(DESTDIR)$(htmldir)
301 302
302.PHONY: .FORCE-PERF-VERSION-FILE 303.PHONY: .FORCE-PERF-VERSION-FILE
diff --git a/tools/perf/Documentation/perf-annotate.txt b/tools/perf/Documentation/perf-annotate.txt
index 5164a655c39f..6f5a498608b2 100644
--- a/tools/perf/Documentation/perf-annotate.txt
+++ b/tools/perf/Documentation/perf-annotate.txt
@@ -8,7 +8,7 @@ perf-annotate - Read perf.data (created by perf record) and display annotated co
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf annotate' [-i <file> | --input=file] symbol_name 11'perf annotate' [-i <file> | --input=file] [symbol_name]
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
@@ -24,6 +24,48 @@ OPTIONS
24--input=:: 24--input=::
25 Input file name. (default: perf.data) 25 Input file name. (default: perf.data)
26 26
27-d::
28--dsos=<dso[,dso...]>::
29 Only consider symbols in these dsos.
30-s::
31--symbol=<symbol>::
32 Symbol to annotate.
33
34-f::
35--force::
36 Don't complain, do it.
37
38-v::
39--verbose::
40 Be more verbose. (Show symbol address, etc)
41
42-D::
43--dump-raw-trace::
44 Dump raw trace in ASCII.
45
46-k::
47--vmlinux=<file>::
48 vmlinux pathname.
49
50-m::
51--modules::
52 Load module symbols. WARNING: use only with -k and LIVE kernel.
53
54-l::
55--print-line::
56 Print matching source lines (may be slow).
57
58-P::
59--full-paths::
60 Don't shorten the displayed pathnames.
61
62--stdio:: Use the stdio interface.
63
64--tui:: Use the TUI interface Use of --tui requires a tty, if one is not
65 present, as when piping to other commands, the stdio interface is
66 used. This interfaces starts by centering on the line with more
67 samples, TAB/UNTAB cycles through the lines with more samples.
68
27SEE ALSO 69SEE ALSO
28-------- 70--------
29linkperf:perf-record[1] 71linkperf:perf-record[1], linkperf:perf-report[1]
diff --git a/tools/perf/Documentation/perf-buildid-list.txt b/tools/perf/Documentation/perf-buildid-list.txt
index 01b642c0bf8f..5eaac6f26d51 100644
--- a/tools/perf/Documentation/perf-buildid-list.txt
+++ b/tools/perf/Documentation/perf-buildid-list.txt
@@ -18,6 +18,9 @@ perf report.
18 18
19OPTIONS 19OPTIONS
20------- 20-------
21-H::
22--with-hits::
23 Show only DSOs with hits.
21-i:: 24-i::
22--input=:: 25--input=::
23 Input file name. (default: perf.data) 26 Input file name. (default: perf.data)
diff --git a/tools/perf/Documentation/perf-diff.txt b/tools/perf/Documentation/perf-diff.txt
index 20d97d84ea1c..74d7481ed7a6 100644
--- a/tools/perf/Documentation/perf-diff.txt
+++ b/tools/perf/Documentation/perf-diff.txt
@@ -19,6 +19,18 @@ If no parameters are passed it will assume perf.data.old and perf.data.
19 19
20OPTIONS 20OPTIONS
21------- 21-------
22-M::
23--displacement::
24 Show position displacement relative to baseline.
25
26-D::
27--dump-raw-trace::
28 Dump raw trace in ASCII.
29
30-m::
31--modules::
32 Load module symbols. WARNING: use only with -k and LIVE kernel
33
22-d:: 34-d::
23--dsos=:: 35--dsos=::
24 Only consider symbols in these dsos. CSV that understands 36 Only consider symbols in these dsos. CSV that understands
@@ -42,7 +54,7 @@ OPTIONS
42--field-separator=:: 54--field-separator=::
43 55
44 Use a special separator character and don't pad with spaces, replacing 56 Use a special separator character and don't pad with spaces, replacing
45 all occurances of this separator in symbol names (and other output) 57 all occurrences of this separator in symbol names (and other output)
46 with a '.' character, that thus it's the only non valid separator. 58 with a '.' character, that thus it's the only non valid separator.
47 59
48-v:: 60-v::
@@ -50,6 +62,13 @@ OPTIONS
50 Be verbose, for instance, show the raw counts in addition to the 62 Be verbose, for instance, show the raw counts in addition to the
51 diff. 63 diff.
52 64
65-f::
66--force::
67 Don't complain, do it.
68
69--symfs=<directory>::
70 Look for files with symbols relative to this directory.
71
53SEE ALSO 72SEE ALSO
54-------- 73--------
55linkperf:perf-record[1] 74linkperf:perf-record[1]
diff --git a/tools/perf/Documentation/perf-evlist.txt b/tools/perf/Documentation/perf-evlist.txt
new file mode 100644
index 000000000000..0cada9e053dc
--- /dev/null
+++ b/tools/perf/Documentation/perf-evlist.txt
@@ -0,0 +1,26 @@
1perf-evlist(1)
2==============
3
4NAME
5----
6perf-evlist - List the event names in a perf.data file
7
8SYNOPSIS
9--------
10[verse]
11'perf evlist <options>'
12
13DESCRIPTION
14-----------
15This command displays the names of events sampled in a perf.data file.
16
17OPTIONS
18-------
19-i::
20--input=::
21 Input file name. (default: perf.data)
22
23SEE ALSO
24--------
25linkperf:perf-record[1], linkperf:perf-list[1],
26linkperf:perf-report[1]
diff --git a/tools/perf/Documentation/perf-kvm.txt b/tools/perf/Documentation/perf-kvm.txt
index d004e19fe6d6..dd84cb2f0a88 100644
--- a/tools/perf/Documentation/perf-kvm.txt
+++ b/tools/perf/Documentation/perf-kvm.txt
@@ -22,7 +22,7 @@ There are a couple of variants of perf kvm:
22 a performance counter profile of guest os in realtime 22 a performance counter profile of guest os in realtime
23 of an arbitrary workload. 23 of an arbitrary workload.
24 24
25 'perf kvm record <command>' to record the performance couinter profile 25 'perf kvm record <command>' to record the performance counter profile
26 of an arbitrary workload and save it into a perf data file. If both 26 of an arbitrary workload and save it into a perf data file. If both
27 --host and --guest are input, the perf data file name is perf.data.kvm. 27 --host and --guest are input, the perf data file name is perf.data.kvm.
28 If there is no --host but --guest, the file name is perf.data.guest. 28 If there is no --host but --guest, the file name is perf.data.guest.
@@ -40,6 +40,12 @@ There are a couple of variants of perf kvm:
40 40
41OPTIONS 41OPTIONS
42------- 42-------
43-i::
44--input=::
45 Input file name.
46-o::
47--output::
48 Output file name.
43--host=:: 49--host=::
44 Collect host side performance profile. 50 Collect host side performance profile.
45--guest=:: 51--guest=::
diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt
index 43e3dd284b90..7a527f7e9da9 100644
--- a/tools/perf/Documentation/perf-list.txt
+++ b/tools/perf/Documentation/perf-list.txt
@@ -8,13 +8,30 @@ perf-list - List all symbolic event types
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf list' 11'perf list' [hw|sw|cache|tracepoint|event_glob]
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
15This command displays the symbolic event types which can be selected in the 15This command displays the symbolic event types which can be selected in the
16various perf commands with the -e option. 16various perf commands with the -e option.
17 17
18EVENT MODIFIERS
19---------------
20
21Events can optionally have a modifer by appending a colon and one or
22more modifiers. Modifiers allow the user to restrict when events are
23counted with 'u' for user-space, 'k' for kernel, 'h' for hypervisor.
24
25The 'p' modifier can be used for specifying how precise the instruction
26address should be. The 'p' modifier is currently only implemented for
27Intel PEBS and can be specified multiple times:
28 0 - SAMPLE_IP can have arbitrary skid
29 1 - SAMPLE_IP must have constant skid
30 2 - SAMPLE_IP requested to have 0 skid
31 3 - SAMPLE_IP must have 0 skid
32
33The PEBS implementation now supports up to 2.
34
18RAW HARDWARE EVENT DESCRIPTOR 35RAW HARDWARE EVENT DESCRIPTOR
19----------------------------- 36-----------------------------
20Even when an event is not available in a symbolic form within perf right now, 37Even when an event is not available in a symbolic form within perf right now,
@@ -46,7 +63,26 @@ details. Some of them are referenced in the SEE ALSO section below.
46 63
47OPTIONS 64OPTIONS
48------- 65-------
49None 66
67Without options all known events will be listed.
68
69To limit the list use:
70
71. 'hw' or 'hardware' to list hardware events such as cache-misses, etc.
72
73. 'sw' or 'software' to list software events such as context switches, etc.
74
75. 'cache' or 'hwcache' to list hardware cache events such as L1-dcache-loads, etc.
76
77. 'tracepoint' to list all tracepoint events, alternatively use
78 'subsys_glob:event_glob' to filter by tracepoint subsystems such as sched,
79 block, etc.
80
81. If none of the above is matched, it will apply the supplied glob to all
82 events, printing the ones that match.
83
84One or more types can be used at the same time, listing the events for the
85types specified.
50 86
51SEE ALSO 87SEE ALSO
52-------- 88--------
diff --git a/tools/perf/Documentation/perf-lock.txt b/tools/perf/Documentation/perf-lock.txt
index b317102138c8..4a26a2f3a6a3 100644
--- a/tools/perf/Documentation/perf-lock.txt
+++ b/tools/perf/Documentation/perf-lock.txt
@@ -24,6 +24,29 @@ and statistics with this 'perf lock' command.
24 24
25 'perf lock report' reports statistical data. 25 'perf lock report' reports statistical data.
26 26
27COMMON OPTIONS
28--------------
29
30-i::
31--input=<file>::
32 Input file name.
33
34-v::
35--verbose::
36 Be more verbose (show symbol address, etc).
37
38-D::
39--dump-raw-trace::
40 Dump raw trace in ASCII.
41
42REPORT OPTIONS
43--------------
44
45-k::
46--key=<value>::
47 Sorting key. Possible values: acquired (default), contended,
48 wait_total, wait_max, wait_min.
49
27SEE ALSO 50SEE ALSO
28-------- 51--------
29linkperf:perf[1] 52linkperf:perf[1]
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 27d52dae5a43..02bafce4b341 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -16,7 +16,9 @@ or
16or 16or
17'perf probe' --list 17'perf probe' --list
18or 18or
19'perf probe' --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]' 19'perf probe' [options] --line='LINE'
20or
21'perf probe' [options] --vars='PROBEPOINT'
20 22
21DESCRIPTION 23DESCRIPTION
22----------- 24-----------
@@ -31,6 +33,11 @@ OPTIONS
31--vmlinux=PATH:: 33--vmlinux=PATH::
32 Specify vmlinux path which has debuginfo (Dwarf binary). 34 Specify vmlinux path which has debuginfo (Dwarf binary).
33 35
36-m::
37--module=MODNAME::
38 Specify module name in which perf-probe searches probe points
39 or lines.
40
34-s:: 41-s::
35--source=PATH:: 42--source=PATH::
36 Specify path to kernel source. 43 Specify path to kernel source.
@@ -57,6 +64,26 @@ OPTIONS
57 Show source code lines which can be probed. This needs an argument 64 Show source code lines which can be probed. This needs an argument
58 which specifies a range of the source code. (see LINE SYNTAX for detail) 65 which specifies a range of the source code. (see LINE SYNTAX for detail)
59 66
67-V::
68--vars=::
69 Show available local variables at given probe point. The argument
70 syntax is same as PROBE SYNTAX, but NO ARGs.
71
72--externs::
73 (Only for --vars) Show external defined variables in addition to local
74 variables.
75
76-F::
77--funcs::
78 Show available functions in given module or kernel.
79
80--filter=FILTER::
81 (Only for --vars and --funcs) Set filter. FILTER is a combination of glob
82 pattern, see FILTER PATTERN for detail.
83 Default FILTER is "!__k???tab_* & !__crc_*" for --vars, and "!_*"
84 for --funcs.
85 If several filters are specified, only the last filter is used.
86
60-f:: 87-f::
61--force:: 88--force::
62 Forcibly add events with existing name. 89 Forcibly add events with existing name.
@@ -99,15 +126,16 @@ Each probe argument follows below syntax.
99 126
100LINE SYNTAX 127LINE SYNTAX
101----------- 128-----------
102Line range is descripted by following syntax. 129Line range is described by following syntax.
103 130
104 "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]" 131 "FUNC[@SRC][:RLN[+NUM|-RLN2]]|SRC[:ALN[+NUM|-ALN2]]"
105 132
106FUNC specifies the function name of showing lines. 'RLN' is the start line 133FUNC specifies the function name of showing lines. 'RLN' is the start line
107number from function entry line, and 'RLN2' is the end line number. As same as 134number from function entry line, and 'RLN2' is the end line number. As same as
108probe syntax, 'SRC' means the source file path, 'ALN' is start line number, 135probe syntax, 'SRC' means the source file path, 'ALN' is start line number,
109and 'ALN2' is end line number in the file. It is also possible to specify how 136and 'ALN2' is end line number in the file. It is also possible to specify how
110many lines to show by using 'NUM'. 137many lines to show by using 'NUM'. Moreover, 'FUNC@SRC' combination is good
138for searching a specific function when several functions share same name.
111So, "source.c:100-120" shows lines between 100th to l20th in source.c file. And "func:10+20" shows 20 lines from 10th line of func function. 139So, "source.c:100-120" shows lines between 100th to l20th in source.c file. And "func:10+20" shows 20 lines from 10th line of func function.
112 140
113LAZY MATCHING 141LAZY MATCHING
@@ -119,6 +147,14 @@ e.g.
119 147
120This provides some sort of flexibility and robustness to probe point definitions against minor code changes. For example, actual 10th line of schedule() can be moved easily by modifying schedule(), but the same line matching 'rq=cpu_rq*' may still exist in the function.) 148This provides some sort of flexibility and robustness to probe point definitions against minor code changes. For example, actual 10th line of schedule() can be moved easily by modifying schedule(), but the same line matching 'rq=cpu_rq*' may still exist in the function.)
121 149
150FILTER PATTERN
151--------------
152 The filter pattern is a glob matching pattern(s) to filter variables.
153 In addition, you can use "!" for specifying filter-out rule. You also can give several rules combined with "&" or "|", and fold those rules as one rule by using "(" ")".
154
155e.g.
156 With --filter "foo* | bar*", perf probe -V shows variables which start with "foo" or "bar".
157 With --filter "!foo* & *bar", perf probe -V shows variables which don't start with "foo" and end with "bar", like "fizzbar". But "foobar" is filtered out.
122 158
123EXAMPLES 159EXAMPLES
124-------- 160--------
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index 3ee27dccfde9..5a520f825295 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -39,19 +39,31 @@ OPTIONS
39 be passed as follows: '\mem:addr[:[r][w][x]]'. 39 be passed as follows: '\mem:addr[:[r][w][x]]'.
40 If you want to profile read-write accesses in 0x1000, just set 40 If you want to profile read-write accesses in 0x1000, just set
41 'mem:0x1000:rw'. 41 'mem:0x1000:rw'.
42
43--filter=<filter>::
44 Event filter.
45
42-a:: 46-a::
43 System-wide collection. 47--all-cpus::
48 System-wide collection from all CPUs.
44 49
45-l:: 50-l::
46 Scale counter values. 51 Scale counter values.
47 52
48-p:: 53-p::
49--pid=:: 54--pid=::
50 Record events on existing pid. 55 Record events on existing process ID.
56
57-t::
58--tid=::
59 Record events on existing thread ID.
51 60
52-r:: 61-r::
53--realtime=:: 62--realtime=::
54 Collect data with this RT SCHED_FIFO priority. 63 Collect data with this RT SCHED_FIFO priority.
64-D::
65--no-delay::
66 Collect data without buffering.
55-A:: 67-A::
56--append:: 68--append::
57 Append to the output file to do incremental profiling. 69 Append to the output file to do incremental profiling.
@@ -83,6 +95,10 @@ OPTIONS
83--call-graph:: 95--call-graph::
84 Do call-graph (stack chain/backtrace) recording. 96 Do call-graph (stack chain/backtrace) recording.
85 97
98-q::
99--quiet::
100 Don't print any message, useful for scripting.
101
86-v:: 102-v::
87--verbose:: 103--verbose::
88 Be more verbose (show counter open errors, etc). 104 Be more verbose (show counter open errors, etc).
@@ -95,6 +111,11 @@ OPTIONS
95--data:: 111--data::
96 Sample addresses. 112 Sample addresses.
97 113
114-T::
115--timestamp::
116 Sample timestamps. Use it with 'perf report -D' to see the timestamps,
117 for instance.
118
98-n:: 119-n::
99--no-samples:: 120--no-samples::
100 Don't sample. 121 Don't sample.
@@ -105,8 +126,8 @@ Collect raw sample records from all opened counters (default for tracepoint coun
105 126
106-C:: 127-C::
107--cpu:: 128--cpu::
108Collect samples only on the list of cpus provided. Multiple CPUs can be provided as a 129Collect samples only on the list of CPUs provided. Multiple CPUs can be provided as a
109comma-sperated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2. 130comma-separated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2.
110In per-thread mode with inheritance mode on (default), samples are captured only when 131In per-thread mode with inheritance mode on (default), samples are captured only when
111the thread executes on the designated CPUs. Default is to monitor all CPUs. 132the thread executes on the designated CPUs. Default is to monitor all CPUs.
112 133
@@ -116,6 +137,17 @@ Do not update the builid cache. This saves some overhead in situations
116where the information in the perf.data file (which includes buildids) 137where the information in the perf.data file (which includes buildids)
117is sufficient. 138is sufficient.
118 139
140-G name,...::
141--cgroup name,...::
142monitor only in the container (cgroup) called "name". This option is available only
143in per-cpu mode. The cgroup filesystem must be mounted. All threads belonging to
144container "name" are monitored when they run on the monitored CPUs. Multiple cgroups
145can be provided. Each cgroup is applied to the corresponding event, i.e., first cgroup
146to first event, second cgroup to second event and so on. It is possible to provide
147an empty cgroup (monitor all the time) using, e.g., -G foo,,bar. Cgroups must have
148corresponding events, i.e., they always refer to events defined earlier on the command
149line.
150
119SEE ALSO 151SEE ALSO
120-------- 152--------
121linkperf:perf-stat[1], linkperf:perf-list[1] 153linkperf:perf-stat[1], linkperf:perf-list[1]
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index abfabe9147a4..8ba03d6e5398 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -20,6 +20,11 @@ OPTIONS
20-i:: 20-i::
21--input=:: 21--input=::
22 Input file name. (default: perf.data) 22 Input file name. (default: perf.data)
23
24-v::
25--verbose::
26 Be more verbose. (show symbol address, etc)
27
23-d:: 28-d::
24--dsos=:: 29--dsos=::
25 Only consider symbols in these dsos. CSV that understands 30 Only consider symbols in these dsos. CSV that understands
@@ -27,6 +32,10 @@ OPTIONS
27-n:: 32-n::
28--show-nr-samples:: 33--show-nr-samples::
29 Show the number of samples for each symbol 34 Show the number of samples for each symbol
35
36--showcpuutilization::
37 Show sample percentage for different cpu modes.
38
30-T:: 39-T::
31--threads:: 40--threads::
32 Show per-thread event counters 41 Show per-thread event counters
@@ -39,12 +48,24 @@ OPTIONS
39 Only consider these symbols. CSV that understands 48 Only consider these symbols. CSV that understands
40 file://filename entries. 49 file://filename entries.
41 50
51-U::
52--hide-unresolved::
53 Only display entries resolved to a symbol.
54
42-s:: 55-s::
43--sort=:: 56--sort=::
44 Sort by key(s): pid, comm, dso, symbol, parent. 57 Sort by key(s): pid, comm, dso, symbol, parent.
45 58
59-p::
60--parent=<regex>::
61 regex filter to identify parent, see: '--sort parent'
62
63-x::
64--exclude-other::
65 Only display entries with parent-match.
66
46-w:: 67-w::
47--field-width=:: 68--column-widths=<width[,width...]>::
48 Force each column width to the provided list, for large terminal 69 Force each column width to the provided list, for large terminal
49 readability. 70 readability.
50 71
@@ -52,19 +73,52 @@ OPTIONS
52--field-separator=:: 73--field-separator=::
53 74
54 Use a special separator character and don't pad with spaces, replacing 75 Use a special separator character and don't pad with spaces, replacing
55 all occurances of this separator in symbol names (and other output) 76 all occurrences of this separator in symbol names (and other output)
56 with a '.' character, that thus it's the only non valid separator. 77 with a '.' character, that thus it's the only non valid separator.
57 78
79-D::
80--dump-raw-trace::
81 Dump raw trace in ASCII.
82
58-g [type,min]:: 83-g [type,min]::
59--call-graph:: 84--call-graph::
60 Display callchains using type and min percent threshold. 85 Display call chains using type and min percent threshold.
61 type can be either: 86 type can be either:
62 - flat: single column, linear exposure of callchains. 87 - flat: single column, linear exposure of call chains.
63 - graph: use a graph tree, displaying absolute overhead rates. 88 - graph: use a graph tree, displaying absolute overhead rates.
64 - fractal: like graph, but displays relative rates. Each branch of 89 - fractal: like graph, but displays relative rates. Each branch of
65 the tree is considered as a new profiled object. + 90 the tree is considered as a new profiled object. +
66 Default: fractal,0.5. 91 Default: fractal,0.5.
67 92
93--pretty=<key>::
94 Pretty printing style. key: normal, raw
95
96--stdio:: Use the stdio interface.
97
98--tui:: Use the TUI interface, that is integrated with annotate and allows
99 zooming into DSOs or threads, among other features. Use of --tui
100 requires a tty, if one is not present, as when piping to other
101 commands, the stdio interface is used.
102
103-k::
104--vmlinux=<file>::
105 vmlinux pathname
106
107--kallsyms=<file>::
108 kallsyms pathname
109
110-m::
111--modules::
112 Load module symbols. WARNING: This should only be used with -k and
113 a LIVE kernel.
114
115-f::
116--force::
117 Don't complain, do it.
118
119--symfs=<directory>::
120 Look for files with symbols relative to this directory.
121
68SEE ALSO 122SEE ALSO
69-------- 123--------
70linkperf:perf-stat[1] 124linkperf:perf-stat[1]
diff --git a/tools/perf/Documentation/perf-sched.txt b/tools/perf/Documentation/perf-sched.txt
index 8417644a6166..46822d5fde1c 100644
--- a/tools/perf/Documentation/perf-sched.txt
+++ b/tools/perf/Documentation/perf-sched.txt
@@ -8,11 +8,11 @@ perf-sched - Tool to trace/measure scheduler properties (latencies)
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf sched' {record|latency|replay|trace} 11'perf sched' {record|latency|map|replay|trace}
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
15There are four variants of perf sched: 15There are five variants of perf sched:
16 16
17 'perf sched record <command>' to record the scheduling events 17 'perf sched record <command>' to record the scheduling events
18 of an arbitrary workload. 18 of an arbitrary workload.
@@ -30,8 +30,22 @@ There are four variants of perf sched:
30 of the workload as it occurred when it was recorded - and can repeat 30 of the workload as it occurred when it was recorded - and can repeat
31 it a number of times, measuring its performance.) 31 it a number of times, measuring its performance.)
32 32
33 'perf sched map' to print a textual context-switching outline of
34 workload captured via perf sched record. Columns stand for
35 individual CPUs, and the two-letter shortcuts stand for tasks that
36 are running on a CPU. A '*' denotes the CPU that had the event, and
37 a dot signals an idle CPU.
38
33OPTIONS 39OPTIONS
34------- 40-------
41-i::
42--input=<file>::
43 Input file name. (default: perf.data)
44
45-v::
46--verbose::
47 Be more verbose. (show symbol address, etc)
48
35-D:: 49-D::
36--dump-raw-trace=:: 50--dump-raw-trace=::
37 Display verbose dump of the sched data. 51 Display verbose dump of the sched data.
diff --git a/tools/perf/Documentation/perf-trace-perl.txt b/tools/perf/Documentation/perf-script-perl.txt
index ee6525ee6d69..3152cca15501 100644
--- a/tools/perf/Documentation/perf-trace-perl.txt
+++ b/tools/perf/Documentation/perf-script-perl.txt
@@ -1,19 +1,19 @@
1perf-trace-perl(1) 1perf-script-perl(1)
2================== 2==================
3 3
4NAME 4NAME
5---- 5----
6perf-trace-perl - Process trace data with a Perl script 6perf-script-perl - Process trace data with a Perl script
7 7
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf trace' [-s [Perl]:script[.pl] ] 11'perf script' [-s [Perl]:script[.pl] ]
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
15 15
16This perf trace option is used to process perf trace data using perf's 16This perf script option is used to process perf script data using perf's
17built-in Perl interpreter. It reads and processes the input file and 17built-in Perl interpreter. It reads and processes the input file and
18displays the results of the trace analysis implemented in the given 18displays the results of the trace analysis implemented in the given
19Perl script, if any. 19Perl script, if any.
@@ -21,7 +21,7 @@ Perl script, if any.
21STARTER SCRIPTS 21STARTER SCRIPTS
22--------------- 22---------------
23 23
24You can avoid reading the rest of this document by running 'perf trace 24You can avoid reading the rest of this document by running 'perf script
25-g perl' in the same directory as an existing perf.data trace file. 25-g perl' in the same directory as an existing perf.data trace file.
26That will generate a starter script containing a handler for each of 26That will generate a starter script containing a handler for each of
27the event types in the trace file; it simply prints every available 27the event types in the trace file; it simply prints every available
@@ -30,13 +30,13 @@ field for each event in the trace file.
30You can also look at the existing scripts in 30You can also look at the existing scripts in
31~/libexec/perf-core/scripts/perl for typical examples showing how to 31~/libexec/perf-core/scripts/perl for typical examples showing how to
32do basic things like aggregate event data, print results, etc. Also, 32do basic things like aggregate event data, print results, etc. Also,
33the check-perf-trace.pl script, while not interesting for its results, 33the check-perf-script.pl script, while not interesting for its results,
34attempts to exercise all of the main scripting features. 34attempts to exercise all of the main scripting features.
35 35
36EVENT HANDLERS 36EVENT HANDLERS
37-------------- 37--------------
38 38
39When perf trace is invoked using a trace script, a user-defined 39When perf script is invoked using a trace script, a user-defined
40'handler function' is called for each event in the trace. If there's 40'handler function' is called for each event in the trace. If there's
41no handler function defined for a given event type, the event is 41no handler function defined for a given event type, the event is
42ignored (or passed to a 'trace_handled' function, see below) and the 42ignored (or passed to a 'trace_handled' function, see below) and the
@@ -63,7 +63,6 @@ The format file for the sched_wakep event defines the following fields
63 field:unsigned char common_flags; 63 field:unsigned char common_flags;
64 field:unsigned char common_preempt_count; 64 field:unsigned char common_preempt_count;
65 field:int common_pid; 65 field:int common_pid;
66 field:int common_lock_depth;
67 66
68 field:char comm[TASK_COMM_LEN]; 67 field:char comm[TASK_COMM_LEN];
69 field:pid_t pid; 68 field:pid_t pid;
@@ -112,13 +111,13 @@ write a useful trace script. The sections below cover the rest.
112SCRIPT LAYOUT 111SCRIPT LAYOUT
113------------- 112-------------
114 113
115Every perf trace Perl script should start by setting up a Perl module 114Every perf script Perl script should start by setting up a Perl module
116search path and 'use'ing a few support modules (see module 115search path and 'use'ing a few support modules (see module
117descriptions below): 116descriptions below):
118 117
119---- 118----
120 use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib"; 119 use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/perf-script-Util/lib";
121 use lib "./Perf-Trace-Util/lib"; 120 use lib "./perf-script-Util/lib";
122 use Perf::Trace::Core; 121 use Perf::Trace::Core;
123 use Perf::Trace::Context; 122 use Perf::Trace::Context;
124 use Perf::Trace::Util; 123 use Perf::Trace::Util;
@@ -162,7 +161,7 @@ sub trace_unhandled
162---- 161----
163 162
164The remaining sections provide descriptions of each of the available 163The remaining sections provide descriptions of each of the available
165built-in perf trace Perl modules and their associated functions. 164built-in perf script Perl modules and their associated functions.
166 165
167AVAILABLE MODULES AND FUNCTIONS 166AVAILABLE MODULES AND FUNCTIONS
168------------------------------- 167-------------------------------
@@ -170,7 +169,7 @@ AVAILABLE MODULES AND FUNCTIONS
170The following sections describe the functions and variables available 169The following sections describe the functions and variables available
171via the various Perf::Trace::* Perl modules. To use the functions and 170via the various Perf::Trace::* Perl modules. To use the functions and
172variables from the given module, add the corresponding 'use 171variables from the given module, add the corresponding 'use
173Perf::Trace::XXX' line to your perf trace script. 172Perf::Trace::XXX' line to your perf script script.
174 173
175Perf::Trace::Core Module 174Perf::Trace::Core Module
176~~~~~~~~~~~~~~~~~~~~~~~~ 175~~~~~~~~~~~~~~~~~~~~~~~~
@@ -204,7 +203,7 @@ argument.
204Perf::Trace::Util Module 203Perf::Trace::Util Module
205~~~~~~~~~~~~~~~~~~~~~~~~ 204~~~~~~~~~~~~~~~~~~~~~~~~
206 205
207Various utility functions for use with perf trace: 206Various utility functions for use with perf script:
208 207
209 nsecs($secs, $nsecs) - returns total nsecs given secs/nsecs pair 208 nsecs($secs, $nsecs) - returns total nsecs given secs/nsecs pair
210 nsecs_secs($nsecs) - returns whole secs portion given nsecs 209 nsecs_secs($nsecs) - returns whole secs portion given nsecs
@@ -214,4 +213,4 @@ Various utility functions for use with perf trace:
214 213
215SEE ALSO 214SEE ALSO
216-------- 215--------
217linkperf:perf-trace[1] 216linkperf:perf-script[1]
diff --git a/tools/perf/Documentation/perf-trace-python.txt b/tools/perf/Documentation/perf-script-python.txt
index 693be804dd3d..471022069119 100644
--- a/tools/perf/Documentation/perf-trace-python.txt
+++ b/tools/perf/Documentation/perf-script-python.txt
@@ -1,19 +1,19 @@
1perf-trace-python(1) 1perf-script-python(1)
2==================== 2====================
3 3
4NAME 4NAME
5---- 5----
6perf-trace-python - Process trace data with a Python script 6perf-script-python - Process trace data with a Python script
7 7
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf trace' [-s [Python]:script[.py] ] 11'perf script' [-s [Python]:script[.py] ]
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
15 15
16This perf trace option is used to process perf trace data using perf's 16This perf script option is used to process perf script data using perf's
17built-in Python interpreter. It reads and processes the input file and 17built-in Python interpreter. It reads and processes the input file and
18displays the results of the trace analysis implemented in the given 18displays the results of the trace analysis implemented in the given
19Python script, if any. 19Python script, if any.
@@ -23,15 +23,15 @@ A QUICK EXAMPLE
23 23
24This section shows the process, start to finish, of creating a working 24This section shows the process, start to finish, of creating a working
25Python script that aggregates and extracts useful information from a 25Python script that aggregates and extracts useful information from a
26raw perf trace stream. You can avoid reading the rest of this 26raw perf script stream. You can avoid reading the rest of this
27document if an example is enough for you; the rest of the document 27document if an example is enough for you; the rest of the document
28provides more details on each step and lists the library functions 28provides more details on each step and lists the library functions
29available to script writers. 29available to script writers.
30 30
31This example actually details the steps that were used to create the 31This example actually details the steps that were used to create the
32'syscall-counts' script you see when you list the available perf trace 32'syscall-counts' script you see when you list the available perf script
33scripts via 'perf trace -l'. As such, this script also shows how to 33scripts via 'perf script -l'. As such, this script also shows how to
34integrate your script into the list of general-purpose 'perf trace' 34integrate your script into the list of general-purpose 'perf script'
35scripts listed by that command. 35scripts listed by that command.
36 36
37The syscall-counts script is a simple script, but demonstrates all the 37The syscall-counts script is a simple script, but demonstrates all the
@@ -105,31 +105,31 @@ That single stream will be recorded in a file in the current directory
105called perf.data. 105called perf.data.
106 106
107Once we have a perf.data file containing our data, we can use the -g 107Once we have a perf.data file containing our data, we can use the -g
108'perf trace' option to generate a Python script that will contain a 108'perf script' option to generate a Python script that will contain a
109callback handler for each event type found in the perf.data trace 109callback handler for each event type found in the perf.data trace
110stream (for more details, see the STARTER SCRIPTS section). 110stream (for more details, see the STARTER SCRIPTS section).
111 111
112---- 112----
113# perf trace -g python 113# perf script -g python
114generated Python script: perf-trace.py 114generated Python script: perf-script.py
115 115
116The output file created also in the current directory is named 116The output file created also in the current directory is named
117perf-trace.py. Here's the file in its entirety: 117perf-script.py. Here's the file in its entirety:
118 118
119# perf trace event handlers, generated by perf trace -g python 119# perf script event handlers, generated by perf script -g python
120# Licensed under the terms of the GNU GPL License version 2 120# Licensed under the terms of the GNU GPL License version 2
121 121
122# The common_* event handler fields are the most useful fields common to 122# The common_* event handler fields are the most useful fields common to
123# all events. They don't necessarily correspond to the 'common_*' fields 123# all events. They don't necessarily correspond to the 'common_*' fields
124# in the format files. Those fields not available as handler params can 124# in the format files. Those fields not available as handler params can
125# be retrieved using Python functions of the form common_*(context). 125# be retrieved using Python functions of the form common_*(context).
126# See the perf-trace-python Documentation for the list of available functions. 126# See the perf-script-python Documentation for the list of available functions.
127 127
128import os 128import os
129import sys 129import sys
130 130
131sys.path.append(os.environ['PERF_EXEC_PATH'] + \ 131sys.path.append(os.environ['PERF_EXEC_PATH'] + \
132 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') 132 '/scripts/python/perf-script-Util/lib/Perf/Trace')
133 133
134from perf_trace_context import * 134from perf_trace_context import *
135from Core import * 135from Core import *
@@ -160,7 +160,7 @@ def print_header(event_name, cpu, secs, nsecs, pid, comm):
160---- 160----
161 161
162At the top is a comment block followed by some import statements and a 162At the top is a comment block followed by some import statements and a
163path append which every perf trace script should include. 163path append which every perf script script should include.
164 164
165Following that are a couple generated functions, trace_begin() and 165Following that are a couple generated functions, trace_begin() and
166trace_end(), which are called at the beginning and the end of the 166trace_end(), which are called at the beginning and the end of the
@@ -189,8 +189,8 @@ simply a utility function used for that purpose. Let's rename the
189script and run it to see the default output: 189script and run it to see the default output:
190 190
191---- 191----
192# mv perf-trace.py syscall-counts.py 192# mv perf-script.py syscall-counts.py
193# perf trace -s syscall-counts.py 193# perf script -s syscall-counts.py
194 194
195raw_syscalls__sys_enter 1 00840.847582083 7506 perf id=1, args= 195raw_syscalls__sys_enter 1 00840.847582083 7506 perf id=1, args=
196raw_syscalls__sys_enter 1 00840.847595764 7506 perf id=1, args= 196raw_syscalls__sys_enter 1 00840.847595764 7506 perf id=1, args=
@@ -216,7 +216,7 @@ import os
216import sys 216import sys
217 217
218sys.path.append(os.environ['PERF_EXEC_PATH'] + \ 218sys.path.append(os.environ['PERF_EXEC_PATH'] + \
219 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') 219 '/scripts/python/perf-script-Util/lib/Perf/Trace')
220 220
221from perf_trace_context import * 221from perf_trace_context import *
222from Core import * 222from Core import *
@@ -279,7 +279,7 @@ import os
279import sys 279import sys
280 280
281sys.path.append(os.environ['PERF_EXEC_PATH'] + \ 281sys.path.append(os.environ['PERF_EXEC_PATH'] + \
282 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') 282 '/scripts/python/perf-script-Util/lib/Perf/Trace')
283 283
284from perf_trace_context import * 284from perf_trace_context import *
285from Core import * 285from Core import *
@@ -315,7 +315,7 @@ def print_syscall_totals():
315 315
316The script can be run just as before: 316The script can be run just as before:
317 317
318 # perf trace -s syscall-counts.py 318 # perf script -s syscall-counts.py
319 319
320So those are the essential steps in writing and running a script. The 320So those are the essential steps in writing and running a script. The
321process can be generalized to any tracepoint or set of tracepoints 321process can be generalized to any tracepoint or set of tracepoints
@@ -324,17 +324,17 @@ interested in by looking at the list of available events shown by
324'perf list' and/or look in /sys/kernel/debug/tracing events for 324'perf list' and/or look in /sys/kernel/debug/tracing events for
325detailed event and field info, record the corresponding trace data 325detailed event and field info, record the corresponding trace data
326using 'perf record', passing it the list of interesting events, 326using 'perf record', passing it the list of interesting events,
327generate a skeleton script using 'perf trace -g python' and modify the 327generate a skeleton script using 'perf script -g python' and modify the
328code to aggregate and display it for your particular needs. 328code to aggregate and display it for your particular needs.
329 329
330After you've done that you may end up with a general-purpose script 330After you've done that you may end up with a general-purpose script
331that you want to keep around and have available for future use. By 331that you want to keep around and have available for future use. By
332writing a couple of very simple shell scripts and putting them in the 332writing a couple of very simple shell scripts and putting them in the
333right place, you can have your script listed alongside the other 333right place, you can have your script listed alongside the other
334scripts listed by the 'perf trace -l' command e.g.: 334scripts listed by the 'perf script -l' command e.g.:
335 335
336---- 336----
337root@tropicana:~# perf trace -l 337root@tropicana:~# perf script -l
338List of available trace scripts: 338List of available trace scripts:
339 workqueue-stats workqueue stats (ins/exe/create/destroy) 339 workqueue-stats workqueue stats (ins/exe/create/destroy)
340 wakeup-latency system-wide min/max/avg wakeup latency 340 wakeup-latency system-wide min/max/avg wakeup latency
@@ -365,14 +365,14 @@ perf record -a -e raw_syscalls:sys_enter
365The 'report' script is also a shell script with the same base name as 365The 'report' script is also a shell script with the same base name as
366your script, but with -report appended. It should also be located in 366your script, but with -report appended. It should also be located in
367the perf/scripts/python/bin directory. In that script, you write the 367the perf/scripts/python/bin directory. In that script, you write the
368'perf trace -s' command-line needed for running your script: 368'perf script -s' command-line needed for running your script:
369 369
370---- 370----
371# cat kernel-source/tools/perf/scripts/python/bin/syscall-counts-report 371# cat kernel-source/tools/perf/scripts/python/bin/syscall-counts-report
372 372
373#!/bin/bash 373#!/bin/bash
374# description: system-wide syscall counts 374# description: system-wide syscall counts
375perf trace -s ~/libexec/perf-core/scripts/python/syscall-counts.py 375perf script -s ~/libexec/perf-core/scripts/python/syscall-counts.py
376---- 376----
377 377
378Note that the location of the Python script given in the shell script 378Note that the location of the Python script given in the shell script
@@ -390,17 +390,17 @@ total 32
390drwxr-xr-x 4 trz trz 4096 2010-01-26 22:30 . 390drwxr-xr-x 4 trz trz 4096 2010-01-26 22:30 .
391drwxr-xr-x 4 trz trz 4096 2010-01-26 22:29 .. 391drwxr-xr-x 4 trz trz 4096 2010-01-26 22:29 ..
392drwxr-xr-x 2 trz trz 4096 2010-01-26 22:29 bin 392drwxr-xr-x 2 trz trz 4096 2010-01-26 22:29 bin
393-rw-r--r-- 1 trz trz 2548 2010-01-26 22:29 check-perf-trace.py 393-rw-r--r-- 1 trz trz 2548 2010-01-26 22:29 check-perf-script.py
394drwxr-xr-x 3 trz trz 4096 2010-01-26 22:49 Perf-Trace-Util 394drwxr-xr-x 3 trz trz 4096 2010-01-26 22:49 perf-script-Util
395-rw-r--r-- 1 trz trz 1462 2010-01-26 22:30 syscall-counts.py 395-rw-r--r-- 1 trz trz 1462 2010-01-26 22:30 syscall-counts.py
396---- 396----
397 397
398Once you've done that (don't forget to do a new 'make install', 398Once you've done that (don't forget to do a new 'make install',
399otherwise your script won't show up at run-time), 'perf trace -l' 399otherwise your script won't show up at run-time), 'perf script -l'
400should show a new entry for your script: 400should show a new entry for your script:
401 401
402---- 402----
403root@tropicana:~# perf trace -l 403root@tropicana:~# perf script -l
404List of available trace scripts: 404List of available trace scripts:
405 workqueue-stats workqueue stats (ins/exe/create/destroy) 405 workqueue-stats workqueue stats (ins/exe/create/destroy)
406 wakeup-latency system-wide min/max/avg wakeup latency 406 wakeup-latency system-wide min/max/avg wakeup latency
@@ -409,19 +409,19 @@ List of available trace scripts:
409 syscall-counts system-wide syscall counts 409 syscall-counts system-wide syscall counts
410---- 410----
411 411
412You can now perform the record step via 'perf trace record': 412You can now perform the record step via 'perf script record':
413 413
414 # perf trace record syscall-counts 414 # perf script record syscall-counts
415 415
416and display the output using 'perf trace report': 416and display the output using 'perf script report':
417 417
418 # perf trace report syscall-counts 418 # perf script report syscall-counts
419 419
420STARTER SCRIPTS 420STARTER SCRIPTS
421--------------- 421---------------
422 422
423You can quickly get started writing a script for a particular set of 423You can quickly get started writing a script for a particular set of
424trace data by generating a skeleton script using 'perf trace -g 424trace data by generating a skeleton script using 'perf script -g
425python' in the same directory as an existing perf.data trace file. 425python' in the same directory as an existing perf.data trace file.
426That will generate a starter script containing a handler for each of 426That will generate a starter script containing a handler for each of
427the event types in the trace file; it simply prints every available 427the event types in the trace file; it simply prints every available
@@ -430,13 +430,13 @@ field for each event in the trace file.
430You can also look at the existing scripts in 430You can also look at the existing scripts in
431~/libexec/perf-core/scripts/python for typical examples showing how to 431~/libexec/perf-core/scripts/python for typical examples showing how to
432do basic things like aggregate event data, print results, etc. Also, 432do basic things like aggregate event data, print results, etc. Also,
433the check-perf-trace.py script, while not interesting for its results, 433the check-perf-script.py script, while not interesting for its results,
434attempts to exercise all of the main scripting features. 434attempts to exercise all of the main scripting features.
435 435
436EVENT HANDLERS 436EVENT HANDLERS
437-------------- 437--------------
438 438
439When perf trace is invoked using a trace script, a user-defined 439When perf script is invoked using a trace script, a user-defined
440'handler function' is called for each event in the trace. If there's 440'handler function' is called for each event in the trace. If there's
441no handler function defined for a given event type, the event is 441no handler function defined for a given event type, the event is
442ignored (or passed to a 'trace_handled' function, see below) and the 442ignored (or passed to a 'trace_handled' function, see below) and the
@@ -463,7 +463,6 @@ The format file for the sched_wakep event defines the following fields
463 field:unsigned char common_flags; 463 field:unsigned char common_flags;
464 field:unsigned char common_preempt_count; 464 field:unsigned char common_preempt_count;
465 field:int common_pid; 465 field:int common_pid;
466 field:int common_lock_depth;
467 466
468 field:char comm[TASK_COMM_LEN]; 467 field:char comm[TASK_COMM_LEN];
469 field:pid_t pid; 468 field:pid_t pid;
@@ -510,7 +509,7 @@ write a useful trace script. The sections below cover the rest.
510SCRIPT LAYOUT 509SCRIPT LAYOUT
511------------- 510-------------
512 511
513Every perf trace Python script should start by setting up a Python 512Every perf script Python script should start by setting up a Python
514module search path and 'import'ing a few support modules (see module 513module search path and 'import'ing a few support modules (see module
515descriptions below): 514descriptions below):
516 515
@@ -519,7 +518,7 @@ descriptions below):
519 import sys 518 import sys
520 519
521 sys.path.append(os.environ['PERF_EXEC_PATH'] + \ 520 sys.path.append(os.environ['PERF_EXEC_PATH'] + \
522 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') 521 '/scripts/python/perf-script-Util/lib/Perf/Trace')
523 522
524 from perf_trace_context import * 523 from perf_trace_context import *
525 from Core import * 524 from Core import *
@@ -559,15 +558,15 @@ def trace_unhandled(event_name, context, common_cpu, common_secs,
559---- 558----
560 559
561The remaining sections provide descriptions of each of the available 560The remaining sections provide descriptions of each of the available
562built-in perf trace Python modules and their associated functions. 561built-in perf script Python modules and their associated functions.
563 562
564AVAILABLE MODULES AND FUNCTIONS 563AVAILABLE MODULES AND FUNCTIONS
565------------------------------- 564-------------------------------
566 565
567The following sections describe the functions and variables available 566The following sections describe the functions and variables available
568via the various perf trace Python modules. To use the functions and 567via the various perf script Python modules. To use the functions and
569variables from the given module, add the corresponding 'from XXXX 568variables from the given module, add the corresponding 'from XXXX
570import' line to your perf trace script. 569import' line to your perf script script.
571 570
572Core.py Module 571Core.py Module
573~~~~~~~~~~~~~~ 572~~~~~~~~~~~~~~
@@ -610,7 +609,7 @@ argument.
610Util.py Module 609Util.py Module
611~~~~~~~~~~~~~~ 610~~~~~~~~~~~~~~
612 611
613Various utility functions for use with perf trace: 612Various utility functions for use with perf script:
614 613
615 nsecs(secs, nsecs) - returns total nsecs given secs/nsecs pair 614 nsecs(secs, nsecs) - returns total nsecs given secs/nsecs pair
616 nsecs_secs(nsecs) - returns whole secs portion given nsecs 615 nsecs_secs(nsecs) - returns whole secs portion given nsecs
@@ -620,4 +619,4 @@ Various utility functions for use with perf trace:
620 619
621SEE ALSO 620SEE ALSO
622-------- 621--------
623linkperf:perf-trace[1] 622linkperf:perf-script[1]
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt
new file mode 100644
index 000000000000..86c87e214b11
--- /dev/null
+++ b/tools/perf/Documentation/perf-script.txt
@@ -0,0 +1,188 @@
1perf-script(1)
2=============
3
4NAME
5----
6perf-script - Read perf.data (created by perf record) and display trace output
7
8SYNOPSIS
9--------
10[verse]
11'perf script' [<options>]
12'perf script' [<options>] record <script> [<record-options>] <command>
13'perf script' [<options>] report <script> [script-args]
14'perf script' [<options>] <script> <required-script-args> [<record-options>] <command>
15'perf script' [<options>] <top-script> [script-args]
16
17DESCRIPTION
18-----------
19This command reads the input file and displays the trace recorded.
20
21There are several variants of perf script:
22
23 'perf script' to see a detailed trace of the workload that was
24 recorded.
25
26 You can also run a set of pre-canned scripts that aggregate and
27 summarize the raw trace data in various ways (the list of scripts is
28 available via 'perf script -l'). The following variants allow you to
29 record and run those scripts:
30
31 'perf script record <script> <command>' to record the events required
32 for 'perf script report'. <script> is the name displayed in the
33 output of 'perf script --list' i.e. the actual script name minus any
34 language extension. If <command> is not specified, the events are
35 recorded using the -a (system-wide) 'perf record' option.
36
37 'perf script report <script> [args]' to run and display the results
38 of <script>. <script> is the name displayed in the output of 'perf
39 trace --list' i.e. the actual script name minus any language
40 extension. The perf.data output from a previous run of 'perf script
41 record <script>' is used and should be present for this command to
42 succeed. [args] refers to the (mainly optional) args expected by
43 the script.
44
45 'perf script <script> <required-script-args> <command>' to both
46 record the events required for <script> and to run the <script>
47 using 'live-mode' i.e. without writing anything to disk. <script>
48 is the name displayed in the output of 'perf script --list' i.e. the
49 actual script name minus any language extension. If <command> is
50 not specified, the events are recorded using the -a (system-wide)
51 'perf record' option. If <script> has any required args, they
52 should be specified before <command>. This mode doesn't allow for
53 optional script args to be specified; if optional script args are
54 desired, they can be specified using separate 'perf script record'
55 and 'perf script report' commands, with the stdout of the record step
56 piped to the stdin of the report script, using the '-o -' and '-i -'
57 options of the corresponding commands.
58
59 'perf script <top-script>' to both record the events required for
60 <top-script> and to run the <top-script> using 'live-mode'
61 i.e. without writing anything to disk. <top-script> is the name
62 displayed in the output of 'perf script --list' i.e. the actual
63 script name minus any language extension; a <top-script> is defined
64 as any script name ending with the string 'top'.
65
66 [<record-options>] can be passed to the record steps of 'perf script
67 record' and 'live-mode' variants; this isn't possible however for
68 <top-script> 'live-mode' or 'perf script report' variants.
69
70 See the 'SEE ALSO' section for links to language-specific
71 information on how to write and run your own trace scripts.
72
73OPTIONS
74-------
75<command>...::
76 Any command you can specify in a shell.
77
78-D::
79--dump-raw-script=::
80 Display verbose dump of the trace data.
81
82-L::
83--Latency=::
84 Show latency attributes (irqs/preemption disabled, etc).
85
86-l::
87--list=::
88 Display a list of available trace scripts.
89
90-s ['lang']::
91--script=::
92 Process trace data with the given script ([lang]:script[.ext]).
93 If the string 'lang' is specified in place of a script name, a
94 list of supported languages will be displayed instead.
95
96-g::
97--gen-script=::
98 Generate perf-script.[ext] starter script for given language,
99 using current perf.data.
100
101-a::
102 Force system-wide collection. Scripts run without a <command>
103 normally use -a by default, while scripts run with a <command>
104 normally don't - this option allows the latter to be run in
105 system-wide mode.
106
107-i::
108--input=::
109 Input file name.
110
111-d::
112--debug-mode::
113 Do various checks like samples ordering and lost events.
114
115-f::
116--fields::
117 Comma separated list of fields to print. Options are:
118 comm, tid, pid, time, cpu, event, trace, sym. Field
119 list can be prepended with the type, trace, sw or hw,
120 to indicate to which event type the field list applies.
121 e.g., -f sw:comm,tid,time,sym and -f trace:time,cpu,trace
122
123 perf script -f <fields>
124
125 is equivalent to:
126
127 perf script -f trace:<fields> -f sw:<fields> -f hw:<fields>
128
129 i.e., the specified fields apply to all event types if the type string
130 is not given.
131
132 The arguments are processed in the order received. A later usage can
133 reset a prior request. e.g.:
134
135 -f trace: -f comm,tid,time,sym
136
137 The first -f suppresses trace events (field list is ""), but then the
138 second invocation sets the fields to comm,tid,time,sym. In this case a
139 warning is given to the user:
140
141 "Overriding previous field request for all events."
142
143 Alternativey, consider the order:
144
145 -f comm,tid,time,sym -f trace:
146
147 The first -f sets the fields for all events and the second -f
148 suppresses trace events. The user is given a warning message about
149 the override, and the result of the above is that only S/W and H/W
150 events are displayed with the given fields.
151
152 For the 'wildcard' option if a user selected field is invalid for an
153 event type, a message is displayed to the user that the option is
154 ignored for that type. For example:
155
156 $ perf script -f comm,tid,trace
157 'trace' not valid for hardware events. Ignoring.
158 'trace' not valid for software events. Ignoring.
159
160 Alternatively, if the type is given an invalid field is specified it
161 is an error. For example:
162
163 perf script -v -f sw:comm,tid,trace
164 'trace' not valid for software events.
165
166 At this point usage is displayed, and perf-script exits.
167
168 Finally, a user may not set fields to none for all event types.
169 i.e., -f "" is not allowed.
170
171-k::
172--vmlinux=<file>::
173 vmlinux pathname
174
175--kallsyms=<file>::
176 kallsyms pathname
177
178--symfs=<directory>::
179 Look for files with symbols relative to this directory.
180
181-G::
182--hide-call-graph::
183 When printing symbols do not display call chain.
184
185SEE ALSO
186--------
187linkperf:perf-record[1], linkperf:perf-script-perl[1],
188linkperf:perf-script-python[1]
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index 4b3a2d46b437..918cc38ee6d1 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -8,8 +8,8 @@ perf-stat - Run a command and gather performance counter statistics
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf stat' [-e <EVENT> | --event=EVENT] [-S] [-a] <command> 11'perf stat' [-e <EVENT> | --event=EVENT] [-a] <command>
12'perf stat' [-e <EVENT> | --event=EVENT] [-S] [-a] -- <command> [<options>] 12'perf stat' [-e <EVENT> | --event=EVENT] [-a] -- <command> [<options>]
13 13
14DESCRIPTION 14DESCRIPTION
15----------- 15-----------
@@ -35,24 +35,65 @@ 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 pid 38 stat events on existing process id
39
40-t::
41--tid=<tid>::
42 stat events on existing thread id
43
39 44
40-a:: 45-a::
41 system-wide collection 46--all-cpus::
47 system-wide collection from all CPUs
42 48
43-c:: 49-c::
44 scale counter values 50--scale::
51 scale/normalize counter values
52
53-r::
54--repeat=<n>::
55 repeat command and print average + stddev (max: 100)
45 56
46-B:: 57-B::
58--big-num::
47 print large numbers with thousands' separators according to locale 59 print large numbers with thousands' separators according to locale
48 60
49-C:: 61-C::
50--cpu=:: 62--cpu=::
51Count only on the list of cpus provided. Multiple CPUs can be provided as a 63Count only on the list of CPUs provided. Multiple CPUs can be provided as a
52comma-sperated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2. 64comma-separated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2.
53In per-thread mode, this option is ignored. The -a option is still necessary 65In per-thread mode, this option is ignored. The -a option is still necessary
54to activate system-wide monitoring. Default is to count on all CPUs. 66to activate system-wide monitoring. Default is to count on all CPUs.
55 67
68-A::
69--no-aggr::
70Do not aggregate counts across all monitored CPUs in system-wide mode (-a).
71This option is only valid in system-wide mode.
72
73-n::
74--null::
75 null run - don't start any counters
76
77-v::
78--verbose::
79 be more verbose (show counter open errors, etc)
80
81-x SEP::
82--field-separator SEP::
83print counts using a CSV-style output to make it easy to import directly into
84spreadsheets. Columns are separated by the string specified in SEP.
85
86-G name::
87--cgroup name::
88monitor only in the container (cgroup) called "name". This option is available only
89in per-cpu mode. The cgroup filesystem must be mounted. All threads belonging to
90container "name" are monitored when they run on the monitored CPUs. Multiple cgroups
91can be provided. Each cgroup is applied to the corresponding event, i.e., first cgroup
92to first event, second cgroup to second event and so on. It is possible to provide
93an empty cgroup (monitor all the time) using, e.g., -G foo,,bar. Cgroups must have
94corresponding events, i.e., they always refer to events defined earlier on the command
95line.
96
56EXAMPLES 97EXAMPLES
57-------- 98--------
58 99
diff --git a/tools/perf/Documentation/perf-test.txt b/tools/perf/Documentation/perf-test.txt
index 1c4b5f5b7f71..2c3b462f64b0 100644
--- a/tools/perf/Documentation/perf-test.txt
+++ b/tools/perf/Documentation/perf-test.txt
@@ -12,7 +12,7 @@ SYNOPSIS
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
15This command does assorted sanity tests, initially thru linked routines but 15This command does assorted sanity tests, initially through linked routines but
16also will look for a directory with more tests in the form of scripts. 16also will look for a directory with more tests in the form of scripts.
17 17
18OPTIONS 18OPTIONS
diff --git a/tools/perf/Documentation/perf-timechart.txt b/tools/perf/Documentation/perf-timechart.txt
index 4b1788355eca..d7b79e2ba2ad 100644
--- a/tools/perf/Documentation/perf-timechart.txt
+++ b/tools/perf/Documentation/perf-timechart.txt
@@ -38,6 +38,8 @@ OPTIONS
38--process:: 38--process::
39 Select the processes to display, by name or PID 39 Select the processes to display, by name or PID
40 40
41--symfs=<directory>::
42 Look for files with symbols relative to this directory.
41 43
42SEE ALSO 44SEE ALSO
43-------- 45--------
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index 1f9687663f2a..f6eb1cdafb77 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -12,7 +12,7 @@ SYNOPSIS
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
15This command generates and displays a performance counter profile in realtime. 15This command generates and displays a performance counter profile in real time.
16 16
17 17
18OPTIONS 18OPTIONS
@@ -27,8 +27,8 @@ OPTIONS
27 27
28-C <cpu-list>:: 28-C <cpu-list>::
29--cpu=<cpu>:: 29--cpu=<cpu>::
30Monitor only on the list of cpus provided. Multiple CPUs can be provided as a 30Monitor only on the list of CPUs provided. Multiple CPUs can be provided as a
31comma-sperated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2. 31comma-separated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2.
32Default is to monitor all CPUS. 32Default is to monitor all CPUS.
33 33
34-d <seconds>:: 34-d <seconds>::
@@ -50,6 +50,10 @@ Default is to monitor all CPUS.
50--count-filter=<count>:: 50--count-filter=<count>::
51 Only display functions with more events than this. 51 Only display functions with more events than this.
52 52
53-g::
54--group::
55 Put the counters into a counter group.
56
53-F <freq>:: 57-F <freq>::
54--freq=<freq>:: 58--freq=<freq>::
55 Profile at this frequency. 59 Profile at this frequency.
@@ -68,7 +72,11 @@ Default is to monitor all CPUS.
68 72
69-p <pid>:: 73-p <pid>::
70--pid=<pid>:: 74--pid=<pid>::
71 Profile events on existing pid. 75 Profile events on existing Process ID.
76
77-t <tid>::
78--tid=<tid>::
79 Profile events on existing thread ID.
72 80
73-r <priority>:: 81-r <priority>::
74--realtime=<priority>:: 82--realtime=<priority>::
@@ -78,6 +86,18 @@ Default is to monitor all CPUS.
78--sym-annotate=<symbol>:: 86--sym-annotate=<symbol>::
79 Annotate this symbol. 87 Annotate this symbol.
80 88
89-K::
90--hide_kernel_symbols::
91 Hide kernel symbols.
92
93-U::
94--hide_user_symbols::
95 Hide user symbols.
96
97-D::
98--dump-symtab::
99 Dump the symbol table used for profiling.
100
81-v:: 101-v::
82--verbose:: 102--verbose::
83 Be more verbose (show counter open errors, etc). 103 Be more verbose (show counter open errors, etc).
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt
deleted file mode 100644
index 122ec9dc4853..000000000000
--- a/tools/perf/Documentation/perf-trace.txt
+++ /dev/null
@@ -1,70 +0,0 @@
1perf-trace(1)
2=============
3
4NAME
5----
6perf-trace - Read perf.data (created by perf record) and display trace output
7
8SYNOPSIS
9--------
10[verse]
11'perf trace' {record <script> | report <script> [args] }
12
13DESCRIPTION
14-----------
15This command reads the input file and displays the trace recorded.
16
17There are several variants of perf trace:
18
19 'perf trace' to see a detailed trace of the workload that was
20 recorded.
21
22 You can also run a set of pre-canned scripts that aggregate and
23 summarize the raw trace data in various ways (the list of scripts is
24 available via 'perf trace -l'). The following variants allow you to
25 record and run those scripts:
26
27 'perf trace record <script>' to record the events required for 'perf
28 trace report'. <script> is the name displayed in the output of
29 'perf trace --list' i.e. the actual script name minus any language
30 extension.
31
32 'perf trace report <script>' to run and display the results of
33 <script>. <script> is the name displayed in the output of 'perf
34 trace --list' i.e. the actual script name minus any language
35 extension. The perf.data output from a previous run of 'perf trace
36 record <script>' is used and should be present for this command to
37 succeed.
38
39 See the 'SEE ALSO' section for links to language-specific
40 information on how to write and run your own trace scripts.
41
42OPTIONS
43-------
44-D::
45--dump-raw-trace=::
46 Display verbose dump of the trace data.
47
48-L::
49--Latency=::
50 Show latency attributes (irqs/preemption disabled, etc).
51
52-l::
53--list=::
54 Display a list of available trace scripts.
55
56-s ['lang']::
57--script=::
58 Process trace data with the given script ([lang]:script[.ext]).
59 If the string 'lang' is specified in place of a script name, a
60 list of supported languages will be displayed instead.
61
62-g::
63--gen-script=::
64 Generate perf-trace.[ext] starter script for given language,
65 using current perf.data.
66
67SEE ALSO
68--------
69linkperf:perf-record[1], linkperf:perf-trace-perl[1],
70linkperf:perf-trace-python[1]
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST
index 8c7fc0c8f0b8..c12659d8cb26 100644
--- a/tools/perf/MANIFEST
+++ b/tools/perf/MANIFEST
@@ -7,6 +7,7 @@ include/linux/stringify.h
7lib/rbtree.c 7lib/rbtree.c
8include/linux/swab.h 8include/linux/swab.h
9arch/*/include/asm/unistd*.h 9arch/*/include/asm/unistd*.h
10arch/*/lib/memcpy*.S
10include/linux/poison.h 11include/linux/poison.h
11include/linux/magic.h 12include/linux/magic.h
12include/linux/hw_breakpoint.h 13include/linux/hw_breakpoint.h
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 1950e19af1cf..940257b5774e 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -3,7 +3,9 @@ ifeq ("$(origin O)", "command line")
3endif 3endif
4 4
5# The default target of this Makefile is... 5# The default target of this Makefile is...
6all:: 6all:
7
8include config/utilities.mak
7 9
8ifneq ($(OUTPUT),) 10ifneq ($(OUTPUT),)
9# check that the output directory actually exists 11# check that the output directory actually exists
@@ -11,152 +13,18 @@ OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd)
11$(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist)) 13$(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist))
12endif 14endif
13 15
14# Define V=1 to have a more verbose compile. 16# Define V to have a more verbose compile.
15# Define V=2 to have an even more verbose compile.
16#
17# Define SNPRINTF_RETURNS_BOGUS if your are on a system which snprintf()
18# or vsnprintf() return -1 instead of number of characters which would
19# have been written to the final string if enough space had been available.
20#
21# Define FREAD_READS_DIRECTORIES if your are on a system which succeeds
22# when attempting to read from an fopen'ed directory.
23#
24# Define NO_OPENSSL environment variable if you do not have OpenSSL.
25# This also implies MOZILLA_SHA1.
26#
27# Define CURLDIR=/foo/bar if your curl header and library files are in
28# /foo/bar/include and /foo/bar/lib directories.
29#
30# Define EXPATDIR=/foo/bar if your expat header and library files are in
31# /foo/bar/include and /foo/bar/lib directories.
32#
33# Define NO_D_INO_IN_DIRENT if you don't have d_ino in your struct dirent.
34#
35# Define NO_D_TYPE_IN_DIRENT if your platform defines DT_UNKNOWN but lacks
36# d_type in struct dirent (latest Cygwin -- will be fixed soonish).
37#
38# Define NO_C99_FORMAT if your formatted IO functions (printf/scanf et.al.)
39# do not support the 'size specifiers' introduced by C99, namely ll, hh,
40# j, z, t. (representing long long int, char, intmax_t, size_t, ptrdiff_t).
41# some C compilers supported these specifiers prior to C99 as an extension.
42#
43# Define NO_STRCASESTR if you don't have strcasestr.
44#
45# Define NO_MEMMEM if you don't have memmem.
46#
47# Define NO_STRTOUMAX if you don't have strtoumax in the C library.
48# If your compiler also does not support long long or does not have
49# strtoull, define NO_STRTOULL.
50#
51# Define NO_SETENV if you don't have setenv in the C library.
52#
53# Define NO_UNSETENV if you don't have unsetenv in the C library.
54#
55# Define NO_MKDTEMP if you don't have mkdtemp in the C library.
56#
57# Define NO_SYS_SELECT_H if you don't have sys/select.h.
58#
59# Define NO_SYMLINK_HEAD if you never want .perf/HEAD to be a symbolic link.
60# Enable it on Windows. By default, symrefs are still used.
61#
62# Define NO_SVN_TESTS if you want to skip time-consuming SVN interoperability
63# tests. These tests take up a significant amount of the total test time
64# but are not needed unless you plan to talk to SVN repos.
65#
66# Define NO_FINK if you are building on Darwin/Mac OS X, have Fink
67# installed in /sw, but don't want PERF to link against any libraries
68# installed there. If defined you may specify your own (or Fink's)
69# include directories and library directories by defining CFLAGS
70# and LDFLAGS appropriately.
71#
72# Define NO_DARWIN_PORTS if you are building on Darwin/Mac OS X,
73# have DarwinPorts installed in /opt/local, but don't want PERF to
74# link against any libraries installed there. If defined you may
75# specify your own (or DarwinPort's) include directories and
76# library directories by defining CFLAGS and LDFLAGS appropriately.
77#
78# Define PPC_SHA1 environment variable when running make to make use of
79# a bundled SHA1 routine optimized for PowerPC.
80#
81# Define ARM_SHA1 environment variable when running make to make use of
82# a bundled SHA1 routine optimized for ARM.
83#
84# Define MOZILLA_SHA1 environment variable when running make to make use of
85# a bundled SHA1 routine coming from Mozilla. It is GPL'd and should be fast
86# on non-x86 architectures (e.g. PowerPC), while the OpenSSL version (default
87# choice) has very fast version optimized for i586.
88# 17#
89# Define NEEDS_SSL_WITH_CRYPTO if you need -lcrypto with -lssl (Darwin). 18# Define PYTHON to point to the python binary if the default
19# `python' is not correct; for example: PYTHON=python2
90# 20#
91# Define NEEDS_LIBICONV if linking with libc is not enough (Darwin). 21# Define PYTHON_CONFIG to point to the python-config binary if
92# 22# the default `$(PYTHON)-config' is not correct.
93# Define NEEDS_SOCKET if linking with libc is not enough (SunOS,
94# Patrick Mauritz).
95#
96# Define NO_MMAP if you want to avoid mmap.
97#
98# Define NO_PTHREADS if you do not have or do not want to use Pthreads.
99#
100# Define NO_PREAD if you have a problem with pread() system call (e.g.
101# cygwin.dll before v1.5.22).
102#
103# Define NO_FAST_WORKING_DIRECTORY if accessing objects in pack files is
104# generally faster on your platform than accessing the working directory.
105#
106# Define NO_TRUSTABLE_FILEMODE if your filesystem may claim to support
107# the executable mode bit, but doesn't really do so.
108#
109# Define NO_IPV6 if you lack IPv6 support and getaddrinfo().
110#
111# Define NO_SOCKADDR_STORAGE if your platform does not have struct
112# sockaddr_storage.
113#
114# Define NO_ICONV if your libc does not properly support iconv.
115#
116# Define OLD_ICONV if your library has an old iconv(), where the second
117# (input buffer pointer) parameter is declared with type (const char **).
118#
119# Define NO_DEFLATE_BOUND if your zlib does not have deflateBound.
120#
121# Define NO_R_TO_GCC_LINKER if your gcc does not like "-R/path/lib"
122# that tells runtime paths to dynamic libraries;
123# "-Wl,-rpath=/path/lib" is used instead.
124#
125# Define USE_NSEC below if you want perf to care about sub-second file mtimes
126# and ctimes. Note that you need recent glibc (at least 2.2.4) for this, and
127# it will BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely
128# randomly break unless your underlying filesystem supports those sub-second
129# times (my ext3 doesn't).
130#
131# Define USE_ST_TIMESPEC if your "struct stat" uses "st_ctimespec" instead of
132# "st_ctim"
133#
134# Define NO_NSEC if your "struct stat" does not have "st_ctim.tv_nsec"
135# available. This automatically turns USE_NSEC off.
136#
137# Define USE_STDEV below if you want perf to care about the underlying device
138# change being considered an inode change from the update-index perspective.
139#
140# Define NO_ST_BLOCKS_IN_STRUCT_STAT if your platform does not have st_blocks
141# field that counts the on-disk footprint in 512-byte blocks.
142# 23#
143# Define ASCIIDOC8 if you want to format documentation with AsciiDoc 8 24# Define ASCIIDOC8 if you want to format documentation with AsciiDoc 8
144# 25#
145# Define DOCBOOK_XSL_172 if you want to format man pages with DocBook XSL v1.72. 26# Define DOCBOOK_XSL_172 if you want to format man pages with DocBook XSL v1.72.
146# 27#
147# Define NO_PERL_MAKEMAKER if you cannot use Makefiles generated by perl's
148# MakeMaker (e.g. using ActiveState under Cygwin).
149#
150# Define NO_PERL if you do not want Perl scripts or libraries at all.
151#
152# Define INTERNAL_QSORT to use Git's implementation of qsort(), which
153# is a simplified version of the merge sort used in glibc. This is
154# recommended if Git triggers O(n^2) behavior in your platform's qsort().
155#
156# Define NO_EXTERNAL_GREP if you don't want "perf grep" to ever call
157# your external grep (e.g., if your system lacks grep, if its grep is
158# broken, or spawning external process is slower than built-in grep perf has).
159#
160# Define LDFLAGS=-static to build a static binary. 28# Define LDFLAGS=-static to build a static binary.
161# 29#
162# Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds. 30# Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds.
@@ -167,12 +35,7 @@ $(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
167 @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT) 35 @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT)
168-include $(OUTPUT)PERF-VERSION-FILE 36-include $(OUTPUT)PERF-VERSION-FILE
169 37
170uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') 38uname_M := $(shell uname -m 2>/dev/null || echo not)
171uname_M := $(shell sh -c 'uname -m 2>/dev/null || echo not')
172uname_O := $(shell sh -c 'uname -o 2>/dev/null || echo not')
173uname_R := $(shell sh -c 'uname -r 2>/dev/null || echo not')
174uname_P := $(shell sh -c 'uname -p 2>/dev/null || echo not')
175uname_V := $(shell sh -c 'uname -v 2>/dev/null || echo not')
176 39
177ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \ 40ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
178 -e s/arm.*/arm/ -e s/sa110/arm/ \ 41 -e s/arm.*/arm/ -e s/sa110/arm/ \
@@ -180,16 +43,23 @@ ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
180 -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \ 43 -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
181 -e s/sh[234].*/sh/ ) 44 -e s/sh[234].*/sh/ )
182 45
46CC = $(CROSS_COMPILE)gcc
47AR = $(CROSS_COMPILE)ar
48
183# Additional ARCH settings for x86 49# Additional ARCH settings for x86
184ifeq ($(ARCH),i386) 50ifeq ($(ARCH),i386)
185 ARCH := x86 51 ARCH := x86
186endif 52endif
187ifeq ($(ARCH),x86_64) 53ifeq ($(ARCH),x86_64)
188 ARCH := x86 54 ARCH := x86
55 IS_X86_64 := $(shell echo __x86_64__ | ${CC} -E -xc - | tail -n 1)
56 ifeq (${IS_X86_64}, 1)
57 RAW_ARCH := x86_64
58 ARCH_CFLAGS := -DARCH_X86_64
59 ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S
60 endif
189endif 61endif
190 62
191# CFLAGS and LDFLAGS are for the users to override from the command line.
192
193# 63#
194# Include saner warnings here, which can catch bugs: 64# Include saner warnings here, which can catch bugs:
195# 65#
@@ -201,13 +71,11 @@ EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wshadow
201EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Winit-self 71EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Winit-self
202EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wpacked 72EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wpacked
203EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wredundant-decls 73EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wredundant-decls
204EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstack-protector
205EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-aliasing=3 74EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-aliasing=3
206EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wswitch-default 75EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wswitch-default
207EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wswitch-enum 76EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wswitch-enum
208EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wno-system-headers 77EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wno-system-headers
209EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wundef 78EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wundef
210EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wvolatile-register-var
211EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wwrite-strings 79EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wwrite-strings
212EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wbad-function-cast 80EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wbad-function-cast
213EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wmissing-declarations 81EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wmissing-declarations
@@ -224,7 +92,7 @@ ifndef PERF_DEBUG
224 CFLAGS_OPTIMIZE = -O6 92 CFLAGS_OPTIMIZE = -O6
225endif 93endif
226 94
227CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) 95CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 -Werror $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS)
228EXTLIBS = -lpthread -lrt -lelf -lm 96EXTLIBS = -lpthread -lrt -lelf -lm
229ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 97ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
230ALL_LDFLAGS = $(LDFLAGS) 98ALL_LDFLAGS = $(LDFLAGS)
@@ -265,32 +133,28 @@ lib = lib
265 133
266export prefix bindir sharedir sysconfdir 134export prefix bindir sharedir sysconfdir
267 135
268CC = $(CROSS_COMPILE)gcc
269AR = $(CROSS_COMPILE)ar
270RM = rm -f 136RM = rm -f
271MKDIR = mkdir 137MKDIR = mkdir
272TAR = tar
273FIND = find 138FIND = find
274INSTALL = install 139INSTALL = install
275RPMBUILD = rpmbuild
276PTHREAD_LIBS = -lpthread
277 140
278# sparse is architecture-neutral, which means that we need to tell it 141# sparse is architecture-neutral, which means that we need to tell it
279# explicitly what architecture to check for. Fix this up for yours.. 142# explicitly what architecture to check for. Fix this up for yours..
280SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__ 143SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
281 144
282ifeq ($(V), 2) 145-include config/feature-tests.mak
283 QUIET_STDERR = ">/dev/null"
284else
285 QUIET_STDERR = ">/dev/null 2>&1"
286endif
287
288-include feature-tests.mak
289 146
290ifeq ($(call try-cc,$(SOURCE_HELLO),-Werror -fstack-protector-all),y) 147ifeq ($(call try-cc,$(SOURCE_HELLO),-Werror -fstack-protector-all),y)
291 CFLAGS := $(CFLAGS) -fstack-protector-all 148 CFLAGS := $(CFLAGS) -fstack-protector-all
292endif 149endif
293 150
151ifeq ($(call try-cc,$(SOURCE_HELLO),-Werror -Wstack-protector),y)
152 CFLAGS := $(CFLAGS) -Wstack-protector
153endif
154
155ifeq ($(call try-cc,$(SOURCE_HELLO),-Werror -Wvolatile-register-var),y)
156 CFLAGS := $(CFLAGS) -Wvolatile-register-var
157endif
294 158
295### --- END CONFIGURATION SECTION --- 159### --- END CONFIGURATION SECTION ---
296 160
@@ -302,46 +166,39 @@ BASIC_LDFLAGS =
302 166
303# Guard against environment variables 167# Guard against environment variables
304BUILTIN_OBJS = 168BUILTIN_OBJS =
305BUILT_INS =
306COMPAT_CFLAGS =
307COMPAT_OBJS =
308LIB_H = 169LIB_H =
309LIB_OBJS = 170LIB_OBJS =
310SCRIPT_PERL = 171PYRF_OBJS =
311SCRIPT_SH = 172SCRIPT_SH =
312TEST_PROGRAMS =
313 173
314SCRIPT_SH += perf-archive.sh 174SCRIPT_SH += perf-archive.sh
315 175
176grep-libs = $(filter -l%,$(1))
177strip-libs = $(filter-out -l%,$(1))
178
179$(OUTPUT)python/perf.so: $(PYRF_OBJS)
180 $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \
181 --quiet build_ext \
182 --build-lib='$(OUTPUT)python' \
183 --build-temp='$(OUTPUT)python/temp'
316# 184#
317# No Perl scripts right now: 185# No Perl scripts right now:
318# 186#
319 187
320# SCRIPT_PERL += perf-add--interactive.perl 188SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH))
321
322SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \
323 $(patsubst %.perl,%,$(SCRIPT_PERL))
324
325# Empty...
326EXTRA_PROGRAMS =
327
328# ... and all the rest that could be moved out of bindir to perfexecdir
329PROGRAMS += $(EXTRA_PROGRAMS)
330 189
331# 190#
332# Single 'perf' binary right now: 191# Single 'perf' binary right now:
333# 192#
334PROGRAMS += $(OUTPUT)perf 193PROGRAMS += $(OUTPUT)perf
335 194
336# List built-in command $C whose implementation cmd_$C() is not in 195LANG_BINDINGS =
337# builtin-$C.o but is linked in as part of some other command.
338#
339 196
340# what 'all' will build and 'install' will install, in perfexecdir 197# what 'all' will build and 'install' will install, in perfexecdir
341ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS) 198ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
342 199
343# what 'all' will build but not install in perfexecdir 200# what 'all' will build but not install in perfexecdir
344OTHER_PROGRAMS = $(OUTPUT)perf$X 201OTHER_PROGRAMS = $(OUTPUT)perf
345 202
346# Set paths to tools early so that they can be used for version tests. 203# Set paths to tools early so that they can be used for version tests.
347ifndef SHELL_PATH 204ifndef SHELL_PATH
@@ -358,11 +215,13 @@ LIB_FILE=$(OUTPUT)libperf.a
358LIB_H += ../../include/linux/perf_event.h 215LIB_H += ../../include/linux/perf_event.h
359LIB_H += ../../include/linux/rbtree.h 216LIB_H += ../../include/linux/rbtree.h
360LIB_H += ../../include/linux/list.h 217LIB_H += ../../include/linux/list.h
218LIB_H += ../../include/linux/const.h
361LIB_H += ../../include/linux/hash.h 219LIB_H += ../../include/linux/hash.h
362LIB_H += ../../include/linux/stringify.h 220LIB_H += ../../include/linux/stringify.h
363LIB_H += util/include/linux/bitmap.h 221LIB_H += util/include/linux/bitmap.h
364LIB_H += util/include/linux/bitops.h 222LIB_H += util/include/linux/bitops.h
365LIB_H += util/include/linux/compiler.h 223LIB_H += util/include/linux/compiler.h
224LIB_H += util/include/linux/const.h
366LIB_H += util/include/linux/ctype.h 225LIB_H += util/include/linux/ctype.h
367LIB_H += util/include/linux/kernel.h 226LIB_H += util/include/linux/kernel.h
368LIB_H += util/include/linux/list.h 227LIB_H += util/include/linux/list.h
@@ -372,6 +231,7 @@ LIB_H += util/include/linux/prefetch.h
372LIB_H += util/include/linux/rbtree.h 231LIB_H += util/include/linux/rbtree.h
373LIB_H += util/include/linux/string.h 232LIB_H += util/include/linux/string.h
374LIB_H += util/include/linux/types.h 233LIB_H += util/include/linux/types.h
234LIB_H += util/include/linux/linkage.h
375LIB_H += util/include/asm/asm-offsets.h 235LIB_H += util/include/asm/asm-offsets.h
376LIB_H += util/include/asm/bug.h 236LIB_H += util/include/asm/bug.h
377LIB_H += util/include/asm/byteorder.h 237LIB_H += util/include/asm/byteorder.h
@@ -380,13 +240,18 @@ LIB_H += util/include/asm/swab.h
380LIB_H += util/include/asm/system.h 240LIB_H += util/include/asm/system.h
381LIB_H += util/include/asm/uaccess.h 241LIB_H += util/include/asm/uaccess.h
382LIB_H += util/include/dwarf-regs.h 242LIB_H += util/include/dwarf-regs.h
243LIB_H += util/include/asm/dwarf2.h
244LIB_H += util/include/asm/cpufeature.h
383LIB_H += perf.h 245LIB_H += perf.h
246LIB_H += util/annotate.h
384LIB_H += util/cache.h 247LIB_H += util/cache.h
385LIB_H += util/callchain.h 248LIB_H += util/callchain.h
386LIB_H += util/build-id.h 249LIB_H += util/build-id.h
387LIB_H += util/debug.h 250LIB_H += util/debug.h
388LIB_H += util/debugfs.h 251LIB_H += util/debugfs.h
389LIB_H += util/event.h 252LIB_H += util/event.h
253LIB_H += util/evsel.h
254LIB_H += util/evlist.h
390LIB_H += util/exec_cmd.h 255LIB_H += util/exec_cmd.h
391LIB_H += util/types.h 256LIB_H += util/types.h
392LIB_H += util/levenshtein.h 257LIB_H += util/levenshtein.h
@@ -395,11 +260,13 @@ LIB_H += util/parse-options.h
395LIB_H += util/parse-events.h 260LIB_H += util/parse-events.h
396LIB_H += util/quote.h 261LIB_H += util/quote.h
397LIB_H += util/util.h 262LIB_H += util/util.h
263LIB_H += util/xyarray.h
398LIB_H += util/header.h 264LIB_H += util/header.h
399LIB_H += util/help.h 265LIB_H += util/help.h
400LIB_H += util/session.h 266LIB_H += util/session.h
401LIB_H += util/strbuf.h 267LIB_H += util/strbuf.h
402LIB_H += util/strlist.h 268LIB_H += util/strlist.h
269LIB_H += util/strfilter.h
403LIB_H += util/svghelper.h 270LIB_H += util/svghelper.h
404LIB_H += util/run-command.h 271LIB_H += util/run-command.h
405LIB_H += util/sigchain.h 272LIB_H += util/sigchain.h
@@ -409,20 +276,27 @@ LIB_H += util/values.h
409LIB_H += util/sort.h 276LIB_H += util/sort.h
410LIB_H += util/hist.h 277LIB_H += util/hist.h
411LIB_H += util/thread.h 278LIB_H += util/thread.h
279LIB_H += util/thread_map.h
412LIB_H += util/trace-event.h 280LIB_H += util/trace-event.h
413LIB_H += util/probe-finder.h 281LIB_H += util/probe-finder.h
414LIB_H += util/probe-event.h 282LIB_H += util/probe-event.h
415LIB_H += util/pstack.h 283LIB_H += util/pstack.h
416LIB_H += util/cpumap.h 284LIB_H += util/cpumap.h
285LIB_H += util/top.h
286LIB_H += $(ARCH_INCLUDE)
287LIB_H += util/cgroup.h
417 288
418LIB_OBJS += $(OUTPUT)util/abspath.o 289LIB_OBJS += $(OUTPUT)util/abspath.o
419LIB_OBJS += $(OUTPUT)util/alias.o 290LIB_OBJS += $(OUTPUT)util/alias.o
291LIB_OBJS += $(OUTPUT)util/annotate.o
420LIB_OBJS += $(OUTPUT)util/build-id.o 292LIB_OBJS += $(OUTPUT)util/build-id.o
421LIB_OBJS += $(OUTPUT)util/config.o 293LIB_OBJS += $(OUTPUT)util/config.o
422LIB_OBJS += $(OUTPUT)util/ctype.o 294LIB_OBJS += $(OUTPUT)util/ctype.o
423LIB_OBJS += $(OUTPUT)util/debugfs.o 295LIB_OBJS += $(OUTPUT)util/debugfs.o
424LIB_OBJS += $(OUTPUT)util/environment.o 296LIB_OBJS += $(OUTPUT)util/environment.o
425LIB_OBJS += $(OUTPUT)util/event.o 297LIB_OBJS += $(OUTPUT)util/event.o
298LIB_OBJS += $(OUTPUT)util/evlist.o
299LIB_OBJS += $(OUTPUT)util/evsel.o
426LIB_OBJS += $(OUTPUT)util/exec_cmd.o 300LIB_OBJS += $(OUTPUT)util/exec_cmd.o
427LIB_OBJS += $(OUTPUT)util/help.o 301LIB_OBJS += $(OUTPUT)util/help.o
428LIB_OBJS += $(OUTPUT)util/levenshtein.o 302LIB_OBJS += $(OUTPUT)util/levenshtein.o
@@ -437,6 +311,8 @@ LIB_OBJS += $(OUTPUT)util/quote.o
437LIB_OBJS += $(OUTPUT)util/strbuf.o 311LIB_OBJS += $(OUTPUT)util/strbuf.o
438LIB_OBJS += $(OUTPUT)util/string.o 312LIB_OBJS += $(OUTPUT)util/string.o
439LIB_OBJS += $(OUTPUT)util/strlist.o 313LIB_OBJS += $(OUTPUT)util/strlist.o
314LIB_OBJS += $(OUTPUT)util/strfilter.o
315LIB_OBJS += $(OUTPUT)util/top.o
440LIB_OBJS += $(OUTPUT)util/usage.o 316LIB_OBJS += $(OUTPUT)util/usage.o
441LIB_OBJS += $(OUTPUT)util/wrapper.o 317LIB_OBJS += $(OUTPUT)util/wrapper.o
442LIB_OBJS += $(OUTPUT)util/sigchain.o 318LIB_OBJS += $(OUTPUT)util/sigchain.o
@@ -451,6 +327,7 @@ LIB_OBJS += $(OUTPUT)util/map.o
451LIB_OBJS += $(OUTPUT)util/pstack.o 327LIB_OBJS += $(OUTPUT)util/pstack.o
452LIB_OBJS += $(OUTPUT)util/session.o 328LIB_OBJS += $(OUTPUT)util/session.o
453LIB_OBJS += $(OUTPUT)util/thread.o 329LIB_OBJS += $(OUTPUT)util/thread.o
330LIB_OBJS += $(OUTPUT)util/thread_map.o
454LIB_OBJS += $(OUTPUT)util/trace-event-parse.o 331LIB_OBJS += $(OUTPUT)util/trace-event-parse.o
455LIB_OBJS += $(OUTPUT)util/trace-event-read.o 332LIB_OBJS += $(OUTPUT)util/trace-event-read.o
456LIB_OBJS += $(OUTPUT)util/trace-event-info.o 333LIB_OBJS += $(OUTPUT)util/trace-event-info.o
@@ -460,7 +337,9 @@ LIB_OBJS += $(OUTPUT)util/sort.o
460LIB_OBJS += $(OUTPUT)util/hist.o 337LIB_OBJS += $(OUTPUT)util/hist.o
461LIB_OBJS += $(OUTPUT)util/probe-event.o 338LIB_OBJS += $(OUTPUT)util/probe-event.o
462LIB_OBJS += $(OUTPUT)util/util.o 339LIB_OBJS += $(OUTPUT)util/util.o
340LIB_OBJS += $(OUTPUT)util/xyarray.o
463LIB_OBJS += $(OUTPUT)util/cpumap.o 341LIB_OBJS += $(OUTPUT)util/cpumap.o
342LIB_OBJS += $(OUTPUT)util/cgroup.o
464 343
465BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o 344BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
466 345
@@ -469,9 +348,13 @@ BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
469# Benchmark modules 348# Benchmark modules
470BUILTIN_OBJS += $(OUTPUT)bench/sched-messaging.o 349BUILTIN_OBJS += $(OUTPUT)bench/sched-messaging.o
471BUILTIN_OBJS += $(OUTPUT)bench/sched-pipe.o 350BUILTIN_OBJS += $(OUTPUT)bench/sched-pipe.o
351ifeq ($(RAW_ARCH),x86_64)
352BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy-x86-64-asm.o
353endif
472BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o 354BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o
473 355
474BUILTIN_OBJS += $(OUTPUT)builtin-diff.o 356BUILTIN_OBJS += $(OUTPUT)builtin-diff.o
357BUILTIN_OBJS += $(OUTPUT)builtin-evlist.o
475BUILTIN_OBJS += $(OUTPUT)builtin-help.o 358BUILTIN_OBJS += $(OUTPUT)builtin-help.o
476BUILTIN_OBJS += $(OUTPUT)builtin-sched.o 359BUILTIN_OBJS += $(OUTPUT)builtin-sched.o
477BUILTIN_OBJS += $(OUTPUT)builtin-buildid-list.o 360BUILTIN_OBJS += $(OUTPUT)builtin-buildid-list.o
@@ -482,7 +365,7 @@ BUILTIN_OBJS += $(OUTPUT)builtin-report.o
482BUILTIN_OBJS += $(OUTPUT)builtin-stat.o 365BUILTIN_OBJS += $(OUTPUT)builtin-stat.o
483BUILTIN_OBJS += $(OUTPUT)builtin-timechart.o 366BUILTIN_OBJS += $(OUTPUT)builtin-timechart.o
484BUILTIN_OBJS += $(OUTPUT)builtin-top.o 367BUILTIN_OBJS += $(OUTPUT)builtin-top.o
485BUILTIN_OBJS += $(OUTPUT)builtin-trace.o 368BUILTIN_OBJS += $(OUTPUT)builtin-script.o
486BUILTIN_OBJS += $(OUTPUT)builtin-probe.o 369BUILTIN_OBJS += $(OUTPUT)builtin-probe.o
487BUILTIN_OBJS += $(OUTPUT)builtin-kmem.o 370BUILTIN_OBJS += $(OUTPUT)builtin-kmem.o
488BUILTIN_OBJS += $(OUTPUT)builtin-lock.o 371BUILTIN_OBJS += $(OUTPUT)builtin-lock.o
@@ -492,6 +375,20 @@ BUILTIN_OBJS += $(OUTPUT)builtin-inject.o
492 375
493PERFLIBS = $(LIB_FILE) 376PERFLIBS = $(LIB_FILE)
494 377
378# Files needed for the python binding, perf.so
379# pyrf is just an internal name needed for all those wrappers.
380# This has to be in sync with what is in the 'sources' variable in
381# tools/perf/util/setup.py
382
383PYRF_OBJS += $(OUTPUT)util/cpumap.o
384PYRF_OBJS += $(OUTPUT)util/ctype.o
385PYRF_OBJS += $(OUTPUT)util/evlist.o
386PYRF_OBJS += $(OUTPUT)util/evsel.o
387PYRF_OBJS += $(OUTPUT)util/python.o
388PYRF_OBJS += $(OUTPUT)util/thread_map.o
389PYRF_OBJS += $(OUTPUT)util/util.o
390PYRF_OBJS += $(OUTPUT)util/xyarray.o
391
495# 392#
496# Platform specific tweaks 393# Platform specific tweaks
497# 394#
@@ -504,7 +401,7 @@ PERFLIBS = $(LIB_FILE)
504-include config.mak 401-include config.mak
505 402
506ifndef NO_DWARF 403ifndef NO_DWARF
507FLAGS_DWARF=$(ALL_CFLAGS) -I/usr/include/elfutils -ldw -lelf $(ALL_LDFLAGS) $(EXTLIBS) 404FLAGS_DWARF=$(ALL_CFLAGS) -ldw -lelf $(ALL_LDFLAGS) $(EXTLIBS)
508ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF)),y) 405ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF)),y)
509 msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev); 406 msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev);
510 NO_DWARF := 1 407 NO_DWARF := 1
@@ -513,22 +410,6 @@ endif # NO_DWARF
513 410
514-include arch/$(ARCH)/Makefile 411-include arch/$(ARCH)/Makefile
515 412
516ifeq ($(uname_S),Darwin)
517 ifndef NO_FINK
518 ifeq ($(shell test -d /sw/lib && echo y),y)
519 BASIC_CFLAGS += -I/sw/include
520 BASIC_LDFLAGS += -L/sw/lib
521 endif
522 endif
523 ifndef NO_DARWIN_PORTS
524 ifeq ($(shell test -d /opt/local/lib && echo y),y)
525 BASIC_CFLAGS += -I/opt/local/include
526 BASIC_LDFLAGS += -L/opt/local/lib
527 endif
528 endif
529 PTHREAD_LIBS =
530endif
531
532ifneq ($(OUTPUT),) 413ifneq ($(OUTPUT),)
533 BASIC_CFLAGS += -I$(OUTPUT) 414 BASIC_CFLAGS += -I$(OUTPUT)
534endif 415endif
@@ -551,7 +432,7 @@ ifndef NO_DWARF
551ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined) 432ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined)
552 msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled); 433 msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled);
553else 434else
554 BASIC_CFLAGS += -I/usr/include/elfutils -DDWARF_SUPPORT 435 BASIC_CFLAGS += -DDWARF_SUPPORT
555 EXTLIBS += -lelf -ldw 436 EXTLIBS += -lelf -ldw
556 LIB_OBJS += $(OUTPUT)util/probe-finder.o 437 LIB_OBJS += $(OUTPUT)util/probe-finder.o
557endif # PERF_HAVE_DWARF_REGS 438endif # PERF_HAVE_DWARF_REGS
@@ -573,6 +454,7 @@ else
573 LIB_OBJS += $(OUTPUT)util/ui/browsers/annotate.o 454 LIB_OBJS += $(OUTPUT)util/ui/browsers/annotate.o
574 LIB_OBJS += $(OUTPUT)util/ui/browsers/hists.o 455 LIB_OBJS += $(OUTPUT)util/ui/browsers/hists.o
575 LIB_OBJS += $(OUTPUT)util/ui/browsers/map.o 456 LIB_OBJS += $(OUTPUT)util/ui/browsers/map.o
457 LIB_OBJS += $(OUTPUT)util/ui/browsers/top.o
576 LIB_OBJS += $(OUTPUT)util/ui/helpline.o 458 LIB_OBJS += $(OUTPUT)util/ui/helpline.o
577 LIB_OBJS += $(OUTPUT)util/ui/progress.o 459 LIB_OBJS += $(OUTPUT)util/ui/progress.o
578 LIB_OBJS += $(OUTPUT)util/ui/util.o 460 LIB_OBJS += $(OUTPUT)util/ui/util.o
@@ -582,38 +464,97 @@ else
582 LIB_H += util/ui/libslang.h 464 LIB_H += util/ui/libslang.h
583 LIB_H += util/ui/progress.h 465 LIB_H += util/ui/progress.h
584 LIB_H += util/ui/util.h 466 LIB_H += util/ui/util.h
467 LIB_H += util/ui/ui.h
585 endif 468 endif
586endif 469endif
587 470
588ifdef NO_LIBPERL 471ifdef NO_LIBPERL
589 BASIC_CFLAGS += -DNO_LIBPERL 472 BASIC_CFLAGS += -DNO_LIBPERL
590else 473else
591 PERL_EMBED_LDOPTS = `perl -MExtUtils::Embed -e ldopts 2>/dev/null` 474 PERL_EMBED_LDOPTS = $(shell perl -MExtUtils::Embed -e ldopts 2>/dev/null)
475 PERL_EMBED_LDFLAGS = $(call strip-libs,$(PERL_EMBED_LDOPTS))
476 PERL_EMBED_LIBADD = $(call grep-libs,$(PERL_EMBED_LDOPTS))
592 PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null` 477 PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
593 FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS) 478 FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
594 479
595 ifneq ($(call try-cc,$(SOURCE_PERL_EMBED),$(FLAGS_PERL_EMBED)),y) 480 ifneq ($(call try-cc,$(SOURCE_PERL_EMBED),$(FLAGS_PERL_EMBED)),y)
596 BASIC_CFLAGS += -DNO_LIBPERL 481 BASIC_CFLAGS += -DNO_LIBPERL
597 else 482 else
598 ALL_LDFLAGS += $(PERL_EMBED_LDOPTS) 483 ALL_LDFLAGS += $(PERL_EMBED_LDFLAGS)
484 EXTLIBS += $(PERL_EMBED_LIBADD)
599 LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-perl.o 485 LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-perl.o
600 LIB_OBJS += $(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o 486 LIB_OBJS += $(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o
601 endif 487 endif
602endif 488endif
603 489
604ifdef NO_LIBPYTHON 490disable-python = $(eval $(disable-python_code))
605 BASIC_CFLAGS += -DNO_LIBPYTHON 491define disable-python_code
492 BASIC_CFLAGS += -DNO_LIBPYTHON
493 $(if $(1),$(warning No $(1) was found))
494 $(warning Python support won't be built)
495endef
496
497override PYTHON := \
498 $(call get-executable-or-default,PYTHON,python)
499
500ifndef PYTHON
501 $(call disable-python,python interpreter)
502 python-clean :=
606else 503else
607 PYTHON_EMBED_LDOPTS = `python-config --ldflags 2>/dev/null` 504
608 PYTHON_EMBED_CCOPTS = `python-config --cflags 2>/dev/null` 505 PYTHON_WORD := $(call shell-wordify,$(PYTHON))
609 FLAGS_PYTHON_EMBED=$(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS) 506
610 ifneq ($(call try-cc,$(SOURCE_PYTHON_EMBED),$(FLAGS_PYTHON_EMBED)),y) 507 python-clean := $(PYTHON_WORD) util/setup.py clean \
611 BASIC_CFLAGS += -DNO_LIBPYTHON 508 --build-lib='$(OUTPUT)python' \
612 else 509 --build-temp='$(OUTPUT)python/temp'
613 ALL_LDFLAGS += $(PYTHON_EMBED_LDOPTS) 510
614 LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-python.o 511 ifdef NO_LIBPYTHON
615 LIB_OBJS += $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o 512 $(call disable-python)
616 endif 513 else
514
515 override PYTHON_CONFIG := \
516 $(call get-executable-or-default,PYTHON_CONFIG,$(PYTHON)-config)
517
518 ifndef PYTHON_CONFIG
519 $(call disable-python,python-config tool)
520 else
521
522 PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG))
523
524 PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null)
525 PYTHON_EMBED_LDFLAGS := $(call strip-libs,$(PYTHON_EMBED_LDOPTS))
526 PYTHON_EMBED_LIBADD := $(call grep-libs,$(PYTHON_EMBED_LDOPTS))
527 PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
528 FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
529
530 ifneq ($(call try-cc,$(SOURCE_PYTHON_EMBED),$(FLAGS_PYTHON_EMBED)),y)
531 $(call disable-python,Python.h (for Python 2.x))
532 else
533
534 ifneq ($(call try-cc,$(SOURCE_PYTHON_VERSION),$(FLAGS_PYTHON_EMBED)),y)
535 $(warning Python 3 is not yet supported; please set)
536 $(warning PYTHON and/or PYTHON_CONFIG appropriately.)
537 $(warning If you also have Python 2 installed, then)
538 $(warning try something like:)
539 $(warning $(and ,))
540 $(warning $(and ,) make PYTHON=python2)
541 $(warning $(and ,))
542 $(warning Otherwise, disable Python support entirely:)
543 $(warning $(and ,))
544 $(warning $(and ,) make NO_LIBPYTHON=1)
545 $(warning $(and ,))
546 $(error $(and ,))
547 else
548 ALL_LDFLAGS += $(PYTHON_EMBED_LDFLAGS)
549 EXTLIBS += $(PYTHON_EMBED_LIBADD)
550 LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-python.o
551 LIB_OBJS += $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o
552 LANG_BINDINGS += $(OUTPUT)python/perf.so
553 endif
554
555 endif
556 endif
557 endif
617endif 558endif
618 559
619ifdef NO_DEMANGLE 560ifdef NO_DEMANGLE
@@ -653,186 +594,14 @@ else
653 endif 594 endif
654endif 595endif
655 596
656ifndef CC_LD_DYNPATH
657 ifdef NO_R_TO_GCC_LINKER
658 # Some gcc does not accept and pass -R to the linker to specify
659 # the runtime dynamic library path.
660 CC_LD_DYNPATH = -Wl,-rpath,
661 else
662 CC_LD_DYNPATH = -R
663 endif
664endif
665 597
666ifdef NEEDS_SOCKET 598ifdef NO_STRLCPY
667 EXTLIBS += -lsocket 599 BASIC_CFLAGS += -DNO_STRLCPY
668endif
669ifdef NEEDS_NSL
670 EXTLIBS += -lnsl
671endif
672ifdef NO_D_TYPE_IN_DIRENT
673 BASIC_CFLAGS += -DNO_D_TYPE_IN_DIRENT
674endif
675ifdef NO_D_INO_IN_DIRENT
676 BASIC_CFLAGS += -DNO_D_INO_IN_DIRENT
677endif
678ifdef NO_ST_BLOCKS_IN_STRUCT_STAT
679 BASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT
680endif
681ifdef USE_NSEC
682 BASIC_CFLAGS += -DUSE_NSEC
683endif
684ifdef USE_ST_TIMESPEC
685 BASIC_CFLAGS += -DUSE_ST_TIMESPEC
686endif
687ifdef NO_NSEC
688 BASIC_CFLAGS += -DNO_NSEC
689endif
690ifdef NO_C99_FORMAT
691 BASIC_CFLAGS += -DNO_C99_FORMAT
692endif
693ifdef SNPRINTF_RETURNS_BOGUS
694 COMPAT_CFLAGS += -DSNPRINTF_RETURNS_BOGUS
695 COMPAT_OBJS += $(OUTPUT)compat/snprintf.o
696endif
697ifdef FREAD_READS_DIRECTORIES
698 COMPAT_CFLAGS += -DFREAD_READS_DIRECTORIES
699 COMPAT_OBJS += $(OUTPUT)compat/fopen.o
700endif
701ifdef NO_SYMLINK_HEAD
702 BASIC_CFLAGS += -DNO_SYMLINK_HEAD
703endif
704ifdef NO_STRCASESTR
705 COMPAT_CFLAGS += -DNO_STRCASESTR
706 COMPAT_OBJS += $(OUTPUT)compat/strcasestr.o
707endif
708ifdef NO_STRTOUMAX
709 COMPAT_CFLAGS += -DNO_STRTOUMAX
710 COMPAT_OBJS += $(OUTPUT)compat/strtoumax.o
711endif
712ifdef NO_STRTOULL
713 COMPAT_CFLAGS += -DNO_STRTOULL
714endif
715ifdef NO_SETENV
716 COMPAT_CFLAGS += -DNO_SETENV
717 COMPAT_OBJS += $(OUTPUT)compat/setenv.o
718endif
719ifdef NO_MKDTEMP
720 COMPAT_CFLAGS += -DNO_MKDTEMP
721 COMPAT_OBJS += $(OUTPUT)compat/mkdtemp.o
722endif
723ifdef NO_UNSETENV
724 COMPAT_CFLAGS += -DNO_UNSETENV
725 COMPAT_OBJS += $(OUTPUT)compat/unsetenv.o
726endif
727ifdef NO_SYS_SELECT_H
728 BASIC_CFLAGS += -DNO_SYS_SELECT_H
729endif
730ifdef NO_MMAP
731 COMPAT_CFLAGS += -DNO_MMAP
732 COMPAT_OBJS += $(OUTPUT)compat/mmap.o
733else 600else
734 ifdef USE_WIN32_MMAP 601 ifneq ($(call try-cc,$(SOURCE_STRLCPY),),y)
735 COMPAT_CFLAGS += -DUSE_WIN32_MMAP 602 BASIC_CFLAGS += -DNO_STRLCPY
736 COMPAT_OBJS += $(OUTPUT)compat/win32mmap.o
737 endif 603 endif
738endif 604endif
739ifdef NO_PREAD
740 COMPAT_CFLAGS += -DNO_PREAD
741 COMPAT_OBJS += $(OUTPUT)compat/pread.o
742endif
743ifdef NO_FAST_WORKING_DIRECTORY
744 BASIC_CFLAGS += -DNO_FAST_WORKING_DIRECTORY
745endif
746ifdef NO_TRUSTABLE_FILEMODE
747 BASIC_CFLAGS += -DNO_TRUSTABLE_FILEMODE
748endif
749ifdef NO_IPV6
750 BASIC_CFLAGS += -DNO_IPV6
751endif
752ifdef NO_UINTMAX_T
753 BASIC_CFLAGS += -Duintmax_t=uint32_t
754endif
755ifdef NO_SOCKADDR_STORAGE
756ifdef NO_IPV6
757 BASIC_CFLAGS += -Dsockaddr_storage=sockaddr_in
758else
759 BASIC_CFLAGS += -Dsockaddr_storage=sockaddr_in6
760endif
761endif
762ifdef NO_INET_NTOP
763 LIB_OBJS += $(OUTPUT)compat/inet_ntop.o
764endif
765ifdef NO_INET_PTON
766 LIB_OBJS += $(OUTPUT)compat/inet_pton.o
767endif
768
769ifdef NO_ICONV
770 BASIC_CFLAGS += -DNO_ICONV
771endif
772
773ifdef OLD_ICONV
774 BASIC_CFLAGS += -DOLD_ICONV
775endif
776
777ifdef NO_DEFLATE_BOUND
778 BASIC_CFLAGS += -DNO_DEFLATE_BOUND
779endif
780
781ifdef PPC_SHA1
782 SHA1_HEADER = "ppc/sha1.h"
783 LIB_OBJS += $(OUTPUT)ppc/sha1.o ppc/sha1ppc.o
784else
785ifdef ARM_SHA1
786 SHA1_HEADER = "arm/sha1.h"
787 LIB_OBJS += $(OUTPUT)arm/sha1.o $(OUTPUT)arm/sha1_arm.o
788else
789ifdef MOZILLA_SHA1
790 SHA1_HEADER = "mozilla-sha1/sha1.h"
791 LIB_OBJS += $(OUTPUT)mozilla-sha1/sha1.o
792else
793 SHA1_HEADER = <openssl/sha.h>
794 EXTLIBS += $(LIB_4_CRYPTO)
795endif
796endif
797endif
798ifdef NO_PERL_MAKEMAKER
799 export NO_PERL_MAKEMAKER
800endif
801ifdef NO_HSTRERROR
802 COMPAT_CFLAGS += -DNO_HSTRERROR
803 COMPAT_OBJS += $(OUTPUT)compat/hstrerror.o
804endif
805ifdef NO_MEMMEM
806 COMPAT_CFLAGS += -DNO_MEMMEM
807 COMPAT_OBJS += $(OUTPUT)compat/memmem.o
808endif
809ifdef INTERNAL_QSORT
810 COMPAT_CFLAGS += -DINTERNAL_QSORT
811 COMPAT_OBJS += $(OUTPUT)compat/qsort.o
812endif
813ifdef RUNTIME_PREFIX
814 COMPAT_CFLAGS += -DRUNTIME_PREFIX
815endif
816
817ifdef DIR_HAS_BSD_GROUP_SEMANTICS
818 COMPAT_CFLAGS += -DDIR_HAS_BSD_GROUP_SEMANTICS
819endif
820ifdef NO_EXTERNAL_GREP
821 BASIC_CFLAGS += -DNO_EXTERNAL_GREP
822endif
823
824ifeq ($(PERL_PATH),)
825NO_PERL=NoThanks
826endif
827
828QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir
829QUIET_SUBDIR1 =
830
831ifneq ($(findstring $(MAKEFLAGS),w),w)
832PRINT_DIR = --no-print-directory
833else # "make -w"
834NO_SUBDIR = :
835endif
836 605
837ifneq ($(findstring $(MAKEFLAGS),s),s) 606ifneq ($(findstring $(MAKEFLAGS),s),s)
838ifndef V 607ifndef V
@@ -840,14 +609,7 @@ ifndef V
840 QUIET_AR = @echo ' ' AR $@; 609 QUIET_AR = @echo ' ' AR $@;
841 QUIET_LINK = @echo ' ' LINK $@; 610 QUIET_LINK = @echo ' ' LINK $@;
842 QUIET_MKDIR = @echo ' ' MKDIR $@; 611 QUIET_MKDIR = @echo ' ' MKDIR $@;
843 QUIET_BUILT_IN = @echo ' ' BUILTIN $@;
844 QUIET_GEN = @echo ' ' GEN $@; 612 QUIET_GEN = @echo ' ' GEN $@;
845 QUIET_SUBDIR0 = +@subdir=
846 QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \
847 $(MAKE) $(PRINT_DIR) -C $$subdir
848 export V
849 export QUIET_GEN
850 export QUIET_BUILT_IN
851endif 613endif
852endif 614endif
853 615
@@ -857,7 +619,6 @@ endif
857 619
858# Shell quote (do not use $(call) to accommodate ancient setups); 620# Shell quote (do not use $(call) to accommodate ancient setups);
859 621
860SHA1_HEADER_SQ = $(subst ','\'',$(SHA1_HEADER))
861ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG)) 622ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG))
862 623
863DESTDIR_SQ = $(subst ','\'',$(DESTDIR)) 624DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
@@ -871,47 +632,38 @@ htmldir_SQ = $(subst ','\'',$(htmldir))
871prefix_SQ = $(subst ','\'',$(prefix)) 632prefix_SQ = $(subst ','\'',$(prefix))
872 633
873SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) 634SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
874PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH))
875
876LIBS = $(PERFLIBS) $(EXTLIBS)
877 635
878BASIC_CFLAGS += -DSHA1_HEADER='$(SHA1_HEADER_SQ)' \ 636LIBS = -Wl,--whole-archive $(PERFLIBS) -Wl,--no-whole-archive -Wl,--start-group $(EXTLIBS) -Wl,--end-group
879 $(COMPAT_CFLAGS)
880LIB_OBJS += $(COMPAT_OBJS)
881 637
882ALL_CFLAGS += $(BASIC_CFLAGS) 638ALL_CFLAGS += $(BASIC_CFLAGS)
639ALL_CFLAGS += $(ARCH_CFLAGS)
883ALL_LDFLAGS += $(BASIC_LDFLAGS) 640ALL_LDFLAGS += $(BASIC_LDFLAGS)
884 641
885export TAR INSTALL DESTDIR SHELL_PATH 642export INSTALL SHELL_PATH
886 643
887 644
888### Build rules 645### Build rules
889 646
890SHELL = $(SHELL_PATH) 647SHELL = $(SHELL_PATH)
891 648
892all:: shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) $(OUTPUT)PERF-BUILD-OPTIONS 649all: shell_compatibility_test $(ALL_PROGRAMS) $(LANG_BINDINGS) $(OTHER_PROGRAMS)
893ifneq (,$X)
894 $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) perf$X)), test '$p' -ef '$p$X' || $(RM) '$p';)
895endif
896
897all::
898 650
899please_set_SHELL_PATH_to_a_more_modern_shell: 651please_set_SHELL_PATH_to_a_more_modern_shell:
900 @$$(:) 652 @$$(:)
901 653
902shell_compatibility_test: please_set_SHELL_PATH_to_a_more_modern_shell 654shell_compatibility_test: please_set_SHELL_PATH_to_a_more_modern_shell
903 655
904strip: $(PROGRAMS) $(OUTPUT)perf$X 656strip: $(PROGRAMS) $(OUTPUT)perf
905 $(STRIP) $(STRIP_OPTS) $(PROGRAMS) $(OUTPUT)perf$X 657 $(STRIP) $(STRIP_OPTS) $(PROGRAMS) $(OUTPUT)perf
906 658
907$(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS 659$(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
908 $(QUIET_CC)$(CC) -DPERF_VERSION='"$(PERF_VERSION)"' \ 660 $(QUIET_CC)$(CC) -DPERF_VERSION='"$(PERF_VERSION)"' \
909 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ 661 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
910 $(ALL_CFLAGS) -c $(filter %.c,$^) -o $@ 662 $(ALL_CFLAGS) -c $(filter %.c,$^) -o $@
911 663
912$(OUTPUT)perf$X: $(OUTPUT)perf.o $(BUILTIN_OBJS) $(PERFLIBS) 664$(OUTPUT)perf: $(OUTPUT)perf.o $(BUILTIN_OBJS) $(PERFLIBS)
913 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(OUTPUT)perf.o \ 665 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) $(OUTPUT)perf.o \
914 $(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS) 666 $(BUILTIN_OBJS) $(LIBS) -o $@
915 667
916$(OUTPUT)builtin-help.o: builtin-help.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS 668$(OUTPUT)builtin-help.o: builtin-help.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
917 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \ 669 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \
@@ -925,39 +677,17 @@ $(OUTPUT)builtin-timechart.o: builtin-timechart.c $(OUTPUT)common-cmds.h $(OUTPU
925 '-DPERF_MAN_PATH="$(mandir_SQ)"' \ 677 '-DPERF_MAN_PATH="$(mandir_SQ)"' \
926 '-DPERF_INFO_PATH="$(infodir_SQ)"' $< 678 '-DPERF_INFO_PATH="$(infodir_SQ)"' $<
927 679
928$(BUILT_INS): $(OUTPUT)perf$X
929 $(QUIET_BUILT_IN)$(RM) $@ && \
930 ln perf$X $@ 2>/dev/null || \
931 ln -s perf$X $@ 2>/dev/null || \
932 cp perf$X $@
933
934$(OUTPUT)common-cmds.h: util/generate-cmdlist.sh command-list.txt 680$(OUTPUT)common-cmds.h: util/generate-cmdlist.sh command-list.txt
935 681
936$(OUTPUT)common-cmds.h: $(wildcard Documentation/perf-*.txt) 682$(OUTPUT)common-cmds.h: $(wildcard Documentation/perf-*.txt)
937 $(QUIET_GEN). util/generate-cmdlist.sh > $@+ && mv $@+ $@ 683 $(QUIET_GEN). util/generate-cmdlist.sh > $@+ && mv $@+ $@
938 684
939$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh 685$(SCRIPTS) : % : %.sh
940 $(QUIET_GEN)$(RM) $(OUTPUT)$@ $(OUTPUT)$@+ && \ 686 $(QUIET_GEN)$(INSTALL) '$@.sh' '$(OUTPUT)$@'
941 sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
942 -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \
943 -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \
944 -e 's/@@PERF_VERSION@@/$(PERF_VERSION)/g' \
945 -e 's/@@NO_CURL@@/$(NO_CURL)/g' \
946 $@.sh > $(OUTPUT)$@+ && \
947 chmod +x $(OUTPUT)$@+ && \
948 mv $(OUTPUT)$@+ $(OUTPUT)$@
949
950configure: configure.ac
951 $(QUIET_GEN)$(RM) $@ $<+ && \
952 sed -e 's/@@PERF_VERSION@@/$(PERF_VERSION)/g' \
953 $< > $<+ && \
954 autoconf -o $@ $<+ && \
955 $(RM) $<+
956 687
957# These can record PERF_VERSION 688# These can record PERF_VERSION
958$(OUTPUT)perf.o perf.spec \ 689$(OUTPUT)perf.o perf.spec \
959 $(patsubst %.sh,%,$(SCRIPT_SH)) \ 690 $(SCRIPTS) \
960 $(patsubst %.perl,%,$(SCRIPT_PERL)) \
961 : $(OUTPUT)PERF-VERSION-FILE 691 : $(OUTPUT)PERF-VERSION-FILE
962 692
963$(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS 693$(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS
@@ -974,9 +704,6 @@ $(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS
974 '-DPREFIX="$(prefix_SQ)"' \ 704 '-DPREFIX="$(prefix_SQ)"' \
975 $< 705 $<
976 706
977$(OUTPUT)builtin-init-db.o: builtin-init-db.c $(OUTPUT)PERF-CFLAGS
978 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DDEFAULT_PERF_TEMPLATE_DIR='"$(template_dir_SQ)"' $<
979
980$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS 707$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS
981 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< 708 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
982 709
@@ -986,6 +713,9 @@ $(OUTPUT)util/ui/browser.o: util/ui/browser.c $(OUTPUT)PERF-CFLAGS
986$(OUTPUT)util/ui/browsers/annotate.o: util/ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS 713$(OUTPUT)util/ui/browsers/annotate.o: util/ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS
987 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 714 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
988 715
716$(OUTPUT)util/ui/browsers/top.o: util/ui/browsers/top.c $(OUTPUT)PERF-CFLAGS
717 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
718
989$(OUTPUT)util/ui/browsers/hists.o: util/ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS 719$(OUTPUT)util/ui/browsers/hists.o: util/ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS
990 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 720 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
991 721
@@ -1007,12 +737,11 @@ $(OUTPUT)util/scripting-engines/trace-event-python.o: util/scripting-engines/tra
1007$(OUTPUT)scripts/python/Perf-Trace-Util/Context.o: scripts/python/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS 737$(OUTPUT)scripts/python/Perf-Trace-Util/Context.o: scripts/python/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS
1008 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $< 738 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $<
1009 739
1010$(OUTPUT)perf-%$X: %.o $(PERFLIBS) 740$(OUTPUT)perf-%: %.o $(PERFLIBS)
1011 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) 741 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
1012 742
1013$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H) 743$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
1014$(patsubst perf-%$X,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h) 744$(patsubst perf-%,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
1015builtin-revert.o wt-status.o: wt-status.h
1016 745
1017# we compile into subdirectories. if the target directory is not the source directory, they might not exists. So 746# we compile into subdirectories. if the target directory is not the source directory, they might not exists. So
1018# we depend the various files onto their directories. 747# we depend the various files onto their directories.
@@ -1025,6 +754,36 @@ $(sort $(dir $(DIRECTORY_DEPS))):
1025$(LIB_FILE): $(LIB_OBJS) 754$(LIB_FILE): $(LIB_OBJS)
1026 $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS) 755 $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS)
1027 756
757help:
758 @echo 'Perf make targets:'
759 @echo ' doc - make *all* documentation (see below)'
760 @echo ' man - make manpage documentation (access with man <foo>)'
761 @echo ' html - make html documentation'
762 @echo ' info - make GNU info documentation (access with info <foo>)'
763 @echo ' pdf - make pdf documentation'
764 @echo ' TAGS - use etags to make tag information for source browsing'
765 @echo ' tags - use ctags to make tag information for source browsing'
766 @echo ' cscope - use cscope to make interactive browsing database'
767 @echo ''
768 @echo 'Perf install targets:'
769 @echo ' NOTE: documentation build requires asciidoc, xmlto packages to be installed'
770 @echo ' HINT: use "make prefix=<path> <install target>" to install to a particular'
771 @echo ' path like make prefix=/usr/local install install-doc'
772 @echo ' install - install compiled binaries'
773 @echo ' install-doc - install *all* documentation'
774 @echo ' install-man - install manpage documentation'
775 @echo ' install-html - install html documentation'
776 @echo ' install-info - install GNU info documentation'
777 @echo ' install-pdf - install pdf documentation'
778 @echo ''
779 @echo ' quick-install-doc - alias for quick-install-man'
780 @echo ' quick-install-man - install the documentation quickly'
781 @echo ' quick-install-html - install the html documentation quickly'
782 @echo ''
783 @echo 'Perf maintainer targets:'
784 @echo ' distclean - alias to clean'
785 @echo ' clean - clean all binary objects and build output'
786
1028doc: 787doc:
1029 $(MAKE) -C Documentation all 788 $(MAKE) -C Documentation all
1030 789
@@ -1063,30 +822,12 @@ $(OUTPUT)PERF-CFLAGS: .FORCE-PERF-CFLAGS
1063 echo "$$FLAGS" >$(OUTPUT)PERF-CFLAGS; \ 822 echo "$$FLAGS" >$(OUTPUT)PERF-CFLAGS; \
1064 fi 823 fi
1065 824
1066# We need to apply sq twice, once to protect from the shell
1067# that runs $(OUTPUT)PERF-BUILD-OPTIONS, and then again to protect it
1068# and the first level quoting from the shell that runs "echo".
1069$(OUTPUT)PERF-BUILD-OPTIONS: .FORCE-PERF-BUILD-OPTIONS
1070 @echo SHELL_PATH=\''$(subst ','\'',$(SHELL_PATH_SQ))'\' >$@
1071 @echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@
1072 @echo NO_CURL=\''$(subst ','\'',$(subst ','\'',$(NO_CURL)))'\' >>$@
1073 @echo NO_PERL=\''$(subst ','\'',$(subst ','\'',$(NO_PERL)))'\' >>$@
1074
1075### Testing rules 825### Testing rules
1076 826
1077#
1078# None right now:
1079#
1080# TEST_PROGRAMS += test-something$X
1081
1082all:: $(TEST_PROGRAMS)
1083
1084# GNU make supports exporting all variables by "export" without parameters. 827# GNU make supports exporting all variables by "export" without parameters.
1085# However, the environment gets quite big, and some programs have problems 828# However, the environment gets quite big, and some programs have problems
1086# with that. 829# with that.
1087 830
1088export NO_SVN_TESTS
1089
1090check: $(OUTPUT)common-cmds.h 831check: $(OUTPUT)common-cmds.h
1091 if sparse; \ 832 if sparse; \
1092 then \ 833 then \
@@ -1095,33 +836,21 @@ check: $(OUTPUT)common-cmds.h
1095 sparse $(ALL_CFLAGS) $(SPARSE_FLAGS) $$i || exit; \ 836 sparse $(ALL_CFLAGS) $(SPARSE_FLAGS) $$i || exit; \
1096 done; \ 837 done; \
1097 else \ 838 else \
1098 echo 2>&1 "Did you mean 'make test'?"; \
1099 exit 1; \ 839 exit 1; \
1100 fi 840 fi
1101 841
1102remove-dashes:
1103 ./fixup-builtins $(BUILT_INS) $(PROGRAMS) $(SCRIPTS)
1104
1105### Installation rules 842### Installation rules
1106 843
1107ifneq ($(filter /%,$(firstword $(template_dir))),)
1108template_instdir = $(template_dir)
1109else
1110template_instdir = $(prefix)/$(template_dir)
1111endif
1112export template_instdir
1113
1114ifneq ($(filter /%,$(firstword $(perfexecdir))),) 844ifneq ($(filter /%,$(firstword $(perfexecdir))),)
1115perfexec_instdir = $(perfexecdir) 845perfexec_instdir = $(perfexecdir)
1116else 846else
1117perfexec_instdir = $(prefix)/$(perfexecdir) 847perfexec_instdir = $(prefix)/$(perfexecdir)
1118endif 848endif
1119perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir)) 849perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir))
1120export perfexec_instdir
1121 850
1122install: all 851install: all
1123 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' 852 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
1124 $(INSTALL) $(OUTPUT)perf$X '$(DESTDIR_SQ)$(bindir_SQ)' 853 $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)'
1125 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace' 854 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
1126 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin' 855 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
1127 $(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' 856 $(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
@@ -1134,14 +863,6 @@ install: all
1134 $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python' 863 $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python'
1135 $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin' 864 $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
1136 865
1137ifdef BUILT_INS
1138 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
1139 $(INSTALL) $(BUILT_INS) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
1140ifneq (,$X)
1141 $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) $(OUTPUT)perf$X)), $(RM) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/$p';)
1142endif
1143endif
1144
1145install-doc: 866install-doc:
1146 $(MAKE) -C Documentation install 867 $(MAKE) -C Documentation install
1147 868
@@ -1166,104 +887,16 @@ quick-install-man:
1166quick-install-html: 887quick-install-html:
1167 $(MAKE) -C Documentation quick-install-html 888 $(MAKE) -C Documentation quick-install-html
1168 889
1169
1170### Maintainer's dist rules
1171#
1172# None right now
1173#
1174#
1175# perf.spec: perf.spec.in
1176# sed -e 's/@@VERSION@@/$(PERF_VERSION)/g' < $< > $@+
1177# mv $@+ $@
1178#
1179# PERF_TARNAME=perf-$(PERF_VERSION)
1180# dist: perf.spec perf-archive$(X) configure
1181# ./perf-archive --format=tar \
1182# --prefix=$(PERF_TARNAME)/ HEAD^{tree} > $(PERF_TARNAME).tar
1183# @mkdir -p $(PERF_TARNAME)
1184# @cp perf.spec configure $(PERF_TARNAME)
1185# @echo $(PERF_VERSION) > $(PERF_TARNAME)/version
1186# $(TAR) rf $(PERF_TARNAME).tar \
1187# $(PERF_TARNAME)/perf.spec \
1188# $(PERF_TARNAME)/configure \
1189# $(PERF_TARNAME)/version
1190# @$(RM) -r $(PERF_TARNAME)
1191# gzip -f -9 $(PERF_TARNAME).tar
1192#
1193# htmldocs = perf-htmldocs-$(PERF_VERSION)
1194# manpages = perf-manpages-$(PERF_VERSION)
1195# dist-doc:
1196# $(RM) -r .doc-tmp-dir
1197# mkdir .doc-tmp-dir
1198# $(MAKE) -C Documentation WEBDOC_DEST=../.doc-tmp-dir install-webdoc
1199# cd .doc-tmp-dir && $(TAR) cf ../$(htmldocs).tar .
1200# gzip -n -9 -f $(htmldocs).tar
1201# :
1202# $(RM) -r .doc-tmp-dir
1203# mkdir -p .doc-tmp-dir/man1 .doc-tmp-dir/man5 .doc-tmp-dir/man7
1204# $(MAKE) -C Documentation DESTDIR=./ \
1205# man1dir=../.doc-tmp-dir/man1 \
1206# man5dir=../.doc-tmp-dir/man5 \
1207# man7dir=../.doc-tmp-dir/man7 \
1208# install
1209# cd .doc-tmp-dir && $(TAR) cf ../$(manpages).tar .
1210# gzip -n -9 -f $(manpages).tar
1211# $(RM) -r .doc-tmp-dir
1212#
1213# rpm: dist
1214# $(RPMBUILD) -ta $(PERF_TARNAME).tar.gz
1215
1216### Cleaning rules 890### Cleaning rules
1217 891
1218distclean: clean
1219# $(RM) configure
1220
1221clean: 892clean:
1222 $(RM) *.o */*.o */*/*.o */*/*/*.o $(LIB_FILE) 893 $(RM) $(OUTPUT){*.o,*/*.o,*/*/*.o,*/*/*/*.o,$(LIB_FILE),perf-archive}
1223 $(RM) $(ALL_PROGRAMS) $(BUILT_INS) perf$X 894 $(RM) $(ALL_PROGRAMS) perf
1224 $(RM) $(TEST_PROGRAMS)
1225 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* 895 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope*
1226 $(RM) -r autom4te.cache
1227 $(RM) config.log config.mak.autogen config.mak.append config.status config.cache
1228 $(RM) -r $(PERF_TARNAME) .doc-tmp-dir
1229 $(RM) $(PERF_TARNAME).tar.gz perf-core_$(PERF_VERSION)-*.tar.gz
1230 $(RM) $(htmldocs).tar.gz $(manpages).tar.gz
1231 $(MAKE) -C Documentation/ clean 896 $(MAKE) -C Documentation/ clean
1232 $(RM) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS $(OUTPUT)PERF-BUILD-OPTIONS 897 $(RM) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS
898 $(python-clean)
1233 899
1234.PHONY: all install clean strip 900.PHONY: all install clean strip
1235.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell 901.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
1236.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS 902.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS
1237.PHONY: .FORCE-PERF-BUILD-OPTIONS
1238
1239### Make sure built-ins do not have dups and listed in perf.c
1240#
1241check-builtins::
1242 ./check-builtins.sh
1243
1244### Test suite coverage testing
1245#
1246# None right now
1247#
1248# .PHONY: coverage coverage-clean coverage-build coverage-report
1249#
1250# coverage:
1251# $(MAKE) coverage-build
1252# $(MAKE) coverage-report
1253#
1254# coverage-clean:
1255# rm -f *.gcda *.gcno
1256#
1257# COVERAGE_CFLAGS = $(CFLAGS) -O0 -ftest-coverage -fprofile-arcs
1258# COVERAGE_LDFLAGS = $(CFLAGS) -O0 -lgcov
1259#
1260# coverage-build: coverage-clean
1261# $(MAKE) CFLAGS="$(COVERAGE_CFLAGS)" LDFLAGS="$(COVERAGE_LDFLAGS)" all
1262# $(MAKE) CFLAGS="$(COVERAGE_CFLAGS)" LDFLAGS="$(COVERAGE_LDFLAGS)" \
1263# -j1 test
1264#
1265# coverage-report:
1266# gcov -b *.c */*.c
1267# grep '^function.*called 0 ' *.c.gcov */*.c.gcov \
1268# | sed -e 's/\([^:]*\)\.gcov: *function \([^ ]*\) called.*/\1: \2/' \
1269# | tee coverage-untested-functions
diff --git a/tools/perf/arch/s390/Makefile b/tools/perf/arch/s390/Makefile
new file mode 100644
index 000000000000..15130b50dfe3
--- /dev/null
+++ b/tools/perf/arch/s390/Makefile
@@ -0,0 +1,4 @@
1ifndef NO_DWARF
2PERF_HAVE_DWARF_REGS := 1
3LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
4endif
diff --git a/tools/perf/arch/s390/util/dwarf-regs.c b/tools/perf/arch/s390/util/dwarf-regs.c
new file mode 100644
index 000000000000..e19653e025fa
--- /dev/null
+++ b/tools/perf/arch/s390/util/dwarf-regs.c
@@ -0,0 +1,22 @@
1/*
2 * Mapping of DWARF debug register numbers into register names.
3 *
4 * Copyright IBM Corp. 2010
5 * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>,
6 *
7 */
8
9#include <libio.h>
10#include <dwarf-regs.h>
11
12#define NUM_GPRS 16
13
14static const char *gpr_names[NUM_GPRS] = {
15 "%r0", "%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7",
16 "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15",
17};
18
19const char *get_arch_regstr(unsigned int n)
20{
21 return (n >= NUM_GPRS) ? NULL : gpr_names[n];
22}
diff --git a/tools/perf/bench/mem-memcpy-arch.h b/tools/perf/bench/mem-memcpy-arch.h
new file mode 100644
index 000000000000..a72e36cb5394
--- /dev/null
+++ b/tools/perf/bench/mem-memcpy-arch.h
@@ -0,0 +1,12 @@
1
2#ifdef ARCH_X86_64
3
4#define MEMCPY_FN(fn, name, desc) \
5 extern void *fn(void *, const void *, size_t);
6
7#include "mem-memcpy-x86-64-asm-def.h"
8
9#undef MEMCPY_FN
10
11#endif
12
diff --git a/tools/perf/bench/mem-memcpy-x86-64-asm-def.h b/tools/perf/bench/mem-memcpy-x86-64-asm-def.h
new file mode 100644
index 000000000000..d588b87696fc
--- /dev/null
+++ b/tools/perf/bench/mem-memcpy-x86-64-asm-def.h
@@ -0,0 +1,4 @@
1
2MEMCPY_FN(__memcpy,
3 "x86-64-unrolled",
4 "unrolled 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
new file mode 100644
index 000000000000..a57b66e853c2
--- /dev/null
+++ b/tools/perf/bench/mem-memcpy-x86-64-asm.S
@@ -0,0 +1,2 @@
1
2#include "../../../arch/x86/lib/memcpy_64.S"
diff --git a/tools/perf/bench/mem-memcpy.c b/tools/perf/bench/mem-memcpy.c
index 38dae7465142..db82021f4b91 100644
--- a/tools/perf/bench/mem-memcpy.c
+++ b/tools/perf/bench/mem-memcpy.c
@@ -12,6 +12,7 @@
12#include "../util/parse-options.h" 12#include "../util/parse-options.h"
13#include "../util/header.h" 13#include "../util/header.h"
14#include "bench.h" 14#include "bench.h"
15#include "mem-memcpy-arch.h"
15 16
16#include <stdio.h> 17#include <stdio.h>
17#include <stdlib.h> 18#include <stdlib.h>
@@ -23,8 +24,10 @@
23 24
24static const char *length_str = "1MB"; 25static const char *length_str = "1MB";
25static const char *routine = "default"; 26static const char *routine = "default";
26static bool use_clock = false; 27static bool use_clock;
27static int clock_fd; 28static int clock_fd;
29static bool only_prefault;
30static bool no_prefault;
28 31
29static const struct option options[] = { 32static const struct option options[] = {
30 OPT_STRING('l', "length", &length_str, "1MB", 33 OPT_STRING('l', "length", &length_str, "1MB",
@@ -34,19 +37,33 @@ static const struct option options[] = {
34 "Specify routine to copy"), 37 "Specify routine to copy"),
35 OPT_BOOLEAN('c', "clock", &use_clock, 38 OPT_BOOLEAN('c', "clock", &use_clock,
36 "Use CPU clock for measuring"), 39 "Use CPU clock for measuring"),
40 OPT_BOOLEAN('o', "only-prefault", &only_prefault,
41 "Show only the result with page faults before memcpy()"),
42 OPT_BOOLEAN('n', "no-prefault", &no_prefault,
43 "Show only the result without page faults before memcpy()"),
37 OPT_END() 44 OPT_END()
38}; 45};
39 46
47typedef void *(*memcpy_t)(void *, const void *, size_t);
48
40struct routine { 49struct routine {
41 const char *name; 50 const char *name;
42 const char *desc; 51 const char *desc;
43 void * (*fn)(void *dst, const void *src, size_t len); 52 memcpy_t fn;
44}; 53};
45 54
46struct routine routines[] = { 55struct routine routines[] = {
47 { "default", 56 { "default",
48 "Default memcpy() provided by glibc", 57 "Default memcpy() provided by glibc",
49 memcpy }, 58 memcpy },
59#ifdef ARCH_X86_64
60
61#define MEMCPY_FN(fn, name, desc) { name, desc, fn },
62#include "mem-memcpy-x86-64-asm-def.h"
63#undef MEMCPY_FN
64
65#endif
66
50 { NULL, 67 { NULL,
51 NULL, 68 NULL,
52 NULL } 69 NULL }
@@ -89,29 +106,98 @@ static double timeval2double(struct timeval *ts)
89 (double)ts->tv_usec / (double)1000000; 106 (double)ts->tv_usec / (double)1000000;
90} 107}
91 108
109static void alloc_mem(void **dst, void **src, size_t length)
110{
111 *dst = zalloc(length);
112 if (!dst)
113 die("memory allocation failed - maybe length is too large?\n");
114
115 *src = zalloc(length);
116 if (!src)
117 die("memory allocation failed - maybe length is too large?\n");
118}
119
120static u64 do_memcpy_clock(memcpy_t fn, size_t len, bool prefault)
121{
122 u64 clock_start = 0ULL, clock_end = 0ULL;
123 void *src = NULL, *dst = NULL;
124
125 alloc_mem(&src, &dst, len);
126
127 if (prefault)
128 fn(dst, src, len);
129
130 clock_start = get_clock();
131 fn(dst, src, len);
132 clock_end = get_clock();
133
134 free(src);
135 free(dst);
136 return clock_end - clock_start;
137}
138
139static double do_memcpy_gettimeofday(memcpy_t fn, size_t len, bool prefault)
140{
141 struct timeval tv_start, tv_end, tv_diff;
142 void *src = NULL, *dst = NULL;
143
144 alloc_mem(&src, &dst, len);
145
146 if (prefault)
147 fn(dst, src, len);
148
149 BUG_ON(gettimeofday(&tv_start, NULL));
150 fn(dst, src, len);
151 BUG_ON(gettimeofday(&tv_end, NULL));
152
153 timersub(&tv_end, &tv_start, &tv_diff);
154
155 free(src);
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
92int bench_mem_memcpy(int argc, const char **argv, 173int bench_mem_memcpy(int argc, const char **argv,
93 const char *prefix __used) 174 const char *prefix __used)
94{ 175{
95 int i; 176 int i;
96 void *dst, *src; 177 size_t len;
97 size_t length; 178 double result_bps[2];
98 double bps = 0.0; 179 u64 result_clock[2];
99 struct timeval tv_start, tv_end, tv_diff;
100 u64 clock_start, clock_end, clock_diff;
101 180
102 clock_start = clock_end = clock_diff = 0ULL;
103 argc = parse_options(argc, argv, options, 181 argc = parse_options(argc, argv, options,
104 bench_mem_memcpy_usage, 0); 182 bench_mem_memcpy_usage, 0);
105 183
106 tv_diff.tv_sec = 0; 184 if (use_clock)
107 tv_diff.tv_usec = 0; 185 init_clock();
108 length = (size_t)perf_atoll((char *)length_str); 186
187 len = (size_t)perf_atoll((char *)length_str);
109 188
110 if ((s64)length <= 0) { 189 result_clock[0] = result_clock[1] = 0ULL;
190 result_bps[0] = result_bps[1] = 0.0;
191
192 if ((s64)len <= 0) {
111 fprintf(stderr, "Invalid length:%s\n", length_str); 193 fprintf(stderr, "Invalid length:%s\n", length_str);
112 return 1; 194 return 1;
113 } 195 }
114 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
115 for (i = 0; routines[i].name; i++) { 201 for (i = 0; routines[i].name; i++) {
116 if (!strcmp(routines[i].name, routine)) 202 if (!strcmp(routines[i].name, routine))
117 break; 203 break;
@@ -126,61 +212,80 @@ int bench_mem_memcpy(int argc, const char **argv,
126 return 1; 212 return 1;
127 } 213 }
128 214
129 dst = zalloc(length); 215 if (bench_format == BENCH_FORMAT_DEFAULT)
130 if (!dst) 216 printf("# Copying %s Bytes ...\n\n", length_str);
131 die("memory allocation failed - maybe length is too large?\n");
132
133 src = zalloc(length);
134 if (!src)
135 die("memory allocation failed - maybe length is too large?\n");
136
137 if (bench_format == BENCH_FORMAT_DEFAULT) {
138 printf("# Copying %s Bytes from %p to %p ...\n\n",
139 length_str, src, dst);
140 }
141
142 if (use_clock) {
143 init_clock();
144 clock_start = get_clock();
145 } else {
146 BUG_ON(gettimeofday(&tv_start, NULL));
147 }
148
149 routines[i].fn(dst, src, length);
150 217
151 if (use_clock) { 218 if (!only_prefault && !no_prefault) {
152 clock_end = get_clock(); 219 /* show both of results */
153 clock_diff = clock_end - clock_start; 220 if (use_clock) {
221 result_clock[0] =
222 do_memcpy_clock(routines[i].fn, len, false);
223 result_clock[1] =
224 do_memcpy_clock(routines[i].fn, len, true);
225 } else {
226 result_bps[0] =
227 do_memcpy_gettimeofday(routines[i].fn,
228 len, false);
229 result_bps[1] =
230 do_memcpy_gettimeofday(routines[i].fn,
231 len, true);
232 }
154 } else { 233 } else {
155 BUG_ON(gettimeofday(&tv_end, NULL)); 234 if (use_clock) {
156 timersub(&tv_end, &tv_start, &tv_diff); 235 result_clock[pf] =
157 bps = (double)((double)length / timeval2double(&tv_diff)); 236 do_memcpy_clock(routines[i].fn,
237 len, only_prefault);
238 } else {
239 result_bps[pf] =
240 do_memcpy_gettimeofday(routines[i].fn,
241 len, only_prefault);
242 }
158 } 243 }
159 244
160 switch (bench_format) { 245 switch (bench_format) {
161 case BENCH_FORMAT_DEFAULT: 246 case BENCH_FORMAT_DEFAULT:
162 if (use_clock) { 247 if (!only_prefault && !no_prefault) {
163 printf(" %14lf Clock/Byte\n", 248 if (use_clock) {
164 (double)clock_diff / (double)length); 249 printf(" %14lf Clock/Byte\n",
165 } else { 250 (double)result_clock[0]
166 if (bps < K) 251 / (double)len);
167 printf(" %14lf B/Sec\n", bps); 252 printf(" %14lf Clock/Byte (with prefault)\n",
168 else if (bps < K * K) 253 (double)result_clock[1]
169 printf(" %14lfd KB/Sec\n", bps / 1024); 254 / (double)len);
170 else if (bps < K * K * K) 255 } else {
171 printf(" %14lf MB/Sec\n", bps / 1024 / 1024); 256 print_bps(result_bps[0]);
172 else { 257 printf("\n");
173 printf(" %14lf GB/Sec\n", 258 print_bps(result_bps[1]);
174 bps / 1024 / 1024 / 1024); 259 printf(" (with prefault)\n");
175 } 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)" : "");
176 } 270 }
177 break; 271 break;
178 case BENCH_FORMAT_SIMPLE: 272 case BENCH_FORMAT_SIMPLE:
179 if (use_clock) { 273 if (!only_prefault && !no_prefault) {
180 printf("%14lf\n", 274 if (use_clock) {
181 (double)clock_diff / (double)length); 275 printf("%lf %lf\n",
182 } else 276 (double)result_clock[0] / (double)len,
183 printf("%lf\n", bps); 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 }
184 break; 289 break;
185 default: 290 default:
186 /* reaching this means there's some disaster: */ 291 /* reaching this means there's some disaster: */
diff --git a/tools/perf/bench/sched-pipe.c b/tools/perf/bench/sched-pipe.c
index d9ab3ce446ac..0c7454f8b8a9 100644
--- a/tools/perf/bench/sched-pipe.c
+++ b/tools/perf/bench/sched-pipe.c
@@ -55,7 +55,7 @@ int bench_sched_pipe(int argc, const char **argv,
55 * discarding returned value of read(), write() 55 * discarding returned value of read(), write()
56 * causes error in building environment for perf 56 * causes error in building environment for perf
57 */ 57 */
58 int ret, wait_stat; 58 int __used ret, wait_stat;
59 pid_t pid, retpid; 59 pid_t pid, retpid;
60 60
61 argc = parse_options(argc, argv, options, 61 argc = parse_options(argc, argv, options,
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 1478dc64bf15..7b139e1e7e86 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -8,7 +8,6 @@
8#include "builtin.h" 8#include "builtin.h"
9 9
10#include "util/util.h" 10#include "util/util.h"
11
12#include "util/color.h" 11#include "util/color.h"
13#include <linux/list.h> 12#include <linux/list.h>
14#include "util/cache.h" 13#include "util/cache.h"
@@ -18,6 +17,9 @@
18#include "perf.h" 17#include "perf.h"
19#include "util/debug.h" 18#include "util/debug.h"
20 19
20#include "util/evlist.h"
21#include "util/evsel.h"
22#include "util/annotate.h"
21#include "util/event.h" 23#include "util/event.h"
22#include "util/parse-options.h" 24#include "util/parse-options.h"
23#include "util/parse-events.h" 25#include "util/parse-events.h"
@@ -28,7 +30,7 @@
28 30
29static char const *input_name = "perf.data"; 31static char const *input_name = "perf.data";
30 32
31static bool force; 33static bool force, use_tui, use_stdio;
32 34
33static bool full_paths; 35static bool full_paths;
34 36
@@ -36,9 +38,13 @@ static bool print_line;
36 38
37static const char *sym_hist_filter; 39static const char *sym_hist_filter;
38 40
39static int hists__add_entry(struct hists *self, struct addr_location *al) 41static int perf_evlist__add_sample(struct perf_evlist *evlist,
42 struct perf_sample *sample,
43 struct perf_evsel *evsel,
44 struct addr_location *al)
40{ 45{
41 struct hist_entry *he; 46 struct hist_entry *he;
47 int ret;
42 48
43 if (sym_hist_filter != NULL && 49 if (sym_hist_filter != NULL &&
44 (al->sym == NULL || strcmp(sym_hist_filter, al->sym->name) != 0)) { 50 (al->sym == NULL || strcmp(sym_hist_filter, al->sym->name) != 0)) {
@@ -51,25 +57,41 @@ static int hists__add_entry(struct hists *self, struct addr_location *al)
51 return 0; 57 return 0;
52 } 58 }
53 59
54 he = __hists__add_entry(self, al, NULL, 1); 60 he = __hists__add_entry(&evsel->hists, al, NULL, 1);
55 if (he == NULL) 61 if (he == NULL)
56 return -ENOMEM; 62 return -ENOMEM;
57 63
58 return hist_entry__inc_addr_samples(he, al->addr); 64 ret = 0;
65 if (he->ms.sym != NULL) {
66 struct annotation *notes = symbol__annotation(he->ms.sym);
67 if (notes->src == NULL &&
68 symbol__alloc_hist(he->ms.sym, evlist->nr_entries) < 0)
69 return -ENOMEM;
70
71 ret = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
72 }
73
74 evsel->hists.stats.total_period += sample->period;
75 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
76 return ret;
59} 77}
60 78
61static int process_sample_event(event_t *event, struct perf_session *session) 79static int process_sample_event(union perf_event *event,
80 struct perf_sample *sample,
81 struct perf_evsel *evsel,
82 struct perf_session *session)
62{ 83{
63 struct addr_location al; 84 struct addr_location al;
64 struct sample_data data;
65 85
66 if (event__preprocess_sample(event, session, &al, &data, NULL) < 0) { 86 if (perf_event__preprocess_sample(event, session, &al, sample,
87 symbol__annotate_init) < 0) {
67 pr_warning("problem processing %d event, skipping it.\n", 88 pr_warning("problem processing %d event, skipping it.\n",
68 event->header.type); 89 event->header.type);
69 return -1; 90 return -1;
70 } 91 }
71 92
72 if (!al.filtered && hists__add_entry(&session->hists, &al)) { 93 if (!al.filtered &&
94 perf_evlist__add_sample(session->evlist, sample, evsel, &al)) {
73 pr_warning("problem incrementing symbol count, " 95 pr_warning("problem incrementing symbol count, "
74 "skipping event\n"); 96 "skipping event\n");
75 return -1; 97 return -1;
@@ -78,261 +100,26 @@ static int process_sample_event(event_t *event, struct perf_session *session)
78 return 0; 100 return 0;
79} 101}
80 102
81static int objdump_line__print(struct objdump_line *self, 103static int hist_entry__tty_annotate(struct hist_entry *he, int evidx)
82 struct list_head *head,
83 struct hist_entry *he, u64 len)
84{
85 struct symbol *sym = he->ms.sym;
86 static const char *prev_line;
87 static const char *prev_color;
88
89 if (self->offset != -1) {
90 const char *path = NULL;
91 unsigned int hits = 0;
92 double percent = 0.0;
93 const char *color;
94 struct sym_priv *priv = symbol__priv(sym);
95 struct sym_ext *sym_ext = priv->ext;
96 struct sym_hist *h = priv->hist;
97 s64 offset = self->offset;
98 struct objdump_line *next = objdump__get_next_ip_line(head, self);
99
100 while (offset < (s64)len &&
101 (next == NULL || offset < next->offset)) {
102 if (sym_ext) {
103 if (path == NULL)
104 path = sym_ext[offset].path;
105 percent += sym_ext[offset].percent;
106 } else
107 hits += h->ip[offset];
108
109 ++offset;
110 }
111
112 if (sym_ext == NULL && h->sum)
113 percent = 100.0 * hits / h->sum;
114
115 color = get_percent_color(percent);
116
117 /*
118 * Also color the filename and line if needed, with
119 * the same color than the percentage. Don't print it
120 * twice for close colored ip with the same filename:line
121 */
122 if (path) {
123 if (!prev_line || strcmp(prev_line, path)
124 || color != prev_color) {
125 color_fprintf(stdout, color, " %s", path);
126 prev_line = path;
127 prev_color = color;
128 }
129 }
130
131 color_fprintf(stdout, color, " %7.2f", percent);
132 printf(" : ");
133 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", self->line);
134 } else {
135 if (!*self->line)
136 printf(" :\n");
137 else
138 printf(" : %s\n", self->line);
139 }
140
141 return 0;
142}
143
144static struct rb_root root_sym_ext;
145
146static void insert_source_line(struct sym_ext *sym_ext)
147{ 104{
148 struct sym_ext *iter; 105 return symbol__tty_annotate(he->ms.sym, he->ms.map, evidx,
149 struct rb_node **p = &root_sym_ext.rb_node; 106 print_line, full_paths, 0, 0);
150 struct rb_node *parent = NULL;
151
152 while (*p != NULL) {
153 parent = *p;
154 iter = rb_entry(parent, struct sym_ext, node);
155
156 if (sym_ext->percent > iter->percent)
157 p = &(*p)->rb_left;
158 else
159 p = &(*p)->rb_right;
160 }
161
162 rb_link_node(&sym_ext->node, parent, p);
163 rb_insert_color(&sym_ext->node, &root_sym_ext);
164} 107}
165 108
166static void free_source_line(struct hist_entry *he, int len) 109static void hists__find_annotations(struct hists *self, int evidx)
167{ 110{
168 struct sym_priv *priv = symbol__priv(he->ms.sym); 111 struct rb_node *nd = rb_first(&self->entries), *next;
169 struct sym_ext *sym_ext = priv->ext;
170 int i;
171
172 if (!sym_ext)
173 return;
174
175 for (i = 0; i < len; i++)
176 free(sym_ext[i].path);
177 free(sym_ext);
178
179 priv->ext = NULL;
180 root_sym_ext = RB_ROOT;
181}
182
183/* Get the filename:line for the colored entries */
184static void
185get_source_line(struct hist_entry *he, int len, const char *filename)
186{
187 struct symbol *sym = he->ms.sym;
188 u64 start;
189 int i;
190 char cmd[PATH_MAX * 2];
191 struct sym_ext *sym_ext;
192 struct sym_priv *priv = symbol__priv(sym);
193 struct sym_hist *h = priv->hist;
194
195 if (!h->sum)
196 return;
197
198 sym_ext = priv->ext = calloc(len, sizeof(struct sym_ext));
199 if (!priv->ext)
200 return;
201
202 start = he->ms.map->unmap_ip(he->ms.map, sym->start);
203
204 for (i = 0; i < len; i++) {
205 char *path = NULL;
206 size_t line_len;
207 u64 offset;
208 FILE *fp;
209
210 sym_ext[i].percent = 100.0 * h->ip[i] / h->sum;
211 if (sym_ext[i].percent <= 0.5)
212 continue;
213
214 offset = start + i;
215 sprintf(cmd, "addr2line -e %s %016llx", filename, offset);
216 fp = popen(cmd, "r");
217 if (!fp)
218 continue;
219
220 if (getline(&path, &line_len, fp) < 0 || !line_len)
221 goto next;
222
223 sym_ext[i].path = malloc(sizeof(char) * line_len + 1);
224 if (!sym_ext[i].path)
225 goto next;
226
227 strcpy(sym_ext[i].path, path);
228 insert_source_line(&sym_ext[i]);
229
230 next:
231 pclose(fp);
232 }
233}
234
235static void print_summary(const char *filename)
236{
237 struct sym_ext *sym_ext;
238 struct rb_node *node;
239
240 printf("\nSorted summary for file %s\n", filename);
241 printf("----------------------------------------------\n\n");
242
243 if (RB_EMPTY_ROOT(&root_sym_ext)) {
244 printf(" Nothing higher than %1.1f%%\n", MIN_GREEN);
245 return;
246 }
247
248 node = rb_first(&root_sym_ext);
249 while (node) {
250 double percent;
251 const char *color;
252 char *path;
253
254 sym_ext = rb_entry(node, struct sym_ext, node);
255 percent = sym_ext->percent;
256 color = get_percent_color(percent);
257 path = sym_ext->path;
258
259 color_fprintf(stdout, color, " %7.2f %s", percent, path);
260 node = rb_next(node);
261 }
262}
263
264static void hist_entry__print_hits(struct hist_entry *self)
265{
266 struct symbol *sym = self->ms.sym;
267 struct sym_priv *priv = symbol__priv(sym);
268 struct sym_hist *h = priv->hist;
269 u64 len = sym->end - sym->start, offset;
270
271 for (offset = 0; offset < len; ++offset)
272 if (h->ip[offset] != 0)
273 printf("%*Lx: %Lu\n", BITS_PER_LONG / 2,
274 sym->start + offset, h->ip[offset]);
275 printf("%*s: %Lu\n", BITS_PER_LONG / 2, "h->sum", h->sum);
276}
277
278static int hist_entry__tty_annotate(struct hist_entry *he)
279{
280 struct map *map = he->ms.map;
281 struct dso *dso = map->dso;
282 struct symbol *sym = he->ms.sym;
283 const char *filename = dso->long_name, *d_filename;
284 u64 len;
285 LIST_HEAD(head);
286 struct objdump_line *pos, *n;
287
288 if (hist_entry__annotate(he, &head, 0) < 0)
289 return -1;
290
291 if (full_paths)
292 d_filename = filename;
293 else
294 d_filename = basename(filename);
295
296 len = sym->end - sym->start;
297
298 if (print_line) {
299 get_source_line(he, len, filename);
300 print_summary(filename);
301 }
302
303 printf("\n\n------------------------------------------------\n");
304 printf(" Percent | Source code & Disassembly of %s\n", d_filename);
305 printf("------------------------------------------------\n");
306
307 if (verbose)
308 hist_entry__print_hits(he);
309
310 list_for_each_entry_safe(pos, n, &head, node) {
311 objdump_line__print(pos, &head, he, len);
312 list_del(&pos->node);
313 objdump_line__free(pos);
314 }
315
316 if (print_line)
317 free_source_line(he, len);
318
319 return 0;
320}
321
322static void hists__find_annotations(struct hists *self)
323{
324 struct rb_node *first = rb_first(&self->entries), *nd = first;
325 int key = KEY_RIGHT; 112 int key = KEY_RIGHT;
326 113
327 while (nd) { 114 while (nd) {
328 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); 115 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
329 struct sym_priv *priv; 116 struct annotation *notes;
330 117
331 if (he->ms.sym == NULL || he->ms.map->dso->annotate_warned) 118 if (he->ms.sym == NULL || he->ms.map->dso->annotate_warned)
332 goto find_next; 119 goto find_next;
333 120
334 priv = symbol__priv(he->ms.sym); 121 notes = symbol__annotation(he->ms.sym);
335 if (priv->hist == NULL) { 122 if (notes->src == NULL) {
336find_next: 123find_next:
337 if (key == KEY_LEFT) 124 if (key == KEY_LEFT)
338 nd = rb_prev(nd); 125 nd = rb_prev(nd);
@@ -342,48 +129,51 @@ find_next:
342 } 129 }
343 130
344 if (use_browser > 0) { 131 if (use_browser > 0) {
345 key = hist_entry__tui_annotate(he); 132 key = hist_entry__tui_annotate(he, evidx);
346 if (is_exit_key(key))
347 break;
348 switch (key) { 133 switch (key) {
349 case KEY_RIGHT: 134 case KEY_RIGHT:
350 case '\t': 135 next = rb_next(nd);
351 nd = rb_next(nd);
352 break; 136 break;
353 case KEY_LEFT: 137 case KEY_LEFT:
354 if (nd == first) 138 next = rb_prev(nd);
355 continue;
356 nd = rb_prev(nd);
357 default:
358 break; 139 break;
140 default:
141 return;
359 } 142 }
143
144 if (next != NULL)
145 nd = next;
360 } else { 146 } else {
361 hist_entry__tty_annotate(he); 147 hist_entry__tty_annotate(he, evidx);
362 nd = rb_next(nd); 148 nd = rb_next(nd);
363 /* 149 /*
364 * Since we have a hist_entry per IP for the same 150 * Since we have a hist_entry per IP for the same
365 * symbol, free he->ms.sym->hist to signal we already 151 * symbol, free he->ms.sym->src to signal we already
366 * processed this symbol. 152 * processed this symbol.
367 */ 153 */
368 free(priv->hist); 154 free(notes->src);
369 priv->hist = NULL; 155 notes->src = NULL;
370 } 156 }
371 } 157 }
372} 158}
373 159
374static struct perf_event_ops event_ops = { 160static struct perf_event_ops event_ops = {
375 .sample = process_sample_event, 161 .sample = process_sample_event,
376 .mmap = event__process_mmap, 162 .mmap = perf_event__process_mmap,
377 .comm = event__process_comm, 163 .comm = perf_event__process_comm,
378 .fork = event__process_task, 164 .fork = perf_event__process_task,
165 .ordered_samples = true,
166 .ordering_requires_timestamps = true,
379}; 167};
380 168
381static int __cmd_annotate(void) 169static int __cmd_annotate(void)
382{ 170{
383 int ret; 171 int ret;
384 struct perf_session *session; 172 struct perf_session *session;
173 struct perf_evsel *pos;
174 u64 total_nr_samples;
385 175
386 session = perf_session__new(input_name, O_RDONLY, force, false); 176 session = perf_session__new(input_name, O_RDONLY, force, false, &event_ops);
387 if (session == NULL) 177 if (session == NULL)
388 return -ENOMEM; 178 return -ENOMEM;
389 179
@@ -402,12 +192,36 @@ static int __cmd_annotate(void)
402 if (verbose > 2) 192 if (verbose > 2)
403 perf_session__fprintf_dsos(session, stdout); 193 perf_session__fprintf_dsos(session, stdout);
404 194
405 hists__collapse_resort(&session->hists); 195 total_nr_samples = 0;
406 hists__output_resort(&session->hists); 196 list_for_each_entry(pos, &session->evlist->entries, node) {
407 hists__find_annotations(&session->hists); 197 struct hists *hists = &pos->hists;
408out_delete: 198 u32 nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
409 perf_session__delete(session); 199
200 if (nr_samples > 0) {
201 total_nr_samples += nr_samples;
202 hists__collapse_resort(hists);
203 hists__output_resort(hists);
204 hists__find_annotations(hists, pos->idx);
205 }
206 }
410 207
208 if (total_nr_samples == 0) {
209 ui__warning("The %s file has no samples!\n", input_name);
210 goto out_delete;
211 }
212out_delete:
213 /*
214 * Speed up the exit process, for large files this can
215 * take quite a while.
216 *
217 * XXX Enable this when using valgrind or if we ever
218 * librarize this command.
219 *
220 * Also experiment with obstacks to see how much speed
221 * up we'll get here.
222 *
223 * perf_session__delete(session);
224 */
411 return ret; 225 return ret;
412} 226}
413 227
@@ -428,6 +242,8 @@ static const struct option options[] = {
428 "be more verbose (show symbol address, etc)"), 242 "be more verbose (show symbol address, etc)"),
429 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 243 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
430 "dump raw trace in ASCII"), 244 "dump raw trace in ASCII"),
245 OPT_BOOLEAN(0, "tui", &use_tui, "Use the TUI interface"),
246 OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"),
431 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 247 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
432 "file", "vmlinux pathname"), 248 "file", "vmlinux pathname"),
433 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, 249 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
@@ -443,9 +259,14 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used)
443{ 259{
444 argc = parse_options(argc, argv, options, annotate_usage, 0); 260 argc = parse_options(argc, argv, options, annotate_usage, 0);
445 261
446 setup_browser(); 262 if (use_stdio)
263 use_browser = 0;
264 else if (use_tui)
265 use_browser = 1;
266
267 setup_browser(true);
447 268
448 symbol_conf.priv_size = sizeof(struct sym_priv); 269 symbol_conf.priv_size = sizeof(struct annotation);
449 symbol_conf.try_vmlinux_path = true; 270 symbol_conf.try_vmlinux_path = true;
450 271
451 if (symbol__init() < 0) 272 if (symbol__init() < 0)
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index 44a47e13bd67..5af32ae9031e 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -36,10 +36,10 @@ static const struct option options[] = {
36 36
37static int __cmd_buildid_list(void) 37static int __cmd_buildid_list(void)
38{ 38{
39 int err = -1;
40 struct perf_session *session; 39 struct perf_session *session;
41 40
42 session = perf_session__new(input_name, O_RDONLY, force, false); 41 session = perf_session__new(input_name, O_RDONLY, force, false,
42 &build_id__mark_dso_hit_ops);
43 if (session == NULL) 43 if (session == NULL)
44 return -1; 44 return -1;
45 45
@@ -49,7 +49,7 @@ static int __cmd_buildid_list(void)
49 perf_session__fprintf_dsos_buildid(session, stdout, with_hits); 49 perf_session__fprintf_dsos_buildid(session, stdout, with_hits);
50 50
51 perf_session__delete(session); 51 perf_session__delete(session);
52 return err; 52 return 0;
53} 53}
54 54
55int cmd_buildid_list(int argc, const char **argv, const char *prefix __used) 55int cmd_buildid_list(int argc, const char **argv, const char *prefix __used)
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index fca1d4402910..e8219990f8b8 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -30,12 +30,14 @@ static int hists__add_entry(struct hists *self,
30 return -ENOMEM; 30 return -ENOMEM;
31} 31}
32 32
33static int diff__process_sample_event(event_t *event, struct perf_session *session) 33static int diff__process_sample_event(union perf_event *event,
34 struct perf_sample *sample,
35 struct perf_evsel *evsel __used,
36 struct perf_session *session)
34{ 37{
35 struct addr_location al; 38 struct addr_location al;
36 struct sample_data data = { .period = 1, };
37 39
38 if (event__preprocess_sample(event, session, &al, &data, NULL) < 0) { 40 if (perf_event__preprocess_sample(event, session, &al, sample, NULL) < 0) {
39 pr_warning("problem processing %d event, skipping it.\n", 41 pr_warning("problem processing %d event, skipping it.\n",
40 event->header.type); 42 event->header.type);
41 return -1; 43 return -1;
@@ -44,22 +46,24 @@ static int diff__process_sample_event(event_t *event, struct perf_session *sessi
44 if (al.filtered || al.sym == NULL) 46 if (al.filtered || al.sym == NULL)
45 return 0; 47 return 0;
46 48
47 if (hists__add_entry(&session->hists, &al, data.period)) { 49 if (hists__add_entry(&session->hists, &al, sample->period)) {
48 pr_warning("problem incrementing symbol period, skipping event\n"); 50 pr_warning("problem incrementing symbol period, skipping event\n");
49 return -1; 51 return -1;
50 } 52 }
51 53
52 session->hists.stats.total_period += data.period; 54 session->hists.stats.total_period += sample->period;
53 return 0; 55 return 0;
54} 56}
55 57
56static struct perf_event_ops event_ops = { 58static struct perf_event_ops event_ops = {
57 .sample = diff__process_sample_event, 59 .sample = diff__process_sample_event,
58 .mmap = event__process_mmap, 60 .mmap = perf_event__process_mmap,
59 .comm = event__process_comm, 61 .comm = perf_event__process_comm,
60 .exit = event__process_task, 62 .exit = perf_event__process_task,
61 .fork = event__process_task, 63 .fork = perf_event__process_task,
62 .lost = event__process_lost, 64 .lost = perf_event__process_lost,
65 .ordered_samples = true,
66 .ordering_requires_timestamps = true,
63}; 67};
64 68
65static void perf_session__insert_hist_entry_by_name(struct rb_root *root, 69static void perf_session__insert_hist_entry_by_name(struct rb_root *root,
@@ -141,8 +145,8 @@ static int __cmd_diff(void)
141 int ret, i; 145 int ret, i;
142 struct perf_session *session[2]; 146 struct perf_session *session[2];
143 147
144 session[0] = perf_session__new(input_old, O_RDONLY, force, false); 148 session[0] = perf_session__new(input_old, O_RDONLY, force, false, &event_ops);
145 session[1] = perf_session__new(input_new, O_RDONLY, force, false); 149 session[1] = perf_session__new(input_new, O_RDONLY, force, false, &event_ops);
146 if (session[0] == NULL || session[1] == NULL) 150 if (session[0] == NULL || session[1] == NULL)
147 return -ENOMEM; 151 return -ENOMEM;
148 152
@@ -173,7 +177,7 @@ static const char * const diff_usage[] = {
173static const struct option options[] = { 177static const struct option options[] = {
174 OPT_INCR('v', "verbose", &verbose, 178 OPT_INCR('v', "verbose", &verbose,
175 "be more verbose (show symbol address, etc)"), 179 "be more verbose (show symbol address, etc)"),
176 OPT_BOOLEAN('m', "displacement", &show_displacement, 180 OPT_BOOLEAN('M', "displacement", &show_displacement,
177 "Show position displacement relative to baseline"), 181 "Show position displacement relative to baseline"),
178 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 182 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
179 "dump raw trace in ASCII"), 183 "dump raw trace in ASCII"),
@@ -191,6 +195,8 @@ static const struct option options[] = {
191 OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator", 195 OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator",
192 "separator for columns, no spaces will be added between " 196 "separator for columns, no spaces will be added between "
193 "columns '.' is reserved."), 197 "columns '.' is reserved."),
198 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
199 "Look for files with symbols relative to this directory"),
194 OPT_END() 200 OPT_END()
195}; 201};
196 202
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c
new file mode 100644
index 000000000000..4c5e9e04a41f
--- /dev/null
+++ b/tools/perf/builtin-evlist.c
@@ -0,0 +1,54 @@
1/*
2 * Builtin evlist command: Show the list of event selectors present
3 * in a perf.data file.
4 */
5#include "builtin.h"
6
7#include "util/util.h"
8
9#include <linux/list.h>
10
11#include "perf.h"
12#include "util/evlist.h"
13#include "util/evsel.h"
14#include "util/parse-events.h"
15#include "util/parse-options.h"
16#include "util/session.h"
17
18static char const *input_name = "perf.data";
19
20static int __cmd_evlist(void)
21{
22 struct perf_session *session;
23 struct perf_evsel *pos;
24
25 session = perf_session__new(input_name, O_RDONLY, 0, false, NULL);
26 if (session == NULL)
27 return -ENOMEM;
28
29 list_for_each_entry(pos, &session->evlist->entries, node)
30 printf("%s\n", event_name(pos));
31
32 perf_session__delete(session);
33 return 0;
34}
35
36static const char * const evlist_usage[] = {
37 "perf evlist [<options>]",
38 NULL
39};
40
41static const struct option options[] = {
42 OPT_STRING('i', "input", &input_name, "file",
43 "input file name"),
44 OPT_END()
45};
46
47int cmd_evlist(int argc, const char **argv, const char *prefix __used)
48{
49 argc = parse_options(argc, argv, options, evlist_usage, 0);
50 if (argc)
51 usage_with_options(evlist_usage, options);
52
53 return __cmd_evlist();
54}
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 8e3e47b064ce..8dfc12bb119b 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -16,8 +16,8 @@
16static char const *input_name = "-"; 16static char const *input_name = "-";
17static bool inject_build_ids; 17static bool inject_build_ids;
18 18
19static int event__repipe(event_t *event __used, 19static int perf_event__repipe_synth(union perf_event *event,
20 struct perf_session *session __used) 20 struct perf_session *session __used)
21{ 21{
22 uint32_t size; 22 uint32_t size;
23 void *buf = event; 23 void *buf = event;
@@ -36,33 +36,52 @@ static int event__repipe(event_t *event __used,
36 return 0; 36 return 0;
37} 37}
38 38
39static int event__repipe_mmap(event_t *self, struct perf_session *session) 39static int perf_event__repipe(union perf_event *event,
40 struct perf_sample *sample __used,
41 struct perf_session *session)
42{
43 return perf_event__repipe_synth(event, session);
44}
45
46static int perf_event__repipe_sample(union perf_event *event,
47 struct perf_sample *sample __used,
48 struct perf_evsel *evsel __used,
49 struct perf_session *session)
50{
51 return perf_event__repipe_synth(event, session);
52}
53
54static int perf_event__repipe_mmap(union perf_event *event,
55 struct perf_sample *sample,
56 struct perf_session *session)
40{ 57{
41 int err; 58 int err;
42 59
43 err = event__process_mmap(self, session); 60 err = perf_event__process_mmap(event, sample, session);
44 event__repipe(self, session); 61 perf_event__repipe(event, sample, session);
45 62
46 return err; 63 return err;
47} 64}
48 65
49static int event__repipe_task(event_t *self, struct perf_session *session) 66static int perf_event__repipe_task(union perf_event *event,
67 struct perf_sample *sample,
68 struct perf_session *session)
50{ 69{
51 int err; 70 int err;
52 71
53 err = event__process_task(self, session); 72 err = perf_event__process_task(event, sample, session);
54 event__repipe(self, session); 73 perf_event__repipe(event, sample, session);
55 74
56 return err; 75 return err;
57} 76}
58 77
59static int event__repipe_tracing_data(event_t *self, 78static int perf_event__repipe_tracing_data(union perf_event *event,
60 struct perf_session *session) 79 struct perf_session *session)
61{ 80{
62 int err; 81 int err;
63 82
64 event__repipe(self, session); 83 perf_event__repipe_synth(event, session);
65 err = event__process_tracing_data(self, session); 84 err = perf_event__process_tracing_data(event, session);
66 85
67 return err; 86 return err;
68} 87}
@@ -101,8 +120,8 @@ static int dso__inject_build_id(struct dso *self, struct perf_session *session)
101 if (self->kernel) 120 if (self->kernel)
102 misc = PERF_RECORD_MISC_KERNEL; 121 misc = PERF_RECORD_MISC_KERNEL;
103 122
104 err = event__synthesize_build_id(self, misc, event__repipe, 123 err = perf_event__synthesize_build_id(self, misc, perf_event__repipe,
105 machine, session); 124 machine, session);
106 if (err) { 125 if (err) {
107 pr_err("Can't synthesize build_id event for %s\n", self->long_name); 126 pr_err("Can't synthesize build_id event for %s\n", self->long_name);
108 return -1; 127 return -1;
@@ -111,7 +130,10 @@ static int dso__inject_build_id(struct dso *self, struct perf_session *session)
111 return 0; 130 return 0;
112} 131}
113 132
114static int event__inject_buildid(event_t *event, struct perf_session *session) 133static int perf_event__inject_buildid(union perf_event *event,
134 struct perf_sample *sample,
135 struct perf_evsel *evsel __used,
136 struct perf_session *session)
115{ 137{
116 struct addr_location al; 138 struct addr_location al;
117 struct thread *thread; 139 struct thread *thread;
@@ -146,24 +168,24 @@ static int event__inject_buildid(event_t *event, struct perf_session *session)
146 } 168 }
147 169
148repipe: 170repipe:
149 event__repipe(event, session); 171 perf_event__repipe(event, sample, session);
150 return 0; 172 return 0;
151} 173}
152 174
153struct perf_event_ops inject_ops = { 175struct perf_event_ops inject_ops = {
154 .sample = event__repipe, 176 .sample = perf_event__repipe_sample,
155 .mmap = event__repipe, 177 .mmap = perf_event__repipe,
156 .comm = event__repipe, 178 .comm = perf_event__repipe,
157 .fork = event__repipe, 179 .fork = perf_event__repipe,
158 .exit = event__repipe, 180 .exit = perf_event__repipe,
159 .lost = event__repipe, 181 .lost = perf_event__repipe,
160 .read = event__repipe, 182 .read = perf_event__repipe,
161 .throttle = event__repipe, 183 .throttle = perf_event__repipe,
162 .unthrottle = event__repipe, 184 .unthrottle = perf_event__repipe,
163 .attr = event__repipe, 185 .attr = perf_event__repipe_synth,
164 .event_type = event__repipe, 186 .event_type = perf_event__repipe_synth,
165 .tracing_data = event__repipe, 187 .tracing_data = perf_event__repipe_synth,
166 .build_id = event__repipe, 188 .build_id = perf_event__repipe_synth,
167}; 189};
168 190
169extern volatile int session_done; 191extern volatile int session_done;
@@ -181,13 +203,13 @@ static int __cmd_inject(void)
181 signal(SIGINT, sig_handler); 203 signal(SIGINT, sig_handler);
182 204
183 if (inject_build_ids) { 205 if (inject_build_ids) {
184 inject_ops.sample = event__inject_buildid; 206 inject_ops.sample = perf_event__inject_buildid;
185 inject_ops.mmap = event__repipe_mmap; 207 inject_ops.mmap = perf_event__repipe_mmap;
186 inject_ops.fork = event__repipe_task; 208 inject_ops.fork = perf_event__repipe_task;
187 inject_ops.tracing_data = event__repipe_tracing_data; 209 inject_ops.tracing_data = perf_event__repipe_tracing_data;
188 } 210 }
189 211
190 session = perf_session__new(input_name, O_RDONLY, false, true); 212 session = perf_session__new(input_name, O_RDONLY, false, true, &inject_ops);
191 if (session == NULL) 213 if (session == NULL)
192 return -ENOMEM; 214 return -ENOMEM;
193 215
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 31f60a2535e0..225e963df105 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -275,9 +275,8 @@ static void process_free_event(void *data,
275 s_alloc->alloc_cpu = -1; 275 s_alloc->alloc_cpu = -1;
276} 276}
277 277
278static void 278static void process_raw_event(union perf_event *raw_event __used, void *data,
279process_raw_event(event_t *raw_event __used, void *data, 279 int cpu, u64 timestamp, struct thread *thread)
280 int cpu, u64 timestamp, struct thread *thread)
281{ 280{
282 struct event *event; 281 struct event *event;
283 int type; 282 int type;
@@ -304,22 +303,13 @@ process_raw_event(event_t *raw_event __used, void *data,
304 } 303 }
305} 304}
306 305
307static int process_sample_event(event_t *event, struct perf_session *session) 306static int process_sample_event(union perf_event *event,
307 struct perf_sample *sample,
308 struct perf_evsel *evsel __used,
309 struct perf_session *session)
308{ 310{
309 struct sample_data data; 311 struct thread *thread = perf_session__findnew(session, event->ip.pid);
310 struct thread *thread;
311 312
312 memset(&data, 0, sizeof(data));
313 data.time = -1;
314 data.cpu = -1;
315 data.period = 1;
316
317 event__parse_sample(event, session->sample_type, &data);
318
319 dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc,
320 data.pid, data.tid, data.ip, data.period);
321
322 thread = perf_session__findnew(session, event->ip.pid);
323 if (thread == NULL) { 313 if (thread == NULL) {
324 pr_debug("problem processing %d event, skipping it.\n", 314 pr_debug("problem processing %d event, skipping it.\n",
325 event->header.type); 315 event->header.type);
@@ -328,15 +318,15 @@ static int process_sample_event(event_t *event, struct perf_session *session)
328 318
329 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 319 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
330 320
331 process_raw_event(event, data.raw_data, data.cpu, 321 process_raw_event(event, sample->raw_data, sample->cpu,
332 data.time, thread); 322 sample->time, thread);
333 323
334 return 0; 324 return 0;
335} 325}
336 326
337static struct perf_event_ops event_ops = { 327static struct perf_event_ops event_ops = {
338 .sample = process_sample_event, 328 .sample = process_sample_event,
339 .comm = event__process_comm, 329 .comm = perf_event__process_comm,
340 .ordered_samples = true, 330 .ordered_samples = true,
341}; 331};
342 332
@@ -382,10 +372,10 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
382 addr = data->ptr; 372 addr = data->ptr;
383 373
384 if (sym != NULL) 374 if (sym != NULL)
385 snprintf(buf, sizeof(buf), "%s+%Lx", sym->name, 375 snprintf(buf, sizeof(buf), "%s+%" PRIx64 "", sym->name,
386 addr - map->unmap_ip(map, sym->start)); 376 addr - map->unmap_ip(map, sym->start));
387 else 377 else
388 snprintf(buf, sizeof(buf), "%#Lx", addr); 378 snprintf(buf, sizeof(buf), "%#" PRIx64 "", addr);
389 printf(" %-34s |", buf); 379 printf(" %-34s |", buf);
390 380
391 printf(" %9llu/%-5lu | %9llu/%-5lu | %8lu | %8lu | %6.3f%%\n", 381 printf(" %9llu/%-5lu | %9llu/%-5lu | %8lu | %8lu | %6.3f%%\n",
@@ -492,7 +482,8 @@ static void sort_result(void)
492static int __cmd_kmem(void) 482static int __cmd_kmem(void)
493{ 483{
494 int err = -EINVAL; 484 int err = -EINVAL;
495 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0, false); 485 struct perf_session *session = perf_session__new(input_name, O_RDONLY,
486 0, false, &event_ops);
496 if (session == NULL) 487 if (session == NULL)
497 return -ENOMEM; 488 return -ENOMEM;
498 489
@@ -747,6 +738,9 @@ static int __cmd_record(int argc, const char **argv)
747 rec_argc = ARRAY_SIZE(record_args) + argc - 1; 738 rec_argc = ARRAY_SIZE(record_args) + argc - 1;
748 rec_argv = calloc(rec_argc + 1, sizeof(char *)); 739 rec_argv = calloc(rec_argc + 1, sizeof(char *));
749 740
741 if (rec_argv == NULL)
742 return -ENOMEM;
743
750 for (i = 0; i < ARRAY_SIZE(record_args); i++) 744 for (i = 0; i < ARRAY_SIZE(record_args); i++)
751 rec_argv[i] = strdup(record_args[i]); 745 rec_argv[i] = strdup(record_args[i]);
752 746
diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c
index d88c6961274c..6313b6eb3ebb 100644
--- a/tools/perf/builtin-list.c
+++ b/tools/perf/builtin-list.c
@@ -5,6 +5,7 @@
5 * 5 *
6 * Copyright (C) 2009, Thomas Gleixner <tglx@linutronix.de> 6 * Copyright (C) 2009, Thomas Gleixner <tglx@linutronix.de>
7 * Copyright (C) 2008-2009, Red Hat Inc, Ingo Molnar <mingo@redhat.com> 7 * Copyright (C) 2008-2009, Red Hat Inc, Ingo Molnar <mingo@redhat.com>
8 * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
8 */ 9 */
9#include "builtin.h" 10#include "builtin.h"
10 11
@@ -13,9 +14,47 @@
13#include "util/parse-events.h" 14#include "util/parse-events.h"
14#include "util/cache.h" 15#include "util/cache.h"
15 16
16int cmd_list(int argc __used, const char **argv __used, const char *prefix __used) 17int cmd_list(int argc, const char **argv, const char *prefix __used)
17{ 18{
18 setup_pager(); 19 setup_pager();
19 print_events(); 20
21 if (argc == 1)
22 print_events(NULL);
23 else {
24 int i;
25
26 for (i = 1; i < argc; ++i) {
27 if (i > 1)
28 putchar('\n');
29 if (strncmp(argv[i], "tracepoint", 10) == 0)
30 print_tracepoint_events(NULL, NULL);
31 else if (strcmp(argv[i], "hw") == 0 ||
32 strcmp(argv[i], "hardware") == 0)
33 print_events_type(PERF_TYPE_HARDWARE);
34 else if (strcmp(argv[i], "sw") == 0 ||
35 strcmp(argv[i], "software") == 0)
36 print_events_type(PERF_TYPE_SOFTWARE);
37 else if (strcmp(argv[i], "cache") == 0 ||
38 strcmp(argv[i], "hwcache") == 0)
39 print_hwcache_events(NULL);
40 else {
41 char *sep = strchr(argv[i], ':'), *s;
42 int sep_idx;
43
44 if (sep == NULL) {
45 print_events(argv[i]);
46 continue;
47 }
48 sep_idx = sep - argv[i];
49 s = strdup(argv[i]);
50 if (s == NULL)
51 return -1;
52
53 s[sep_idx] = '\0';
54 print_tracepoint_events(s, s + sep_idx + 1);
55 free(s);
56 }
57 }
58 }
20 return 0; 59 return 0;
21} 60}
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index 821c1586a22b..9ac05aafd9b2 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -202,9 +202,20 @@ static struct thread_stat *thread_stat_findnew_first(u32 tid)
202SINGLE_KEY(nr_acquired) 202SINGLE_KEY(nr_acquired)
203SINGLE_KEY(nr_contended) 203SINGLE_KEY(nr_contended)
204SINGLE_KEY(wait_time_total) 204SINGLE_KEY(wait_time_total)
205SINGLE_KEY(wait_time_min)
206SINGLE_KEY(wait_time_max) 205SINGLE_KEY(wait_time_max)
207 206
207static int lock_stat_key_wait_time_min(struct lock_stat *one,
208 struct lock_stat *two)
209{
210 u64 s1 = one->wait_time_min;
211 u64 s2 = two->wait_time_min;
212 if (s1 == ULLONG_MAX)
213 s1 = 0;
214 if (s2 == ULLONG_MAX)
215 s2 = 0;
216 return s1 > s2;
217}
218
208struct lock_key { 219struct lock_key {
209 /* 220 /*
210 * name: the value for specify by user 221 * name: the value for specify by user
@@ -782,9 +793,9 @@ static void print_result(void)
782 pr_info("%10u ", st->nr_acquired); 793 pr_info("%10u ", st->nr_acquired);
783 pr_info("%10u ", st->nr_contended); 794 pr_info("%10u ", st->nr_contended);
784 795
785 pr_info("%15llu ", st->wait_time_total); 796 pr_info("%15" PRIu64 " ", st->wait_time_total);
786 pr_info("%15llu ", st->wait_time_max); 797 pr_info("%15" PRIu64 " ", st->wait_time_max);
787 pr_info("%15llu ", st->wait_time_min == ULLONG_MAX ? 798 pr_info("%15" PRIu64 " ", st->wait_time_min == ULLONG_MAX ?
788 0 : st->wait_time_min); 799 0 : st->wait_time_min);
789 pr_info("\n"); 800 pr_info("\n");
790 } 801 }
@@ -834,35 +845,33 @@ static void dump_info(void)
834 die("Unknown type of information\n"); 845 die("Unknown type of information\n");
835} 846}
836 847
837static int process_sample_event(event_t *self, struct perf_session *s) 848static int process_sample_event(union perf_event *event,
849 struct perf_sample *sample,
850 struct perf_evsel *evsel __used,
851 struct perf_session *s)
838{ 852{
839 struct sample_data data; 853 struct thread *thread = perf_session__findnew(s, sample->tid);
840 struct thread *thread;
841 854
842 bzero(&data, sizeof(data));
843 event__parse_sample(self, s->sample_type, &data);
844
845 thread = perf_session__findnew(s, data.tid);
846 if (thread == NULL) { 855 if (thread == NULL) {
847 pr_debug("problem processing %d event, skipping it.\n", 856 pr_debug("problem processing %d event, skipping it.\n",
848 self->header.type); 857 event->header.type);
849 return -1; 858 return -1;
850 } 859 }
851 860
852 process_raw_event(data.raw_data, data.cpu, data.time, thread); 861 process_raw_event(sample->raw_data, sample->cpu, sample->time, thread);
853 862
854 return 0; 863 return 0;
855} 864}
856 865
857static struct perf_event_ops eops = { 866static struct perf_event_ops eops = {
858 .sample = process_sample_event, 867 .sample = process_sample_event,
859 .comm = event__process_comm, 868 .comm = perf_event__process_comm,
860 .ordered_samples = true, 869 .ordered_samples = true,
861}; 870};
862 871
863static int read_events(void) 872static int read_events(void)
864{ 873{
865 session = perf_session__new(input_name, O_RDONLY, 0, false); 874 session = perf_session__new(input_name, O_RDONLY, 0, false, &eops);
866 if (!session) 875 if (!session)
867 die("Initializing perf session failed\n"); 876 die("Initializing perf session failed\n");
868 877
@@ -897,7 +906,7 @@ static const char * const report_usage[] = {
897 906
898static const struct option report_options[] = { 907static const struct option report_options[] = {
899 OPT_STRING('k', "key", &sort_key, "acquired", 908 OPT_STRING('k', "key", &sort_key, "acquired",
900 "key for sorting"), 909 "key for sorting (acquired / contended / wait_total / wait_max / wait_min)"),
901 /* TODO: type */ 910 /* TODO: type */
902 OPT_END() 911 OPT_END()
903}; 912};
@@ -947,6 +956,9 @@ static int __cmd_record(int argc, const char **argv)
947 rec_argc = ARRAY_SIZE(record_args) + argc - 1; 956 rec_argc = ARRAY_SIZE(record_args) + argc - 1;
948 rec_argv = calloc(rec_argc + 1, sizeof(char *)); 957 rec_argv = calloc(rec_argc + 1, sizeof(char *));
949 958
959 if (rec_argv == NULL)
960 return -ENOMEM;
961
950 for (i = 0; i < ARRAY_SIZE(record_args); i++) 962 for (i = 0; i < ARRAY_SIZE(record_args); i++)
951 rec_argv[i] = strdup(record_args[i]); 963 rec_argv[i] = strdup(record_args[i]);
952 964
@@ -982,9 +994,9 @@ int cmd_lock(int argc, const char **argv, const char *prefix __used)
982 usage_with_options(report_usage, report_options); 994 usage_with_options(report_usage, report_options);
983 } 995 }
984 __cmd_report(); 996 __cmd_report();
985 } else if (!strcmp(argv[0], "trace")) { 997 } else if (!strcmp(argv[0], "script")) {
986 /* Aliased to 'perf trace' */ 998 /* Aliased to 'perf script' */
987 return cmd_trace(argc, argv, prefix); 999 return cmd_script(argc, argv, prefix);
988 } else if (!strcmp(argv[0], "info")) { 1000 } else if (!strcmp(argv[0], "info")) {
989 if (argc) { 1001 if (argc) {
990 argc = parse_options(argc, argv, 1002 argc = parse_options(argc, argv,
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 199d5e19554f..2c0e64d0b4aa 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -36,6 +36,7 @@
36#include "builtin.h" 36#include "builtin.h"
37#include "util/util.h" 37#include "util/util.h"
38#include "util/strlist.h" 38#include "util/strlist.h"
39#include "util/strfilter.h"
39#include "util/symbol.h" 40#include "util/symbol.h"
40#include "util/debug.h" 41#include "util/debug.h"
41#include "util/debugfs.h" 42#include "util/debugfs.h"
@@ -43,6 +44,8 @@
43#include "util/probe-finder.h" 44#include "util/probe-finder.h"
44#include "util/probe-event.h" 45#include "util/probe-event.h"
45 46
47#define DEFAULT_VAR_FILTER "!__k???tab_* & !__crc_*"
48#define DEFAULT_FUNC_FILTER "!_*"
46#define MAX_PATH_LEN 256 49#define MAX_PATH_LEN 256
47 50
48/* Session management structure */ 51/* Session management structure */
@@ -50,14 +53,19 @@ static struct {
50 bool list_events; 53 bool list_events;
51 bool force_add; 54 bool force_add;
52 bool show_lines; 55 bool show_lines;
56 bool show_vars;
57 bool show_ext_vars;
58 bool show_funcs;
59 bool mod_events;
53 int nevents; 60 int nevents;
54 struct perf_probe_event events[MAX_PROBES]; 61 struct perf_probe_event events[MAX_PROBES];
55 struct strlist *dellist; 62 struct strlist *dellist;
56 struct line_range line_range; 63 struct line_range line_range;
64 const char *target_module;
57 int max_probe_points; 65 int max_probe_points;
66 struct strfilter *filter;
58} params; 67} params;
59 68
60
61/* Parse an event definition. Note that any error must die. */ 69/* Parse an event definition. Note that any error must die. */
62static int parse_probe_event(const char *str) 70static int parse_probe_event(const char *str)
63{ 71{
@@ -92,6 +100,7 @@ static int parse_probe_event_argv(int argc, const char **argv)
92 len = 0; 100 len = 0;
93 for (i = 0; i < argc; i++) 101 for (i = 0; i < argc; i++)
94 len += sprintf(&buf[len], "%s ", argv[i]); 102 len += sprintf(&buf[len], "%s ", argv[i]);
103 params.mod_events = true;
95 ret = parse_probe_event(buf); 104 ret = parse_probe_event(buf);
96 free(buf); 105 free(buf);
97 return ret; 106 return ret;
@@ -100,9 +109,10 @@ static int parse_probe_event_argv(int argc, const char **argv)
100static int opt_add_probe_event(const struct option *opt __used, 109static int opt_add_probe_event(const struct option *opt __used,
101 const char *str, int unset __used) 110 const char *str, int unset __used)
102{ 111{
103 if (str) 112 if (str) {
113 params.mod_events = true;
104 return parse_probe_event(str); 114 return parse_probe_event(str);
105 else 115 } else
106 return 0; 116 return 0;
107} 117}
108 118
@@ -110,6 +120,7 @@ static int opt_del_probe_event(const struct option *opt __used,
110 const char *str, int unset __used) 120 const char *str, int unset __used)
111{ 121{
112 if (str) { 122 if (str) {
123 params.mod_events = true;
113 if (!params.dellist) 124 if (!params.dellist)
114 params.dellist = strlist__new(true, NULL); 125 params.dellist = strlist__new(true, NULL);
115 strlist__add(params.dellist, str); 126 strlist__add(params.dellist, str);
@@ -130,15 +141,56 @@ static int opt_show_lines(const struct option *opt __used,
130 141
131 return ret; 142 return ret;
132} 143}
144
145static int opt_show_vars(const struct option *opt __used,
146 const char *str, int unset __used)
147{
148 struct perf_probe_event *pev = &params.events[params.nevents];
149 int ret;
150
151 if (!str)
152 return 0;
153
154 ret = parse_probe_event(str);
155 if (!ret && pev->nargs != 0) {
156 pr_err(" Error: '--vars' doesn't accept arguments.\n");
157 return -EINVAL;
158 }
159 params.show_vars = true;
160
161 return ret;
162}
133#endif 163#endif
134 164
165static int opt_set_filter(const struct option *opt __used,
166 const char *str, int unset __used)
167{
168 const char *err;
169
170 if (str) {
171 pr_debug2("Set filter: %s\n", str);
172 if (params.filter)
173 strfilter__delete(params.filter);
174 params.filter = strfilter__new(str, &err);
175 if (!params.filter) {
176 pr_err("Filter parse error at %td.\n", err - str + 1);
177 pr_err("Source: \"%s\"\n", str);
178 pr_err(" %*c\n", (int)(err - str + 1), '^');
179 return -EINVAL;
180 }
181 }
182
183 return 0;
184}
185
135static const char * const probe_usage[] = { 186static const char * const probe_usage[] = {
136 "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]", 187 "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]",
137 "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]", 188 "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]",
138 "perf probe [<options>] --del '[GROUP:]EVENT' ...", 189 "perf probe [<options>] --del '[GROUP:]EVENT' ...",
139 "perf probe --list", 190 "perf probe --list",
140#ifdef DWARF_SUPPORT 191#ifdef DWARF_SUPPORT
141 "perf probe --line 'LINEDESC'", 192 "perf probe [<options>] --line 'LINEDESC'",
193 "perf probe [<options>] --vars 'PROBEPOINT'",
142#endif 194#endif
143 NULL 195 NULL
144}; 196};
@@ -180,14 +232,28 @@ static const struct option options[] = {
180 OPT_CALLBACK('L', "line", NULL, 232 OPT_CALLBACK('L', "line", NULL,
181 "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]", 233 "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]",
182 "Show source code lines.", opt_show_lines), 234 "Show source code lines.", opt_show_lines),
235 OPT_CALLBACK('V', "vars", NULL,
236 "FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT",
237 "Show accessible variables on PROBEDEF", opt_show_vars),
238 OPT_BOOLEAN('\0', "externs", &params.show_ext_vars,
239 "Show external variables too (with --vars only)"),
183 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 240 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
184 "file", "vmlinux pathname"), 241 "file", "vmlinux pathname"),
185 OPT_STRING('s', "source", &symbol_conf.source_prefix, 242 OPT_STRING('s', "source", &symbol_conf.source_prefix,
186 "directory", "path to kernel source"), 243 "directory", "path to kernel source"),
244 OPT_STRING('m', "module", &params.target_module,
245 "modname", "target module name"),
187#endif 246#endif
188 OPT__DRY_RUN(&probe_event_dry_run), 247 OPT__DRY_RUN(&probe_event_dry_run),
189 OPT_INTEGER('\0', "max-probes", &params.max_probe_points, 248 OPT_INTEGER('\0', "max-probes", &params.max_probe_points,
190 "Set how many probe points can be found for a probe."), 249 "Set how many probe points can be found for a probe."),
250 OPT_BOOLEAN('F', "funcs", &params.show_funcs,
251 "Show potential probe-able functions."),
252 OPT_CALLBACK('\0', "filter", NULL,
253 "[!]FILTER", "Set a filter (with --vars/funcs only)\n"
254 "\t\t\t(default: \"" DEFAULT_VAR_FILTER "\" for --vars,\n"
255 "\t\t\t \"" DEFAULT_FUNC_FILTER "\" for --funcs)",
256 opt_set_filter),
191 OPT_END() 257 OPT_END()
192}; 258};
193 259
@@ -213,11 +279,16 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
213 params.max_probe_points = MAX_PROBES; 279 params.max_probe_points = MAX_PROBES;
214 280
215 if ((!params.nevents && !params.dellist && !params.list_events && 281 if ((!params.nevents && !params.dellist && !params.list_events &&
216 !params.show_lines)) 282 !params.show_lines && !params.show_funcs))
217 usage_with_options(probe_usage, options); 283 usage_with_options(probe_usage, options);
218 284
285 /*
286 * Only consider the user's kernel image path if given.
287 */
288 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
289
219 if (params.list_events) { 290 if (params.list_events) {
220 if (params.nevents != 0 || params.dellist) { 291 if (params.mod_events) {
221 pr_err(" Error: Don't use --list with --add/--del.\n"); 292 pr_err(" Error: Don't use --list with --add/--del.\n");
222 usage_with_options(probe_usage, options); 293 usage_with_options(probe_usage, options);
223 } 294 }
@@ -225,26 +296,83 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
225 pr_err(" Error: Don't use --list with --line.\n"); 296 pr_err(" Error: Don't use --list with --line.\n");
226 usage_with_options(probe_usage, options); 297 usage_with_options(probe_usage, options);
227 } 298 }
299 if (params.show_vars) {
300 pr_err(" Error: Don't use --list with --vars.\n");
301 usage_with_options(probe_usage, options);
302 }
303 if (params.show_funcs) {
304 pr_err(" Error: Don't use --list with --funcs.\n");
305 usage_with_options(probe_usage, options);
306 }
228 ret = show_perf_probe_events(); 307 ret = show_perf_probe_events();
229 if (ret < 0) 308 if (ret < 0)
230 pr_err(" Error: Failed to show event list. (%d)\n", 309 pr_err(" Error: Failed to show event list. (%d)\n",
231 ret); 310 ret);
232 return ret; 311 return ret;
233 } 312 }
313 if (params.show_funcs) {
314 if (params.nevents != 0 || params.dellist) {
315 pr_err(" Error: Don't use --funcs with"
316 " --add/--del.\n");
317 usage_with_options(probe_usage, options);
318 }
319 if (params.show_lines) {
320 pr_err(" Error: Don't use --funcs with --line.\n");
321 usage_with_options(probe_usage, options);
322 }
323 if (params.show_vars) {
324 pr_err(" Error: Don't use --funcs with --vars.\n");
325 usage_with_options(probe_usage, options);
326 }
327 if (!params.filter)
328 params.filter = strfilter__new(DEFAULT_FUNC_FILTER,
329 NULL);
330 ret = show_available_funcs(params.target_module,
331 params.filter);
332 strfilter__delete(params.filter);
333 if (ret < 0)
334 pr_err(" Error: Failed to show functions."
335 " (%d)\n", ret);
336 return ret;
337 }
234 338
235#ifdef DWARF_SUPPORT 339#ifdef DWARF_SUPPORT
236 if (params.show_lines) { 340 if (params.show_lines) {
237 if (params.nevents != 0 || params.dellist) { 341 if (params.mod_events) {
238 pr_warning(" Error: Don't use --line with" 342 pr_err(" Error: Don't use --line with"
239 " --add/--del.\n"); 343 " --add/--del.\n");
344 usage_with_options(probe_usage, options);
345 }
346 if (params.show_vars) {
347 pr_err(" Error: Don't use --line with --vars.\n");
240 usage_with_options(probe_usage, options); 348 usage_with_options(probe_usage, options);
241 } 349 }
242 350
243 ret = show_line_range(&params.line_range); 351 ret = show_line_range(&params.line_range, params.target_module);
244 if (ret < 0) 352 if (ret < 0)
245 pr_err(" Error: Failed to show lines. (%d)\n", ret); 353 pr_err(" Error: Failed to show lines. (%d)\n", ret);
246 return ret; 354 return ret;
247 } 355 }
356 if (params.show_vars) {
357 if (params.mod_events) {
358 pr_err(" Error: Don't use --vars with"
359 " --add/--del.\n");
360 usage_with_options(probe_usage, options);
361 }
362 if (!params.filter)
363 params.filter = strfilter__new(DEFAULT_VAR_FILTER,
364 NULL);
365
366 ret = show_available_vars(params.events, params.nevents,
367 params.max_probe_points,
368 params.target_module,
369 params.filter,
370 params.show_ext_vars);
371 strfilter__delete(params.filter);
372 if (ret < 0)
373 pr_err(" Error: Failed to show vars. (%d)\n", ret);
374 return ret;
375 }
248#endif 376#endif
249 377
250 if (params.dellist) { 378 if (params.dellist) {
@@ -258,8 +386,9 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
258 386
259 if (params.nevents) { 387 if (params.nevents) {
260 ret = add_perf_probe_events(params.events, params.nevents, 388 ret = add_perf_probe_events(params.events, params.nevents,
261 params.force_add, 389 params.max_probe_points,
262 params.max_probe_points); 390 params.target_module,
391 params.force_add);
263 if (ret < 0) { 392 if (ret < 0) {
264 pr_err(" Error: Failed to add events. (%d)\n", ret); 393 pr_err(" Error: Failed to add events. (%d)\n", ret);
265 return ret; 394 return ret;
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index ff77b805de71..8e2c85798185 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -18,41 +18,43 @@
18 18
19#include "util/header.h" 19#include "util/header.h"
20#include "util/event.h" 20#include "util/event.h"
21#include "util/evlist.h"
22#include "util/evsel.h"
21#include "util/debug.h" 23#include "util/debug.h"
22#include "util/session.h" 24#include "util/session.h"
23#include "util/symbol.h" 25#include "util/symbol.h"
24#include "util/cpumap.h" 26#include "util/cpumap.h"
27#include "util/thread_map.h"
25 28
26#include <unistd.h> 29#include <unistd.h>
27#include <sched.h> 30#include <sched.h>
28#include <sys/mman.h> 31#include <sys/mman.h>
29 32
33#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
34
30enum write_mode_t { 35enum write_mode_t {
31 WRITE_FORCE, 36 WRITE_FORCE,
32 WRITE_APPEND 37 WRITE_APPEND
33}; 38};
34 39
35static int *fd[MAX_NR_CPUS][MAX_COUNTERS];
36
37static u64 user_interval = ULLONG_MAX; 40static u64 user_interval = ULLONG_MAX;
38static u64 default_interval = 0; 41static u64 default_interval = 0;
39 42
40static int nr_cpus = 0;
41static unsigned int page_size; 43static unsigned int page_size;
42static unsigned int mmap_pages = 128; 44static unsigned int mmap_pages = UINT_MAX;
43static unsigned int user_freq = UINT_MAX; 45static unsigned int user_freq = UINT_MAX;
44static int freq = 1000; 46static int freq = 1000;
45static int output; 47static int output;
46static int pipe_output = 0; 48static int pipe_output = 0;
47static const char *output_name = "perf.data"; 49static const char *output_name = NULL;
48static int group = 0; 50static int group = 0;
49static int realtime_prio = 0; 51static int realtime_prio = 0;
52static bool nodelay = false;
50static bool raw_samples = false; 53static bool raw_samples = false;
54static bool sample_id_all_avail = true;
51static bool system_wide = false; 55static bool system_wide = false;
52static pid_t target_pid = -1; 56static pid_t target_pid = -1;
53static pid_t target_tid = -1; 57static pid_t target_tid = -1;
54static pid_t *all_tids = NULL;
55static int thread_num = 0;
56static pid_t child_pid = -1; 58static pid_t child_pid = -1;
57static bool no_inherit = false; 59static bool no_inherit = false;
58static enum write_mode_t write_mode = WRITE_FORCE; 60static enum write_mode_t write_mode = WRITE_FORCE;
@@ -60,53 +62,20 @@ static bool call_graph = false;
60static bool inherit_stat = false; 62static bool inherit_stat = false;
61static bool no_samples = false; 63static bool no_samples = false;
62static bool sample_address = false; 64static bool sample_address = false;
65static bool sample_time = false;
63static bool no_buildid = false; 66static bool no_buildid = false;
67static bool no_buildid_cache = false;
68static struct perf_evlist *evsel_list;
64 69
65static long samples = 0; 70static long samples = 0;
66static u64 bytes_written = 0; 71static u64 bytes_written = 0;
67 72
68static struct pollfd *event_array;
69
70static int nr_poll = 0;
71static int nr_cpu = 0;
72
73static int file_new = 1; 73static int file_new = 1;
74static off_t post_processing_offset; 74static off_t post_processing_offset;
75 75
76static struct perf_session *session; 76static struct perf_session *session;
77static const char *cpu_list; 77static const char *cpu_list;
78 78
79struct mmap_data {
80 int counter;
81 void *base;
82 unsigned int mask;
83 unsigned int prev;
84};
85
86static struct mmap_data mmap_array[MAX_NR_CPUS];
87
88static unsigned long mmap_read_head(struct mmap_data *md)
89{
90 struct perf_event_mmap_page *pc = md->base;
91 long head;
92
93 head = pc->data_head;
94 rmb();
95
96 return head;
97}
98
99static void mmap_write_tail(struct mmap_data *md, unsigned long tail)
100{
101 struct perf_event_mmap_page *pc = md->base;
102
103 /*
104 * ensure all reads are done before we write the tail out.
105 */
106 /* mb(); */
107 pc->data_tail = tail;
108}
109
110static void advance_output(size_t size) 79static void advance_output(size_t size)
111{ 80{
112 bytes_written += size; 81 bytes_written += size;
@@ -127,41 +96,26 @@ static void write_output(void *buf, size_t size)
127 } 96 }
128} 97}
129 98
130static int process_synthesized_event(event_t *event, 99static int process_synthesized_event(union perf_event *event,
100 struct perf_sample *sample __used,
131 struct perf_session *self __used) 101 struct perf_session *self __used)
132{ 102{
133 write_output(event, event->header.size); 103 write_output(event, event->header.size);
134 return 0; 104 return 0;
135} 105}
136 106
137static void mmap_read(struct mmap_data *md) 107static void mmap_read(struct perf_mmap *md)
138{ 108{
139 unsigned int head = mmap_read_head(md); 109 unsigned int head = perf_mmap__read_head(md);
140 unsigned int old = md->prev; 110 unsigned int old = md->prev;
141 unsigned char *data = md->base + page_size; 111 unsigned char *data = md->base + page_size;
142 unsigned long size; 112 unsigned long size;
143 void *buf; 113 void *buf;
144 int diff;
145 114
146 /* 115 if (old == head)
147 * If we're further behind than half the buffer, there's a chance 116 return;
148 * the writer will bite our tail and mess up the samples under us.
149 *
150 * If we somehow ended up ahead of the head, we got messed up.
151 *
152 * In either case, truncate and restart at head.
153 */
154 diff = head - old;
155 if (diff < 0) {
156 fprintf(stderr, "WARNING: failed to keep up with mmap data\n");
157 /*
158 * head points to a known good entry, start there.
159 */
160 old = head;
161 }
162 117
163 if (old != head) 118 samples++;
164 samples++;
165 119
166 size = head - old; 120 size = head - old;
167 121
@@ -180,7 +134,7 @@ static void mmap_read(struct mmap_data *md)
180 write_output(buf, size); 134 write_output(buf, size);
181 135
182 md->prev = old; 136 md->prev = old;
183 mmap_write_tail(md, old); 137 perf_mmap__write_tail(md, old);
184} 138}
185 139
186static volatile int done = 0; 140static volatile int done = 0;
@@ -197,55 +151,26 @@ static void sig_atexit(void)
197 if (child_pid > 0) 151 if (child_pid > 0)
198 kill(child_pid, SIGTERM); 152 kill(child_pid, SIGTERM);
199 153
200 if (signr == -1) 154 if (signr == -1 || signr == SIGUSR1)
201 return; 155 return;
202 156
203 signal(signr, SIG_DFL); 157 signal(signr, SIG_DFL);
204 kill(getpid(), signr); 158 kill(getpid(), signr);
205} 159}
206 160
207static int group_fd; 161static void config_attr(struct perf_evsel *evsel, struct perf_evlist *evlist)
208
209static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr)
210{
211 struct perf_header_attr *h_attr;
212
213 if (nr < session->header.attrs) {
214 h_attr = session->header.attr[nr];
215 } else {
216 h_attr = perf_header_attr__new(a);
217 if (h_attr != NULL)
218 if (perf_header__add_attr(&session->header, h_attr) < 0) {
219 perf_header_attr__delete(h_attr);
220 h_attr = NULL;
221 }
222 }
223
224 return h_attr;
225}
226
227static void create_counter(int counter, int cpu)
228{ 162{
229 char *filter = filters[counter]; 163 struct perf_event_attr *attr = &evsel->attr;
230 struct perf_event_attr *attr = attrs + counter; 164 int track = !evsel->idx; /* only the first counter needs these */
231 struct perf_header_attr *h_attr;
232 int track = !counter; /* only the first counter needs these */
233 int thread_index;
234 int ret;
235 struct {
236 u64 count;
237 u64 time_enabled;
238 u64 time_running;
239 u64 id;
240 } read_data;
241 165
166 attr->inherit = !no_inherit;
242 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | 167 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
243 PERF_FORMAT_TOTAL_TIME_RUNNING | 168 PERF_FORMAT_TOTAL_TIME_RUNNING |
244 PERF_FORMAT_ID; 169 PERF_FORMAT_ID;
245 170
246 attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID; 171 attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID;
247 172
248 if (nr_counters > 1) 173 if (evlist->nr_entries > 1)
249 attr->sample_type |= PERF_SAMPLE_ID; 174 attr->sample_type |= PERF_SAMPLE_ID;
250 175
251 /* 176 /*
@@ -280,35 +205,94 @@ static void create_counter(int counter, int cpu)
280 if (system_wide) 205 if (system_wide)
281 attr->sample_type |= PERF_SAMPLE_CPU; 206 attr->sample_type |= PERF_SAMPLE_CPU;
282 207
208 if (sample_id_all_avail &&
209 (sample_time || system_wide || !no_inherit || cpu_list))
210 attr->sample_type |= PERF_SAMPLE_TIME;
211
283 if (raw_samples) { 212 if (raw_samples) {
284 attr->sample_type |= PERF_SAMPLE_TIME; 213 attr->sample_type |= PERF_SAMPLE_TIME;
285 attr->sample_type |= PERF_SAMPLE_RAW; 214 attr->sample_type |= PERF_SAMPLE_RAW;
286 attr->sample_type |= PERF_SAMPLE_CPU; 215 attr->sample_type |= PERF_SAMPLE_CPU;
287 } 216 }
288 217
218 if (nodelay) {
219 attr->watermark = 0;
220 attr->wakeup_events = 1;
221 }
222
289 attr->mmap = track; 223 attr->mmap = track;
290 attr->comm = track; 224 attr->comm = track;
291 attr->inherit = !no_inherit; 225
292 if (target_pid == -1 && target_tid == -1 && !system_wide) { 226 if (target_pid == -1 && target_tid == -1 && !system_wide) {
293 attr->disabled = 1; 227 attr->disabled = 1;
294 attr->enable_on_exec = 1; 228 attr->enable_on_exec = 1;
295 } 229 }
230}
296 231
297 for (thread_index = 0; thread_index < thread_num; thread_index++) { 232static bool perf_evlist__equal(struct perf_evlist *evlist,
298try_again: 233 struct perf_evlist *other)
299 fd[nr_cpu][counter][thread_index] = sys_perf_event_open(attr, 234{
300 all_tids[thread_index], cpu, group_fd, 0); 235 struct perf_evsel *pos, *pair;
236
237 if (evlist->nr_entries != other->nr_entries)
238 return false;
239
240 pair = list_entry(other->entries.next, struct perf_evsel, node);
301 241
302 if (fd[nr_cpu][counter][thread_index] < 0) { 242 list_for_each_entry(pos, &evlist->entries, node) {
243 if (memcmp(&pos->attr, &pair->attr, sizeof(pos->attr) != 0))
244 return false;
245 pair = list_entry(pair->node.next, struct perf_evsel, node);
246 }
247
248 return true;
249}
250
251static void open_counters(struct perf_evlist *evlist)
252{
253 struct perf_evsel *pos;
254
255 if (evlist->cpus->map[0] < 0)
256 no_inherit = true;
257
258 list_for_each_entry(pos, &evlist->entries, node) {
259 struct perf_event_attr *attr = &pos->attr;
260 /*
261 * Check if parse_single_tracepoint_event has already asked for
262 * PERF_SAMPLE_TIME.
263 *
264 * XXX this is kludgy but short term fix for problems introduced by
265 * eac23d1c that broke 'perf script' by having different sample_types
266 * when using multiple tracepoint events when we use a perf binary
267 * that tries to use sample_id_all on an older kernel.
268 *
269 * We need to move counter creation to perf_session, support
270 * different sample_types, etc.
271 */
272 bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
273
274 config_attr(pos, evlist);
275retry_sample_id:
276 attr->sample_id_all = sample_id_all_avail ? 1 : 0;
277try_again:
278 if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group) < 0) {
303 int err = errno; 279 int err = errno;
304 280
305 if (err == EPERM || err == EACCES) 281 if (err == EPERM || err == EACCES) {
306 die("Permission error - are you root?\n" 282 ui__warning_paranoid();
307 "\t Consider tweaking" 283 exit(EXIT_FAILURE);
308 " /proc/sys/kernel/perf_event_paranoid.\n"); 284 } else if (err == ENODEV && cpu_list) {
309 else if (err == ENODEV && cpu_list) {
310 die("No such device - did you specify" 285 die("No such device - did you specify"
311 " an out-of-range profile CPU?\n"); 286 " an out-of-range profile CPU?\n");
287 } else if (err == EINVAL && sample_id_all_avail) {
288 /*
289 * Old kernel, no attr->sample_id_type_all field
290 */
291 sample_id_all_avail = false;
292 if (!sample_time && !raw_samples && !time_needed)
293 attr->sample_type &= ~PERF_SAMPLE_TIME;
294
295 goto retry_sample_id;
312 } 296 }
313 297
314 /* 298 /*
@@ -320,14 +304,22 @@ try_again:
320 && attr->config == PERF_COUNT_HW_CPU_CYCLES) { 304 && attr->config == PERF_COUNT_HW_CPU_CYCLES) {
321 305
322 if (verbose) 306 if (verbose)
323 warning(" ... trying to fall back to cpu-clock-ticks\n"); 307 ui__warning("The cycles event is not supported, "
308 "trying to fall back to cpu-clock-ticks\n");
324 attr->type = PERF_TYPE_SOFTWARE; 309 attr->type = PERF_TYPE_SOFTWARE;
325 attr->config = PERF_COUNT_SW_CPU_CLOCK; 310 attr->config = PERF_COUNT_SW_CPU_CLOCK;
326 goto try_again; 311 goto try_again;
327 } 312 }
313
314 if (err == ENOENT) {
315 ui__warning("The %s event is not supported.\n",
316 event_name(pos));
317 exit(EXIT_FAILURE);
318 }
319
328 printf("\n"); 320 printf("\n");
329 error("perfcounter syscall returned with %d (%s)\n", 321 error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n",
330 fd[nr_cpu][counter][thread_index], strerror(err)); 322 err, strerror(err));
331 323
332#if defined(__i386__) || defined(__x86_64__) 324#if defined(__i386__) || defined(__x86_64__)
333 if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP) 325 if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP)
@@ -338,85 +330,28 @@ try_again:
338#endif 330#endif
339 331
340 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); 332 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
341 exit(-1);
342 } 333 }
334 }
343 335
344 h_attr = get_header_attr(attr, counter); 336 if (perf_evlist__set_filters(evlist)) {
345 if (h_attr == NULL) 337 error("failed to set filter with %d (%s)\n", errno,
346 die("nomem\n"); 338 strerror(errno));
347 339 exit(-1);
348 if (!file_new) { 340 }
349 if (memcmp(&h_attr->attr, attr, sizeof(*attr))) {
350 fprintf(stderr, "incompatible append\n");
351 exit(-1);
352 }
353 }
354 341
355 if (read(fd[nr_cpu][counter][thread_index], &read_data, sizeof(read_data)) == -1) { 342 if (perf_evlist__mmap(evlist, mmap_pages, false) < 0)
356 perror("Unable to read perf file descriptor\n"); 343 die("failed to mmap with %d (%s)\n", errno, strerror(errno));
357 exit(-1);
358 }
359 344
360 if (perf_header_attr__add_id(h_attr, read_data.id) < 0) { 345 if (file_new)
361 pr_warning("Not enough memory to add id\n"); 346 session->evlist = evlist;
347 else {
348 if (!perf_evlist__equal(session->evlist, evlist)) {
349 fprintf(stderr, "incompatible append\n");
362 exit(-1); 350 exit(-1);
363 } 351 }
352 }
364 353
365 assert(fd[nr_cpu][counter][thread_index] >= 0); 354 perf_session__update_sample_type(session);
366 fcntl(fd[nr_cpu][counter][thread_index], F_SETFL, O_NONBLOCK);
367
368 /*
369 * First counter acts as the group leader:
370 */
371 if (group && group_fd == -1)
372 group_fd = fd[nr_cpu][counter][thread_index];
373
374 if (counter || thread_index) {
375 ret = ioctl(fd[nr_cpu][counter][thread_index],
376 PERF_EVENT_IOC_SET_OUTPUT,
377 fd[nr_cpu][0][0]);
378 if (ret) {
379 error("failed to set output: %d (%s)\n", errno,
380 strerror(errno));
381 exit(-1);
382 }
383 } else {
384 mmap_array[nr_cpu].counter = counter;
385 mmap_array[nr_cpu].prev = 0;
386 mmap_array[nr_cpu].mask = mmap_pages*page_size - 1;
387 mmap_array[nr_cpu].base = mmap(NULL, (mmap_pages+1)*page_size,
388 PROT_READ|PROT_WRITE, MAP_SHARED, fd[nr_cpu][counter][thread_index], 0);
389 if (mmap_array[nr_cpu].base == MAP_FAILED) {
390 error("failed to mmap with %d (%s)\n", errno, strerror(errno));
391 exit(-1);
392 }
393
394 event_array[nr_poll].fd = fd[nr_cpu][counter][thread_index];
395 event_array[nr_poll].events = POLLIN;
396 nr_poll++;
397 }
398
399 if (filter != NULL) {
400 ret = ioctl(fd[nr_cpu][counter][thread_index],
401 PERF_EVENT_IOC_SET_FILTER, filter);
402 if (ret) {
403 error("failed to set filter with %d (%s)\n", errno,
404 strerror(errno));
405 exit(-1);
406 }
407 }
408 }
409}
410
411static void open_counters(int cpu)
412{
413 int counter;
414
415 group_fd = -1;
416 for (counter = 0; counter < nr_counters; counter++)
417 create_counter(counter, cpu);
418
419 nr_cpu++;
420} 355}
421 356
422static int process_buildids(void) 357static int process_buildids(void)
@@ -437,14 +372,16 @@ static void atexit_header(void)
437 if (!pipe_output) { 372 if (!pipe_output) {
438 session->header.data_size += bytes_written; 373 session->header.data_size += bytes_written;
439 374
440 process_buildids(); 375 if (!no_buildid)
441 perf_header__write(&session->header, output, true); 376 process_buildids();
377 perf_session__write_header(session, evsel_list, output, true);
442 perf_session__delete(session); 378 perf_session__delete(session);
379 perf_evlist__delete(evsel_list);
443 symbol__exit(); 380 symbol__exit();
444 } 381 }
445} 382}
446 383
447static void event__synthesize_guest_os(struct machine *machine, void *data) 384static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
448{ 385{
449 int err; 386 int err;
450 struct perf_session *psession = data; 387 struct perf_session *psession = data;
@@ -460,8 +397,8 @@ static void event__synthesize_guest_os(struct machine *machine, void *data)
460 *method is used to avoid symbol missing when the first addr is 397 *method is used to avoid symbol missing when the first addr is
461 *in module instead of in guest kernel. 398 *in module instead of in guest kernel.
462 */ 399 */
463 err = event__synthesize_modules(process_synthesized_event, 400 err = perf_event__synthesize_modules(process_synthesized_event,
464 psession, machine); 401 psession, machine);
465 if (err < 0) 402 if (err < 0)
466 pr_err("Couldn't record guest kernel [%d]'s reference" 403 pr_err("Couldn't record guest kernel [%d]'s reference"
467 " relocation symbol.\n", machine->pid); 404 " relocation symbol.\n", machine->pid);
@@ -470,11 +407,12 @@ static void event__synthesize_guest_os(struct machine *machine, void *data)
470 * We use _stext for guest kernel because guest kernel's /proc/kallsyms 407 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
471 * have no _text sometimes. 408 * have no _text sometimes.
472 */ 409 */
473 err = event__synthesize_kernel_mmap(process_synthesized_event, 410 err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
474 psession, machine, "_text"); 411 psession, machine, "_text");
475 if (err < 0) 412 if (err < 0)
476 err = event__synthesize_kernel_mmap(process_synthesized_event, 413 err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
477 psession, machine, "_stext"); 414 psession, machine,
415 "_stext");
478 if (err < 0) 416 if (err < 0)
479 pr_err("Couldn't record guest kernel [%d]'s reference" 417 pr_err("Couldn't record guest kernel [%d]'s reference"
480 " relocation symbol.\n", machine->pid); 418 " relocation symbol.\n", machine->pid);
@@ -489,9 +427,9 @@ static void mmap_read_all(void)
489{ 427{
490 int i; 428 int i;
491 429
492 for (i = 0; i < nr_cpu; i++) { 430 for (i = 0; i < evsel_list->nr_mmaps; i++) {
493 if (mmap_array[i].base) 431 if (evsel_list->mmap[i].base)
494 mmap_read(&mmap_array[i]); 432 mmap_read(&evsel_list->mmap[i]);
495 } 433 }
496 434
497 if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO)) 435 if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO))
@@ -500,7 +438,7 @@ static void mmap_read_all(void)
500 438
501static int __cmd_record(int argc, const char **argv) 439static int __cmd_record(int argc, const char **argv)
502{ 440{
503 int i, counter; 441 int i;
504 struct stat st; 442 struct stat st;
505 int flags; 443 int flags;
506 int err; 444 int err;
@@ -515,24 +453,33 @@ static int __cmd_record(int argc, const char **argv)
515 atexit(sig_atexit); 453 atexit(sig_atexit);
516 signal(SIGCHLD, sig_handler); 454 signal(SIGCHLD, sig_handler);
517 signal(SIGINT, sig_handler); 455 signal(SIGINT, sig_handler);
456 signal(SIGUSR1, sig_handler);
518 457
519 if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) { 458 if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) {
520 perror("failed to create pipes"); 459 perror("failed to create pipes");
521 exit(-1); 460 exit(-1);
522 } 461 }
523 462
524 if (!strcmp(output_name, "-")) 463 if (!output_name) {
525 pipe_output = 1; 464 if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
526 else if (!stat(output_name, &st) && st.st_size) { 465 pipe_output = 1;
527 if (write_mode == WRITE_FORCE) { 466 else
528 char oldname[PATH_MAX]; 467 output_name = "perf.data";
529 snprintf(oldname, sizeof(oldname), "%s.old", 468 }
530 output_name); 469 if (output_name) {
531 unlink(oldname); 470 if (!strcmp(output_name, "-"))
532 rename(output_name, oldname); 471 pipe_output = 1;
472 else if (!stat(output_name, &st) && st.st_size) {
473 if (write_mode == WRITE_FORCE) {
474 char oldname[PATH_MAX];
475 snprintf(oldname, sizeof(oldname), "%s.old",
476 output_name);
477 unlink(oldname);
478 rename(output_name, oldname);
479 }
480 } else if (write_mode == WRITE_APPEND) {
481 write_mode = WRITE_FORCE;
533 } 482 }
534 } else if (write_mode == WRITE_APPEND) {
535 write_mode = WRITE_FORCE;
536 } 483 }
537 484
538 flags = O_CREAT|O_RDWR; 485 flags = O_CREAT|O_RDWR;
@@ -551,25 +498,27 @@ static int __cmd_record(int argc, const char **argv)
551 } 498 }
552 499
553 session = perf_session__new(output_name, O_WRONLY, 500 session = perf_session__new(output_name, O_WRONLY,
554 write_mode == WRITE_FORCE, false); 501 write_mode == WRITE_FORCE, false, NULL);
555 if (session == NULL) { 502 if (session == NULL) {
556 pr_err("Not enough memory for reading perf file header\n"); 503 pr_err("Not enough memory for reading perf file header\n");
557 return -1; 504 return -1;
558 } 505 }
559 506
507 if (!no_buildid)
508 perf_header__set_feat(&session->header, HEADER_BUILD_ID);
509
560 if (!file_new) { 510 if (!file_new) {
561 err = perf_header__read(session, output); 511 err = perf_session__read_header(session, output);
562 if (err < 0) 512 if (err < 0)
563 goto out_delete_session; 513 goto out_delete_session;
564 } 514 }
565 515
566 if (have_tracepoints(attrs, nr_counters)) 516 if (have_tracepoints(&evsel_list->entries))
567 perf_header__set_feat(&session->header, HEADER_TRACE_INFO); 517 perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
568 518
569 /* 519 /* 512 kiB: default amount of unprivileged mlocked memory */
570 * perf_session__delete(session) will be called at atexit_header() 520 if (mmap_pages == UINT_MAX)
571 */ 521 mmap_pages = (512 * 1024) / page_size;
572 atexit(atexit_header);
573 522
574 if (forks) { 523 if (forks) {
575 child_pid = fork(); 524 child_pid = fork();
@@ -606,11 +555,12 @@ static int __cmd_record(int argc, const char **argv)
606 execvp(argv[0], (char **)argv); 555 execvp(argv[0], (char **)argv);
607 556
608 perror(argv[0]); 557 perror(argv[0]);
558 kill(getppid(), SIGUSR1);
609 exit(-1); 559 exit(-1);
610 } 560 }
611 561
612 if (!system_wide && target_tid == -1 && target_pid == -1) 562 if (!system_wide && target_tid == -1 && target_pid == -1)
613 all_tids[0] = child_pid; 563 evsel_list->threads->map[0] = child_pid;
614 564
615 close(child_ready_pipe[1]); 565 close(child_ready_pipe[1]);
616 close(go_pipe[0]); 566 close(go_pipe[0]);
@@ -624,25 +574,20 @@ static int __cmd_record(int argc, const char **argv)
624 close(child_ready_pipe[0]); 574 close(child_ready_pipe[0]);
625 } 575 }
626 576
627 nr_cpus = read_cpu_map(cpu_list); 577 open_counters(evsel_list);
628 if (nr_cpus < 1) {
629 perror("failed to collect number of CPUs\n");
630 return -1;
631 }
632 578
633 if (!system_wide && no_inherit && !cpu_list) { 579 /*
634 open_counters(-1); 580 * perf_session__delete(session) will be called at atexit_header()
635 } else { 581 */
636 for (i = 0; i < nr_cpus; i++) 582 atexit(atexit_header);
637 open_counters(cpumap[i]);
638 }
639 583
640 if (pipe_output) { 584 if (pipe_output) {
641 err = perf_header__write_pipe(output); 585 err = perf_header__write_pipe(output);
642 if (err < 0) 586 if (err < 0)
643 return err; 587 return err;
644 } else if (file_new) { 588 } else if (file_new) {
645 err = perf_header__write(&session->header, output, false); 589 err = perf_session__write_header(session, evsel_list,
590 output, false);
646 if (err < 0) 591 if (err < 0)
647 return err; 592 return err;
648 } 593 }
@@ -650,22 +595,21 @@ static int __cmd_record(int argc, const char **argv)
650 post_processing_offset = lseek(output, 0, SEEK_CUR); 595 post_processing_offset = lseek(output, 0, SEEK_CUR);
651 596
652 if (pipe_output) { 597 if (pipe_output) {
653 err = event__synthesize_attrs(&session->header, 598 err = perf_session__synthesize_attrs(session,
654 process_synthesized_event, 599 process_synthesized_event);
655 session);
656 if (err < 0) { 600 if (err < 0) {
657 pr_err("Couldn't synthesize attrs.\n"); 601 pr_err("Couldn't synthesize attrs.\n");
658 return err; 602 return err;
659 } 603 }
660 604
661 err = event__synthesize_event_types(process_synthesized_event, 605 err = perf_event__synthesize_event_types(process_synthesized_event,
662 session); 606 session);
663 if (err < 0) { 607 if (err < 0) {
664 pr_err("Couldn't synthesize event_types.\n"); 608 pr_err("Couldn't synthesize event_types.\n");
665 return err; 609 return err;
666 } 610 }
667 611
668 if (have_tracepoints(attrs, nr_counters)) { 612 if (have_tracepoints(&evsel_list->entries)) {
669 /* 613 /*
670 * FIXME err <= 0 here actually means that 614 * FIXME err <= 0 here actually means that
671 * there were no tracepoints so its not really 615 * there were no tracepoints so its not really
@@ -674,10 +618,9 @@ static int __cmd_record(int argc, const char **argv)
674 * return this more properly and also 618 * return this more properly and also
675 * propagate errors that now are calling die() 619 * propagate errors that now are calling die()
676 */ 620 */
677 err = event__synthesize_tracing_data(output, attrs, 621 err = perf_event__synthesize_tracing_data(output, evsel_list,
678 nr_counters, 622 process_synthesized_event,
679 process_synthesized_event, 623 session);
680 session);
681 if (err <= 0) { 624 if (err <= 0) {
682 pr_err("Couldn't record tracing data.\n"); 625 pr_err("Couldn't record tracing data.\n");
683 return err; 626 return err;
@@ -692,30 +635,34 @@ static int __cmd_record(int argc, const char **argv)
692 return -1; 635 return -1;
693 } 636 }
694 637
695 err = event__synthesize_kernel_mmap(process_synthesized_event, 638 err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
696 session, machine, "_text"); 639 session, machine, "_text");
697 if (err < 0) 640 if (err < 0)
698 err = event__synthesize_kernel_mmap(process_synthesized_event, 641 err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
699 session, machine, "_stext"); 642 session, machine, "_stext");
700 if (err < 0) { 643 if (err < 0)
701 pr_err("Couldn't record kernel reference relocation symbol.\n"); 644 pr_err("Couldn't record kernel reference relocation symbol\n"
702 return err; 645 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
703 } 646 "Check /proc/kallsyms permission or run as root.\n");
647
648 err = perf_event__synthesize_modules(process_synthesized_event,
649 session, machine);
650 if (err < 0)
651 pr_err("Couldn't record kernel module information.\n"
652 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
653 "Check /proc/modules permission or run as root.\n");
704 654
705 err = event__synthesize_modules(process_synthesized_event,
706 session, machine);
707 if (err < 0) {
708 pr_err("Couldn't record kernel reference relocation symbol.\n");
709 return err;
710 }
711 if (perf_guest) 655 if (perf_guest)
712 perf_session__process_machines(session, event__synthesize_guest_os); 656 perf_session__process_machines(session,
657 perf_event__synthesize_guest_os);
713 658
714 if (!system_wide) 659 if (!system_wide)
715 event__synthesize_thread(target_tid, process_synthesized_event, 660 perf_event__synthesize_thread_map(evsel_list->threads,
716 session); 661 process_synthesized_event,
662 session);
717 else 663 else
718 event__synthesize_threads(process_synthesized_event, session); 664 perf_event__synthesize_threads(process_synthesized_event,
665 session);
719 666
720 if (realtime_prio) { 667 if (realtime_prio) {
721 struct sched_param param; 668 struct sched_param param;
@@ -742,32 +689,35 @@ static int __cmd_record(int argc, const char **argv)
742 if (hits == samples) { 689 if (hits == samples) {
743 if (done) 690 if (done)
744 break; 691 break;
745 err = poll(event_array, nr_poll, -1); 692 err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
746 waking++; 693 waking++;
747 } 694 }
748 695
749 if (done) { 696 if (done) {
750 for (i = 0; i < nr_cpu; i++) { 697 for (i = 0; i < evsel_list->cpus->nr; i++) {
751 for (counter = 0; 698 struct perf_evsel *pos;
752 counter < nr_counters; 699
753 counter++) { 700 list_for_each_entry(pos, &evsel_list->entries, node) {
754 for (thread = 0; 701 for (thread = 0;
755 thread < thread_num; 702 thread < evsel_list->threads->nr;
756 thread++) 703 thread++)
757 ioctl(fd[i][counter][thread], 704 ioctl(FD(pos, i, thread),
758 PERF_EVENT_IOC_DISABLE); 705 PERF_EVENT_IOC_DISABLE);
759 } 706 }
760 } 707 }
761 } 708 }
762 } 709 }
763 710
711 if (quiet || signr == SIGUSR1)
712 return 0;
713
764 fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking); 714 fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
765 715
766 /* 716 /*
767 * Approximate RIP event size: 24 bytes. 717 * Approximate RIP event size: 24 bytes.
768 */ 718 */
769 fprintf(stderr, 719 fprintf(stderr,
770 "[ perf record: Captured and wrote %.3f MB %s (~%lld samples) ]\n", 720 "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
771 (double)bytes_written / 1024.0 / 1024.0, 721 (double)bytes_written / 1024.0 / 1024.0,
772 output_name, 722 output_name,
773 bytes_written / 24); 723 bytes_written / 24);
@@ -787,11 +737,11 @@ static const char * const record_usage[] = {
787 737
788static bool force, append_file; 738static bool force, append_file;
789 739
790static const struct option options[] = { 740const struct option record_options[] = {
791 OPT_CALLBACK('e', "event", NULL, "event", 741 OPT_CALLBACK('e', "event", &evsel_list, "event",
792 "event selector. use 'perf list' to list available events", 742 "event selector. use 'perf list' to list available events",
793 parse_events), 743 parse_events),
794 OPT_CALLBACK(0, "filter", NULL, "filter", 744 OPT_CALLBACK(0, "filter", &evsel_list, "filter",
795 "event filter", parse_filter), 745 "event filter", parse_filter),
796 OPT_INTEGER('p', "pid", &target_pid, 746 OPT_INTEGER('p', "pid", &target_pid,
797 "record events on existing process id"), 747 "record events on existing process id"),
@@ -799,6 +749,8 @@ static const struct option options[] = {
799 "record events on existing thread id"), 749 "record events on existing thread id"),
800 OPT_INTEGER('r', "realtime", &realtime_prio, 750 OPT_INTEGER('r', "realtime", &realtime_prio,
801 "collect data with this RT SCHED_FIFO priority"), 751 "collect data with this RT SCHED_FIFO priority"),
752 OPT_BOOLEAN('D', "no-delay", &nodelay,
753 "collect data without buffering"),
802 OPT_BOOLEAN('R', "raw-samples", &raw_samples, 754 OPT_BOOLEAN('R', "raw-samples", &raw_samples,
803 "collect raw sample records from all opened counters"), 755 "collect raw sample records from all opened counters"),
804 OPT_BOOLEAN('a', "all-cpus", &system_wide, 756 OPT_BOOLEAN('a', "all-cpus", &system_wide,
@@ -820,74 +772,92 @@ static const struct option options[] = {
820 "do call-graph (stack chain/backtrace) recording"), 772 "do call-graph (stack chain/backtrace) recording"),
821 OPT_INCR('v', "verbose", &verbose, 773 OPT_INCR('v', "verbose", &verbose,
822 "be more verbose (show counter open errors, etc)"), 774 "be more verbose (show counter open errors, etc)"),
775 OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
823 OPT_BOOLEAN('s', "stat", &inherit_stat, 776 OPT_BOOLEAN('s', "stat", &inherit_stat,
824 "per thread counts"), 777 "per thread counts"),
825 OPT_BOOLEAN('d', "data", &sample_address, 778 OPT_BOOLEAN('d', "data", &sample_address,
826 "Sample addresses"), 779 "Sample addresses"),
780 OPT_BOOLEAN('T', "timestamp", &sample_time, "Sample timestamps"),
827 OPT_BOOLEAN('n', "no-samples", &no_samples, 781 OPT_BOOLEAN('n', "no-samples", &no_samples,
828 "don't sample"), 782 "don't sample"),
829 OPT_BOOLEAN('N', "no-buildid-cache", &no_buildid, 783 OPT_BOOLEAN('N', "no-buildid-cache", &no_buildid_cache,
830 "do not update the buildid cache"), 784 "do not update the buildid cache"),
785 OPT_BOOLEAN('B', "no-buildid", &no_buildid,
786 "do not collect buildids in perf.data"),
787 OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
788 "monitor event in cgroup name only",
789 parse_cgroups),
831 OPT_END() 790 OPT_END()
832}; 791};
833 792
834int cmd_record(int argc, const char **argv, const char *prefix __used) 793int cmd_record(int argc, const char **argv, const char *prefix __used)
835{ 794{
836 int i, j, err = -ENOMEM; 795 int err = -ENOMEM;
796 struct perf_evsel *pos;
837 797
838 argc = parse_options(argc, argv, options, record_usage, 798 evsel_list = perf_evlist__new(NULL, NULL);
799 if (evsel_list == NULL)
800 return -ENOMEM;
801
802 argc = parse_options(argc, argv, record_options, record_usage,
839 PARSE_OPT_STOP_AT_NON_OPTION); 803 PARSE_OPT_STOP_AT_NON_OPTION);
840 if (!argc && target_pid == -1 && target_tid == -1 && 804 if (!argc && target_pid == -1 && target_tid == -1 &&
841 !system_wide && !cpu_list) 805 !system_wide && !cpu_list)
842 usage_with_options(record_usage, options); 806 usage_with_options(record_usage, record_options);
843 807
844 if (force && append_file) { 808 if (force && append_file) {
845 fprintf(stderr, "Can't overwrite and append at the same time." 809 fprintf(stderr, "Can't overwrite and append at the same time."
846 " You need to choose between -f and -A"); 810 " You need to choose between -f and -A");
847 usage_with_options(record_usage, options); 811 usage_with_options(record_usage, record_options);
848 } else if (append_file) { 812 } else if (append_file) {
849 write_mode = WRITE_APPEND; 813 write_mode = WRITE_APPEND;
850 } else { 814 } else {
851 write_mode = WRITE_FORCE; 815 write_mode = WRITE_FORCE;
852 } 816 }
853 817
818 if (nr_cgroups && !system_wide) {
819 fprintf(stderr, "cgroup monitoring only available in"
820 " system-wide mode\n");
821 usage_with_options(record_usage, record_options);
822 }
823
854 symbol__init(); 824 symbol__init();
855 if (no_buildid) 825
826 if (symbol_conf.kptr_restrict)
827 pr_warning(
828"WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
829"check /proc/sys/kernel/kptr_restrict.\n\n"
830"Samples in kernel functions may not be resolved if a suitable vmlinux\n"
831"file is not found in the buildid cache or in the vmlinux path.\n\n"
832"Samples in kernel modules won't be resolved at all.\n\n"
833"If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
834"even with a suitable vmlinux or kallsyms file.\n\n");
835
836 if (no_buildid_cache || no_buildid)
856 disable_buildid_cache(); 837 disable_buildid_cache();
857 838
858 if (!nr_counters) { 839 if (evsel_list->nr_entries == 0 &&
859 nr_counters = 1; 840 perf_evlist__add_default(evsel_list) < 0) {
860 attrs[0].type = PERF_TYPE_HARDWARE; 841 pr_err("Not enough memory for event selector list\n");
861 attrs[0].config = PERF_COUNT_HW_CPU_CYCLES; 842 goto out_symbol_exit;
862 } 843 }
863 844
864 if (target_pid != -1) { 845 if (target_pid != -1)
865 target_tid = target_pid; 846 target_tid = target_pid;
866 thread_num = find_all_tid(target_pid, &all_tids);
867 if (thread_num <= 0) {
868 fprintf(stderr, "Can't find all threads of pid %d\n",
869 target_pid);
870 usage_with_options(record_usage, options);
871 }
872 } else {
873 all_tids=malloc(sizeof(pid_t));
874 if (!all_tids)
875 goto out_symbol_exit;
876 847
877 all_tids[0] = target_tid; 848 if (perf_evlist__create_maps(evsel_list, target_pid,
878 thread_num = 1; 849 target_tid, cpu_list) < 0)
879 } 850 usage_with_options(record_usage, record_options);
880 851
881 for (i = 0; i < MAX_NR_CPUS; i++) { 852 list_for_each_entry(pos, &evsel_list->entries, node) {
882 for (j = 0; j < MAX_COUNTERS; j++) { 853 if (perf_evsel__alloc_fd(pos, evsel_list->cpus->nr,
883 fd[i][j] = malloc(sizeof(int)*thread_num); 854 evsel_list->threads->nr) < 0)
884 if (!fd[i][j]) 855 goto out_free_fd;
885 goto out_free_fd; 856 if (perf_header__push_event(pos->attr.config, event_name(pos)))
886 } 857 goto out_free_fd;
887 } 858 }
888 event_array = malloc( 859
889 sizeof(struct pollfd)*MAX_NR_CPUS*MAX_COUNTERS*thread_num); 860 if (perf_evlist__alloc_pollfd(evsel_list) < 0)
890 if (!event_array)
891 goto out_free_fd; 861 goto out_free_fd;
892 862
893 if (user_interval != ULLONG_MAX) 863 if (user_interval != ULLONG_MAX)
@@ -905,20 +875,12 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
905 } else { 875 } else {
906 fprintf(stderr, "frequency and count are zero, aborting\n"); 876 fprintf(stderr, "frequency and count are zero, aborting\n");
907 err = -EINVAL; 877 err = -EINVAL;
908 goto out_free_event_array; 878 goto out_free_fd;
909 } 879 }
910 880
911 err = __cmd_record(argc, argv); 881 err = __cmd_record(argc, argv);
912
913out_free_event_array:
914 free(event_array);
915out_free_fd: 882out_free_fd:
916 for (i = 0; i < MAX_NR_CPUS; i++) { 883 perf_evlist__delete_maps(evsel_list);
917 for (j = 0; j < MAX_COUNTERS; j++)
918 free(fd[i][j]);
919 }
920 free(all_tids);
921 all_tids = NULL;
922out_symbol_exit: 884out_symbol_exit:
923 symbol__exit(); 885 symbol__exit();
924 return err; 886 return err;
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 55fc1f46892a..287a173523a7 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -9,6 +9,7 @@
9 9
10#include "util/util.h" 10#include "util/util.h"
11 11
12#include "util/annotate.h"
12#include "util/color.h" 13#include "util/color.h"
13#include <linux/list.h> 14#include <linux/list.h>
14#include "util/cache.h" 15#include "util/cache.h"
@@ -20,6 +21,8 @@
20 21
21#include "perf.h" 22#include "perf.h"
22#include "util/debug.h" 23#include "util/debug.h"
24#include "util/evlist.h"
25#include "util/evsel.h"
23#include "util/header.h" 26#include "util/header.h"
24#include "util/session.h" 27#include "util/session.h"
25 28
@@ -32,7 +35,7 @@
32 35
33static char const *input_name = "perf.data"; 36static char const *input_name = "perf.data";
34 37
35static bool force; 38static bool force, use_tui, use_stdio;
36static bool hide_unresolved; 39static bool hide_unresolved;
37static bool dont_use_callchains; 40static bool dont_use_callchains;
38 41
@@ -43,119 +46,68 @@ static const char default_pretty_printing_style[] = "normal";
43static const char *pretty_printing_style = default_pretty_printing_style; 46static const char *pretty_printing_style = default_pretty_printing_style;
44 47
45static char callchain_default_opt[] = "fractal,0.5"; 48static char callchain_default_opt[] = "fractal,0.5";
49static symbol_filter_t annotate_init;
46 50
47static struct hists *perf_session__hists_findnew(struct perf_session *self, 51static int perf_session__add_hist_entry(struct perf_session *session,
48 u64 event_stream, u32 type,
49 u64 config)
50{
51 struct rb_node **p = &self->hists_tree.rb_node;
52 struct rb_node *parent = NULL;
53 struct hists *iter, *new;
54
55 while (*p != NULL) {
56 parent = *p;
57 iter = rb_entry(parent, struct hists, rb_node);
58 if (iter->config == config)
59 return iter;
60
61
62 if (config > iter->config)
63 p = &(*p)->rb_right;
64 else
65 p = &(*p)->rb_left;
66 }
67
68 new = malloc(sizeof(struct hists));
69 if (new == NULL)
70 return NULL;
71 memset(new, 0, sizeof(struct hists));
72 new->event_stream = event_stream;
73 new->config = config;
74 new->type = type;
75 rb_link_node(&new->rb_node, parent, p);
76 rb_insert_color(&new->rb_node, &self->hists_tree);
77 return new;
78}
79
80static int perf_session__add_hist_entry(struct perf_session *self,
81 struct addr_location *al, 52 struct addr_location *al,
82 struct sample_data *data) 53 struct perf_sample *sample,
54 struct perf_evsel *evsel)
83{ 55{
84 struct map_symbol *syms = NULL;
85 struct symbol *parent = NULL; 56 struct symbol *parent = NULL;
86 int err = -ENOMEM; 57 int err = 0;
87 struct hist_entry *he; 58 struct hist_entry *he;
88 struct hists *hists; 59
89 struct perf_event_attr *attr; 60 if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) {
90 61 err = perf_session__resolve_callchain(session, al->thread,
91 if ((sort__has_parent || symbol_conf.use_callchain) && data->callchain) { 62 sample->callchain, &parent);
92 syms = perf_session__resolve_callchain(self, al->thread, 63 if (err)
93 data->callchain, &parent); 64 return err;
94 if (syms == NULL)
95 return -ENOMEM;
96 } 65 }
97 66
98 attr = perf_header__find_attr(data->id, &self->header); 67 he = __hists__add_entry(&evsel->hists, al, parent, sample->period);
99 if (attr)
100 hists = perf_session__hists_findnew(self, data->id, attr->type, attr->config);
101 else
102 hists = perf_session__hists_findnew(self, data->id, 0, 0);
103 if (hists == NULL)
104 goto out_free_syms;
105 he = __hists__add_entry(hists, al, parent, data->period);
106 if (he == NULL) 68 if (he == NULL)
107 goto out_free_syms; 69 return -ENOMEM;
108 err = 0; 70
109 if (symbol_conf.use_callchain) { 71 if (symbol_conf.use_callchain) {
110 err = append_chain(he->callchain, data->callchain, syms, data->period); 72 err = callchain_append(he->callchain, &session->callchain_cursor,
73 sample->period);
111 if (err) 74 if (err)
112 goto out_free_syms; 75 return err;
113 } 76 }
114 /* 77 /*
115 * Only in the newt browser we are doing integrated annotation, 78 * Only in the newt browser we are doing integrated annotation,
116 * so we don't allocated the extra space needed because the stdio 79 * so we don't allocated the extra space needed because the stdio
117 * code will not use it. 80 * code will not use it.
118 */ 81 */
119 if (use_browser > 0) 82 if (al->sym != NULL && use_browser > 0) {
120 err = hist_entry__inc_addr_samples(he, al->addr); 83 struct annotation *notes = symbol__annotation(he->ms.sym);
121out_free_syms:
122 free(syms);
123 return err;
124}
125 84
126static int add_event_total(struct perf_session *session, 85 assert(evsel != NULL);
127 struct sample_data *data,
128 struct perf_event_attr *attr)
129{
130 struct hists *hists;
131 86
132 if (attr) 87 err = -ENOMEM;
133 hists = perf_session__hists_findnew(session, data->id, 88 if (notes->src == NULL &&
134 attr->type, attr->config); 89 symbol__alloc_hist(he->ms.sym, session->evlist->nr_entries) < 0)
135 else 90 goto out;
136 hists = perf_session__hists_findnew(session, data->id, 0, 0);
137 91
138 if (!hists) 92 err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
139 return -ENOMEM; 93 }
140 94
141 hists->stats.total_period += data->period; 95 evsel->hists.stats.total_period += sample->period;
142 /* 96 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
143 * FIXME: add_event_total should be moved from here to 97out:
144 * perf_session__process_event so that the proper hist is passed to 98 return err;
145 * the event_op methods.
146 */
147 hists__inc_nr_events(hists, PERF_RECORD_SAMPLE);
148 session->hists.stats.total_period += data->period;
149 return 0;
150} 99}
151 100
152static int process_sample_event(event_t *event, struct perf_session *session) 101
102static int process_sample_event(union perf_event *event,
103 struct perf_sample *sample,
104 struct perf_evsel *evsel,
105 struct perf_session *session)
153{ 106{
154 struct sample_data data = { .period = 1, };
155 struct addr_location al; 107 struct addr_location al;
156 struct perf_event_attr *attr;
157 108
158 if (event__preprocess_sample(event, session, &al, &data, NULL) < 0) { 109 if (perf_event__preprocess_sample(event, session, &al, sample,
110 annotate_init) < 0) {
159 fprintf(stderr, "problem processing %d event, skipping it.\n", 111 fprintf(stderr, "problem processing %d event, skipping it.\n",
160 event->header.type); 112 event->header.type);
161 return -1; 113 return -1;
@@ -164,30 +116,25 @@ static int process_sample_event(event_t *event, struct perf_session *session)
164 if (al.filtered || (hide_unresolved && al.sym == NULL)) 116 if (al.filtered || (hide_unresolved && al.sym == NULL))
165 return 0; 117 return 0;
166 118
167 if (perf_session__add_hist_entry(session, &al, &data)) { 119 if (al.map != NULL)
168 pr_debug("problem incrementing symbol period, skipping event\n"); 120 al.map->dso->hit = 1;
169 return -1;
170 }
171 121
172 attr = perf_header__find_attr(data.id, &session->header); 122 if (perf_session__add_hist_entry(session, &al, sample, evsel)) {
173 123 pr_debug("problem incrementing symbol period, skipping event\n");
174 if (add_event_total(session, &data, attr)) {
175 pr_debug("problem adding event period\n");
176 return -1; 124 return -1;
177 } 125 }
178 126
179 return 0; 127 return 0;
180} 128}
181 129
182static int process_read_event(event_t *event, struct perf_session *session __used) 130static int process_read_event(union perf_event *event,
131 struct perf_sample *sample __used,
132 struct perf_session *session)
183{ 133{
184 struct perf_event_attr *attr; 134 struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist,
185 135 event->read.id);
186 attr = perf_header__find_attr(event->read.id, &session->header);
187
188 if (show_threads) { 136 if (show_threads) {
189 const char *name = attr ? __event_name(attr->type, attr->config) 137 const char *name = evsel ? event_name(evsel) : "unknown";
190 : "unknown";
191 perf_read_values_add_value(&show_threads_values, 138 perf_read_values_add_value(&show_threads_values,
192 event->read.pid, event->read.tid, 139 event->read.pid, event->read.tid,
193 event->read.id, 140 event->read.id,
@@ -195,8 +142,8 @@ static int process_read_event(event_t *event, struct perf_session *session __use
195 event->read.value); 142 event->read.value);
196 } 143 }
197 144
198 dump_printf(": %d %d %s %Lu\n", event->read.pid, event->read.tid, 145 dump_printf(": %d %d %s %" PRIu64 "\n", event->read.pid, event->read.tid,
199 attr ? __event_name(attr->type, attr->config) : "FAIL", 146 evsel ? event_name(evsel) : "FAIL",
200 event->read.value); 147 event->read.value);
201 148
202 return 0; 149 return 0;
@@ -220,7 +167,7 @@ static int perf_session__setup_sample_type(struct perf_session *self)
220 } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE && 167 } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE &&
221 !symbol_conf.use_callchain) { 168 !symbol_conf.use_callchain) {
222 symbol_conf.use_callchain = true; 169 symbol_conf.use_callchain = true;
223 if (register_callchain_param(&callchain_param) < 0) { 170 if (callchain_register_param(&callchain_param) < 0) {
224 fprintf(stderr, "Can't register callchain" 171 fprintf(stderr, "Can't register callchain"
225 " params\n"); 172 " params\n");
226 return -EINVAL; 173 return -EINVAL;
@@ -231,17 +178,19 @@ static int perf_session__setup_sample_type(struct perf_session *self)
231} 178}
232 179
233static struct perf_event_ops event_ops = { 180static struct perf_event_ops event_ops = {
234 .sample = process_sample_event, 181 .sample = process_sample_event,
235 .mmap = event__process_mmap, 182 .mmap = perf_event__process_mmap,
236 .comm = event__process_comm, 183 .comm = perf_event__process_comm,
237 .exit = event__process_task, 184 .exit = perf_event__process_task,
238 .fork = event__process_task, 185 .fork = perf_event__process_task,
239 .lost = event__process_lost, 186 .lost = perf_event__process_lost,
240 .read = process_read_event, 187 .read = process_read_event,
241 .attr = event__process_attr, 188 .attr = perf_event__process_attr,
242 .event_type = event__process_event_type, 189 .event_type = perf_event__process_event_type,
243 .tracing_data = event__process_tracing_data, 190 .tracing_data = perf_event__process_tracing_data,
244 .build_id = event__process_build_id, 191 .build_id = perf_event__process_build_id,
192 .ordered_samples = true,
193 .ordering_requires_timestamps = true,
245}; 194};
246 195
247extern volatile int session_done; 196extern volatile int session_done;
@@ -265,21 +214,21 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self,
265 return ret + fprintf(fp, "\n#\n"); 214 return ret + fprintf(fp, "\n#\n");
266} 215}
267 216
268static int hists__tty_browse_tree(struct rb_root *tree, const char *help) 217static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
218 const char *help)
269{ 219{
270 struct rb_node *next = rb_first(tree); 220 struct perf_evsel *pos;
271 221
272 while (next) { 222 list_for_each_entry(pos, &evlist->entries, node) {
273 struct hists *hists = rb_entry(next, struct hists, rb_node); 223 struct hists *hists = &pos->hists;
274 const char *evname = NULL; 224 const char *evname = NULL;
275 225
276 if (rb_first(&hists->entries) != rb_last(&hists->entries)) 226 if (rb_first(&hists->entries) != rb_last(&hists->entries))
277 evname = __event_name(hists->type, hists->config); 227 evname = event_name(pos);
278 228
279 hists__fprintf_nr_sample_events(hists, evname, stdout); 229 hists__fprintf_nr_sample_events(hists, evname, stdout);
280 hists__fprintf(hists, NULL, false, stdout); 230 hists__fprintf(hists, NULL, false, stdout);
281 fprintf(stdout, "\n\n"); 231 fprintf(stdout, "\n\n");
282 next = rb_next(&hists->rb_node);
283 } 232 }
284 233
285 if (sort_order == default_sort_order && 234 if (sort_order == default_sort_order &&
@@ -300,13 +249,16 @@ static int hists__tty_browse_tree(struct rb_root *tree, const char *help)
300static int __cmd_report(void) 249static int __cmd_report(void)
301{ 250{
302 int ret = -EINVAL; 251 int ret = -EINVAL;
252 u64 nr_samples;
303 struct perf_session *session; 253 struct perf_session *session;
304 struct rb_node *next; 254 struct perf_evsel *pos;
255 struct map *kernel_map;
256 struct kmap *kernel_kmap;
305 const char *help = "For a higher level overview, try: perf report --sort comm,dso"; 257 const char *help = "For a higher level overview, try: perf report --sort comm,dso";
306 258
307 signal(SIGINT, sig_handler); 259 signal(SIGINT, sig_handler);
308 260
309 session = perf_session__new(input_name, O_RDONLY, force, false); 261 session = perf_session__new(input_name, O_RDONLY, force, false, &event_ops);
310 if (session == NULL) 262 if (session == NULL)
311 return -ENOMEM; 263 return -ENOMEM;
312 264
@@ -321,6 +273,24 @@ static int __cmd_report(void)
321 if (ret) 273 if (ret)
322 goto out_delete; 274 goto out_delete;
323 275
276 kernel_map = session->host_machine.vmlinux_maps[MAP__FUNCTION];
277 kernel_kmap = map__kmap(kernel_map);
278 if (kernel_map == NULL ||
279 (kernel_map->dso->hit &&
280 (kernel_kmap->ref_reloc_sym == NULL ||
281 kernel_kmap->ref_reloc_sym->addr == 0))) {
282 const struct dso *kdso = kernel_map->dso;
283
284 ui__warning(
285"Kernel address maps (/proc/{kallsyms,modules}) were restricted.\n\n"
286"Check /proc/sys/kernel/kptr_restrict before running 'perf record'.\n\n%s\n\n"
287"Samples in kernel modules can't be resolved as well.\n\n",
288 RB_EMPTY_ROOT(&kdso->symbols[MAP__FUNCTION]) ?
289"As no suitable kallsyms nor vmlinux was found, kernel samples\n"
290"can't be resolved." :
291"If some relocation was applied (e.g. kexec) symbols may be misresolved.");
292 }
293
324 if (dump_trace) { 294 if (dump_trace) {
325 perf_session__fprintf_nr_events(session, stdout); 295 perf_session__fprintf_nr_events(session, stdout);
326 goto out_delete; 296 goto out_delete;
@@ -332,20 +302,24 @@ static int __cmd_report(void)
332 if (verbose > 2) 302 if (verbose > 2)
333 perf_session__fprintf_dsos(session, stdout); 303 perf_session__fprintf_dsos(session, stdout);
334 304
335 next = rb_first(&session->hists_tree); 305 nr_samples = 0;
336 while (next) { 306 list_for_each_entry(pos, &session->evlist->entries, node) {
337 struct hists *hists; 307 struct hists *hists = &pos->hists;
338 308
339 hists = rb_entry(next, struct hists, rb_node);
340 hists__collapse_resort(hists); 309 hists__collapse_resort(hists);
341 hists__output_resort(hists); 310 hists__output_resort(hists);
342 next = rb_next(&hists->rb_node); 311 nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE];
312 }
313
314 if (nr_samples == 0) {
315 ui__warning("The %s file has no samples!\n", input_name);
316 goto out_delete;
343 } 317 }
344 318
345 if (use_browser > 0) 319 if (use_browser > 0)
346 hists__tui_browse_tree(&session->hists_tree, help); 320 perf_evlist__tui_browse_hists(session->evlist, help);
347 else 321 else
348 hists__tty_browse_tree(&session->hists_tree, help); 322 perf_evlist__tty_browse_hists(session->evlist, help);
349 323
350out_delete: 324out_delete:
351 /* 325 /*
@@ -420,7 +394,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
420 if (tok2) 394 if (tok2)
421 callchain_param.print_limit = strtod(tok2, &endptr); 395 callchain_param.print_limit = strtod(tok2, &endptr);
422setup: 396setup:
423 if (register_callchain_param(&callchain_param) < 0) { 397 if (callchain_register_param(&callchain_param) < 0) {
424 fprintf(stderr, "Can't register callchain params\n"); 398 fprintf(stderr, "Can't register callchain params\n");
425 return -1; 399 return -1;
426 } 400 }
@@ -441,6 +415,8 @@ static const struct option options[] = {
441 "dump raw trace in ASCII"), 415 "dump raw trace in ASCII"),
442 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 416 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
443 "file", "vmlinux pathname"), 417 "file", "vmlinux pathname"),
418 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
419 "file", "kallsyms pathname"),
444 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), 420 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
445 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, 421 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
446 "load module symbols - WARNING: use only with -k and LIVE kernel"), 422 "load module symbols - WARNING: use only with -k and LIVE kernel"),
@@ -450,6 +426,8 @@ static const struct option options[] = {
450 "Show per-thread event counters"), 426 "Show per-thread event counters"),
451 OPT_STRING(0, "pretty", &pretty_printing_style, "key", 427 OPT_STRING(0, "pretty", &pretty_printing_style, "key",
452 "pretty printing style key: normal raw"), 428 "pretty printing style key: normal raw"),
429 OPT_BOOLEAN(0, "tui", &use_tui, "Use the TUI interface"),
430 OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"),
453 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 431 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
454 "sort by key(s): pid, comm, dso, symbol, parent"), 432 "sort by key(s): pid, comm, dso, symbol, parent"),
455 OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization, 433 OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
@@ -475,6 +453,8 @@ static const struct option options[] = {
475 "columns '.' is reserved."), 453 "columns '.' is reserved."),
476 OPT_BOOLEAN('U', "hide-unresolved", &hide_unresolved, 454 OPT_BOOLEAN('U', "hide-unresolved", &hide_unresolved,
477 "Only display entries resolved to a symbol"), 455 "Only display entries resolved to a symbol"),
456 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
457 "Look for files with symbols relative to this directory"),
478 OPT_END() 458 OPT_END()
479}; 459};
480 460
@@ -482,15 +462,23 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
482{ 462{
483 argc = parse_options(argc, argv, options, report_usage, 0); 463 argc = parse_options(argc, argv, options, report_usage, 0);
484 464
465 if (use_stdio)
466 use_browser = 0;
467 else if (use_tui)
468 use_browser = 1;
469
485 if (strcmp(input_name, "-") != 0) 470 if (strcmp(input_name, "-") != 0)
486 setup_browser(); 471 setup_browser(true);
472 else
473 use_browser = 0;
487 /* 474 /*
488 * Only in the newt browser we are doing integrated annotation, 475 * Only in the newt browser we are doing integrated annotation,
489 * so don't allocate extra space that won't be used in the stdio 476 * so don't allocate extra space that won't be used in the stdio
490 * implementation. 477 * implementation.
491 */ 478 */
492 if (use_browser > 0) { 479 if (use_browser > 0) {
493 symbol_conf.priv_size = sizeof(struct sym_priv); 480 symbol_conf.priv_size = sizeof(struct annotation);
481 annotate_init = symbol__annotate_init;
494 /* 482 /*
495 * For searching by name on the "Browse map details". 483 * For searching by name on the "Browse map details".
496 * providing it only in verbose mode not to bloat too 484 * providing it only in verbose mode not to bloat too
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 55f3b5dcc731..dcfe8873c9a1 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -193,7 +193,7 @@ static void calibrate_run_measurement_overhead(void)
193 } 193 }
194 run_measurement_overhead = min_delta; 194 run_measurement_overhead = min_delta;
195 195
196 printf("run measurement overhead: %Ld nsecs\n", min_delta); 196 printf("run measurement overhead: %" PRIu64 " nsecs\n", min_delta);
197} 197}
198 198
199static void calibrate_sleep_measurement_overhead(void) 199static void calibrate_sleep_measurement_overhead(void)
@@ -211,7 +211,7 @@ static void calibrate_sleep_measurement_overhead(void)
211 min_delta -= 10000; 211 min_delta -= 10000;
212 sleep_measurement_overhead = min_delta; 212 sleep_measurement_overhead = min_delta;
213 213
214 printf("sleep measurement overhead: %Ld nsecs\n", min_delta); 214 printf("sleep measurement overhead: %" PRIu64 " nsecs\n", min_delta);
215} 215}
216 216
217static struct sched_atom * 217static struct sched_atom *
@@ -369,11 +369,6 @@ static void
369process_sched_event(struct task_desc *this_task __used, struct sched_atom *atom) 369process_sched_event(struct task_desc *this_task __used, struct sched_atom *atom)
370{ 370{
371 int ret = 0; 371 int ret = 0;
372 u64 now;
373 long long delta;
374
375 now = get_nsecs();
376 delta = start_time + atom->timestamp - now;
377 372
378 switch (atom->type) { 373 switch (atom->type) {
379 case SCHED_EVENT_RUN: 374 case SCHED_EVENT_RUN:
@@ -489,7 +484,8 @@ static void create_tasks(void)
489 484
490 err = pthread_attr_init(&attr); 485 err = pthread_attr_init(&attr);
491 BUG_ON(err); 486 BUG_ON(err);
492 err = pthread_attr_setstacksize(&attr, (size_t)(16*1024)); 487 err = pthread_attr_setstacksize(&attr,
488 (size_t) max(16 * 1024, PTHREAD_STACK_MIN));
493 BUG_ON(err); 489 BUG_ON(err);
494 err = pthread_mutex_lock(&start_work_mutex); 490 err = pthread_mutex_lock(&start_work_mutex);
495 BUG_ON(err); 491 BUG_ON(err);
@@ -561,7 +557,7 @@ static void wait_for_tasks(void)
561 557
562static void run_one_test(void) 558static void run_one_test(void)
563{ 559{
564 u64 T0, T1, delta, avg_delta, fluct, std_dev; 560 u64 T0, T1, delta, avg_delta, fluct;
565 561
566 T0 = get_nsecs(); 562 T0 = get_nsecs();
567 wait_for_tasks(); 563 wait_for_tasks();
@@ -577,7 +573,6 @@ static void run_one_test(void)
577 else 573 else
578 fluct = delta - avg_delta; 574 fluct = delta - avg_delta;
579 sum_fluct += fluct; 575 sum_fluct += fluct;
580 std_dev = sum_fluct / nr_runs / sqrt(nr_runs);
581 if (!run_avg) 576 if (!run_avg)
582 run_avg = delta; 577 run_avg = delta;
583 run_avg = (run_avg*9 + delta)/10; 578 run_avg = (run_avg*9 + delta)/10;
@@ -616,13 +611,13 @@ static void test_calibrations(void)
616 burn_nsecs(1e6); 611 burn_nsecs(1e6);
617 T1 = get_nsecs(); 612 T1 = get_nsecs();
618 613
619 printf("the run test took %Ld nsecs\n", T1-T0); 614 printf("the run test took %" PRIu64 " nsecs\n", T1 - T0);
620 615
621 T0 = get_nsecs(); 616 T0 = get_nsecs();
622 sleep_nsecs(1e6); 617 sleep_nsecs(1e6);
623 T1 = get_nsecs(); 618 T1 = get_nsecs();
624 619
625 printf("the sleep test took %Ld nsecs\n", T1-T0); 620 printf("the sleep test took %" PRIu64 " nsecs\n", T1 - T0);
626} 621}
627 622
628#define FILL_FIELD(ptr, field, event, data) \ 623#define FILL_FIELD(ptr, field, event, data) \
@@ -798,7 +793,7 @@ replay_switch_event(struct trace_switch_event *switch_event,
798 u64 timestamp, 793 u64 timestamp,
799 struct thread *thread __used) 794 struct thread *thread __used)
800{ 795{
801 struct task_desc *prev, *next; 796 struct task_desc *prev, __used *next;
802 u64 timestamp0; 797 u64 timestamp0;
803 s64 delta; 798 s64 delta;
804 799
@@ -815,10 +810,10 @@ replay_switch_event(struct trace_switch_event *switch_event,
815 delta = 0; 810 delta = 0;
816 811
817 if (delta < 0) 812 if (delta < 0)
818 die("hm, delta: %Ld < 0 ?\n", delta); 813 die("hm, delta: %" PRIu64 " < 0 ?\n", delta);
819 814
820 if (verbose) { 815 if (verbose) {
821 printf(" ... switch from %s/%d to %s/%d [ran %Ld nsecs]\n", 816 printf(" ... switch from %s/%d to %s/%d [ran %" PRIu64 " nsecs]\n",
822 switch_event->prev_comm, switch_event->prev_pid, 817 switch_event->prev_comm, switch_event->prev_pid,
823 switch_event->next_comm, switch_event->next_pid, 818 switch_event->next_comm, switch_event->next_pid,
824 delta); 819 delta);
@@ -1047,7 +1042,7 @@ latency_switch_event(struct trace_switch_event *switch_event,
1047 delta = 0; 1042 delta = 0;
1048 1043
1049 if (delta < 0) 1044 if (delta < 0)
1050 die("hm, delta: %Ld < 0 ?\n", delta); 1045 die("hm, delta: %" PRIu64 " < 0 ?\n", delta);
1051 1046
1052 1047
1053 sched_out = perf_session__findnew(session, switch_event->prev_pid); 1048 sched_out = perf_session__findnew(session, switch_event->prev_pid);
@@ -1220,7 +1215,7 @@ static void output_lat_thread(struct work_atoms *work_list)
1220 1215
1221 avg = work_list->total_lat / work_list->nb_atoms; 1216 avg = work_list->total_lat / work_list->nb_atoms;
1222 1217
1223 printf("|%11.3f ms |%9llu | avg:%9.3f ms | max:%9.3f ms | max at: %9.6f s\n", 1218 printf("|%11.3f ms |%9" PRIu64 " | avg:%9.3f ms | max:%9.3f ms | max at: %9.6f s\n",
1224 (double)work_list->total_runtime / 1e6, 1219 (double)work_list->total_runtime / 1e6,
1225 work_list->nb_atoms, (double)avg / 1e6, 1220 work_list->nb_atoms, (double)avg / 1e6,
1226 (double)work_list->max_lat / 1e6, 1221 (double)work_list->max_lat / 1e6,
@@ -1403,7 +1398,7 @@ map_switch_event(struct trace_switch_event *switch_event,
1403 u64 timestamp, 1398 u64 timestamp,
1404 struct thread *thread __used) 1399 struct thread *thread __used)
1405{ 1400{
1406 struct thread *sched_out, *sched_in; 1401 struct thread *sched_out __used, *sched_in;
1407 int new_shortname; 1402 int new_shortname;
1408 u64 timestamp0; 1403 u64 timestamp0;
1409 s64 delta; 1404 s64 delta;
@@ -1422,7 +1417,7 @@ map_switch_event(struct trace_switch_event *switch_event,
1422 delta = 0; 1417 delta = 0;
1423 1418
1424 if (delta < 0) 1419 if (delta < 0)
1425 die("hm, delta: %Ld < 0 ?\n", delta); 1420 die("hm, delta: %" PRIu64 " < 0 ?\n", delta);
1426 1421
1427 1422
1428 sched_out = perf_session__findnew(session, switch_event->prev_pid); 1423 sched_out = perf_session__findnew(session, switch_event->prev_pid);
@@ -1579,9 +1574,9 @@ process_sched_migrate_task_event(void *data, struct perf_session *session,
1579 event, cpu, timestamp, thread); 1574 event, cpu, timestamp, thread);
1580} 1575}
1581 1576
1582static void 1577static void process_raw_event(union perf_event *raw_event __used,
1583process_raw_event(event_t *raw_event __used, struct perf_session *session, 1578 struct perf_session *session, void *data, int cpu,
1584 void *data, int cpu, u64 timestamp, struct thread *thread) 1579 u64 timestamp, struct thread *thread)
1585{ 1580{
1586 struct event *event; 1581 struct event *event;
1587 int type; 1582 int type;
@@ -1606,25 +1601,17 @@ process_raw_event(event_t *raw_event __used, struct perf_session *session,
1606 process_sched_migrate_task_event(data, session, event, cpu, timestamp, thread); 1601 process_sched_migrate_task_event(data, session, event, cpu, timestamp, thread);
1607} 1602}
1608 1603
1609static int process_sample_event(event_t *event, struct perf_session *session) 1604static int process_sample_event(union perf_event *event,
1605 struct perf_sample *sample,
1606 struct perf_evsel *evsel __used,
1607 struct perf_session *session)
1610{ 1608{
1611 struct sample_data data;
1612 struct thread *thread; 1609 struct thread *thread;
1613 1610
1614 if (!(session->sample_type & PERF_SAMPLE_RAW)) 1611 if (!(session->sample_type & PERF_SAMPLE_RAW))
1615 return 0; 1612 return 0;
1616 1613
1617 memset(&data, 0, sizeof(data)); 1614 thread = perf_session__findnew(session, sample->pid);
1618 data.time = -1;
1619 data.cpu = -1;
1620 data.period = -1;
1621
1622 event__parse_sample(event, session->sample_type, &data);
1623
1624 dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc,
1625 data.pid, data.tid, data.ip, data.period);
1626
1627 thread = perf_session__findnew(session, data.pid);
1628 if (thread == NULL) { 1615 if (thread == NULL) {
1629 pr_debug("problem processing %d event, skipping it.\n", 1616 pr_debug("problem processing %d event, skipping it.\n",
1630 event->header.type); 1617 event->header.type);
@@ -1633,26 +1620,28 @@ static int process_sample_event(event_t *event, struct perf_session *session)
1633 1620
1634 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 1621 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
1635 1622
1636 if (profile_cpu != -1 && profile_cpu != (int)data.cpu) 1623 if (profile_cpu != -1 && profile_cpu != (int)sample->cpu)
1637 return 0; 1624 return 0;
1638 1625
1639 process_raw_event(event, session, data.raw_data, data.cpu, data.time, thread); 1626 process_raw_event(event, session, sample->raw_data, sample->cpu,
1627 sample->time, thread);
1640 1628
1641 return 0; 1629 return 0;
1642} 1630}
1643 1631
1644static struct perf_event_ops event_ops = { 1632static struct perf_event_ops event_ops = {
1645 .sample = process_sample_event, 1633 .sample = process_sample_event,
1646 .comm = event__process_comm, 1634 .comm = perf_event__process_comm,
1647 .lost = event__process_lost, 1635 .lost = perf_event__process_lost,
1648 .fork = event__process_task, 1636 .fork = perf_event__process_task,
1649 .ordered_samples = true, 1637 .ordered_samples = true,
1650}; 1638};
1651 1639
1652static int read_events(void) 1640static int read_events(void)
1653{ 1641{
1654 int err = -EINVAL; 1642 int err = -EINVAL;
1655 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0, false); 1643 struct perf_session *session = perf_session__new(input_name, O_RDONLY,
1644 0, false, &event_ops);
1656 if (session == NULL) 1645 if (session == NULL)
1657 return -ENOMEM; 1646 return -ENOMEM;
1658 1647
@@ -1720,7 +1709,7 @@ static void __cmd_lat(void)
1720 } 1709 }
1721 1710
1722 printf(" -----------------------------------------------------------------------------------------\n"); 1711 printf(" -----------------------------------------------------------------------------------------\n");
1723 printf(" TOTAL: |%11.3f ms |%9Ld |\n", 1712 printf(" TOTAL: |%11.3f ms |%9" PRIu64 " |\n",
1724 (double)all_runtime/1e6, all_count); 1713 (double)all_runtime/1e6, all_count);
1725 1714
1726 printf(" ---------------------------------------------------\n"); 1715 printf(" ---------------------------------------------------\n");
@@ -1850,15 +1839,15 @@ static const char *record_args[] = {
1850 "-f", 1839 "-f",
1851 "-m", "1024", 1840 "-m", "1024",
1852 "-c", "1", 1841 "-c", "1",
1853 "-e", "sched:sched_switch:r", 1842 "-e", "sched:sched_switch",
1854 "-e", "sched:sched_stat_wait:r", 1843 "-e", "sched:sched_stat_wait",
1855 "-e", "sched:sched_stat_sleep:r", 1844 "-e", "sched:sched_stat_sleep",
1856 "-e", "sched:sched_stat_iowait:r", 1845 "-e", "sched:sched_stat_iowait",
1857 "-e", "sched:sched_stat_runtime:r", 1846 "-e", "sched:sched_stat_runtime",
1858 "-e", "sched:sched_process_exit:r", 1847 "-e", "sched:sched_process_exit",
1859 "-e", "sched:sched_process_fork:r", 1848 "-e", "sched:sched_process_fork",
1860 "-e", "sched:sched_wakeup:r", 1849 "-e", "sched:sched_wakeup",
1861 "-e", "sched:sched_migrate_task:r", 1850 "-e", "sched:sched_migrate_task",
1862}; 1851};
1863 1852
1864static int __cmd_record(int argc, const char **argv) 1853static int __cmd_record(int argc, const char **argv)
@@ -1869,6 +1858,9 @@ static int __cmd_record(int argc, const char **argv)
1869 rec_argc = ARRAY_SIZE(record_args) + argc - 1; 1858 rec_argc = ARRAY_SIZE(record_args) + argc - 1;
1870 rec_argv = calloc(rec_argc + 1, sizeof(char *)); 1859 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1871 1860
1861 if (rec_argv == NULL)
1862 return -ENOMEM;
1863
1872 for (i = 0; i < ARRAY_SIZE(record_args); i++) 1864 for (i = 0; i < ARRAY_SIZE(record_args); i++)
1873 rec_argv[i] = strdup(record_args[i]); 1865 rec_argv[i] = strdup(record_args[i]);
1874 1866
@@ -1888,10 +1880,10 @@ int cmd_sched(int argc, const char **argv, const char *prefix __used)
1888 usage_with_options(sched_usage, sched_options); 1880 usage_with_options(sched_usage, sched_options);
1889 1881
1890 /* 1882 /*
1891 * Aliased to 'perf trace' for now: 1883 * Aliased to 'perf script' for now:
1892 */ 1884 */
1893 if (!strcmp(argv[0], "trace")) 1885 if (!strcmp(argv[0], "script"))
1894 return cmd_trace(argc, argv, prefix); 1886 return cmd_script(argc, argv, prefix);
1895 1887
1896 symbol__init(); 1888 symbol__init();
1897 if (!strncmp(argv[0], "rec", 3)) { 1889 if (!strncmp(argv[0], "rec", 3)) {
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
new file mode 100644
index 000000000000..22747de7234b
--- /dev/null
+++ b/tools/perf/builtin-script.c
@@ -0,0 +1,1230 @@
1#include "builtin.h"
2
3#include "perf.h"
4#include "util/cache.h"
5#include "util/debug.h"
6#include "util/exec_cmd.h"
7#include "util/header.h"
8#include "util/parse-options.h"
9#include "util/session.h"
10#include "util/symbol.h"
11#include "util/thread.h"
12#include "util/trace-event.h"
13#include "util/util.h"
14#include "util/evlist.h"
15#include "util/evsel.h"
16
17static char const *script_name;
18static char const *generate_script_lang;
19static bool debug_mode;
20static u64 last_timestamp;
21static u64 nr_unordered;
22extern const struct option record_options[];
23static bool no_callchain;
24
25enum perf_output_field {
26 PERF_OUTPUT_COMM = 1U << 0,
27 PERF_OUTPUT_TID = 1U << 1,
28 PERF_OUTPUT_PID = 1U << 2,
29 PERF_OUTPUT_TIME = 1U << 3,
30 PERF_OUTPUT_CPU = 1U << 4,
31 PERF_OUTPUT_EVNAME = 1U << 5,
32 PERF_OUTPUT_TRACE = 1U << 6,
33 PERF_OUTPUT_SYM = 1U << 7,
34};
35
36struct output_option {
37 const char *str;
38 enum perf_output_field field;
39} all_output_options[] = {
40 {.str = "comm", .field = PERF_OUTPUT_COMM},
41 {.str = "tid", .field = PERF_OUTPUT_TID},
42 {.str = "pid", .field = PERF_OUTPUT_PID},
43 {.str = "time", .field = PERF_OUTPUT_TIME},
44 {.str = "cpu", .field = PERF_OUTPUT_CPU},
45 {.str = "event", .field = PERF_OUTPUT_EVNAME},
46 {.str = "trace", .field = PERF_OUTPUT_TRACE},
47 {.str = "sym", .field = PERF_OUTPUT_SYM},
48};
49
50/* default set to maintain compatibility with current format */
51static struct {
52 bool user_set;
53 bool wildcard_set;
54 u64 fields;
55 u64 invalid_fields;
56} output[PERF_TYPE_MAX] = {
57
58 [PERF_TYPE_HARDWARE] = {
59 .user_set = false,
60
61 .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
62 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
63 PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM,
64
65 .invalid_fields = PERF_OUTPUT_TRACE,
66 },
67
68 [PERF_TYPE_SOFTWARE] = {
69 .user_set = false,
70
71 .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
72 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
73 PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM,
74
75 .invalid_fields = PERF_OUTPUT_TRACE,
76 },
77
78 [PERF_TYPE_TRACEPOINT] = {
79 .user_set = false,
80
81 .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
82 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
83 PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE,
84 },
85
86 [PERF_TYPE_RAW] = {
87 .user_set = false,
88
89 .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
90 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
91 PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM,
92
93 .invalid_fields = PERF_OUTPUT_TRACE,
94 },
95};
96
97static bool output_set_by_user(void)
98{
99 int j;
100 for (j = 0; j < PERF_TYPE_MAX; ++j) {
101 if (output[j].user_set)
102 return true;
103 }
104 return false;
105}
106
107static const char *output_field2str(enum perf_output_field field)
108{
109 int i, imax = ARRAY_SIZE(all_output_options);
110 const char *str = "";
111
112 for (i = 0; i < imax; ++i) {
113 if (all_output_options[i].field == field) {
114 str = all_output_options[i].str;
115 break;
116 }
117 }
118 return str;
119}
120
121#define PRINT_FIELD(x) (output[attr->type].fields & PERF_OUTPUT_##x)
122
123static int perf_event_attr__check_stype(struct perf_event_attr *attr,
124 u64 sample_type, const char *sample_msg,
125 enum perf_output_field field)
126{
127 int type = attr->type;
128 const char *evname;
129
130 if (attr->sample_type & sample_type)
131 return 0;
132
133 if (output[type].user_set) {
134 evname = __event_name(attr->type, attr->config);
135 pr_err("Samples for '%s' event do not have %s attribute set. "
136 "Cannot print '%s' field.\n",
137 evname, sample_msg, output_field2str(field));
138 return -1;
139 }
140
141 /* user did not ask for it explicitly so remove from the default list */
142 output[type].fields &= ~field;
143 evname = __event_name(attr->type, attr->config);
144 pr_debug("Samples for '%s' event do not have %s attribute set. "
145 "Skipping '%s' field.\n",
146 evname, sample_msg, output_field2str(field));
147
148 return 0;
149}
150
151static int perf_evsel__check_attr(struct perf_evsel *evsel,
152 struct perf_session *session)
153{
154 struct perf_event_attr *attr = &evsel->attr;
155
156 if (PRINT_FIELD(TRACE) &&
157 !perf_session__has_traces(session, "record -R"))
158 return -EINVAL;
159
160 if (PRINT_FIELD(SYM)) {
161 if (perf_event_attr__check_stype(attr, PERF_SAMPLE_IP, "IP",
162 PERF_OUTPUT_SYM))
163 return -EINVAL;
164
165 if (!no_callchain &&
166 !(attr->sample_type & PERF_SAMPLE_CALLCHAIN))
167 symbol_conf.use_callchain = false;
168 }
169
170 if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) &&
171 perf_event_attr__check_stype(attr, PERF_SAMPLE_TID, "TID",
172 PERF_OUTPUT_TID|PERF_OUTPUT_PID))
173 return -EINVAL;
174
175 if (PRINT_FIELD(TIME) &&
176 perf_event_attr__check_stype(attr, PERF_SAMPLE_TIME, "TIME",
177 PERF_OUTPUT_TIME))
178 return -EINVAL;
179
180 if (PRINT_FIELD(CPU) &&
181 perf_event_attr__check_stype(attr, PERF_SAMPLE_CPU, "CPU",
182 PERF_OUTPUT_CPU))
183 return -EINVAL;
184
185 return 0;
186}
187
188/*
189 * verify all user requested events exist and the samples
190 * have the expected data
191 */
192static int perf_session__check_output_opt(struct perf_session *session)
193{
194 int j;
195 struct perf_evsel *evsel;
196
197 for (j = 0; j < PERF_TYPE_MAX; ++j) {
198 evsel = perf_session__find_first_evtype(session, j);
199
200 /*
201 * even if fields is set to 0 (ie., show nothing) event must
202 * exist if user explicitly includes it on the command line
203 */
204 if (!evsel && output[j].user_set && !output[j].wildcard_set) {
205 pr_err("%s events do not exist. "
206 "Remove corresponding -f option to proceed.\n",
207 event_type(j));
208 return -1;
209 }
210
211 if (evsel && output[j].fields &&
212 perf_evsel__check_attr(evsel, session))
213 return -1;
214 }
215
216 return 0;
217}
218
219static void print_sample_start(struct perf_sample *sample,
220 struct thread *thread,
221 struct perf_event_attr *attr)
222{
223 int type;
224 struct event *event;
225 const char *evname = NULL;
226 unsigned long secs;
227 unsigned long usecs;
228 unsigned long long nsecs;
229
230 if (PRINT_FIELD(COMM)) {
231 if (latency_format)
232 printf("%8.8s ", thread->comm);
233 else if (PRINT_FIELD(SYM) && symbol_conf.use_callchain)
234 printf("%s ", thread->comm);
235 else
236 printf("%16s ", thread->comm);
237 }
238
239 if (PRINT_FIELD(PID) && PRINT_FIELD(TID))
240 printf("%5d/%-5d ", sample->pid, sample->tid);
241 else if (PRINT_FIELD(PID))
242 printf("%5d ", sample->pid);
243 else if (PRINT_FIELD(TID))
244 printf("%5d ", sample->tid);
245
246 if (PRINT_FIELD(CPU)) {
247 if (latency_format)
248 printf("%3d ", sample->cpu);
249 else
250 printf("[%03d] ", sample->cpu);
251 }
252
253 if (PRINT_FIELD(TIME)) {
254 nsecs = sample->time;
255 secs = nsecs / NSECS_PER_SEC;
256 nsecs -= secs * NSECS_PER_SEC;
257 usecs = nsecs / NSECS_PER_USEC;
258 printf("%5lu.%06lu: ", secs, usecs);
259 }
260
261 if (PRINT_FIELD(EVNAME)) {
262 if (attr->type == PERF_TYPE_TRACEPOINT) {
263 type = trace_parse_common_type(sample->raw_data);
264 event = trace_find_event(type);
265 if (event)
266 evname = event->name;
267 } else
268 evname = __event_name(attr->type, attr->config);
269
270 printf("%s: ", evname ? evname : "(unknown)");
271 }
272}
273
274static void process_event(union perf_event *event __unused,
275 struct perf_sample *sample,
276 struct perf_evsel *evsel,
277 struct perf_session *session,
278 struct thread *thread)
279{
280 struct perf_event_attr *attr = &evsel->attr;
281
282 if (output[attr->type].fields == 0)
283 return;
284
285 print_sample_start(sample, thread, attr);
286
287 if (PRINT_FIELD(TRACE))
288 print_trace_event(sample->cpu, sample->raw_data,
289 sample->raw_size);
290
291 if (PRINT_FIELD(SYM)) {
292 if (!symbol_conf.use_callchain)
293 printf(" ");
294 else
295 printf("\n");
296 perf_session__print_symbols(event, sample, session);
297 }
298
299 printf("\n");
300}
301
302static int default_start_script(const char *script __unused,
303 int argc __unused,
304 const char **argv __unused)
305{
306 return 0;
307}
308
309static int default_stop_script(void)
310{
311 return 0;
312}
313
314static int default_generate_script(const char *outfile __unused)
315{
316 return 0;
317}
318
319static struct scripting_ops default_scripting_ops = {
320 .start_script = default_start_script,
321 .stop_script = default_stop_script,
322 .process_event = process_event,
323 .generate_script = default_generate_script,
324};
325
326static struct scripting_ops *scripting_ops;
327
328static void setup_scripting(void)
329{
330 setup_perl_scripting();
331 setup_python_scripting();
332
333 scripting_ops = &default_scripting_ops;
334}
335
336static int cleanup_scripting(void)
337{
338 pr_debug("\nperf script stopped\n");
339
340 return scripting_ops->stop_script();
341}
342
343static char const *input_name = "perf.data";
344
345static int process_sample_event(union perf_event *event,
346 struct perf_sample *sample,
347 struct perf_evsel *evsel,
348 struct perf_session *session)
349{
350 struct thread *thread = perf_session__findnew(session, event->ip.pid);
351
352 if (thread == NULL) {
353 pr_debug("problem processing %d event, skipping it.\n",
354 event->header.type);
355 return -1;
356 }
357
358 if (debug_mode) {
359 if (sample->time < last_timestamp) {
360 pr_err("Samples misordered, previous: %" PRIu64
361 " this: %" PRIu64 "\n", last_timestamp,
362 sample->time);
363 nr_unordered++;
364 }
365 last_timestamp = sample->time;
366 return 0;
367 }
368 scripting_ops->process_event(event, sample, evsel, session, thread);
369
370 session->hists.stats.total_period += sample->period;
371 return 0;
372}
373
374static struct perf_event_ops event_ops = {
375 .sample = process_sample_event,
376 .mmap = perf_event__process_mmap,
377 .comm = perf_event__process_comm,
378 .exit = perf_event__process_task,
379 .fork = perf_event__process_task,
380 .attr = perf_event__process_attr,
381 .event_type = perf_event__process_event_type,
382 .tracing_data = perf_event__process_tracing_data,
383 .build_id = perf_event__process_build_id,
384 .ordered_samples = true,
385 .ordering_requires_timestamps = true,
386};
387
388extern volatile int session_done;
389
390static void sig_handler(int sig __unused)
391{
392 session_done = 1;
393}
394
395static int __cmd_script(struct perf_session *session)
396{
397 int ret;
398
399 signal(SIGINT, sig_handler);
400
401 ret = perf_session__process_events(session, &event_ops);
402
403 if (debug_mode)
404 pr_err("Misordered timestamps: %" PRIu64 "\n", nr_unordered);
405
406 return ret;
407}
408
409struct script_spec {
410 struct list_head node;
411 struct scripting_ops *ops;
412 char spec[0];
413};
414
415static LIST_HEAD(script_specs);
416
417static struct script_spec *script_spec__new(const char *spec,
418 struct scripting_ops *ops)
419{
420 struct script_spec *s = malloc(sizeof(*s) + strlen(spec) + 1);
421
422 if (s != NULL) {
423 strcpy(s->spec, spec);
424 s->ops = ops;
425 }
426
427 return s;
428}
429
430static void script_spec__delete(struct script_spec *s)
431{
432 free(s->spec);
433 free(s);
434}
435
436static void script_spec__add(struct script_spec *s)
437{
438 list_add_tail(&s->node, &script_specs);
439}
440
441static struct script_spec *script_spec__find(const char *spec)
442{
443 struct script_spec *s;
444
445 list_for_each_entry(s, &script_specs, node)
446 if (strcasecmp(s->spec, spec) == 0)
447 return s;
448 return NULL;
449}
450
451static struct script_spec *script_spec__findnew(const char *spec,
452 struct scripting_ops *ops)
453{
454 struct script_spec *s = script_spec__find(spec);
455
456 if (s)
457 return s;
458
459 s = script_spec__new(spec, ops);
460 if (!s)
461 goto out_delete_spec;
462
463 script_spec__add(s);
464
465 return s;
466
467out_delete_spec:
468 script_spec__delete(s);
469
470 return NULL;
471}
472
473int script_spec_register(const char *spec, struct scripting_ops *ops)
474{
475 struct script_spec *s;
476
477 s = script_spec__find(spec);
478 if (s)
479 return -1;
480
481 s = script_spec__findnew(spec, ops);
482 if (!s)
483 return -1;
484
485 return 0;
486}
487
488static struct scripting_ops *script_spec__lookup(const char *spec)
489{
490 struct script_spec *s = script_spec__find(spec);
491 if (!s)
492 return NULL;
493
494 return s->ops;
495}
496
497static void list_available_languages(void)
498{
499 struct script_spec *s;
500
501 fprintf(stderr, "\n");
502 fprintf(stderr, "Scripting language extensions (used in "
503 "perf script -s [spec:]script.[spec]):\n\n");
504
505 list_for_each_entry(s, &script_specs, node)
506 fprintf(stderr, " %-42s [%s]\n", s->spec, s->ops->name);
507
508 fprintf(stderr, "\n");
509}
510
511static int parse_scriptname(const struct option *opt __used,
512 const char *str, int unset __used)
513{
514 char spec[PATH_MAX];
515 const char *script, *ext;
516 int len;
517
518 if (strcmp(str, "lang") == 0) {
519 list_available_languages();
520 exit(0);
521 }
522
523 script = strchr(str, ':');
524 if (script) {
525 len = script - str;
526 if (len >= PATH_MAX) {
527 fprintf(stderr, "invalid language specifier");
528 return -1;
529 }
530 strncpy(spec, str, len);
531 spec[len] = '\0';
532 scripting_ops = script_spec__lookup(spec);
533 if (!scripting_ops) {
534 fprintf(stderr, "invalid language specifier");
535 return -1;
536 }
537 script++;
538 } else {
539 script = str;
540 ext = strrchr(script, '.');
541 if (!ext) {
542 fprintf(stderr, "invalid script extension");
543 return -1;
544 }
545 scripting_ops = script_spec__lookup(++ext);
546 if (!scripting_ops) {
547 fprintf(stderr, "invalid script extension");
548 return -1;
549 }
550 }
551
552 script_name = strdup(script);
553
554 return 0;
555}
556
557static int parse_output_fields(const struct option *opt __used,
558 const char *arg, int unset __used)
559{
560 char *tok;
561 int i, imax = sizeof(all_output_options) / sizeof(struct output_option);
562 int j;
563 int rc = 0;
564 char *str = strdup(arg);
565 int type = -1;
566
567 if (!str)
568 return -ENOMEM;
569
570 /* first word can state for which event type the user is specifying
571 * the fields. If no type exists, the specified fields apply to all
572 * event types found in the file minus the invalid fields for a type.
573 */
574 tok = strchr(str, ':');
575 if (tok) {
576 *tok = '\0';
577 tok++;
578 if (!strcmp(str, "hw"))
579 type = PERF_TYPE_HARDWARE;
580 else if (!strcmp(str, "sw"))
581 type = PERF_TYPE_SOFTWARE;
582 else if (!strcmp(str, "trace"))
583 type = PERF_TYPE_TRACEPOINT;
584 else if (!strcmp(str, "raw"))
585 type = PERF_TYPE_RAW;
586 else {
587 fprintf(stderr, "Invalid event type in field string.\n");
588 return -EINVAL;
589 }
590
591 if (output[type].user_set)
592 pr_warning("Overriding previous field request for %s events.\n",
593 event_type(type));
594
595 output[type].fields = 0;
596 output[type].user_set = true;
597 output[type].wildcard_set = false;
598
599 } else {
600 tok = str;
601 if (strlen(str) == 0) {
602 fprintf(stderr,
603 "Cannot set fields to 'none' for all event types.\n");
604 rc = -EINVAL;
605 goto out;
606 }
607
608 if (output_set_by_user())
609 pr_warning("Overriding previous field request for all events.\n");
610
611 for (j = 0; j < PERF_TYPE_MAX; ++j) {
612 output[j].fields = 0;
613 output[j].user_set = true;
614 output[j].wildcard_set = true;
615 }
616 }
617
618 tok = strtok(tok, ",");
619 while (tok) {
620 for (i = 0; i < imax; ++i) {
621 if (strcmp(tok, all_output_options[i].str) == 0)
622 break;
623 }
624 if (i == imax) {
625 fprintf(stderr, "Invalid field requested.\n");
626 rc = -EINVAL;
627 goto out;
628 }
629
630 if (type == -1) {
631 /* add user option to all events types for
632 * which it is valid
633 */
634 for (j = 0; j < PERF_TYPE_MAX; ++j) {
635 if (output[j].invalid_fields & all_output_options[i].field) {
636 pr_warning("\'%s\' not valid for %s events. Ignoring.\n",
637 all_output_options[i].str, event_type(j));
638 } else
639 output[j].fields |= all_output_options[i].field;
640 }
641 } else {
642 if (output[type].invalid_fields & all_output_options[i].field) {
643 fprintf(stderr, "\'%s\' not valid for %s events.\n",
644 all_output_options[i].str, event_type(type));
645
646 rc = -EINVAL;
647 goto out;
648 }
649 output[type].fields |= all_output_options[i].field;
650 }
651
652 tok = strtok(NULL, ",");
653 }
654
655 if (type >= 0) {
656 if (output[type].fields == 0) {
657 pr_debug("No fields requested for %s type. "
658 "Events will not be displayed.\n", event_type(type));
659 }
660 }
661
662out:
663 free(str);
664 return rc;
665}
666
667/* Helper function for filesystems that return a dent->d_type DT_UNKNOWN */
668static int is_directory(const char *base_path, const struct dirent *dent)
669{
670 char path[PATH_MAX];
671 struct stat st;
672
673 sprintf(path, "%s/%s", base_path, dent->d_name);
674 if (stat(path, &st))
675 return 0;
676
677 return S_ISDIR(st.st_mode);
678}
679
680#define for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next)\
681 while (!readdir_r(scripts_dir, &lang_dirent, &lang_next) && \
682 lang_next) \
683 if ((lang_dirent.d_type == DT_DIR || \
684 (lang_dirent.d_type == DT_UNKNOWN && \
685 is_directory(scripts_path, &lang_dirent))) && \
686 (strcmp(lang_dirent.d_name, ".")) && \
687 (strcmp(lang_dirent.d_name, "..")))
688
689#define for_each_script(lang_path, lang_dir, script_dirent, script_next)\
690 while (!readdir_r(lang_dir, &script_dirent, &script_next) && \
691 script_next) \
692 if (script_dirent.d_type != DT_DIR && \
693 (script_dirent.d_type != DT_UNKNOWN || \
694 !is_directory(lang_path, &script_dirent)))
695
696
697#define RECORD_SUFFIX "-record"
698#define REPORT_SUFFIX "-report"
699
700struct script_desc {
701 struct list_head node;
702 char *name;
703 char *half_liner;
704 char *args;
705};
706
707static LIST_HEAD(script_descs);
708
709static struct script_desc *script_desc__new(const char *name)
710{
711 struct script_desc *s = zalloc(sizeof(*s));
712
713 if (s != NULL && name)
714 s->name = strdup(name);
715
716 return s;
717}
718
719static void script_desc__delete(struct script_desc *s)
720{
721 free(s->name);
722 free(s->half_liner);
723 free(s->args);
724 free(s);
725}
726
727static void script_desc__add(struct script_desc *s)
728{
729 list_add_tail(&s->node, &script_descs);
730}
731
732static struct script_desc *script_desc__find(const char *name)
733{
734 struct script_desc *s;
735
736 list_for_each_entry(s, &script_descs, node)
737 if (strcasecmp(s->name, name) == 0)
738 return s;
739 return NULL;
740}
741
742static struct script_desc *script_desc__findnew(const char *name)
743{
744 struct script_desc *s = script_desc__find(name);
745
746 if (s)
747 return s;
748
749 s = script_desc__new(name);
750 if (!s)
751 goto out_delete_desc;
752
753 script_desc__add(s);
754
755 return s;
756
757out_delete_desc:
758 script_desc__delete(s);
759
760 return NULL;
761}
762
763static const char *ends_with(const char *str, const char *suffix)
764{
765 size_t suffix_len = strlen(suffix);
766 const char *p = str;
767
768 if (strlen(str) > suffix_len) {
769 p = str + strlen(str) - suffix_len;
770 if (!strncmp(p, suffix, suffix_len))
771 return p;
772 }
773
774 return NULL;
775}
776
777static char *ltrim(char *str)
778{
779 int len = strlen(str);
780
781 while (len && isspace(*str)) {
782 len--;
783 str++;
784 }
785
786 return str;
787}
788
789static int read_script_info(struct script_desc *desc, const char *filename)
790{
791 char line[BUFSIZ], *p;
792 FILE *fp;
793
794 fp = fopen(filename, "r");
795 if (!fp)
796 return -1;
797
798 while (fgets(line, sizeof(line), fp)) {
799 p = ltrim(line);
800 if (strlen(p) == 0)
801 continue;
802 if (*p != '#')
803 continue;
804 p++;
805 if (strlen(p) && *p == '!')
806 continue;
807
808 p = ltrim(p);
809 if (strlen(p) && p[strlen(p) - 1] == '\n')
810 p[strlen(p) - 1] = '\0';
811
812 if (!strncmp(p, "description:", strlen("description:"))) {
813 p += strlen("description:");
814 desc->half_liner = strdup(ltrim(p));
815 continue;
816 }
817
818 if (!strncmp(p, "args:", strlen("args:"))) {
819 p += strlen("args:");
820 desc->args = strdup(ltrim(p));
821 continue;
822 }
823 }
824
825 fclose(fp);
826
827 return 0;
828}
829
830static int list_available_scripts(const struct option *opt __used,
831 const char *s __used, int unset __used)
832{
833 struct dirent *script_next, *lang_next, script_dirent, lang_dirent;
834 char scripts_path[MAXPATHLEN];
835 DIR *scripts_dir, *lang_dir;
836 char script_path[MAXPATHLEN];
837 char lang_path[MAXPATHLEN];
838 struct script_desc *desc;
839 char first_half[BUFSIZ];
840 char *script_root;
841 char *str;
842
843 snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
844
845 scripts_dir = opendir(scripts_path);
846 if (!scripts_dir)
847 return -1;
848
849 for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next) {
850 snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path,
851 lang_dirent.d_name);
852 lang_dir = opendir(lang_path);
853 if (!lang_dir)
854 continue;
855
856 for_each_script(lang_path, lang_dir, script_dirent, script_next) {
857 script_root = strdup(script_dirent.d_name);
858 str = (char *)ends_with(script_root, REPORT_SUFFIX);
859 if (str) {
860 *str = '\0';
861 desc = script_desc__findnew(script_root);
862 snprintf(script_path, MAXPATHLEN, "%s/%s",
863 lang_path, script_dirent.d_name);
864 read_script_info(desc, script_path);
865 }
866 free(script_root);
867 }
868 }
869
870 fprintf(stdout, "List of available trace scripts:\n");
871 list_for_each_entry(desc, &script_descs, node) {
872 sprintf(first_half, "%s %s", desc->name,
873 desc->args ? desc->args : "");
874 fprintf(stdout, " %-36s %s\n", first_half,
875 desc->half_liner ? desc->half_liner : "");
876 }
877
878 exit(0);
879}
880
881static char *get_script_path(const char *script_root, const char *suffix)
882{
883 struct dirent *script_next, *lang_next, script_dirent, lang_dirent;
884 char scripts_path[MAXPATHLEN];
885 char script_path[MAXPATHLEN];
886 DIR *scripts_dir, *lang_dir;
887 char lang_path[MAXPATHLEN];
888 char *str, *__script_root;
889 char *path = NULL;
890
891 snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
892
893 scripts_dir = opendir(scripts_path);
894 if (!scripts_dir)
895 return NULL;
896
897 for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next) {
898 snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path,
899 lang_dirent.d_name);
900 lang_dir = opendir(lang_path);
901 if (!lang_dir)
902 continue;
903
904 for_each_script(lang_path, lang_dir, script_dirent, script_next) {
905 __script_root = strdup(script_dirent.d_name);
906 str = (char *)ends_with(__script_root, suffix);
907 if (str) {
908 *str = '\0';
909 if (strcmp(__script_root, script_root))
910 continue;
911 snprintf(script_path, MAXPATHLEN, "%s/%s",
912 lang_path, script_dirent.d_name);
913 path = strdup(script_path);
914 free(__script_root);
915 break;
916 }
917 free(__script_root);
918 }
919 }
920
921 return path;
922}
923
924static bool is_top_script(const char *script_path)
925{
926 return ends_with(script_path, "top") == NULL ? false : true;
927}
928
929static int has_required_arg(char *script_path)
930{
931 struct script_desc *desc;
932 int n_args = 0;
933 char *p;
934
935 desc = script_desc__new(NULL);
936
937 if (read_script_info(desc, script_path))
938 goto out;
939
940 if (!desc->args)
941 goto out;
942
943 for (p = desc->args; *p; p++)
944 if (*p == '<')
945 n_args++;
946out:
947 script_desc__delete(desc);
948
949 return n_args;
950}
951
952static const char * const script_usage[] = {
953 "perf script [<options>]",
954 "perf script [<options>] record <script> [<record-options>] <command>",
955 "perf script [<options>] report <script> [script-args]",
956 "perf script [<options>] <script> [<record-options>] <command>",
957 "perf script [<options>] <top-script> [script-args]",
958 NULL
959};
960
961static const struct option options[] = {
962 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
963 "dump raw trace in ASCII"),
964 OPT_INCR('v', "verbose", &verbose,
965 "be more verbose (show symbol address, etc)"),
966 OPT_BOOLEAN('L', "Latency", &latency_format,
967 "show latency attributes (irqs/preemption disabled, etc)"),
968 OPT_CALLBACK_NOOPT('l', "list", NULL, NULL, "list available scripts",
969 list_available_scripts),
970 OPT_CALLBACK('s', "script", NULL, "name",
971 "script file name (lang:script name, script name, or *)",
972 parse_scriptname),
973 OPT_STRING('g', "gen-script", &generate_script_lang, "lang",
974 "generate perf-script.xx script in specified language"),
975 OPT_STRING('i', "input", &input_name, "file",
976 "input file name"),
977 OPT_BOOLEAN('d', "debug-mode", &debug_mode,
978 "do various checks like samples ordering and lost events"),
979 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
980 "file", "vmlinux pathname"),
981 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
982 "file", "kallsyms pathname"),
983 OPT_BOOLEAN('G', "hide-call-graph", &no_callchain,
984 "When printing symbols do not display call chain"),
985 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
986 "Look for files with symbols relative to this directory"),
987 OPT_CALLBACK('f', "fields", NULL, "str",
988 "comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace,raw. Fields: comm,tid,pid,time,cpu,event,trace,sym",
989 parse_output_fields),
990
991 OPT_END()
992};
993
994static bool have_cmd(int argc, const char **argv)
995{
996 char **__argv = malloc(sizeof(const char *) * argc);
997
998 if (!__argv)
999 die("malloc");
1000 memcpy(__argv, argv, sizeof(const char *) * argc);
1001 argc = parse_options(argc, (const char **)__argv, record_options,
1002 NULL, PARSE_OPT_STOP_AT_NON_OPTION);
1003 free(__argv);
1004
1005 return argc != 0;
1006}
1007
1008int cmd_script(int argc, const char **argv, const char *prefix __used)
1009{
1010 char *rec_script_path = NULL;
1011 char *rep_script_path = NULL;
1012 struct perf_session *session;
1013 char *script_path = NULL;
1014 const char **__argv;
1015 bool system_wide;
1016 int i, j, err;
1017
1018 setup_scripting();
1019
1020 argc = parse_options(argc, argv, options, script_usage,
1021 PARSE_OPT_STOP_AT_NON_OPTION);
1022
1023 if (argc > 1 && !strncmp(argv[0], "rec", strlen("rec"))) {
1024 rec_script_path = get_script_path(argv[1], RECORD_SUFFIX);
1025 if (!rec_script_path)
1026 return cmd_record(argc, argv, NULL);
1027 }
1028
1029 if (argc > 1 && !strncmp(argv[0], "rep", strlen("rep"))) {
1030 rep_script_path = get_script_path(argv[1], REPORT_SUFFIX);
1031 if (!rep_script_path) {
1032 fprintf(stderr,
1033 "Please specify a valid report script"
1034 "(see 'perf script -l' for listing)\n");
1035 return -1;
1036 }
1037 }
1038
1039 /* make sure PERF_EXEC_PATH is set for scripts */
1040 perf_set_argv_exec_path(perf_exec_path());
1041
1042 if (argc && !script_name && !rec_script_path && !rep_script_path) {
1043 int live_pipe[2];
1044 int rep_args;
1045 pid_t pid;
1046
1047 rec_script_path = get_script_path(argv[0], RECORD_SUFFIX);
1048 rep_script_path = get_script_path(argv[0], REPORT_SUFFIX);
1049
1050 if (!rec_script_path && !rep_script_path) {
1051 fprintf(stderr, " Couldn't find script %s\n\n See perf"
1052 " script -l for available scripts.\n", argv[0]);
1053 usage_with_options(script_usage, options);
1054 }
1055
1056 if (is_top_script(argv[0])) {
1057 rep_args = argc - 1;
1058 } else {
1059 int rec_args;
1060
1061 rep_args = has_required_arg(rep_script_path);
1062 rec_args = (argc - 1) - rep_args;
1063 if (rec_args < 0) {
1064 fprintf(stderr, " %s script requires options."
1065 "\n\n See perf script -l for available "
1066 "scripts and options.\n", argv[0]);
1067 usage_with_options(script_usage, options);
1068 }
1069 }
1070
1071 if (pipe(live_pipe) < 0) {
1072 perror("failed to create pipe");
1073 exit(-1);
1074 }
1075
1076 pid = fork();
1077 if (pid < 0) {
1078 perror("failed to fork");
1079 exit(-1);
1080 }
1081
1082 if (!pid) {
1083 system_wide = true;
1084 j = 0;
1085
1086 dup2(live_pipe[1], 1);
1087 close(live_pipe[0]);
1088
1089 if (!is_top_script(argv[0]))
1090 system_wide = !have_cmd(argc - rep_args,
1091 &argv[rep_args]);
1092
1093 __argv = malloc((argc + 6) * sizeof(const char *));
1094 if (!__argv)
1095 die("malloc");
1096
1097 __argv[j++] = "/bin/sh";
1098 __argv[j++] = rec_script_path;
1099 if (system_wide)
1100 __argv[j++] = "-a";
1101 __argv[j++] = "-q";
1102 __argv[j++] = "-o";
1103 __argv[j++] = "-";
1104 for (i = rep_args + 1; i < argc; i++)
1105 __argv[j++] = argv[i];
1106 __argv[j++] = NULL;
1107
1108 execvp("/bin/sh", (char **)__argv);
1109 free(__argv);
1110 exit(-1);
1111 }
1112
1113 dup2(live_pipe[0], 0);
1114 close(live_pipe[1]);
1115
1116 __argv = malloc((argc + 4) * sizeof(const char *));
1117 if (!__argv)
1118 die("malloc");
1119 j = 0;
1120 __argv[j++] = "/bin/sh";
1121 __argv[j++] = rep_script_path;
1122 for (i = 1; i < rep_args + 1; i++)
1123 __argv[j++] = argv[i];
1124 __argv[j++] = "-i";
1125 __argv[j++] = "-";
1126 __argv[j++] = NULL;
1127
1128 execvp("/bin/sh", (char **)__argv);
1129 free(__argv);
1130 exit(-1);
1131 }
1132
1133 if (rec_script_path)
1134 script_path = rec_script_path;
1135 if (rep_script_path)
1136 script_path = rep_script_path;
1137
1138 if (script_path) {
1139 system_wide = false;
1140 j = 0;
1141
1142 if (rec_script_path)
1143 system_wide = !have_cmd(argc - 1, &argv[1]);
1144
1145 __argv = malloc((argc + 2) * sizeof(const char *));
1146 if (!__argv)
1147 die("malloc");
1148 __argv[j++] = "/bin/sh";
1149 __argv[j++] = script_path;
1150 if (system_wide)
1151 __argv[j++] = "-a";
1152 for (i = 2; i < argc; i++)
1153 __argv[j++] = argv[i];
1154 __argv[j++] = NULL;
1155
1156 execvp("/bin/sh", (char **)__argv);
1157 free(__argv);
1158 exit(-1);
1159 }
1160
1161 if (symbol__init() < 0)
1162 return -1;
1163 if (!script_name)
1164 setup_pager();
1165
1166 session = perf_session__new(input_name, O_RDONLY, 0, false, &event_ops);
1167 if (session == NULL)
1168 return -ENOMEM;
1169
1170 if (!no_callchain)
1171 symbol_conf.use_callchain = true;
1172 else
1173 symbol_conf.use_callchain = false;
1174
1175 if (generate_script_lang) {
1176 struct stat perf_stat;
1177 int input;
1178
1179 if (output_set_by_user()) {
1180 fprintf(stderr,
1181 "custom fields not supported for generated scripts");
1182 return -1;
1183 }
1184
1185 input = open(input_name, O_RDONLY);
1186 if (input < 0) {
1187 perror("failed to open file");
1188 exit(-1);
1189 }
1190
1191 err = fstat(input, &perf_stat);
1192 if (err < 0) {
1193 perror("failed to stat file");
1194 exit(-1);
1195 }
1196
1197 if (!perf_stat.st_size) {
1198 fprintf(stderr, "zero-sized file, nothing to do!\n");
1199 exit(0);
1200 }
1201
1202 scripting_ops = script_spec__lookup(generate_script_lang);
1203 if (!scripting_ops) {
1204 fprintf(stderr, "invalid language specifier");
1205 return -1;
1206 }
1207
1208 err = scripting_ops->generate_script("perf-script");
1209 goto out;
1210 }
1211
1212 if (script_name) {
1213 err = scripting_ops->start_script(script_name, argc, argv);
1214 if (err)
1215 goto out;
1216 pr_debug("perf script started with script %s\n\n", script_name);
1217 }
1218
1219
1220 err = perf_session__check_output_opt(session);
1221 if (err < 0)
1222 goto out;
1223
1224 err = __cmd_script(session);
1225
1226 perf_session__delete(session);
1227 cleanup_scripting();
1228out:
1229 return err;
1230}
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index a6b4d44f9502..a9f06715e44d 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -6,24 +6,28 @@
6 * 6 *
7 * Sample output: 7 * Sample output:
8 8
9 $ perf stat ~/hackbench 10 9 $ perf stat ./hackbench 10
10 Time: 0.104
11 10
12 Performance counter stats for '/home/mingo/hackbench': 11 Time: 0.118
13 12
14 1255.538611 task clock ticks # 10.143 CPU utilization factor 13 Performance counter stats for './hackbench 10':
15 54011 context switches # 0.043 M/sec
16 385 CPU migrations # 0.000 M/sec
17 17755 pagefaults # 0.014 M/sec
18 3808323185 CPU cycles # 3033.219 M/sec
19 1575111190 instructions # 1254.530 M/sec
20 17367895 cache references # 13.833 M/sec
21 7674421 cache misses # 6.112 M/sec
22 14
23 Wall-clock time elapsed: 123.786620 msecs 15 1708.761321 task-clock # 11.037 CPUs utilized
16 41,190 context-switches # 0.024 M/sec
17 6,735 CPU-migrations # 0.004 M/sec
18 17,318 page-faults # 0.010 M/sec
19 5,205,202,243 cycles # 3.046 GHz
20 3,856,436,920 stalled-cycles-frontend # 74.09% frontend cycles idle
21 1,600,790,871 stalled-cycles-backend # 30.75% backend cycles idle
22 2,603,501,247 instructions # 0.50 insns per cycle
23 # 1.48 stalled cycles per insn
24 484,357,498 branches # 283.455 M/sec
25 6,388,934 branch-misses # 1.32% of all branches
26
27 0.154822978 seconds time elapsed
24 28
25 * 29 *
26 * Copyright (C) 2008, Red Hat Inc, Ingo Molnar <mingo@redhat.com> 30 * Copyright (C) 2008-2011, Red Hat Inc, Ingo Molnar <mingo@redhat.com>
27 * 31 *
28 * Improvements and fixes by: 32 * Improvements and fixes by:
29 * 33 *
@@ -43,15 +47,21 @@
43#include "util/parse-options.h" 47#include "util/parse-options.h"
44#include "util/parse-events.h" 48#include "util/parse-events.h"
45#include "util/event.h" 49#include "util/event.h"
50#include "util/evlist.h"
51#include "util/evsel.h"
46#include "util/debug.h" 52#include "util/debug.h"
53#include "util/color.h"
47#include "util/header.h" 54#include "util/header.h"
48#include "util/cpumap.h" 55#include "util/cpumap.h"
49#include "util/thread.h" 56#include "util/thread.h"
57#include "util/thread_map.h"
50 58
51#include <sys/prctl.h> 59#include <sys/prctl.h>
52#include <math.h> 60#include <math.h>
53#include <locale.h> 61#include <locale.h>
54 62
63#define DEFAULT_SEPARATOR " "
64
55static struct perf_event_attr default_attrs[] = { 65static struct perf_event_attr default_attrs[] = {
56 66
57 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK }, 67 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK },
@@ -60,34 +70,127 @@ static struct perf_event_attr default_attrs[] = {
60 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS }, 70 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS },
61 71
62 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES }, 72 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES },
73 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_FRONTEND },
74 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_BACKEND },
63 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS }, 75 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS },
64 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS }, 76 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS },
65 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES }, 77 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES },
66 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_REFERENCES },
67 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_MISSES },
68 78
69}; 79};
70 80
81/*
82 * Detailed stats (-d), covering the L1 and last level data caches:
83 */
84static struct perf_event_attr detailed_attrs[] = {
85
86 { .type = PERF_TYPE_HW_CACHE,
87 .config =
88 PERF_COUNT_HW_CACHE_L1D << 0 |
89 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
90 (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) },
91
92 { .type = PERF_TYPE_HW_CACHE,
93 .config =
94 PERF_COUNT_HW_CACHE_L1D << 0 |
95 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
96 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) },
97
98 { .type = PERF_TYPE_HW_CACHE,
99 .config =
100 PERF_COUNT_HW_CACHE_LL << 0 |
101 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
102 (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) },
103
104 { .type = PERF_TYPE_HW_CACHE,
105 .config =
106 PERF_COUNT_HW_CACHE_LL << 0 |
107 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
108 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) },
109};
110
111/*
112 * Very detailed stats (-d -d), covering the instruction cache and the TLB caches:
113 */
114static struct perf_event_attr very_detailed_attrs[] = {
115
116 { .type = PERF_TYPE_HW_CACHE,
117 .config =
118 PERF_COUNT_HW_CACHE_L1I << 0 |
119 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
120 (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) },
121
122 { .type = PERF_TYPE_HW_CACHE,
123 .config =
124 PERF_COUNT_HW_CACHE_L1I << 0 |
125 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
126 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) },
127
128 { .type = PERF_TYPE_HW_CACHE,
129 .config =
130 PERF_COUNT_HW_CACHE_DTLB << 0 |
131 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
132 (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) },
133
134 { .type = PERF_TYPE_HW_CACHE,
135 .config =
136 PERF_COUNT_HW_CACHE_DTLB << 0 |
137 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
138 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) },
139
140 { .type = PERF_TYPE_HW_CACHE,
141 .config =
142 PERF_COUNT_HW_CACHE_ITLB << 0 |
143 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
144 (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) },
145
146 { .type = PERF_TYPE_HW_CACHE,
147 .config =
148 PERF_COUNT_HW_CACHE_ITLB << 0 |
149 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
150 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) },
151
152};
153
154/*
155 * Very, very detailed stats (-d -d -d), adding prefetch events:
156 */
157static struct perf_event_attr very_very_detailed_attrs[] = {
158
159 { .type = PERF_TYPE_HW_CACHE,
160 .config =
161 PERF_COUNT_HW_CACHE_L1D << 0 |
162 (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) |
163 (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) },
164
165 { .type = PERF_TYPE_HW_CACHE,
166 .config =
167 PERF_COUNT_HW_CACHE_L1D << 0 |
168 (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) |
169 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) },
170};
171
172
173
174struct perf_evlist *evsel_list;
175
71static bool system_wide = false; 176static bool system_wide = false;
72static int nr_cpus = 0;
73static int run_idx = 0; 177static int run_idx = 0;
74 178
75static int run_count = 1; 179static int run_count = 1;
76static bool no_inherit = false; 180static bool no_inherit = false;
77static bool scale = true; 181static bool scale = true;
182static bool no_aggr = false;
78static pid_t target_pid = -1; 183static pid_t target_pid = -1;
79static pid_t target_tid = -1; 184static pid_t target_tid = -1;
80static pid_t *all_tids = NULL;
81static int thread_num = 0;
82static pid_t child_pid = -1; 185static pid_t child_pid = -1;
83static bool null_run = false; 186static bool null_run = false;
84static bool big_num = false; 187static int detailed_run = 0;
188static bool sync_run = false;
189static bool big_num = true;
190static int big_num_opt = -1;
85static const char *cpu_list; 191static const char *cpu_list;
86 192static const char *csv_sep = NULL;
87 193static bool csv_output = false;
88static int *fd[MAX_NR_CPUS][MAX_COUNTERS];
89
90static int event_scaled[MAX_COUNTERS];
91 194
92static volatile int done = 0; 195static volatile int done = 0;
93 196
@@ -96,6 +199,22 @@ struct stats
96 double n, mean, M2; 199 double n, mean, M2;
97}; 200};
98 201
202struct perf_stat {
203 struct stats res_stats[3];
204};
205
206static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel)
207{
208 evsel->priv = zalloc(sizeof(struct perf_stat));
209 return evsel->priv == NULL ? -ENOMEM : 0;
210}
211
212static void perf_evsel__free_stat_priv(struct perf_evsel *evsel)
213{
214 free(evsel->priv);
215 evsel->priv = NULL;
216}
217
99static void update_stats(struct stats *stats, u64 val) 218static void update_stats(struct stats *stats, u64 val)
100{ 219{
101 double delta; 220 double delta;
@@ -135,154 +254,143 @@ static double stddev_stats(struct stats *stats)
135 return sqrt(variance_mean); 254 return sqrt(variance_mean);
136} 255}
137 256
138struct stats event_res_stats[MAX_COUNTERS][3]; 257struct stats runtime_nsecs_stats[MAX_NR_CPUS];
139struct stats runtime_nsecs_stats; 258struct stats runtime_cycles_stats[MAX_NR_CPUS];
259struct stats runtime_stalled_cycles_front_stats[MAX_NR_CPUS];
260struct stats runtime_stalled_cycles_back_stats[MAX_NR_CPUS];
261struct stats runtime_branches_stats[MAX_NR_CPUS];
262struct stats runtime_cacherefs_stats[MAX_NR_CPUS];
263struct stats runtime_l1_dcache_stats[MAX_NR_CPUS];
264struct stats runtime_l1_icache_stats[MAX_NR_CPUS];
265struct stats runtime_ll_cache_stats[MAX_NR_CPUS];
266struct stats runtime_itlb_cache_stats[MAX_NR_CPUS];
267struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS];
140struct stats walltime_nsecs_stats; 268struct stats walltime_nsecs_stats;
141struct stats runtime_cycles_stats;
142struct stats runtime_branches_stats;
143
144#define MATCH_EVENT(t, c, counter) \
145 (attrs[counter].type == PERF_TYPE_##t && \
146 attrs[counter].config == PERF_COUNT_##c)
147 269
148#define ERR_PERF_OPEN \ 270static int create_perf_stat_counter(struct perf_evsel *evsel)
149"Error: counter %d, sys_perf_event_open() syscall returned with %d (%s)\n"
150
151static int create_perf_stat_counter(int counter)
152{ 271{
153 struct perf_event_attr *attr = attrs + counter; 272 struct perf_event_attr *attr = &evsel->attr;
154 int thread;
155 int ncreated = 0;
156 273
157 if (scale) 274 if (scale)
158 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | 275 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
159 PERF_FORMAT_TOTAL_TIME_RUNNING; 276 PERF_FORMAT_TOTAL_TIME_RUNNING;
160 277
161 if (system_wide) { 278 attr->inherit = !no_inherit;
162 int cpu; 279
163 280 if (system_wide)
164 for (cpu = 0; cpu < nr_cpus; cpu++) { 281 return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, false);
165 fd[cpu][counter][0] = sys_perf_event_open(attr, 282
166 -1, cpumap[cpu], -1, 0); 283 if (target_pid == -1 && target_tid == -1) {
167 if (fd[cpu][counter][0] < 0) 284 attr->disabled = 1;
168 pr_debug(ERR_PERF_OPEN, counter, 285 attr->enable_on_exec = 1;
169 fd[cpu][counter][0], strerror(errno));
170 else
171 ++ncreated;
172 }
173 } else {
174 attr->inherit = !no_inherit;
175 if (target_pid == -1 && target_tid == -1) {
176 attr->disabled = 1;
177 attr->enable_on_exec = 1;
178 }
179 for (thread = 0; thread < thread_num; thread++) {
180 fd[0][counter][thread] = sys_perf_event_open(attr,
181 all_tids[thread], -1, -1, 0);
182 if (fd[0][counter][thread] < 0)
183 pr_debug(ERR_PERF_OPEN, counter,
184 fd[0][counter][thread],
185 strerror(errno));
186 else
187 ++ncreated;
188 }
189 } 286 }
190 287
191 return ncreated; 288 return perf_evsel__open_per_thread(evsel, evsel_list->threads, false);
192} 289}
193 290
194/* 291/*
195 * Does the counter have nsecs as a unit? 292 * Does the counter have nsecs as a unit?
196 */ 293 */
197static inline int nsec_counter(int counter) 294static inline int nsec_counter(struct perf_evsel *evsel)
198{ 295{
199 if (MATCH_EVENT(SOFTWARE, SW_CPU_CLOCK, counter) || 296 if (perf_evsel__match(evsel, SOFTWARE, SW_CPU_CLOCK) ||
200 MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) 297 perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK))
201 return 1; 298 return 1;
202 299
203 return 0; 300 return 0;
204} 301}
205 302
206/* 303/*
304 * Update various tracking values we maintain to print
305 * more semantic information such as miss/hit ratios,
306 * instruction rates, etc:
307 */
308static void update_shadow_stats(struct perf_evsel *counter, u64 *count)
309{
310 if (perf_evsel__match(counter, SOFTWARE, SW_TASK_CLOCK))
311 update_stats(&runtime_nsecs_stats[0], count[0]);
312 else if (perf_evsel__match(counter, HARDWARE, HW_CPU_CYCLES))
313 update_stats(&runtime_cycles_stats[0], count[0]);
314 else if (perf_evsel__match(counter, HARDWARE, HW_STALLED_CYCLES_FRONTEND))
315 update_stats(&runtime_stalled_cycles_front_stats[0], count[0]);
316 else if (perf_evsel__match(counter, HARDWARE, HW_STALLED_CYCLES_BACKEND))
317 update_stats(&runtime_stalled_cycles_back_stats[0], count[0]);
318 else if (perf_evsel__match(counter, HARDWARE, HW_BRANCH_INSTRUCTIONS))
319 update_stats(&runtime_branches_stats[0], count[0]);
320 else if (perf_evsel__match(counter, HARDWARE, HW_CACHE_REFERENCES))
321 update_stats(&runtime_cacherefs_stats[0], count[0]);
322 else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_L1D))
323 update_stats(&runtime_l1_dcache_stats[0], count[0]);
324 else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_L1I))
325 update_stats(&runtime_l1_icache_stats[0], count[0]);
326 else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_LL))
327 update_stats(&runtime_ll_cache_stats[0], count[0]);
328 else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_DTLB))
329 update_stats(&runtime_dtlb_cache_stats[0], count[0]);
330 else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_ITLB))
331 update_stats(&runtime_itlb_cache_stats[0], count[0]);
332}
333
334/*
207 * Read out the results of a single counter: 335 * Read out the results of a single counter:
336 * aggregate counts across CPUs in system-wide mode
208 */ 337 */
209static void read_counter(int counter) 338static int read_counter_aggr(struct perf_evsel *counter)
210{ 339{
211 u64 count[3], single_count[3]; 340 struct perf_stat *ps = counter->priv;
212 int cpu; 341 u64 *count = counter->counts->aggr.values;
213 size_t res, nv; 342 int i;
214 int scaled;
215 int i, thread;
216 343
217 count[0] = count[1] = count[2] = 0; 344 if (__perf_evsel__read(counter, evsel_list->cpus->nr,
345 evsel_list->threads->nr, scale) < 0)
346 return -1;
218 347
219 nv = scale ? 3 : 1; 348 for (i = 0; i < 3; i++)
220 for (cpu = 0; cpu < nr_cpus; cpu++) { 349 update_stats(&ps->res_stats[i], count[i]);
221 for (thread = 0; thread < thread_num; thread++) {
222 if (fd[cpu][counter][thread] < 0)
223 continue;
224 350
225 res = read(fd[cpu][counter][thread], 351 if (verbose) {
226 single_count, nv * sizeof(u64)); 352 fprintf(stderr, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
227 assert(res == nv * sizeof(u64)); 353 event_name(counter), count[0], count[1], count[2]);
354 }
228 355
229 close(fd[cpu][counter][thread]); 356 /*
230 fd[cpu][counter][thread] = -1; 357 * Save the full runtime - to allow normalization during printout:
358 */
359 update_shadow_stats(counter, count);
231 360
232 count[0] += single_count[0]; 361 return 0;
233 if (scale) { 362}
234 count[1] += single_count[1];
235 count[2] += single_count[2];
236 }
237 }
238 }
239 363
240 scaled = 0; 364/*
241 if (scale) { 365 * Read out the results of a single counter:
242 if (count[2] == 0) { 366 * do not aggregate counts across CPUs in system-wide mode
243 event_scaled[counter] = -1; 367 */
244 count[0] = 0; 368static int read_counter(struct perf_evsel *counter)
245 return; 369{
246 } 370 u64 *count;
371 int cpu;
247 372
248 if (count[2] < count[1]) { 373 for (cpu = 0; cpu < evsel_list->cpus->nr; cpu++) {
249 event_scaled[counter] = 1; 374 if (__perf_evsel__read_on_cpu(counter, cpu, 0, scale) < 0)
250 count[0] = (unsigned long long) 375 return -1;
251 ((double)count[0] * count[1] / count[2] + 0.5);
252 }
253 }
254 376
255 for (i = 0; i < 3; i++) 377 count = counter->counts->cpu[cpu].values;
256 update_stats(&event_res_stats[counter][i], count[i]);
257 378
258 if (verbose) { 379 update_shadow_stats(counter, count);
259 fprintf(stderr, "%s: %Ld %Ld %Ld\n", event_name(counter),
260 count[0], count[1], count[2]);
261 } 380 }
262 381
263 /* 382 return 0;
264 * Save the full runtime - to allow normalization during printout:
265 */
266 if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter))
267 update_stats(&runtime_nsecs_stats, count[0]);
268 if (MATCH_EVENT(HARDWARE, HW_CPU_CYCLES, counter))
269 update_stats(&runtime_cycles_stats, count[0]);
270 if (MATCH_EVENT(HARDWARE, HW_BRANCH_INSTRUCTIONS, counter))
271 update_stats(&runtime_branches_stats, count[0]);
272} 383}
273 384
274static int run_perf_stat(int argc __used, const char **argv) 385static int run_perf_stat(int argc __used, const char **argv)
275{ 386{
276 unsigned long long t0, t1; 387 unsigned long long t0, t1;
388 struct perf_evsel *counter;
277 int status = 0; 389 int status = 0;
278 int counter, ncreated = 0;
279 int child_ready_pipe[2], go_pipe[2]; 390 int child_ready_pipe[2], go_pipe[2];
280 const bool forks = (argc > 0); 391 const bool forks = (argc > 0);
281 char buf; 392 char buf;
282 393
283 if (!system_wide)
284 nr_cpus = 1;
285
286 if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) { 394 if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) {
287 perror("failed to create pipes"); 395 perror("failed to create pipes");
288 exit(1); 396 exit(1);
@@ -322,7 +430,7 @@ static int run_perf_stat(int argc __used, const char **argv)
322 } 430 }
323 431
324 if (target_tid == -1 && target_pid == -1 && !system_wide) 432 if (target_tid == -1 && target_pid == -1 && !system_wide)
325 all_tids[0] = child_pid; 433 evsel_list->threads->map[0] = child_pid;
326 434
327 /* 435 /*
328 * Wait for the child to be ready to exec. 436 * Wait for the child to be ready to exec.
@@ -334,15 +442,35 @@ static int run_perf_stat(int argc __used, const char **argv)
334 close(child_ready_pipe[0]); 442 close(child_ready_pipe[0]);
335 } 443 }
336 444
337 for (counter = 0; counter < nr_counters; counter++) 445 list_for_each_entry(counter, &evsel_list->entries, node) {
338 ncreated += create_perf_stat_counter(counter); 446 if (create_perf_stat_counter(counter) < 0) {
447 if (errno == EINVAL || errno == ENOSYS || errno == ENOENT) {
448 if (verbose)
449 ui__warning("%s event is not supported by the kernel.\n",
450 event_name(counter));
451 continue;
452 }
453
454 if (errno == EPERM || errno == EACCES) {
455 error("You may not have permission to collect %sstats.\n"
456 "\t Consider tweaking"
457 " /proc/sys/kernel/perf_event_paranoid or running as root.",
458 system_wide ? "system-wide " : "");
459 } else {
460 error("open_counter returned with %d (%s). "
461 "/bin/dmesg may provide additional information.\n",
462 errno, strerror(errno));
463 }
464 if (child_pid != -1)
465 kill(child_pid, SIGTERM);
466 die("Not all events could be opened.\n");
467 return -1;
468 }
469 }
339 470
340 if (ncreated == 0) { 471 if (perf_evlist__set_filters(evsel_list)) {
341 pr_err("No permission to collect %sstats.\n" 472 error("failed to set filter with %d (%s)\n", errno,
342 "Consider tweaking /proc/sys/kernel/perf_event_paranoid.\n", 473 strerror(errno));
343 system_wide ? "system-wide " : "");
344 if (child_pid != -1)
345 kill(child_pid, SIGTERM);
346 return -1; 474 return -1;
347 } 475 }
348 476
@@ -362,136 +490,501 @@ static int run_perf_stat(int argc __used, const char **argv)
362 490
363 update_stats(&walltime_nsecs_stats, t1 - t0); 491 update_stats(&walltime_nsecs_stats, t1 - t0);
364 492
365 for (counter = 0; counter < nr_counters; counter++) 493 if (no_aggr) {
366 read_counter(counter); 494 list_for_each_entry(counter, &evsel_list->entries, node) {
495 read_counter(counter);
496 perf_evsel__close_fd(counter, evsel_list->cpus->nr, 1);
497 }
498 } else {
499 list_for_each_entry(counter, &evsel_list->entries, node) {
500 read_counter_aggr(counter);
501 perf_evsel__close_fd(counter, evsel_list->cpus->nr,
502 evsel_list->threads->nr);
503 }
504 }
367 505
368 return WEXITSTATUS(status); 506 return WEXITSTATUS(status);
369} 507}
370 508
371static void print_noise(int counter, double avg) 509static void print_noise_pct(double total, double avg)
510{
511 double pct = 0.0;
512
513 if (avg)
514 pct = 100.0*total/avg;
515
516 fprintf(stderr, " ( +-%6.2f%% )", pct);
517}
518
519static void print_noise(struct perf_evsel *evsel, double avg)
372{ 520{
521 struct perf_stat *ps;
522
373 if (run_count == 1) 523 if (run_count == 1)
374 return; 524 return;
375 525
376 fprintf(stderr, " ( +- %7.3f%% )", 526 ps = evsel->priv;
377 100 * stddev_stats(&event_res_stats[counter][0]) / avg); 527 print_noise_pct(stddev_stats(&ps->res_stats[0]), avg);
378} 528}
379 529
380static void nsec_printout(int counter, double avg) 530static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg)
381{ 531{
382 double msecs = avg / 1e6; 532 double msecs = avg / 1e6;
533 char cpustr[16] = { '\0', };
534 const char *fmt = csv_output ? "%s%.6f%s%s" : "%s%18.6f%s%-25s";
383 535
384 fprintf(stderr, " %18.6f %-24s", msecs, event_name(counter)); 536 if (no_aggr)
537 sprintf(cpustr, "CPU%*d%s",
538 csv_output ? 0 : -4,
539 evsel_list->cpus->map[cpu], csv_sep);
385 540
386 if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) { 541 fprintf(stderr, fmt, cpustr, msecs, csv_sep, event_name(evsel));
387 fprintf(stderr, " # %10.3f CPUs ", 542
388 avg / avg_stats(&walltime_nsecs_stats)); 543 if (evsel->cgrp)
389 } 544 fprintf(stderr, "%s%s", csv_sep, evsel->cgrp->name);
545
546 if (csv_output)
547 return;
548
549 if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK))
550 fprintf(stderr, " # %8.3f CPUs utilized ", avg / avg_stats(&walltime_nsecs_stats));
551}
552
553static void print_stalled_cycles_frontend(int cpu, struct perf_evsel *evsel __used, double avg)
554{
555 double total, ratio = 0.0;
556 const char *color;
557
558 total = avg_stats(&runtime_cycles_stats[cpu]);
559
560 if (total)
561 ratio = avg / total * 100.0;
562
563 color = PERF_COLOR_NORMAL;
564 if (ratio > 50.0)
565 color = PERF_COLOR_RED;
566 else if (ratio > 30.0)
567 color = PERF_COLOR_MAGENTA;
568 else if (ratio > 10.0)
569 color = PERF_COLOR_YELLOW;
570
571 fprintf(stderr, " # ");
572 color_fprintf(stderr, color, "%6.2f%%", ratio);
573 fprintf(stderr, " frontend cycles idle ");
574}
575
576static void print_stalled_cycles_backend(int cpu, struct perf_evsel *evsel __used, double avg)
577{
578 double total, ratio = 0.0;
579 const char *color;
580
581 total = avg_stats(&runtime_cycles_stats[cpu]);
582
583 if (total)
584 ratio = avg / total * 100.0;
585
586 color = PERF_COLOR_NORMAL;
587 if (ratio > 75.0)
588 color = PERF_COLOR_RED;
589 else if (ratio > 50.0)
590 color = PERF_COLOR_MAGENTA;
591 else if (ratio > 20.0)
592 color = PERF_COLOR_YELLOW;
593
594 fprintf(stderr, " # ");
595 color_fprintf(stderr, color, "%6.2f%%", ratio);
596 fprintf(stderr, " backend cycles idle ");
597}
598
599static void print_branch_misses(int cpu, struct perf_evsel *evsel __used, double avg)
600{
601 double total, ratio = 0.0;
602 const char *color;
603
604 total = avg_stats(&runtime_branches_stats[cpu]);
605
606 if (total)
607 ratio = avg / total * 100.0;
608
609 color = PERF_COLOR_NORMAL;
610 if (ratio > 20.0)
611 color = PERF_COLOR_RED;
612 else if (ratio > 10.0)
613 color = PERF_COLOR_MAGENTA;
614 else if (ratio > 5.0)
615 color = PERF_COLOR_YELLOW;
616
617 fprintf(stderr, " # ");
618 color_fprintf(stderr, color, "%6.2f%%", ratio);
619 fprintf(stderr, " of all branches ");
620}
621
622static void print_l1_dcache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
623{
624 double total, ratio = 0.0;
625 const char *color;
626
627 total = avg_stats(&runtime_l1_dcache_stats[cpu]);
628
629 if (total)
630 ratio = avg / total * 100.0;
631
632 color = PERF_COLOR_NORMAL;
633 if (ratio > 20.0)
634 color = PERF_COLOR_RED;
635 else if (ratio > 10.0)
636 color = PERF_COLOR_MAGENTA;
637 else if (ratio > 5.0)
638 color = PERF_COLOR_YELLOW;
639
640 fprintf(stderr, " # ");
641 color_fprintf(stderr, color, "%6.2f%%", ratio);
642 fprintf(stderr, " of all L1-dcache hits ");
390} 643}
391 644
392static void abs_printout(int counter, double avg) 645static void print_l1_icache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
393{ 646{
394 double total, ratio = 0.0; 647 double total, ratio = 0.0;
648 const char *color;
395 649
396 if (big_num) 650 total = avg_stats(&runtime_l1_icache_stats[cpu]);
397 fprintf(stderr, " %'18.0f %-24s", avg, event_name(counter)); 651
652 if (total)
653 ratio = avg / total * 100.0;
654
655 color = PERF_COLOR_NORMAL;
656 if (ratio > 20.0)
657 color = PERF_COLOR_RED;
658 else if (ratio > 10.0)
659 color = PERF_COLOR_MAGENTA;
660 else if (ratio > 5.0)
661 color = PERF_COLOR_YELLOW;
662
663 fprintf(stderr, " # ");
664 color_fprintf(stderr, color, "%6.2f%%", ratio);
665 fprintf(stderr, " of all L1-icache hits ");
666}
667
668static void print_dtlb_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
669{
670 double total, ratio = 0.0;
671 const char *color;
672
673 total = avg_stats(&runtime_dtlb_cache_stats[cpu]);
674
675 if (total)
676 ratio = avg / total * 100.0;
677
678 color = PERF_COLOR_NORMAL;
679 if (ratio > 20.0)
680 color = PERF_COLOR_RED;
681 else if (ratio > 10.0)
682 color = PERF_COLOR_MAGENTA;
683 else if (ratio > 5.0)
684 color = PERF_COLOR_YELLOW;
685
686 fprintf(stderr, " # ");
687 color_fprintf(stderr, color, "%6.2f%%", ratio);
688 fprintf(stderr, " of all dTLB cache hits ");
689}
690
691static void print_itlb_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
692{
693 double total, ratio = 0.0;
694 const char *color;
695
696 total = avg_stats(&runtime_itlb_cache_stats[cpu]);
697
698 if (total)
699 ratio = avg / total * 100.0;
700
701 color = PERF_COLOR_NORMAL;
702 if (ratio > 20.0)
703 color = PERF_COLOR_RED;
704 else if (ratio > 10.0)
705 color = PERF_COLOR_MAGENTA;
706 else if (ratio > 5.0)
707 color = PERF_COLOR_YELLOW;
708
709 fprintf(stderr, " # ");
710 color_fprintf(stderr, color, "%6.2f%%", ratio);
711 fprintf(stderr, " of all iTLB cache hits ");
712}
713
714static void print_ll_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
715{
716 double total, ratio = 0.0;
717 const char *color;
718
719 total = avg_stats(&runtime_ll_cache_stats[cpu]);
720
721 if (total)
722 ratio = avg / total * 100.0;
723
724 color = PERF_COLOR_NORMAL;
725 if (ratio > 20.0)
726 color = PERF_COLOR_RED;
727 else if (ratio > 10.0)
728 color = PERF_COLOR_MAGENTA;
729 else if (ratio > 5.0)
730 color = PERF_COLOR_YELLOW;
731
732 fprintf(stderr, " # ");
733 color_fprintf(stderr, color, "%6.2f%%", ratio);
734 fprintf(stderr, " of all LL-cache hits ");
735}
736
737static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
738{
739 double total, ratio = 0.0;
740 char cpustr[16] = { '\0', };
741 const char *fmt;
742
743 if (csv_output)
744 fmt = "%s%.0f%s%s";
745 else if (big_num)
746 fmt = "%s%'18.0f%s%-25s";
398 else 747 else
399 fprintf(stderr, " %18.0f %-24s", avg, event_name(counter)); 748 fmt = "%s%18.0f%s%-25s";
400 749
401 if (MATCH_EVENT(HARDWARE, HW_INSTRUCTIONS, counter)) { 750 if (no_aggr)
402 total = avg_stats(&runtime_cycles_stats); 751 sprintf(cpustr, "CPU%*d%s",
752 csv_output ? 0 : -4,
753 evsel_list->cpus->map[cpu], csv_sep);
754 else
755 cpu = 0;
756
757 fprintf(stderr, fmt, cpustr, avg, csv_sep, event_name(evsel));
758
759 if (evsel->cgrp)
760 fprintf(stderr, "%s%s", csv_sep, evsel->cgrp->name);
761
762 if (csv_output)
763 return;
764
765 if (perf_evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS)) {
766 total = avg_stats(&runtime_cycles_stats[cpu]);
403 767
404 if (total) 768 if (total)
405 ratio = avg / total; 769 ratio = avg / total;
406 770
407 fprintf(stderr, " # %10.3f IPC ", ratio); 771 fprintf(stderr, " # %5.2f insns per cycle ", ratio);
408 } else if (MATCH_EVENT(HARDWARE, HW_BRANCH_MISSES, counter) && 772
409 runtime_branches_stats.n != 0) { 773 total = avg_stats(&runtime_stalled_cycles_front_stats[cpu]);
410 total = avg_stats(&runtime_branches_stats); 774 total = max(total, avg_stats(&runtime_stalled_cycles_back_stats[cpu]));
775
776 if (total && avg) {
777 ratio = total / avg;
778 fprintf(stderr, "\n # %5.2f stalled cycles per insn", ratio);
779 }
780
781 } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) &&
782 runtime_branches_stats[cpu].n != 0) {
783 print_branch_misses(cpu, evsel, avg);
784 } else if (
785 evsel->attr.type == PERF_TYPE_HW_CACHE &&
786 evsel->attr.config == ( PERF_COUNT_HW_CACHE_L1D |
787 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
788 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) &&
789 runtime_l1_dcache_stats[cpu].n != 0) {
790 print_l1_dcache_misses(cpu, evsel, avg);
791 } else if (
792 evsel->attr.type == PERF_TYPE_HW_CACHE &&
793 evsel->attr.config == ( PERF_COUNT_HW_CACHE_L1I |
794 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
795 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) &&
796 runtime_l1_icache_stats[cpu].n != 0) {
797 print_l1_icache_misses(cpu, evsel, avg);
798 } else if (
799 evsel->attr.type == PERF_TYPE_HW_CACHE &&
800 evsel->attr.config == ( PERF_COUNT_HW_CACHE_DTLB |
801 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
802 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) &&
803 runtime_dtlb_cache_stats[cpu].n != 0) {
804 print_dtlb_cache_misses(cpu, evsel, avg);
805 } else if (
806 evsel->attr.type == PERF_TYPE_HW_CACHE &&
807 evsel->attr.config == ( PERF_COUNT_HW_CACHE_ITLB |
808 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
809 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) &&
810 runtime_itlb_cache_stats[cpu].n != 0) {
811 print_itlb_cache_misses(cpu, evsel, avg);
812 } else if (
813 evsel->attr.type == PERF_TYPE_HW_CACHE &&
814 evsel->attr.config == ( PERF_COUNT_HW_CACHE_LL |
815 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
816 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) &&
817 runtime_ll_cache_stats[cpu].n != 0) {
818 print_ll_cache_misses(cpu, evsel, avg);
819 } else if (perf_evsel__match(evsel, HARDWARE, HW_CACHE_MISSES) &&
820 runtime_cacherefs_stats[cpu].n != 0) {
821 total = avg_stats(&runtime_cacherefs_stats[cpu]);
411 822
412 if (total) 823 if (total)
413 ratio = avg * 100 / total; 824 ratio = avg * 100 / total;
414 825
415 fprintf(stderr, " # %10.3f %% ", ratio); 826 fprintf(stderr, " # %8.3f %% of all cache refs ", ratio);
827
828 } else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_FRONTEND)) {
829 print_stalled_cycles_frontend(cpu, evsel, avg);
830 } else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_BACKEND)) {
831 print_stalled_cycles_backend(cpu, evsel, avg);
832 } else if (perf_evsel__match(evsel, HARDWARE, HW_CPU_CYCLES)) {
833 total = avg_stats(&runtime_nsecs_stats[cpu]);
834
835 if (total)
836 ratio = 1.0 * avg / total;
416 837
417 } else if (runtime_nsecs_stats.n != 0) { 838 fprintf(stderr, " # %8.3f GHz ", ratio);
418 total = avg_stats(&runtime_nsecs_stats); 839 } else if (runtime_nsecs_stats[cpu].n != 0) {
840 total = avg_stats(&runtime_nsecs_stats[cpu]);
419 841
420 if (total) 842 if (total)
421 ratio = 1000.0 * avg / total; 843 ratio = 1000.0 * avg / total;
422 844
423 fprintf(stderr, " # %10.3f M/sec", ratio); 845 fprintf(stderr, " # %8.3f M/sec ", ratio);
846 } else {
847 fprintf(stderr, " ");
424 } 848 }
425} 849}
426 850
427/* 851/*
428 * Print out the results of a single counter: 852 * Print out the results of a single counter:
853 * aggregated counts in system-wide mode
429 */ 854 */
430static void print_counter(int counter) 855static void print_counter_aggr(struct perf_evsel *counter)
431{ 856{
432 double avg = avg_stats(&event_res_stats[counter][0]); 857 struct perf_stat *ps = counter->priv;
433 int scaled = event_scaled[counter]; 858 double avg = avg_stats(&ps->res_stats[0]);
859 int scaled = counter->counts->scaled;
434 860
435 if (scaled == -1) { 861 if (scaled == -1) {
436 fprintf(stderr, " %18s %-24s\n", 862 fprintf(stderr, "%*s%s%*s",
437 "<not counted>", event_name(counter)); 863 csv_output ? 0 : 18,
864 "<not counted>",
865 csv_sep,
866 csv_output ? 0 : -24,
867 event_name(counter));
868
869 if (counter->cgrp)
870 fprintf(stderr, "%s%s", csv_sep, counter->cgrp->name);
871
872 fputc('\n', stderr);
438 return; 873 return;
439 } 874 }
440 875
441 if (nsec_counter(counter)) 876 if (nsec_counter(counter))
442 nsec_printout(counter, avg); 877 nsec_printout(-1, counter, avg);
443 else 878 else
444 abs_printout(counter, avg); 879 abs_printout(-1, counter, avg);
880
881 if (csv_output) {
882 fputc('\n', stderr);
883 return;
884 }
445 885
446 print_noise(counter, avg); 886 print_noise(counter, avg);
447 887
448 if (scaled) { 888 if (scaled) {
449 double avg_enabled, avg_running; 889 double avg_enabled, avg_running;
450 890
451 avg_enabled = avg_stats(&event_res_stats[counter][1]); 891 avg_enabled = avg_stats(&ps->res_stats[1]);
452 avg_running = avg_stats(&event_res_stats[counter][2]); 892 avg_running = avg_stats(&ps->res_stats[2]);
453 893
454 fprintf(stderr, " (scaled from %.2f%%)", 894 fprintf(stderr, " [%5.2f%%]", 100 * avg_running / avg_enabled);
455 100 * avg_running / avg_enabled);
456 } 895 }
457
458 fprintf(stderr, "\n"); 896 fprintf(stderr, "\n");
459} 897}
460 898
899/*
900 * Print out the results of a single counter:
901 * does not use aggregated count in system-wide
902 */
903static void print_counter(struct perf_evsel *counter)
904{
905 u64 ena, run, val;
906 int cpu;
907
908 for (cpu = 0; cpu < evsel_list->cpus->nr; cpu++) {
909 val = counter->counts->cpu[cpu].val;
910 ena = counter->counts->cpu[cpu].ena;
911 run = counter->counts->cpu[cpu].run;
912 if (run == 0 || ena == 0) {
913 fprintf(stderr, "CPU%*d%s%*s%s%*s",
914 csv_output ? 0 : -4,
915 evsel_list->cpus->map[cpu], csv_sep,
916 csv_output ? 0 : 18,
917 "<not counted>", csv_sep,
918 csv_output ? 0 : -24,
919 event_name(counter));
920
921 if (counter->cgrp)
922 fprintf(stderr, "%s%s", csv_sep, counter->cgrp->name);
923
924 fputc('\n', stderr);
925 continue;
926 }
927
928 if (nsec_counter(counter))
929 nsec_printout(cpu, counter, val);
930 else
931 abs_printout(cpu, counter, val);
932
933 if (!csv_output) {
934 print_noise(counter, 1.0);
935
936 if (run != ena)
937 fprintf(stderr, " (%.2f%%)", 100.0 * run / ena);
938 }
939 fputc('\n', stderr);
940 }
941}
942
461static void print_stat(int argc, const char **argv) 943static void print_stat(int argc, const char **argv)
462{ 944{
463 int i, counter; 945 struct perf_evsel *counter;
946 int i;
464 947
465 fflush(stdout); 948 fflush(stdout);
466 949
467 fprintf(stderr, "\n"); 950 if (!csv_output) {
468 fprintf(stderr, " Performance counter stats for "); 951 fprintf(stderr, "\n");
469 if(target_pid == -1 && target_tid == -1) { 952 fprintf(stderr, " Performance counter stats for ");
470 fprintf(stderr, "\'%s", argv[0]); 953 if(target_pid == -1 && target_tid == -1) {
471 for (i = 1; i < argc; i++) 954 fprintf(stderr, "\'%s", argv[0]);
472 fprintf(stderr, " %s", argv[i]); 955 for (i = 1; i < argc; i++)
473 } else if (target_pid != -1) 956 fprintf(stderr, " %s", argv[i]);
474 fprintf(stderr, "process id \'%d", target_pid); 957 } else if (target_pid != -1)
475 else 958 fprintf(stderr, "process id \'%d", target_pid);
476 fprintf(stderr, "thread id \'%d", target_tid); 959 else
477 960 fprintf(stderr, "thread id \'%d", target_tid);
478 fprintf(stderr, "\'"); 961
479 if (run_count > 1) 962 fprintf(stderr, "\'");
480 fprintf(stderr, " (%d runs)", run_count); 963 if (run_count > 1)
481 fprintf(stderr, ":\n\n"); 964 fprintf(stderr, " (%d runs)", run_count);
965 fprintf(stderr, ":\n\n");
966 }
482 967
483 for (counter = 0; counter < nr_counters; counter++) 968 if (no_aggr) {
484 print_counter(counter); 969 list_for_each_entry(counter, &evsel_list->entries, node)
970 print_counter(counter);
971 } else {
972 list_for_each_entry(counter, &evsel_list->entries, node)
973 print_counter_aggr(counter);
974 }
485 975
486 fprintf(stderr, "\n"); 976 if (!csv_output) {
487 fprintf(stderr, " %18.9f seconds time elapsed", 977 if (!null_run)
488 avg_stats(&walltime_nsecs_stats)/1e9); 978 fprintf(stderr, "\n");
489 if (run_count > 1) { 979 fprintf(stderr, " %17.9f seconds time elapsed",
490 fprintf(stderr, " ( +- %7.3f%% )", 980 avg_stats(&walltime_nsecs_stats)/1e9);
491 100*stddev_stats(&walltime_nsecs_stats) / 981 if (run_count > 1) {
492 avg_stats(&walltime_nsecs_stats)); 982 fprintf(stderr, " ");
983 print_noise_pct(stddev_stats(&walltime_nsecs_stats),
984 avg_stats(&walltime_nsecs_stats));
985 }
986 fprintf(stderr, "\n\n");
493 } 987 }
494 fprintf(stderr, "\n\n");
495} 988}
496 989
497static volatile int signr = -1; 990static volatile int signr = -1;
@@ -521,10 +1014,19 @@ static const char * const stat_usage[] = {
521 NULL 1014 NULL
522}; 1015};
523 1016
1017static int stat__set_big_num(const struct option *opt __used,
1018 const char *s __used, int unset)
1019{
1020 big_num_opt = unset ? 0 : 1;
1021 return 0;
1022}
1023
524static const struct option options[] = { 1024static const struct option options[] = {
525 OPT_CALLBACK('e', "event", NULL, "event", 1025 OPT_CALLBACK('e', "event", &evsel_list, "event",
526 "event selector. use 'perf list' to list available events", 1026 "event selector. use 'perf list' to list available events",
527 parse_events), 1027 parse_events),
1028 OPT_CALLBACK(0, "filter", &evsel_list, "filter",
1029 "event filter", parse_filter),
528 OPT_BOOLEAN('i', "no-inherit", &no_inherit, 1030 OPT_BOOLEAN('i', "no-inherit", &no_inherit,
529 "child tasks do not inherit counters"), 1031 "child tasks do not inherit counters"),
530 OPT_INTEGER('p', "pid", &target_pid, 1032 OPT_INTEGER('p', "pid", &target_pid,
@@ -541,64 +1043,162 @@ static const struct option options[] = {
541 "repeat command and print average + stddev (max: 100)"), 1043 "repeat command and print average + stddev (max: 100)"),
542 OPT_BOOLEAN('n', "null", &null_run, 1044 OPT_BOOLEAN('n', "null", &null_run,
543 "null run - dont start any counters"), 1045 "null run - dont start any counters"),
544 OPT_BOOLEAN('B', "big-num", &big_num, 1046 OPT_INCR('d', "detailed", &detailed_run,
545 "print large numbers with thousands\' separators"), 1047 "detailed run - start a lot of events"),
1048 OPT_BOOLEAN('S', "sync", &sync_run,
1049 "call sync() before starting a run"),
1050 OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL,
1051 "print large numbers with thousands\' separators",
1052 stat__set_big_num),
546 OPT_STRING('C', "cpu", &cpu_list, "cpu", 1053 OPT_STRING('C', "cpu", &cpu_list, "cpu",
547 "list of cpus to monitor in system-wide"), 1054 "list of cpus to monitor in system-wide"),
1055 OPT_BOOLEAN('A', "no-aggr", &no_aggr,
1056 "disable CPU count aggregation"),
1057 OPT_STRING('x', "field-separator", &csv_sep, "separator",
1058 "print counts with custom separator"),
1059 OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
1060 "monitor event in cgroup name only",
1061 parse_cgroups),
548 OPT_END() 1062 OPT_END()
549}; 1063};
550 1064
1065/*
1066 * Add default attributes, if there were no attributes specified or
1067 * if -d/--detailed, -d -d or -d -d -d is used:
1068 */
1069static int add_default_attributes(void)
1070{
1071 struct perf_evsel *pos;
1072 size_t attr_nr = 0;
1073 size_t c;
1074
1075 /* Set attrs if no event is selected and !null_run: */
1076 if (null_run)
1077 return 0;
1078
1079 if (!evsel_list->nr_entries) {
1080 for (c = 0; c < ARRAY_SIZE(default_attrs); c++) {
1081 pos = perf_evsel__new(default_attrs + c, c + attr_nr);
1082 if (pos == NULL)
1083 return -1;
1084 perf_evlist__add(evsel_list, pos);
1085 }
1086 attr_nr += c;
1087 }
1088
1089 /* Detailed events get appended to the event list: */
1090
1091 if (detailed_run < 1)
1092 return 0;
1093
1094 /* Append detailed run extra attributes: */
1095 for (c = 0; c < ARRAY_SIZE(detailed_attrs); c++) {
1096 pos = perf_evsel__new(detailed_attrs + c, c + attr_nr);
1097 if (pos == NULL)
1098 return -1;
1099 perf_evlist__add(evsel_list, pos);
1100 }
1101 attr_nr += c;
1102
1103 if (detailed_run < 2)
1104 return 0;
1105
1106 /* Append very detailed run extra attributes: */
1107 for (c = 0; c < ARRAY_SIZE(very_detailed_attrs); c++) {
1108 pos = perf_evsel__new(very_detailed_attrs + c, c + attr_nr);
1109 if (pos == NULL)
1110 return -1;
1111 perf_evlist__add(evsel_list, pos);
1112 }
1113
1114 if (detailed_run < 3)
1115 return 0;
1116
1117 /* Append very, very detailed run extra attributes: */
1118 for (c = 0; c < ARRAY_SIZE(very_very_detailed_attrs); c++) {
1119 pos = perf_evsel__new(very_very_detailed_attrs + c, c + attr_nr);
1120 if (pos == NULL)
1121 return -1;
1122 perf_evlist__add(evsel_list, pos);
1123 }
1124
1125
1126 return 0;
1127}
1128
551int cmd_stat(int argc, const char **argv, const char *prefix __used) 1129int cmd_stat(int argc, const char **argv, const char *prefix __used)
552{ 1130{
553 int status; 1131 struct perf_evsel *pos;
554 int i,j; 1132 int status = -ENOMEM;
555 1133
556 setlocale(LC_ALL, ""); 1134 setlocale(LC_ALL, "");
557 1135
1136 evsel_list = perf_evlist__new(NULL, NULL);
1137 if (evsel_list == NULL)
1138 return -ENOMEM;
1139
558 argc = parse_options(argc, argv, options, stat_usage, 1140 argc = parse_options(argc, argv, options, stat_usage,
559 PARSE_OPT_STOP_AT_NON_OPTION); 1141 PARSE_OPT_STOP_AT_NON_OPTION);
1142
1143 if (csv_sep)
1144 csv_output = true;
1145 else
1146 csv_sep = DEFAULT_SEPARATOR;
1147
1148 /*
1149 * let the spreadsheet do the pretty-printing
1150 */
1151 if (csv_output) {
1152 /* User explicitely passed -B? */
1153 if (big_num_opt == 1) {
1154 fprintf(stderr, "-B option not supported with -x\n");
1155 usage_with_options(stat_usage, options);
1156 } else /* Nope, so disable big number formatting */
1157 big_num = false;
1158 } else if (big_num_opt == 0) /* User passed --no-big-num */
1159 big_num = false;
1160
560 if (!argc && target_pid == -1 && target_tid == -1) 1161 if (!argc && target_pid == -1 && target_tid == -1)
561 usage_with_options(stat_usage, options); 1162 usage_with_options(stat_usage, options);
562 if (run_count <= 0) 1163 if (run_count <= 0)
563 usage_with_options(stat_usage, options); 1164 usage_with_options(stat_usage, options);
564 1165
565 /* Set attrs and nr_counters if no event is selected and !null_run */ 1166 /* no_aggr, cgroup are for system-wide only */
566 if (!null_run && !nr_counters) { 1167 if ((no_aggr || nr_cgroups) && !system_wide) {
567 memcpy(attrs, default_attrs, sizeof(default_attrs)); 1168 fprintf(stderr, "both cgroup and no-aggregation "
568 nr_counters = ARRAY_SIZE(default_attrs); 1169 "modes only available in system-wide mode\n");
1170
1171 usage_with_options(stat_usage, options);
569 } 1172 }
570 1173
571 if (system_wide) 1174 if (add_default_attributes())
572 nr_cpus = read_cpu_map(cpu_list); 1175 goto out;
573 else
574 nr_cpus = 1;
575 1176
576 if (nr_cpus < 1) 1177 if (target_pid != -1)
1178 target_tid = target_pid;
1179
1180 evsel_list->threads = thread_map__new(target_pid, target_tid);
1181 if (evsel_list->threads == NULL) {
1182 pr_err("Problems finding threads of monitor\n");
577 usage_with_options(stat_usage, options); 1183 usage_with_options(stat_usage, options);
1184 }
578 1185
579 if (target_pid != -1) { 1186 if (system_wide)
580 target_tid = target_pid; 1187 evsel_list->cpus = cpu_map__new(cpu_list);
581 thread_num = find_all_tid(target_pid, &all_tids); 1188 else
582 if (thread_num <= 0) { 1189 evsel_list->cpus = cpu_map__dummy_new();
583 fprintf(stderr, "Can't find all threads of pid %d\n",
584 target_pid);
585 usage_with_options(stat_usage, options);
586 }
587 } else {
588 all_tids=malloc(sizeof(pid_t));
589 if (!all_tids)
590 return -ENOMEM;
591 1190
592 all_tids[0] = target_tid; 1191 if (evsel_list->cpus == NULL) {
593 thread_num = 1; 1192 perror("failed to parse CPUs map");
1193 usage_with_options(stat_usage, options);
1194 return -1;
594 } 1195 }
595 1196
596 for (i = 0; i < MAX_NR_CPUS; i++) { 1197 list_for_each_entry(pos, &evsel_list->entries, node) {
597 for (j = 0; j < MAX_COUNTERS; j++) { 1198 if (perf_evsel__alloc_stat_priv(pos) < 0 ||
598 fd[i][j] = malloc(sizeof(int)*thread_num); 1199 perf_evsel__alloc_counts(pos, evsel_list->cpus->nr) < 0 ||
599 if (!fd[i][j]) 1200 perf_evsel__alloc_fd(pos, evsel_list->cpus->nr, evsel_list->threads->nr) < 0)
600 return -ENOMEM; 1201 goto out_free_fd;
601 }
602 } 1202 }
603 1203
604 /* 1204 /*
@@ -616,11 +1216,20 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
616 for (run_idx = 0; run_idx < run_count; run_idx++) { 1216 for (run_idx = 0; run_idx < run_count; run_idx++) {
617 if (run_count != 1 && verbose) 1217 if (run_count != 1 && verbose)
618 fprintf(stderr, "[ perf stat: executing run #%d ... ]\n", run_idx + 1); 1218 fprintf(stderr, "[ perf stat: executing run #%d ... ]\n", run_idx + 1);
1219
1220 if (sync_run)
1221 sync();
1222
619 status = run_perf_stat(argc, argv); 1223 status = run_perf_stat(argc, argv);
620 } 1224 }
621 1225
622 if (status != -1) 1226 if (status != -1)
623 print_stat(argc, argv); 1227 print_stat(argc, argv);
624 1228out_free_fd:
1229 list_for_each_entry(pos, &evsel_list->entries, node)
1230 perf_evsel__free_stat_priv(pos);
1231 perf_evlist__delete_maps(evsel_list);
1232out:
1233 perf_evlist__delete(evsel_list);
625 return status; 1234 return status;
626} 1235}
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 035b9fa063a9..2da9162262b0 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -7,10 +7,11 @@
7 7
8#include "util/cache.h" 8#include "util/cache.h"
9#include "util/debug.h" 9#include "util/debug.h"
10#include "util/evlist.h"
10#include "util/parse-options.h" 11#include "util/parse-options.h"
11#include "util/session.h" 12#include "util/parse-events.h"
12#include "util/symbol.h" 13#include "util/symbol.h"
13#include "util/thread.h" 14#include "util/thread_map.h"
14 15
15static long page_size; 16static long page_size;
16 17
@@ -119,10 +120,16 @@ static int test__vmlinux_matches_kallsyms(void)
119 * end addresses too. 120 * end addresses too.
120 */ 121 */
121 for (nd = rb_first(&vmlinux_map->dso->symbols[type]); nd; nd = rb_next(nd)) { 122 for (nd = rb_first(&vmlinux_map->dso->symbols[type]); nd; nd = rb_next(nd)) {
122 struct symbol *pair; 123 struct symbol *pair, *first_pair;
124 bool backwards = true;
123 125
124 sym = rb_entry(nd, struct symbol, rb_node); 126 sym = rb_entry(nd, struct symbol, rb_node);
125 pair = machine__find_kernel_symbol(&kallsyms, type, sym->start, NULL, NULL); 127
128 if (sym->start == sym->end)
129 continue;
130
131 first_pair = machine__find_kernel_symbol(&kallsyms, type, sym->start, NULL, NULL);
132 pair = first_pair;
126 133
127 if (pair && pair->start == sym->start) { 134 if (pair && pair->start == sym->start) {
128next_pair: 135next_pair:
@@ -140,11 +147,13 @@ next_pair:
140 if (llabs(skew) < page_size) 147 if (llabs(skew) < page_size)
141 continue; 148 continue;
142 149
143 pr_debug("%#Lx: diff end addr for %s v: %#Lx k: %#Lx\n", 150 pr_debug("%#" PRIx64 ": diff end addr for %s v: %#" PRIx64 " k: %#" PRIx64 "\n",
144 sym->start, sym->name, sym->end, pair->end); 151 sym->start, sym->name, sym->end, pair->end);
145 } else { 152 } else {
146 struct rb_node *nnd = rb_prev(&pair->rb_node); 153 struct rb_node *nnd;
147 154detour:
155 nnd = backwards ? rb_prev(&pair->rb_node) :
156 rb_next(&pair->rb_node);
148 if (nnd) { 157 if (nnd) {
149 struct symbol *next = rb_entry(nnd, struct symbol, rb_node); 158 struct symbol *next = rb_entry(nnd, struct symbol, rb_node);
150 159
@@ -153,11 +162,18 @@ next_pair:
153 goto next_pair; 162 goto next_pair;
154 } 163 }
155 } 164 }
156 pr_debug("%#Lx: diff name v: %s k: %s\n", 165
166 if (backwards) {
167 backwards = false;
168 pair = first_pair;
169 goto detour;
170 }
171
172 pr_debug("%#" PRIx64 ": diff name v: %s k: %s\n",
157 sym->start, sym->name, pair->name); 173 sym->start, sym->name, pair->name);
158 } 174 }
159 } else 175 } else
160 pr_debug("%#Lx: %s not on kallsyms\n", sym->start, sym->name); 176 pr_debug("%#" PRIx64 ": %s not on kallsyms\n", sym->start, sym->name);
161 177
162 err = -1; 178 err = -1;
163 } 179 }
@@ -196,10 +212,10 @@ next_pair:
196 212
197 if (pair->start == pos->start) { 213 if (pair->start == pos->start) {
198 pair->priv = 1; 214 pair->priv = 1;
199 pr_info(" %Lx-%Lx %Lx %s in kallsyms as", 215 pr_info(" %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s in kallsyms as",
200 pos->start, pos->end, pos->pgoff, pos->dso->name); 216 pos->start, pos->end, pos->pgoff, pos->dso->name);
201 if (pos->pgoff != pair->pgoff || pos->end != pair->end) 217 if (pos->pgoff != pair->pgoff || pos->end != pair->end)
202 pr_info(": \n*%Lx-%Lx %Lx", 218 pr_info(": \n*%" PRIx64 "-%" PRIx64 " %" PRIx64 "",
203 pair->start, pair->end, pair->pgoff); 219 pair->start, pair->end, pair->pgoff);
204 pr_info(" %s\n", pair->dso->name); 220 pr_info(" %s\n", pair->dso->name);
205 pair->priv = 1; 221 pair->priv = 1;
@@ -219,6 +235,371 @@ out:
219 return err; 235 return err;
220} 236}
221 237
238#include "util/cpumap.h"
239#include "util/evsel.h"
240#include <sys/types.h>
241
242static int trace_event__id(const char *evname)
243{
244 char *filename;
245 int err = -1, fd;
246
247 if (asprintf(&filename,
248 "/sys/kernel/debug/tracing/events/syscalls/%s/id",
249 evname) < 0)
250 return -1;
251
252 fd = open(filename, O_RDONLY);
253 if (fd >= 0) {
254 char id[16];
255 if (read(fd, id, sizeof(id)) > 0)
256 err = atoi(id);
257 close(fd);
258 }
259
260 free(filename);
261 return err;
262}
263
264static int test__open_syscall_event(void)
265{
266 int err = -1, fd;
267 struct thread_map *threads;
268 struct perf_evsel *evsel;
269 struct perf_event_attr attr;
270 unsigned int nr_open_calls = 111, i;
271 int id = trace_event__id("sys_enter_open");
272
273 if (id < 0) {
274 pr_debug("is debugfs mounted on /sys/kernel/debug?\n");
275 return -1;
276 }
277
278 threads = thread_map__new(-1, getpid());
279 if (threads == NULL) {
280 pr_debug("thread_map__new\n");
281 return -1;
282 }
283
284 memset(&attr, 0, sizeof(attr));
285 attr.type = PERF_TYPE_TRACEPOINT;
286 attr.config = id;
287 evsel = perf_evsel__new(&attr, 0);
288 if (evsel == NULL) {
289 pr_debug("perf_evsel__new\n");
290 goto out_thread_map_delete;
291 }
292
293 if (perf_evsel__open_per_thread(evsel, threads, false) < 0) {
294 pr_debug("failed to open counter: %s, "
295 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
296 strerror(errno));
297 goto out_evsel_delete;
298 }
299
300 for (i = 0; i < nr_open_calls; ++i) {
301 fd = open("/etc/passwd", O_RDONLY);
302 close(fd);
303 }
304
305 if (perf_evsel__read_on_cpu(evsel, 0, 0) < 0) {
306 pr_debug("perf_evsel__read_on_cpu\n");
307 goto out_close_fd;
308 }
309
310 if (evsel->counts->cpu[0].val != nr_open_calls) {
311 pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls, got %" PRIu64 "\n",
312 nr_open_calls, evsel->counts->cpu[0].val);
313 goto out_close_fd;
314 }
315
316 err = 0;
317out_close_fd:
318 perf_evsel__close_fd(evsel, 1, threads->nr);
319out_evsel_delete:
320 perf_evsel__delete(evsel);
321out_thread_map_delete:
322 thread_map__delete(threads);
323 return err;
324}
325
326#include <sched.h>
327
328static int test__open_syscall_event_on_all_cpus(void)
329{
330 int err = -1, fd, cpu;
331 struct thread_map *threads;
332 struct cpu_map *cpus;
333 struct perf_evsel *evsel;
334 struct perf_event_attr attr;
335 unsigned int nr_open_calls = 111, i;
336 cpu_set_t cpu_set;
337 int id = trace_event__id("sys_enter_open");
338
339 if (id < 0) {
340 pr_debug("is debugfs mounted on /sys/kernel/debug?\n");
341 return -1;
342 }
343
344 threads = thread_map__new(-1, getpid());
345 if (threads == NULL) {
346 pr_debug("thread_map__new\n");
347 return -1;
348 }
349
350 cpus = cpu_map__new(NULL);
351 if (cpus == NULL) {
352 pr_debug("cpu_map__new\n");
353 goto out_thread_map_delete;
354 }
355
356
357 CPU_ZERO(&cpu_set);
358
359 memset(&attr, 0, sizeof(attr));
360 attr.type = PERF_TYPE_TRACEPOINT;
361 attr.config = id;
362 evsel = perf_evsel__new(&attr, 0);
363 if (evsel == NULL) {
364 pr_debug("perf_evsel__new\n");
365 goto out_thread_map_delete;
366 }
367
368 if (perf_evsel__open(evsel, cpus, threads, false) < 0) {
369 pr_debug("failed to open counter: %s, "
370 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
371 strerror(errno));
372 goto out_evsel_delete;
373 }
374
375 for (cpu = 0; cpu < cpus->nr; ++cpu) {
376 unsigned int ncalls = nr_open_calls + cpu;
377 /*
378 * XXX eventually lift this restriction in a way that
379 * keeps perf building on older glibc installations
380 * without CPU_ALLOC. 1024 cpus in 2010 still seems
381 * a reasonable upper limit tho :-)
382 */
383 if (cpus->map[cpu] >= CPU_SETSIZE) {
384 pr_debug("Ignoring CPU %d\n", cpus->map[cpu]);
385 continue;
386 }
387
388 CPU_SET(cpus->map[cpu], &cpu_set);
389 if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) {
390 pr_debug("sched_setaffinity() failed on CPU %d: %s ",
391 cpus->map[cpu],
392 strerror(errno));
393 goto out_close_fd;
394 }
395 for (i = 0; i < ncalls; ++i) {
396 fd = open("/etc/passwd", O_RDONLY);
397 close(fd);
398 }
399 CPU_CLR(cpus->map[cpu], &cpu_set);
400 }
401
402 /*
403 * Here we need to explicitely preallocate the counts, as if
404 * we use the auto allocation it will allocate just for 1 cpu,
405 * as we start by cpu 0.
406 */
407 if (perf_evsel__alloc_counts(evsel, cpus->nr) < 0) {
408 pr_debug("perf_evsel__alloc_counts(ncpus=%d)\n", cpus->nr);
409 goto out_close_fd;
410 }
411
412 err = 0;
413
414 for (cpu = 0; cpu < cpus->nr; ++cpu) {
415 unsigned int expected;
416
417 if (cpus->map[cpu] >= CPU_SETSIZE)
418 continue;
419
420 if (perf_evsel__read_on_cpu(evsel, cpu, 0) < 0) {
421 pr_debug("perf_evsel__read_on_cpu\n");
422 err = -1;
423 break;
424 }
425
426 expected = nr_open_calls + cpu;
427 if (evsel->counts->cpu[cpu].val != expected) {
428 pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls on cpu %d, got %" PRIu64 "\n",
429 expected, cpus->map[cpu], evsel->counts->cpu[cpu].val);
430 err = -1;
431 }
432 }
433
434out_close_fd:
435 perf_evsel__close_fd(evsel, 1, threads->nr);
436out_evsel_delete:
437 perf_evsel__delete(evsel);
438out_thread_map_delete:
439 thread_map__delete(threads);
440 return err;
441}
442
443/*
444 * This test will generate random numbers of calls to some getpid syscalls,
445 * then establish an mmap for a group of events that are created to monitor
446 * the syscalls.
447 *
448 * It will receive the events, using mmap, use its PERF_SAMPLE_ID generated
449 * sample.id field to map back to its respective perf_evsel instance.
450 *
451 * Then it checks if the number of syscalls reported as perf events by
452 * the kernel corresponds to the number of syscalls made.
453 */
454static int test__basic_mmap(void)
455{
456 int err = -1;
457 union perf_event *event;
458 struct thread_map *threads;
459 struct cpu_map *cpus;
460 struct perf_evlist *evlist;
461 struct perf_event_attr attr = {
462 .type = PERF_TYPE_TRACEPOINT,
463 .read_format = PERF_FORMAT_ID,
464 .sample_type = PERF_SAMPLE_ID,
465 .watermark = 0,
466 };
467 cpu_set_t cpu_set;
468 const char *syscall_names[] = { "getsid", "getppid", "getpgrp",
469 "getpgid", };
470 pid_t (*syscalls[])(void) = { (void *)getsid, getppid, getpgrp,
471 (void*)getpgid };
472#define nsyscalls ARRAY_SIZE(syscall_names)
473 int ids[nsyscalls];
474 unsigned int nr_events[nsyscalls],
475 expected_nr_events[nsyscalls], i, j;
476 struct perf_evsel *evsels[nsyscalls], *evsel;
477 int sample_size = __perf_evsel__sample_size(attr.sample_type);
478
479 for (i = 0; i < nsyscalls; ++i) {
480 char name[64];
481
482 snprintf(name, sizeof(name), "sys_enter_%s", syscall_names[i]);
483 ids[i] = trace_event__id(name);
484 if (ids[i] < 0) {
485 pr_debug("Is debugfs mounted on /sys/kernel/debug?\n");
486 return -1;
487 }
488 nr_events[i] = 0;
489 expected_nr_events[i] = random() % 257;
490 }
491
492 threads = thread_map__new(-1, getpid());
493 if (threads == NULL) {
494 pr_debug("thread_map__new\n");
495 return -1;
496 }
497
498 cpus = cpu_map__new(NULL);
499 if (cpus == NULL) {
500 pr_debug("cpu_map__new\n");
501 goto out_free_threads;
502 }
503
504 CPU_ZERO(&cpu_set);
505 CPU_SET(cpus->map[0], &cpu_set);
506 sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
507 if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) {
508 pr_debug("sched_setaffinity() failed on CPU %d: %s ",
509 cpus->map[0], strerror(errno));
510 goto out_free_cpus;
511 }
512
513 evlist = perf_evlist__new(cpus, threads);
514 if (evlist == NULL) {
515 pr_debug("perf_evlist__new\n");
516 goto out_free_cpus;
517 }
518
519 /* anonymous union fields, can't be initialized above */
520 attr.wakeup_events = 1;
521 attr.sample_period = 1;
522
523 for (i = 0; i < nsyscalls; ++i) {
524 attr.config = ids[i];
525 evsels[i] = perf_evsel__new(&attr, i);
526 if (evsels[i] == NULL) {
527 pr_debug("perf_evsel__new\n");
528 goto out_free_evlist;
529 }
530
531 perf_evlist__add(evlist, evsels[i]);
532
533 if (perf_evsel__open(evsels[i], cpus, threads, false) < 0) {
534 pr_debug("failed to open counter: %s, "
535 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
536 strerror(errno));
537 goto out_close_fd;
538 }
539 }
540
541 if (perf_evlist__mmap(evlist, 128, true) < 0) {
542 pr_debug("failed to mmap events: %d (%s)\n", errno,
543 strerror(errno));
544 goto out_close_fd;
545 }
546
547 for (i = 0; i < nsyscalls; ++i)
548 for (j = 0; j < expected_nr_events[i]; ++j) {
549 int foo = syscalls[i]();
550 ++foo;
551 }
552
553 while ((event = perf_evlist__mmap_read(evlist, 0)) != NULL) {
554 struct perf_sample sample;
555
556 if (event->header.type != PERF_RECORD_SAMPLE) {
557 pr_debug("unexpected %s event\n",
558 perf_event__name(event->header.type));
559 goto out_munmap;
560 }
561
562 err = perf_event__parse_sample(event, attr.sample_type, sample_size,
563 false, &sample);
564 if (err) {
565 pr_err("Can't parse sample, err = %d\n", err);
566 goto out_munmap;
567 }
568
569 evsel = perf_evlist__id2evsel(evlist, sample.id);
570 if (evsel == NULL) {
571 pr_debug("event with id %" PRIu64
572 " doesn't map to an evsel\n", sample.id);
573 goto out_munmap;
574 }
575 nr_events[evsel->idx]++;
576 }
577
578 list_for_each_entry(evsel, &evlist->entries, node) {
579 if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) {
580 pr_debug("expected %d %s events, got %d\n",
581 expected_nr_events[evsel->idx],
582 event_name(evsel), nr_events[evsel->idx]);
583 goto out_munmap;
584 }
585 }
586
587 err = 0;
588out_munmap:
589 perf_evlist__munmap(evlist);
590out_close_fd:
591 for (i = 0; i < nsyscalls; ++i)
592 perf_evsel__close_fd(evsels[i], 1, threads->nr);
593out_free_evlist:
594 perf_evlist__delete(evlist);
595out_free_cpus:
596 cpu_map__delete(cpus);
597out_free_threads:
598 thread_map__delete(threads);
599 return err;
600#undef nsyscalls
601}
602
222static struct test { 603static struct test {
223 const char *desc; 604 const char *desc;
224 int (*func)(void); 605 int (*func)(void);
@@ -228,6 +609,18 @@ static struct test {
228 .func = test__vmlinux_matches_kallsyms, 609 .func = test__vmlinux_matches_kallsyms,
229 }, 610 },
230 { 611 {
612 .desc = "detect open syscall event",
613 .func = test__open_syscall_event,
614 },
615 {
616 .desc = "detect open syscall event on all cpus",
617 .func = test__open_syscall_event_on_all_cpus,
618 },
619 {
620 .desc = "read samples using the mmap interface",
621 .func = test__basic_mmap,
622 },
623 {
231 .func = NULL, 624 .func = NULL,
232 }, 625 },
233}; 626};
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 9bcc38f0b706..aa26f4d66d10 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -32,6 +32,10 @@
32#include "util/session.h" 32#include "util/session.h"
33#include "util/svghelper.h" 33#include "util/svghelper.h"
34 34
35#define SUPPORT_OLD_POWER_EVENTS 1
36#define PWR_EVENT_EXIT -1
37
38
35static char const *input_name = "perf.data"; 39static char const *input_name = "perf.data";
36static char const *output_name = "output.svg"; 40static char const *output_name = "output.svg";
37 41
@@ -260,9 +264,6 @@ pid_put_sample(int pid, int type, unsigned int cpu, u64 start, u64 end)
260 c->start_time = start; 264 c->start_time = start;
261 if (p->start_time == 0 || p->start_time > start) 265 if (p->start_time == 0 || p->start_time > start)
262 p->start_time = start; 266 p->start_time = start;
263
264 if (cpu > numcpus)
265 numcpus = cpu;
266} 267}
267 268
268#define MAX_CPUS 4096 269#define MAX_CPUS 4096
@@ -272,19 +273,25 @@ static int cpus_cstate_state[MAX_CPUS];
272static u64 cpus_pstate_start_times[MAX_CPUS]; 273static u64 cpus_pstate_start_times[MAX_CPUS];
273static u64 cpus_pstate_state[MAX_CPUS]; 274static u64 cpus_pstate_state[MAX_CPUS];
274 275
275static int process_comm_event(event_t *event, struct perf_session *session __used) 276static int process_comm_event(union perf_event *event,
277 struct perf_sample *sample __used,
278 struct perf_session *session __used)
276{ 279{
277 pid_set_comm(event->comm.tid, event->comm.comm); 280 pid_set_comm(event->comm.tid, event->comm.comm);
278 return 0; 281 return 0;
279} 282}
280 283
281static int process_fork_event(event_t *event, struct perf_session *session __used) 284static int process_fork_event(union perf_event *event,
285 struct perf_sample *sample __used,
286 struct perf_session *session __used)
282{ 287{
283 pid_fork(event->fork.pid, event->fork.ppid, event->fork.time); 288 pid_fork(event->fork.pid, event->fork.ppid, event->fork.time);
284 return 0; 289 return 0;
285} 290}
286 291
287static int process_exit_event(event_t *event, struct perf_session *session __used) 292static int process_exit_event(union perf_event *event,
293 struct perf_sample *sample __used,
294 struct perf_session *session __used)
288{ 295{
289 pid_exit(event->fork.pid, event->fork.time); 296 pid_exit(event->fork.pid, event->fork.time);
290 return 0; 297 return 0;
@@ -298,12 +305,21 @@ struct trace_entry {
298 int lock_depth; 305 int lock_depth;
299}; 306};
300 307
301struct power_entry { 308#ifdef SUPPORT_OLD_POWER_EVENTS
309static int use_old_power_events;
310struct power_entry_old {
302 struct trace_entry te; 311 struct trace_entry te;
303 u64 type; 312 u64 type;
304 u64 value; 313 u64 value;
305 u64 cpu_id; 314 u64 cpu_id;
306}; 315};
316#endif
317
318struct power_processor_entry {
319 struct trace_entry te;
320 u32 state;
321 u32 cpu_id;
322};
307 323
308#define TASK_COMM_LEN 16 324#define TASK_COMM_LEN 16
309struct wakeup_entry { 325struct wakeup_entry {
@@ -470,48 +486,79 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te)
470} 486}
471 487
472 488
473static int process_sample_event(event_t *event, struct perf_session *session) 489static int process_sample_event(union perf_event *event __used,
490 struct perf_sample *sample,
491 struct perf_evsel *evsel __used,
492 struct perf_session *session)
474{ 493{
475 struct sample_data data;
476 struct trace_entry *te; 494 struct trace_entry *te;
477 495
478 memset(&data, 0, sizeof(data));
479
480 event__parse_sample(event, session->sample_type, &data);
481
482 if (session->sample_type & PERF_SAMPLE_TIME) { 496 if (session->sample_type & PERF_SAMPLE_TIME) {
483 if (!first_time || first_time > data.time) 497 if (!first_time || first_time > sample->time)
484 first_time = data.time; 498 first_time = sample->time;
485 if (last_time < data.time) 499 if (last_time < sample->time)
486 last_time = data.time; 500 last_time = sample->time;
487 } 501 }
488 502
489 te = (void *)data.raw_data; 503 te = (void *)sample->raw_data;
490 if (session->sample_type & PERF_SAMPLE_RAW && data.raw_size > 0) { 504 if (session->sample_type & PERF_SAMPLE_RAW && sample->raw_size > 0) {
491 char *event_str; 505 char *event_str;
492 struct power_entry *pe; 506#ifdef SUPPORT_OLD_POWER_EVENTS
493 507 struct power_entry_old *peo;
494 pe = (void *)te; 508 peo = (void *)te;
495 509#endif
510 /*
511 * FIXME: use evsel, its already mapped from id to perf_evsel,
512 * remove perf_header__find_event infrastructure bits.
513 * Mapping all these "power:cpu_idle" strings to the tracepoint
514 * ID and then just comparing against evsel->attr.config.
515 *
516 * e.g.:
517 *
518 * if (evsel->attr.config == power_cpu_idle_id)
519 */
496 event_str = perf_header__find_event(te->type); 520 event_str = perf_header__find_event(te->type);
497 521
498 if (!event_str) 522 if (!event_str)
499 return 0; 523 return 0;
500 524
501 if (strcmp(event_str, "power:power_start") == 0) 525 if (sample->cpu > numcpus)
502 c_state_start(pe->cpu_id, data.time, pe->value); 526 numcpus = sample->cpu;
527
528 if (strcmp(event_str, "power:cpu_idle") == 0) {
529 struct power_processor_entry *ppe = (void *)te;
530 if (ppe->state == (u32)PWR_EVENT_EXIT)
531 c_state_end(ppe->cpu_id, sample->time);
532 else
533 c_state_start(ppe->cpu_id, sample->time,
534 ppe->state);
535 }
536 else if (strcmp(event_str, "power:cpu_frequency") == 0) {
537 struct power_processor_entry *ppe = (void *)te;
538 p_state_change(ppe->cpu_id, sample->time, ppe->state);
539 }
540
541 else if (strcmp(event_str, "sched:sched_wakeup") == 0)
542 sched_wakeup(sample->cpu, sample->time, sample->pid, te);
503 543
504 if (strcmp(event_str, "power:power_end") == 0) 544 else if (strcmp(event_str, "sched:sched_switch") == 0)
505 c_state_end(pe->cpu_id, data.time); 545 sched_switch(sample->cpu, sample->time, te);
506 546
507 if (strcmp(event_str, "power:power_frequency") == 0) 547#ifdef SUPPORT_OLD_POWER_EVENTS
508 p_state_change(pe->cpu_id, data.time, pe->value); 548 if (use_old_power_events) {
549 if (strcmp(event_str, "power:power_start") == 0)
550 c_state_start(peo->cpu_id, sample->time,
551 peo->value);
509 552
510 if (strcmp(event_str, "sched:sched_wakeup") == 0) 553 else if (strcmp(event_str, "power:power_end") == 0)
511 sched_wakeup(data.cpu, data.time, data.pid, te); 554 c_state_end(sample->cpu, sample->time);
512 555
513 if (strcmp(event_str, "sched:sched_switch") == 0) 556 else if (strcmp(event_str,
514 sched_switch(data.cpu, data.time, te); 557 "power:power_frequency") == 0)
558 p_state_change(peo->cpu_id, sample->time,
559 peo->value);
560 }
561#endif
515 } 562 }
516 return 0; 563 return 0;
517} 564}
@@ -937,7 +984,8 @@ static struct perf_event_ops event_ops = {
937 984
938static int __cmd_timechart(void) 985static int __cmd_timechart(void)
939{ 986{
940 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0, false); 987 struct perf_session *session = perf_session__new(input_name, O_RDONLY,
988 0, false, &event_ops);
941 int ret = -EINVAL; 989 int ret = -EINVAL;
942 990
943 if (session == NULL) 991 if (session == NULL)
@@ -968,7 +1016,8 @@ static const char * const timechart_usage[] = {
968 NULL 1016 NULL
969}; 1017};
970 1018
971static const char *record_args[] = { 1019#ifdef SUPPORT_OLD_POWER_EVENTS
1020static const char * const record_old_args[] = {
972 "record", 1021 "record",
973 "-a", 1022 "-a",
974 "-R", 1023 "-R",
@@ -980,16 +1029,43 @@ static const char *record_args[] = {
980 "-e", "sched:sched_wakeup", 1029 "-e", "sched:sched_wakeup",
981 "-e", "sched:sched_switch", 1030 "-e", "sched:sched_switch",
982}; 1031};
1032#endif
1033
1034static const char * const record_new_args[] = {
1035 "record",
1036 "-a",
1037 "-R",
1038 "-f",
1039 "-c", "1",
1040 "-e", "power:cpu_frequency",
1041 "-e", "power:cpu_idle",
1042 "-e", "sched:sched_wakeup",
1043 "-e", "sched:sched_switch",
1044};
983 1045
984static int __cmd_record(int argc, const char **argv) 1046static int __cmd_record(int argc, const char **argv)
985{ 1047{
986 unsigned int rec_argc, i, j; 1048 unsigned int rec_argc, i, j;
987 const char **rec_argv; 1049 const char **rec_argv;
1050 const char * const *record_args = record_new_args;
1051 unsigned int record_elems = ARRAY_SIZE(record_new_args);
1052
1053#ifdef SUPPORT_OLD_POWER_EVENTS
1054 if (!is_valid_tracepoint("power:cpu_idle") &&
1055 is_valid_tracepoint("power:power_start")) {
1056 use_old_power_events = 1;
1057 record_args = record_old_args;
1058 record_elems = ARRAY_SIZE(record_old_args);
1059 }
1060#endif
988 1061
989 rec_argc = ARRAY_SIZE(record_args) + argc - 1; 1062 rec_argc = record_elems + argc - 1;
990 rec_argv = calloc(rec_argc + 1, sizeof(char *)); 1063 rec_argv = calloc(rec_argc + 1, sizeof(char *));
991 1064
992 for (i = 0; i < ARRAY_SIZE(record_args); i++) 1065 if (rec_argv == NULL)
1066 return -ENOMEM;
1067
1068 for (i = 0; i < record_elems; i++)
993 rec_argv[i] = strdup(record_args[i]); 1069 rec_argv[i] = strdup(record_args[i]);
994 1070
995 for (j = 1; j < (unsigned int)argc; j++, i++) 1071 for (j = 1; j < (unsigned int)argc; j++, i++)
@@ -1018,6 +1094,8 @@ static const struct option options[] = {
1018 OPT_CALLBACK('p', "process", NULL, "process", 1094 OPT_CALLBACK('p', "process", NULL, "process",
1019 "process selector. Pass a pid or process name.", 1095 "process selector. Pass a pid or process name.",
1020 parse_process), 1096 parse_process),
1097 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
1098 "Look for files with symbols relative to this directory"),
1021 OPT_END() 1099 OPT_END()
1022}; 1100};
1023 1101
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index b513e40974f4..f2f3f4937aa2 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -20,15 +20,22 @@
20 20
21#include "perf.h" 21#include "perf.h"
22 22
23#include "util/annotate.h"
24#include "util/cache.h"
23#include "util/color.h" 25#include "util/color.h"
26#include "util/evlist.h"
27#include "util/evsel.h"
24#include "util/session.h" 28#include "util/session.h"
25#include "util/symbol.h" 29#include "util/symbol.h"
26#include "util/thread.h" 30#include "util/thread.h"
31#include "util/thread_map.h"
32#include "util/top.h"
27#include "util/util.h" 33#include "util/util.h"
28#include <linux/rbtree.h> 34#include <linux/rbtree.h>
29#include "util/parse-options.h" 35#include "util/parse-options.h"
30#include "util/parse-events.h" 36#include "util/parse-events.h"
31#include "util/cpumap.h" 37#include "util/cpumap.h"
38#include "util/xyarray.h"
32 39
33#include "util/debug.h" 40#include "util/debug.h"
34 41
@@ -38,11 +45,11 @@
38#include <stdio.h> 45#include <stdio.h>
39#include <termios.h> 46#include <termios.h>
40#include <unistd.h> 47#include <unistd.h>
48#include <inttypes.h>
41 49
42#include <errno.h> 50#include <errno.h>
43#include <time.h> 51#include <time.h>
44#include <sched.h> 52#include <sched.h>
45#include <pthread.h>
46 53
47#include <sys/syscall.h> 54#include <sys/syscall.h>
48#include <sys/ioctl.h> 55#include <sys/ioctl.h>
@@ -55,88 +62,44 @@
55#include <linux/unistd.h> 62#include <linux/unistd.h>
56#include <linux/types.h> 63#include <linux/types.h>
57 64
58static int *fd[MAX_NR_CPUS][MAX_COUNTERS]; 65static struct perf_top top = {
66 .count_filter = 5,
67 .delay_secs = 2,
68 .display_weighted = -1,
69 .target_pid = -1,
70 .target_tid = -1,
71 .active_symbols = LIST_HEAD_INIT(top.active_symbols),
72 .active_symbols_lock = PTHREAD_MUTEX_INITIALIZER,
73 .active_symbols_cond = PTHREAD_COND_INITIALIZER,
74 .freq = 1000, /* 1 KHz */
75};
59 76
60static bool system_wide = false; 77static bool system_wide = false;
61 78
62static int default_interval = 0; 79static bool use_tui, use_stdio;
63 80
64static int count_filter = 5; 81static int default_interval = 0;
65static int print_entries;
66 82
67static int target_pid = -1; 83static bool kptr_restrict_warned;
68static int target_tid = -1; 84static bool vmlinux_warned;
69static pid_t *all_tids = NULL;
70static int thread_num = 0;
71static bool inherit = false; 85static bool inherit = false;
72static int profile_cpu = -1;
73static int nr_cpus = 0;
74static int realtime_prio = 0; 86static int realtime_prio = 0;
75static bool group = false; 87static bool group = false;
76static unsigned int page_size; 88static unsigned int page_size;
77static unsigned int mmap_pages = 16; 89static unsigned int mmap_pages = 128;
78static int freq = 1000; /* 1 KHz */
79 90
80static int delay_secs = 2;
81static bool zero = false;
82static bool dump_symtab = false; 91static bool dump_symtab = false;
83 92
84static bool hide_kernel_symbols = false;
85static bool hide_user_symbols = false;
86static struct winsize winsize; 93static struct winsize winsize;
87 94
88/*
89 * Source
90 */
91
92struct source_line {
93 u64 eip;
94 unsigned long count[MAX_COUNTERS];
95 char *line;
96 struct source_line *next;
97};
98
99static const char *sym_filter = NULL; 95static const char *sym_filter = NULL;
100struct sym_entry *sym_filter_entry = NULL;
101struct sym_entry *sym_filter_entry_sched = NULL; 96struct sym_entry *sym_filter_entry_sched = NULL;
102static int sym_pcnt_filter = 5; 97static int sym_pcnt_filter = 5;
103static int sym_counter = 0;
104static int display_weighted = -1;
105static const char *cpu_list;
106
107/*
108 * Symbols
109 */
110
111struct sym_entry_source {
112 struct source_line *source;
113 struct source_line *lines;
114 struct source_line **lines_tail;
115 pthread_mutex_t lock;
116};
117
118struct sym_entry {
119 struct rb_node rb_node;
120 struct list_head node;
121 unsigned long snap_count;
122 double weight;
123 int skip;
124 u16 name_len;
125 u8 origin;
126 struct map *map;
127 struct sym_entry_source *src;
128 unsigned long count[0];
129};
130 98
131/* 99/*
132 * Source functions 100 * Source functions
133 */ 101 */
134 102
135static inline struct symbol *sym_entry__symbol(struct sym_entry *self)
136{
137 return ((void *)self) + symbol_conf.priv_size;
138}
139
140void get_term_dimensions(struct winsize *ws) 103void get_term_dimensions(struct winsize *ws)
141{ 104{
142 char *s = getenv("LINES"); 105 char *s = getenv("LINES");
@@ -161,10 +124,10 @@ void get_term_dimensions(struct winsize *ws)
161 124
162static void update_print_entries(struct winsize *ws) 125static void update_print_entries(struct winsize *ws)
163{ 126{
164 print_entries = ws->ws_row; 127 top.print_entries = ws->ws_row;
165 128
166 if (print_entries > 9) 129 if (top.print_entries > 9)
167 print_entries -= 9; 130 top.print_entries -= 9;
168} 131}
169 132
170static void sig_winch_handler(int sig __used) 133static void sig_winch_handler(int sig __used)
@@ -176,12 +139,9 @@ static void sig_winch_handler(int sig __used)
176static int parse_source(struct sym_entry *syme) 139static int parse_source(struct sym_entry *syme)
177{ 140{
178 struct symbol *sym; 141 struct symbol *sym;
179 struct sym_entry_source *source; 142 struct annotation *notes;
180 struct map *map; 143 struct map *map;
181 FILE *file; 144 int err = -1;
182 char command[PATH_MAX*2];
183 const char *path;
184 u64 len;
185 145
186 if (!syme) 146 if (!syme)
187 return -1; 147 return -1;
@@ -192,408 +152,137 @@ static int parse_source(struct sym_entry *syme)
192 /* 152 /*
193 * We can't annotate with just /proc/kallsyms 153 * We can't annotate with just /proc/kallsyms
194 */ 154 */
195 if (map->dso->origin == DSO__ORIG_KERNEL) 155 if (map->dso->symtab_type == SYMTAB__KALLSYMS) {
156 pr_err("Can't annotate %s: No vmlinux file was found in the "
157 "path\n", sym->name);
158 sleep(1);
196 return -1; 159 return -1;
197
198 if (syme->src == NULL) {
199 syme->src = zalloc(sizeof(*source));
200 if (syme->src == NULL)
201 return -1;
202 pthread_mutex_init(&syme->src->lock, NULL);
203 } 160 }
204 161
205 source = syme->src; 162 notes = symbol__annotation(sym);
206 163 if (notes->src != NULL) {
207 if (source->lines) { 164 pthread_mutex_lock(&notes->lock);
208 pthread_mutex_lock(&source->lock);
209 goto out_assign; 165 goto out_assign;
210 } 166 }
211 path = map->dso->long_name;
212
213 len = sym->end - sym->start;
214
215 sprintf(command,
216 "objdump --start-address=%#0*Lx --stop-address=%#0*Lx -dS %s",
217 BITS_PER_LONG / 4, map__rip_2objdump(map, sym->start),
218 BITS_PER_LONG / 4, map__rip_2objdump(map, sym->end), path);
219
220 file = popen(command, "r");
221 if (!file)
222 return -1;
223
224 pthread_mutex_lock(&source->lock);
225 source->lines_tail = &source->lines;
226 while (!feof(file)) {
227 struct source_line *src;
228 size_t dummy = 0;
229 char *c, *sep;
230
231 src = malloc(sizeof(struct source_line));
232 assert(src != NULL);
233 memset(src, 0, sizeof(struct source_line));
234
235 if (getline(&src->line, &dummy, file) < 0)
236 break;
237 if (!src->line)
238 break;
239 167
240 c = strchr(src->line, '\n'); 168 pthread_mutex_lock(&notes->lock);
241 if (c)
242 *c = 0;
243 169
244 src->next = NULL; 170 if (symbol__alloc_hist(sym, top.evlist->nr_entries) < 0) {
245 *source->lines_tail = src; 171 pthread_mutex_unlock(&notes->lock);
246 source->lines_tail = &src->next; 172 pr_err("Not enough memory for annotating '%s' symbol!\n",
247 173 sym->name);
248 src->eip = strtoull(src->line, &sep, 16); 174 sleep(1);
249 if (*sep == ':') 175 return err;
250 src->eip = map__objdump_2ip(map, src->eip);
251 else /* this line has no ip info (e.g. source line) */
252 src->eip = 0;
253 } 176 }
254 pclose(file); 177
178 err = symbol__annotate(sym, syme->map, 0);
179 if (err == 0) {
255out_assign: 180out_assign:
256 sym_filter_entry = syme; 181 top.sym_filter_entry = syme;
257 pthread_mutex_unlock(&source->lock); 182 }
258 return 0; 183
184 pthread_mutex_unlock(&notes->lock);
185 return err;
259} 186}
260 187
261static void __zero_source_counters(struct sym_entry *syme) 188static void __zero_source_counters(struct sym_entry *syme)
262{ 189{
263 int i; 190 struct symbol *sym = sym_entry__symbol(syme);
264 struct source_line *line; 191 symbol__annotate_zero_histograms(sym);
265
266 line = syme->src->lines;
267 while (line) {
268 for (i = 0; i < nr_counters; i++)
269 line->count[i] = 0;
270 line = line->next;
271 }
272} 192}
273 193
274static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip) 194static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip)
275{ 195{
276 struct source_line *line; 196 struct annotation *notes;
277 197 struct symbol *sym;
278 if (syme != sym_filter_entry)
279 return;
280 198
281 if (pthread_mutex_trylock(&syme->src->lock)) 199 if (syme != top.sym_filter_entry)
282 return; 200 return;
283 201
284 if (syme->src == NULL || syme->src->source == NULL) 202 sym = sym_entry__symbol(syme);
285 goto out_unlock; 203 notes = symbol__annotation(sym);
286
287 for (line = syme->src->lines; line; line = line->next) {
288 /* skip lines without IP info */
289 if (line->eip == 0)
290 continue;
291 if (line->eip == ip) {
292 line->count[counter]++;
293 break;
294 }
295 if (line->eip > ip)
296 break;
297 }
298out_unlock:
299 pthread_mutex_unlock(&syme->src->lock);
300}
301
302#define PATTERN_LEN (BITS_PER_LONG / 4 + 2)
303
304static void lookup_sym_source(struct sym_entry *syme)
305{
306 struct symbol *symbol = sym_entry__symbol(syme);
307 struct source_line *line;
308 char pattern[PATTERN_LEN + 1];
309
310 sprintf(pattern, "%0*Lx <", BITS_PER_LONG / 4,
311 map__rip_2objdump(syme->map, symbol->start));
312
313 pthread_mutex_lock(&syme->src->lock);
314 for (line = syme->src->lines; line; line = line->next) {
315 if (memcmp(line->line, pattern, PATTERN_LEN) == 0) {
316 syme->src->source = line;
317 break;
318 }
319 }
320 pthread_mutex_unlock(&syme->src->lock);
321}
322 204
323static void show_lines(struct source_line *queue, int count, int total) 205 if (pthread_mutex_trylock(&notes->lock))
324{ 206 return;
325 int i;
326 struct source_line *line;
327 207
328 line = queue; 208 ip = syme->map->map_ip(syme->map, ip);
329 for (i = 0; i < count; i++) { 209 symbol__inc_addr_samples(sym, syme->map, counter, ip);
330 float pcnt = 100.0*(float)line->count[sym_counter]/(float)total;
331 210
332 printf("%8li %4.1f%%\t%s\n", line->count[sym_counter], pcnt, line->line); 211 pthread_mutex_unlock(&notes->lock);
333 line = line->next;
334 }
335} 212}
336 213
337#define TRACE_COUNT 3
338
339static void show_details(struct sym_entry *syme) 214static void show_details(struct sym_entry *syme)
340{ 215{
216 struct annotation *notes;
341 struct symbol *symbol; 217 struct symbol *symbol;
342 struct source_line *line; 218 int more;
343 struct source_line *line_queue = NULL;
344 int displayed = 0;
345 int line_queue_count = 0, total = 0, more = 0;
346 219
347 if (!syme) 220 if (!syme)
348 return; 221 return;
349 222
350 if (!syme->src->source)
351 lookup_sym_source(syme);
352
353 if (!syme->src->source)
354 return;
355
356 symbol = sym_entry__symbol(syme); 223 symbol = sym_entry__symbol(syme);
357 printf("Showing %s for %s\n", event_name(sym_counter), symbol->name); 224 notes = symbol__annotation(symbol);
358 printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter);
359
360 pthread_mutex_lock(&syme->src->lock);
361 line = syme->src->source;
362 while (line) {
363 total += line->count[sym_counter];
364 line = line->next;
365 }
366
367 line = syme->src->source;
368 while (line) {
369 float pcnt = 0.0;
370
371 if (!line_queue_count)
372 line_queue = line;
373 line_queue_count++;
374
375 if (line->count[sym_counter])
376 pcnt = 100.0 * line->count[sym_counter] / (float)total;
377 if (pcnt >= (float)sym_pcnt_filter) {
378 if (displayed <= print_entries)
379 show_lines(line_queue, line_queue_count, total);
380 else more++;
381 displayed += line_queue_count;
382 line_queue_count = 0;
383 line_queue = NULL;
384 } else if (line_queue_count > TRACE_COUNT) {
385 line_queue = line_queue->next;
386 line_queue_count--;
387 }
388
389 line->count[sym_counter] = zero ? 0 : line->count[sym_counter] * 7 / 8;
390 line = line->next;
391 }
392 pthread_mutex_unlock(&syme->src->lock);
393 if (more)
394 printf("%d lines not displayed, maybe increase display entries [e]\n", more);
395}
396
397/*
398 * Symbols will be added here in event__process_sample and will get out
399 * after decayed.
400 */
401static LIST_HEAD(active_symbols);
402static pthread_mutex_t active_symbols_lock = PTHREAD_MUTEX_INITIALIZER;
403
404/*
405 * Ordering weight: count-1 * count-2 * ... / count-n
406 */
407static double sym_weight(const struct sym_entry *sym)
408{
409 double weight = sym->snap_count;
410 int counter;
411 225
412 if (!display_weighted) 226 pthread_mutex_lock(&notes->lock);
413 return weight;
414 227
415 for (counter = 1; counter < nr_counters-1; counter++) 228 if (notes->src == NULL)
416 weight *= sym->count[counter]; 229 goto out_unlock;
417 230
418 weight /= (sym->count[counter] + 1); 231 printf("Showing %s for %s\n", event_name(top.sym_evsel), symbol->name);
232 printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter);
419 233
420 return weight; 234 more = symbol__annotate_printf(symbol, syme->map, top.sym_evsel->idx,
235 0, sym_pcnt_filter, top.print_entries, 4);
236 if (top.zero)
237 symbol__annotate_zero_histogram(symbol, top.sym_evsel->idx);
238 else
239 symbol__annotate_decay_histogram(symbol, top.sym_evsel->idx);
240 if (more != 0)
241 printf("%d lines not displayed, maybe increase display entries [e]\n", more);
242out_unlock:
243 pthread_mutex_unlock(&notes->lock);
421} 244}
422 245
423static long samples;
424static long kernel_samples, us_samples;
425static long exact_samples;
426static long guest_us_samples, guest_kernel_samples;
427static const char CONSOLE_CLEAR[] = ""; 246static const char CONSOLE_CLEAR[] = "";
428 247
429static void __list_insert_active_sym(struct sym_entry *syme) 248static void __list_insert_active_sym(struct sym_entry *syme)
430{ 249{
431 list_add(&syme->node, &active_symbols); 250 list_add(&syme->node, &top.active_symbols);
432}
433
434static void list_remove_active_sym(struct sym_entry *syme)
435{
436 pthread_mutex_lock(&active_symbols_lock);
437 list_del_init(&syme->node);
438 pthread_mutex_unlock(&active_symbols_lock);
439}
440
441static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se)
442{
443 struct rb_node **p = &tree->rb_node;
444 struct rb_node *parent = NULL;
445 struct sym_entry *iter;
446
447 while (*p != NULL) {
448 parent = *p;
449 iter = rb_entry(parent, struct sym_entry, rb_node);
450
451 if (se->weight > iter->weight)
452 p = &(*p)->rb_left;
453 else
454 p = &(*p)->rb_right;
455 }
456
457 rb_link_node(&se->rb_node, parent, p);
458 rb_insert_color(&se->rb_node, tree);
459} 251}
460 252
461static void print_sym_table(void) 253static void print_sym_table(struct perf_session *session)
462{ 254{
463 int printed = 0, j; 255 char bf[160];
464 int counter, snap = !display_weighted ? sym_counter : 0; 256 int printed = 0;
465 float samples_per_sec = samples/delay_secs;
466 float ksamples_per_sec = kernel_samples/delay_secs;
467 float us_samples_per_sec = (us_samples)/delay_secs;
468 float guest_kernel_samples_per_sec = (guest_kernel_samples)/delay_secs;
469 float guest_us_samples_per_sec = (guest_us_samples)/delay_secs;
470 float esamples_percent = (100.0*exact_samples)/samples;
471 float sum_ksamples = 0.0;
472 struct sym_entry *syme, *n;
473 struct rb_root tmp = RB_ROOT;
474 struct rb_node *nd; 257 struct rb_node *nd;
475 int sym_width = 0, dso_width = 0, dso_short_width = 0; 258 struct sym_entry *syme;
259 struct rb_root tmp = RB_ROOT;
476 const int win_width = winsize.ws_col - 1; 260 const int win_width = winsize.ws_col - 1;
477 261 int sym_width, dso_width, dso_short_width;
478 samples = us_samples = kernel_samples = exact_samples = 0; 262 float sum_ksamples = perf_top__decay_samples(&top, &tmp);
479 guest_kernel_samples = guest_us_samples = 0;
480
481 /* Sort the active symbols */
482 pthread_mutex_lock(&active_symbols_lock);
483 syme = list_entry(active_symbols.next, struct sym_entry, node);
484 pthread_mutex_unlock(&active_symbols_lock);
485
486 list_for_each_entry_safe_from(syme, n, &active_symbols, node) {
487 syme->snap_count = syme->count[snap];
488 if (syme->snap_count != 0) {
489
490 if ((hide_user_symbols &&
491 syme->origin == PERF_RECORD_MISC_USER) ||
492 (hide_kernel_symbols &&
493 syme->origin == PERF_RECORD_MISC_KERNEL)) {
494 list_remove_active_sym(syme);
495 continue;
496 }
497 syme->weight = sym_weight(syme);
498 rb_insert_active_sym(&tmp, syme);
499 sum_ksamples += syme->snap_count;
500
501 for (j = 0; j < nr_counters; j++)
502 syme->count[j] = zero ? 0 : syme->count[j] * 7 / 8;
503 } else
504 list_remove_active_sym(syme);
505 }
506 263
507 puts(CONSOLE_CLEAR); 264 puts(CONSOLE_CLEAR);
508 265
509 printf("%-*.*s\n", win_width, win_width, graph_dotted_line); 266 perf_top__header_snprintf(&top, bf, sizeof(bf));
510 if (!perf_guest) { 267 printf("%s\n", bf);
511 printf(" PerfTop:%8.0f irqs/sec kernel:%4.1f%%"
512 " exact: %4.1f%% [",
513 samples_per_sec,
514 100.0 - (100.0 * ((samples_per_sec - ksamples_per_sec) /
515 samples_per_sec)),
516 esamples_percent);
517 } else {
518 printf(" PerfTop:%8.0f irqs/sec kernel:%4.1f%% us:%4.1f%%"
519 " guest kernel:%4.1f%% guest us:%4.1f%%"
520 " exact: %4.1f%% [",
521 samples_per_sec,
522 100.0 - (100.0 * ((samples_per_sec-ksamples_per_sec) /
523 samples_per_sec)),
524 100.0 - (100.0 * ((samples_per_sec-us_samples_per_sec) /
525 samples_per_sec)),
526 100.0 - (100.0 * ((samples_per_sec -
527 guest_kernel_samples_per_sec) /
528 samples_per_sec)),
529 100.0 - (100.0 * ((samples_per_sec -
530 guest_us_samples_per_sec) /
531 samples_per_sec)),
532 esamples_percent);
533 }
534
535 if (nr_counters == 1 || !display_weighted) {
536 printf("%Ld", (u64)attrs[0].sample_period);
537 if (freq)
538 printf("Hz ");
539 else
540 printf(" ");
541 }
542
543 if (!display_weighted)
544 printf("%s", event_name(sym_counter));
545 else for (counter = 0; counter < nr_counters; counter++) {
546 if (counter)
547 printf("/");
548
549 printf("%s", event_name(counter));
550 }
551 268
552 printf( "], "); 269 perf_top__reset_sample_counters(&top);
553
554 if (target_pid != -1)
555 printf(" (target_pid: %d", target_pid);
556 else if (target_tid != -1)
557 printf(" (target_tid: %d", target_tid);
558 else
559 printf(" (all");
560
561 if (profile_cpu != -1)
562 printf(", cpu: %d)\n", profile_cpu);
563 else {
564 if (target_tid != -1)
565 printf(")\n");
566 else
567 printf(", %d CPUs)\n", nr_cpus);
568 }
569 270
570 printf("%-*.*s\n", win_width, win_width, graph_dotted_line); 271 printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
571 272
572 if (sym_filter_entry) { 273 if (session->hists.stats.total_lost != 0) {
573 show_details(sym_filter_entry); 274 color_fprintf(stdout, PERF_COLOR_RED, "WARNING:");
574 return; 275 printf(" LOST %" PRIu64 " events, Check IO/CPU overload\n",
276 session->hists.stats.total_lost);
575 } 277 }
576 278
577 /* 279 if (top.sym_filter_entry) {
578 * Find the longest symbol name that will be displayed 280 show_details(top.sym_filter_entry);
579 */ 281 return;
580 for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
581 syme = rb_entry(nd, struct sym_entry, rb_node);
582 if (++printed > print_entries ||
583 (int)syme->snap_count < count_filter)
584 continue;
585
586 if (syme->map->dso->long_name_len > dso_width)
587 dso_width = syme->map->dso->long_name_len;
588
589 if (syme->map->dso->short_name_len > dso_short_width)
590 dso_short_width = syme->map->dso->short_name_len;
591
592 if (syme->name_len > sym_width)
593 sym_width = syme->name_len;
594 } 282 }
595 283
596 printed = 0; 284 perf_top__find_widths(&top, &tmp, &dso_width, &dso_short_width,
285 &sym_width);
597 286
598 if (sym_width + dso_width > winsize.ws_col - 29) { 287 if (sym_width + dso_width > winsize.ws_col - 29) {
599 dso_width = dso_short_width; 288 dso_width = dso_short_width;
@@ -601,7 +290,7 @@ static void print_sym_table(void)
601 sym_width = winsize.ws_col - dso_width - 29; 290 sym_width = winsize.ws_col - dso_width - 29;
602 } 291 }
603 putchar('\n'); 292 putchar('\n');
604 if (nr_counters == 1) 293 if (top.evlist->nr_entries == 1)
605 printf(" samples pcnt"); 294 printf(" samples pcnt");
606 else 295 else
607 printf(" weight samples pcnt"); 296 printf(" weight samples pcnt");
@@ -610,7 +299,7 @@ static void print_sym_table(void)
610 printf(" RIP "); 299 printf(" RIP ");
611 printf(" %-*.*s DSO\n", sym_width, sym_width, "function"); 300 printf(" %-*.*s DSO\n", sym_width, sym_width, "function");
612 printf(" %s _______ _____", 301 printf(" %s _______ _____",
613 nr_counters == 1 ? " " : "______"); 302 top.evlist->nr_entries == 1 ? " " : "______");
614 if (verbose) 303 if (verbose)
615 printf(" ________________"); 304 printf(" ________________");
616 printf(" %-*.*s", sym_width, sym_width, graph_line); 305 printf(" %-*.*s", sym_width, sym_width, graph_line);
@@ -623,20 +312,21 @@ static void print_sym_table(void)
623 312
624 syme = rb_entry(nd, struct sym_entry, rb_node); 313 syme = rb_entry(nd, struct sym_entry, rb_node);
625 sym = sym_entry__symbol(syme); 314 sym = sym_entry__symbol(syme);
626 if (++printed > print_entries || (int)syme->snap_count < count_filter) 315 if (++printed > top.print_entries ||
316 (int)syme->snap_count < top.count_filter)
627 continue; 317 continue;
628 318
629 pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) / 319 pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) /
630 sum_ksamples)); 320 sum_ksamples));
631 321
632 if (nr_counters == 1 || !display_weighted) 322 if (top.evlist->nr_entries == 1 || !top.display_weighted)
633 printf("%20.2f ", syme->weight); 323 printf("%20.2f ", syme->weight);
634 else 324 else
635 printf("%9.1f %10ld ", syme->weight, syme->snap_count); 325 printf("%9.1f %10ld ", syme->weight, syme->snap_count);
636 326
637 percent_color_fprintf(stdout, "%4.1f%%", pcnt); 327 percent_color_fprintf(stdout, "%4.1f%%", pcnt);
638 if (verbose) 328 if (verbose)
639 printf(" %016llx", sym->start); 329 printf(" %016" PRIx64, sym->start);
640 printf(" %-*.*s", sym_width, sym_width, sym->name); 330 printf(" %-*.*s", sym_width, sym_width, sym->name);
641 printf(" %-*.*s\n", dso_width, dso_width, 331 printf(" %-*.*s\n", dso_width, dso_width,
642 dso_width >= syme->map->dso->long_name_len ? 332 dso_width >= syme->map->dso->long_name_len ?
@@ -688,10 +378,8 @@ static void prompt_symbol(struct sym_entry **target, const char *msg)
688 378
689 /* zero counters of active symbol */ 379 /* zero counters of active symbol */
690 if (syme) { 380 if (syme) {
691 pthread_mutex_lock(&syme->src->lock);
692 __zero_source_counters(syme); 381 __zero_source_counters(syme);
693 *target = NULL; 382 *target = NULL;
694 pthread_mutex_unlock(&syme->src->lock);
695 } 383 }
696 384
697 fprintf(stdout, "\n%s: ", msg); 385 fprintf(stdout, "\n%s: ", msg);
@@ -702,11 +390,11 @@ static void prompt_symbol(struct sym_entry **target, const char *msg)
702 if (p) 390 if (p)
703 *p = 0; 391 *p = 0;
704 392
705 pthread_mutex_lock(&active_symbols_lock); 393 pthread_mutex_lock(&top.active_symbols_lock);
706 syme = list_entry(active_symbols.next, struct sym_entry, node); 394 syme = list_entry(top.active_symbols.next, struct sym_entry, node);
707 pthread_mutex_unlock(&active_symbols_lock); 395 pthread_mutex_unlock(&top.active_symbols_lock);
708 396
709 list_for_each_entry_safe_from(syme, n, &active_symbols, node) { 397 list_for_each_entry_safe_from(syme, n, &top.active_symbols, node) {
710 struct symbol *sym = sym_entry__symbol(syme); 398 struct symbol *sym = sym_entry__symbol(syme);
711 399
712 if (!strcmp(buf, sym->name)) { 400 if (!strcmp(buf, sym->name)) {
@@ -730,34 +418,34 @@ static void print_mapped_keys(void)
730{ 418{
731 char *name = NULL; 419 char *name = NULL;
732 420
733 if (sym_filter_entry) { 421 if (top.sym_filter_entry) {
734 struct symbol *sym = sym_entry__symbol(sym_filter_entry); 422 struct symbol *sym = sym_entry__symbol(top.sym_filter_entry);
735 name = sym->name; 423 name = sym->name;
736 } 424 }
737 425
738 fprintf(stdout, "\nMapped keys:\n"); 426 fprintf(stdout, "\nMapped keys:\n");
739 fprintf(stdout, "\t[d] display refresh delay. \t(%d)\n", delay_secs); 427 fprintf(stdout, "\t[d] display refresh delay. \t(%d)\n", top.delay_secs);
740 fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", print_entries); 428 fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", top.print_entries);
741 429
742 if (nr_counters > 1) 430 if (top.evlist->nr_entries > 1)
743 fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(sym_counter)); 431 fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(top.sym_evsel));
744 432
745 fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter); 433 fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", top.count_filter);
746 434
747 fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter); 435 fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter);
748 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); 436 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL");
749 fprintf(stdout, "\t[S] stop annotation.\n"); 437 fprintf(stdout, "\t[S] stop annotation.\n");
750 438
751 if (nr_counters > 1) 439 if (top.evlist->nr_entries > 1)
752 fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0); 440 fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", top.display_weighted ? 1 : 0);
753 441
754 fprintf(stdout, 442 fprintf(stdout,
755 "\t[K] hide kernel_symbols symbols. \t(%s)\n", 443 "\t[K] hide kernel_symbols symbols. \t(%s)\n",
756 hide_kernel_symbols ? "yes" : "no"); 444 top.hide_kernel_symbols ? "yes" : "no");
757 fprintf(stdout, 445 fprintf(stdout,
758 "\t[U] hide user symbols. \t(%s)\n", 446 "\t[U] hide user symbols. \t(%s)\n",
759 hide_user_symbols ? "yes" : "no"); 447 top.hide_user_symbols ? "yes" : "no");
760 fprintf(stdout, "\t[z] toggle sample zeroing. \t(%d)\n", zero ? 1 : 0); 448 fprintf(stdout, "\t[z] toggle sample zeroing. \t(%d)\n", top.zero ? 1 : 0);
761 fprintf(stdout, "\t[qQ] quit.\n"); 449 fprintf(stdout, "\t[qQ] quit.\n");
762} 450}
763 451
@@ -778,7 +466,7 @@ static int key_mapped(int c)
778 return 1; 466 return 1;
779 case 'E': 467 case 'E':
780 case 'w': 468 case 'w':
781 return nr_counters > 1 ? 1 : 0; 469 return top.evlist->nr_entries > 1 ? 1 : 0;
782 default: 470 default:
783 break; 471 break;
784 } 472 }
@@ -813,43 +501,50 @@ static void handle_keypress(struct perf_session *session, int c)
813 501
814 switch (c) { 502 switch (c) {
815 case 'd': 503 case 'd':
816 prompt_integer(&delay_secs, "Enter display delay"); 504 prompt_integer(&top.delay_secs, "Enter display delay");
817 if (delay_secs < 1) 505 if (top.delay_secs < 1)
818 delay_secs = 1; 506 top.delay_secs = 1;
819 break; 507 break;
820 case 'e': 508 case 'e':
821 prompt_integer(&print_entries, "Enter display entries (lines)"); 509 prompt_integer(&top.print_entries, "Enter display entries (lines)");
822 if (print_entries == 0) { 510 if (top.print_entries == 0) {
823 sig_winch_handler(SIGWINCH); 511 sig_winch_handler(SIGWINCH);
824 signal(SIGWINCH, sig_winch_handler); 512 signal(SIGWINCH, sig_winch_handler);
825 } else 513 } else
826 signal(SIGWINCH, SIG_DFL); 514 signal(SIGWINCH, SIG_DFL);
827 break; 515 break;
828 case 'E': 516 case 'E':
829 if (nr_counters > 1) { 517 if (top.evlist->nr_entries > 1) {
830 int i; 518 /* Select 0 as the default event: */
519 int counter = 0;
831 520
832 fprintf(stderr, "\nAvailable events:"); 521 fprintf(stderr, "\nAvailable events:");
833 for (i = 0; i < nr_counters; i++)
834 fprintf(stderr, "\n\t%d %s", i, event_name(i));
835 522
836 prompt_integer(&sym_counter, "Enter details event counter"); 523 list_for_each_entry(top.sym_evsel, &top.evlist->entries, node)
524 fprintf(stderr, "\n\t%d %s", top.sym_evsel->idx, event_name(top.sym_evsel));
525
526 prompt_integer(&counter, "Enter details event counter");
837 527
838 if (sym_counter >= nr_counters) { 528 if (counter >= top.evlist->nr_entries) {
839 fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(0)); 529 top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node);
840 sym_counter = 0; 530 fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(top.sym_evsel));
841 sleep(1); 531 sleep(1);
532 break;
842 } 533 }
843 } else sym_counter = 0; 534 list_for_each_entry(top.sym_evsel, &top.evlist->entries, node)
535 if (top.sym_evsel->idx == counter)
536 break;
537 } else
538 top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node);
844 break; 539 break;
845 case 'f': 540 case 'f':
846 prompt_integer(&count_filter, "Enter display event count filter"); 541 prompt_integer(&top.count_filter, "Enter display event count filter");
847 break; 542 break;
848 case 'F': 543 case 'F':
849 prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)"); 544 prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)");
850 break; 545 break;
851 case 'K': 546 case 'K':
852 hide_kernel_symbols = !hide_kernel_symbols; 547 top.hide_kernel_symbols = !top.hide_kernel_symbols;
853 break; 548 break;
854 case 'q': 549 case 'q':
855 case 'Q': 550 case 'Q':
@@ -858,34 +553,50 @@ static void handle_keypress(struct perf_session *session, int c)
858 perf_session__fprintf_dsos(session, stderr); 553 perf_session__fprintf_dsos(session, stderr);
859 exit(0); 554 exit(0);
860 case 's': 555 case 's':
861 prompt_symbol(&sym_filter_entry, "Enter details symbol"); 556 prompt_symbol(&top.sym_filter_entry, "Enter details symbol");
862 break; 557 break;
863 case 'S': 558 case 'S':
864 if (!sym_filter_entry) 559 if (!top.sym_filter_entry)
865 break; 560 break;
866 else { 561 else {
867 struct sym_entry *syme = sym_filter_entry; 562 struct sym_entry *syme = top.sym_filter_entry;
868 563
869 pthread_mutex_lock(&syme->src->lock); 564 top.sym_filter_entry = NULL;
870 sym_filter_entry = NULL;
871 __zero_source_counters(syme); 565 __zero_source_counters(syme);
872 pthread_mutex_unlock(&syme->src->lock);
873 } 566 }
874 break; 567 break;
875 case 'U': 568 case 'U':
876 hide_user_symbols = !hide_user_symbols; 569 top.hide_user_symbols = !top.hide_user_symbols;
877 break; 570 break;
878 case 'w': 571 case 'w':
879 display_weighted = ~display_weighted; 572 top.display_weighted = ~top.display_weighted;
880 break; 573 break;
881 case 'z': 574 case 'z':
882 zero = !zero; 575 top.zero = !top.zero;
883 break; 576 break;
884 default: 577 default:
885 break; 578 break;
886 } 579 }
887} 580}
888 581
582static void *display_thread_tui(void *arg __used)
583{
584 int err = 0;
585 pthread_mutex_lock(&top.active_symbols_lock);
586 while (list_empty(&top.active_symbols)) {
587 err = pthread_cond_wait(&top.active_symbols_cond,
588 &top.active_symbols_lock);
589 if (err)
590 break;
591 }
592 pthread_mutex_unlock(&top.active_symbols_lock);
593 if (!err)
594 perf_top__tui_browser(&top);
595 exit_browser(0);
596 exit(0);
597 return NULL;
598}
599
889static void *display_thread(void *arg __used) 600static void *display_thread(void *arg __used)
890{ 601{
891 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; 602 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
@@ -900,13 +611,13 @@ static void *display_thread(void *arg __used)
900 tc.c_cc[VTIME] = 0; 611 tc.c_cc[VTIME] = 0;
901 612
902repeat: 613repeat:
903 delay_msecs = delay_secs * 1000; 614 delay_msecs = top.delay_secs * 1000;
904 tcsetattr(0, TCSANOW, &tc); 615 tcsetattr(0, TCSANOW, &tc);
905 /* trash return*/ 616 /* trash return*/
906 getc(stdin); 617 getc(stdin);
907 618
908 do { 619 do {
909 print_sym_table(); 620 print_sym_table(session);
910 } while (!poll(&stdin_poll, 1, delay_msecs) == 1); 621 } while (!poll(&stdin_poll, 1, delay_msecs) == 1);
911 622
912 c = getc(stdin); 623 c = getc(stdin);
@@ -921,6 +632,7 @@ repeat:
921/* Tag samples to be skipped. */ 632/* Tag samples to be skipped. */
922static const char *skip_symbols[] = { 633static const char *skip_symbols[] = {
923 "default_idle", 634 "default_idle",
635 "native_safe_halt",
924 "cpu_idle", 636 "cpu_idle",
925 "enter_idle", 637 "enter_idle",
926 "exit_idle", 638 "exit_idle",
@@ -956,9 +668,9 @@ static int symbol_filter(struct map *map, struct symbol *sym)
956 668
957 syme = symbol__priv(sym); 669 syme = symbol__priv(sym);
958 syme->map = map; 670 syme->map = map;
959 syme->src = NULL; 671 symbol__annotate_init(map, sym);
960 672
961 if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) { 673 if (!top.sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) {
962 /* schedule initial sym_filter_entry setup */ 674 /* schedule initial sym_filter_entry setup */
963 sym_filter_entry_sched = syme; 675 sym_filter_entry_sched = syme;
964 sym_filter = NULL; 676 sym_filter = NULL;
@@ -966,48 +678,45 @@ static int symbol_filter(struct map *map, struct symbol *sym)
966 678
967 for (i = 0; skip_symbols[i]; i++) { 679 for (i = 0; skip_symbols[i]; i++) {
968 if (!strcmp(skip_symbols[i], name)) { 680 if (!strcmp(skip_symbols[i], name)) {
969 syme->skip = 1; 681 sym->ignore = true;
970 break; 682 break;
971 } 683 }
972 } 684 }
973 685
974 if (!syme->skip)
975 syme->name_len = strlen(sym->name);
976
977 return 0; 686 return 0;
978} 687}
979 688
980static void event__process_sample(const event_t *self, 689static void perf_event__process_sample(const union perf_event *event,
981 struct perf_session *session, int counter) 690 struct perf_sample *sample,
691 struct perf_session *session)
982{ 692{
983 u64 ip = self->ip.ip; 693 u64 ip = event->ip.ip;
984 struct sym_entry *syme; 694 struct sym_entry *syme;
985 struct addr_location al; 695 struct addr_location al;
986 struct sample_data data;
987 struct machine *machine; 696 struct machine *machine;
988 u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 697 u8 origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
989 698
990 ++samples; 699 ++top.samples;
991 700
992 switch (origin) { 701 switch (origin) {
993 case PERF_RECORD_MISC_USER: 702 case PERF_RECORD_MISC_USER:
994 ++us_samples; 703 ++top.us_samples;
995 if (hide_user_symbols) 704 if (top.hide_user_symbols)
996 return; 705 return;
997 machine = perf_session__find_host_machine(session); 706 machine = perf_session__find_host_machine(session);
998 break; 707 break;
999 case PERF_RECORD_MISC_KERNEL: 708 case PERF_RECORD_MISC_KERNEL:
1000 ++kernel_samples; 709 ++top.kernel_samples;
1001 if (hide_kernel_symbols) 710 if (top.hide_kernel_symbols)
1002 return; 711 return;
1003 machine = perf_session__find_host_machine(session); 712 machine = perf_session__find_host_machine(session);
1004 break; 713 break;
1005 case PERF_RECORD_MISC_GUEST_KERNEL: 714 case PERF_RECORD_MISC_GUEST_KERNEL:
1006 ++guest_kernel_samples; 715 ++top.guest_kernel_samples;
1007 machine = perf_session__find_machine(session, self->ip.pid); 716 machine = perf_session__find_machine(session, event->ip.pid);
1008 break; 717 break;
1009 case PERF_RECORD_MISC_GUEST_USER: 718 case PERF_RECORD_MISC_GUEST_USER:
1010 ++guest_us_samples; 719 ++top.guest_us_samples;
1011 /* 720 /*
1012 * TODO: we don't process guest user from host side 721 * TODO: we don't process guest user from host side
1013 * except simple counting. 722 * except simple counting.
@@ -1019,19 +728,34 @@ static void event__process_sample(const event_t *self,
1019 728
1020 if (!machine && perf_guest) { 729 if (!machine && perf_guest) {
1021 pr_err("Can't find guest [%d]'s kernel information\n", 730 pr_err("Can't find guest [%d]'s kernel information\n",
1022 self->ip.pid); 731 event->ip.pid);
1023 return; 732 return;
1024 } 733 }
1025 734
1026 if (self->header.misc & PERF_RECORD_MISC_EXACT_IP) 735 if (event->header.misc & PERF_RECORD_MISC_EXACT_IP)
1027 exact_samples++; 736 top.exact_samples++;
1028 737
1029 if (event__preprocess_sample(self, session, &al, &data, 738 if (perf_event__preprocess_sample(event, session, &al, sample,
1030 symbol_filter) < 0 || 739 symbol_filter) < 0 ||
1031 al.filtered) 740 al.filtered)
1032 return; 741 return;
1033 742
743 if (!kptr_restrict_warned &&
744 symbol_conf.kptr_restrict &&
745 al.cpumode == PERF_RECORD_MISC_KERNEL) {
746 ui__warning(
747"Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
748"Check /proc/sys/kernel/kptr_restrict.\n\n"
749"Kernel%s samples will not be resolved.\n",
750 !RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION]) ?
751 " modules" : "");
752 if (use_browser <= 0)
753 sleep(5);
754 kptr_restrict_warned = true;
755 }
756
1034 if (al.sym == NULL) { 757 if (al.sym == NULL) {
758 const char *msg = "Kernel samples will not be resolved.\n";
1035 /* 759 /*
1036 * As we do lazy loading of symtabs we only will know if the 760 * As we do lazy loading of symtabs we only will know if the
1037 * specified vmlinux file is invalid when we actually have a 761 * specified vmlinux file is invalid when we actually have a
@@ -1043,11 +767,20 @@ static void event__process_sample(const event_t *self,
1043 * --hide-kernel-symbols, even if the user specifies an 767 * --hide-kernel-symbols, even if the user specifies an
1044 * invalid --vmlinux ;-) 768 * invalid --vmlinux ;-)
1045 */ 769 */
1046 if (al.map == machine->vmlinux_maps[MAP__FUNCTION] && 770 if (!kptr_restrict_warned && !vmlinux_warned &&
771 al.map == machine->vmlinux_maps[MAP__FUNCTION] &&
1047 RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) { 772 RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) {
1048 pr_err("The %s file can't be used\n", 773 if (symbol_conf.vmlinux_name) {
1049 symbol_conf.vmlinux_name); 774 ui__warning("The %s file can't be used.\n%s",
1050 exit(1); 775 symbol_conf.vmlinux_name, msg);
776 } else {
777 ui__warning("A vmlinux file was not found.\n%s",
778 msg);
779 }
780
781 if (use_browser <= 0)
782 sleep(5);
783 vmlinux_warned = true;
1051 } 784 }
1052 785
1053 return; 786 return;
@@ -1055,13 +788,13 @@ static void event__process_sample(const event_t *self,
1055 788
1056 /* let's see, whether we need to install initial sym_filter_entry */ 789 /* let's see, whether we need to install initial sym_filter_entry */
1057 if (sym_filter_entry_sched) { 790 if (sym_filter_entry_sched) {
1058 sym_filter_entry = sym_filter_entry_sched; 791 top.sym_filter_entry = sym_filter_entry_sched;
1059 sym_filter_entry_sched = NULL; 792 sym_filter_entry_sched = NULL;
1060 if (parse_source(sym_filter_entry) < 0) { 793 if (parse_source(top.sym_filter_entry) < 0) {
1061 struct symbol *sym = sym_entry__symbol(sym_filter_entry); 794 struct symbol *sym = sym_entry__symbol(top.sym_filter_entry);
1062 795
1063 pr_err("Can't annotate %s", sym->name); 796 pr_err("Can't annotate %s", sym->name);
1064 if (sym_filter_entry->map->dso->origin == DSO__ORIG_KERNEL) { 797 if (top.sym_filter_entry->map->dso->symtab_type == SYMTAB__KALLSYMS) {
1065 pr_err(": No vmlinux file was found in the path:\n"); 798 pr_err(": No vmlinux file was found in the path:\n");
1066 machine__fprintf_vmlinux_path(machine, stderr); 799 machine__fprintf_vmlinux_path(machine, stderr);
1067 } else 800 } else
@@ -1071,226 +804,158 @@ static void event__process_sample(const event_t *self,
1071 } 804 }
1072 805
1073 syme = symbol__priv(al.sym); 806 syme = symbol__priv(al.sym);
1074 if (!syme->skip) { 807 if (!al.sym->ignore) {
1075 syme->count[counter]++; 808 struct perf_evsel *evsel;
1076 syme->origin = origin; 809
1077 record_precise_ip(syme, counter, ip); 810 evsel = perf_evlist__id2evsel(top.evlist, sample->id);
1078 pthread_mutex_lock(&active_symbols_lock); 811 assert(evsel != NULL);
1079 if (list_empty(&syme->node) || !syme->node.next) 812 syme->count[evsel->idx]++;
813 record_precise_ip(syme, evsel->idx, ip);
814 pthread_mutex_lock(&top.active_symbols_lock);
815 if (list_empty(&syme->node) || !syme->node.next) {
816 static bool first = true;
1080 __list_insert_active_sym(syme); 817 __list_insert_active_sym(syme);
1081 pthread_mutex_unlock(&active_symbols_lock); 818 if (first) {
819 pthread_cond_broadcast(&top.active_symbols_cond);
820 first = false;
821 }
822 }
823 pthread_mutex_unlock(&top.active_symbols_lock);
1082 } 824 }
1083} 825}
1084 826
1085struct mmap_data { 827static void perf_session__mmap_read_idx(struct perf_session *self, int idx)
1086 int counter;
1087 void *base;
1088 int mask;
1089 unsigned int prev;
1090};
1091
1092static unsigned int mmap_read_head(struct mmap_data *md)
1093{
1094 struct perf_event_mmap_page *pc = md->base;
1095 int head;
1096
1097 head = pc->data_head;
1098 rmb();
1099
1100 return head;
1101}
1102
1103static void perf_session__mmap_read_counter(struct perf_session *self,
1104 struct mmap_data *md)
1105{ 828{
1106 unsigned int head = mmap_read_head(md); 829 struct perf_sample sample;
1107 unsigned int old = md->prev; 830 union perf_event *event;
1108 unsigned char *data = md->base + page_size; 831 int ret;
1109 int diff;
1110
1111 /*
1112 * If we're further behind than half the buffer, there's a chance
1113 * the writer will bite our tail and mess up the samples under us.
1114 *
1115 * If we somehow ended up ahead of the head, we got messed up.
1116 *
1117 * In either case, truncate and restart at head.
1118 */
1119 diff = head - old;
1120 if (diff > md->mask / 2 || diff < 0) {
1121 fprintf(stderr, "WARNING: failed to keep up with mmap data.\n");
1122
1123 /*
1124 * head points to a known good entry, start there.
1125 */
1126 old = head;
1127 }
1128
1129 for (; old != head;) {
1130 event_t *event = (event_t *)&data[old & md->mask];
1131
1132 event_t event_copy;
1133
1134 size_t size = event->header.size;
1135 832
1136 /* 833 while ((event = perf_evlist__mmap_read(top.evlist, idx)) != NULL) {
1137 * Event straddles the mmap boundary -- header should always 834 ret = perf_session__parse_sample(self, event, &sample);
1138 * be inside due to u64 alignment of output. 835 if (ret) {
1139 */ 836 pr_err("Can't parse sample, err = %d\n", ret);
1140 if ((old & md->mask) + size != ((old + size) & md->mask)) { 837 continue;
1141 unsigned int offset = old;
1142 unsigned int len = min(sizeof(*event), size), cpy;
1143 void *dst = &event_copy;
1144
1145 do {
1146 cpy = min(md->mask + 1 - (offset & md->mask), len);
1147 memcpy(dst, &data[offset & md->mask], cpy);
1148 offset += cpy;
1149 dst += cpy;
1150 len -= cpy;
1151 } while (len);
1152
1153 event = &event_copy;
1154 } 838 }
1155 839
1156 if (event->header.type == PERF_RECORD_SAMPLE) 840 if (event->header.type == PERF_RECORD_SAMPLE)
1157 event__process_sample(event, self, md->counter); 841 perf_event__process_sample(event, &sample, self);
1158 else 842 else
1159 event__process(event, self); 843 perf_event__process(event, &sample, self);
1160 old += size;
1161 } 844 }
1162
1163 md->prev = old;
1164} 845}
1165 846
1166static struct pollfd *event_array;
1167static struct mmap_data *mmap_array[MAX_NR_CPUS][MAX_COUNTERS];
1168
1169static void perf_session__mmap_read(struct perf_session *self) 847static void perf_session__mmap_read(struct perf_session *self)
1170{ 848{
1171 int i, counter, thread_index; 849 int i;
1172
1173 for (i = 0; i < nr_cpus; i++) {
1174 for (counter = 0; counter < nr_counters; counter++)
1175 for (thread_index = 0;
1176 thread_index < thread_num;
1177 thread_index++) {
1178 perf_session__mmap_read_counter(self,
1179 &mmap_array[i][counter][thread_index]);
1180 }
1181 }
1182}
1183 850
1184int nr_poll; 851 for (i = 0; i < top.evlist->nr_mmaps; i++)
1185int group_fd; 852 perf_session__mmap_read_idx(self, i);
853}
1186 854
1187static void start_counter(int i, int counter) 855static void start_counters(struct perf_evlist *evlist)
1188{ 856{
1189 struct perf_event_attr *attr; 857 struct perf_evsel *counter;
1190 int cpu;
1191 int thread_index;
1192
1193 cpu = profile_cpu;
1194 if (target_tid == -1 && profile_cpu == -1)
1195 cpu = cpumap[i];
1196 858
1197 attr = attrs + counter; 859 list_for_each_entry(counter, &evlist->entries, node) {
860 struct perf_event_attr *attr = &counter->attr;
1198 861
1199 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; 862 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
1200 863
1201 if (freq) { 864 if (top.freq) {
1202 attr->sample_type |= PERF_SAMPLE_PERIOD; 865 attr->sample_type |= PERF_SAMPLE_PERIOD;
1203 attr->freq = 1; 866 attr->freq = 1;
1204 attr->sample_freq = freq; 867 attr->sample_freq = top.freq;
1205 } 868 }
1206 869
1207 attr->inherit = (cpu < 0) && inherit; 870 if (evlist->nr_entries > 1) {
1208 attr->mmap = 1; 871 attr->sample_type |= PERF_SAMPLE_ID;
872 attr->read_format |= PERF_FORMAT_ID;
873 }
1209 874
1210 for (thread_index = 0; thread_index < thread_num; thread_index++) { 875 attr->mmap = 1;
876 attr->inherit = inherit;
1211try_again: 877try_again:
1212 fd[i][counter][thread_index] = sys_perf_event_open(attr, 878 if (perf_evsel__open(counter, top.evlist->cpus,
1213 all_tids[thread_index], cpu, group_fd, 0); 879 top.evlist->threads, group) < 0) {
1214
1215 if (fd[i][counter][thread_index] < 0) {
1216 int err = errno; 880 int err = errno;
1217 881
1218 if (err == EPERM || err == EACCES) 882 if (err == EPERM || err == EACCES) {
1219 die("No permission - are you root?\n"); 883 ui__warning_paranoid();
884 goto out_err;
885 }
1220 /* 886 /*
1221 * If it's cycles then fall back to hrtimer 887 * If it's cycles then fall back to hrtimer
1222 * based cpu-clock-tick sw counter, which 888 * based cpu-clock-tick sw counter, which
1223 * is always available even if no PMU support: 889 * is always available even if no PMU support:
1224 */ 890 */
1225 if (attr->type == PERF_TYPE_HARDWARE 891 if (attr->type == PERF_TYPE_HARDWARE &&
1226 && attr->config == PERF_COUNT_HW_CPU_CYCLES) { 892 attr->config == PERF_COUNT_HW_CPU_CYCLES) {
1227
1228 if (verbose) 893 if (verbose)
1229 warning(" ... trying to fall back to cpu-clock-ticks\n"); 894 ui__warning("Cycles event not supported,\n"
895 "trying to fall back to cpu-clock-ticks\n");
1230 896
1231 attr->type = PERF_TYPE_SOFTWARE; 897 attr->type = PERF_TYPE_SOFTWARE;
1232 attr->config = PERF_COUNT_SW_CPU_CLOCK; 898 attr->config = PERF_COUNT_SW_CPU_CLOCK;
1233 goto try_again; 899 goto try_again;
1234 } 900 }
1235 printf("\n"); 901
1236 error("perfcounter syscall returned with %d (%s)\n", 902 if (err == ENOENT) {
1237 fd[i][counter][thread_index], strerror(err)); 903 ui__warning("The %s event is not supported.\n",
1238 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); 904 event_name(counter));
1239 exit(-1); 905 goto out_err;
906 }
907
908 ui__warning("The sys_perf_event_open() syscall "
909 "returned with %d (%s). /bin/dmesg "
910 "may provide additional information.\n"
911 "No CONFIG_PERF_EVENTS=y kernel support "
912 "configured?\n", err, strerror(err));
913 goto out_err;
1240 } 914 }
1241 assert(fd[i][counter][thread_index] >= 0); 915 }
1242 fcntl(fd[i][counter][thread_index], F_SETFL, O_NONBLOCK);
1243 916
1244 /* 917 if (perf_evlist__mmap(evlist, mmap_pages, false) < 0) {
1245 * First counter acts as the group leader: 918 ui__warning("Failed to mmap with %d (%s)\n",
1246 */ 919 errno, strerror(errno));
1247 if (group && group_fd == -1) 920 goto out_err;
1248 group_fd = fd[i][counter][thread_index];
1249
1250 event_array[nr_poll].fd = fd[i][counter][thread_index];
1251 event_array[nr_poll].events = POLLIN;
1252 nr_poll++;
1253
1254 mmap_array[i][counter][thread_index].counter = counter;
1255 mmap_array[i][counter][thread_index].prev = 0;
1256 mmap_array[i][counter][thread_index].mask = mmap_pages*page_size - 1;
1257 mmap_array[i][counter][thread_index].base = mmap(NULL, (mmap_pages+1)*page_size,
1258 PROT_READ, MAP_SHARED, fd[i][counter][thread_index], 0);
1259 if (mmap_array[i][counter][thread_index].base == MAP_FAILED)
1260 die("failed to mmap with %d (%s)\n", errno, strerror(errno));
1261 } 921 }
922
923 return;
924
925out_err:
926 exit_browser(0);
927 exit(0);
1262} 928}
1263 929
1264static int __cmd_top(void) 930static int __cmd_top(void)
1265{ 931{
1266 pthread_t thread; 932 pthread_t thread;
1267 int i, counter; 933 int ret __used;
1268 int ret;
1269 /* 934 /*
1270 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this 935 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this
1271 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now. 936 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now.
1272 */ 937 */
1273 struct perf_session *session = perf_session__new(NULL, O_WRONLY, false, false); 938 struct perf_session *session = perf_session__new(NULL, O_WRONLY, false, false, NULL);
1274 if (session == NULL) 939 if (session == NULL)
1275 return -ENOMEM; 940 return -ENOMEM;
1276 941
1277 if (target_tid != -1) 942 if (top.target_tid != -1)
1278 event__synthesize_thread(target_tid, event__process, session); 943 perf_event__synthesize_thread_map(top.evlist->threads,
944 perf_event__process, session);
1279 else 945 else
1280 event__synthesize_threads(event__process, session); 946 perf_event__synthesize_threads(perf_event__process, session);
1281 947
1282 for (i = 0; i < nr_cpus; i++) { 948 start_counters(top.evlist);
1283 group_fd = -1; 949 session->evlist = top.evlist;
1284 for (counter = 0; counter < nr_counters; counter++) 950 perf_session__update_sample_type(session);
1285 start_counter(i, counter);
1286 }
1287 951
1288 /* Wait for a minimal set of events before starting the snapshot */ 952 /* Wait for a minimal set of events before starting the snapshot */
1289 poll(&event_array[0], nr_poll, 100); 953 poll(top.evlist->pollfd, top.evlist->nr_fds, 100);
1290 954
1291 perf_session__mmap_read(session); 955 perf_session__mmap_read(session);
1292 956
1293 if (pthread_create(&thread, NULL, display_thread, session)) { 957 if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui :
958 display_thread), session)) {
1294 printf("Could not create display thread.\n"); 959 printf("Could not create display thread.\n");
1295 exit(-1); 960 exit(-1);
1296 } 961 }
@@ -1306,12 +971,12 @@ static int __cmd_top(void)
1306 } 971 }
1307 972
1308 while (1) { 973 while (1) {
1309 int hits = samples; 974 u64 hits = top.samples;
1310 975
1311 perf_session__mmap_read(session); 976 perf_session__mmap_read(session);
1312 977
1313 if (hits == samples) 978 if (hits == top.samples)
1314 ret = poll(event_array, nr_poll, 100); 979 ret = poll(top.evlist->pollfd, top.evlist->nr_fds, 100);
1315 } 980 }
1316 981
1317 return 0; 982 return 0;
@@ -1323,31 +988,31 @@ static const char * const top_usage[] = {
1323}; 988};
1324 989
1325static const struct option options[] = { 990static const struct option options[] = {
1326 OPT_CALLBACK('e', "event", NULL, "event", 991 OPT_CALLBACK('e', "event", &top.evlist, "event",
1327 "event selector. use 'perf list' to list available events", 992 "event selector. use 'perf list' to list available events",
1328 parse_events), 993 parse_events),
1329 OPT_INTEGER('c', "count", &default_interval, 994 OPT_INTEGER('c', "count", &default_interval,
1330 "event period to sample"), 995 "event period to sample"),
1331 OPT_INTEGER('p', "pid", &target_pid, 996 OPT_INTEGER('p', "pid", &top.target_pid,
1332 "profile events on existing process id"), 997 "profile events on existing process id"),
1333 OPT_INTEGER('t', "tid", &target_tid, 998 OPT_INTEGER('t', "tid", &top.target_tid,
1334 "profile events on existing thread id"), 999 "profile events on existing thread id"),
1335 OPT_BOOLEAN('a', "all-cpus", &system_wide, 1000 OPT_BOOLEAN('a', "all-cpus", &system_wide,
1336 "system-wide collection from all CPUs"), 1001 "system-wide collection from all CPUs"),
1337 OPT_STRING('C', "cpu", &cpu_list, "cpu", 1002 OPT_STRING('C', "cpu", &top.cpu_list, "cpu",
1338 "list of cpus to monitor"), 1003 "list of cpus to monitor"),
1339 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 1004 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
1340 "file", "vmlinux pathname"), 1005 "file", "vmlinux pathname"),
1341 OPT_BOOLEAN('K', "hide_kernel_symbols", &hide_kernel_symbols, 1006 OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols,
1342 "hide kernel symbols"), 1007 "hide kernel symbols"),
1343 OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"), 1008 OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"),
1344 OPT_INTEGER('r', "realtime", &realtime_prio, 1009 OPT_INTEGER('r', "realtime", &realtime_prio,
1345 "collect data with this RT SCHED_FIFO priority"), 1010 "collect data with this RT SCHED_FIFO priority"),
1346 OPT_INTEGER('d', "delay", &delay_secs, 1011 OPT_INTEGER('d', "delay", &top.delay_secs,
1347 "number of seconds to delay between refreshes"), 1012 "number of seconds to delay between refreshes"),
1348 OPT_BOOLEAN('D', "dump-symtab", &dump_symtab, 1013 OPT_BOOLEAN('D', "dump-symtab", &dump_symtab,
1349 "dump the symbol table used for profiling"), 1014 "dump the symbol table used for profiling"),
1350 OPT_INTEGER('f', "count-filter", &count_filter, 1015 OPT_INTEGER('f', "count-filter", &top.count_filter,
1351 "only display functions with more events than this"), 1016 "only display functions with more events than this"),
1352 OPT_BOOLEAN('g', "group", &group, 1017 OPT_BOOLEAN('g', "group", &group,
1353 "put the counters into a counter group"), 1018 "put the counters into a counter group"),
@@ -1355,14 +1020,16 @@ static const struct option options[] = {
1355 "child tasks inherit counters"), 1020 "child tasks inherit counters"),
1356 OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name", 1021 OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name",
1357 "symbol to annotate"), 1022 "symbol to annotate"),
1358 OPT_BOOLEAN('z', "zero", &zero, 1023 OPT_BOOLEAN('z', "zero", &top.zero,
1359 "zero history across updates"), 1024 "zero history across updates"),
1360 OPT_INTEGER('F', "freq", &freq, 1025 OPT_INTEGER('F', "freq", &top.freq,
1361 "profile at this frequency"), 1026 "profile at this frequency"),
1362 OPT_INTEGER('E', "entries", &print_entries, 1027 OPT_INTEGER('E', "entries", &top.print_entries,
1363 "display this many functions"), 1028 "display this many functions"),
1364 OPT_BOOLEAN('U', "hide_user_symbols", &hide_user_symbols, 1029 OPT_BOOLEAN('U', "hide_user_symbols", &top.hide_user_symbols,
1365 "hide user symbols"), 1030 "hide user symbols"),
1031 OPT_BOOLEAN(0, "tui", &use_tui, "Use the TUI interface"),
1032 OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"),
1366 OPT_INCR('v', "verbose", &verbose, 1033 OPT_INCR('v', "verbose", &verbose,
1367 "be more verbose (show counter open errors, etc)"), 1034 "be more verbose (show counter open errors, etc)"),
1368 OPT_END() 1035 OPT_END()
@@ -1370,8 +1037,12 @@ static const struct option options[] = {
1370 1037
1371int cmd_top(int argc, const char **argv, const char *prefix __used) 1038int cmd_top(int argc, const char **argv, const char *prefix __used)
1372{ 1039{
1373 int counter; 1040 struct perf_evsel *pos;
1374 int i,j; 1041 int status = -ENOMEM;
1042
1043 top.evlist = perf_evlist__new(NULL, NULL);
1044 if (top.evlist == NULL)
1045 return -ENOMEM;
1375 1046
1376 page_size = sysconf(_SC_PAGE_SIZE); 1047 page_size = sysconf(_SC_PAGE_SIZE);
1377 1048
@@ -1379,92 +1050,90 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1379 if (argc) 1050 if (argc)
1380 usage_with_options(top_usage, options); 1051 usage_with_options(top_usage, options);
1381 1052
1382 if (target_pid != -1) { 1053 /*
1383 target_tid = target_pid; 1054 * XXX For now start disabled, only using TUI if explicitely asked for.
1384 thread_num = find_all_tid(target_pid, &all_tids); 1055 * Change that when handle_keys equivalent gets written, live annotation
1385 if (thread_num <= 0) { 1056 * done, etc.
1386 fprintf(stderr, "Can't find all threads of pid %d\n", 1057 */
1387 target_pid); 1058 use_browser = 0;
1388 usage_with_options(top_usage, options);
1389 }
1390 } else {
1391 all_tids=malloc(sizeof(pid_t));
1392 if (!all_tids)
1393 return -ENOMEM;
1394 1059
1395 all_tids[0] = target_tid; 1060 if (use_stdio)
1396 thread_num = 1; 1061 use_browser = 0;
1397 } 1062 else if (use_tui)
1063 use_browser = 1;
1398 1064
1399 for (i = 0; i < MAX_NR_CPUS; i++) { 1065 setup_browser(false);
1400 for (j = 0; j < MAX_COUNTERS; j++) {
1401 fd[i][j] = malloc(sizeof(int)*thread_num);
1402 mmap_array[i][j] = zalloc(
1403 sizeof(struct mmap_data)*thread_num);
1404 if (!fd[i][j] || !mmap_array[i][j])
1405 return -ENOMEM;
1406 }
1407 }
1408 event_array = malloc(
1409 sizeof(struct pollfd)*MAX_NR_CPUS*MAX_COUNTERS*thread_num);
1410 if (!event_array)
1411 return -ENOMEM;
1412 1066
1413 /* CPU and PID are mutually exclusive */ 1067 /* CPU and PID are mutually exclusive */
1414 if (target_tid > 0 && cpu_list) { 1068 if (top.target_tid > 0 && top.cpu_list) {
1415 printf("WARNING: PID switch overriding CPU\n"); 1069 printf("WARNING: PID switch overriding CPU\n");
1416 sleep(1); 1070 sleep(1);
1417 cpu_list = NULL; 1071 top.cpu_list = NULL;
1418 } 1072 }
1419 1073
1420 if (!nr_counters) 1074 if (top.target_pid != -1)
1421 nr_counters = 1; 1075 top.target_tid = top.target_pid;
1422 1076
1423 symbol_conf.priv_size = (sizeof(struct sym_entry) + 1077 if (perf_evlist__create_maps(top.evlist, top.target_pid,
1424 (nr_counters + 1) * sizeof(unsigned long)); 1078 top.target_tid, top.cpu_list) < 0)
1079 usage_with_options(top_usage, options);
1425 1080
1426 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); 1081 if (!top.evlist->nr_entries &&
1427 if (symbol__init() < 0) 1082 perf_evlist__add_default(top.evlist) < 0) {
1428 return -1; 1083 pr_err("Not enough memory for event selector list\n");
1084 return -ENOMEM;
1085 }
1429 1086
1430 if (delay_secs < 1) 1087 if (top.delay_secs < 1)
1431 delay_secs = 1; 1088 top.delay_secs = 1;
1432 1089
1433 /* 1090 /*
1434 * User specified count overrides default frequency. 1091 * User specified count overrides default frequency.
1435 */ 1092 */
1436 if (default_interval) 1093 if (default_interval)
1437 freq = 0; 1094 top.freq = 0;
1438 else if (freq) { 1095 else if (top.freq) {
1439 default_interval = freq; 1096 default_interval = top.freq;
1440 } else { 1097 } else {
1441 fprintf(stderr, "frequency and count are zero, aborting\n"); 1098 fprintf(stderr, "frequency and count are zero, aborting\n");
1442 exit(EXIT_FAILURE); 1099 exit(EXIT_FAILURE);
1443 } 1100 }
1444 1101
1445 /* 1102 list_for_each_entry(pos, &top.evlist->entries, node) {
1446 * Fill in the ones not specifically initialized via -c: 1103 if (perf_evsel__alloc_fd(pos, top.evlist->cpus->nr,
1447 */ 1104 top.evlist->threads->nr) < 0)
1448 for (counter = 0; counter < nr_counters; counter++) { 1105 goto out_free_fd;
1449 if (attrs[counter].sample_period) 1106 /*
1107 * Fill in the ones not specifically initialized via -c:
1108 */
1109 if (pos->attr.sample_period)
1450 continue; 1110 continue;
1451 1111
1452 attrs[counter].sample_period = default_interval; 1112 pos->attr.sample_period = default_interval;
1453 } 1113 }
1454 1114
1455 if (target_tid != -1) 1115 if (perf_evlist__alloc_pollfd(top.evlist) < 0 ||
1456 nr_cpus = 1; 1116 perf_evlist__alloc_mmap(top.evlist) < 0)
1457 else 1117 goto out_free_fd;
1458 nr_cpus = read_cpu_map(cpu_list);
1459 1118
1460 if (nr_cpus < 1) 1119 top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node);
1461 usage_with_options(top_usage, options); 1120
1121 symbol_conf.priv_size = (sizeof(struct sym_entry) + sizeof(struct annotation) +
1122 (top.evlist->nr_entries + 1) * sizeof(unsigned long));
1123
1124 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
1125 if (symbol__init() < 0)
1126 return -1;
1462 1127
1463 get_term_dimensions(&winsize); 1128 get_term_dimensions(&winsize);
1464 if (print_entries == 0) { 1129 if (top.print_entries == 0) {
1465 update_print_entries(&winsize); 1130 update_print_entries(&winsize);
1466 signal(SIGWINCH, sig_winch_handler); 1131 signal(SIGWINCH, sig_winch_handler);
1467 } 1132 }
1468 1133
1469 return __cmd_top(); 1134 status = __cmd_top();
1135out_free_fd:
1136 perf_evlist__delete(top.evlist);
1137
1138 return status;
1470} 1139}
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
deleted file mode 100644
index 40a6a2992d15..000000000000
--- a/tools/perf/builtin-trace.c
+++ /dev/null
@@ -1,734 +0,0 @@
1#include "builtin.h"
2
3#include "perf.h"
4#include "util/cache.h"
5#include "util/debug.h"
6#include "util/exec_cmd.h"
7#include "util/header.h"
8#include "util/parse-options.h"
9#include "util/session.h"
10#include "util/symbol.h"
11#include "util/thread.h"
12#include "util/trace-event.h"
13#include "util/util.h"
14
15static char const *script_name;
16static char const *generate_script_lang;
17static bool debug_mode;
18static u64 last_timestamp;
19static u64 nr_unordered;
20
21static int default_start_script(const char *script __unused,
22 int argc __unused,
23 const char **argv __unused)
24{
25 return 0;
26}
27
28static int default_stop_script(void)
29{
30 return 0;
31}
32
33static int default_generate_script(const char *outfile __unused)
34{
35 return 0;
36}
37
38static struct scripting_ops default_scripting_ops = {
39 .start_script = default_start_script,
40 .stop_script = default_stop_script,
41 .process_event = print_event,
42 .generate_script = default_generate_script,
43};
44
45static struct scripting_ops *scripting_ops;
46
47static void setup_scripting(void)
48{
49 /* make sure PERF_EXEC_PATH is set for scripts */
50 perf_set_argv_exec_path(perf_exec_path());
51
52 setup_perl_scripting();
53 setup_python_scripting();
54
55 scripting_ops = &default_scripting_ops;
56}
57
58static int cleanup_scripting(void)
59{
60 pr_debug("\nperf trace script stopped\n");
61
62 return scripting_ops->stop_script();
63}
64
65static char const *input_name = "perf.data";
66
67static int process_sample_event(event_t *event, struct perf_session *session)
68{
69 struct sample_data data;
70 struct thread *thread;
71
72 memset(&data, 0, sizeof(data));
73 data.time = -1;
74 data.cpu = -1;
75 data.period = 1;
76
77 event__parse_sample(event, session->sample_type, &data);
78
79 dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc,
80 data.pid, data.tid, data.ip, data.period);
81
82 thread = perf_session__findnew(session, event->ip.pid);
83 if (thread == NULL) {
84 pr_debug("problem processing %d event, skipping it.\n",
85 event->header.type);
86 return -1;
87 }
88
89 if (session->sample_type & PERF_SAMPLE_RAW) {
90 if (debug_mode) {
91 if (data.time < last_timestamp) {
92 pr_err("Samples misordered, previous: %llu "
93 "this: %llu\n", last_timestamp,
94 data.time);
95 nr_unordered++;
96 }
97 last_timestamp = data.time;
98 return 0;
99 }
100 /*
101 * FIXME: better resolve from pid from the struct trace_entry
102 * field, although it should be the same than this perf
103 * event pid
104 */
105 scripting_ops->process_event(data.cpu, data.raw_data,
106 data.raw_size,
107 data.time, thread->comm);
108 }
109
110 session->hists.stats.total_period += data.period;
111 return 0;
112}
113
114static u64 nr_lost;
115
116static int process_lost_event(event_t *event, struct perf_session *session __used)
117{
118 nr_lost += event->lost.lost;
119
120 return 0;
121}
122
123static struct perf_event_ops event_ops = {
124 .sample = process_sample_event,
125 .comm = event__process_comm,
126 .attr = event__process_attr,
127 .event_type = event__process_event_type,
128 .tracing_data = event__process_tracing_data,
129 .build_id = event__process_build_id,
130 .lost = process_lost_event,
131 .ordered_samples = true,
132};
133
134extern volatile int session_done;
135
136static void sig_handler(int sig __unused)
137{
138 session_done = 1;
139}
140
141static int __cmd_trace(struct perf_session *session)
142{
143 int ret;
144
145 signal(SIGINT, sig_handler);
146
147 ret = perf_session__process_events(session, &event_ops);
148
149 if (debug_mode) {
150 pr_err("Misordered timestamps: %llu\n", nr_unordered);
151 pr_err("Lost events: %llu\n", nr_lost);
152 }
153
154 return ret;
155}
156
157struct script_spec {
158 struct list_head node;
159 struct scripting_ops *ops;
160 char spec[0];
161};
162
163LIST_HEAD(script_specs);
164
165static struct script_spec *script_spec__new(const char *spec,
166 struct scripting_ops *ops)
167{
168 struct script_spec *s = malloc(sizeof(*s) + strlen(spec) + 1);
169
170 if (s != NULL) {
171 strcpy(s->spec, spec);
172 s->ops = ops;
173 }
174
175 return s;
176}
177
178static void script_spec__delete(struct script_spec *s)
179{
180 free(s->spec);
181 free(s);
182}
183
184static void script_spec__add(struct script_spec *s)
185{
186 list_add_tail(&s->node, &script_specs);
187}
188
189static struct script_spec *script_spec__find(const char *spec)
190{
191 struct script_spec *s;
192
193 list_for_each_entry(s, &script_specs, node)
194 if (strcasecmp(s->spec, spec) == 0)
195 return s;
196 return NULL;
197}
198
199static struct script_spec *script_spec__findnew(const char *spec,
200 struct scripting_ops *ops)
201{
202 struct script_spec *s = script_spec__find(spec);
203
204 if (s)
205 return s;
206
207 s = script_spec__new(spec, ops);
208 if (!s)
209 goto out_delete_spec;
210
211 script_spec__add(s);
212
213 return s;
214
215out_delete_spec:
216 script_spec__delete(s);
217
218 return NULL;
219}
220
221int script_spec_register(const char *spec, struct scripting_ops *ops)
222{
223 struct script_spec *s;
224
225 s = script_spec__find(spec);
226 if (s)
227 return -1;
228
229 s = script_spec__findnew(spec, ops);
230 if (!s)
231 return -1;
232
233 return 0;
234}
235
236static struct scripting_ops *script_spec__lookup(const char *spec)
237{
238 struct script_spec *s = script_spec__find(spec);
239 if (!s)
240 return NULL;
241
242 return s->ops;
243}
244
245static void list_available_languages(void)
246{
247 struct script_spec *s;
248
249 fprintf(stderr, "\n");
250 fprintf(stderr, "Scripting language extensions (used in "
251 "perf trace -s [spec:]script.[spec]):\n\n");
252
253 list_for_each_entry(s, &script_specs, node)
254 fprintf(stderr, " %-42s [%s]\n", s->spec, s->ops->name);
255
256 fprintf(stderr, "\n");
257}
258
259static int parse_scriptname(const struct option *opt __used,
260 const char *str, int unset __used)
261{
262 char spec[PATH_MAX];
263 const char *script, *ext;
264 int len;
265
266 if (strcmp(str, "lang") == 0) {
267 list_available_languages();
268 exit(0);
269 }
270
271 script = strchr(str, ':');
272 if (script) {
273 len = script - str;
274 if (len >= PATH_MAX) {
275 fprintf(stderr, "invalid language specifier");
276 return -1;
277 }
278 strncpy(spec, str, len);
279 spec[len] = '\0';
280 scripting_ops = script_spec__lookup(spec);
281 if (!scripting_ops) {
282 fprintf(stderr, "invalid language specifier");
283 return -1;
284 }
285 script++;
286 } else {
287 script = str;
288 ext = strchr(script, '.');
289 if (!ext) {
290 fprintf(stderr, "invalid script extension");
291 return -1;
292 }
293 scripting_ops = script_spec__lookup(++ext);
294 if (!scripting_ops) {
295 fprintf(stderr, "invalid script extension");
296 return -1;
297 }
298 }
299
300 script_name = strdup(script);
301
302 return 0;
303}
304
305#define for_each_lang(scripts_dir, lang_dirent, lang_next) \
306 while (!readdir_r(scripts_dir, &lang_dirent, &lang_next) && \
307 lang_next) \
308 if (lang_dirent.d_type == DT_DIR && \
309 (strcmp(lang_dirent.d_name, ".")) && \
310 (strcmp(lang_dirent.d_name, "..")))
311
312#define for_each_script(lang_dir, script_dirent, script_next) \
313 while (!readdir_r(lang_dir, &script_dirent, &script_next) && \
314 script_next) \
315 if (script_dirent.d_type != DT_DIR)
316
317
318#define RECORD_SUFFIX "-record"
319#define REPORT_SUFFIX "-report"
320
321struct script_desc {
322 struct list_head node;
323 char *name;
324 char *half_liner;
325 char *args;
326};
327
328LIST_HEAD(script_descs);
329
330static struct script_desc *script_desc__new(const char *name)
331{
332 struct script_desc *s = zalloc(sizeof(*s));
333
334 if (s != NULL)
335 s->name = strdup(name);
336
337 return s;
338}
339
340static void script_desc__delete(struct script_desc *s)
341{
342 free(s->name);
343 free(s);
344}
345
346static void script_desc__add(struct script_desc *s)
347{
348 list_add_tail(&s->node, &script_descs);
349}
350
351static struct script_desc *script_desc__find(const char *name)
352{
353 struct script_desc *s;
354
355 list_for_each_entry(s, &script_descs, node)
356 if (strcasecmp(s->name, name) == 0)
357 return s;
358 return NULL;
359}
360
361static struct script_desc *script_desc__findnew(const char *name)
362{
363 struct script_desc *s = script_desc__find(name);
364
365 if (s)
366 return s;
367
368 s = script_desc__new(name);
369 if (!s)
370 goto out_delete_desc;
371
372 script_desc__add(s);
373
374 return s;
375
376out_delete_desc:
377 script_desc__delete(s);
378
379 return NULL;
380}
381
382static char *ends_with(char *str, const char *suffix)
383{
384 size_t suffix_len = strlen(suffix);
385 char *p = str;
386
387 if (strlen(str) > suffix_len) {
388 p = str + strlen(str) - suffix_len;
389 if (!strncmp(p, suffix, suffix_len))
390 return p;
391 }
392
393 return NULL;
394}
395
396static char *ltrim(char *str)
397{
398 int len = strlen(str);
399
400 while (len && isspace(*str)) {
401 len--;
402 str++;
403 }
404
405 return str;
406}
407
408static int read_script_info(struct script_desc *desc, const char *filename)
409{
410 char line[BUFSIZ], *p;
411 FILE *fp;
412
413 fp = fopen(filename, "r");
414 if (!fp)
415 return -1;
416
417 while (fgets(line, sizeof(line), fp)) {
418 p = ltrim(line);
419 if (strlen(p) == 0)
420 continue;
421 if (*p != '#')
422 continue;
423 p++;
424 if (strlen(p) && *p == '!')
425 continue;
426
427 p = ltrim(p);
428 if (strlen(p) && p[strlen(p) - 1] == '\n')
429 p[strlen(p) - 1] = '\0';
430
431 if (!strncmp(p, "description:", strlen("description:"))) {
432 p += strlen("description:");
433 desc->half_liner = strdup(ltrim(p));
434 continue;
435 }
436
437 if (!strncmp(p, "args:", strlen("args:"))) {
438 p += strlen("args:");
439 desc->args = strdup(ltrim(p));
440 continue;
441 }
442 }
443
444 fclose(fp);
445
446 return 0;
447}
448
449static int list_available_scripts(const struct option *opt __used,
450 const char *s __used, int unset __used)
451{
452 struct dirent *script_next, *lang_next, script_dirent, lang_dirent;
453 char scripts_path[MAXPATHLEN];
454 DIR *scripts_dir, *lang_dir;
455 char script_path[MAXPATHLEN];
456 char lang_path[MAXPATHLEN];
457 struct script_desc *desc;
458 char first_half[BUFSIZ];
459 char *script_root;
460 char *str;
461
462 snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
463
464 scripts_dir = opendir(scripts_path);
465 if (!scripts_dir)
466 return -1;
467
468 for_each_lang(scripts_dir, lang_dirent, lang_next) {
469 snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path,
470 lang_dirent.d_name);
471 lang_dir = opendir(lang_path);
472 if (!lang_dir)
473 continue;
474
475 for_each_script(lang_dir, script_dirent, script_next) {
476 script_root = strdup(script_dirent.d_name);
477 str = ends_with(script_root, REPORT_SUFFIX);
478 if (str) {
479 *str = '\0';
480 desc = script_desc__findnew(script_root);
481 snprintf(script_path, MAXPATHLEN, "%s/%s",
482 lang_path, script_dirent.d_name);
483 read_script_info(desc, script_path);
484 }
485 free(script_root);
486 }
487 }
488
489 fprintf(stdout, "List of available trace scripts:\n");
490 list_for_each_entry(desc, &script_descs, node) {
491 sprintf(first_half, "%s %s", desc->name,
492 desc->args ? desc->args : "");
493 fprintf(stdout, " %-36s %s\n", first_half,
494 desc->half_liner ? desc->half_liner : "");
495 }
496
497 exit(0);
498}
499
500static char *get_script_path(const char *script_root, const char *suffix)
501{
502 struct dirent *script_next, *lang_next, script_dirent, lang_dirent;
503 char scripts_path[MAXPATHLEN];
504 char script_path[MAXPATHLEN];
505 DIR *scripts_dir, *lang_dir;
506 char lang_path[MAXPATHLEN];
507 char *str, *__script_root;
508 char *path = NULL;
509
510 snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
511
512 scripts_dir = opendir(scripts_path);
513 if (!scripts_dir)
514 return NULL;
515
516 for_each_lang(scripts_dir, lang_dirent, lang_next) {
517 snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path,
518 lang_dirent.d_name);
519 lang_dir = opendir(lang_path);
520 if (!lang_dir)
521 continue;
522
523 for_each_script(lang_dir, script_dirent, script_next) {
524 __script_root = strdup(script_dirent.d_name);
525 str = ends_with(__script_root, suffix);
526 if (str) {
527 *str = '\0';
528 if (strcmp(__script_root, script_root))
529 continue;
530 snprintf(script_path, MAXPATHLEN, "%s/%s",
531 lang_path, script_dirent.d_name);
532 path = strdup(script_path);
533 free(__script_root);
534 break;
535 }
536 free(__script_root);
537 }
538 }
539
540 return path;
541}
542
543static const char * const trace_usage[] = {
544 "perf trace [<options>] <command>",
545 NULL
546};
547
548static const struct option options[] = {
549 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
550 "dump raw trace in ASCII"),
551 OPT_INCR('v', "verbose", &verbose,
552 "be more verbose (show symbol address, etc)"),
553 OPT_BOOLEAN('L', "Latency", &latency_format,
554 "show latency attributes (irqs/preemption disabled, etc)"),
555 OPT_CALLBACK_NOOPT('l', "list", NULL, NULL, "list available scripts",
556 list_available_scripts),
557 OPT_CALLBACK('s', "script", NULL, "name",
558 "script file name (lang:script name, script name, or *)",
559 parse_scriptname),
560 OPT_STRING('g', "gen-script", &generate_script_lang, "lang",
561 "generate perf-trace.xx script in specified language"),
562 OPT_STRING('i', "input", &input_name, "file",
563 "input file name"),
564 OPT_BOOLEAN('d', "debug-mode", &debug_mode,
565 "do various checks like samples ordering and lost events"),
566
567 OPT_END()
568};
569
570int cmd_trace(int argc, const char **argv, const char *prefix __used)
571{
572 struct perf_session *session;
573 const char *suffix = NULL;
574 const char **__argv;
575 char *script_path;
576 int i, err;
577
578 if (argc >= 2 && strncmp(argv[1], "rec", strlen("rec")) == 0) {
579 if (argc < 3) {
580 fprintf(stderr,
581 "Please specify a record script\n");
582 return -1;
583 }
584 suffix = RECORD_SUFFIX;
585 }
586
587 if (argc >= 2 && strncmp(argv[1], "rep", strlen("rep")) == 0) {
588 if (argc < 3) {
589 fprintf(stderr,
590 "Please specify a report script\n");
591 return -1;
592 }
593 suffix = REPORT_SUFFIX;
594 }
595
596 if (!suffix && argc >= 2 && strncmp(argv[1], "-", strlen("-")) != 0) {
597 char *record_script_path, *report_script_path;
598 int live_pipe[2];
599 pid_t pid;
600
601 record_script_path = get_script_path(argv[1], RECORD_SUFFIX);
602 if (!record_script_path) {
603 fprintf(stderr, "record script not found\n");
604 return -1;
605 }
606
607 report_script_path = get_script_path(argv[1], REPORT_SUFFIX);
608 if (!report_script_path) {
609 fprintf(stderr, "report script not found\n");
610 return -1;
611 }
612
613 if (pipe(live_pipe) < 0) {
614 perror("failed to create pipe");
615 exit(-1);
616 }
617
618 pid = fork();
619 if (pid < 0) {
620 perror("failed to fork");
621 exit(-1);
622 }
623
624 if (!pid) {
625 dup2(live_pipe[1], 1);
626 close(live_pipe[0]);
627
628 __argv = malloc(5 * sizeof(const char *));
629 __argv[0] = "/bin/sh";
630 __argv[1] = record_script_path;
631 __argv[2] = "-o";
632 __argv[3] = "-";
633 __argv[4] = NULL;
634
635 execvp("/bin/sh", (char **)__argv);
636 exit(-1);
637 }
638
639 dup2(live_pipe[0], 0);
640 close(live_pipe[1]);
641
642 __argv = malloc((argc + 3) * sizeof(const char *));
643 __argv[0] = "/bin/sh";
644 __argv[1] = report_script_path;
645 for (i = 2; i < argc; i++)
646 __argv[i] = argv[i];
647 __argv[i++] = "-i";
648 __argv[i++] = "-";
649 __argv[i++] = NULL;
650
651 execvp("/bin/sh", (char **)__argv);
652 exit(-1);
653 }
654
655 if (suffix) {
656 script_path = get_script_path(argv[2], suffix);
657 if (!script_path) {
658 fprintf(stderr, "script not found\n");
659 return -1;
660 }
661
662 __argv = malloc((argc + 1) * sizeof(const char *));
663 __argv[0] = "/bin/sh";
664 __argv[1] = script_path;
665 for (i = 3; i < argc; i++)
666 __argv[i - 1] = argv[i];
667 __argv[argc - 1] = NULL;
668
669 execvp("/bin/sh", (char **)__argv);
670 exit(-1);
671 }
672
673 setup_scripting();
674
675 argc = parse_options(argc, argv, options, trace_usage,
676 PARSE_OPT_STOP_AT_NON_OPTION);
677
678 if (symbol__init() < 0)
679 return -1;
680 if (!script_name)
681 setup_pager();
682
683 session = perf_session__new(input_name, O_RDONLY, 0, false);
684 if (session == NULL)
685 return -ENOMEM;
686
687 if (strcmp(input_name, "-") &&
688 !perf_session__has_traces(session, "record -R"))
689 return -EINVAL;
690
691 if (generate_script_lang) {
692 struct stat perf_stat;
693
694 int input = open(input_name, O_RDONLY);
695 if (input < 0) {
696 perror("failed to open file");
697 exit(-1);
698 }
699
700 err = fstat(input, &perf_stat);
701 if (err < 0) {
702 perror("failed to stat file");
703 exit(-1);
704 }
705
706 if (!perf_stat.st_size) {
707 fprintf(stderr, "zero-sized file, nothing to do!\n");
708 exit(0);
709 }
710
711 scripting_ops = script_spec__lookup(generate_script_lang);
712 if (!scripting_ops) {
713 fprintf(stderr, "invalid language specifier");
714 return -1;
715 }
716
717 err = scripting_ops->generate_script("perf-trace");
718 goto out;
719 }
720
721 if (script_name) {
722 err = scripting_ops->start_script(script_name, argc, argv);
723 if (err)
724 goto out;
725 pr_debug("perf trace started with script %s\n\n", script_name);
726 }
727
728 err = __cmd_trace(session);
729
730 perf_session__delete(session);
731 cleanup_scripting();
732out:
733 return err;
734}
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h
index 921245b28583..4702e2443a8e 100644
--- a/tools/perf/builtin.h
+++ b/tools/perf/builtin.h
@@ -19,6 +19,7 @@ extern int cmd_bench(int argc, const char **argv, const char *prefix);
19extern int cmd_buildid_cache(int argc, const char **argv, const char *prefix); 19extern int cmd_buildid_cache(int argc, const char **argv, const char *prefix);
20extern int cmd_buildid_list(int argc, const char **argv, const char *prefix); 20extern int cmd_buildid_list(int argc, const char **argv, const char *prefix);
21extern int cmd_diff(int argc, const char **argv, const char *prefix); 21extern int cmd_diff(int argc, const char **argv, const char *prefix);
22extern int cmd_evlist(int argc, const char **argv, const char *prefix);
22extern int cmd_help(int argc, const char **argv, const char *prefix); 23extern int cmd_help(int argc, const char **argv, const char *prefix);
23extern int cmd_sched(int argc, const char **argv, const char *prefix); 24extern int cmd_sched(int argc, const char **argv, const char *prefix);
24extern int cmd_list(int argc, const char **argv, const char *prefix); 25extern int cmd_list(int argc, const char **argv, const char *prefix);
@@ -27,7 +28,7 @@ extern int cmd_report(int argc, const char **argv, const char *prefix);
27extern int cmd_stat(int argc, const char **argv, const char *prefix); 28extern int cmd_stat(int argc, const char **argv, const char *prefix);
28extern int cmd_timechart(int argc, const char **argv, const char *prefix); 29extern int cmd_timechart(int argc, const char **argv, const char *prefix);
29extern int cmd_top(int argc, const char **argv, const char *prefix); 30extern int cmd_top(int argc, const char **argv, const char *prefix);
30extern int cmd_trace(int argc, const char **argv, const char *prefix); 31extern int cmd_script(int argc, const char **argv, const char *prefix);
31extern int cmd_version(int argc, const char **argv, const char *prefix); 32extern int cmd_version(int argc, const char **argv, const char *prefix);
32extern int cmd_probe(int argc, const char **argv, const char *prefix); 33extern int cmd_probe(int argc, const char **argv, const char *prefix);
33extern int cmd_kmem(int argc, const char **argv, const char *prefix); 34extern int cmd_kmem(int argc, const char **argv, const char *prefix);
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt
index 949d77fc0b97..d695fe40fbff 100644
--- a/tools/perf/command-list.txt
+++ b/tools/perf/command-list.txt
@@ -8,6 +8,7 @@ perf-bench mainporcelain common
8perf-buildid-cache mainporcelain common 8perf-buildid-cache mainporcelain common
9perf-buildid-list mainporcelain common 9perf-buildid-list mainporcelain common
10perf-diff mainporcelain common 10perf-diff mainporcelain common
11perf-evlist mainporcelain common
11perf-inject mainporcelain common 12perf-inject mainporcelain common
12perf-list mainporcelain common 13perf-list mainporcelain common
13perf-sched mainporcelain common 14perf-sched mainporcelain common
@@ -16,7 +17,7 @@ perf-report mainporcelain common
16perf-stat mainporcelain common 17perf-stat mainporcelain common
17perf-timechart mainporcelain common 18perf-timechart mainporcelain common
18perf-top mainporcelain common 19perf-top mainporcelain common
19perf-trace mainporcelain common 20perf-script mainporcelain common
20perf-probe mainporcelain common 21perf-probe mainporcelain common
21perf-kmem mainporcelain common 22perf-kmem mainporcelain common
22perf-lock mainporcelain common 23perf-lock mainporcelain common
diff --git a/tools/perf/feature-tests.mak b/tools/perf/config/feature-tests.mak
index 7a7b60859053..6170fd2531b5 100644
--- a/tools/perf/feature-tests.mak
+++ b/tools/perf/config/feature-tests.mak
@@ -9,8 +9,8 @@ endef
9ifndef NO_DWARF 9ifndef NO_DWARF
10define SOURCE_DWARF 10define SOURCE_DWARF
11#include <dwarf.h> 11#include <dwarf.h>
12#include <libdw.h> 12#include <elfutils/libdw.h>
13#include <version.h> 13#include <elfutils/version.h>
14#ifndef _ELFUTILS_PREREQ 14#ifndef _ELFUTILS_PREREQ
15#error 15#error
16#endif 16#endif
@@ -79,9 +79,15 @@ endef
79endif 79endif
80 80
81ifndef NO_LIBPYTHON 81ifndef NO_LIBPYTHON
82define SOURCE_PYTHON_VERSION
83#include <Python.h>
84#if PY_VERSION_HEX >= 0x03000000
85 #error
86#endif
87int main(void){}
88endef
82define SOURCE_PYTHON_EMBED 89define SOURCE_PYTHON_EMBED
83#include <Python.h> 90#include <Python.h>
84
85int main(void) 91int main(void)
86{ 92{
87 Py_Initialize(); 93 Py_Initialize();
@@ -110,10 +116,13 @@ int main(void)
110} 116}
111endef 117endef
112 118
113# try-cc 119define SOURCE_STRLCPY
114# Usage: option = $(call try-cc, source-to-build, cc-options) 120#include <stdlib.h>
115try-cc = $(shell sh -c \ 121extern size_t strlcpy(char *dest, const char *src, size_t size);
116 'TMP="$(OUTPUT)$(TMPOUT).$$$$"; \ 122
117 echo "$(1)" | \ 123int main(void)
118 $(CC) -x c - $(2) -o "$$TMP" > /dev/null 2>&1 && echo y; \ 124{
119 rm -f "$$TMP"') 125 strlcpy(NULL, NULL, 0);
126 return 0;
127}
128endef
diff --git a/tools/perf/config/utilities.mak b/tools/perf/config/utilities.mak
new file mode 100644
index 000000000000..8046182a19eb
--- /dev/null
+++ b/tools/perf/config/utilities.mak
@@ -0,0 +1,188 @@
1# This allows us to work with the newline character:
2define newline
3
4
5endef
6newline := $(newline)
7
8# nl-escape
9#
10# Usage: escape = $(call nl-escape[,escape])
11#
12# This is used as the common way to specify
13# what should replace a newline when escaping
14# newlines; the default is a bizarre string.
15#
16nl-escape = $(or $(1),m822df3020w6a44id34bt574ctac44eb9f4n)
17
18# escape-nl
19#
20# Usage: escaped-text = $(call escape-nl,text[,escape])
21#
22# GNU make's $(shell ...) function converts to a
23# single space each newline character in the output
24# produced during the expansion; this may not be
25# desirable.
26#
27# The only solution is to change each newline into
28# something that won't be converted, so that the
29# information can be recovered later with
30# $(call unescape-nl...)
31#
32escape-nl = $(subst $(newline),$(call nl-escape,$(2)),$(1))
33
34# unescape-nl
35#
36# Usage: text = $(call unescape-nl,escaped-text[,escape])
37#
38# See escape-nl.
39#
40unescape-nl = $(subst $(call nl-escape,$(2)),$(newline),$(1))
41
42# shell-escape-nl
43#
44# Usage: $(shell some-command | $(call shell-escape-nl[,escape]))
45#
46# Use this to escape newlines from within a shell call;
47# the default escape is a bizarre string.
48#
49# NOTE: The escape is used directly as a string constant
50# in an `awk' program that is delimited by shell
51# single-quotes, so be wary of the characters
52# that are chosen.
53#
54define shell-escape-nl
55awk 'NR==1 {t=$$0} NR>1 {t=t "$(nl-escape)" $$0} END {printf t}'
56endef
57
58# shell-unescape-nl
59#
60# Usage: $(shell some-command | $(call shell-unescape-nl[,escape]))
61#
62# Use this to unescape newlines from within a shell call;
63# the default escape is a bizarre string.
64#
65# NOTE: The escape is used directly as an extended regular
66# expression constant in an `awk' program that is
67# delimited by shell single-quotes, so be wary
68# of the characters that are chosen.
69#
70# (The bash shell has a bug where `{gsub(...),...}' is
71# misinterpreted as a brace expansion; this can be
72# overcome by putting a space between `{' and `gsub').
73#
74define shell-unescape-nl
75awk 'NR==1 {t=$$0} NR>1 {t=t "\n" $$0} END { gsub(/$(nl-escape)/,"\n",t); printf t }'
76endef
77
78# escape-for-shell-sq
79#
80# Usage: embeddable-text = $(call escape-for-shell-sq,text)
81#
82# This function produces text that is suitable for
83# embedding in a shell string that is delimited by
84# single-quotes.
85#
86escape-for-shell-sq = $(subst ','\'',$(1))
87
88# shell-sq
89#
90# Usage: single-quoted-and-escaped-text = $(call shell-sq,text)
91#
92shell-sq = '$(escape-for-shell-sq)'
93
94# shell-wordify
95#
96# Usage: wordified-text = $(call shell-wordify,text)
97#
98# For instance:
99#
100# |define text
101# |hello
102# |world
103# |endef
104# |
105# |target:
106# | echo $(call shell-wordify,$(text))
107#
108# At least GNU make gets confused by expanding a newline
109# within the context of a command line of a makefile rule
110# (this is in constrast to a `$(shell ...)' function call,
111# which can handle it just fine).
112#
113# This function avoids the problem by producing a string
114# that works as a shell word, regardless of whether or
115# not it contains a newline.
116#
117# If the text to be wordified contains a newline, then
118# an intrictate shell command substitution is constructed
119# to render the text as a single line; when the shell
120# processes the resulting escaped text, it transforms
121# it into the original unescaped text.
122#
123# If the text does not contain a newline, then this function
124# produces the same results as the `$(shell-sq)' function.
125#
126shell-wordify = $(if $(findstring $(newline),$(1)),$(_sw-esc-nl),$(shell-sq))
127define _sw-esc-nl
128"$$(echo $(call escape-nl,$(shell-sq),$(2)) | $(call shell-unescape-nl,$(2)))"
129endef
130
131# is-absolute
132#
133# Usage: bool-value = $(call is-absolute,path)
134#
135is-absolute = $(shell echo $(shell-sq) | grep ^/ -q && echo y)
136
137# lookup
138#
139# Usage: absolute-executable-path-or-empty = $(call lookup,path)
140#
141# (It's necessary to use `sh -c' because GNU make messes up by
142# trying too hard and getting things wrong).
143#
144lookup = $(call unescape-nl,$(shell sh -c $(_l-sh)))
145_l-sh = $(call shell-sq,command -v $(shell-sq) | $(call shell-escape-nl,))
146
147# is-executable
148#
149# Usage: bool-value = $(call is-executable,path)
150#
151# (It's necessary to use `sh -c' because GNU make messes up by
152# trying too hard and getting things wrong).
153#
154is-executable = $(call _is-executable-helper,$(shell-sq))
155_is-executable-helper = $(shell sh -c $(_is-executable-sh))
156_is-executable-sh = $(call shell-sq,test -f $(1) -a -x $(1) && echo y)
157
158# get-executable
159#
160# Usage: absolute-executable-path-or-empty = $(call get-executable,path)
161#
162# The goal is to get an absolute path for an executable;
163# the `command -v' is defined by POSIX, but it's not
164# necessarily very portable, so it's only used if
165# relative path resolution is requested, as determined
166# by the presence of a leading `/'.
167#
168get-executable = $(if $(1),$(if $(is-absolute),$(_ge-abspath),$(lookup)))
169_ge-abspath = $(if $(is-executable),$(1))
170
171# get-supplied-or-default-executable
172#
173# Usage: absolute-executable-path-or-empty = $(call get-executable-or-default,variable,default)
174#
175define get-executable-or-default
176$(if $($(1)),$(call _ge_attempt,$($(1)),$(1)),$(call _ge_attempt,$(2)))
177endef
178_ge_attempt = $(or $(get-executable),$(_gea_warn),$(call _gea_err,$(2)))
179_gea_warn = $(warning The path '$(1)' is not executable.)
180_gea_err = $(if $(1),$(error Please set '$(1)' appropriately))
181
182# try-cc
183# Usage: option = $(call try-cc, source-to-build, cc-options)
184try-cc = $(shell sh -c \
185 'TMP="$(OUTPUT)$(TMPOUT).$$$$"; \
186 echo "$(1)" | \
187 $(CC) -x c - $(2) -o "$$TMP" > /dev/null 2>&1 && echo y; \
188 rm -f "$$TMP"')
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index cdd6c03f1e14..ec635b7cc8ea 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -313,6 +313,7 @@ static void handle_internal_command(int argc, const char **argv)
313 { "buildid-cache", cmd_buildid_cache, 0 }, 313 { "buildid-cache", cmd_buildid_cache, 0 },
314 { "buildid-list", cmd_buildid_list, 0 }, 314 { "buildid-list", cmd_buildid_list, 0 },
315 { "diff", cmd_diff, 0 }, 315 { "diff", cmd_diff, 0 },
316 { "evlist", cmd_evlist, 0 },
316 { "help", cmd_help, 0 }, 317 { "help", cmd_help, 0 },
317 { "list", cmd_list, 0 }, 318 { "list", cmd_list, 0 },
318 { "record", cmd_record, 0 }, 319 { "record", cmd_record, 0 },
@@ -323,7 +324,7 @@ static void handle_internal_command(int argc, const char **argv)
323 { "top", cmd_top, 0 }, 324 { "top", cmd_top, 0 },
324 { "annotate", cmd_annotate, 0 }, 325 { "annotate", cmd_annotate, 0 },
325 { "version", cmd_version, 0 }, 326 { "version", cmd_version, 0 },
326 { "trace", cmd_trace, 0 }, 327 { "script", cmd_script, 0 },
327 { "sched", cmd_sched, 0 }, 328 { "sched", cmd_sched, 0 },
328 { "probe", cmd_probe, 0 }, 329 { "probe", cmd_probe, 0 },
329 { "kmem", cmd_kmem, 0 }, 330 { "kmem", cmd_kmem, 0 },
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 95aaf565c704..a5fc660c1f12 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -94,6 +94,32 @@ void get_term_dimensions(struct winsize *ws);
94#include "util/types.h" 94#include "util/types.h"
95#include <stdbool.h> 95#include <stdbool.h>
96 96
97struct perf_mmap {
98 void *base;
99 int mask;
100 unsigned int prev;
101};
102
103static inline unsigned int perf_mmap__read_head(struct perf_mmap *mm)
104{
105 struct perf_event_mmap_page *pc = mm->base;
106 int head = pc->data_head;
107 rmb();
108 return head;
109}
110
111static inline void perf_mmap__write_tail(struct perf_mmap *md,
112 unsigned long tail)
113{
114 struct perf_event_mmap_page *pc = md->base;
115
116 /*
117 * ensure all reads are done before we write the tail out.
118 */
119 /* mb(); */
120 pc->data_tail = tail;
121}
122
97/* 123/*
98 * prctl(PR_TASK_PERF_EVENTS_DISABLE) will (cheaply) disable all 124 * prctl(PR_TASK_PERF_EVENTS_DISABLE) will (cheaply) disable all
99 * counters in the current task. 125 * counters in the current task.
diff --git a/tools/perf/python/twatch.py b/tools/perf/python/twatch.py
new file mode 100755
index 000000000000..df638c438a9f
--- /dev/null
+++ b/tools/perf/python/twatch.py
@@ -0,0 +1,41 @@
1#! /usr/bin/python
2# -*- python -*-
3# -*- coding: utf-8 -*-
4# twatch - Experimental use of the perf python interface
5# Copyright (C) 2011 Arnaldo Carvalho de Melo <acme@redhat.com>
6#
7# This application is free software; you can redistribute it and/or
8# modify it under the terms of the GNU General Public License
9# as published by the Free Software Foundation; version 2.
10#
11# This application is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14# General Public License for more details.
15
16import perf
17
18def main():
19 cpus = perf.cpu_map()
20 threads = perf.thread_map()
21 evsel = perf.evsel(task = 1, comm = 1, mmap = 0,
22 wakeup_events = 1, sample_period = 1,
23 sample_id_all = 1,
24 sample_type = perf.SAMPLE_PERIOD | perf.SAMPLE_TID | perf.SAMPLE_CPU | perf.SAMPLE_TID)
25 evsel.open(cpus = cpus, threads = threads);
26 evlist = perf.evlist(cpus, threads)
27 evlist.add(evsel)
28 evlist.mmap()
29 while True:
30 evlist.poll(timeout = -1)
31 for cpu in cpus:
32 event = evlist.read_on_cpu(cpu)
33 if not event:
34 continue
35 print "cpu: %2d, pid: %4d, tid: %4d" % (event.sample_cpu,
36 event.sample_pid,
37 event.sample_tid),
38 print event
39
40if __name__ == '__main__':
41 main()
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/Context.c b/tools/perf/scripts/perl/Perf-Trace-Util/Context.c
index 01a64ad693f2..790ceba6ad3f 100644
--- a/tools/perf/scripts/perl/Perf-Trace-Util/Context.c
+++ b/tools/perf/scripts/perl/Perf-Trace-Util/Context.c
@@ -8,7 +8,7 @@
8 8
9#line 1 "Context.xs" 9#line 1 "Context.xs"
10/* 10/*
11 * Context.xs. XS interfaces for perf trace. 11 * Context.xs. XS interfaces for perf script.
12 * 12 *
13 * Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com> 13 * Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com>
14 * 14 *
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/Context.xs b/tools/perf/scripts/perl/Perf-Trace-Util/Context.xs
index 549cf0467d30..c1e2ed1ed34e 100644
--- a/tools/perf/scripts/perl/Perf-Trace-Util/Context.xs
+++ b/tools/perf/scripts/perl/Perf-Trace-Util/Context.xs
@@ -1,5 +1,5 @@
1/* 1/*
2 * Context.xs. XS interfaces for perf trace. 2 * Context.xs. XS interfaces for perf script.
3 * 3 *
4 * Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com> 4 * Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com>
5 * 5 *
@@ -23,7 +23,7 @@
23#include "perl.h" 23#include "perl.h"
24#include "XSUB.h" 24#include "XSUB.h"
25#include "../../../perf.h" 25#include "../../../perf.h"
26#include "../../../util/trace-event.h" 26#include "../../../util/script-event.h"
27 27
28MODULE = Perf::Trace::Context PACKAGE = Perf::Trace::Context 28MODULE = Perf::Trace::Context PACKAGE = Perf::Trace::Context
29PROTOTYPES: ENABLE 29PROTOTYPES: ENABLE
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/README b/tools/perf/scripts/perl/Perf-Trace-Util/README
index 9a9707630791..2f0c7f3043ee 100644
--- a/tools/perf/scripts/perl/Perf-Trace-Util/README
+++ b/tools/perf/scripts/perl/Perf-Trace-Util/README
@@ -1,7 +1,7 @@
1Perf-Trace-Util version 0.01 1Perf-Trace-Util version 0.01
2============================ 2============================
3 3
4This module contains utility functions for use with perf trace. 4This module contains utility functions for use with perf script.
5 5
6Core.pm and Util.pm are pure Perl modules; Core.pm contains routines 6Core.pm and Util.pm are pure Perl modules; Core.pm contains routines
7that the core perf support for Perl calls on and should always be 7that the core perf support for Perl calls on and should always be
@@ -33,7 +33,7 @@ After you do that:
33 33
34INSTALLATION 34INSTALLATION
35 35
36Building perf with perf trace Perl scripting should install this 36Building perf with perf script Perl scripting should install this
37module in the right place. 37module in the right place.
38 38
39You should make sure libperl and ExtUtils/Embed.pm are installed first 39You should make sure libperl and ExtUtils/Embed.pm are installed first
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Context.pm b/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Context.pm
index 6c7f3659cb17..4e2f6039ac92 100644
--- a/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Context.pm
+++ b/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Context.pm
@@ -34,7 +34,7 @@ Perf::Trace::Context - Perl extension for accessing functions in perf.
34 34
35=head1 SEE ALSO 35=head1 SEE ALSO
36 36
37Perf (trace) documentation 37Perf (script) documentation
38 38
39=head1 AUTHOR 39=head1 AUTHOR
40 40
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Core.pm b/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Core.pm
index 9df376a9f629..9158458d3eeb 100644
--- a/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Core.pm
+++ b/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Core.pm
@@ -163,7 +163,7 @@ sub dump_symbolic_fields
163__END__ 163__END__
164=head1 NAME 164=head1 NAME
165 165
166Perf::Trace::Core - Perl extension for perf trace 166Perf::Trace::Core - Perl extension for perf script
167 167
168=head1 SYNOPSIS 168=head1 SYNOPSIS
169 169
@@ -171,7 +171,7 @@ Perf::Trace::Core - Perl extension for perf trace
171 171
172=head1 SEE ALSO 172=head1 SEE ALSO
173 173
174Perf (trace) documentation 174Perf (script) documentation
175 175
176=head1 AUTHOR 176=head1 AUTHOR
177 177
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Util.pm b/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Util.pm
index d94b40c8ac85..053500114625 100644
--- a/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Util.pm
+++ b/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Util.pm
@@ -65,7 +65,7 @@ sub clear_term
65__END__ 65__END__
66=head1 NAME 66=head1 NAME
67 67
68Perf::Trace::Util - Perl extension for perf trace 68Perf::Trace::Util - Perl extension for perf script
69 69
70=head1 SYNOPSIS 70=head1 SYNOPSIS
71 71
@@ -73,7 +73,7 @@ Perf::Trace::Util - Perl extension for perf trace
73 73
74=head1 SEE ALSO 74=head1 SEE ALSO
75 75
76Perf (trace) documentation 76Perf (script) documentation
77 77
78=head1 AUTHOR 78=head1 AUTHOR
79 79
diff --git a/tools/perf/scripts/perl/bin/failed-syscalls-record b/tools/perf/scripts/perl/bin/failed-syscalls-record
index eb5846bcb565..8104895a7b67 100644
--- a/tools/perf/scripts/perl/bin/failed-syscalls-record
+++ b/tools/perf/scripts/perl/bin/failed-syscalls-record
@@ -1,2 +1,2 @@
1#!/bin/bash 1#!/bin/bash
2perf record -a -e raw_syscalls:sys_exit $@ 2perf record -e raw_syscalls:sys_exit $@
diff --git a/tools/perf/scripts/perl/bin/failed-syscalls-report b/tools/perf/scripts/perl/bin/failed-syscalls-report
index e3a5e55d54ff..9f83cc1ad8ba 100644
--- a/tools/perf/scripts/perl/bin/failed-syscalls-report
+++ b/tools/perf/scripts/perl/bin/failed-syscalls-report
@@ -7,4 +7,4 @@ if [ $# -gt 0 ] ; then
7 shift 7 shift
8 fi 8 fi
9fi 9fi
10perf trace $@ -s ~/libexec/perf-core/scripts/perl/failed-syscalls.pl $comm 10perf script $@ -s "$PERF_EXEC_PATH"/scripts/perl/failed-syscalls.pl $comm
diff --git a/tools/perf/scripts/perl/bin/rw-by-file-record b/tools/perf/scripts/perl/bin/rw-by-file-record
index 5bfaae5a6cba..33efc8673aae 100644
--- a/tools/perf/scripts/perl/bin/rw-by-file-record
+++ b/tools/perf/scripts/perl/bin/rw-by-file-record
@@ -1,3 +1,3 @@
1#!/bin/bash 1#!/bin/bash
2perf record -a -e syscalls:sys_enter_read -e syscalls:sys_enter_write $@ 2perf record -e syscalls:sys_enter_read -e syscalls:sys_enter_write $@
3 3
diff --git a/tools/perf/scripts/perl/bin/rw-by-file-report b/tools/perf/scripts/perl/bin/rw-by-file-report
index d83070b7eeb5..77200b3f3100 100644
--- a/tools/perf/scripts/perl/bin/rw-by-file-report
+++ b/tools/perf/scripts/perl/bin/rw-by-file-report
@@ -7,7 +7,4 @@ if [ $# -lt 1 ] ; then
7fi 7fi
8comm=$1 8comm=$1
9shift 9shift
10perf trace $@ -s ~/libexec/perf-core/scripts/perl/rw-by-file.pl $comm 10perf script $@ -s "$PERF_EXEC_PATH"/scripts/perl/rw-by-file.pl $comm
11
12
13
diff --git a/tools/perf/scripts/perl/bin/rw-by-pid-record b/tools/perf/scripts/perl/bin/rw-by-pid-record
index 6e0b2f7755ac..7cb9db230448 100644
--- a/tools/perf/scripts/perl/bin/rw-by-pid-record
+++ b/tools/perf/scripts/perl/bin/rw-by-pid-record
@@ -1,2 +1,2 @@
1#!/bin/bash 1#!/bin/bash
2perf record -a -e syscalls:sys_enter_read -e syscalls:sys_exit_read -e syscalls:sys_enter_write -e syscalls:sys_exit_write $@ 2perf record -e syscalls:sys_enter_read -e syscalls:sys_exit_read -e syscalls:sys_enter_write -e syscalls:sys_exit_write $@
diff --git a/tools/perf/scripts/perl/bin/rw-by-pid-report b/tools/perf/scripts/perl/bin/rw-by-pid-report
index 7ef46983f62f..a27b9f311f95 100644
--- a/tools/perf/scripts/perl/bin/rw-by-pid-report
+++ b/tools/perf/scripts/perl/bin/rw-by-pid-report
@@ -1,6 +1,3 @@
1#!/bin/bash 1#!/bin/bash
2# description: system-wide r/w activity 2# description: system-wide r/w activity
3perf trace $@ -s ~/libexec/perf-core/scripts/perl/rw-by-pid.pl 3perf script $@ -s "$PERF_EXEC_PATH"/scripts/perl/rw-by-pid.pl
4
5
6
diff --git a/tools/perf/scripts/perl/bin/rwtop-record b/tools/perf/scripts/perl/bin/rwtop-record
index 6e0b2f7755ac..7cb9db230448 100644
--- a/tools/perf/scripts/perl/bin/rwtop-record
+++ b/tools/perf/scripts/perl/bin/rwtop-record
@@ -1,2 +1,2 @@
1#!/bin/bash 1#!/bin/bash
2perf record -a -e syscalls:sys_enter_read -e syscalls:sys_exit_read -e syscalls:sys_enter_write -e syscalls:sys_exit_write $@ 2perf record -e syscalls:sys_enter_read -e syscalls:sys_exit_read -e syscalls:sys_enter_write -e syscalls:sys_exit_write $@
diff --git a/tools/perf/scripts/perl/bin/rwtop-report b/tools/perf/scripts/perl/bin/rwtop-report
index 93e698cd3f38..83e11ec2e190 100644
--- a/tools/perf/scripts/perl/bin/rwtop-report
+++ b/tools/perf/scripts/perl/bin/rwtop-report
@@ -17,7 +17,4 @@ if [ "$n_args" -gt 0 ] ; then
17 interval=$1 17 interval=$1
18 shift 18 shift
19fi 19fi
20perf trace $@ -s ~/libexec/perf-core/scripts/perl/rwtop.pl $interval 20perf script $@ -s "$PERF_EXEC_PATH"/scripts/perl/rwtop.pl $interval
21
22
23
diff --git a/tools/perf/scripts/perl/bin/wakeup-latency-record b/tools/perf/scripts/perl/bin/wakeup-latency-record
index 9f2acaaae9f0..464251a1bd7e 100644
--- a/tools/perf/scripts/perl/bin/wakeup-latency-record
+++ b/tools/perf/scripts/perl/bin/wakeup-latency-record
@@ -1,5 +1,5 @@
1#!/bin/bash 1#!/bin/bash
2perf record -a -e sched:sched_switch -e sched:sched_wakeup $@ 2perf record -e sched:sched_switch -e sched:sched_wakeup $@
3 3
4 4
5 5
diff --git a/tools/perf/scripts/perl/bin/wakeup-latency-report b/tools/perf/scripts/perl/bin/wakeup-latency-report
index a0d898f9ca1d..889e8130cca5 100644
--- a/tools/perf/scripts/perl/bin/wakeup-latency-report
+++ b/tools/perf/scripts/perl/bin/wakeup-latency-report
@@ -1,6 +1,3 @@
1#!/bin/bash 1#!/bin/bash
2# description: system-wide min/max/avg wakeup latency 2# description: system-wide min/max/avg wakeup latency
3perf trace $@ -s ~/libexec/perf-core/scripts/perl/wakeup-latency.pl 3perf script $@ -s "$PERF_EXEC_PATH"/scripts/perl/wakeup-latency.pl
4
5
6
diff --git a/tools/perf/scripts/perl/bin/workqueue-stats-record b/tools/perf/scripts/perl/bin/workqueue-stats-record
index 85301f2471ff..8edda9078d5d 100644
--- a/tools/perf/scripts/perl/bin/workqueue-stats-record
+++ b/tools/perf/scripts/perl/bin/workqueue-stats-record
@@ -1,2 +1,2 @@
1#!/bin/bash 1#!/bin/bash
2perf record -a -e workqueue:workqueue_creation -e workqueue:workqueue_destruction -e workqueue:workqueue_execution -e workqueue:workqueue_insertion $@ 2perf record -e workqueue:workqueue_creation -e workqueue:workqueue_destruction -e workqueue:workqueue_execution -e workqueue:workqueue_insertion $@
diff --git a/tools/perf/scripts/perl/bin/workqueue-stats-report b/tools/perf/scripts/perl/bin/workqueue-stats-report
index 35081132ef97..6d91411d248c 100644
--- a/tools/perf/scripts/perl/bin/workqueue-stats-report
+++ b/tools/perf/scripts/perl/bin/workqueue-stats-report
@@ -1,7 +1,3 @@
1#!/bin/bash 1#!/bin/bash
2# description: workqueue stats (ins/exe/create/destroy) 2# description: workqueue stats (ins/exe/create/destroy)
3perf trace $@ -s ~/libexec/perf-core/scripts/perl/workqueue-stats.pl 3perf script $@ -s "$PERF_EXEC_PATH"/scripts/perl/workqueue-stats.pl
4
5
6
7
diff --git a/tools/perf/scripts/perl/check-perf-trace.pl b/tools/perf/scripts/perl/check-perf-trace.pl
index 4e7dc0a407a5..4e7076c20616 100644
--- a/tools/perf/scripts/perl/check-perf-trace.pl
+++ b/tools/perf/scripts/perl/check-perf-trace.pl
@@ -1,4 +1,4 @@
1# perf trace event handlers, generated by perf trace -g perl 1# perf script event handlers, generated by perf script -g perl
2# (c) 2009, Tom Zanussi <tzanussi@gmail.com> 2# (c) 2009, Tom Zanussi <tzanussi@gmail.com>
3# Licensed under the terms of the GNU GPL License version 2 3# Licensed under the terms of the GNU GPL License version 2
4 4
diff --git a/tools/perf/scripts/perl/rw-by-file.pl b/tools/perf/scripts/perl/rw-by-file.pl
index 2a39097687b9..74844ee2be3e 100644
--- a/tools/perf/scripts/perl/rw-by-file.pl
+++ b/tools/perf/scripts/perl/rw-by-file.pl
@@ -18,7 +18,7 @@ use lib "./Perf-Trace-Util/lib";
18use Perf::Trace::Core; 18use Perf::Trace::Core;
19use Perf::Trace::Util; 19use Perf::Trace::Util;
20 20
21my $usage = "perf trace -s rw-by-file.pl <comm>\n"; 21my $usage = "perf script -s rw-by-file.pl <comm>\n";
22 22
23my $for_comm = shift or die $usage; 23my $for_comm = shift or die $usage;
24 24
diff --git a/tools/perf/scripts/perl/workqueue-stats.pl b/tools/perf/scripts/perl/workqueue-stats.pl
index b84b12699b70..a8eaff5119e0 100644
--- a/tools/perf/scripts/perl/workqueue-stats.pl
+++ b/tools/perf/scripts/perl/workqueue-stats.pl
@@ -10,7 +10,7 @@
10# workqueue:workqueue_destruction -e workqueue:workqueue_execution 10# workqueue:workqueue_destruction -e workqueue:workqueue_execution
11# -e workqueue:workqueue_insertion 11# -e workqueue:workqueue_insertion
12# 12#
13# perf trace -p -s tools/perf/scripts/perl/workqueue-stats.pl 13# perf script -p -s tools/perf/scripts/perl/workqueue-stats.pl
14 14
15use 5.010000; 15use 5.010000;
16use strict; 16use strict;
diff --git a/tools/perf/scripts/python/Perf-Trace-Util/Context.c b/tools/perf/scripts/python/Perf-Trace-Util/Context.c
index 957085dd5d8d..315067b8f552 100644
--- a/tools/perf/scripts/python/Perf-Trace-Util/Context.c
+++ b/tools/perf/scripts/python/Perf-Trace-Util/Context.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Context.c. Python interfaces for perf trace. 2 * Context.c. Python interfaces for perf script.
3 * 3 *
4 * Copyright (C) 2010 Tom Zanussi <tzanussi@gmail.com> 4 * Copyright (C) 2010 Tom Zanussi <tzanussi@gmail.com>
5 * 5 *
diff --git a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py
index aad7525bca1d..de7211e4fa47 100644
--- a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py
+++ b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py
@@ -1,4 +1,4 @@
1# Core.py - Python extension for perf trace, core functions 1# Core.py - Python extension for perf script, core functions
2# 2#
3# Copyright (C) 2010 by Tom Zanussi <tzanussi@gmail.com> 3# Copyright (C) 2010 by Tom Zanussi <tzanussi@gmail.com>
4# 4#
diff --git a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/SchedGui.py b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/SchedGui.py
index ae9a56e43e05..fdd92f699055 100644
--- a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/SchedGui.py
+++ b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/SchedGui.py
@@ -1,4 +1,4 @@
1# SchedGui.py - Python extension for perf trace, basic GUI code for 1# SchedGui.py - Python extension for perf script, basic GUI code for
2# traces drawing and overview. 2# traces drawing and overview.
3# 3#
4# Copyright (C) 2010 by Frederic Weisbecker <fweisbec@gmail.com> 4# Copyright (C) 2010 by Frederic Weisbecker <fweisbec@gmail.com>
diff --git a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py
index 9689bc0acd9f..15c8400240fd 100644
--- a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py
+++ b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py
@@ -1,4 +1,4 @@
1# Util.py - Python extension for perf trace, miscellaneous utility code 1# Util.py - Python extension for perf script, miscellaneous utility code
2# 2#
3# Copyright (C) 2010 by Tom Zanussi <tzanussi@gmail.com> 3# Copyright (C) 2010 by Tom Zanussi <tzanussi@gmail.com>
4# 4#
@@ -6,6 +6,14 @@
6# Public License ("GPL") version 2 as published by the Free Software 6# Public License ("GPL") version 2 as published by the Free Software
7# Foundation. 7# Foundation.
8 8
9import errno, os
10
11FUTEX_WAIT = 0
12FUTEX_WAKE = 1
13FUTEX_PRIVATE_FLAG = 128
14FUTEX_CLOCK_REALTIME = 256
15FUTEX_CMD_MASK = ~(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME)
16
9NSECS_PER_SEC = 1000000000 17NSECS_PER_SEC = 1000000000
10 18
11def avg(total, n): 19def avg(total, n):
@@ -24,5 +32,55 @@ def nsecs_str(nsecs):
24 str = "%5u.%09u" % (nsecs_secs(nsecs), nsecs_nsecs(nsecs)), 32 str = "%5u.%09u" % (nsecs_secs(nsecs), nsecs_nsecs(nsecs)),
25 return str 33 return str
26 34
35def add_stats(dict, key, value):
36 if not dict.has_key(key):
37 dict[key] = (value, value, value, 1)
38 else:
39 min, max, avg, count = dict[key]
40 if value < min:
41 min = value
42 if value > max:
43 max = value
44 avg = (avg + value) / 2
45 dict[key] = (min, max, avg, count + 1)
46
27def clear_term(): 47def clear_term():
28 print("\x1b[H\x1b[2J") 48 print("\x1b[H\x1b[2J")
49
50audit_package_warned = False
51
52try:
53 import audit
54 machine_to_id = {
55 'x86_64': audit.MACH_86_64,
56 'alpha' : audit.MACH_ALPHA,
57 'ia64' : audit.MACH_IA64,
58 'ppc' : audit.MACH_PPC,
59 'ppc64' : audit.MACH_PPC64,
60 's390' : audit.MACH_S390,
61 's390x' : audit.MACH_S390X,
62 'i386' : audit.MACH_X86,
63 'i586' : audit.MACH_X86,
64 'i686' : audit.MACH_X86,
65 }
66 try:
67 machine_to_id['armeb'] = audit.MACH_ARMEB
68 except:
69 pass
70 machine_id = machine_to_id[os.uname()[4]]
71except:
72 if not audit_package_warned:
73 audit_package_warned = True
74 print "Install the audit-libs-python package to get syscall names"
75
76def syscall_name(id):
77 try:
78 return audit.audit_syscall_to_name(id, machine_id)
79 except:
80 return str(id)
81
82def strerror(nr):
83 try:
84 return errno.errorcode[abs(nr)]
85 except:
86 return "Unknown %d errno" % nr
diff --git a/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record b/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record
index eb5846bcb565..8104895a7b67 100644
--- a/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record
+++ b/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record
@@ -1,2 +1,2 @@
1#!/bin/bash 1#!/bin/bash
2perf record -a -e raw_syscalls:sys_exit $@ 2perf record -e raw_syscalls:sys_exit $@
diff --git a/tools/perf/scripts/python/bin/failed-syscalls-by-pid-report b/tools/perf/scripts/python/bin/failed-syscalls-by-pid-report
index 30293545fcc2..fda5096d0cbf 100644
--- a/tools/perf/scripts/python/bin/failed-syscalls-by-pid-report
+++ b/tools/perf/scripts/python/bin/failed-syscalls-by-pid-report
@@ -7,4 +7,4 @@ if [ $# -gt 0 ] ; then
7 shift 7 shift
8 fi 8 fi
9fi 9fi
10perf trace $@ -s ~/libexec/perf-core/scripts/python/failed-syscalls-by-pid.py $comm 10perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/failed-syscalls-by-pid.py $comm
diff --git a/tools/perf/scripts/python/bin/futex-contention-record b/tools/perf/scripts/python/bin/futex-contention-record
new file mode 100644
index 000000000000..b1495c9a9b20
--- /dev/null
+++ b/tools/perf/scripts/python/bin/futex-contention-record
@@ -0,0 +1,2 @@
1#!/bin/bash
2perf record -e syscalls:sys_enter_futex -e syscalls:sys_exit_futex $@
diff --git a/tools/perf/scripts/python/bin/futex-contention-report b/tools/perf/scripts/python/bin/futex-contention-report
new file mode 100644
index 000000000000..6c44271091ab
--- /dev/null
+++ b/tools/perf/scripts/python/bin/futex-contention-report
@@ -0,0 +1,4 @@
1#!/bin/bash
2# description: futext contention measurement
3
4perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/futex-contention.py
diff --git a/tools/perf/scripts/python/bin/netdev-times-record b/tools/perf/scripts/python/bin/netdev-times-record
new file mode 100644
index 000000000000..558754b840a9
--- /dev/null
+++ b/tools/perf/scripts/python/bin/netdev-times-record
@@ -0,0 +1,8 @@
1#!/bin/bash
2perf record -e net:net_dev_xmit -e net:net_dev_queue \
3 -e net:netif_receive_skb -e net:netif_rx \
4 -e skb:consume_skb -e skb:kfree_skb \
5 -e skb:skb_copy_datagram_iovec -e napi:napi_poll \
6 -e irq:irq_handler_entry -e irq:irq_handler_exit \
7 -e irq:softirq_entry -e irq:softirq_exit \
8 -e irq:softirq_raise $@
diff --git a/tools/perf/scripts/python/bin/netdev-times-report b/tools/perf/scripts/python/bin/netdev-times-report
new file mode 100644
index 000000000000..8f759291da86
--- /dev/null
+++ b/tools/perf/scripts/python/bin/netdev-times-report
@@ -0,0 +1,5 @@
1#!/bin/bash
2# description: display a process of packet and processing time
3# args: [tx] [rx] [dev=] [debug]
4
5perf script -s "$PERF_EXEC_PATH"/scripts/python/netdev-times.py $@
diff --git a/tools/perf/scripts/python/bin/sched-migration-record b/tools/perf/scripts/python/bin/sched-migration-record
index 17a3e9bd9e8f..7493fddbe995 100644
--- a/tools/perf/scripts/python/bin/sched-migration-record
+++ b/tools/perf/scripts/python/bin/sched-migration-record
@@ -1,2 +1,2 @@
1#!/bin/bash 1#!/bin/bash
2perf record -m 16384 -a -e sched:sched_wakeup -e sched:sched_wakeup_new -e sched:sched_switch -e sched:sched_migrate_task $@ 2perf record -m 16384 -e sched:sched_wakeup -e sched:sched_wakeup_new -e sched:sched_switch -e sched:sched_migrate_task $@
diff --git a/tools/perf/scripts/python/bin/sched-migration-report b/tools/perf/scripts/python/bin/sched-migration-report
index 61d05f72e443..68b037a1849b 100644
--- a/tools/perf/scripts/python/bin/sched-migration-report
+++ b/tools/perf/scripts/python/bin/sched-migration-report
@@ -1,3 +1,3 @@
1#!/bin/bash 1#!/bin/bash
2# description: sched migration overview 2# description: sched migration overview
3perf trace $@ -s ~/libexec/perf-core/scripts/python/sched-migration.py 3perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/sched-migration.py
diff --git a/tools/perf/scripts/python/bin/sctop-record b/tools/perf/scripts/python/bin/sctop-record
index 1fc5998b721d..4efbfaa7f6a5 100644
--- a/tools/perf/scripts/python/bin/sctop-record
+++ b/tools/perf/scripts/python/bin/sctop-record
@@ -1,2 +1,2 @@
1#!/bin/bash 1#!/bin/bash
2perf record -a -e raw_syscalls:sys_enter $@ 2perf record -e raw_syscalls:sys_enter $@
diff --git a/tools/perf/scripts/python/bin/sctop-report b/tools/perf/scripts/python/bin/sctop-report
index b01c842ae7b4..c32db294124d 100644
--- a/tools/perf/scripts/python/bin/sctop-report
+++ b/tools/perf/scripts/python/bin/sctop-report
@@ -21,4 +21,4 @@ elif [ "$n_args" -gt 0 ] ; then
21 interval=$1 21 interval=$1
22 shift 22 shift
23fi 23fi
24perf trace $@ -s ~/libexec/perf-core/scripts/python/sctop.py $comm $interval 24perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/sctop.py $comm $interval
diff --git a/tools/perf/scripts/python/bin/syscall-counts-by-pid-record b/tools/perf/scripts/python/bin/syscall-counts-by-pid-record
index 1fc5998b721d..4efbfaa7f6a5 100644
--- a/tools/perf/scripts/python/bin/syscall-counts-by-pid-record
+++ b/tools/perf/scripts/python/bin/syscall-counts-by-pid-record
@@ -1,2 +1,2 @@
1#!/bin/bash 1#!/bin/bash
2perf record -a -e raw_syscalls:sys_enter $@ 2perf record -e raw_syscalls:sys_enter $@
diff --git a/tools/perf/scripts/python/bin/syscall-counts-by-pid-report b/tools/perf/scripts/python/bin/syscall-counts-by-pid-report
index 9e9d8ddd72ce..16eb8d65c543 100644
--- a/tools/perf/scripts/python/bin/syscall-counts-by-pid-report
+++ b/tools/perf/scripts/python/bin/syscall-counts-by-pid-report
@@ -7,4 +7,4 @@ if [ $# -gt 0 ] ; then
7 shift 7 shift
8 fi 8 fi
9fi 9fi
10perf trace $@ -s ~/libexec/perf-core/scripts/python/syscall-counts-by-pid.py $comm 10perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/syscall-counts-by-pid.py $comm
diff --git a/tools/perf/scripts/python/bin/syscall-counts-record b/tools/perf/scripts/python/bin/syscall-counts-record
index 1fc5998b721d..4efbfaa7f6a5 100644
--- a/tools/perf/scripts/python/bin/syscall-counts-record
+++ b/tools/perf/scripts/python/bin/syscall-counts-record
@@ -1,2 +1,2 @@
1#!/bin/bash 1#!/bin/bash
2perf record -a -e raw_syscalls:sys_enter $@ 2perf record -e raw_syscalls:sys_enter $@
diff --git a/tools/perf/scripts/python/bin/syscall-counts-report b/tools/perf/scripts/python/bin/syscall-counts-report
index dc076b618796..0f0e9d453bb4 100644
--- a/tools/perf/scripts/python/bin/syscall-counts-report
+++ b/tools/perf/scripts/python/bin/syscall-counts-report
@@ -7,4 +7,4 @@ if [ $# -gt 0 ] ; then
7 shift 7 shift
8 fi 8 fi
9fi 9fi
10perf trace $@ -s ~/libexec/perf-core/scripts/python/syscall-counts.py $comm 10perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/syscall-counts.py $comm
diff --git a/tools/perf/scripts/python/check-perf-trace.py b/tools/perf/scripts/python/check-perf-trace.py
index d9f7893e315c..4647a7694cf6 100644
--- a/tools/perf/scripts/python/check-perf-trace.py
+++ b/tools/perf/scripts/python/check-perf-trace.py
@@ -1,4 +1,4 @@
1# perf trace event handlers, generated by perf trace -g python 1# perf script event handlers, generated by perf script -g python
2# (c) 2010, Tom Zanussi <tzanussi@gmail.com> 2# (c) 2010, Tom Zanussi <tzanussi@gmail.com>
3# Licensed under the terms of the GNU GPL License version 2 3# Licensed under the terms of the GNU GPL License version 2
4# 4#
diff --git a/tools/perf/scripts/python/failed-syscalls-by-pid.py b/tools/perf/scripts/python/failed-syscalls-by-pid.py
index 0ca02278fe69..85805fac4116 100644
--- a/tools/perf/scripts/python/failed-syscalls-by-pid.py
+++ b/tools/perf/scripts/python/failed-syscalls-by-pid.py
@@ -13,21 +13,26 @@ sys.path.append(os.environ['PERF_EXEC_PATH'] + \
13 13
14from perf_trace_context import * 14from perf_trace_context import *
15from Core import * 15from Core import *
16from Util import *
16 17
17usage = "perf trace -s syscall-counts-by-pid.py [comm]\n"; 18usage = "perf script -s syscall-counts-by-pid.py [comm|pid]\n";
18 19
19for_comm = None 20for_comm = None
21for_pid = None
20 22
21if len(sys.argv) > 2: 23if len(sys.argv) > 2:
22 sys.exit(usage) 24 sys.exit(usage)
23 25
24if len(sys.argv) > 1: 26if len(sys.argv) > 1:
25 for_comm = sys.argv[1] 27 try:
28 for_pid = int(sys.argv[1])
29 except:
30 for_comm = sys.argv[1]
26 31
27syscalls = autodict() 32syscalls = autodict()
28 33
29def trace_begin(): 34def trace_begin():
30 pass 35 print "Press control+C to stop and show the summary"
31 36
32def trace_end(): 37def trace_end():
33 print_error_totals() 38 print_error_totals()
@@ -35,9 +40,9 @@ def trace_end():
35def raw_syscalls__sys_exit(event_name, context, common_cpu, 40def raw_syscalls__sys_exit(event_name, context, common_cpu,
36 common_secs, common_nsecs, common_pid, common_comm, 41 common_secs, common_nsecs, common_pid, common_comm,
37 id, ret): 42 id, ret):
38 if for_comm is not None: 43 if (for_comm and common_comm != for_comm) or \
39 if common_comm != for_comm: 44 (for_pid and common_pid != for_pid ):
40 return 45 return
41 46
42 if ret < 0: 47 if ret < 0:
43 try: 48 try:
@@ -62,7 +67,7 @@ def print_error_totals():
62 print "\n%s [%d]\n" % (comm, pid), 67 print "\n%s [%d]\n" % (comm, pid),
63 id_keys = syscalls[comm][pid].keys() 68 id_keys = syscalls[comm][pid].keys()
64 for id in id_keys: 69 for id in id_keys:
65 print " syscall: %-16d\n" % (id), 70 print " syscall: %-16s\n" % syscall_name(id),
66 ret_keys = syscalls[comm][pid][id].keys() 71 ret_keys = syscalls[comm][pid][id].keys()
67 for ret, val in sorted(syscalls[comm][pid][id].iteritems(), key = lambda(k, v): (v, k), reverse = True): 72 for ret, val in sorted(syscalls[comm][pid][id].iteritems(), key = lambda(k, v): (v, k), reverse = True):
68 print " err = %-20d %10d\n" % (ret, val), 73 print " err = %-20s %10d\n" % (strerror(ret), val),
diff --git a/tools/perf/scripts/python/futex-contention.py b/tools/perf/scripts/python/futex-contention.py
new file mode 100644
index 000000000000..11e70a388d41
--- /dev/null
+++ b/tools/perf/scripts/python/futex-contention.py
@@ -0,0 +1,50 @@
1# futex contention
2# (c) 2010, Arnaldo Carvalho de Melo <acme@redhat.com>
3# Licensed under the terms of the GNU GPL License version 2
4#
5# Translation of:
6#
7# http://sourceware.org/systemtap/wiki/WSFutexContention
8#
9# to perf python scripting.
10#
11# Measures futex contention
12
13import os, sys
14sys.path.append(os.environ['PERF_EXEC_PATH'] + '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
15from Util import *
16
17process_names = {}
18thread_thislock = {}
19thread_blocktime = {}
20
21lock_waits = {} # long-lived stats on (tid,lock) blockage elapsed time
22process_names = {} # long-lived pid-to-execname mapping
23
24def syscalls__sys_enter_futex(event, ctxt, cpu, s, ns, tid, comm,
25 nr, uaddr, op, val, utime, uaddr2, val3):
26 cmd = op & FUTEX_CMD_MASK
27 if cmd != FUTEX_WAIT:
28 return # we don't care about originators of WAKE events
29
30 process_names[tid] = comm
31 thread_thislock[tid] = uaddr
32 thread_blocktime[tid] = nsecs(s, ns)
33
34def syscalls__sys_exit_futex(event, ctxt, cpu, s, ns, tid, comm,
35 nr, ret):
36 if thread_blocktime.has_key(tid):
37 elapsed = nsecs(s, ns) - thread_blocktime[tid]
38 add_stats(lock_waits, (tid, thread_thislock[tid]), elapsed)
39 del thread_blocktime[tid]
40 del thread_thislock[tid]
41
42def trace_begin():
43 print "Press control+C to stop and show the summary"
44
45def trace_end():
46 for (tid, lock) in lock_waits:
47 min, max, avg, count = lock_waits[tid, lock]
48 print "%s[%d] lock %x contended %d times, %d avg ns" % \
49 (process_names[tid], tid, lock, count, avg)
50
diff --git a/tools/perf/scripts/python/netdev-times.py b/tools/perf/scripts/python/netdev-times.py
new file mode 100644
index 000000000000..9aa0a32972e8
--- /dev/null
+++ b/tools/perf/scripts/python/netdev-times.py
@@ -0,0 +1,464 @@
1# Display a process of packets and processed time.
2# It helps us to investigate networking or network device.
3#
4# options
5# tx: show only tx chart
6# rx: show only rx chart
7# dev=: show only thing related to specified device
8# debug: work with debug mode. It shows buffer status.
9
10import os
11import sys
12
13sys.path.append(os.environ['PERF_EXEC_PATH'] + \
14 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
15
16from perf_trace_context import *
17from Core import *
18from Util import *
19
20all_event_list = []; # insert all tracepoint event related with this script
21irq_dic = {}; # key is cpu and value is a list which stacks irqs
22 # which raise NET_RX softirq
23net_rx_dic = {}; # key is cpu and value include time of NET_RX softirq-entry
24 # and a list which stacks receive
25receive_hunk_list = []; # a list which include a sequence of receive events
26rx_skb_list = []; # received packet list for matching
27 # skb_copy_datagram_iovec
28
29buffer_budget = 65536; # the budget of rx_skb_list, tx_queue_list and
30 # tx_xmit_list
31of_count_rx_skb_list = 0; # overflow count
32
33tx_queue_list = []; # list of packets which pass through dev_queue_xmit
34of_count_tx_queue_list = 0; # overflow count
35
36tx_xmit_list = []; # list of packets which pass through dev_hard_start_xmit
37of_count_tx_xmit_list = 0; # overflow count
38
39tx_free_list = []; # list of packets which is freed
40
41# options
42show_tx = 0;
43show_rx = 0;
44dev = 0; # store a name of device specified by option "dev="
45debug = 0;
46
47# indices of event_info tuple
48EINFO_IDX_NAME= 0
49EINFO_IDX_CONTEXT=1
50EINFO_IDX_CPU= 2
51EINFO_IDX_TIME= 3
52EINFO_IDX_PID= 4
53EINFO_IDX_COMM= 5
54
55# Calculate a time interval(msec) from src(nsec) to dst(nsec)
56def diff_msec(src, dst):
57 return (dst - src) / 1000000.0
58
59# Display a process of transmitting a packet
60def print_transmit(hunk):
61 if dev != 0 and hunk['dev'].find(dev) < 0:
62 return
63 print "%7s %5d %6d.%06dsec %12.3fmsec %12.3fmsec" % \
64 (hunk['dev'], hunk['len'],
65 nsecs_secs(hunk['queue_t']),
66 nsecs_nsecs(hunk['queue_t'])/1000,
67 diff_msec(hunk['queue_t'], hunk['xmit_t']),
68 diff_msec(hunk['xmit_t'], hunk['free_t']))
69
70# Format for displaying rx packet processing
71PF_IRQ_ENTRY= " irq_entry(+%.3fmsec irq=%d:%s)"
72PF_SOFT_ENTRY=" softirq_entry(+%.3fmsec)"
73PF_NAPI_POLL= " napi_poll_exit(+%.3fmsec %s)"
74PF_JOINT= " |"
75PF_WJOINT= " | |"
76PF_NET_RECV= " |---netif_receive_skb(+%.3fmsec skb=%x len=%d)"
77PF_NET_RX= " |---netif_rx(+%.3fmsec skb=%x)"
78PF_CPY_DGRAM= " | skb_copy_datagram_iovec(+%.3fmsec %d:%s)"
79PF_KFREE_SKB= " | kfree_skb(+%.3fmsec location=%x)"
80PF_CONS_SKB= " | consume_skb(+%.3fmsec)"
81
82# Display a process of received packets and interrputs associated with
83# a NET_RX softirq
84def print_receive(hunk):
85 show_hunk = 0
86 irq_list = hunk['irq_list']
87 cpu = irq_list[0]['cpu']
88 base_t = irq_list[0]['irq_ent_t']
89 # check if this hunk should be showed
90 if dev != 0:
91 for i in range(len(irq_list)):
92 if irq_list[i]['name'].find(dev) >= 0:
93 show_hunk = 1
94 break
95 else:
96 show_hunk = 1
97 if show_hunk == 0:
98 return
99
100 print "%d.%06dsec cpu=%d" % \
101 (nsecs_secs(base_t), nsecs_nsecs(base_t)/1000, cpu)
102 for i in range(len(irq_list)):
103 print PF_IRQ_ENTRY % \
104 (diff_msec(base_t, irq_list[i]['irq_ent_t']),
105 irq_list[i]['irq'], irq_list[i]['name'])
106 print PF_JOINT
107 irq_event_list = irq_list[i]['event_list']
108 for j in range(len(irq_event_list)):
109 irq_event = irq_event_list[j]
110 if irq_event['event'] == 'netif_rx':
111 print PF_NET_RX % \
112 (diff_msec(base_t, irq_event['time']),
113 irq_event['skbaddr'])
114 print PF_JOINT
115 print PF_SOFT_ENTRY % \
116 diff_msec(base_t, hunk['sirq_ent_t'])
117 print PF_JOINT
118 event_list = hunk['event_list']
119 for i in range(len(event_list)):
120 event = event_list[i]
121 if event['event_name'] == 'napi_poll':
122 print PF_NAPI_POLL % \
123 (diff_msec(base_t, event['event_t']), event['dev'])
124 if i == len(event_list) - 1:
125 print ""
126 else:
127 print PF_JOINT
128 else:
129 print PF_NET_RECV % \
130 (diff_msec(base_t, event['event_t']), event['skbaddr'],
131 event['len'])
132 if 'comm' in event.keys():
133 print PF_WJOINT
134 print PF_CPY_DGRAM % \
135 (diff_msec(base_t, event['comm_t']),
136 event['pid'], event['comm'])
137 elif 'handle' in event.keys():
138 print PF_WJOINT
139 if event['handle'] == "kfree_skb":
140 print PF_KFREE_SKB % \
141 (diff_msec(base_t,
142 event['comm_t']),
143 event['location'])
144 elif event['handle'] == "consume_skb":
145 print PF_CONS_SKB % \
146 diff_msec(base_t,
147 event['comm_t'])
148 print PF_JOINT
149
150def trace_begin():
151 global show_tx
152 global show_rx
153 global dev
154 global debug
155
156 for i in range(len(sys.argv)):
157 if i == 0:
158 continue
159 arg = sys.argv[i]
160 if arg == 'tx':
161 show_tx = 1
162 elif arg =='rx':
163 show_rx = 1
164 elif arg.find('dev=',0, 4) >= 0:
165 dev = arg[4:]
166 elif arg == 'debug':
167 debug = 1
168 if show_tx == 0 and show_rx == 0:
169 show_tx = 1
170 show_rx = 1
171
172def trace_end():
173 # order all events in time
174 all_event_list.sort(lambda a,b :cmp(a[EINFO_IDX_TIME],
175 b[EINFO_IDX_TIME]))
176 # process all events
177 for i in range(len(all_event_list)):
178 event_info = all_event_list[i]
179 name = event_info[EINFO_IDX_NAME]
180 if name == 'irq__softirq_exit':
181 handle_irq_softirq_exit(event_info)
182 elif name == 'irq__softirq_entry':
183 handle_irq_softirq_entry(event_info)
184 elif name == 'irq__softirq_raise':
185 handle_irq_softirq_raise(event_info)
186 elif name == 'irq__irq_handler_entry':
187 handle_irq_handler_entry(event_info)
188 elif name == 'irq__irq_handler_exit':
189 handle_irq_handler_exit(event_info)
190 elif name == 'napi__napi_poll':
191 handle_napi_poll(event_info)
192 elif name == 'net__netif_receive_skb':
193 handle_netif_receive_skb(event_info)
194 elif name == 'net__netif_rx':
195 handle_netif_rx(event_info)
196 elif name == 'skb__skb_copy_datagram_iovec':
197 handle_skb_copy_datagram_iovec(event_info)
198 elif name == 'net__net_dev_queue':
199 handle_net_dev_queue(event_info)
200 elif name == 'net__net_dev_xmit':
201 handle_net_dev_xmit(event_info)
202 elif name == 'skb__kfree_skb':
203 handle_kfree_skb(event_info)
204 elif name == 'skb__consume_skb':
205 handle_consume_skb(event_info)
206 # display receive hunks
207 if show_rx:
208 for i in range(len(receive_hunk_list)):
209 print_receive(receive_hunk_list[i])
210 # display transmit hunks
211 if show_tx:
212 print " dev len Qdisc " \
213 " netdevice free"
214 for i in range(len(tx_free_list)):
215 print_transmit(tx_free_list[i])
216 if debug:
217 print "debug buffer status"
218 print "----------------------------"
219 print "xmit Qdisc:remain:%d overflow:%d" % \
220 (len(tx_queue_list), of_count_tx_queue_list)
221 print "xmit netdevice:remain:%d overflow:%d" % \
222 (len(tx_xmit_list), of_count_tx_xmit_list)
223 print "receive:remain:%d overflow:%d" % \
224 (len(rx_skb_list), of_count_rx_skb_list)
225
226# called from perf, when it finds a correspoinding event
227def irq__softirq_entry(name, context, cpu, sec, nsec, pid, comm, vec):
228 if symbol_str("irq__softirq_entry", "vec", vec) != "NET_RX":
229 return
230 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, vec)
231 all_event_list.append(event_info)
232
233def irq__softirq_exit(name, context, cpu, sec, nsec, pid, comm, vec):
234 if symbol_str("irq__softirq_entry", "vec", vec) != "NET_RX":
235 return
236 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, vec)
237 all_event_list.append(event_info)
238
239def irq__softirq_raise(name, context, cpu, sec, nsec, pid, comm, vec):
240 if symbol_str("irq__softirq_entry", "vec", vec) != "NET_RX":
241 return
242 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, vec)
243 all_event_list.append(event_info)
244
245def irq__irq_handler_entry(name, context, cpu, sec, nsec, pid, comm,
246 irq, irq_name):
247 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
248 irq, irq_name)
249 all_event_list.append(event_info)
250
251def irq__irq_handler_exit(name, context, cpu, sec, nsec, pid, comm, irq, ret):
252 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, irq, ret)
253 all_event_list.append(event_info)
254
255def napi__napi_poll(name, context, cpu, sec, nsec, pid, comm, napi, dev_name):
256 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
257 napi, dev_name)
258 all_event_list.append(event_info)
259
260def net__netif_receive_skb(name, context, cpu, sec, nsec, pid, comm, skbaddr,
261 skblen, dev_name):
262 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
263 skbaddr, skblen, dev_name)
264 all_event_list.append(event_info)
265
266def net__netif_rx(name, context, cpu, sec, nsec, pid, comm, skbaddr,
267 skblen, dev_name):
268 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
269 skbaddr, skblen, dev_name)
270 all_event_list.append(event_info)
271
272def net__net_dev_queue(name, context, cpu, sec, nsec, pid, comm,
273 skbaddr, skblen, dev_name):
274 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
275 skbaddr, skblen, dev_name)
276 all_event_list.append(event_info)
277
278def net__net_dev_xmit(name, context, cpu, sec, nsec, pid, comm,
279 skbaddr, skblen, rc, dev_name):
280 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
281 skbaddr, skblen, rc ,dev_name)
282 all_event_list.append(event_info)
283
284def skb__kfree_skb(name, context, cpu, sec, nsec, pid, comm,
285 skbaddr, protocol, location):
286 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
287 skbaddr, protocol, location)
288 all_event_list.append(event_info)
289
290def skb__consume_skb(name, context, cpu, sec, nsec, pid, comm, skbaddr):
291 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
292 skbaddr)
293 all_event_list.append(event_info)
294
295def skb__skb_copy_datagram_iovec(name, context, cpu, sec, nsec, pid, comm,
296 skbaddr, skblen):
297 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
298 skbaddr, skblen)
299 all_event_list.append(event_info)
300
301def handle_irq_handler_entry(event_info):
302 (name, context, cpu, time, pid, comm, irq, irq_name) = event_info
303 if cpu not in irq_dic.keys():
304 irq_dic[cpu] = []
305 irq_record = {'irq':irq, 'name':irq_name, 'cpu':cpu, 'irq_ent_t':time}
306 irq_dic[cpu].append(irq_record)
307
308def handle_irq_handler_exit(event_info):
309 (name, context, cpu, time, pid, comm, irq, ret) = event_info
310 if cpu not in irq_dic.keys():
311 return
312 irq_record = irq_dic[cpu].pop()
313 if irq != irq_record['irq']:
314 return
315 irq_record.update({'irq_ext_t':time})
316 # if an irq doesn't include NET_RX softirq, drop.
317 if 'event_list' in irq_record.keys():
318 irq_dic[cpu].append(irq_record)
319
320def handle_irq_softirq_raise(event_info):
321 (name, context, cpu, time, pid, comm, vec) = event_info
322 if cpu not in irq_dic.keys() \
323 or len(irq_dic[cpu]) == 0:
324 return
325 irq_record = irq_dic[cpu].pop()
326 if 'event_list' in irq_record.keys():
327 irq_event_list = irq_record['event_list']
328 else:
329 irq_event_list = []
330 irq_event_list.append({'time':time, 'event':'sirq_raise'})
331 irq_record.update({'event_list':irq_event_list})
332 irq_dic[cpu].append(irq_record)
333
334def handle_irq_softirq_entry(event_info):
335 (name, context, cpu, time, pid, comm, vec) = event_info
336 net_rx_dic[cpu] = {'sirq_ent_t':time, 'event_list':[]}
337
338def handle_irq_softirq_exit(event_info):
339 (name, context, cpu, time, pid, comm, vec) = event_info
340 irq_list = []
341 event_list = 0
342 if cpu in irq_dic.keys():
343 irq_list = irq_dic[cpu]
344 del irq_dic[cpu]
345 if cpu in net_rx_dic.keys():
346 sirq_ent_t = net_rx_dic[cpu]['sirq_ent_t']
347 event_list = net_rx_dic[cpu]['event_list']
348 del net_rx_dic[cpu]
349 if irq_list == [] or event_list == 0:
350 return
351 rec_data = {'sirq_ent_t':sirq_ent_t, 'sirq_ext_t':time,
352 'irq_list':irq_list, 'event_list':event_list}
353 # merge information realted to a NET_RX softirq
354 receive_hunk_list.append(rec_data)
355
356def handle_napi_poll(event_info):
357 (name, context, cpu, time, pid, comm, napi, dev_name) = event_info
358 if cpu in net_rx_dic.keys():
359 event_list = net_rx_dic[cpu]['event_list']
360 rec_data = {'event_name':'napi_poll',
361 'dev':dev_name, 'event_t':time}
362 event_list.append(rec_data)
363
364def handle_netif_rx(event_info):
365 (name, context, cpu, time, pid, comm,
366 skbaddr, skblen, dev_name) = event_info
367 if cpu not in irq_dic.keys() \
368 or len(irq_dic[cpu]) == 0:
369 return
370 irq_record = irq_dic[cpu].pop()
371 if 'event_list' in irq_record.keys():
372 irq_event_list = irq_record['event_list']
373 else:
374 irq_event_list = []
375 irq_event_list.append({'time':time, 'event':'netif_rx',
376 'skbaddr':skbaddr, 'skblen':skblen, 'dev_name':dev_name})
377 irq_record.update({'event_list':irq_event_list})
378 irq_dic[cpu].append(irq_record)
379
380def handle_netif_receive_skb(event_info):
381 global of_count_rx_skb_list
382
383 (name, context, cpu, time, pid, comm,
384 skbaddr, skblen, dev_name) = event_info
385 if cpu in net_rx_dic.keys():
386 rec_data = {'event_name':'netif_receive_skb',
387 'event_t':time, 'skbaddr':skbaddr, 'len':skblen}
388 event_list = net_rx_dic[cpu]['event_list']
389 event_list.append(rec_data)
390 rx_skb_list.insert(0, rec_data)
391 if len(rx_skb_list) > buffer_budget:
392 rx_skb_list.pop()
393 of_count_rx_skb_list += 1
394
395def handle_net_dev_queue(event_info):
396 global of_count_tx_queue_list
397
398 (name, context, cpu, time, pid, comm,
399 skbaddr, skblen, dev_name) = event_info
400 skb = {'dev':dev_name, 'skbaddr':skbaddr, 'len':skblen, 'queue_t':time}
401 tx_queue_list.insert(0, skb)
402 if len(tx_queue_list) > buffer_budget:
403 tx_queue_list.pop()
404 of_count_tx_queue_list += 1
405
406def handle_net_dev_xmit(event_info):
407 global of_count_tx_xmit_list
408
409 (name, context, cpu, time, pid, comm,
410 skbaddr, skblen, rc, dev_name) = event_info
411 if rc == 0: # NETDEV_TX_OK
412 for i in range(len(tx_queue_list)):
413 skb = tx_queue_list[i]
414 if skb['skbaddr'] == skbaddr:
415 skb['xmit_t'] = time
416 tx_xmit_list.insert(0, skb)
417 del tx_queue_list[i]
418 if len(tx_xmit_list) > buffer_budget:
419 tx_xmit_list.pop()
420 of_count_tx_xmit_list += 1
421 return
422
423def handle_kfree_skb(event_info):
424 (name, context, cpu, time, pid, comm,
425 skbaddr, protocol, location) = event_info
426 for i in range(len(tx_queue_list)):
427 skb = tx_queue_list[i]
428 if skb['skbaddr'] == skbaddr:
429 del tx_queue_list[i]
430 return
431 for i in range(len(tx_xmit_list)):
432 skb = tx_xmit_list[i]
433 if skb['skbaddr'] == skbaddr:
434 skb['free_t'] = time
435 tx_free_list.append(skb)
436 del tx_xmit_list[i]
437 return
438 for i in range(len(rx_skb_list)):
439 rec_data = rx_skb_list[i]
440 if rec_data['skbaddr'] == skbaddr:
441 rec_data.update({'handle':"kfree_skb",
442 'comm':comm, 'pid':pid, 'comm_t':time})
443 del rx_skb_list[i]
444 return
445
446def handle_consume_skb(event_info):
447 (name, context, cpu, time, pid, comm, skbaddr) = event_info
448 for i in range(len(tx_xmit_list)):
449 skb = tx_xmit_list[i]
450 if skb['skbaddr'] == skbaddr:
451 skb['free_t'] = time
452 tx_free_list.append(skb)
453 del tx_xmit_list[i]
454 return
455
456def handle_skb_copy_datagram_iovec(event_info):
457 (name, context, cpu, time, pid, comm, skbaddr, skblen) = event_info
458 for i in range(len(rx_skb_list)):
459 rec_data = rx_skb_list[i]
460 if skbaddr == rec_data['skbaddr']:
461 rec_data.update({'handle':"skb_copy_datagram_iovec",
462 'comm':comm, 'pid':pid, 'comm_t':time})
463 del rx_skb_list[i]
464 return
diff --git a/tools/perf/scripts/python/sched-migration.py b/tools/perf/scripts/python/sched-migration.py
index b934383c3364..74d55ec08aed 100644
--- a/tools/perf/scripts/python/sched-migration.py
+++ b/tools/perf/scripts/python/sched-migration.py
@@ -4,7 +4,7 @@
4# 4#
5# Copyright (C) 2010 Frederic Weisbecker <fweisbec@gmail.com> 5# Copyright (C) 2010 Frederic Weisbecker <fweisbec@gmail.com>
6# 6#
7# perf trace event handlers have been generated by perf trace -g python 7# perf script event handlers have been generated by perf script -g python
8# 8#
9# This software is distributed under the terms of the GNU General 9# This software is distributed under the terms of the GNU General
10# Public License ("GPL") version 2 as published by the Free Software 10# Public License ("GPL") version 2 as published by the Free Software
diff --git a/tools/perf/scripts/python/sctop.py b/tools/perf/scripts/python/sctop.py
index 6cafad40c296..42c267e292fa 100644
--- a/tools/perf/scripts/python/sctop.py
+++ b/tools/perf/scripts/python/sctop.py
@@ -8,10 +8,7 @@
8# will be refreshed every [interval] seconds. The default interval is 8# will be refreshed every [interval] seconds. The default interval is
9# 3 seconds. 9# 3 seconds.
10 10
11import thread 11import os, sys, thread, time
12import time
13import os
14import sys
15 12
16sys.path.append(os.environ['PERF_EXEC_PATH'] + \ 13sys.path.append(os.environ['PERF_EXEC_PATH'] + \
17 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') 14 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
@@ -20,7 +17,7 @@ from perf_trace_context import *
20from Core import * 17from Core import *
21from Util import * 18from Util import *
22 19
23usage = "perf trace -s syscall-counts.py [comm] [interval]\n"; 20usage = "perf script -s sctop.py [comm] [interval]\n";
24 21
25for_comm = None 22for_comm = None
26default_interval = 3 23default_interval = 3
@@ -71,7 +68,7 @@ def print_syscall_totals(interval):
71 for id, val in sorted(syscalls.iteritems(), key = lambda(k, v): (v, k), \ 68 for id, val in sorted(syscalls.iteritems(), key = lambda(k, v): (v, k), \
72 reverse = True): 69 reverse = True):
73 try: 70 try:
74 print "%-40d %10d\n" % (id, val), 71 print "%-40s %10d\n" % (syscall_name(id), val),
75 except TypeError: 72 except TypeError:
76 pass 73 pass
77 syscalls.clear() 74 syscalls.clear()
diff --git a/tools/perf/scripts/python/syscall-counts-by-pid.py b/tools/perf/scripts/python/syscall-counts-by-pid.py
index af722d6a4b3f..c64d1c55d745 100644
--- a/tools/perf/scripts/python/syscall-counts-by-pid.py
+++ b/tools/perf/scripts/python/syscall-counts-by-pid.py
@@ -5,29 +5,33 @@
5# Displays system-wide system call totals, broken down by syscall. 5# Displays system-wide system call totals, broken down by syscall.
6# If a [comm] arg is specified, only syscalls called by [comm] are displayed. 6# If a [comm] arg is specified, only syscalls called by [comm] are displayed.
7 7
8import os 8import os, sys
9import sys
10 9
11sys.path.append(os.environ['PERF_EXEC_PATH'] + \ 10sys.path.append(os.environ['PERF_EXEC_PATH'] + \
12 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') 11 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
13 12
14from perf_trace_context import * 13from perf_trace_context import *
15from Core import * 14from Core import *
15from Util import syscall_name
16 16
17usage = "perf trace -s syscall-counts-by-pid.py [comm]\n"; 17usage = "perf script -s syscall-counts-by-pid.py [comm]\n";
18 18
19for_comm = None 19for_comm = None
20for_pid = None
20 21
21if len(sys.argv) > 2: 22if len(sys.argv) > 2:
22 sys.exit(usage) 23 sys.exit(usage)
23 24
24if len(sys.argv) > 1: 25if len(sys.argv) > 1:
25 for_comm = sys.argv[1] 26 try:
27 for_pid = int(sys.argv[1])
28 except:
29 for_comm = sys.argv[1]
26 30
27syscalls = autodict() 31syscalls = autodict()
28 32
29def trace_begin(): 33def trace_begin():
30 pass 34 print "Press control+C to stop and show the summary"
31 35
32def trace_end(): 36def trace_end():
33 print_syscall_totals() 37 print_syscall_totals()
@@ -35,9 +39,10 @@ def trace_end():
35def raw_syscalls__sys_enter(event_name, context, common_cpu, 39def raw_syscalls__sys_enter(event_name, context, common_cpu,
36 common_secs, common_nsecs, common_pid, common_comm, 40 common_secs, common_nsecs, common_pid, common_comm,
37 id, args): 41 id, args):
38 if for_comm is not None: 42
39 if common_comm != for_comm: 43 if (for_comm and common_comm != for_comm) or \
40 return 44 (for_pid and common_pid != for_pid ):
45 return
41 try: 46 try:
42 syscalls[common_comm][common_pid][id] += 1 47 syscalls[common_comm][common_pid][id] += 1
43 except TypeError: 48 except TypeError:
@@ -61,4 +66,4 @@ def print_syscall_totals():
61 id_keys = syscalls[comm][pid].keys() 66 id_keys = syscalls[comm][pid].keys()
62 for id, val in sorted(syscalls[comm][pid].iteritems(), \ 67 for id, val in sorted(syscalls[comm][pid].iteritems(), \
63 key = lambda(k, v): (v, k), reverse = True): 68 key = lambda(k, v): (v, k), reverse = True):
64 print " %-38d %10d\n" % (id, val), 69 print " %-38s %10d\n" % (syscall_name(id), val),
diff --git a/tools/perf/scripts/python/syscall-counts.py b/tools/perf/scripts/python/syscall-counts.py
index f977e85ff049..b435d3f188e8 100644
--- a/tools/perf/scripts/python/syscall-counts.py
+++ b/tools/perf/scripts/python/syscall-counts.py
@@ -13,8 +13,9 @@ sys.path.append(os.environ['PERF_EXEC_PATH'] + \
13 13
14from perf_trace_context import * 14from perf_trace_context import *
15from Core import * 15from Core import *
16from Util import syscall_name
16 17
17usage = "perf trace -s syscall-counts.py [comm]\n"; 18usage = "perf script -s syscall-counts.py [comm]\n";
18 19
19for_comm = None 20for_comm = None
20 21
@@ -27,7 +28,7 @@ if len(sys.argv) > 1:
27syscalls = autodict() 28syscalls = autodict()
28 29
29def trace_begin(): 30def trace_begin():
30 pass 31 print "Press control+C to stop and show the summary"
31 32
32def trace_end(): 33def trace_end():
33 print_syscall_totals() 34 print_syscall_totals()
@@ -55,4 +56,4 @@ def print_syscall_totals():
55 56
56 for id, val in sorted(syscalls.iteritems(), key = lambda(k, v): (v, k), \ 57 for id, val in sorted(syscalls.iteritems(), key = lambda(k, v): (v, k), \
57 reverse = True): 58 reverse = True):
58 print "%-40d %10d\n" % (id, val), 59 print "%-40s %10d\n" % (syscall_name(id), val),
diff --git a/tools/perf/util/PERF-VERSION-GEN b/tools/perf/util/PERF-VERSION-GEN
index 97d76562a1a0..ad73300f7bac 100755
--- a/tools/perf/util/PERF-VERSION-GEN
+++ b/tools/perf/util/PERF-VERSION-GEN
@@ -23,12 +23,7 @@ if test -d ../../.git -o -f ../../.git &&
23then 23then
24 VN=$(echo "$VN" | sed -e 's/-/./g'); 24 VN=$(echo "$VN" | sed -e 's/-/./g');
25else 25else
26 eval `grep '^VERSION\s*=' ../../Makefile|tr -d ' '` 26 VN=$(MAKEFLAGS= make -sC ../.. kernelversion)
27 eval `grep '^PATCHLEVEL\s*=' ../../Makefile|tr -d ' '`
28 eval `grep '^SUBLEVEL\s*=' ../../Makefile|tr -d ' '`
29 eval `grep '^EXTRAVERSION\s*=' ../../Makefile|tr -d ' '`
30
31 VN="${VERSION}.${PATCHLEVEL}.${SUBLEVEL}${EXTRAVERSION}"
32fi 27fi
33 28
34VN=$(expr "$VN" : v*'\(.*\)') 29VN=$(expr "$VN" : v*'\(.*\)')
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
new file mode 100644
index 000000000000..e01af2b1a469
--- /dev/null
+++ b/tools/perf/util/annotate.c
@@ -0,0 +1,605 @@
1/*
2 * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
3 *
4 * Parts came from builtin-annotate.c, see those files for further
5 * copyright notes.
6 *
7 * Released under the GPL v2. (and only v2, not any later version)
8 */
9
10#include "util.h"
11#include "build-id.h"
12#include "color.h"
13#include "cache.h"
14#include "symbol.h"
15#include "debug.h"
16#include "annotate.h"
17#include <pthread.h>
18
19int symbol__annotate_init(struct map *map __used, struct symbol *sym)
20{
21 struct annotation *notes = symbol__annotation(sym);
22 pthread_mutex_init(&notes->lock, NULL);
23 return 0;
24}
25
26int symbol__alloc_hist(struct symbol *sym, int nevents)
27{
28 struct annotation *notes = symbol__annotation(sym);
29 size_t sizeof_sym_hist = (sizeof(struct sym_hist) +
30 (sym->end - sym->start) * sizeof(u64));
31
32 notes->src = zalloc(sizeof(*notes->src) + nevents * sizeof_sym_hist);
33 if (notes->src == NULL)
34 return -1;
35 notes->src->sizeof_sym_hist = sizeof_sym_hist;
36 notes->src->nr_histograms = nevents;
37 INIT_LIST_HEAD(&notes->src->source);
38 return 0;
39}
40
41void symbol__annotate_zero_histograms(struct symbol *sym)
42{
43 struct annotation *notes = symbol__annotation(sym);
44
45 pthread_mutex_lock(&notes->lock);
46 if (notes->src != NULL)
47 memset(notes->src->histograms, 0,
48 notes->src->nr_histograms * notes->src->sizeof_sym_hist);
49 pthread_mutex_unlock(&notes->lock);
50}
51
52int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
53 int evidx, u64 addr)
54{
55 unsigned offset;
56 struct annotation *notes;
57 struct sym_hist *h;
58
59 notes = symbol__annotation(sym);
60 if (notes->src == NULL)
61 return -ENOMEM;
62
63 pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr));
64
65 if (addr >= sym->end)
66 return 0;
67
68 offset = addr - sym->start;
69 h = annotation__histogram(notes, evidx);
70 h->sum++;
71 h->addr[offset]++;
72
73 pr_debug3("%#" PRIx64 " %s: period++ [addr: %#" PRIx64 ", %#" PRIx64
74 ", evidx=%d] => %" PRIu64 "\n", sym->start, sym->name,
75 addr, addr - sym->start, evidx, h->addr[offset]);
76 return 0;
77}
78
79static struct objdump_line *objdump_line__new(s64 offset, char *line, size_t privsize)
80{
81 struct objdump_line *self = malloc(sizeof(*self) + privsize);
82
83 if (self != NULL) {
84 self->offset = offset;
85 self->line = line;
86 }
87
88 return self;
89}
90
91void objdump_line__free(struct objdump_line *self)
92{
93 free(self->line);
94 free(self);
95}
96
97static void objdump__add_line(struct list_head *head, struct objdump_line *line)
98{
99 list_add_tail(&line->node, head);
100}
101
102struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
103 struct objdump_line *pos)
104{
105 list_for_each_entry_continue(pos, head, node)
106 if (pos->offset >= 0)
107 return pos;
108
109 return NULL;
110}
111
112static int objdump_line__print(struct objdump_line *oline, struct symbol *sym,
113 int evidx, u64 len, int min_pcnt,
114 int printed, int max_lines,
115 struct objdump_line *queue)
116{
117 static const char *prev_line;
118 static const char *prev_color;
119
120 if (oline->offset != -1) {
121 const char *path = NULL;
122 unsigned int hits = 0;
123 double percent = 0.0;
124 const char *color;
125 struct annotation *notes = symbol__annotation(sym);
126 struct source_line *src_line = notes->src->lines;
127 struct sym_hist *h = annotation__histogram(notes, evidx);
128 s64 offset = oline->offset;
129 struct objdump_line *next;
130
131 next = objdump__get_next_ip_line(&notes->src->source, oline);
132
133 while (offset < (s64)len &&
134 (next == NULL || offset < next->offset)) {
135 if (src_line) {
136 if (path == NULL)
137 path = src_line[offset].path;
138 percent += src_line[offset].percent;
139 } else
140 hits += h->addr[offset];
141
142 ++offset;
143 }
144
145 if (src_line == NULL && h->sum)
146 percent = 100.0 * hits / h->sum;
147
148 if (percent < min_pcnt)
149 return -1;
150
151 if (max_lines && printed >= max_lines)
152 return 1;
153
154 if (queue != NULL) {
155 list_for_each_entry_from(queue, &notes->src->source, node) {
156 if (queue == oline)
157 break;
158 objdump_line__print(queue, sym, evidx, len,
159 0, 0, 1, NULL);
160 }
161 }
162
163 color = get_percent_color(percent);
164
165 /*
166 * Also color the filename and line if needed, with
167 * the same color than the percentage. Don't print it
168 * twice for close colored addr with the same filename:line
169 */
170 if (path) {
171 if (!prev_line || strcmp(prev_line, path)
172 || color != prev_color) {
173 color_fprintf(stdout, color, " %s", path);
174 prev_line = path;
175 prev_color = color;
176 }
177 }
178
179 color_fprintf(stdout, color, " %7.2f", percent);
180 printf(" : ");
181 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", oline->line);
182 } else if (max_lines && printed >= max_lines)
183 return 1;
184 else {
185 if (queue)
186 return -1;
187
188 if (!*oline->line)
189 printf(" :\n");
190 else
191 printf(" : %s\n", oline->line);
192 }
193
194 return 0;
195}
196
197static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
198 FILE *file, size_t privsize)
199{
200 struct annotation *notes = symbol__annotation(sym);
201 struct objdump_line *objdump_line;
202 char *line = NULL, *tmp, *tmp2, *c;
203 size_t line_len;
204 s64 line_ip, offset = -1;
205
206 if (getline(&line, &line_len, file) < 0)
207 return -1;
208
209 if (!line)
210 return -1;
211
212 while (line_len != 0 && isspace(line[line_len - 1]))
213 line[--line_len] = '\0';
214
215 c = strchr(line, '\n');
216 if (c)
217 *c = 0;
218
219 line_ip = -1;
220
221 /*
222 * Strip leading spaces:
223 */
224 tmp = line;
225 while (*tmp) {
226 if (*tmp != ' ')
227 break;
228 tmp++;
229 }
230
231 if (*tmp) {
232 /*
233 * Parse hexa addresses followed by ':'
234 */
235 line_ip = strtoull(tmp, &tmp2, 16);
236 if (*tmp2 != ':' || tmp == tmp2 || tmp2[1] == '\0')
237 line_ip = -1;
238 }
239
240 if (line_ip != -1) {
241 u64 start = map__rip_2objdump(map, sym->start),
242 end = map__rip_2objdump(map, sym->end);
243
244 offset = line_ip - start;
245 if (offset < 0 || (u64)line_ip > end)
246 offset = -1;
247 }
248
249 objdump_line = objdump_line__new(offset, line, privsize);
250 if (objdump_line == NULL) {
251 free(line);
252 return -1;
253 }
254 objdump__add_line(&notes->src->source, objdump_line);
255
256 return 0;
257}
258
259int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
260{
261 struct dso *dso = map->dso;
262 char *filename = dso__build_id_filename(dso, NULL, 0);
263 bool free_filename = true;
264 char command[PATH_MAX * 2];
265 FILE *file;
266 int err = 0;
267 char symfs_filename[PATH_MAX];
268
269 if (filename) {
270 snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
271 symbol_conf.symfs, filename);
272 }
273
274 if (filename == NULL) {
275 if (dso->has_build_id) {
276 pr_err("Can't annotate %s: not enough memory\n",
277 sym->name);
278 return -ENOMEM;
279 }
280 goto fallback;
281 } else if (readlink(symfs_filename, command, sizeof(command)) < 0 ||
282 strstr(command, "[kernel.kallsyms]") ||
283 access(symfs_filename, R_OK)) {
284 free(filename);
285fallback:
286 /*
287 * If we don't have build-ids or the build-id file isn't in the
288 * cache, or is just a kallsyms file, well, lets hope that this
289 * DSO is the same as when 'perf record' ran.
290 */
291 filename = dso->long_name;
292 snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
293 symbol_conf.symfs, filename);
294 free_filename = false;
295 }
296
297 if (dso->symtab_type == SYMTAB__KALLSYMS) {
298 char bf[BUILD_ID_SIZE * 2 + 16] = " with build id ";
299 char *build_id_msg = NULL;
300
301 if (dso->annotate_warned)
302 goto out_free_filename;
303
304 if (dso->has_build_id) {
305 build_id__sprintf(dso->build_id,
306 sizeof(dso->build_id), bf + 15);
307 build_id_msg = bf;
308 }
309 err = -ENOENT;
310 dso->annotate_warned = 1;
311 pr_err("Can't annotate %s: No vmlinux file%s was found in the "
312 "path.\nPlease use 'perf buildid-cache -av vmlinux' or "
313 "--vmlinux vmlinux.\n",
314 sym->name, build_id_msg ?: "");
315 goto out_free_filename;
316 }
317
318 pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__,
319 filename, sym->name, map->unmap_ip(map, sym->start),
320 map->unmap_ip(map, sym->end));
321
322 pr_debug("annotating [%p] %30s : [%p] %30s\n",
323 dso, dso->long_name, sym, sym->name);
324
325 snprintf(command, sizeof(command),
326 "objdump --start-address=0x%016" PRIx64
327 " --stop-address=0x%016" PRIx64 " -dS -C %s|grep -v %s|expand",
328 map__rip_2objdump(map, sym->start),
329 map__rip_2objdump(map, sym->end),
330 symfs_filename, filename);
331
332 pr_debug("Executing: %s\n", command);
333
334 file = popen(command, "r");
335 if (!file)
336 goto out_free_filename;
337
338 while (!feof(file))
339 if (symbol__parse_objdump_line(sym, map, file, privsize) < 0)
340 break;
341
342 pclose(file);
343out_free_filename:
344 if (free_filename)
345 free(filename);
346 return err;
347}
348
349static void insert_source_line(struct rb_root *root, struct source_line *src_line)
350{
351 struct source_line *iter;
352 struct rb_node **p = &root->rb_node;
353 struct rb_node *parent = NULL;
354
355 while (*p != NULL) {
356 parent = *p;
357 iter = rb_entry(parent, struct source_line, node);
358
359 if (src_line->percent > iter->percent)
360 p = &(*p)->rb_left;
361 else
362 p = &(*p)->rb_right;
363 }
364
365 rb_link_node(&src_line->node, parent, p);
366 rb_insert_color(&src_line->node, root);
367}
368
369static void symbol__free_source_line(struct symbol *sym, int len)
370{
371 struct annotation *notes = symbol__annotation(sym);
372 struct source_line *src_line = notes->src->lines;
373 int i;
374
375 for (i = 0; i < len; i++)
376 free(src_line[i].path);
377
378 free(src_line);
379 notes->src->lines = NULL;
380}
381
382/* Get the filename:line for the colored entries */
383static int symbol__get_source_line(struct symbol *sym, struct map *map,
384 int evidx, struct rb_root *root, int len,
385 const char *filename)
386{
387 u64 start;
388 int i;
389 char cmd[PATH_MAX * 2];
390 struct source_line *src_line;
391 struct annotation *notes = symbol__annotation(sym);
392 struct sym_hist *h = annotation__histogram(notes, evidx);
393
394 if (!h->sum)
395 return 0;
396
397 src_line = notes->src->lines = calloc(len, sizeof(struct source_line));
398 if (!notes->src->lines)
399 return -1;
400
401 start = map->unmap_ip(map, sym->start);
402
403 for (i = 0; i < len; i++) {
404 char *path = NULL;
405 size_t line_len;
406 u64 offset;
407 FILE *fp;
408
409 src_line[i].percent = 100.0 * h->addr[i] / h->sum;
410 if (src_line[i].percent <= 0.5)
411 continue;
412
413 offset = start + i;
414 sprintf(cmd, "addr2line -e %s %016" PRIx64, filename, offset);
415 fp = popen(cmd, "r");
416 if (!fp)
417 continue;
418
419 if (getline(&path, &line_len, fp) < 0 || !line_len)
420 goto next;
421
422 src_line[i].path = malloc(sizeof(char) * line_len + 1);
423 if (!src_line[i].path)
424 goto next;
425
426 strcpy(src_line[i].path, path);
427 insert_source_line(root, &src_line[i]);
428
429 next:
430 pclose(fp);
431 }
432
433 return 0;
434}
435
436static void print_summary(struct rb_root *root, const char *filename)
437{
438 struct source_line *src_line;
439 struct rb_node *node;
440
441 printf("\nSorted summary for file %s\n", filename);
442 printf("----------------------------------------------\n\n");
443
444 if (RB_EMPTY_ROOT(root)) {
445 printf(" Nothing higher than %1.1f%%\n", MIN_GREEN);
446 return;
447 }
448
449 node = rb_first(root);
450 while (node) {
451 double percent;
452 const char *color;
453 char *path;
454
455 src_line = rb_entry(node, struct source_line, node);
456 percent = src_line->percent;
457 color = get_percent_color(percent);
458 path = src_line->path;
459
460 color_fprintf(stdout, color, " %7.2f %s", percent, path);
461 node = rb_next(node);
462 }
463}
464
465static void symbol__annotate_hits(struct symbol *sym, int evidx)
466{
467 struct annotation *notes = symbol__annotation(sym);
468 struct sym_hist *h = annotation__histogram(notes, evidx);
469 u64 len = sym->end - sym->start, offset;
470
471 for (offset = 0; offset < len; ++offset)
472 if (h->addr[offset] != 0)
473 printf("%*" PRIx64 ": %" PRIu64 "\n", BITS_PER_LONG / 2,
474 sym->start + offset, h->addr[offset]);
475 printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum);
476}
477
478int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
479 bool full_paths, int min_pcnt, int max_lines,
480 int context)
481{
482 struct dso *dso = map->dso;
483 const char *filename = dso->long_name, *d_filename;
484 struct annotation *notes = symbol__annotation(sym);
485 struct objdump_line *pos, *queue = NULL;
486 int printed = 2, queue_len = 0;
487 int more = 0;
488 u64 len;
489
490 if (full_paths)
491 d_filename = filename;
492 else
493 d_filename = basename(filename);
494
495 len = sym->end - sym->start;
496
497 printf(" Percent | Source code & Disassembly of %s\n", d_filename);
498 printf("------------------------------------------------\n");
499
500 if (verbose)
501 symbol__annotate_hits(sym, evidx);
502
503 list_for_each_entry(pos, &notes->src->source, node) {
504 if (context && queue == NULL) {
505 queue = pos;
506 queue_len = 0;
507 }
508
509 switch (objdump_line__print(pos, sym, evidx, len, min_pcnt,
510 printed, max_lines, queue)) {
511 case 0:
512 ++printed;
513 if (context) {
514 printed += queue_len;
515 queue = NULL;
516 queue_len = 0;
517 }
518 break;
519 case 1:
520 /* filtered by max_lines */
521 ++more;
522 break;
523 case -1:
524 default:
525 /*
526 * Filtered by min_pcnt or non IP lines when
527 * context != 0
528 */
529 if (!context)
530 break;
531 if (queue_len == context)
532 queue = list_entry(queue->node.next, typeof(*queue), node);
533 else
534 ++queue_len;
535 break;
536 }
537 }
538
539 return more;
540}
541
542void symbol__annotate_zero_histogram(struct symbol *sym, int evidx)
543{
544 struct annotation *notes = symbol__annotation(sym);
545 struct sym_hist *h = annotation__histogram(notes, evidx);
546
547 memset(h, 0, notes->src->sizeof_sym_hist);
548}
549
550void symbol__annotate_decay_histogram(struct symbol *sym, int evidx)
551{
552 struct annotation *notes = symbol__annotation(sym);
553 struct sym_hist *h = annotation__histogram(notes, evidx);
554 struct objdump_line *pos;
555 int len = sym->end - sym->start;
556
557 h->sum = 0;
558
559 list_for_each_entry(pos, &notes->src->source, node) {
560 if (pos->offset != -1 && pos->offset < len) {
561 h->addr[pos->offset] = h->addr[pos->offset] * 7 / 8;
562 h->sum += h->addr[pos->offset];
563 }
564 }
565}
566
567void objdump_line_list__purge(struct list_head *head)
568{
569 struct objdump_line *pos, *n;
570
571 list_for_each_entry_safe(pos, n, head, node) {
572 list_del(&pos->node);
573 objdump_line__free(pos);
574 }
575}
576
577int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
578 bool print_lines, bool full_paths, int min_pcnt,
579 int max_lines)
580{
581 struct dso *dso = map->dso;
582 const char *filename = dso->long_name;
583 struct rb_root source_line = RB_ROOT;
584 u64 len;
585
586 if (symbol__annotate(sym, map, 0) < 0)
587 return -1;
588
589 len = sym->end - sym->start;
590
591 if (print_lines) {
592 symbol__get_source_line(sym, map, evidx, &source_line,
593 len, filename);
594 print_summary(&source_line, filename);
595 }
596
597 symbol__annotate_printf(sym, map, evidx, full_paths,
598 min_pcnt, max_lines, 0);
599 if (print_lines)
600 symbol__free_source_line(sym, len);
601
602 objdump_line_list__purge(&symbol__annotation(sym)->src->source);
603
604 return 0;
605}
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
new file mode 100644
index 000000000000..c2c286896801
--- /dev/null
+++ b/tools/perf/util/annotate.h
@@ -0,0 +1,103 @@
1#ifndef __PERF_ANNOTATE_H
2#define __PERF_ANNOTATE_H
3
4#include <stdbool.h>
5#include "types.h"
6#include "symbol.h"
7#include <linux/list.h>
8#include <linux/rbtree.h>
9
10struct objdump_line {
11 struct list_head node;
12 s64 offset;
13 char *line;
14};
15
16void objdump_line__free(struct objdump_line *self);
17struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
18 struct objdump_line *pos);
19
20struct sym_hist {
21 u64 sum;
22 u64 addr[0];
23};
24
25struct source_line {
26 struct rb_node node;
27 double percent;
28 char *path;
29};
30
31/** struct annotated_source - symbols with hits have this attached as in sannotation
32 *
33 * @histogram: Array of addr hit histograms per event being monitored
34 * @lines: If 'print_lines' is specified, per source code line percentages
35 * @source: source parsed from objdump -dS
36 *
37 * lines is allocated, percentages calculated and all sorted by percentage
38 * when the annotation is about to be presented, so the percentages are for
39 * one of the entries in the histogram array, i.e. for the event/counter being
40 * presented. It is deallocated right after symbol__{tui,tty,etc}_annotate
41 * returns.
42 */
43struct annotated_source {
44 struct list_head source;
45 struct source_line *lines;
46 int nr_histograms;
47 int sizeof_sym_hist;
48 struct sym_hist histograms[0];
49};
50
51struct annotation {
52 pthread_mutex_t lock;
53 struct annotated_source *src;
54};
55
56struct sannotation {
57 struct annotation annotation;
58 struct symbol symbol;
59};
60
61static inline struct sym_hist *annotation__histogram(struct annotation *notes, int idx)
62{
63 return (((void *)&notes->src->histograms) +
64 (notes->src->sizeof_sym_hist * idx));
65}
66
67static inline struct annotation *symbol__annotation(struct symbol *sym)
68{
69 struct sannotation *a = container_of(sym, struct sannotation, symbol);
70 return &a->annotation;
71}
72
73int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
74 int evidx, u64 addr);
75int symbol__alloc_hist(struct symbol *sym, int nevents);
76void symbol__annotate_zero_histograms(struct symbol *sym);
77
78int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize);
79int symbol__annotate_init(struct map *map __used, struct symbol *sym);
80int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
81 bool full_paths, int min_pcnt, int max_lines,
82 int context);
83void symbol__annotate_zero_histogram(struct symbol *sym, int evidx);
84void symbol__annotate_decay_histogram(struct symbol *sym, int evidx);
85void objdump_line_list__purge(struct list_head *head);
86
87int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
88 bool print_lines, bool full_paths, int min_pcnt,
89 int max_lines);
90
91#ifdef NO_NEWT_SUPPORT
92static inline int symbol__tui_annotate(struct symbol *sym __used,
93 struct map *map __used,
94 int evidx __used, int refresh __used)
95{
96 return 0;
97}
98#else
99int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
100 int refresh);
101#endif
102
103#endif /* __PERF_ANNOTATE_H */
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index e437edb72417..a91cd99f26ea 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -14,7 +14,10 @@
14#include <linux/kernel.h> 14#include <linux/kernel.h>
15#include "debug.h" 15#include "debug.h"
16 16
17static int build_id__mark_dso_hit(event_t *event, struct perf_session *session) 17static int build_id__mark_dso_hit(union perf_event *event,
18 struct perf_sample *sample __used,
19 struct perf_evsel *evsel __used,
20 struct perf_session *session)
18{ 21{
19 struct addr_location al; 22 struct addr_location al;
20 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 23 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
@@ -35,12 +38,14 @@ static int build_id__mark_dso_hit(event_t *event, struct perf_session *session)
35 return 0; 38 return 0;
36} 39}
37 40
38static int event__exit_del_thread(event_t *self, struct perf_session *session) 41static int perf_event__exit_del_thread(union perf_event *event,
42 struct perf_sample *sample __used,
43 struct perf_session *session)
39{ 44{
40 struct thread *thread = perf_session__findnew(session, self->fork.tid); 45 struct thread *thread = perf_session__findnew(session, event->fork.tid);
41 46
42 dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid, 47 dump_printf("(%d:%d):(%d:%d)\n", event->fork.pid, event->fork.tid,
43 self->fork.ppid, self->fork.ptid); 48 event->fork.ppid, event->fork.ptid);
44 49
45 if (thread) { 50 if (thread) {
46 rb_erase(&thread->rb_node, &session->threads); 51 rb_erase(&thread->rb_node, &session->threads);
@@ -53,9 +58,9 @@ static int event__exit_del_thread(event_t *self, struct perf_session *session)
53 58
54struct perf_event_ops build_id__mark_dso_hit_ops = { 59struct perf_event_ops build_id__mark_dso_hit_ops = {
55 .sample = build_id__mark_dso_hit, 60 .sample = build_id__mark_dso_hit,
56 .mmap = event__process_mmap, 61 .mmap = perf_event__process_mmap,
57 .fork = event__process_task, 62 .fork = perf_event__process_task,
58 .exit = event__exit_del_thread, 63 .exit = perf_event__exit_del_thread,
59}; 64};
60 65
61char *dso__build_id_filename(struct dso *self, char *bf, size_t size) 66char *dso__build_id_filename(struct dso *self, char *bf, size_t size)
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index 27e9ebe4076e..fc5e5a09d5b9 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -34,13 +34,14 @@ extern int pager_use_color;
34extern int use_browser; 34extern int use_browser;
35 35
36#ifdef NO_NEWT_SUPPORT 36#ifdef NO_NEWT_SUPPORT
37static inline void setup_browser(void) 37static inline void setup_browser(bool fallback_to_pager)
38{ 38{
39 setup_pager(); 39 if (fallback_to_pager)
40 setup_pager();
40} 41}
41static inline void exit_browser(bool wait_for_ok __used) {} 42static inline void exit_browser(bool wait_for_ok __used) {}
42#else 43#else
43void setup_browser(void); 44void setup_browser(bool fallback_to_pager);
44void exit_browser(bool wait_for_ok); 45void exit_browser(bool wait_for_ok);
45#endif 46#endif
46 47
@@ -82,6 +83,8 @@ extern char *perf_path(const char *fmt, ...) __attribute__((format (printf, 1, 2
82extern char *perf_pathdup(const char *fmt, ...) 83extern char *perf_pathdup(const char *fmt, ...)
83 __attribute__((format (printf, 1, 2))); 84 __attribute__((format (printf, 1, 2)));
84 85
86#ifdef NO_STRLCPY
85extern size_t strlcpy(char *dest, const char *src, size_t size); 87extern size_t strlcpy(char *dest, const char *src, size_t size);
88#endif
86 89
87#endif /* __PERF_CACHE_H */ 90#endif /* __PERF_CACHE_H */
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index f231f43424d2..9f7106a8d9a4 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (C) 2009-2010, Frederic Weisbecker <fweisbec@gmail.com> 2 * Copyright (C) 2009-2011, Frederic Weisbecker <fweisbec@gmail.com>
3 * 3 *
4 * Handle the callchains from the stream in an ad-hoc radix tree and then 4 * Handle the callchains from the stream in an ad-hoc radix tree and then
5 * sort them in an rbtree. 5 * sort them in an rbtree.
@@ -18,7 +18,8 @@
18#include "util.h" 18#include "util.h"
19#include "callchain.h" 19#include "callchain.h"
20 20
21bool ip_callchain__valid(struct ip_callchain *chain, const event_t *event) 21bool ip_callchain__valid(struct ip_callchain *chain,
22 const union perf_event *event)
22{ 23{
23 unsigned int chain_size = event->header.size; 24 unsigned int chain_size = event->header.size;
24 chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event; 25 chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event;
@@ -26,7 +27,10 @@ bool ip_callchain__valid(struct ip_callchain *chain, const event_t *event)
26} 27}
27 28
28#define chain_for_each_child(child, parent) \ 29#define chain_for_each_child(child, parent) \
29 list_for_each_entry(child, &parent->children, brothers) 30 list_for_each_entry(child, &parent->children, siblings)
31
32#define chain_for_each_child_safe(child, next, parent) \
33 list_for_each_entry_safe(child, next, &parent->children, siblings)
30 34
31static void 35static void
32rb_insert_callchain(struct rb_root *root, struct callchain_node *chain, 36rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
@@ -35,14 +39,14 @@ rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
35 struct rb_node **p = &root->rb_node; 39 struct rb_node **p = &root->rb_node;
36 struct rb_node *parent = NULL; 40 struct rb_node *parent = NULL;
37 struct callchain_node *rnode; 41 struct callchain_node *rnode;
38 u64 chain_cumul = cumul_hits(chain); 42 u64 chain_cumul = callchain_cumul_hits(chain);
39 43
40 while (*p) { 44 while (*p) {
41 u64 rnode_cumul; 45 u64 rnode_cumul;
42 46
43 parent = *p; 47 parent = *p;
44 rnode = rb_entry(parent, struct callchain_node, rb_node); 48 rnode = rb_entry(parent, struct callchain_node, rb_node);
45 rnode_cumul = cumul_hits(rnode); 49 rnode_cumul = callchain_cumul_hits(rnode);
46 50
47 switch (mode) { 51 switch (mode) {
48 case CHAIN_FLAT: 52 case CHAIN_FLAT:
@@ -86,10 +90,10 @@ __sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
86 * sort them by hit 90 * sort them by hit
87 */ 91 */
88static void 92static void
89sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node, 93sort_chain_flat(struct rb_root *rb_root, struct callchain_root *root,
90 u64 min_hit, struct callchain_param *param __used) 94 u64 min_hit, struct callchain_param *param __used)
91{ 95{
92 __sort_chain_flat(rb_root, node, min_hit); 96 __sort_chain_flat(rb_root, &root->node, min_hit);
93} 97}
94 98
95static void __sort_chain_graph_abs(struct callchain_node *node, 99static void __sort_chain_graph_abs(struct callchain_node *node,
@@ -101,18 +105,18 @@ static void __sort_chain_graph_abs(struct callchain_node *node,
101 105
102 chain_for_each_child(child, node) { 106 chain_for_each_child(child, node) {
103 __sort_chain_graph_abs(child, min_hit); 107 __sort_chain_graph_abs(child, min_hit);
104 if (cumul_hits(child) >= min_hit) 108 if (callchain_cumul_hits(child) >= min_hit)
105 rb_insert_callchain(&node->rb_root, child, 109 rb_insert_callchain(&node->rb_root, child,
106 CHAIN_GRAPH_ABS); 110 CHAIN_GRAPH_ABS);
107 } 111 }
108} 112}
109 113
110static void 114static void
111sort_chain_graph_abs(struct rb_root *rb_root, struct callchain_node *chain_root, 115sort_chain_graph_abs(struct rb_root *rb_root, struct callchain_root *chain_root,
112 u64 min_hit, struct callchain_param *param __used) 116 u64 min_hit, struct callchain_param *param __used)
113{ 117{
114 __sort_chain_graph_abs(chain_root, min_hit); 118 __sort_chain_graph_abs(&chain_root->node, min_hit);
115 rb_root->rb_node = chain_root->rb_root.rb_node; 119 rb_root->rb_node = chain_root->node.rb_root.rb_node;
116} 120}
117 121
118static void __sort_chain_graph_rel(struct callchain_node *node, 122static void __sort_chain_graph_rel(struct callchain_node *node,
@@ -126,21 +130,21 @@ static void __sort_chain_graph_rel(struct callchain_node *node,
126 130
127 chain_for_each_child(child, node) { 131 chain_for_each_child(child, node) {
128 __sort_chain_graph_rel(child, min_percent); 132 __sort_chain_graph_rel(child, min_percent);
129 if (cumul_hits(child) >= min_hit) 133 if (callchain_cumul_hits(child) >= min_hit)
130 rb_insert_callchain(&node->rb_root, child, 134 rb_insert_callchain(&node->rb_root, child,
131 CHAIN_GRAPH_REL); 135 CHAIN_GRAPH_REL);
132 } 136 }
133} 137}
134 138
135static void 139static void
136sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_node *chain_root, 140sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_root *chain_root,
137 u64 min_hit __used, struct callchain_param *param) 141 u64 min_hit __used, struct callchain_param *param)
138{ 142{
139 __sort_chain_graph_rel(chain_root, param->min_percent / 100.0); 143 __sort_chain_graph_rel(&chain_root->node, param->min_percent / 100.0);
140 rb_root->rb_node = chain_root->rb_root.rb_node; 144 rb_root->rb_node = chain_root->node.rb_root.rb_node;
141} 145}
142 146
143int register_callchain_param(struct callchain_param *param) 147int callchain_register_param(struct callchain_param *param)
144{ 148{
145 switch (param->mode) { 149 switch (param->mode) {
146 case CHAIN_GRAPH_ABS: 150 case CHAIN_GRAPH_ABS:
@@ -186,32 +190,27 @@ create_child(struct callchain_node *parent, bool inherit_children)
186 chain_for_each_child(next, new) 190 chain_for_each_child(next, new)
187 next->parent = new; 191 next->parent = new;
188 } 192 }
189 list_add_tail(&new->brothers, &parent->children); 193 list_add_tail(&new->siblings, &parent->children);
190 194
191 return new; 195 return new;
192} 196}
193 197
194 198
195struct resolved_ip {
196 u64 ip;
197 struct map_symbol ms;
198};
199
200struct resolved_chain {
201 u64 nr;
202 struct resolved_ip ips[0];
203};
204
205
206/* 199/*
207 * Fill the node with callchain values 200 * Fill the node with callchain values
208 */ 201 */
209static void 202static void
210fill_node(struct callchain_node *node, struct resolved_chain *chain, int start) 203fill_node(struct callchain_node *node, struct callchain_cursor *cursor)
211{ 204{
212 unsigned int i; 205 struct callchain_cursor_node *cursor_node;
213 206
214 for (i = start; i < chain->nr; i++) { 207 node->val_nr = cursor->nr - cursor->pos;
208 if (!node->val_nr)
209 pr_warning("Warning: empty node in callchain tree\n");
210
211 cursor_node = callchain_cursor_current(cursor);
212
213 while (cursor_node) {
215 struct callchain_list *call; 214 struct callchain_list *call;
216 215
217 call = zalloc(sizeof(*call)); 216 call = zalloc(sizeof(*call));
@@ -219,23 +218,25 @@ fill_node(struct callchain_node *node, struct resolved_chain *chain, int start)
219 perror("not enough memory for the code path tree"); 218 perror("not enough memory for the code path tree");
220 return; 219 return;
221 } 220 }
222 call->ip = chain->ips[i].ip; 221 call->ip = cursor_node->ip;
223 call->ms = chain->ips[i].ms; 222 call->ms.sym = cursor_node->sym;
223 call->ms.map = cursor_node->map;
224 list_add_tail(&call->list, &node->val); 224 list_add_tail(&call->list, &node->val);
225
226 callchain_cursor_advance(cursor);
227 cursor_node = callchain_cursor_current(cursor);
225 } 228 }
226 node->val_nr = chain->nr - start;
227 if (!node->val_nr)
228 pr_warning("Warning: empty node in callchain tree\n");
229} 229}
230 230
231static void 231static void
232add_child(struct callchain_node *parent, struct resolved_chain *chain, 232add_child(struct callchain_node *parent,
233 int start, u64 period) 233 struct callchain_cursor *cursor,
234 u64 period)
234{ 235{
235 struct callchain_node *new; 236 struct callchain_node *new;
236 237
237 new = create_child(parent, false); 238 new = create_child(parent, false);
238 fill_node(new, chain, start); 239 fill_node(new, cursor);
239 240
240 new->children_hit = 0; 241 new->children_hit = 0;
241 new->hit = period; 242 new->hit = period;
@@ -247,9 +248,10 @@ add_child(struct callchain_node *parent, struct resolved_chain *chain,
247 * Then create another child to host the given callchain of new branch 248 * Then create another child to host the given callchain of new branch
248 */ 249 */
249static void 250static void
250split_add_child(struct callchain_node *parent, struct resolved_chain *chain, 251split_add_child(struct callchain_node *parent,
251 struct callchain_list *to_split, int idx_parents, int idx_local, 252 struct callchain_cursor *cursor,
252 u64 period) 253 struct callchain_list *to_split,
254 u64 idx_parents, u64 idx_local, u64 period)
253{ 255{
254 struct callchain_node *new; 256 struct callchain_node *new;
255 struct list_head *old_tail; 257 struct list_head *old_tail;
@@ -269,14 +271,14 @@ split_add_child(struct callchain_node *parent, struct resolved_chain *chain,
269 /* split the hits */ 271 /* split the hits */
270 new->hit = parent->hit; 272 new->hit = parent->hit;
271 new->children_hit = parent->children_hit; 273 new->children_hit = parent->children_hit;
272 parent->children_hit = cumul_hits(new); 274 parent->children_hit = callchain_cumul_hits(new);
273 new->val_nr = parent->val_nr - idx_local; 275 new->val_nr = parent->val_nr - idx_local;
274 parent->val_nr = idx_local; 276 parent->val_nr = idx_local;
275 277
276 /* create a new child for the new branch if any */ 278 /* create a new child for the new branch if any */
277 if (idx_total < chain->nr) { 279 if (idx_total < cursor->nr) {
278 parent->hit = 0; 280 parent->hit = 0;
279 add_child(parent, chain, idx_total, period); 281 add_child(parent, cursor, period);
280 parent->children_hit += period; 282 parent->children_hit += period;
281 } else { 283 } else {
282 parent->hit = period; 284 parent->hit = period;
@@ -284,37 +286,41 @@ split_add_child(struct callchain_node *parent, struct resolved_chain *chain,
284} 286}
285 287
286static int 288static int
287__append_chain(struct callchain_node *root, struct resolved_chain *chain, 289append_chain(struct callchain_node *root,
288 unsigned int start, u64 period); 290 struct callchain_cursor *cursor,
291 u64 period);
289 292
290static void 293static void
291__append_chain_children(struct callchain_node *root, 294append_chain_children(struct callchain_node *root,
292 struct resolved_chain *chain, 295 struct callchain_cursor *cursor,
293 unsigned int start, u64 period) 296 u64 period)
294{ 297{
295 struct callchain_node *rnode; 298 struct callchain_node *rnode;
296 299
297 /* lookup in childrens */ 300 /* lookup in childrens */
298 chain_for_each_child(rnode, root) { 301 chain_for_each_child(rnode, root) {
299 unsigned int ret = __append_chain(rnode, chain, start, period); 302 unsigned int ret = append_chain(rnode, cursor, period);
300 303
301 if (!ret) 304 if (!ret)
302 goto inc_children_hit; 305 goto inc_children_hit;
303 } 306 }
304 /* nothing in children, add to the current node */ 307 /* nothing in children, add to the current node */
305 add_child(root, chain, start, period); 308 add_child(root, cursor, period);
306 309
307inc_children_hit: 310inc_children_hit:
308 root->children_hit += period; 311 root->children_hit += period;
309} 312}
310 313
311static int 314static int
312__append_chain(struct callchain_node *root, struct resolved_chain *chain, 315append_chain(struct callchain_node *root,
313 unsigned int start, u64 period) 316 struct callchain_cursor *cursor,
317 u64 period)
314{ 318{
319 struct callchain_cursor_node *curr_snap = cursor->curr;
315 struct callchain_list *cnode; 320 struct callchain_list *cnode;
316 unsigned int i = start; 321 u64 start = cursor->pos;
317 bool found = false; 322 bool found = false;
323 u64 matches;
318 324
319 /* 325 /*
320 * Lookup in the current node 326 * Lookup in the current node
@@ -322,85 +328,134 @@ __append_chain(struct callchain_node *root, struct resolved_chain *chain,
322 * anywhere inside a function. 328 * anywhere inside a function.
323 */ 329 */
324 list_for_each_entry(cnode, &root->val, list) { 330 list_for_each_entry(cnode, &root->val, list) {
331 struct callchain_cursor_node *node;
325 struct symbol *sym; 332 struct symbol *sym;
326 333
327 if (i == chain->nr) 334 node = callchain_cursor_current(cursor);
335 if (!node)
328 break; 336 break;
329 337
330 sym = chain->ips[i].ms.sym; 338 sym = node->sym;
331 339
332 if (cnode->ms.sym && sym) { 340 if (cnode->ms.sym && sym) {
333 if (cnode->ms.sym->start != sym->start) 341 if (cnode->ms.sym->start != sym->start)
334 break; 342 break;
335 } else if (cnode->ip != chain->ips[i].ip) 343 } else if (cnode->ip != node->ip)
336 break; 344 break;
337 345
338 if (!found) 346 if (!found)
339 found = true; 347 found = true;
340 i++; 348
349 callchain_cursor_advance(cursor);
341 } 350 }
342 351
343 /* matches not, relay on the parent */ 352 /* matches not, relay on the parent */
344 if (!found) 353 if (!found) {
354 cursor->curr = curr_snap;
355 cursor->pos = start;
345 return -1; 356 return -1;
357 }
358
359 matches = cursor->pos - start;
346 360
347 /* we match only a part of the node. Split it and add the new chain */ 361 /* we match only a part of the node. Split it and add the new chain */
348 if (i - start < root->val_nr) { 362 if (matches < root->val_nr) {
349 split_add_child(root, chain, cnode, start, i - start, period); 363 split_add_child(root, cursor, cnode, start, matches, period);
350 return 0; 364 return 0;
351 } 365 }
352 366
353 /* we match 100% of the path, increment the hit */ 367 /* we match 100% of the path, increment the hit */
354 if (i - start == root->val_nr && i == chain->nr) { 368 if (matches == root->val_nr && cursor->pos == cursor->nr) {
355 root->hit += period; 369 root->hit += period;
356 return 0; 370 return 0;
357 } 371 }
358 372
359 /* We match the node and still have a part remaining */ 373 /* We match the node and still have a part remaining */
360 __append_chain_children(root, chain, i, period); 374 append_chain_children(root, cursor, period);
361 375
362 return 0; 376 return 0;
363} 377}
364 378
365static void filter_context(struct ip_callchain *old, struct resolved_chain *new, 379int callchain_append(struct callchain_root *root,
366 struct map_symbol *syms) 380 struct callchain_cursor *cursor,
381 u64 period)
367{ 382{
368 int i, j = 0; 383 if (!cursor->nr)
384 return 0;
385
386 callchain_cursor_commit(cursor);
387
388 append_chain_children(&root->node, cursor, period);
369 389
370 for (i = 0; i < (int)old->nr; i++) { 390 if (cursor->nr > root->max_depth)
371 if (old->ips[i] >= PERF_CONTEXT_MAX) 391 root->max_depth = cursor->nr;
372 continue;
373 392
374 new->ips[j].ip = old->ips[i]; 393 return 0;
375 new->ips[j].ms = syms[i]; 394}
376 j++; 395
396static int
397merge_chain_branch(struct callchain_cursor *cursor,
398 struct callchain_node *dst, struct callchain_node *src)
399{
400 struct callchain_cursor_node **old_last = cursor->last;
401 struct callchain_node *child, *next_child;
402 struct callchain_list *list, *next_list;
403 int old_pos = cursor->nr;
404 int err = 0;
405
406 list_for_each_entry_safe(list, next_list, &src->val, list) {
407 callchain_cursor_append(cursor, list->ip,
408 list->ms.map, list->ms.sym);
409 list_del(&list->list);
410 free(list);
411 }
412
413 if (src->hit) {
414 callchain_cursor_commit(cursor);
415 append_chain_children(dst, cursor, src->hit);
416 }
417
418 chain_for_each_child_safe(child, next_child, src) {
419 err = merge_chain_branch(cursor, dst, child);
420 if (err)
421 break;
422
423 list_del(&child->siblings);
424 free(child);
377 } 425 }
378 426
379 new->nr = j; 427 cursor->nr = old_pos;
428 cursor->last = old_last;
429
430 return err;
380} 431}
381 432
433int callchain_merge(struct callchain_cursor *cursor,
434 struct callchain_root *dst, struct callchain_root *src)
435{
436 return merge_chain_branch(cursor, &dst->node, &src->node);
437}
382 438
383int append_chain(struct callchain_node *root, struct ip_callchain *chain, 439int callchain_cursor_append(struct callchain_cursor *cursor,
384 struct map_symbol *syms, u64 period) 440 u64 ip, struct map *map, struct symbol *sym)
385{ 441{
386 struct resolved_chain *filtered; 442 struct callchain_cursor_node *node = *cursor->last;
387 443
388 if (!chain->nr) 444 if (!node) {
389 return 0; 445 node = calloc(sizeof(*node), 1);
446 if (!node)
447 return -ENOMEM;
390 448
391 filtered = zalloc(sizeof(*filtered) + 449 *cursor->last = node;
392 chain->nr * sizeof(struct resolved_ip)); 450 }
393 if (!filtered)
394 return -ENOMEM;
395 451
396 filter_context(chain, filtered, syms); 452 node->ip = ip;
453 node->map = map;
454 node->sym = sym;
397 455
398 if (!filtered->nr) 456 cursor->nr++;
399 goto end;
400 457
401 __append_chain_children(root, filtered, 0, period); 458 cursor->last = &node->next;
402end:
403 free(filtered);
404 459
405 return 0; 460 return 0;
406} 461}
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 6de4313924fb..1a79df9f739f 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -16,7 +16,7 @@ enum chain_mode {
16 16
17struct callchain_node { 17struct callchain_node {
18 struct callchain_node *parent; 18 struct callchain_node *parent;
19 struct list_head brothers; 19 struct list_head siblings;
20 struct list_head children; 20 struct list_head children;
21 struct list_head val; 21 struct list_head val;
22 struct rb_node rb_node; /* to sort nodes in an rbtree */ 22 struct rb_node rb_node; /* to sort nodes in an rbtree */
@@ -26,9 +26,14 @@ struct callchain_node {
26 u64 children_hit; 26 u64 children_hit;
27}; 27};
28 28
29struct callchain_root {
30 u64 max_depth;
31 struct callchain_node node;
32};
33
29struct callchain_param; 34struct callchain_param;
30 35
31typedef void (*sort_chain_func_t)(struct rb_root *, struct callchain_node *, 36typedef void (*sort_chain_func_t)(struct rb_root *, struct callchain_root *,
32 u64, struct callchain_param *); 37 u64, struct callchain_param *);
33 38
34struct callchain_param { 39struct callchain_param {
@@ -44,25 +49,87 @@ struct callchain_list {
44 struct list_head list; 49 struct list_head list;
45}; 50};
46 51
47static inline void callchain_init(struct callchain_node *node) 52/*
53 * A callchain cursor is a single linked list that
54 * let one feed a callchain progressively.
55 * It keeps persitent allocated entries to minimize
56 * allocations.
57 */
58struct callchain_cursor_node {
59 u64 ip;
60 struct map *map;
61 struct symbol *sym;
62 struct callchain_cursor_node *next;
63};
64
65struct callchain_cursor {
66 u64 nr;
67 struct callchain_cursor_node *first;
68 struct callchain_cursor_node **last;
69 u64 pos;
70 struct callchain_cursor_node *curr;
71};
72
73static inline void callchain_init(struct callchain_root *root)
48{ 74{
49 INIT_LIST_HEAD(&node->brothers); 75 INIT_LIST_HEAD(&root->node.siblings);
50 INIT_LIST_HEAD(&node->children); 76 INIT_LIST_HEAD(&root->node.children);
51 INIT_LIST_HEAD(&node->val); 77 INIT_LIST_HEAD(&root->node.val);
52 78
53 node->children_hit = 0; 79 root->node.parent = NULL;
54 node->parent = NULL; 80 root->node.hit = 0;
55 node->hit = 0; 81 root->node.children_hit = 0;
82 root->max_depth = 0;
56} 83}
57 84
58static inline u64 cumul_hits(struct callchain_node *node) 85static inline u64 callchain_cumul_hits(struct callchain_node *node)
59{ 86{
60 return node->hit + node->children_hit; 87 return node->hit + node->children_hit;
61} 88}
62 89
63int register_callchain_param(struct callchain_param *param); 90int callchain_register_param(struct callchain_param *param);
64int append_chain(struct callchain_node *root, struct ip_callchain *chain, 91int callchain_append(struct callchain_root *root,
65 struct map_symbol *syms, u64 period); 92 struct callchain_cursor *cursor,
93 u64 period);
94
95int callchain_merge(struct callchain_cursor *cursor,
96 struct callchain_root *dst, struct callchain_root *src);
97
98bool ip_callchain__valid(struct ip_callchain *chain,
99 const union perf_event *event);
100/*
101 * Initialize a cursor before adding entries inside, but keep
102 * the previously allocated entries as a cache.
103 */
104static inline void callchain_cursor_reset(struct callchain_cursor *cursor)
105{
106 cursor->nr = 0;
107 cursor->last = &cursor->first;
108}
109
110int callchain_cursor_append(struct callchain_cursor *cursor, u64 ip,
111 struct map *map, struct symbol *sym);
112
113/* Close a cursor writing session. Initialize for the reader */
114static inline void callchain_cursor_commit(struct callchain_cursor *cursor)
115{
116 cursor->curr = cursor->first;
117 cursor->pos = 0;
118}
119
120/* Cursor reading iteration helpers */
121static inline struct callchain_cursor_node *
122callchain_cursor_current(struct callchain_cursor *cursor)
123{
124 if (cursor->pos == cursor->nr)
125 return NULL;
126
127 return cursor->curr;
128}
66 129
67bool ip_callchain__valid(struct ip_callchain *chain, const event_t *event); 130static inline void callchain_cursor_advance(struct callchain_cursor *cursor)
131{
132 cursor->curr = cursor->curr->next;
133 cursor->pos++;
134}
68#endif /* __PERF_CALLCHAIN_H */ 135#endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c
new file mode 100644
index 000000000000..96bee5c46008
--- /dev/null
+++ b/tools/perf/util/cgroup.c
@@ -0,0 +1,178 @@
1#include "util.h"
2#include "../perf.h"
3#include "parse-options.h"
4#include "evsel.h"
5#include "cgroup.h"
6#include "debugfs.h" /* MAX_PATH, STR() */
7#include "evlist.h"
8
9int nr_cgroups;
10
11static int
12cgroupfs_find_mountpoint(char *buf, size_t maxlen)
13{
14 FILE *fp;
15 char mountpoint[MAX_PATH+1], tokens[MAX_PATH+1], type[MAX_PATH+1];
16 char *token, *saved_ptr = NULL;
17 int found = 0;
18
19 fp = fopen("/proc/mounts", "r");
20 if (!fp)
21 return -1;
22
23 /*
24 * in order to handle split hierarchy, we need to scan /proc/mounts
25 * and inspect every cgroupfs mount point to find one that has
26 * perf_event subsystem
27 */
28 while (fscanf(fp, "%*s %"STR(MAX_PATH)"s %"STR(MAX_PATH)"s %"
29 STR(MAX_PATH)"s %*d %*d\n",
30 mountpoint, type, tokens) == 3) {
31
32 if (!strcmp(type, "cgroup")) {
33
34 token = strtok_r(tokens, ",", &saved_ptr);
35
36 while (token != NULL) {
37 if (!strcmp(token, "perf_event")) {
38 found = 1;
39 break;
40 }
41 token = strtok_r(NULL, ",", &saved_ptr);
42 }
43 }
44 if (found)
45 break;
46 }
47 fclose(fp);
48 if (!found)
49 return -1;
50
51 if (strlen(mountpoint) < maxlen) {
52 strcpy(buf, mountpoint);
53 return 0;
54 }
55 return -1;
56}
57
58static int open_cgroup(char *name)
59{
60 char path[MAX_PATH+1];
61 char mnt[MAX_PATH+1];
62 int fd;
63
64
65 if (cgroupfs_find_mountpoint(mnt, MAX_PATH+1))
66 return -1;
67
68 snprintf(path, MAX_PATH, "%s/%s", mnt, name);
69
70 fd = open(path, O_RDONLY);
71 if (fd == -1)
72 fprintf(stderr, "no access to cgroup %s\n", path);
73
74 return fd;
75}
76
77static int add_cgroup(struct perf_evlist *evlist, char *str)
78{
79 struct perf_evsel *counter;
80 struct cgroup_sel *cgrp = NULL;
81 int n;
82 /*
83 * check if cgrp is already defined, if so we reuse it
84 */
85 list_for_each_entry(counter, &evlist->entries, node) {
86 cgrp = counter->cgrp;
87 if (!cgrp)
88 continue;
89 if (!strcmp(cgrp->name, str))
90 break;
91
92 cgrp = NULL;
93 }
94
95 if (!cgrp) {
96 cgrp = zalloc(sizeof(*cgrp));
97 if (!cgrp)
98 return -1;
99
100 cgrp->name = str;
101
102 cgrp->fd = open_cgroup(str);
103 if (cgrp->fd == -1) {
104 free(cgrp);
105 return -1;
106 }
107 }
108
109 /*
110 * find corresponding event
111 * if add cgroup N, then need to find event N
112 */
113 n = 0;
114 list_for_each_entry(counter, &evlist->entries, node) {
115 if (n == nr_cgroups)
116 goto found;
117 n++;
118 }
119 if (cgrp->refcnt == 0)
120 free(cgrp);
121
122 return -1;
123found:
124 cgrp->refcnt++;
125 counter->cgrp = cgrp;
126 return 0;
127}
128
129void close_cgroup(struct cgroup_sel *cgrp)
130{
131 if (!cgrp)
132 return;
133
134 /* XXX: not reentrant */
135 if (--cgrp->refcnt == 0) {
136 close(cgrp->fd);
137 free(cgrp->name);
138 free(cgrp);
139 }
140}
141
142int parse_cgroups(const struct option *opt __used, const char *str,
143 int unset __used)
144{
145 struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
146 const char *p, *e, *eos = str + strlen(str);
147 char *s;
148 int ret;
149
150 if (list_empty(&evlist->entries)) {
151 fprintf(stderr, "must define events before cgroups\n");
152 return -1;
153 }
154
155 for (;;) {
156 p = strchr(str, ',');
157 e = p ? p : eos;
158
159 /* allow empty cgroups, i.e., skip */
160 if (e - str) {
161 /* termination added */
162 s = strndup(str, e - str);
163 if (!s)
164 return -1;
165 ret = add_cgroup(evlist, s);
166 if (ret) {
167 free(s);
168 return -1;
169 }
170 }
171 /* nr_cgroups is increased een for empty cgroups */
172 nr_cgroups++;
173 if (!p)
174 break;
175 str = p+1;
176 }
177 return 0;
178}
diff --git a/tools/perf/util/cgroup.h b/tools/perf/util/cgroup.h
new file mode 100644
index 000000000000..89acd6debdc5
--- /dev/null
+++ b/tools/perf/util/cgroup.h
@@ -0,0 +1,17 @@
1#ifndef __CGROUP_H__
2#define __CGROUP_H__
3
4struct option;
5
6struct cgroup_sel {
7 char *name;
8 int fd;
9 int refcnt;
10};
11
12
13extern int nr_cgroups; /* number of explicit cgroups defined */
14extern void close_cgroup(struct cgroup_sel *cgrp);
15extern int parse_cgroups(const struct option *opt, const char *str, int unset);
16
17#endif /* __CGROUP_H__ */
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
index 0f9b8d7a7d7e..6893eec693ab 100644
--- a/tools/perf/util/cpumap.c
+++ b/tools/perf/util/cpumap.c
@@ -4,32 +4,53 @@
4#include <assert.h> 4#include <assert.h>
5#include <stdio.h> 5#include <stdio.h>
6 6
7int cpumap[MAX_NR_CPUS]; 7static struct cpu_map *cpu_map__default_new(void)
8
9static int default_cpu_map(void)
10{ 8{
11 int nr_cpus, i; 9 struct cpu_map *cpus;
10 int nr_cpus;
12 11
13 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); 12 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
14 assert(nr_cpus <= MAX_NR_CPUS); 13 if (nr_cpus < 0)
15 assert((int)nr_cpus >= 0); 14 return NULL;
15
16 cpus = malloc(sizeof(*cpus) + nr_cpus * sizeof(int));
17 if (cpus != NULL) {
18 int i;
19 for (i = 0; i < nr_cpus; ++i)
20 cpus->map[i] = i;
16 21
17 for (i = 0; i < nr_cpus; ++i) 22 cpus->nr = nr_cpus;
18 cpumap[i] = i; 23 }
19 24
20 return nr_cpus; 25 return cpus;
21} 26}
22 27
23static int read_all_cpu_map(void) 28static struct cpu_map *cpu_map__trim_new(int nr_cpus, int *tmp_cpus)
24{ 29{
30 size_t payload_size = nr_cpus * sizeof(int);
31 struct cpu_map *cpus = malloc(sizeof(*cpus) + payload_size);
32
33 if (cpus != NULL) {
34 cpus->nr = nr_cpus;
35 memcpy(cpus->map, tmp_cpus, payload_size);
36 }
37
38 return cpus;
39}
40
41static struct cpu_map *cpu_map__read_all_cpu_map(void)
42{
43 struct cpu_map *cpus = NULL;
25 FILE *onlnf; 44 FILE *onlnf;
26 int nr_cpus = 0; 45 int nr_cpus = 0;
46 int *tmp_cpus = NULL, *tmp;
47 int max_entries = 0;
27 int n, cpu, prev; 48 int n, cpu, prev;
28 char sep; 49 char sep;
29 50
30 onlnf = fopen("/sys/devices/system/cpu/online", "r"); 51 onlnf = fopen("/sys/devices/system/cpu/online", "r");
31 if (!onlnf) 52 if (!onlnf)
32 return default_cpu_map(); 53 return cpu_map__default_new();
33 54
34 sep = 0; 55 sep = 0;
35 prev = -1; 56 prev = -1;
@@ -38,12 +59,28 @@ static int read_all_cpu_map(void)
38 if (n <= 0) 59 if (n <= 0)
39 break; 60 break;
40 if (prev >= 0) { 61 if (prev >= 0) {
41 assert(nr_cpus + cpu - prev - 1 < MAX_NR_CPUS); 62 int new_max = nr_cpus + cpu - prev - 1;
63
64 if (new_max >= max_entries) {
65 max_entries = new_max + MAX_NR_CPUS / 2;
66 tmp = realloc(tmp_cpus, max_entries * sizeof(int));
67 if (tmp == NULL)
68 goto out_free_tmp;
69 tmp_cpus = tmp;
70 }
71
42 while (++prev < cpu) 72 while (++prev < cpu)
43 cpumap[nr_cpus++] = prev; 73 tmp_cpus[nr_cpus++] = prev;
74 }
75 if (nr_cpus == max_entries) {
76 max_entries += MAX_NR_CPUS;
77 tmp = realloc(tmp_cpus, max_entries * sizeof(int));
78 if (tmp == NULL)
79 goto out_free_tmp;
80 tmp_cpus = tmp;
44 } 81 }
45 assert (nr_cpus < MAX_NR_CPUS); 82
46 cpumap[nr_cpus++] = cpu; 83 tmp_cpus[nr_cpus++] = cpu;
47 if (n == 2 && sep == '-') 84 if (n == 2 && sep == '-')
48 prev = cpu; 85 prev = cpu;
49 else 86 else
@@ -51,24 +88,31 @@ static int read_all_cpu_map(void)
51 if (n == 1 || sep == '\n') 88 if (n == 1 || sep == '\n')
52 break; 89 break;
53 } 90 }
54 fclose(onlnf);
55 if (nr_cpus > 0)
56 return nr_cpus;
57 91
58 return default_cpu_map(); 92 if (nr_cpus > 0)
93 cpus = cpu_map__trim_new(nr_cpus, tmp_cpus);
94 else
95 cpus = cpu_map__default_new();
96out_free_tmp:
97 free(tmp_cpus);
98 fclose(onlnf);
99 return cpus;
59} 100}
60 101
61int read_cpu_map(const char *cpu_list) 102struct cpu_map *cpu_map__new(const char *cpu_list)
62{ 103{
104 struct cpu_map *cpus = NULL;
63 unsigned long start_cpu, end_cpu = 0; 105 unsigned long start_cpu, end_cpu = 0;
64 char *p = NULL; 106 char *p = NULL;
65 int i, nr_cpus = 0; 107 int i, nr_cpus = 0;
108 int *tmp_cpus = NULL, *tmp;
109 int max_entries = 0;
66 110
67 if (!cpu_list) 111 if (!cpu_list)
68 return read_all_cpu_map(); 112 return cpu_map__read_all_cpu_map();
69 113
70 if (!isdigit(*cpu_list)) 114 if (!isdigit(*cpu_list))
71 goto invalid; 115 goto out;
72 116
73 while (isdigit(*cpu_list)) { 117 while (isdigit(*cpu_list)) {
74 p = NULL; 118 p = NULL;
@@ -94,21 +138,47 @@ int read_cpu_map(const char *cpu_list)
94 for (; start_cpu <= end_cpu; start_cpu++) { 138 for (; start_cpu <= end_cpu; start_cpu++) {
95 /* check for duplicates */ 139 /* check for duplicates */
96 for (i = 0; i < nr_cpus; i++) 140 for (i = 0; i < nr_cpus; i++)
97 if (cpumap[i] == (int)start_cpu) 141 if (tmp_cpus[i] == (int)start_cpu)
98 goto invalid; 142 goto invalid;
99 143
100 assert(nr_cpus < MAX_NR_CPUS); 144 if (nr_cpus == max_entries) {
101 cpumap[nr_cpus++] = (int)start_cpu; 145 max_entries += MAX_NR_CPUS;
146 tmp = realloc(tmp_cpus, max_entries * sizeof(int));
147 if (tmp == NULL)
148 goto invalid;
149 tmp_cpus = tmp;
150 }
151 tmp_cpus[nr_cpus++] = (int)start_cpu;
102 } 152 }
103 if (*p) 153 if (*p)
104 ++p; 154 ++p;
105 155
106 cpu_list = p; 156 cpu_list = p;
107 } 157 }
108 if (nr_cpus > 0)
109 return nr_cpus;
110 158
111 return default_cpu_map(); 159 if (nr_cpus > 0)
160 cpus = cpu_map__trim_new(nr_cpus, tmp_cpus);
161 else
162 cpus = cpu_map__default_new();
112invalid: 163invalid:
113 return -1; 164 free(tmp_cpus);
165out:
166 return cpus;
167}
168
169struct cpu_map *cpu_map__dummy_new(void)
170{
171 struct cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int));
172
173 if (cpus != NULL) {
174 cpus->nr = 1;
175 cpus->map[0] = -1;
176 }
177
178 return cpus;
179}
180
181void cpu_map__delete(struct cpu_map *map)
182{
183 free(map);
114} 184}
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
index 3e60f56e490e..072c0a374794 100644
--- a/tools/perf/util/cpumap.h
+++ b/tools/perf/util/cpumap.h
@@ -1,7 +1,13 @@
1#ifndef __PERF_CPUMAP_H 1#ifndef __PERF_CPUMAP_H
2#define __PERF_CPUMAP_H 2#define __PERF_CPUMAP_H
3 3
4extern int read_cpu_map(const char *cpu_list); 4struct cpu_map {
5extern int cpumap[]; 5 int nr;
6 int map[];
7};
8
9struct cpu_map *cpu_map__new(const char *cpu_list);
10struct cpu_map *cpu_map__dummy_new(void);
11void cpu_map__delete(struct cpu_map *map);
6 12
7#endif /* __PERF_CPUMAP_H */ 13#endif /* __PERF_CPUMAP_H */
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index f9c7e3ad1aa7..155749d74350 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -12,8 +12,8 @@
12#include "debug.h" 12#include "debug.h"
13#include "util.h" 13#include "util.h"
14 14
15int verbose = 0; 15int verbose;
16bool dump_trace = false; 16bool dump_trace = false, quiet = false;
17 17
18int eprintf(int level, const char *fmt, ...) 18int eprintf(int level, const char *fmt, ...)
19{ 19{
@@ -46,22 +46,28 @@ int dump_printf(const char *fmt, ...)
46 return ret; 46 return ret;
47} 47}
48 48
49static int dump_printf_color(const char *fmt, const char *color, ...) 49#ifdef NO_NEWT_SUPPORT
50void ui__warning(const char *format, ...)
50{ 51{
51 va_list args; 52 va_list args;
52 int ret = 0;
53
54 if (dump_trace) {
55 va_start(args, color);
56 ret = color_vfprintf(stdout, color, fmt, args);
57 va_end(args);
58 }
59 53
60 return ret; 54 va_start(args, format);
55 vfprintf(stderr, format, args);
56 va_end(args);
61} 57}
58#endif
62 59
60void ui__warning_paranoid(void)
61{
62 ui__warning("Permission error - are you root?\n"
63 "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n"
64 " -1 - Not paranoid at all\n"
65 " 0 - Disallow raw tracepoint access for unpriv\n"
66 " 1 - Disallow cpu events for unpriv\n"
67 " 2 - Disallow kernel profiling for unpriv\n");
68}
63 69
64void trace_event(event_t *event) 70void trace_event(union perf_event *event)
65{ 71{
66 unsigned char *raw_event = (void *)event; 72 unsigned char *raw_event = (void *)event;
67 const char *color = PERF_COLOR_BLUE; 73 const char *color = PERF_COLOR_BLUE;
@@ -70,29 +76,29 @@ void trace_event(event_t *event)
70 if (!dump_trace) 76 if (!dump_trace)
71 return; 77 return;
72 78
73 dump_printf("."); 79 printf(".");
74 dump_printf_color("\n. ... raw event: size %d bytes\n", color, 80 color_fprintf(stdout, color, "\n. ... raw event: size %d bytes\n",
75 event->header.size); 81 event->header.size);
76 82
77 for (i = 0; i < event->header.size; i++) { 83 for (i = 0; i < event->header.size; i++) {
78 if ((i & 15) == 0) { 84 if ((i & 15) == 0) {
79 dump_printf("."); 85 printf(".");
80 dump_printf_color(" %04x: ", color, i); 86 color_fprintf(stdout, color, " %04x: ", i);
81 } 87 }
82 88
83 dump_printf_color(" %02x", color, raw_event[i]); 89 color_fprintf(stdout, color, " %02x", raw_event[i]);
84 90
85 if (((i & 15) == 15) || i == event->header.size-1) { 91 if (((i & 15) == 15) || i == event->header.size-1) {
86 dump_printf_color(" ", color); 92 color_fprintf(stdout, color, " ");
87 for (j = 0; j < 15-(i & 15); j++) 93 for (j = 0; j < 15-(i & 15); j++)
88 dump_printf_color(" ", color); 94 color_fprintf(stdout, color, " ");
89 for (j = i & ~15; j <= i; j++) { 95 for (j = i & ~15; j <= i; j++) {
90 dump_printf_color("%c", color, 96 color_fprintf(stdout, color, "%c",
91 isprint(raw_event[j]) ? 97 isprint(raw_event[j]) ?
92 raw_event[j] : '.'); 98 raw_event[j] : '.');
93 } 99 }
94 dump_printf_color("\n", color); 100 color_fprintf(stdout, color, "\n");
95 } 101 }
96 } 102 }
97 dump_printf(".\n"); 103 printf(".\n");
98} 104}
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index 7a17ee061bcb..fd53db47e3de 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -6,10 +6,10 @@
6#include "event.h" 6#include "event.h"
7 7
8extern int verbose; 8extern int verbose;
9extern bool dump_trace; 9extern bool quiet, dump_trace;
10 10
11int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); 11int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
12void trace_event(event_t *event); 12void trace_event(union perf_event *event);
13 13
14struct ui_progress; 14struct ui_progress;
15 15
@@ -35,4 +35,7 @@ int ui_helpline__show_help(const char *format, va_list ap);
35#include "ui/progress.h" 35#include "ui/progress.h"
36#endif 36#endif
37 37
38void ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2)));
39void ui__warning_paranoid(void);
40
38#endif /* __PERF_DEBUG_H */ 41#endif /* __PERF_DEBUG_H */
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index dab9e754a281..3c1b8a632101 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -6,29 +6,48 @@
6#include "string.h" 6#include "string.h"
7#include "strlist.h" 7#include "strlist.h"
8#include "thread.h" 8#include "thread.h"
9#include "thread_map.h"
10
11static const char *perf_event__names[] = {
12 [0] = "TOTAL",
13 [PERF_RECORD_MMAP] = "MMAP",
14 [PERF_RECORD_LOST] = "LOST",
15 [PERF_RECORD_COMM] = "COMM",
16 [PERF_RECORD_EXIT] = "EXIT",
17 [PERF_RECORD_THROTTLE] = "THROTTLE",
18 [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE",
19 [PERF_RECORD_FORK] = "FORK",
20 [PERF_RECORD_READ] = "READ",
21 [PERF_RECORD_SAMPLE] = "SAMPLE",
22 [PERF_RECORD_HEADER_ATTR] = "ATTR",
23 [PERF_RECORD_HEADER_EVENT_TYPE] = "EVENT_TYPE",
24 [PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA",
25 [PERF_RECORD_HEADER_BUILD_ID] = "BUILD_ID",
26 [PERF_RECORD_FINISHED_ROUND] = "FINISHED_ROUND",
27};
28
29const char *perf_event__name(unsigned int id)
30{
31 if (id >= ARRAY_SIZE(perf_event__names))
32 return "INVALID";
33 if (!perf_event__names[id])
34 return "UNKNOWN";
35 return perf_event__names[id];
36}
9 37
10const char *event__name[] = { 38static struct perf_sample synth_sample = {
11 [0] = "TOTAL", 39 .pid = -1,
12 [PERF_RECORD_MMAP] = "MMAP", 40 .tid = -1,
13 [PERF_RECORD_LOST] = "LOST", 41 .time = -1,
14 [PERF_RECORD_COMM] = "COMM", 42 .stream_id = -1,
15 [PERF_RECORD_EXIT] = "EXIT", 43 .cpu = -1,
16 [PERF_RECORD_THROTTLE] = "THROTTLE", 44 .period = 1,
17 [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE",
18 [PERF_RECORD_FORK] = "FORK",
19 [PERF_RECORD_READ] = "READ",
20 [PERF_RECORD_SAMPLE] = "SAMPLE",
21 [PERF_RECORD_HEADER_ATTR] = "ATTR",
22 [PERF_RECORD_HEADER_EVENT_TYPE] = "EVENT_TYPE",
23 [PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA",
24 [PERF_RECORD_HEADER_BUILD_ID] = "BUILD_ID",
25}; 45};
26 46
27static pid_t event__synthesize_comm(pid_t pid, int full, 47static pid_t perf_event__synthesize_comm(union perf_event *event, pid_t pid,
28 event__handler_t process, 48 int full, perf_event__handler_t process,
29 struct perf_session *session) 49 struct perf_session *session)
30{ 50{
31 event_t ev;
32 char filename[PATH_MAX]; 51 char filename[PATH_MAX];
33 char bf[BUFSIZ]; 52 char bf[BUFSIZ];
34 FILE *fp; 53 FILE *fp;
@@ -49,34 +68,39 @@ out_race:
49 return 0; 68 return 0;
50 } 69 }
51 70
52 memset(&ev.comm, 0, sizeof(ev.comm)); 71 memset(&event->comm, 0, sizeof(event->comm));
53 while (!ev.comm.comm[0] || !ev.comm.pid) { 72
54 if (fgets(bf, sizeof(bf), fp) == NULL) 73 while (!event->comm.comm[0] || !event->comm.pid) {
55 goto out_failure; 74 if (fgets(bf, sizeof(bf), fp) == NULL) {
75 pr_warning("couldn't get COMM and pgid, malformed %s\n", filename);
76 goto out;
77 }
56 78
57 if (memcmp(bf, "Name:", 5) == 0) { 79 if (memcmp(bf, "Name:", 5) == 0) {
58 char *name = bf + 5; 80 char *name = bf + 5;
59 while (*name && isspace(*name)) 81 while (*name && isspace(*name))
60 ++name; 82 ++name;
61 size = strlen(name) - 1; 83 size = strlen(name) - 1;
62 memcpy(ev.comm.comm, name, size++); 84 memcpy(event->comm.comm, name, size++);
63 } else if (memcmp(bf, "Tgid:", 5) == 0) { 85 } else if (memcmp(bf, "Tgid:", 5) == 0) {
64 char *tgids = bf + 5; 86 char *tgids = bf + 5;
65 while (*tgids && isspace(*tgids)) 87 while (*tgids && isspace(*tgids))
66 ++tgids; 88 ++tgids;
67 tgid = ev.comm.pid = atoi(tgids); 89 tgid = event->comm.pid = atoi(tgids);
68 } 90 }
69 } 91 }
70 92
71 ev.comm.header.type = PERF_RECORD_COMM; 93 event->comm.header.type = PERF_RECORD_COMM;
72 size = ALIGN(size, sizeof(u64)); 94 size = ALIGN(size, sizeof(u64));
73 ev.comm.header.size = sizeof(ev.comm) - (sizeof(ev.comm.comm) - size); 95 memset(event->comm.comm + size, 0, session->id_hdr_size);
74 96 event->comm.header.size = (sizeof(event->comm) -
97 (sizeof(event->comm.comm) - size) +
98 session->id_hdr_size);
75 if (!full) { 99 if (!full) {
76 ev.comm.tid = pid; 100 event->comm.tid = pid;
77 101
78 process(&ev, session); 102 process(event, &synth_sample, session);
79 goto out_fclose; 103 goto out;
80 } 104 }
81 105
82 snprintf(filename, sizeof(filename), "/proc/%d/task", pid); 106 snprintf(filename, sizeof(filename), "/proc/%d/task", pid);
@@ -91,24 +115,22 @@ out_race:
91 if (*end) 115 if (*end)
92 continue; 116 continue;
93 117
94 ev.comm.tid = pid; 118 event->comm.tid = pid;
95 119
96 process(&ev, session); 120 process(event, &synth_sample, session);
97 } 121 }
98 closedir(tasks);
99 122
100out_fclose: 123 closedir(tasks);
124out:
101 fclose(fp); 125 fclose(fp);
102 return tgid;
103 126
104out_failure: 127 return tgid;
105 pr_warning("couldn't get COMM and pgid, malformed %s\n", filename);
106 return -1;
107} 128}
108 129
109static int event__synthesize_mmap_events(pid_t pid, pid_t tgid, 130static int perf_event__synthesize_mmap_events(union perf_event *event,
110 event__handler_t process, 131 pid_t pid, pid_t tgid,
111 struct perf_session *session) 132 perf_event__handler_t process,
133 struct perf_session *session)
112{ 134{
113 char filename[PATH_MAX]; 135 char filename[PATH_MAX];
114 FILE *fp; 136 FILE *fp;
@@ -124,29 +146,25 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
124 return -1; 146 return -1;
125 } 147 }
126 148
149 event->header.type = PERF_RECORD_MMAP;
150 /*
151 * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c
152 */
153 event->header.misc = PERF_RECORD_MISC_USER;
154
127 while (1) { 155 while (1) {
128 char bf[BUFSIZ], *pbf = bf; 156 char bf[BUFSIZ], *pbf = bf;
129 event_t ev = {
130 .header = {
131 .type = PERF_RECORD_MMAP,
132 /*
133 * Just like the kernel, see __perf_event_mmap
134 * in kernel/perf_event.c
135 */
136 .misc = PERF_RECORD_MISC_USER,
137 },
138 };
139 int n; 157 int n;
140 size_t size; 158 size_t size;
141 if (fgets(bf, sizeof(bf), fp) == NULL) 159 if (fgets(bf, sizeof(bf), fp) == NULL)
142 break; 160 break;
143 161
144 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ 162 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
145 n = hex2u64(pbf, &ev.mmap.start); 163 n = hex2u64(pbf, &event->mmap.start);
146 if (n < 0) 164 if (n < 0)
147 continue; 165 continue;
148 pbf += n + 1; 166 pbf += n + 1;
149 n = hex2u64(pbf, &ev.mmap.len); 167 n = hex2u64(pbf, &event->mmap.len);
150 if (n < 0) 168 if (n < 0)
151 continue; 169 continue;
152 pbf += n + 3; 170 pbf += n + 3;
@@ -161,19 +179,21 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
161 continue; 179 continue;
162 180
163 pbf += 3; 181 pbf += 3;
164 n = hex2u64(pbf, &ev.mmap.pgoff); 182 n = hex2u64(pbf, &event->mmap.pgoff);
165 183
166 size = strlen(execname); 184 size = strlen(execname);
167 execname[size - 1] = '\0'; /* Remove \n */ 185 execname[size - 1] = '\0'; /* Remove \n */
168 memcpy(ev.mmap.filename, execname, size); 186 memcpy(event->mmap.filename, execname, size);
169 size = ALIGN(size, sizeof(u64)); 187 size = ALIGN(size, sizeof(u64));
170 ev.mmap.len -= ev.mmap.start; 188 event->mmap.len -= event->mmap.start;
171 ev.mmap.header.size = (sizeof(ev.mmap) - 189 event->mmap.header.size = (sizeof(event->mmap) -
172 (sizeof(ev.mmap.filename) - size)); 190 (sizeof(event->mmap.filename) - size));
173 ev.mmap.pid = tgid; 191 memset(event->mmap.filename + size, 0, session->id_hdr_size);
174 ev.mmap.tid = pid; 192 event->mmap.header.size += session->id_hdr_size;
175 193 event->mmap.pid = tgid;
176 process(&ev, session); 194 event->mmap.tid = pid;
195
196 process(event, &synth_sample, session);
177 } 197 }
178 } 198 }
179 199
@@ -181,26 +201,33 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
181 return 0; 201 return 0;
182} 202}
183 203
184int event__synthesize_modules(event__handler_t process, 204int perf_event__synthesize_modules(perf_event__handler_t process,
185 struct perf_session *session, 205 struct perf_session *session,
186 struct machine *machine) 206 struct machine *machine)
187{ 207{
188 struct rb_node *nd; 208 struct rb_node *nd;
189 struct map_groups *kmaps = &machine->kmaps; 209 struct map_groups *kmaps = &machine->kmaps;
190 u16 misc; 210 union perf_event *event = zalloc((sizeof(event->mmap) +
211 session->id_hdr_size));
212 if (event == NULL) {
213 pr_debug("Not enough memory synthesizing mmap event "
214 "for kernel modules\n");
215 return -1;
216 }
217
218 event->header.type = PERF_RECORD_MMAP;
191 219
192 /* 220 /*
193 * kernel uses 0 for user space maps, see kernel/perf_event.c 221 * kernel uses 0 for user space maps, see kernel/perf_event.c
194 * __perf_event_mmap 222 * __perf_event_mmap
195 */ 223 */
196 if (machine__is_host(machine)) 224 if (machine__is_host(machine))
197 misc = PERF_RECORD_MISC_KERNEL; 225 event->header.misc = PERF_RECORD_MISC_KERNEL;
198 else 226 else
199 misc = PERF_RECORD_MISC_GUEST_KERNEL; 227 event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL;
200 228
201 for (nd = rb_first(&kmaps->maps[MAP__FUNCTION]); 229 for (nd = rb_first(&kmaps->maps[MAP__FUNCTION]);
202 nd; nd = rb_next(nd)) { 230 nd; nd = rb_next(nd)) {
203 event_t ev;
204 size_t size; 231 size_t size;
205 struct map *pos = rb_entry(nd, struct map, rb_node); 232 struct map *pos = rb_entry(nd, struct map, rb_node);
206 233
@@ -208,39 +235,87 @@ int event__synthesize_modules(event__handler_t process,
208 continue; 235 continue;
209 236
210 size = ALIGN(pos->dso->long_name_len + 1, sizeof(u64)); 237 size = ALIGN(pos->dso->long_name_len + 1, sizeof(u64));
211 memset(&ev, 0, sizeof(ev)); 238 event->mmap.header.type = PERF_RECORD_MMAP;
212 ev.mmap.header.misc = misc; 239 event->mmap.header.size = (sizeof(event->mmap) -
213 ev.mmap.header.type = PERF_RECORD_MMAP; 240 (sizeof(event->mmap.filename) - size));
214 ev.mmap.header.size = (sizeof(ev.mmap) - 241 memset(event->mmap.filename + size, 0, session->id_hdr_size);
215 (sizeof(ev.mmap.filename) - size)); 242 event->mmap.header.size += session->id_hdr_size;
216 ev.mmap.start = pos->start; 243 event->mmap.start = pos->start;
217 ev.mmap.len = pos->end - pos->start; 244 event->mmap.len = pos->end - pos->start;
218 ev.mmap.pid = machine->pid; 245 event->mmap.pid = machine->pid;
219 246
220 memcpy(ev.mmap.filename, pos->dso->long_name, 247 memcpy(event->mmap.filename, pos->dso->long_name,
221 pos->dso->long_name_len + 1); 248 pos->dso->long_name_len + 1);
222 process(&ev, session); 249 process(event, &synth_sample, session);
223 } 250 }
224 251
252 free(event);
225 return 0; 253 return 0;
226} 254}
227 255
228int event__synthesize_thread(pid_t pid, event__handler_t process, 256static int __event__synthesize_thread(union perf_event *comm_event,
229 struct perf_session *session) 257 union perf_event *mmap_event,
258 pid_t pid, perf_event__handler_t process,
259 struct perf_session *session)
230{ 260{
231 pid_t tgid = event__synthesize_comm(pid, 1, process, session); 261 pid_t tgid = perf_event__synthesize_comm(comm_event, pid, 1, process,
262 session);
232 if (tgid == -1) 263 if (tgid == -1)
233 return -1; 264 return -1;
234 return event__synthesize_mmap_events(pid, tgid, process, session); 265 return perf_event__synthesize_mmap_events(mmap_event, pid, tgid,
266 process, session);
267}
268
269int perf_event__synthesize_thread_map(struct thread_map *threads,
270 perf_event__handler_t process,
271 struct perf_session *session)
272{
273 union perf_event *comm_event, *mmap_event;
274 int err = -1, thread;
275
276 comm_event = malloc(sizeof(comm_event->comm) + session->id_hdr_size);
277 if (comm_event == NULL)
278 goto out;
279
280 mmap_event = malloc(sizeof(mmap_event->mmap) + session->id_hdr_size);
281 if (mmap_event == NULL)
282 goto out_free_comm;
283
284 err = 0;
285 for (thread = 0; thread < threads->nr; ++thread) {
286 if (__event__synthesize_thread(comm_event, mmap_event,
287 threads->map[thread],
288 process, session)) {
289 err = -1;
290 break;
291 }
292 }
293 free(mmap_event);
294out_free_comm:
295 free(comm_event);
296out:
297 return err;
235} 298}
236 299
237void event__synthesize_threads(event__handler_t process, 300int perf_event__synthesize_threads(perf_event__handler_t process,
238 struct perf_session *session) 301 struct perf_session *session)
239{ 302{
240 DIR *proc; 303 DIR *proc;
241 struct dirent dirent, *next; 304 struct dirent dirent, *next;
305 union perf_event *comm_event, *mmap_event;
306 int err = -1;
307
308 comm_event = malloc(sizeof(comm_event->comm) + session->id_hdr_size);
309 if (comm_event == NULL)
310 goto out;
311
312 mmap_event = malloc(sizeof(mmap_event->mmap) + session->id_hdr_size);
313 if (mmap_event == NULL)
314 goto out_free_comm;
242 315
243 proc = opendir("/proc"); 316 proc = opendir("/proc");
317 if (proc == NULL)
318 goto out_free_mmap;
244 319
245 while (!readdir_r(proc, &dirent, &next) && next) { 320 while (!readdir_r(proc, &dirent, &next) && next) {
246 char *end; 321 char *end;
@@ -249,10 +324,18 @@ void event__synthesize_threads(event__handler_t process,
249 if (*end) /* only interested in proper numerical dirents */ 324 if (*end) /* only interested in proper numerical dirents */
250 continue; 325 continue;
251 326
252 event__synthesize_thread(pid, process, session); 327 __event__synthesize_thread(comm_event, mmap_event, pid,
328 process, session);
253 } 329 }
254 330
255 closedir(proc); 331 closedir(proc);
332 err = 0;
333out_free_mmap:
334 free(mmap_event);
335out_free_comm:
336 free(comm_event);
337out:
338 return err;
256} 339}
257 340
258struct process_symbol_args { 341struct process_symbol_args {
@@ -260,7 +343,8 @@ struct process_symbol_args {
260 u64 start; 343 u64 start;
261}; 344};
262 345
263static int find_symbol_cb(void *arg, const char *name, char type, u64 start) 346static int find_symbol_cb(void *arg, const char *name, char type,
347 u64 start, u64 end __used)
264{ 348{
265 struct process_symbol_args *args = arg; 349 struct process_symbol_args *args = arg;
266 350
@@ -276,28 +360,30 @@ static int find_symbol_cb(void *arg, const char *name, char type, u64 start)
276 return 1; 360 return 1;
277} 361}
278 362
279int event__synthesize_kernel_mmap(event__handler_t process, 363int perf_event__synthesize_kernel_mmap(perf_event__handler_t process,
280 struct perf_session *session, 364 struct perf_session *session,
281 struct machine *machine, 365 struct machine *machine,
282 const char *symbol_name) 366 const char *symbol_name)
283{ 367{
284 size_t size; 368 size_t size;
285 const char *filename, *mmap_name; 369 const char *filename, *mmap_name;
286 char path[PATH_MAX]; 370 char path[PATH_MAX];
287 char name_buff[PATH_MAX]; 371 char name_buff[PATH_MAX];
288 struct map *map; 372 struct map *map;
289 373 int err;
290 event_t ev = {
291 .header = {
292 .type = PERF_RECORD_MMAP,
293 },
294 };
295 /* 374 /*
296 * We should get this from /sys/kernel/sections/.text, but till that is 375 * We should get this from /sys/kernel/sections/.text, but till that is
297 * available use this, and after it is use this as a fallback for older 376 * available use this, and after it is use this as a fallback for older
298 * kernels. 377 * kernels.
299 */ 378 */
300 struct process_symbol_args args = { .name = symbol_name, }; 379 struct process_symbol_args args = { .name = symbol_name, };
380 union perf_event *event = zalloc((sizeof(event->mmap) +
381 session->id_hdr_size));
382 if (event == NULL) {
383 pr_debug("Not enough memory synthesizing mmap event "
384 "for kernel modules\n");
385 return -1;
386 }
301 387
302 mmap_name = machine__mmap_name(machine, name_buff, sizeof(name_buff)); 388 mmap_name = machine__mmap_name(machine, name_buff, sizeof(name_buff));
303 if (machine__is_host(machine)) { 389 if (machine__is_host(machine)) {
@@ -305,10 +391,10 @@ int event__synthesize_kernel_mmap(event__handler_t process,
305 * kernel uses PERF_RECORD_MISC_USER for user space maps, 391 * kernel uses PERF_RECORD_MISC_USER for user space maps,
306 * see kernel/perf_event.c __perf_event_mmap 392 * see kernel/perf_event.c __perf_event_mmap
307 */ 393 */
308 ev.header.misc = PERF_RECORD_MISC_KERNEL; 394 event->header.misc = PERF_RECORD_MISC_KERNEL;
309 filename = "/proc/kallsyms"; 395 filename = "/proc/kallsyms";
310 } else { 396 } else {
311 ev.header.misc = PERF_RECORD_MISC_GUEST_KERNEL; 397 event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL;
312 if (machine__is_default_guest(machine)) 398 if (machine__is_default_guest(machine))
313 filename = (char *) symbol_conf.default_guest_kallsyms; 399 filename = (char *) symbol_conf.default_guest_kallsyms;
314 else { 400 else {
@@ -321,54 +407,32 @@ int event__synthesize_kernel_mmap(event__handler_t process,
321 return -ENOENT; 407 return -ENOENT;
322 408
323 map = machine->vmlinux_maps[MAP__FUNCTION]; 409 map = machine->vmlinux_maps[MAP__FUNCTION];
324 size = snprintf(ev.mmap.filename, sizeof(ev.mmap.filename), 410 size = snprintf(event->mmap.filename, sizeof(event->mmap.filename),
325 "%s%s", mmap_name, symbol_name) + 1; 411 "%s%s", mmap_name, symbol_name) + 1;
326 size = ALIGN(size, sizeof(u64)); 412 size = ALIGN(size, sizeof(u64));
327 ev.mmap.header.size = (sizeof(ev.mmap) - 413 event->mmap.header.type = PERF_RECORD_MMAP;
328 (sizeof(ev.mmap.filename) - size)); 414 event->mmap.header.size = (sizeof(event->mmap) -
329 ev.mmap.pgoff = args.start; 415 (sizeof(event->mmap.filename) - size) + session->id_hdr_size);
330 ev.mmap.start = map->start; 416 event->mmap.pgoff = args.start;
331 ev.mmap.len = map->end - ev.mmap.start; 417 event->mmap.start = map->start;
332 ev.mmap.pid = machine->pid; 418 event->mmap.len = map->end - event->mmap.start;
333 419 event->mmap.pid = machine->pid;
334 return process(&ev, session); 420
335} 421 err = process(event, &synth_sample, session);
336 422 free(event);
337static void thread__comm_adjust(struct thread *self, struct hists *hists) 423
338{ 424 return err;
339 char *comm = self->comm;
340
341 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
342 (!symbol_conf.comm_list ||
343 strlist__has_entry(symbol_conf.comm_list, comm))) {
344 u16 slen = strlen(comm);
345
346 if (hists__new_col_len(hists, HISTC_COMM, slen))
347 hists__set_col_len(hists, HISTC_THREAD, slen + 6);
348 }
349} 425}
350 426
351static int thread__set_comm_adjust(struct thread *self, const char *comm, 427int perf_event__process_comm(union perf_event *event,
352 struct hists *hists) 428 struct perf_sample *sample __used,
353{ 429 struct perf_session *session)
354 int ret = thread__set_comm(self, comm);
355
356 if (ret)
357 return ret;
358
359 thread__comm_adjust(self, hists);
360
361 return 0;
362}
363
364int event__process_comm(event_t *self, struct perf_session *session)
365{ 430{
366 struct thread *thread = perf_session__findnew(session, self->comm.tid); 431 struct thread *thread = perf_session__findnew(session, event->comm.tid);
367 432
368 dump_printf(": %s:%d\n", self->comm.comm, self->comm.tid); 433 dump_printf(": %s:%d\n", event->comm.comm, event->comm.tid);
369 434
370 if (thread == NULL || thread__set_comm_adjust(thread, self->comm.comm, 435 if (thread == NULL || thread__set_comm(thread, event->comm.comm)) {
371 &session->hists)) {
372 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); 436 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
373 return -1; 437 return -1;
374 } 438 }
@@ -376,27 +440,31 @@ int event__process_comm(event_t *self, struct perf_session *session)
376 return 0; 440 return 0;
377} 441}
378 442
379int event__process_lost(event_t *self, struct perf_session *session) 443int perf_event__process_lost(union perf_event *event,
444 struct perf_sample *sample __used,
445 struct perf_session *session)
380{ 446{
381 dump_printf(": id:%Ld: lost:%Ld\n", self->lost.id, self->lost.lost); 447 dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n",
382 session->hists.stats.total_lost += self->lost.lost; 448 event->lost.id, event->lost.lost);
449 session->hists.stats.total_lost += event->lost.lost;
383 return 0; 450 return 0;
384} 451}
385 452
386static void event_set_kernel_mmap_len(struct map **maps, event_t *self) 453static void perf_event__set_kernel_mmap_len(union perf_event *event,
454 struct map **maps)
387{ 455{
388 maps[MAP__FUNCTION]->start = self->mmap.start; 456 maps[MAP__FUNCTION]->start = event->mmap.start;
389 maps[MAP__FUNCTION]->end = self->mmap.start + self->mmap.len; 457 maps[MAP__FUNCTION]->end = event->mmap.start + event->mmap.len;
390 /* 458 /*
391 * Be a bit paranoid here, some perf.data file came with 459 * Be a bit paranoid here, some perf.data file came with
392 * a zero sized synthesized MMAP event for the kernel. 460 * a zero sized synthesized MMAP event for the kernel.
393 */ 461 */
394 if (maps[MAP__FUNCTION]->end == 0) 462 if (maps[MAP__FUNCTION]->end == 0)
395 maps[MAP__FUNCTION]->end = ~0UL; 463 maps[MAP__FUNCTION]->end = ~0ULL;
396} 464}
397 465
398static int event__process_kernel_mmap(event_t *self, 466static int perf_event__process_kernel_mmap(union perf_event *event,
399 struct perf_session *session) 467 struct perf_session *session)
400{ 468{
401 struct map *map; 469 struct map *map;
402 char kmmap_prefix[PATH_MAX]; 470 char kmmap_prefix[PATH_MAX];
@@ -404,9 +472,9 @@ static int event__process_kernel_mmap(event_t *self,
404 enum dso_kernel_type kernel_type; 472 enum dso_kernel_type kernel_type;
405 bool is_kernel_mmap; 473 bool is_kernel_mmap;
406 474
407 machine = perf_session__findnew_machine(session, self->mmap.pid); 475 machine = perf_session__findnew_machine(session, event->mmap.pid);
408 if (!machine) { 476 if (!machine) {
409 pr_err("Can't find id %d's machine\n", self->mmap.pid); 477 pr_err("Can't find id %d's machine\n", event->mmap.pid);
410 goto out_problem; 478 goto out_problem;
411 } 479 }
412 480
@@ -416,17 +484,17 @@ static int event__process_kernel_mmap(event_t *self,
416 else 484 else
417 kernel_type = DSO_TYPE_GUEST_KERNEL; 485 kernel_type = DSO_TYPE_GUEST_KERNEL;
418 486
419 is_kernel_mmap = memcmp(self->mmap.filename, 487 is_kernel_mmap = memcmp(event->mmap.filename,
420 kmmap_prefix, 488 kmmap_prefix,
421 strlen(kmmap_prefix)) == 0; 489 strlen(kmmap_prefix)) == 0;
422 if (self->mmap.filename[0] == '/' || 490 if (event->mmap.filename[0] == '/' ||
423 (!is_kernel_mmap && self->mmap.filename[0] == '[')) { 491 (!is_kernel_mmap && event->mmap.filename[0] == '[')) {
424 492
425 char short_module_name[1024]; 493 char short_module_name[1024];
426 char *name, *dot; 494 char *name, *dot;
427 495
428 if (self->mmap.filename[0] == '/') { 496 if (event->mmap.filename[0] == '/') {
429 name = strrchr(self->mmap.filename, '/'); 497 name = strrchr(event->mmap.filename, '/');
430 if (name == NULL) 498 if (name == NULL)
431 goto out_problem; 499 goto out_problem;
432 500
@@ -438,10 +506,10 @@ static int event__process_kernel_mmap(event_t *self,
438 "[%.*s]", (int)(dot - name), name); 506 "[%.*s]", (int)(dot - name), name);
439 strxfrchar(short_module_name, '-', '_'); 507 strxfrchar(short_module_name, '-', '_');
440 } else 508 } else
441 strcpy(short_module_name, self->mmap.filename); 509 strcpy(short_module_name, event->mmap.filename);
442 510
443 map = machine__new_module(machine, self->mmap.start, 511 map = machine__new_module(machine, event->mmap.start,
444 self->mmap.filename); 512 event->mmap.filename);
445 if (map == NULL) 513 if (map == NULL)
446 goto out_problem; 514 goto out_problem;
447 515
@@ -451,9 +519,9 @@ static int event__process_kernel_mmap(event_t *self,
451 519
452 map->dso->short_name = name; 520 map->dso->short_name = name;
453 map->dso->sname_alloc = 1; 521 map->dso->sname_alloc = 1;
454 map->end = map->start + self->mmap.len; 522 map->end = map->start + event->mmap.len;
455 } else if (is_kernel_mmap) { 523 } else if (is_kernel_mmap) {
456 const char *symbol_name = (self->mmap.filename + 524 const char *symbol_name = (event->mmap.filename +
457 strlen(kmmap_prefix)); 525 strlen(kmmap_prefix));
458 /* 526 /*
459 * Should be there already, from the build-id table in 527 * Should be there already, from the build-id table in
@@ -468,10 +536,19 @@ static int event__process_kernel_mmap(event_t *self,
468 if (__machine__create_kernel_maps(machine, kernel) < 0) 536 if (__machine__create_kernel_maps(machine, kernel) < 0)
469 goto out_problem; 537 goto out_problem;
470 538
471 event_set_kernel_mmap_len(machine->vmlinux_maps, self); 539 perf_event__set_kernel_mmap_len(event, machine->vmlinux_maps);
472 perf_session__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps, 540
473 symbol_name, 541 /*
474 self->mmap.pgoff); 542 * Avoid using a zero address (kptr_restrict) for the ref reloc
543 * symbol. Effectively having zero here means that at record
544 * time /proc/sys/kernel/kptr_restrict was non zero.
545 */
546 if (event->mmap.pgoff != 0) {
547 perf_session__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps,
548 symbol_name,
549 event->mmap.pgoff);
550 }
551
475 if (machine__is_default_guest(machine)) { 552 if (machine__is_default_guest(machine)) {
476 /* 553 /*
477 * preload dso of guest kernel and modules 554 * preload dso of guest kernel and modules
@@ -485,21 +562,23 @@ out_problem:
485 return -1; 562 return -1;
486} 563}
487 564
488int event__process_mmap(event_t *self, struct perf_session *session) 565int perf_event__process_mmap(union perf_event *event,
566 struct perf_sample *sample __used,
567 struct perf_session *session)
489{ 568{
490 struct machine *machine; 569 struct machine *machine;
491 struct thread *thread; 570 struct thread *thread;
492 struct map *map; 571 struct map *map;
493 u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 572 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
494 int ret = 0; 573 int ret = 0;
495 574
496 dump_printf(" %d/%d: [%#Lx(%#Lx) @ %#Lx]: %s\n", 575 dump_printf(" %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %s\n",
497 self->mmap.pid, self->mmap.tid, self->mmap.start, 576 event->mmap.pid, event->mmap.tid, event->mmap.start,
498 self->mmap.len, self->mmap.pgoff, self->mmap.filename); 577 event->mmap.len, event->mmap.pgoff, event->mmap.filename);
499 578
500 if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL || 579 if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
501 cpumode == PERF_RECORD_MISC_KERNEL) { 580 cpumode == PERF_RECORD_MISC_KERNEL) {
502 ret = event__process_kernel_mmap(self, session); 581 ret = perf_event__process_kernel_mmap(event, session);
503 if (ret < 0) 582 if (ret < 0)
504 goto out_problem; 583 goto out_problem;
505 return 0; 584 return 0;
@@ -508,12 +587,12 @@ int event__process_mmap(event_t *self, struct perf_session *session)
508 machine = perf_session__find_host_machine(session); 587 machine = perf_session__find_host_machine(session);
509 if (machine == NULL) 588 if (machine == NULL)
510 goto out_problem; 589 goto out_problem;
511 thread = perf_session__findnew(session, self->mmap.pid); 590 thread = perf_session__findnew(session, event->mmap.pid);
512 if (thread == NULL) 591 if (thread == NULL)
513 goto out_problem; 592 goto out_problem;
514 map = map__new(&machine->user_dsos, self->mmap.start, 593 map = map__new(&machine->user_dsos, event->mmap.start,
515 self->mmap.len, self->mmap.pgoff, 594 event->mmap.len, event->mmap.pgoff,
516 self->mmap.pid, self->mmap.filename, 595 event->mmap.pid, event->mmap.filename,
517 MAP__FUNCTION); 596 MAP__FUNCTION);
518 if (map == NULL) 597 if (map == NULL)
519 goto out_problem; 598 goto out_problem;
@@ -526,15 +605,17 @@ out_problem:
526 return 0; 605 return 0;
527} 606}
528 607
529int event__process_task(event_t *self, struct perf_session *session) 608int perf_event__process_task(union perf_event *event,
609 struct perf_sample *sample __used,
610 struct perf_session *session)
530{ 611{
531 struct thread *thread = perf_session__findnew(session, self->fork.tid); 612 struct thread *thread = perf_session__findnew(session, event->fork.tid);
532 struct thread *parent = perf_session__findnew(session, self->fork.ptid); 613 struct thread *parent = perf_session__findnew(session, event->fork.ptid);
533 614
534 dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid, 615 dump_printf("(%d:%d):(%d:%d)\n", event->fork.pid, event->fork.tid,
535 self->fork.ppid, self->fork.ptid); 616 event->fork.ppid, event->fork.ptid);
536 617
537 if (self->header.type == PERF_RECORD_EXIT) { 618 if (event->header.type == PERF_RECORD_EXIT) {
538 perf_session__remove_thread(session, thread); 619 perf_session__remove_thread(session, thread);
539 return 0; 620 return 0;
540 } 621 }
@@ -548,19 +629,22 @@ int event__process_task(event_t *self, struct perf_session *session)
548 return 0; 629 return 0;
549} 630}
550 631
551int event__process(event_t *event, struct perf_session *session) 632int perf_event__process(union perf_event *event, struct perf_sample *sample,
633 struct perf_session *session)
552{ 634{
553 switch (event->header.type) { 635 switch (event->header.type) {
554 case PERF_RECORD_COMM: 636 case PERF_RECORD_COMM:
555 event__process_comm(event, session); 637 perf_event__process_comm(event, sample, session);
556 break; 638 break;
557 case PERF_RECORD_MMAP: 639 case PERF_RECORD_MMAP:
558 event__process_mmap(event, session); 640 perf_event__process_mmap(event, sample, session);
559 break; 641 break;
560 case PERF_RECORD_FORK: 642 case PERF_RECORD_FORK:
561 case PERF_RECORD_EXIT: 643 case PERF_RECORD_EXIT:
562 event__process_task(event, session); 644 perf_event__process_task(event, sample, session);
563 break; 645 break;
646 case PERF_RECORD_LOST:
647 perf_event__process_lost(event, sample, session);
564 default: 648 default:
565 break; 649 break;
566 } 650 }
@@ -635,7 +719,7 @@ try_again:
635 * in the whole kernel symbol list. 719 * in the whole kernel symbol list.
636 */ 720 */
637 if ((long long)al->addr < 0 && 721 if ((long long)al->addr < 0 &&
638 cpumode == PERF_RECORD_MISC_KERNEL && 722 cpumode == PERF_RECORD_MISC_USER &&
639 machine && mg != &machine->kmaps) { 723 machine && mg != &machine->kmaps) {
640 mg = &machine->kmaps; 724 mg = &machine->kmaps;
641 goto try_again; 725 goto try_again;
@@ -657,49 +741,15 @@ void thread__find_addr_location(struct thread *self,
657 al->sym = NULL; 741 al->sym = NULL;
658} 742}
659 743
660static void dso__calc_col_width(struct dso *self, struct hists *hists) 744int perf_event__preprocess_sample(const union perf_event *event,
661{ 745 struct perf_session *session,
662 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep && 746 struct addr_location *al,
663 (!symbol_conf.dso_list || 747 struct perf_sample *sample,
664 strlist__has_entry(symbol_conf.dso_list, self->name))) { 748 symbol_filter_t filter)
665 u16 slen = dso__name_len(self);
666 hists__new_col_len(hists, HISTC_DSO, slen);
667 }
668
669 self->slen_calculated = 1;
670}
671
672int event__preprocess_sample(const event_t *self, struct perf_session *session,
673 struct addr_location *al, struct sample_data *data,
674 symbol_filter_t filter)
675{ 749{
676 u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 750 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
677 struct thread *thread; 751 struct thread *thread = perf_session__findnew(session, event->ip.pid);
678
679 event__parse_sample(self, session->sample_type, data);
680
681 dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld cpu:%d\n",
682 self->header.misc, data->pid, data->tid, data->ip,
683 data->period, data->cpu);
684 752
685 if (session->sample_type & PERF_SAMPLE_CALLCHAIN) {
686 unsigned int i;
687
688 dump_printf("... chain: nr:%Lu\n", data->callchain->nr);
689
690 if (!ip_callchain__valid(data->callchain, self)) {
691 pr_debug("call-chain problem with event, "
692 "skipping it.\n");
693 goto out_filtered;
694 }
695
696 if (dump_trace) {
697 for (i = 0; i < data->callchain->nr; i++)
698 dump_printf("..... %2d: %016Lx\n",
699 i, data->callchain->ips[i]);
700 }
701 }
702 thread = perf_session__findnew(session, self->ip.pid);
703 if (thread == NULL) 753 if (thread == NULL)
704 return -1; 754 return -1;
705 755
@@ -720,12 +770,12 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session,
720 machine__create_kernel_maps(&session->host_machine); 770 machine__create_kernel_maps(&session->host_machine);
721 771
722 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION, 772 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION,
723 self->ip.pid, self->ip.ip, al); 773 event->ip.pid, event->ip.ip, al);
724 dump_printf(" ...... dso: %s\n", 774 dump_printf(" ...... dso: %s\n",
725 al->map ? al->map->dso->long_name : 775 al->map ? al->map->dso->long_name :
726 al->level == 'H' ? "[hypervisor]" : "<not found>"); 776 al->level == 'H' ? "[hypervisor]" : "<not found>");
727 al->sym = NULL; 777 al->sym = NULL;
728 al->cpu = data->cpu; 778 al->cpu = sample->cpu;
729 779
730 if (al->map) { 780 if (al->map) {
731 if (symbol_conf.dso_list && 781 if (symbol_conf.dso_list &&
@@ -736,23 +786,8 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session,
736 strlist__has_entry(symbol_conf.dso_list, 786 strlist__has_entry(symbol_conf.dso_list,
737 al->map->dso->long_name))))) 787 al->map->dso->long_name)))))
738 goto out_filtered; 788 goto out_filtered;
739 /*
740 * We have to do this here as we may have a dso with no symbol
741 * hit that has a name longer than the ones with symbols
742 * sampled.
743 */
744 if (!sort_dso.elide && !al->map->dso->slen_calculated)
745 dso__calc_col_width(al->map->dso, &session->hists);
746 789
747 al->sym = map__find_symbol(al->map, al->addr, filter); 790 al->sym = map__find_symbol(al->map, al->addr, filter);
748 } else {
749 const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
750
751 if (hists__col_len(&session->hists, HISTC_DSO) < unresolved_col_width &&
752 !symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
753 !symbol_conf.dso_list)
754 hists__set_col_len(&session->hists, HISTC_DSO,
755 unresolved_col_width);
756 } 791 }
757 792
758 if (symbol_conf.sym_list && al->sym && 793 if (symbol_conf.sym_list && al->sym &&
@@ -765,72 +800,3 @@ out_filtered:
765 al->filtered = true; 800 al->filtered = true;
766 return 0; 801 return 0;
767} 802}
768
769int event__parse_sample(const event_t *event, u64 type, struct sample_data *data)
770{
771 const u64 *array = event->sample.array;
772
773 if (type & PERF_SAMPLE_IP) {
774 data->ip = event->ip.ip;
775 array++;
776 }
777
778 if (type & PERF_SAMPLE_TID) {
779 u32 *p = (u32 *)array;
780 data->pid = p[0];
781 data->tid = p[1];
782 array++;
783 }
784
785 if (type & PERF_SAMPLE_TIME) {
786 data->time = *array;
787 array++;
788 }
789
790 if (type & PERF_SAMPLE_ADDR) {
791 data->addr = *array;
792 array++;
793 }
794
795 data->id = -1ULL;
796 if (type & PERF_SAMPLE_ID) {
797 data->id = *array;
798 array++;
799 }
800
801 if (type & PERF_SAMPLE_STREAM_ID) {
802 data->stream_id = *array;
803 array++;
804 }
805
806 if (type & PERF_SAMPLE_CPU) {
807 u32 *p = (u32 *)array;
808 data->cpu = *p;
809 array++;
810 } else
811 data->cpu = -1;
812
813 if (type & PERF_SAMPLE_PERIOD) {
814 data->period = *array;
815 array++;
816 }
817
818 if (type & PERF_SAMPLE_READ) {
819 pr_debug("PERF_SAMPLE_READ is unsuported for now\n");
820 return -1;
821 }
822
823 if (type & PERF_SAMPLE_CALLCHAIN) {
824 data->callchain = (struct ip_callchain *)array;
825 array += 1 + data->callchain->nr;
826 }
827
828 if (type & PERF_SAMPLE_RAW) {
829 u32 *p = (u32 *)array;
830 data->raw_size = *p;
831 p++;
832 data->raw_data = p;
833 }
834
835 return 0;
836}
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 8e790dae7026..1d7f66488a88 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -56,12 +56,19 @@ struct read_event {
56 u64 id; 56 u64 id;
57}; 57};
58 58
59
60#define PERF_SAMPLE_MASK \
61 (PERF_SAMPLE_IP | PERF_SAMPLE_TID | \
62 PERF_SAMPLE_TIME | PERF_SAMPLE_ADDR | \
63 PERF_SAMPLE_ID | PERF_SAMPLE_STREAM_ID | \
64 PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD)
65
59struct sample_event { 66struct sample_event {
60 struct perf_event_header header; 67 struct perf_event_header header;
61 u64 array[]; 68 u64 array[];
62}; 69};
63 70
64struct sample_data { 71struct perf_sample {
65 u64 ip; 72 u64 ip;
66 u32 pid, tid; 73 u32 pid, tid;
67 u64 time; 74 u64 time;
@@ -85,6 +92,7 @@ struct build_id_event {
85}; 92};
86 93
87enum perf_user_event_type { /* above any possible kernel type */ 94enum perf_user_event_type { /* above any possible kernel type */
95 PERF_RECORD_USER_TYPE_START = 64,
88 PERF_RECORD_HEADER_ATTR = 64, 96 PERF_RECORD_HEADER_ATTR = 64,
89 PERF_RECORD_HEADER_EVENT_TYPE = 65, 97 PERF_RECORD_HEADER_EVENT_TYPE = 65,
90 PERF_RECORD_HEADER_TRACING_DATA = 66, 98 PERF_RECORD_HEADER_TRACING_DATA = 66,
@@ -116,7 +124,7 @@ struct tracing_data_event {
116 u32 size; 124 u32 size;
117}; 125};
118 126
119typedef union event_union { 127union perf_event {
120 struct perf_event_header header; 128 struct perf_event_header header;
121 struct ip_event ip; 129 struct ip_event ip;
122 struct mmap_event mmap; 130 struct mmap_event mmap;
@@ -129,39 +137,55 @@ typedef union event_union {
129 struct event_type_event event_type; 137 struct event_type_event event_type;
130 struct tracing_data_event tracing_data; 138 struct tracing_data_event tracing_data;
131 struct build_id_event build_id; 139 struct build_id_event build_id;
132} event_t; 140};
133 141
134void event__print_totals(void); 142void perf_event__print_totals(void);
135 143
136struct perf_session; 144struct perf_session;
137 145struct thread_map;
138typedef int (*event__handler_t)(event_t *event, struct perf_session *session); 146
139 147typedef int (*perf_event__handler_synth_t)(union perf_event *event,
140int event__synthesize_thread(pid_t pid, event__handler_t process, 148 struct perf_session *session);
149typedef int (*perf_event__handler_t)(union perf_event *event,
150 struct perf_sample *sample,
151 struct perf_session *session);
152
153int perf_event__synthesize_thread_map(struct thread_map *threads,
154 perf_event__handler_t process,
155 struct perf_session *session);
156int perf_event__synthesize_threads(perf_event__handler_t process,
157 struct perf_session *session);
158int perf_event__synthesize_kernel_mmap(perf_event__handler_t process,
159 struct perf_session *session,
160 struct machine *machine,
161 const char *symbol_name);
162
163int perf_event__synthesize_modules(perf_event__handler_t process,
164 struct perf_session *session,
165 struct machine *machine);
166
167int perf_event__process_comm(union perf_event *event, struct perf_sample *sample,
141 struct perf_session *session); 168 struct perf_session *session);
142void event__synthesize_threads(event__handler_t process, 169int perf_event__process_lost(union perf_event *event, struct perf_sample *sample,
143 struct perf_session *session); 170 struct perf_session *session);
144int event__synthesize_kernel_mmap(event__handler_t process, 171int perf_event__process_mmap(union perf_event *event, struct perf_sample *sample,
145 struct perf_session *session, 172 struct perf_session *session);
146 struct machine *machine, 173int perf_event__process_task(union perf_event *event, struct perf_sample *sample,
147 const char *symbol_name); 174 struct perf_session *session);
148 175int perf_event__process(union perf_event *event, struct perf_sample *sample,
149int event__synthesize_modules(event__handler_t process, 176 struct perf_session *session);
150 struct perf_session *session,
151 struct machine *machine);
152
153int event__process_comm(event_t *self, struct perf_session *session);
154int event__process_lost(event_t *self, struct perf_session *session);
155int event__process_mmap(event_t *self, struct perf_session *session);
156int event__process_task(event_t *self, struct perf_session *session);
157int event__process(event_t *event, struct perf_session *session);
158 177
159struct addr_location; 178struct addr_location;
160int event__preprocess_sample(const event_t *self, struct perf_session *session, 179int perf_event__preprocess_sample(const union perf_event *self,
161 struct addr_location *al, struct sample_data *data, 180 struct perf_session *session,
162 symbol_filter_t filter); 181 struct addr_location *al,
163int event__parse_sample(const event_t *event, u64 type, struct sample_data *data); 182 struct perf_sample *sample,
183 symbol_filter_t filter);
184
185const char *perf_event__name(unsigned int id);
164 186
165extern const char *event__name[]; 187int perf_event__parse_sample(const union perf_event *event, u64 type,
188 int sample_size, bool sample_id_all,
189 struct perf_sample *sample);
166 190
167#endif /* __PERF_RECORD_H */ 191#endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
new file mode 100644
index 000000000000..b021ea9265c3
--- /dev/null
+++ b/tools/perf/util/evlist.c
@@ -0,0 +1,500 @@
1/*
2 * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
3 *
4 * Parts came from builtin-{top,stat,record}.c, see those files for further
5 * copyright notes.
6 *
7 * Released under the GPL v2. (and only v2, not any later version)
8 */
9#include <poll.h>
10#include "cpumap.h"
11#include "thread_map.h"
12#include "evlist.h"
13#include "evsel.h"
14#include "util.h"
15
16#include <sys/mman.h>
17
18#include <linux/bitops.h>
19#include <linux/hash.h>
20
21#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
22#define SID(e, x, y) xyarray__entry(e->sample_id, x, y)
23
24void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
25 struct thread_map *threads)
26{
27 int i;
28
29 for (i = 0; i < PERF_EVLIST__HLIST_SIZE; ++i)
30 INIT_HLIST_HEAD(&evlist->heads[i]);
31 INIT_LIST_HEAD(&evlist->entries);
32 perf_evlist__set_maps(evlist, cpus, threads);
33}
34
35struct perf_evlist *perf_evlist__new(struct cpu_map *cpus,
36 struct thread_map *threads)
37{
38 struct perf_evlist *evlist = zalloc(sizeof(*evlist));
39
40 if (evlist != NULL)
41 perf_evlist__init(evlist, cpus, threads);
42
43 return evlist;
44}
45
46static void perf_evlist__purge(struct perf_evlist *evlist)
47{
48 struct perf_evsel *pos, *n;
49
50 list_for_each_entry_safe(pos, n, &evlist->entries, node) {
51 list_del_init(&pos->node);
52 perf_evsel__delete(pos);
53 }
54
55 evlist->nr_entries = 0;
56}
57
58void perf_evlist__exit(struct perf_evlist *evlist)
59{
60 free(evlist->mmap);
61 free(evlist->pollfd);
62 evlist->mmap = NULL;
63 evlist->pollfd = NULL;
64}
65
66void perf_evlist__delete(struct perf_evlist *evlist)
67{
68 perf_evlist__purge(evlist);
69 perf_evlist__exit(evlist);
70 free(evlist);
71}
72
73void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry)
74{
75 list_add_tail(&entry->node, &evlist->entries);
76 ++evlist->nr_entries;
77}
78
79int perf_evlist__add_default(struct perf_evlist *evlist)
80{
81 struct perf_event_attr attr = {
82 .type = PERF_TYPE_HARDWARE,
83 .config = PERF_COUNT_HW_CPU_CYCLES,
84 };
85 struct perf_evsel *evsel = perf_evsel__new(&attr, 0);
86
87 if (evsel == NULL)
88 return -ENOMEM;
89
90 perf_evlist__add(evlist, evsel);
91 return 0;
92}
93
94int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
95{
96 int nfds = evlist->cpus->nr * evlist->threads->nr * evlist->nr_entries;
97 evlist->pollfd = malloc(sizeof(struct pollfd) * nfds);
98 return evlist->pollfd != NULL ? 0 : -ENOMEM;
99}
100
101void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd)
102{
103 fcntl(fd, F_SETFL, O_NONBLOCK);
104 evlist->pollfd[evlist->nr_fds].fd = fd;
105 evlist->pollfd[evlist->nr_fds].events = POLLIN;
106 evlist->nr_fds++;
107}
108
109static void perf_evlist__id_hash(struct perf_evlist *evlist,
110 struct perf_evsel *evsel,
111 int cpu, int thread, u64 id)
112{
113 int hash;
114 struct perf_sample_id *sid = SID(evsel, cpu, thread);
115
116 sid->id = id;
117 sid->evsel = evsel;
118 hash = hash_64(sid->id, PERF_EVLIST__HLIST_BITS);
119 hlist_add_head(&sid->node, &evlist->heads[hash]);
120}
121
122void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel,
123 int cpu, int thread, u64 id)
124{
125 perf_evlist__id_hash(evlist, evsel, cpu, thread, id);
126 evsel->id[evsel->ids++] = id;
127}
128
129static int perf_evlist__id_add_fd(struct perf_evlist *evlist,
130 struct perf_evsel *evsel,
131 int cpu, int thread, int fd)
132{
133 u64 read_data[4] = { 0, };
134 int id_idx = 1; /* The first entry is the counter value */
135
136 if (!(evsel->attr.read_format & PERF_FORMAT_ID) ||
137 read(fd, &read_data, sizeof(read_data)) == -1)
138 return -1;
139
140 if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
141 ++id_idx;
142 if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
143 ++id_idx;
144
145 perf_evlist__id_add(evlist, evsel, cpu, thread, read_data[id_idx]);
146 return 0;
147}
148
149struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id)
150{
151 struct hlist_head *head;
152 struct hlist_node *pos;
153 struct perf_sample_id *sid;
154 int hash;
155
156 if (evlist->nr_entries == 1)
157 return list_entry(evlist->entries.next, struct perf_evsel, node);
158
159 hash = hash_64(id, PERF_EVLIST__HLIST_BITS);
160 head = &evlist->heads[hash];
161
162 hlist_for_each_entry(sid, pos, head, node)
163 if (sid->id == id)
164 return sid->evsel;
165 return NULL;
166}
167
168union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
169{
170 /* XXX Move this to perf.c, making it generally available */
171 unsigned int page_size = sysconf(_SC_PAGE_SIZE);
172 struct perf_mmap *md = &evlist->mmap[idx];
173 unsigned int head = perf_mmap__read_head(md);
174 unsigned int old = md->prev;
175 unsigned char *data = md->base + page_size;
176 union perf_event *event = NULL;
177
178 if (evlist->overwrite) {
179 /*
180 * If we're further behind than half the buffer, there's a chance
181 * the writer will bite our tail and mess up the samples under us.
182 *
183 * If we somehow ended up ahead of the head, we got messed up.
184 *
185 * In either case, truncate and restart at head.
186 */
187 int diff = head - old;
188 if (diff > md->mask / 2 || diff < 0) {
189 fprintf(stderr, "WARNING: failed to keep up with mmap data.\n");
190
191 /*
192 * head points to a known good entry, start there.
193 */
194 old = head;
195 }
196 }
197
198 if (old != head) {
199 size_t size;
200
201 event = (union perf_event *)&data[old & md->mask];
202 size = event->header.size;
203
204 /*
205 * Event straddles the mmap boundary -- header should always
206 * be inside due to u64 alignment of output.
207 */
208 if ((old & md->mask) + size != ((old + size) & md->mask)) {
209 unsigned int offset = old;
210 unsigned int len = min(sizeof(*event), size), cpy;
211 void *dst = &evlist->event_copy;
212
213 do {
214 cpy = min(md->mask + 1 - (offset & md->mask), len);
215 memcpy(dst, &data[offset & md->mask], cpy);
216 offset += cpy;
217 dst += cpy;
218 len -= cpy;
219 } while (len);
220
221 event = &evlist->event_copy;
222 }
223
224 old += size;
225 }
226
227 md->prev = old;
228
229 if (!evlist->overwrite)
230 perf_mmap__write_tail(md, old);
231
232 return event;
233}
234
235void perf_evlist__munmap(struct perf_evlist *evlist)
236{
237 int i;
238
239 for (i = 0; i < evlist->nr_mmaps; i++) {
240 if (evlist->mmap[i].base != NULL) {
241 munmap(evlist->mmap[i].base, evlist->mmap_len);
242 evlist->mmap[i].base = NULL;
243 }
244 }
245
246 free(evlist->mmap);
247 evlist->mmap = NULL;
248}
249
250int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
251{
252 evlist->nr_mmaps = evlist->cpus->nr;
253 if (evlist->cpus->map[0] == -1)
254 evlist->nr_mmaps = evlist->threads->nr;
255 evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap));
256 return evlist->mmap != NULL ? 0 : -ENOMEM;
257}
258
259static int __perf_evlist__mmap(struct perf_evlist *evlist,
260 int idx, int prot, int mask, int fd)
261{
262 evlist->mmap[idx].prev = 0;
263 evlist->mmap[idx].mask = mask;
264 evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, prot,
265 MAP_SHARED, fd, 0);
266 if (evlist->mmap[idx].base == MAP_FAILED)
267 return -1;
268
269 perf_evlist__add_pollfd(evlist, fd);
270 return 0;
271}
272
273static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int mask)
274{
275 struct perf_evsel *evsel;
276 int cpu, thread;
277
278 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
279 int output = -1;
280
281 for (thread = 0; thread < evlist->threads->nr; thread++) {
282 list_for_each_entry(evsel, &evlist->entries, node) {
283 int fd = FD(evsel, cpu, thread);
284
285 if (output == -1) {
286 output = fd;
287 if (__perf_evlist__mmap(evlist, cpu,
288 prot, mask, output) < 0)
289 goto out_unmap;
290 } else {
291 if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, output) != 0)
292 goto out_unmap;
293 }
294
295 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
296 perf_evlist__id_add_fd(evlist, evsel, cpu, thread, fd) < 0)
297 goto out_unmap;
298 }
299 }
300 }
301
302 return 0;
303
304out_unmap:
305 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
306 if (evlist->mmap[cpu].base != NULL) {
307 munmap(evlist->mmap[cpu].base, evlist->mmap_len);
308 evlist->mmap[cpu].base = NULL;
309 }
310 }
311 return -1;
312}
313
314static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, int mask)
315{
316 struct perf_evsel *evsel;
317 int thread;
318
319 for (thread = 0; thread < evlist->threads->nr; thread++) {
320 int output = -1;
321
322 list_for_each_entry(evsel, &evlist->entries, node) {
323 int fd = FD(evsel, 0, thread);
324
325 if (output == -1) {
326 output = fd;
327 if (__perf_evlist__mmap(evlist, thread,
328 prot, mask, output) < 0)
329 goto out_unmap;
330 } else {
331 if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, output) != 0)
332 goto out_unmap;
333 }
334
335 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
336 perf_evlist__id_add_fd(evlist, evsel, 0, thread, fd) < 0)
337 goto out_unmap;
338 }
339 }
340
341 return 0;
342
343out_unmap:
344 for (thread = 0; thread < evlist->threads->nr; thread++) {
345 if (evlist->mmap[thread].base != NULL) {
346 munmap(evlist->mmap[thread].base, evlist->mmap_len);
347 evlist->mmap[thread].base = NULL;
348 }
349 }
350 return -1;
351}
352
353/** perf_evlist__mmap - Create per cpu maps to receive events
354 *
355 * @evlist - list of events
356 * @pages - map length in pages
357 * @overwrite - overwrite older events?
358 *
359 * If overwrite is false the user needs to signal event consuption using:
360 *
361 * struct perf_mmap *m = &evlist->mmap[cpu];
362 * unsigned int head = perf_mmap__read_head(m);
363 *
364 * perf_mmap__write_tail(m, head)
365 *
366 * Using perf_evlist__read_on_cpu does this automatically.
367 */
368int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite)
369{
370 unsigned int page_size = sysconf(_SC_PAGE_SIZE);
371 int mask = pages * page_size - 1;
372 struct perf_evsel *evsel;
373 const struct cpu_map *cpus = evlist->cpus;
374 const struct thread_map *threads = evlist->threads;
375 int prot = PROT_READ | (overwrite ? 0 : PROT_WRITE);
376
377 if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0)
378 return -ENOMEM;
379
380 if (evlist->pollfd == NULL && perf_evlist__alloc_pollfd(evlist) < 0)
381 return -ENOMEM;
382
383 evlist->overwrite = overwrite;
384 evlist->mmap_len = (pages + 1) * page_size;
385
386 list_for_each_entry(evsel, &evlist->entries, node) {
387 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
388 evsel->sample_id == NULL &&
389 perf_evsel__alloc_id(evsel, cpus->nr, threads->nr) < 0)
390 return -ENOMEM;
391 }
392
393 if (evlist->cpus->map[0] == -1)
394 return perf_evlist__mmap_per_thread(evlist, prot, mask);
395
396 return perf_evlist__mmap_per_cpu(evlist, prot, mask);
397}
398
399int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid,
400 pid_t target_tid, const char *cpu_list)
401{
402 evlist->threads = thread_map__new(target_pid, target_tid);
403
404 if (evlist->threads == NULL)
405 return -1;
406
407 if (cpu_list == NULL && target_tid != -1)
408 evlist->cpus = cpu_map__dummy_new();
409 else
410 evlist->cpus = cpu_map__new(cpu_list);
411
412 if (evlist->cpus == NULL)
413 goto out_delete_threads;
414
415 return 0;
416
417out_delete_threads:
418 thread_map__delete(evlist->threads);
419 return -1;
420}
421
422void perf_evlist__delete_maps(struct perf_evlist *evlist)
423{
424 cpu_map__delete(evlist->cpus);
425 thread_map__delete(evlist->threads);
426 evlist->cpus = NULL;
427 evlist->threads = NULL;
428}
429
430int perf_evlist__set_filters(struct perf_evlist *evlist)
431{
432 const struct thread_map *threads = evlist->threads;
433 const struct cpu_map *cpus = evlist->cpus;
434 struct perf_evsel *evsel;
435 char *filter;
436 int thread;
437 int cpu;
438 int err;
439 int fd;
440
441 list_for_each_entry(evsel, &evlist->entries, node) {
442 filter = evsel->filter;
443 if (!filter)
444 continue;
445 for (cpu = 0; cpu < cpus->nr; cpu++) {
446 for (thread = 0; thread < threads->nr; thread++) {
447 fd = FD(evsel, cpu, thread);
448 err = ioctl(fd, PERF_EVENT_IOC_SET_FILTER, filter);
449 if (err)
450 return err;
451 }
452 }
453 }
454
455 return 0;
456}
457
458bool perf_evlist__valid_sample_type(const struct perf_evlist *evlist)
459{
460 struct perf_evsel *pos, *first;
461
462 pos = first = list_entry(evlist->entries.next, struct perf_evsel, node);
463
464 list_for_each_entry_continue(pos, &evlist->entries, node) {
465 if (first->attr.sample_type != pos->attr.sample_type)
466 return false;
467 }
468
469 return true;
470}
471
472u64 perf_evlist__sample_type(const struct perf_evlist *evlist)
473{
474 struct perf_evsel *first;
475
476 first = list_entry(evlist->entries.next, struct perf_evsel, node);
477 return first->attr.sample_type;
478}
479
480bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist)
481{
482 struct perf_evsel *pos, *first;
483
484 pos = first = list_entry(evlist->entries.next, struct perf_evsel, node);
485
486 list_for_each_entry_continue(pos, &evlist->entries, node) {
487 if (first->attr.sample_id_all != pos->attr.sample_id_all)
488 return false;
489 }
490
491 return true;
492}
493
494bool perf_evlist__sample_id_all(const struct perf_evlist *evlist)
495{
496 struct perf_evsel *first;
497
498 first = list_entry(evlist->entries.next, struct perf_evsel, node);
499 return first->attr.sample_id_all;
500}
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
new file mode 100644
index 000000000000..b2b862374f37
--- /dev/null
+++ b/tools/perf/util/evlist.h
@@ -0,0 +1,74 @@
1#ifndef __PERF_EVLIST_H
2#define __PERF_EVLIST_H 1
3
4#include <linux/list.h>
5#include "../perf.h"
6#include "event.h"
7
8struct pollfd;
9struct thread_map;
10struct cpu_map;
11
12#define PERF_EVLIST__HLIST_BITS 8
13#define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS)
14
15struct perf_evlist {
16 struct list_head entries;
17 struct hlist_head heads[PERF_EVLIST__HLIST_SIZE];
18 int nr_entries;
19 int nr_fds;
20 int nr_mmaps;
21 int mmap_len;
22 bool overwrite;
23 union perf_event event_copy;
24 struct perf_mmap *mmap;
25 struct pollfd *pollfd;
26 struct thread_map *threads;
27 struct cpu_map *cpus;
28};
29
30struct perf_evsel;
31
32struct perf_evlist *perf_evlist__new(struct cpu_map *cpus,
33 struct thread_map *threads);
34void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
35 struct thread_map *threads);
36void perf_evlist__exit(struct perf_evlist *evlist);
37void perf_evlist__delete(struct perf_evlist *evlist);
38
39void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry);
40int perf_evlist__add_default(struct perf_evlist *evlist);
41
42void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel,
43 int cpu, int thread, u64 id);
44
45int perf_evlist__alloc_pollfd(struct perf_evlist *evlist);
46void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd);
47
48struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id);
49
50union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx);
51
52int perf_evlist__alloc_mmap(struct perf_evlist *evlist);
53int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite);
54void perf_evlist__munmap(struct perf_evlist *evlist);
55
56static inline void perf_evlist__set_maps(struct perf_evlist *evlist,
57 struct cpu_map *cpus,
58 struct thread_map *threads)
59{
60 evlist->cpus = cpus;
61 evlist->threads = threads;
62}
63
64int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid,
65 pid_t target_tid, const char *cpu_list);
66void perf_evlist__delete_maps(struct perf_evlist *evlist);
67int perf_evlist__set_filters(struct perf_evlist *evlist);
68
69u64 perf_evlist__sample_type(const struct perf_evlist *evlist);
70bool perf_evlist__sample_id_all(const const struct perf_evlist *evlist);
71
72bool perf_evlist__valid_sample_type(const struct perf_evlist *evlist);
73bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist);
74#endif /* __PERF_EVLIST_H */
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
new file mode 100644
index 000000000000..0239eb87b232
--- /dev/null
+++ b/tools/perf/util/evsel.c
@@ -0,0 +1,440 @@
1/*
2 * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
3 *
4 * Parts came from builtin-{top,stat,record}.c, see those files for further
5 * copyright notes.
6 *
7 * Released under the GPL v2. (and only v2, not any later version)
8 */
9
10#include "evsel.h"
11#include "evlist.h"
12#include "util.h"
13#include "cpumap.h"
14#include "thread_map.h"
15
16#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
17
18int __perf_evsel__sample_size(u64 sample_type)
19{
20 u64 mask = sample_type & PERF_SAMPLE_MASK;
21 int size = 0;
22 int i;
23
24 for (i = 0; i < 64; i++) {
25 if (mask & (1ULL << i))
26 size++;
27 }
28
29 size *= sizeof(u64);
30
31 return size;
32}
33
34void perf_evsel__init(struct perf_evsel *evsel,
35 struct perf_event_attr *attr, int idx)
36{
37 evsel->idx = idx;
38 evsel->attr = *attr;
39 INIT_LIST_HEAD(&evsel->node);
40}
41
42struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
43{
44 struct perf_evsel *evsel = zalloc(sizeof(*evsel));
45
46 if (evsel != NULL)
47 perf_evsel__init(evsel, attr, idx);
48
49 return evsel;
50}
51
52int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
53{
54 int cpu, thread;
55 evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int));
56
57 if (evsel->fd) {
58 for (cpu = 0; cpu < ncpus; cpu++) {
59 for (thread = 0; thread < nthreads; thread++) {
60 FD(evsel, cpu, thread) = -1;
61 }
62 }
63 }
64
65 return evsel->fd != NULL ? 0 : -ENOMEM;
66}
67
68int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
69{
70 evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id));
71 if (evsel->sample_id == NULL)
72 return -ENOMEM;
73
74 evsel->id = zalloc(ncpus * nthreads * sizeof(u64));
75 if (evsel->id == NULL) {
76 xyarray__delete(evsel->sample_id);
77 evsel->sample_id = NULL;
78 return -ENOMEM;
79 }
80
81 return 0;
82}
83
84int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus)
85{
86 evsel->counts = zalloc((sizeof(*evsel->counts) +
87 (ncpus * sizeof(struct perf_counts_values))));
88 return evsel->counts != NULL ? 0 : -ENOMEM;
89}
90
91void perf_evsel__free_fd(struct perf_evsel *evsel)
92{
93 xyarray__delete(evsel->fd);
94 evsel->fd = NULL;
95}
96
97void perf_evsel__free_id(struct perf_evsel *evsel)
98{
99 xyarray__delete(evsel->sample_id);
100 evsel->sample_id = NULL;
101 free(evsel->id);
102 evsel->id = NULL;
103}
104
105void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
106{
107 int cpu, thread;
108
109 for (cpu = 0; cpu < ncpus; cpu++)
110 for (thread = 0; thread < nthreads; ++thread) {
111 close(FD(evsel, cpu, thread));
112 FD(evsel, cpu, thread) = -1;
113 }
114}
115
116void perf_evsel__exit(struct perf_evsel *evsel)
117{
118 assert(list_empty(&evsel->node));
119 xyarray__delete(evsel->fd);
120 xyarray__delete(evsel->sample_id);
121 free(evsel->id);
122}
123
124void perf_evsel__delete(struct perf_evsel *evsel)
125{
126 perf_evsel__exit(evsel);
127 close_cgroup(evsel->cgrp);
128 free(evsel->name);
129 free(evsel);
130}
131
132int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
133 int cpu, int thread, bool scale)
134{
135 struct perf_counts_values count;
136 size_t nv = scale ? 3 : 1;
137
138 if (FD(evsel, cpu, thread) < 0)
139 return -EINVAL;
140
141 if (evsel->counts == NULL && perf_evsel__alloc_counts(evsel, cpu + 1) < 0)
142 return -ENOMEM;
143
144 if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0)
145 return -errno;
146
147 if (scale) {
148 if (count.run == 0)
149 count.val = 0;
150 else if (count.run < count.ena)
151 count.val = (u64)((double)count.val * count.ena / count.run + 0.5);
152 } else
153 count.ena = count.run = 0;
154
155 evsel->counts->cpu[cpu] = count;
156 return 0;
157}
158
159int __perf_evsel__read(struct perf_evsel *evsel,
160 int ncpus, int nthreads, bool scale)
161{
162 size_t nv = scale ? 3 : 1;
163 int cpu, thread;
164 struct perf_counts_values *aggr = &evsel->counts->aggr, count;
165
166 aggr->val = aggr->ena = aggr->run = 0;
167
168 for (cpu = 0; cpu < ncpus; cpu++) {
169 for (thread = 0; thread < nthreads; thread++) {
170 if (FD(evsel, cpu, thread) < 0)
171 continue;
172
173 if (readn(FD(evsel, cpu, thread),
174 &count, nv * sizeof(u64)) < 0)
175 return -errno;
176
177 aggr->val += count.val;
178 if (scale) {
179 aggr->ena += count.ena;
180 aggr->run += count.run;
181 }
182 }
183 }
184
185 evsel->counts->scaled = 0;
186 if (scale) {
187 if (aggr->run == 0) {
188 evsel->counts->scaled = -1;
189 aggr->val = 0;
190 return 0;
191 }
192
193 if (aggr->run < aggr->ena) {
194 evsel->counts->scaled = 1;
195 aggr->val = (u64)((double)aggr->val * aggr->ena / aggr->run + 0.5);
196 }
197 } else
198 aggr->ena = aggr->run = 0;
199
200 return 0;
201}
202
203static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
204 struct thread_map *threads, bool group)
205{
206 int cpu, thread;
207 unsigned long flags = 0;
208 int pid = -1;
209
210 if (evsel->fd == NULL &&
211 perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0)
212 return -1;
213
214 if (evsel->cgrp) {
215 flags = PERF_FLAG_PID_CGROUP;
216 pid = evsel->cgrp->fd;
217 }
218
219 for (cpu = 0; cpu < cpus->nr; cpu++) {
220 int group_fd = -1;
221
222 for (thread = 0; thread < threads->nr; thread++) {
223
224 if (!evsel->cgrp)
225 pid = threads->map[thread];
226
227 FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr,
228 pid,
229 cpus->map[cpu],
230 group_fd, flags);
231 if (FD(evsel, cpu, thread) < 0)
232 goto out_close;
233
234 if (group && group_fd == -1)
235 group_fd = FD(evsel, cpu, thread);
236 }
237 }
238
239 return 0;
240
241out_close:
242 do {
243 while (--thread >= 0) {
244 close(FD(evsel, cpu, thread));
245 FD(evsel, cpu, thread) = -1;
246 }
247 thread = threads->nr;
248 } while (--cpu >= 0);
249 return -1;
250}
251
252static struct {
253 struct cpu_map map;
254 int cpus[1];
255} empty_cpu_map = {
256 .map.nr = 1,
257 .cpus = { -1, },
258};
259
260static struct {
261 struct thread_map map;
262 int threads[1];
263} empty_thread_map = {
264 .map.nr = 1,
265 .threads = { -1, },
266};
267
268int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
269 struct thread_map *threads, bool group)
270{
271 if (cpus == NULL) {
272 /* Work around old compiler warnings about strict aliasing */
273 cpus = &empty_cpu_map.map;
274 }
275
276 if (threads == NULL)
277 threads = &empty_thread_map.map;
278
279 return __perf_evsel__open(evsel, cpus, threads, group);
280}
281
282int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
283 struct cpu_map *cpus, bool group)
284{
285 return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group);
286}
287
288int perf_evsel__open_per_thread(struct perf_evsel *evsel,
289 struct thread_map *threads, bool group)
290{
291 return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group);
292}
293
294static int perf_event__parse_id_sample(const union perf_event *event, u64 type,
295 struct perf_sample *sample)
296{
297 const u64 *array = event->sample.array;
298
299 array += ((event->header.size -
300 sizeof(event->header)) / sizeof(u64)) - 1;
301
302 if (type & PERF_SAMPLE_CPU) {
303 u32 *p = (u32 *)array;
304 sample->cpu = *p;
305 array--;
306 }
307
308 if (type & PERF_SAMPLE_STREAM_ID) {
309 sample->stream_id = *array;
310 array--;
311 }
312
313 if (type & PERF_SAMPLE_ID) {
314 sample->id = *array;
315 array--;
316 }
317
318 if (type & PERF_SAMPLE_TIME) {
319 sample->time = *array;
320 array--;
321 }
322
323 if (type & PERF_SAMPLE_TID) {
324 u32 *p = (u32 *)array;
325 sample->pid = p[0];
326 sample->tid = p[1];
327 }
328
329 return 0;
330}
331
332static bool sample_overlap(const union perf_event *event,
333 const void *offset, u64 size)
334{
335 const void *base = event;
336
337 if (offset + size > base + event->header.size)
338 return true;
339
340 return false;
341}
342
343int perf_event__parse_sample(const union perf_event *event, u64 type,
344 int sample_size, bool sample_id_all,
345 struct perf_sample *data)
346{
347 const u64 *array;
348
349 data->cpu = data->pid = data->tid = -1;
350 data->stream_id = data->id = data->time = -1ULL;
351
352 if (event->header.type != PERF_RECORD_SAMPLE) {
353 if (!sample_id_all)
354 return 0;
355 return perf_event__parse_id_sample(event, type, data);
356 }
357
358 array = event->sample.array;
359
360 if (sample_size + sizeof(event->header) > event->header.size)
361 return -EFAULT;
362
363 if (type & PERF_SAMPLE_IP) {
364 data->ip = event->ip.ip;
365 array++;
366 }
367
368 if (type & PERF_SAMPLE_TID) {
369 u32 *p = (u32 *)array;
370 data->pid = p[0];
371 data->tid = p[1];
372 array++;
373 }
374
375 if (type & PERF_SAMPLE_TIME) {
376 data->time = *array;
377 array++;
378 }
379
380 if (type & PERF_SAMPLE_ADDR) {
381 data->addr = *array;
382 array++;
383 }
384
385 data->id = -1ULL;
386 if (type & PERF_SAMPLE_ID) {
387 data->id = *array;
388 array++;
389 }
390
391 if (type & PERF_SAMPLE_STREAM_ID) {
392 data->stream_id = *array;
393 array++;
394 }
395
396 if (type & PERF_SAMPLE_CPU) {
397 u32 *p = (u32 *)array;
398 data->cpu = *p;
399 array++;
400 }
401
402 if (type & PERF_SAMPLE_PERIOD) {
403 data->period = *array;
404 array++;
405 }
406
407 if (type & PERF_SAMPLE_READ) {
408 fprintf(stderr, "PERF_SAMPLE_READ is unsuported for now\n");
409 return -1;
410 }
411
412 if (type & PERF_SAMPLE_CALLCHAIN) {
413 if (sample_overlap(event, array, sizeof(data->callchain->nr)))
414 return -EFAULT;
415
416 data->callchain = (struct ip_callchain *)array;
417
418 if (sample_overlap(event, array, data->callchain->nr))
419 return -EFAULT;
420
421 array += 1 + data->callchain->nr;
422 }
423
424 if (type & PERF_SAMPLE_RAW) {
425 u32 *p = (u32 *)array;
426
427 if (sample_overlap(event, array, sizeof(u32)))
428 return -EFAULT;
429
430 data->raw_size = *p;
431 p++;
432
433 if (sample_overlap(event, p, data->raw_size))
434 return -EFAULT;
435
436 data->raw_data = p;
437 }
438
439 return 0;
440}
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
new file mode 100644
index 000000000000..7e9366e4490b
--- /dev/null
+++ b/tools/perf/util/evsel.h
@@ -0,0 +1,159 @@
1#ifndef __PERF_EVSEL_H
2#define __PERF_EVSEL_H 1
3
4#include <linux/list.h>
5#include <stdbool.h>
6#include "../../../include/linux/perf_event.h"
7#include "types.h"
8#include "xyarray.h"
9#include "cgroup.h"
10#include "hist.h"
11
12struct perf_counts_values {
13 union {
14 struct {
15 u64 val;
16 u64 ena;
17 u64 run;
18 };
19 u64 values[3];
20 };
21};
22
23struct perf_counts {
24 s8 scaled;
25 struct perf_counts_values aggr;
26 struct perf_counts_values cpu[];
27};
28
29struct perf_evsel;
30
31/*
32 * Per fd, to map back from PERF_SAMPLE_ID to evsel, only used when there are
33 * more than one entry in the evlist.
34 */
35struct perf_sample_id {
36 struct hlist_node node;
37 u64 id;
38 struct perf_evsel *evsel;
39};
40
41/** struct perf_evsel - event selector
42 *
43 * @name - Can be set to retain the original event name passed by the user,
44 * so that when showing results in tools such as 'perf stat', we
45 * show the name used, not some alias.
46 */
47struct perf_evsel {
48 struct list_head node;
49 struct perf_event_attr attr;
50 char *filter;
51 struct xyarray *fd;
52 struct xyarray *sample_id;
53 u64 *id;
54 struct perf_counts *counts;
55 int idx;
56 int ids;
57 struct hists hists;
58 char *name;
59 union {
60 void *priv;
61 off_t id_offset;
62 };
63 struct cgroup_sel *cgrp;
64};
65
66struct cpu_map;
67struct thread_map;
68struct perf_evlist;
69
70struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx);
71void perf_evsel__init(struct perf_evsel *evsel,
72 struct perf_event_attr *attr, int idx);
73void perf_evsel__exit(struct perf_evsel *evsel);
74void perf_evsel__delete(struct perf_evsel *evsel);
75
76int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
77int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads);
78int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus);
79void perf_evsel__free_fd(struct perf_evsel *evsel);
80void perf_evsel__free_id(struct perf_evsel *evsel);
81void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
82
83int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
84 struct cpu_map *cpus, bool group);
85int perf_evsel__open_per_thread(struct perf_evsel *evsel,
86 struct thread_map *threads, bool group);
87int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
88 struct thread_map *threads, bool group);
89
90#define perf_evsel__match(evsel, t, c) \
91 (evsel->attr.type == PERF_TYPE_##t && \
92 evsel->attr.config == PERF_COUNT_##c)
93
94int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
95 int cpu, int thread, bool scale);
96
97/**
98 * perf_evsel__read_on_cpu - Read out the results on a CPU and thread
99 *
100 * @evsel - event selector to read value
101 * @cpu - CPU of interest
102 * @thread - thread of interest
103 */
104static inline int perf_evsel__read_on_cpu(struct perf_evsel *evsel,
105 int cpu, int thread)
106{
107 return __perf_evsel__read_on_cpu(evsel, cpu, thread, false);
108}
109
110/**
111 * perf_evsel__read_on_cpu_scaled - Read out the results on a CPU and thread, scaled
112 *
113 * @evsel - event selector to read value
114 * @cpu - CPU of interest
115 * @thread - thread of interest
116 */
117static inline int perf_evsel__read_on_cpu_scaled(struct perf_evsel *evsel,
118 int cpu, int thread)
119{
120 return __perf_evsel__read_on_cpu(evsel, cpu, thread, true);
121}
122
123int __perf_evsel__read(struct perf_evsel *evsel, int ncpus, int nthreads,
124 bool scale);
125
126/**
127 * perf_evsel__read - Read the aggregate results on all CPUs
128 *
129 * @evsel - event selector to read value
130 * @ncpus - Number of cpus affected, from zero
131 * @nthreads - Number of threads affected, from zero
132 */
133static inline int perf_evsel__read(struct perf_evsel *evsel,
134 int ncpus, int nthreads)
135{
136 return __perf_evsel__read(evsel, ncpus, nthreads, false);
137}
138
139/**
140 * perf_evsel__read_scaled - Read the aggregate results on all CPUs, scaled
141 *
142 * @evsel - event selector to read value
143 * @ncpus - Number of cpus affected, from zero
144 * @nthreads - Number of threads affected, from zero
145 */
146static inline int perf_evsel__read_scaled(struct perf_evsel *evsel,
147 int ncpus, int nthreads)
148{
149 return __perf_evsel__read(evsel, ncpus, nthreads, true);
150}
151
152int __perf_evsel__sample_size(u64 sample_type);
153
154static inline int perf_evsel__sample_size(struct perf_evsel *evsel)
155{
156 return __perf_evsel__sample_size(evsel->attr.sample_type);
157}
158
159#endif /* __PERF_EVSEL_H */
diff --git a/tools/perf/util/exec_cmd.c b/tools/perf/util/exec_cmd.c
index 67eeff571568..7adf4ad15d8f 100644
--- a/tools/perf/util/exec_cmd.c
+++ b/tools/perf/util/exec_cmd.c
@@ -11,31 +11,12 @@ static const char *argv0_path;
11 11
12const char *system_path(const char *path) 12const char *system_path(const char *path)
13{ 13{
14#ifdef RUNTIME_PREFIX
15 static const char *prefix;
16#else
17 static const char *prefix = PREFIX; 14 static const char *prefix = PREFIX;
18#endif
19 struct strbuf d = STRBUF_INIT; 15 struct strbuf d = STRBUF_INIT;
20 16
21 if (is_absolute_path(path)) 17 if (is_absolute_path(path))
22 return path; 18 return path;
23 19
24#ifdef RUNTIME_PREFIX
25 assert(argv0_path);
26 assert(is_absolute_path(argv0_path));
27
28 if (!prefix &&
29 !(prefix = strip_path_suffix(argv0_path, PERF_EXEC_PATH)) &&
30 !(prefix = strip_path_suffix(argv0_path, BINDIR)) &&
31 !(prefix = strip_path_suffix(argv0_path, "perf"))) {
32 prefix = PREFIX;
33 fprintf(stderr, "RUNTIME_PREFIX requested, "
34 "but prefix computation failed. "
35 "Using static fallback '%s'.\n", prefix);
36 }
37#endif
38
39 strbuf_addf(&d, "%s/%s", prefix, path); 20 strbuf_addf(&d, "%s/%s", prefix, path);
40 path = strbuf_detach(&d, NULL); 21 path = strbuf_detach(&d, NULL);
41 return path; 22 return path;
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index d7e67b167ea3..afb0849fe530 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -8,6 +8,8 @@
8#include <linux/list.h> 8#include <linux/list.h>
9#include <linux/kernel.h> 9#include <linux/kernel.h>
10 10
11#include "evlist.h"
12#include "evsel.h"
11#include "util.h" 13#include "util.h"
12#include "header.h" 14#include "header.h"
13#include "../perf.h" 15#include "../perf.h"
@@ -18,89 +20,6 @@
18 20
19static bool no_buildid_cache = false; 21static bool no_buildid_cache = false;
20 22
21/*
22 * Create new perf.data header attribute:
23 */
24struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr)
25{
26 struct perf_header_attr *self = malloc(sizeof(*self));
27
28 if (self != NULL) {
29 self->attr = *attr;
30 self->ids = 0;
31 self->size = 1;
32 self->id = malloc(sizeof(u64));
33 if (self->id == NULL) {
34 free(self);
35 self = NULL;
36 }
37 }
38
39 return self;
40}
41
42void perf_header_attr__delete(struct perf_header_attr *self)
43{
44 free(self->id);
45 free(self);
46}
47
48int perf_header_attr__add_id(struct perf_header_attr *self, u64 id)
49{
50 int pos = self->ids;
51
52 self->ids++;
53 if (self->ids > self->size) {
54 int nsize = self->size * 2;
55 u64 *nid = realloc(self->id, nsize * sizeof(u64));
56
57 if (nid == NULL)
58 return -1;
59
60 self->size = nsize;
61 self->id = nid;
62 }
63 self->id[pos] = id;
64 return 0;
65}
66
67int perf_header__init(struct perf_header *self)
68{
69 self->size = 1;
70 self->attr = malloc(sizeof(void *));
71 return self->attr == NULL ? -ENOMEM : 0;
72}
73
74void perf_header__exit(struct perf_header *self)
75{
76 int i;
77 for (i = 0; i < self->attrs; ++i)
78 perf_header_attr__delete(self->attr[i]);
79 free(self->attr);
80}
81
82int perf_header__add_attr(struct perf_header *self,
83 struct perf_header_attr *attr)
84{
85 if (self->frozen)
86 return -1;
87
88 if (self->attrs == self->size) {
89 int nsize = self->size * 2;
90 struct perf_header_attr **nattr;
91
92 nattr = realloc(self->attr, nsize * sizeof(void *));
93 if (nattr == NULL)
94 return -1;
95
96 self->size = nsize;
97 self->attr = nattr;
98 }
99
100 self->attr[self->attrs++] = attr;
101 return 0;
102}
103
104static int event_count; 23static int event_count;
105static struct perf_trace_event_type *events; 24static struct perf_trace_event_type *events;
106 25
@@ -147,14 +66,19 @@ struct perf_file_attr {
147 struct perf_file_section ids; 66 struct perf_file_section ids;
148}; 67};
149 68
150void perf_header__set_feat(struct perf_header *self, int feat) 69void perf_header__set_feat(struct perf_header *header, int feat)
70{
71 set_bit(feat, header->adds_features);
72}
73
74void perf_header__clear_feat(struct perf_header *header, int feat)
151{ 75{
152 set_bit(feat, self->adds_features); 76 clear_bit(feat, header->adds_features);
153} 77}
154 78
155bool perf_header__has_feat(const struct perf_header *self, int feat) 79bool perf_header__has_feat(const struct perf_header *header, int feat)
156{ 80{
157 return test_bit(feat, self->adds_features); 81 return test_bit(feat, header->adds_features);
158} 82}
159 83
160static int do_write(int fd, const void *buf, size_t size) 84static int do_write(int fd, const void *buf, size_t size)
@@ -223,22 +147,22 @@ static int __dsos__write_buildid_table(struct list_head *head, pid_t pid,
223 return 0; 147 return 0;
224} 148}
225 149
226static int machine__write_buildid_table(struct machine *self, int fd) 150static int machine__write_buildid_table(struct machine *machine, int fd)
227{ 151{
228 int err; 152 int err;
229 u16 kmisc = PERF_RECORD_MISC_KERNEL, 153 u16 kmisc = PERF_RECORD_MISC_KERNEL,
230 umisc = PERF_RECORD_MISC_USER; 154 umisc = PERF_RECORD_MISC_USER;
231 155
232 if (!machine__is_host(self)) { 156 if (!machine__is_host(machine)) {
233 kmisc = PERF_RECORD_MISC_GUEST_KERNEL; 157 kmisc = PERF_RECORD_MISC_GUEST_KERNEL;
234 umisc = PERF_RECORD_MISC_GUEST_USER; 158 umisc = PERF_RECORD_MISC_GUEST_USER;
235 } 159 }
236 160
237 err = __dsos__write_buildid_table(&self->kernel_dsos, self->pid, 161 err = __dsos__write_buildid_table(&machine->kernel_dsos, machine->pid,
238 kmisc, fd); 162 kmisc, fd);
239 if (err == 0) 163 if (err == 0)
240 err = __dsos__write_buildid_table(&self->user_dsos, 164 err = __dsos__write_buildid_table(&machine->user_dsos,
241 self->pid, umisc, fd); 165 machine->pid, umisc, fd);
242 return err; 166 return err;
243} 167}
244 168
@@ -265,15 +189,24 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
265 const char *name, bool is_kallsyms) 189 const char *name, bool is_kallsyms)
266{ 190{
267 const size_t size = PATH_MAX; 191 const size_t size = PATH_MAX;
268 char *filename = malloc(size), 192 char *realname, *filename = malloc(size),
269 *linkname = malloc(size), *targetname; 193 *linkname = malloc(size), *targetname;
270 int len, err = -1; 194 int len, err = -1;
271 195
272 if (filename == NULL || linkname == NULL) 196 if (is_kallsyms) {
197 if (symbol_conf.kptr_restrict) {
198 pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n");
199 return 0;
200 }
201 realname = (char *)name;
202 } else
203 realname = realpath(name, NULL);
204
205 if (realname == NULL || filename == NULL || linkname == NULL)
273 goto out_free; 206 goto out_free;
274 207
275 len = snprintf(filename, size, "%s%s%s", 208 len = snprintf(filename, size, "%s%s%s",
276 debugdir, is_kallsyms ? "/" : "", name); 209 debugdir, is_kallsyms ? "/" : "", realname);
277 if (mkdir_p(filename, 0755)) 210 if (mkdir_p(filename, 0755))
278 goto out_free; 211 goto out_free;
279 212
@@ -283,7 +216,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
283 if (is_kallsyms) { 216 if (is_kallsyms) {
284 if (copyfile("/proc/kallsyms", filename)) 217 if (copyfile("/proc/kallsyms", filename))
285 goto out_free; 218 goto out_free;
286 } else if (link(name, filename) && copyfile(name, filename)) 219 } else if (link(realname, filename) && copyfile(name, filename))
287 goto out_free; 220 goto out_free;
288 } 221 }
289 222
@@ -300,6 +233,8 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
300 if (symlink(targetname, linkname) == 0) 233 if (symlink(targetname, linkname) == 0)
301 err = 0; 234 err = 0;
302out_free: 235out_free:
236 if (!is_kallsyms)
237 free(realname);
303 free(filename); 238 free(filename);
304 free(linkname); 239 free(linkname);
305 return err; 240 return err;
@@ -354,12 +289,12 @@ out_free:
354 return err; 289 return err;
355} 290}
356 291
357static int dso__cache_build_id(struct dso *self, const char *debugdir) 292static int dso__cache_build_id(struct dso *dso, const char *debugdir)
358{ 293{
359 bool is_kallsyms = self->kernel && self->long_name[0] != '/'; 294 bool is_kallsyms = dso->kernel && dso->long_name[0] != '/';
360 295
361 return build_id_cache__add_b(self->build_id, sizeof(self->build_id), 296 return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id),
362 self->long_name, debugdir, is_kallsyms); 297 dso->long_name, debugdir, is_kallsyms);
363} 298}
364 299
365static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir) 300static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir)
@@ -374,14 +309,14 @@ static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir)
374 return err; 309 return err;
375} 310}
376 311
377static int machine__cache_build_ids(struct machine *self, const char *debugdir) 312static int machine__cache_build_ids(struct machine *machine, const char *debugdir)
378{ 313{
379 int ret = __dsos__cache_build_ids(&self->kernel_dsos, debugdir); 314 int ret = __dsos__cache_build_ids(&machine->kernel_dsos, debugdir);
380 ret |= __dsos__cache_build_ids(&self->user_dsos, debugdir); 315 ret |= __dsos__cache_build_ids(&machine->user_dsos, debugdir);
381 return ret; 316 return ret;
382} 317}
383 318
384static int perf_session__cache_build_ids(struct perf_session *self) 319static int perf_session__cache_build_ids(struct perf_session *session)
385{ 320{
386 struct rb_node *nd; 321 struct rb_node *nd;
387 int ret; 322 int ret;
@@ -392,28 +327,28 @@ static int perf_session__cache_build_ids(struct perf_session *self)
392 if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) 327 if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
393 return -1; 328 return -1;
394 329
395 ret = machine__cache_build_ids(&self->host_machine, debugdir); 330 ret = machine__cache_build_ids(&session->host_machine, debugdir);
396 331
397 for (nd = rb_first(&self->machines); nd; nd = rb_next(nd)) { 332 for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) {
398 struct machine *pos = rb_entry(nd, struct machine, rb_node); 333 struct machine *pos = rb_entry(nd, struct machine, rb_node);
399 ret |= machine__cache_build_ids(pos, debugdir); 334 ret |= machine__cache_build_ids(pos, debugdir);
400 } 335 }
401 return ret ? -1 : 0; 336 return ret ? -1 : 0;
402} 337}
403 338
404static bool machine__read_build_ids(struct machine *self, bool with_hits) 339static bool machine__read_build_ids(struct machine *machine, bool with_hits)
405{ 340{
406 bool ret = __dsos__read_build_ids(&self->kernel_dsos, with_hits); 341 bool ret = __dsos__read_build_ids(&machine->kernel_dsos, with_hits);
407 ret |= __dsos__read_build_ids(&self->user_dsos, with_hits); 342 ret |= __dsos__read_build_ids(&machine->user_dsos, with_hits);
408 return ret; 343 return ret;
409} 344}
410 345
411static bool perf_session__read_build_ids(struct perf_session *self, bool with_hits) 346static bool perf_session__read_build_ids(struct perf_session *session, bool with_hits)
412{ 347{
413 struct rb_node *nd; 348 struct rb_node *nd;
414 bool ret = machine__read_build_ids(&self->host_machine, with_hits); 349 bool ret = machine__read_build_ids(&session->host_machine, with_hits);
415 350
416 for (nd = rb_first(&self->machines); nd; nd = rb_next(nd)) { 351 for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) {
417 struct machine *pos = rb_entry(nd, struct machine, rb_node); 352 struct machine *pos = rb_entry(nd, struct machine, rb_node);
418 ret |= machine__read_build_ids(pos, with_hits); 353 ret |= machine__read_build_ids(pos, with_hits);
419 } 354 }
@@ -421,7 +356,8 @@ static bool perf_session__read_build_ids(struct perf_session *self, bool with_hi
421 return ret; 356 return ret;
422} 357}
423 358
424static int perf_header__adds_write(struct perf_header *self, int fd) 359static int perf_header__adds_write(struct perf_header *header,
360 struct perf_evlist *evlist, int fd)
425{ 361{
426 int nr_sections; 362 int nr_sections;
427 struct perf_session *session; 363 struct perf_session *session;
@@ -430,11 +366,13 @@ static int perf_header__adds_write(struct perf_header *self, int fd)
430 u64 sec_start; 366 u64 sec_start;
431 int idx = 0, err; 367 int idx = 0, err;
432 368
433 session = container_of(self, struct perf_session, header); 369 session = container_of(header, struct perf_session, header);
434 if (perf_session__read_build_ids(session, true))
435 perf_header__set_feat(self, HEADER_BUILD_ID);
436 370
437 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); 371 if (perf_header__has_feat(header, HEADER_BUILD_ID &&
372 !perf_session__read_build_ids(session, true)))
373 perf_header__clear_feat(header, HEADER_BUILD_ID);
374
375 nr_sections = bitmap_weight(header->adds_features, HEADER_FEAT_BITS);
438 if (!nr_sections) 376 if (!nr_sections)
439 return 0; 377 return 0;
440 378
@@ -444,28 +382,28 @@ static int perf_header__adds_write(struct perf_header *self, int fd)
444 382
445 sec_size = sizeof(*feat_sec) * nr_sections; 383 sec_size = sizeof(*feat_sec) * nr_sections;
446 384
447 sec_start = self->data_offset + self->data_size; 385 sec_start = header->data_offset + header->data_size;
448 lseek(fd, sec_start + sec_size, SEEK_SET); 386 lseek(fd, sec_start + sec_size, SEEK_SET);
449 387
450 if (perf_header__has_feat(self, HEADER_TRACE_INFO)) { 388 if (perf_header__has_feat(header, HEADER_TRACE_INFO)) {
451 struct perf_file_section *trace_sec; 389 struct perf_file_section *trace_sec;
452 390
453 trace_sec = &feat_sec[idx++]; 391 trace_sec = &feat_sec[idx++];
454 392
455 /* Write trace info */ 393 /* Write trace info */
456 trace_sec->offset = lseek(fd, 0, SEEK_CUR); 394 trace_sec->offset = lseek(fd, 0, SEEK_CUR);
457 read_tracing_data(fd, attrs, nr_counters); 395 read_tracing_data(fd, &evlist->entries);
458 trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset; 396 trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset;
459 } 397 }
460 398
461 if (perf_header__has_feat(self, HEADER_BUILD_ID)) { 399 if (perf_header__has_feat(header, HEADER_BUILD_ID)) {
462 struct perf_file_section *buildid_sec; 400 struct perf_file_section *buildid_sec;
463 401
464 buildid_sec = &feat_sec[idx++]; 402 buildid_sec = &feat_sec[idx++];
465 403
466 /* Write build-ids */ 404 /* Write build-ids */
467 buildid_sec->offset = lseek(fd, 0, SEEK_CUR); 405 buildid_sec->offset = lseek(fd, 0, SEEK_CUR);
468 err = dsos__write_buildid_table(self, fd); 406 err = dsos__write_buildid_table(header, fd);
469 if (err < 0) { 407 if (err < 0) {
470 pr_debug("failed to write buildid table\n"); 408 pr_debug("failed to write buildid table\n");
471 goto out_free; 409 goto out_free;
@@ -504,32 +442,41 @@ int perf_header__write_pipe(int fd)
504 return 0; 442 return 0;
505} 443}
506 444
507int perf_header__write(struct perf_header *self, int fd, bool at_exit) 445int perf_session__write_header(struct perf_session *session,
446 struct perf_evlist *evlist,
447 int fd, bool at_exit)
508{ 448{
509 struct perf_file_header f_header; 449 struct perf_file_header f_header;
510 struct perf_file_attr f_attr; 450 struct perf_file_attr f_attr;
511 struct perf_header_attr *attr; 451 struct perf_header *header = &session->header;
512 int i, err; 452 struct perf_evsel *attr, *pair = NULL;
453 int err;
513 454
514 lseek(fd, sizeof(f_header), SEEK_SET); 455 lseek(fd, sizeof(f_header), SEEK_SET);
515 456
516 for (i = 0; i < self->attrs; i++) { 457 if (session->evlist != evlist)
517 attr = self->attr[i]; 458 pair = list_entry(session->evlist->entries.next, struct perf_evsel, node);
518 459
460 list_for_each_entry(attr, &evlist->entries, node) {
519 attr->id_offset = lseek(fd, 0, SEEK_CUR); 461 attr->id_offset = lseek(fd, 0, SEEK_CUR);
520 err = do_write(fd, attr->id, attr->ids * sizeof(u64)); 462 err = do_write(fd, attr->id, attr->ids * sizeof(u64));
521 if (err < 0) { 463 if (err < 0) {
464out_err_write:
522 pr_debug("failed to write perf header\n"); 465 pr_debug("failed to write perf header\n");
523 return err; 466 return err;
524 } 467 }
468 if (session->evlist != evlist) {
469 err = do_write(fd, pair->id, pair->ids * sizeof(u64));
470 if (err < 0)
471 goto out_err_write;
472 attr->ids += pair->ids;
473 pair = list_entry(pair->node.next, struct perf_evsel, node);
474 }
525 } 475 }
526 476
477 header->attr_offset = lseek(fd, 0, SEEK_CUR);
527 478
528 self->attr_offset = lseek(fd, 0, SEEK_CUR); 479 list_for_each_entry(attr, &evlist->entries, node) {
529
530 for (i = 0; i < self->attrs; i++) {
531 attr = self->attr[i];
532
533 f_attr = (struct perf_file_attr){ 480 f_attr = (struct perf_file_attr){
534 .attr = attr->attr, 481 .attr = attr->attr,
535 .ids = { 482 .ids = {
@@ -544,20 +491,20 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit)
544 } 491 }
545 } 492 }
546 493
547 self->event_offset = lseek(fd, 0, SEEK_CUR); 494 header->event_offset = lseek(fd, 0, SEEK_CUR);
548 self->event_size = event_count * sizeof(struct perf_trace_event_type); 495 header->event_size = event_count * sizeof(struct perf_trace_event_type);
549 if (events) { 496 if (events) {
550 err = do_write(fd, events, self->event_size); 497 err = do_write(fd, events, header->event_size);
551 if (err < 0) { 498 if (err < 0) {
552 pr_debug("failed to write perf header events\n"); 499 pr_debug("failed to write perf header events\n");
553 return err; 500 return err;
554 } 501 }
555 } 502 }
556 503
557 self->data_offset = lseek(fd, 0, SEEK_CUR); 504 header->data_offset = lseek(fd, 0, SEEK_CUR);
558 505
559 if (at_exit) { 506 if (at_exit) {
560 err = perf_header__adds_write(self, fd); 507 err = perf_header__adds_write(header, evlist, fd);
561 if (err < 0) 508 if (err < 0)
562 return err; 509 return err;
563 } 510 }
@@ -567,20 +514,20 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit)
567 .size = sizeof(f_header), 514 .size = sizeof(f_header),
568 .attr_size = sizeof(f_attr), 515 .attr_size = sizeof(f_attr),
569 .attrs = { 516 .attrs = {
570 .offset = self->attr_offset, 517 .offset = header->attr_offset,
571 .size = self->attrs * sizeof(f_attr), 518 .size = evlist->nr_entries * sizeof(f_attr),
572 }, 519 },
573 .data = { 520 .data = {
574 .offset = self->data_offset, 521 .offset = header->data_offset,
575 .size = self->data_size, 522 .size = header->data_size,
576 }, 523 },
577 .event_types = { 524 .event_types = {
578 .offset = self->event_offset, 525 .offset = header->event_offset,
579 .size = self->event_size, 526 .size = header->event_size,
580 }, 527 },
581 }; 528 };
582 529
583 memcpy(&f_header.adds_features, &self->adds_features, sizeof(self->adds_features)); 530 memcpy(&f_header.adds_features, &header->adds_features, sizeof(header->adds_features));
584 531
585 lseek(fd, 0, SEEK_SET); 532 lseek(fd, 0, SEEK_SET);
586 err = do_write(fd, &f_header, sizeof(f_header)); 533 err = do_write(fd, &f_header, sizeof(f_header));
@@ -588,26 +535,26 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit)
588 pr_debug("failed to write perf header\n"); 535 pr_debug("failed to write perf header\n");
589 return err; 536 return err;
590 } 537 }
591 lseek(fd, self->data_offset + self->data_size, SEEK_SET); 538 lseek(fd, header->data_offset + header->data_size, SEEK_SET);
592 539
593 self->frozen = 1; 540 header->frozen = 1;
594 return 0; 541 return 0;
595} 542}
596 543
597static int perf_header__getbuffer64(struct perf_header *self, 544static int perf_header__getbuffer64(struct perf_header *header,
598 int fd, void *buf, size_t size) 545 int fd, void *buf, size_t size)
599{ 546{
600 if (do_read(fd, buf, size) <= 0) 547 if (readn(fd, buf, size) <= 0)
601 return -1; 548 return -1;
602 549
603 if (self->needs_swap) 550 if (header->needs_swap)
604 mem_bswap_64(buf, size); 551 mem_bswap_64(buf, size);
605 552
606 return 0; 553 return 0;
607} 554}
608 555
609int perf_header__process_sections(struct perf_header *self, int fd, 556int perf_header__process_sections(struct perf_header *header, int fd,
610 int (*process)(struct perf_file_section *self, 557 int (*process)(struct perf_file_section *section,
611 struct perf_header *ph, 558 struct perf_header *ph,
612 int feat, int fd)) 559 int feat, int fd))
613{ 560{
@@ -617,7 +564,7 @@ int perf_header__process_sections(struct perf_header *self, int fd,
617 int idx = 0; 564 int idx = 0;
618 int err = -1, feat = 1; 565 int err = -1, feat = 1;
619 566
620 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); 567 nr_sections = bitmap_weight(header->adds_features, HEADER_FEAT_BITS);
621 if (!nr_sections) 568 if (!nr_sections)
622 return 0; 569 return 0;
623 570
@@ -627,17 +574,17 @@ int perf_header__process_sections(struct perf_header *self, int fd,
627 574
628 sec_size = sizeof(*feat_sec) * nr_sections; 575 sec_size = sizeof(*feat_sec) * nr_sections;
629 576
630 lseek(fd, self->data_offset + self->data_size, SEEK_SET); 577 lseek(fd, header->data_offset + header->data_size, SEEK_SET);
631 578
632 if (perf_header__getbuffer64(self, fd, feat_sec, sec_size)) 579 if (perf_header__getbuffer64(header, fd, feat_sec, sec_size))
633 goto out_free; 580 goto out_free;
634 581
635 err = 0; 582 err = 0;
636 while (idx < nr_sections && feat < HEADER_LAST_FEATURE) { 583 while (idx < nr_sections && feat < HEADER_LAST_FEATURE) {
637 if (perf_header__has_feat(self, feat)) { 584 if (perf_header__has_feat(header, feat)) {
638 struct perf_file_section *sec = &feat_sec[idx++]; 585 struct perf_file_section *sec = &feat_sec[idx++];
639 586
640 err = process(sec, self, feat, fd); 587 err = process(sec, header, feat, fd);
641 if (err < 0) 588 if (err < 0)
642 break; 589 break;
643 } 590 }
@@ -648,35 +595,35 @@ out_free:
648 return err; 595 return err;
649} 596}
650 597
651int perf_file_header__read(struct perf_file_header *self, 598int perf_file_header__read(struct perf_file_header *header,
652 struct perf_header *ph, int fd) 599 struct perf_header *ph, int fd)
653{ 600{
654 lseek(fd, 0, SEEK_SET); 601 lseek(fd, 0, SEEK_SET);
655 602
656 if (do_read(fd, self, sizeof(*self)) <= 0 || 603 if (readn(fd, header, sizeof(*header)) <= 0 ||
657 memcmp(&self->magic, __perf_magic, sizeof(self->magic))) 604 memcmp(&header->magic, __perf_magic, sizeof(header->magic)))
658 return -1; 605 return -1;
659 606
660 if (self->attr_size != sizeof(struct perf_file_attr)) { 607 if (header->attr_size != sizeof(struct perf_file_attr)) {
661 u64 attr_size = bswap_64(self->attr_size); 608 u64 attr_size = bswap_64(header->attr_size);
662 609
663 if (attr_size != sizeof(struct perf_file_attr)) 610 if (attr_size != sizeof(struct perf_file_attr))
664 return -1; 611 return -1;
665 612
666 mem_bswap_64(self, offsetof(struct perf_file_header, 613 mem_bswap_64(header, offsetof(struct perf_file_header,
667 adds_features)); 614 adds_features));
668 ph->needs_swap = true; 615 ph->needs_swap = true;
669 } 616 }
670 617
671 if (self->size != sizeof(*self)) { 618 if (header->size != sizeof(*header)) {
672 /* Support the previous format */ 619 /* Support the previous format */
673 if (self->size == offsetof(typeof(*self), adds_features)) 620 if (header->size == offsetof(typeof(*header), adds_features))
674 bitmap_zero(self->adds_features, HEADER_FEAT_BITS); 621 bitmap_zero(header->adds_features, HEADER_FEAT_BITS);
675 else 622 else
676 return -1; 623 return -1;
677 } 624 }
678 625
679 memcpy(&ph->adds_features, &self->adds_features, 626 memcpy(&ph->adds_features, &header->adds_features,
680 sizeof(ph->adds_features)); 627 sizeof(ph->adds_features));
681 /* 628 /*
682 * FIXME: hack that assumes that if we need swap the perf.data file 629 * FIXME: hack that assumes that if we need swap the perf.data file
@@ -690,10 +637,10 @@ int perf_file_header__read(struct perf_file_header *self,
690 perf_header__set_feat(ph, HEADER_BUILD_ID); 637 perf_header__set_feat(ph, HEADER_BUILD_ID);
691 } 638 }
692 639
693 ph->event_offset = self->event_types.offset; 640 ph->event_offset = header->event_types.offset;
694 ph->event_size = self->event_types.size; 641 ph->event_size = header->event_types.size;
695 ph->data_offset = self->data.offset; 642 ph->data_offset = header->data.offset;
696 ph->data_size = self->data.size; 643 ph->data_size = header->data.size;
697 return 0; 644 return 0;
698} 645}
699 646
@@ -752,14 +699,50 @@ out:
752 return err; 699 return err;
753} 700}
754 701
755static int perf_header__read_build_ids(struct perf_header *self, 702static int perf_header__read_build_ids_abi_quirk(struct perf_header *header,
756 int input, u64 offset, u64 size) 703 int input, u64 offset, u64 size)
757{ 704{
758 struct perf_session *session = container_of(self, 705 struct perf_session *session = container_of(header, struct perf_session, header);
759 struct perf_session, header); 706 struct {
707 struct perf_event_header header;
708 u8 build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))];
709 char filename[0];
710 } old_bev;
760 struct build_id_event bev; 711 struct build_id_event bev;
761 char filename[PATH_MAX]; 712 char filename[PATH_MAX];
762 u64 limit = offset + size; 713 u64 limit = offset + size;
714
715 while (offset < limit) {
716 ssize_t len;
717
718 if (read(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev))
719 return -1;
720
721 if (header->needs_swap)
722 perf_event_header__bswap(&old_bev.header);
723
724 len = old_bev.header.size - sizeof(old_bev);
725 if (read(input, filename, len) != len)
726 return -1;
727
728 bev.header = old_bev.header;
729 bev.pid = 0;
730 memcpy(bev.build_id, old_bev.build_id, sizeof(bev.build_id));
731 __event_process_build_id(&bev, filename, session);
732
733 offset += bev.header.size;
734 }
735
736 return 0;
737}
738
739static int perf_header__read_build_ids(struct perf_header *header,
740 int input, u64 offset, u64 size)
741{
742 struct perf_session *session = container_of(header, struct perf_session, header);
743 struct build_id_event bev;
744 char filename[PATH_MAX];
745 u64 limit = offset + size, orig_offset = offset;
763 int err = -1; 746 int err = -1;
764 747
765 while (offset < limit) { 748 while (offset < limit) {
@@ -768,12 +751,30 @@ static int perf_header__read_build_ids(struct perf_header *self,
768 if (read(input, &bev, sizeof(bev)) != sizeof(bev)) 751 if (read(input, &bev, sizeof(bev)) != sizeof(bev))
769 goto out; 752 goto out;
770 753
771 if (self->needs_swap) 754 if (header->needs_swap)
772 perf_event_header__bswap(&bev.header); 755 perf_event_header__bswap(&bev.header);
773 756
774 len = bev.header.size - sizeof(bev); 757 len = bev.header.size - sizeof(bev);
775 if (read(input, filename, len) != len) 758 if (read(input, filename, len) != len)
776 goto out; 759 goto out;
760 /*
761 * The a1645ce1 changeset:
762 *
763 * "perf: 'perf kvm' tool for monitoring guest performance from host"
764 *
765 * Added a field to struct build_id_event that broke the file
766 * format.
767 *
768 * Since the kernel build-id is the first entry, process the
769 * table using the old format if the well known
770 * '[kernel.kallsyms]' string for the kernel build-id has the
771 * first 4 characters chopped off (where the pid_t sits).
772 */
773 if (memcmp(filename, "nel.kallsyms]", 13) == 0) {
774 if (lseek(input, orig_offset, SEEK_SET) == (off_t)-1)
775 return -1;
776 return perf_header__read_build_ids_abi_quirk(header, input, offset, size);
777 }
777 778
778 __event_process_build_id(&bev, filename, session); 779 __event_process_build_id(&bev, filename, session);
779 780
@@ -784,13 +785,13 @@ out:
784 return err; 785 return err;
785} 786}
786 787
787static int perf_file_section__process(struct perf_file_section *self, 788static int perf_file_section__process(struct perf_file_section *section,
788 struct perf_header *ph, 789 struct perf_header *ph,
789 int feat, int fd) 790 int feat, int fd)
790{ 791{
791 if (lseek(fd, self->offset, SEEK_SET) == (off_t)-1) { 792 if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) {
792 pr_debug("Failed to lseek to %Ld offset for feature %d, " 793 pr_debug("Failed to lseek to %" PRIu64 " offset for feature "
793 "continuing...\n", self->offset, feat); 794 "%d, continuing...\n", section->offset, feat);
794 return 0; 795 return 0;
795 } 796 }
796 797
@@ -800,7 +801,7 @@ static int perf_file_section__process(struct perf_file_section *self,
800 break; 801 break;
801 802
802 case HEADER_BUILD_ID: 803 case HEADER_BUILD_ID:
803 if (perf_header__read_build_ids(ph, fd, self->offset, self->size)) 804 if (perf_header__read_build_ids(ph, fd, section->offset, section->size))
804 pr_debug("Failed to read buildids, continuing...\n"); 805 pr_debug("Failed to read buildids, continuing...\n");
805 break; 806 break;
806 default: 807 default:
@@ -810,21 +811,21 @@ static int perf_file_section__process(struct perf_file_section *self,
810 return 0; 811 return 0;
811} 812}
812 813
813static int perf_file_header__read_pipe(struct perf_pipe_file_header *self, 814static int perf_file_header__read_pipe(struct perf_pipe_file_header *header,
814 struct perf_header *ph, int fd, 815 struct perf_header *ph, int fd,
815 bool repipe) 816 bool repipe)
816{ 817{
817 if (do_read(fd, self, sizeof(*self)) <= 0 || 818 if (readn(fd, header, sizeof(*header)) <= 0 ||
818 memcmp(&self->magic, __perf_magic, sizeof(self->magic))) 819 memcmp(&header->magic, __perf_magic, sizeof(header->magic)))
819 return -1; 820 return -1;
820 821
821 if (repipe && do_write(STDOUT_FILENO, self, sizeof(*self)) < 0) 822 if (repipe && do_write(STDOUT_FILENO, header, sizeof(*header)) < 0)
822 return -1; 823 return -1;
823 824
824 if (self->size != sizeof(*self)) { 825 if (header->size != sizeof(*header)) {
825 u64 size = bswap_64(self->size); 826 u64 size = bswap_64(header->size);
826 827
827 if (size != sizeof(*self)) 828 if (size != sizeof(*header))
828 return -1; 829 return -1;
829 830
830 ph->needs_swap = true; 831 ph->needs_swap = true;
@@ -835,10 +836,10 @@ static int perf_file_header__read_pipe(struct perf_pipe_file_header *self,
835 836
836static int perf_header__read_pipe(struct perf_session *session, int fd) 837static int perf_header__read_pipe(struct perf_session *session, int fd)
837{ 838{
838 struct perf_header *self = &session->header; 839 struct perf_header *header = &session->header;
839 struct perf_pipe_file_header f_header; 840 struct perf_pipe_file_header f_header;
840 841
841 if (perf_file_header__read_pipe(&f_header, self, fd, 842 if (perf_file_header__read_pipe(&f_header, header, fd,
842 session->repipe) < 0) { 843 session->repipe) < 0) {
843 pr_debug("incompatible file format\n"); 844 pr_debug("incompatible file format\n");
844 return -EINVAL; 845 return -EINVAL;
@@ -849,18 +850,22 @@ static int perf_header__read_pipe(struct perf_session *session, int fd)
849 return 0; 850 return 0;
850} 851}
851 852
852int perf_header__read(struct perf_session *session, int fd) 853int perf_session__read_header(struct perf_session *session, int fd)
853{ 854{
854 struct perf_header *self = &session->header; 855 struct perf_header *header = &session->header;
855 struct perf_file_header f_header; 856 struct perf_file_header f_header;
856 struct perf_file_attr f_attr; 857 struct perf_file_attr f_attr;
857 u64 f_id; 858 u64 f_id;
858 int nr_attrs, nr_ids, i, j; 859 int nr_attrs, nr_ids, i, j;
859 860
861 session->evlist = perf_evlist__new(NULL, NULL);
862 if (session->evlist == NULL)
863 return -ENOMEM;
864
860 if (session->fd_pipe) 865 if (session->fd_pipe)
861 return perf_header__read_pipe(session, fd); 866 return perf_header__read_pipe(session, fd);
862 867
863 if (perf_file_header__read(&f_header, self, fd) < 0) { 868 if (perf_file_header__read(&f_header, header, fd) < 0) {
864 pr_debug("incompatible file format\n"); 869 pr_debug("incompatible file format\n");
865 return -EINVAL; 870 return -EINVAL;
866 } 871 }
@@ -869,33 +874,39 @@ int perf_header__read(struct perf_session *session, int fd)
869 lseek(fd, f_header.attrs.offset, SEEK_SET); 874 lseek(fd, f_header.attrs.offset, SEEK_SET);
870 875
871 for (i = 0; i < nr_attrs; i++) { 876 for (i = 0; i < nr_attrs; i++) {
872 struct perf_header_attr *attr; 877 struct perf_evsel *evsel;
873 off_t tmp; 878 off_t tmp;
874 879
875 if (perf_header__getbuffer64(self, fd, &f_attr, sizeof(f_attr))) 880 if (perf_header__getbuffer64(header, fd, &f_attr, sizeof(f_attr)))
876 goto out_errno; 881 goto out_errno;
877 882
878 tmp = lseek(fd, 0, SEEK_CUR); 883 tmp = lseek(fd, 0, SEEK_CUR);
884 evsel = perf_evsel__new(&f_attr.attr, i);
879 885
880 attr = perf_header_attr__new(&f_attr.attr); 886 if (evsel == NULL)
881 if (attr == NULL) 887 goto out_delete_evlist;
882 return -ENOMEM; 888 /*
889 * Do it before so that if perf_evsel__alloc_id fails, this
890 * entry gets purged too at perf_evlist__delete().
891 */
892 perf_evlist__add(session->evlist, evsel);
883 893
884 nr_ids = f_attr.ids.size / sizeof(u64); 894 nr_ids = f_attr.ids.size / sizeof(u64);
895 /*
896 * We don't have the cpu and thread maps on the header, so
897 * for allocating the perf_sample_id table we fake 1 cpu and
898 * hattr->ids threads.
899 */
900 if (perf_evsel__alloc_id(evsel, 1, nr_ids))
901 goto out_delete_evlist;
902
885 lseek(fd, f_attr.ids.offset, SEEK_SET); 903 lseek(fd, f_attr.ids.offset, SEEK_SET);
886 904
887 for (j = 0; j < nr_ids; j++) { 905 for (j = 0; j < nr_ids; j++) {
888 if (perf_header__getbuffer64(self, fd, &f_id, sizeof(f_id))) 906 if (perf_header__getbuffer64(header, fd, &f_id, sizeof(f_id)))
889 goto out_errno; 907 goto out_errno;
890 908
891 if (perf_header_attr__add_id(attr, f_id) < 0) { 909 perf_evlist__id_add(session->evlist, evsel, 0, j, f_id);
892 perf_header_attr__delete(attr);
893 return -ENOMEM;
894 }
895 }
896 if (perf_header__add_attr(self, attr) < 0) {
897 perf_header_attr__delete(attr);
898 return -ENOMEM;
899 } 910 }
900 911
901 lseek(fd, tmp, SEEK_SET); 912 lseek(fd, tmp, SEEK_SET);
@@ -906,70 +917,32 @@ int perf_header__read(struct perf_session *session, int fd)
906 events = malloc(f_header.event_types.size); 917 events = malloc(f_header.event_types.size);
907 if (events == NULL) 918 if (events == NULL)
908 return -ENOMEM; 919 return -ENOMEM;
909 if (perf_header__getbuffer64(self, fd, events, 920 if (perf_header__getbuffer64(header, fd, events,
910 f_header.event_types.size)) 921 f_header.event_types.size))
911 goto out_errno; 922 goto out_errno;
912 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); 923 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
913 } 924 }
914 925
915 perf_header__process_sections(self, fd, perf_file_section__process); 926 perf_header__process_sections(header, fd, perf_file_section__process);
916 927
917 lseek(fd, self->data_offset, SEEK_SET); 928 lseek(fd, header->data_offset, SEEK_SET);
918 929
919 self->frozen = 1; 930 header->frozen = 1;
920 return 0; 931 return 0;
921out_errno: 932out_errno:
922 return -errno; 933 return -errno;
923}
924
925u64 perf_header__sample_type(struct perf_header *header)
926{
927 u64 type = 0;
928 int i;
929
930 for (i = 0; i < header->attrs; i++) {
931 struct perf_header_attr *attr = header->attr[i];
932
933 if (!type)
934 type = attr->attr.sample_type;
935 else if (type != attr->attr.sample_type)
936 die("non matching sample_type");
937 }
938
939 return type;
940}
941
942struct perf_event_attr *
943perf_header__find_attr(u64 id, struct perf_header *header)
944{
945 int i;
946
947 /*
948 * We set id to -1 if the data file doesn't contain sample
949 * ids. Check for this and avoid walking through the entire
950 * list of ids which may be large.
951 */
952 if (id == -1ULL)
953 return NULL;
954
955 for (i = 0; i < header->attrs; i++) {
956 struct perf_header_attr *attr = header->attr[i];
957 int j;
958
959 for (j = 0; j < attr->ids; j++) {
960 if (attr->id[j] == id)
961 return &attr->attr;
962 }
963 }
964 934
965 return NULL; 935out_delete_evlist:
936 perf_evlist__delete(session->evlist);
937 session->evlist = NULL;
938 return -ENOMEM;
966} 939}
967 940
968int event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, 941int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id,
969 event__handler_t process, 942 perf_event__handler_t process,
970 struct perf_session *session) 943 struct perf_session *session)
971{ 944{
972 event_t *ev; 945 union perf_event *ev;
973 size_t size; 946 size_t size;
974 int err; 947 int err;
975 948
@@ -980,31 +953,31 @@ int event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id,
980 953
981 ev = malloc(size); 954 ev = malloc(size);
982 955
956 if (ev == NULL)
957 return -ENOMEM;
958
983 ev->attr.attr = *attr; 959 ev->attr.attr = *attr;
984 memcpy(ev->attr.id, id, ids * sizeof(u64)); 960 memcpy(ev->attr.id, id, ids * sizeof(u64));
985 961
986 ev->attr.header.type = PERF_RECORD_HEADER_ATTR; 962 ev->attr.header.type = PERF_RECORD_HEADER_ATTR;
987 ev->attr.header.size = size; 963 ev->attr.header.size = size;
988 964
989 err = process(ev, session); 965 err = process(ev, NULL, session);
990 966
991 free(ev); 967 free(ev);
992 968
993 return err; 969 return err;
994} 970}
995 971
996int event__synthesize_attrs(struct perf_header *self, 972int perf_session__synthesize_attrs(struct perf_session *session,
997 event__handler_t process, 973 perf_event__handler_t process)
998 struct perf_session *session)
999{ 974{
1000 struct perf_header_attr *attr; 975 struct perf_evsel *attr;
1001 int i, err = 0; 976 int err = 0;
1002
1003 for (i = 0; i < self->attrs; i++) {
1004 attr = self->attr[i];
1005 977
1006 err = event__synthesize_attr(&attr->attr, attr->ids, attr->id, 978 list_for_each_entry(attr, &session->evlist->entries, node) {
1007 process, session); 979 err = perf_event__synthesize_attr(&attr->attr, attr->ids,
980 attr->id, process, session);
1008 if (err) { 981 if (err) {
1009 pr_debug("failed to create perf header attribute\n"); 982 pr_debug("failed to create perf header attribute\n");
1010 return err; 983 return err;
@@ -1014,29 +987,39 @@ int event__synthesize_attrs(struct perf_header *self,
1014 return err; 987 return err;
1015} 988}
1016 989
1017int event__process_attr(event_t *self, struct perf_session *session) 990int perf_event__process_attr(union perf_event *event,
991 struct perf_session *session)
1018{ 992{
1019 struct perf_header_attr *attr;
1020 unsigned int i, ids, n_ids; 993 unsigned int i, ids, n_ids;
994 struct perf_evsel *evsel;
995
996 if (session->evlist == NULL) {
997 session->evlist = perf_evlist__new(NULL, NULL);
998 if (session->evlist == NULL)
999 return -ENOMEM;
1000 }
1021 1001
1022 attr = perf_header_attr__new(&self->attr.attr); 1002 evsel = perf_evsel__new(&event->attr.attr,
1023 if (attr == NULL) 1003 session->evlist->nr_entries);
1004 if (evsel == NULL)
1024 return -ENOMEM; 1005 return -ENOMEM;
1025 1006
1026 ids = self->header.size; 1007 perf_evlist__add(session->evlist, evsel);
1027 ids -= (void *)&self->attr.id - (void *)self; 1008
1009 ids = event->header.size;
1010 ids -= (void *)&event->attr.id - (void *)event;
1028 n_ids = ids / sizeof(u64); 1011 n_ids = ids / sizeof(u64);
1012 /*
1013 * We don't have the cpu and thread maps on the header, so
1014 * for allocating the perf_sample_id table we fake 1 cpu and
1015 * hattr->ids threads.
1016 */
1017 if (perf_evsel__alloc_id(evsel, 1, n_ids))
1018 return -ENOMEM;
1029 1019
1030 for (i = 0; i < n_ids; i++) { 1020 for (i = 0; i < n_ids; i++) {
1031 if (perf_header_attr__add_id(attr, self->attr.id[i]) < 0) { 1021 perf_evlist__id_add(session->evlist, evsel, 0, i,
1032 perf_header_attr__delete(attr); 1022 event->attr.id[i]);
1033 return -ENOMEM;
1034 }
1035 }
1036
1037 if (perf_header__add_attr(&session->header, attr) < 0) {
1038 perf_header_attr__delete(attr);
1039 return -ENOMEM;
1040 } 1023 }
1041 1024
1042 perf_session__update_sample_type(session); 1025 perf_session__update_sample_type(session);
@@ -1044,11 +1027,11 @@ int event__process_attr(event_t *self, struct perf_session *session)
1044 return 0; 1027 return 0;
1045} 1028}
1046 1029
1047int event__synthesize_event_type(u64 event_id, char *name, 1030int perf_event__synthesize_event_type(u64 event_id, char *name,
1048 event__handler_t process, 1031 perf_event__handler_t process,
1049 struct perf_session *session) 1032 struct perf_session *session)
1050{ 1033{
1051 event_t ev; 1034 union perf_event ev;
1052 size_t size = 0; 1035 size_t size = 0;
1053 int err = 0; 1036 int err = 0;
1054 1037
@@ -1064,13 +1047,13 @@ int event__synthesize_event_type(u64 event_id, char *name,
1064 ev.event_type.header.size = sizeof(ev.event_type) - 1047 ev.event_type.header.size = sizeof(ev.event_type) -
1065 (sizeof(ev.event_type.event_type.name) - size); 1048 (sizeof(ev.event_type.event_type.name) - size);
1066 1049
1067 err = process(&ev, session); 1050 err = process(&ev, NULL, session);
1068 1051
1069 return err; 1052 return err;
1070} 1053}
1071 1054
1072int event__synthesize_event_types(event__handler_t process, 1055int perf_event__synthesize_event_types(perf_event__handler_t process,
1073 struct perf_session *session) 1056 struct perf_session *session)
1074{ 1057{
1075 struct perf_trace_event_type *type; 1058 struct perf_trace_event_type *type;
1076 int i, err = 0; 1059 int i, err = 0;
@@ -1078,8 +1061,9 @@ int event__synthesize_event_types(event__handler_t process,
1078 for (i = 0; i < event_count; i++) { 1061 for (i = 0; i < event_count; i++) {
1079 type = &events[i]; 1062 type = &events[i];
1080 1063
1081 err = event__synthesize_event_type(type->event_id, type->name, 1064 err = perf_event__synthesize_event_type(type->event_id,
1082 process, session); 1065 type->name, process,
1066 session);
1083 if (err) { 1067 if (err) {
1084 pr_debug("failed to create perf header event type\n"); 1068 pr_debug("failed to create perf header event type\n");
1085 return err; 1069 return err;
@@ -1089,29 +1073,28 @@ int event__synthesize_event_types(event__handler_t process,
1089 return err; 1073 return err;
1090} 1074}
1091 1075
1092int event__process_event_type(event_t *self, 1076int perf_event__process_event_type(union perf_event *event,
1093 struct perf_session *session __unused) 1077 struct perf_session *session __unused)
1094{ 1078{
1095 if (perf_header__push_event(self->event_type.event_type.event_id, 1079 if (perf_header__push_event(event->event_type.event_type.event_id,
1096 self->event_type.event_type.name) < 0) 1080 event->event_type.event_type.name) < 0)
1097 return -ENOMEM; 1081 return -ENOMEM;
1098 1082
1099 return 0; 1083 return 0;
1100} 1084}
1101 1085
1102int event__synthesize_tracing_data(int fd, struct perf_event_attr *pattrs, 1086int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist,
1103 int nb_events, 1087 perf_event__handler_t process,
1104 event__handler_t process,
1105 struct perf_session *session __unused) 1088 struct perf_session *session __unused)
1106{ 1089{
1107 event_t ev; 1090 union perf_event ev;
1108 ssize_t size = 0, aligned_size = 0, padding; 1091 ssize_t size = 0, aligned_size = 0, padding;
1109 int err = 0; 1092 int err __used = 0;
1110 1093
1111 memset(&ev, 0, sizeof(ev)); 1094 memset(&ev, 0, sizeof(ev));
1112 1095
1113 ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA; 1096 ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA;
1114 size = read_tracing_data_size(fd, pattrs, nb_events); 1097 size = read_tracing_data_size(fd, &evlist->entries);
1115 if (size <= 0) 1098 if (size <= 0)
1116 return size; 1099 return size;
1117 aligned_size = ALIGN(size, sizeof(u64)); 1100 aligned_size = ALIGN(size, sizeof(u64));
@@ -1119,18 +1102,18 @@ int event__synthesize_tracing_data(int fd, struct perf_event_attr *pattrs,
1119 ev.tracing_data.header.size = sizeof(ev.tracing_data); 1102 ev.tracing_data.header.size = sizeof(ev.tracing_data);
1120 ev.tracing_data.size = aligned_size; 1103 ev.tracing_data.size = aligned_size;
1121 1104
1122 process(&ev, session); 1105 process(&ev, NULL, session);
1123 1106
1124 err = read_tracing_data(fd, pattrs, nb_events); 1107 err = read_tracing_data(fd, &evlist->entries);
1125 write_padded(fd, NULL, 0, padding); 1108 write_padded(fd, NULL, 0, padding);
1126 1109
1127 return aligned_size; 1110 return aligned_size;
1128} 1111}
1129 1112
1130int event__process_tracing_data(event_t *self, 1113int perf_event__process_tracing_data(union perf_event *event,
1131 struct perf_session *session) 1114 struct perf_session *session)
1132{ 1115{
1133 ssize_t size_read, padding, size = self->tracing_data.size; 1116 ssize_t size_read, padding, size = event->tracing_data.size;
1134 off_t offset = lseek(session->fd, 0, SEEK_CUR); 1117 off_t offset = lseek(session->fd, 0, SEEK_CUR);
1135 char buf[BUFSIZ]; 1118 char buf[BUFSIZ];
1136 1119
@@ -1156,12 +1139,12 @@ int event__process_tracing_data(event_t *self,
1156 return size_read + padding; 1139 return size_read + padding;
1157} 1140}
1158 1141
1159int event__synthesize_build_id(struct dso *pos, u16 misc, 1142int perf_event__synthesize_build_id(struct dso *pos, u16 misc,
1160 event__handler_t process, 1143 perf_event__handler_t process,
1161 struct machine *machine, 1144 struct machine *machine,
1162 struct perf_session *session) 1145 struct perf_session *session)
1163{ 1146{
1164 event_t ev; 1147 union perf_event ev;
1165 size_t len; 1148 size_t len;
1166 int err = 0; 1149 int err = 0;
1167 1150
@@ -1179,16 +1162,16 @@ int event__synthesize_build_id(struct dso *pos, u16 misc,
1179 ev.build_id.header.size = sizeof(ev.build_id) + len; 1162 ev.build_id.header.size = sizeof(ev.build_id) + len;
1180 memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len); 1163 memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len);
1181 1164
1182 err = process(&ev, session); 1165 err = process(&ev, NULL, session);
1183 1166
1184 return err; 1167 return err;
1185} 1168}
1186 1169
1187int event__process_build_id(event_t *self, 1170int perf_event__process_build_id(union perf_event *event,
1188 struct perf_session *session) 1171 struct perf_session *session)
1189{ 1172{
1190 __event_process_build_id(&self->build_id, 1173 __event_process_build_id(&event->build_id,
1191 self->build_id.filename, 1174 event->build_id.filename,
1192 session); 1175 session);
1193 return 0; 1176 return 0;
1194} 1177}
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 402ac2454cf8..1886256768a1 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -9,13 +9,6 @@
9 9
10#include <linux/bitmap.h> 10#include <linux/bitmap.h>
11 11
12struct perf_header_attr {
13 struct perf_event_attr attr;
14 int ids, size;
15 u64 *id;
16 off_t id_offset;
17};
18
19enum { 12enum {
20 HEADER_TRACE_INFO = 1, 13 HEADER_TRACE_INFO = 1,
21 HEADER_BUILD_ID, 14 HEADER_BUILD_ID,
@@ -46,14 +39,12 @@ struct perf_pipe_file_header {
46 39
47struct perf_header; 40struct perf_header;
48 41
49int perf_file_header__read(struct perf_file_header *self, 42int perf_file_header__read(struct perf_file_header *header,
50 struct perf_header *ph, int fd); 43 struct perf_header *ph, int fd);
51 44
52struct perf_header { 45struct perf_header {
53 int frozen; 46 int frozen;
54 int attrs, size;
55 bool needs_swap; 47 bool needs_swap;
56 struct perf_header_attr **attr;
57 s64 attr_offset; 48 s64 attr_offset;
58 u64 data_offset; 49 u64 data_offset;
59 u64 data_size; 50 u64 data_size;
@@ -62,32 +53,23 @@ struct perf_header {
62 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS); 53 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
63}; 54};
64 55
65int perf_header__init(struct perf_header *self); 56struct perf_evlist;
66void perf_header__exit(struct perf_header *self);
67 57
68int perf_header__read(struct perf_session *session, int fd); 58int perf_session__read_header(struct perf_session *session, int fd);
69int perf_header__write(struct perf_header *self, int fd, bool at_exit); 59int perf_session__write_header(struct perf_session *session,
60 struct perf_evlist *evlist,
61 int fd, bool at_exit);
70int perf_header__write_pipe(int fd); 62int perf_header__write_pipe(int fd);
71 63
72int perf_header__add_attr(struct perf_header *self,
73 struct perf_header_attr *attr);
74
75int perf_header__push_event(u64 id, const char *name); 64int perf_header__push_event(u64 id, const char *name);
76char *perf_header__find_event(u64 id); 65char *perf_header__find_event(u64 id);
77 66
78struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr); 67void perf_header__set_feat(struct perf_header *header, int feat);
79void perf_header_attr__delete(struct perf_header_attr *self); 68void perf_header__clear_feat(struct perf_header *header, int feat);
69bool perf_header__has_feat(const struct perf_header *header, int feat);
80 70
81int perf_header_attr__add_id(struct perf_header_attr *self, u64 id); 71int perf_header__process_sections(struct perf_header *header, int fd,
82 72 int (*process)(struct perf_file_section *section,
83u64 perf_header__sample_type(struct perf_header *header);
84struct perf_event_attr *
85perf_header__find_attr(u64 id, struct perf_header *header);
86void perf_header__set_feat(struct perf_header *self, int feat);
87bool perf_header__has_feat(const struct perf_header *self, int feat);
88
89int perf_header__process_sections(struct perf_header *self, int fd,
90 int (*process)(struct perf_file_section *self,
91 struct perf_header *ph, 73 struct perf_header *ph,
92 int feat, int fd)); 74 int feat, int fd));
93 75
@@ -95,33 +77,31 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
95 const char *name, bool is_kallsyms); 77 const char *name, bool is_kallsyms);
96int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir); 78int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir);
97 79
98int event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, 80int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id,
99 event__handler_t process, 81 perf_event__handler_t process,
100 struct perf_session *session);
101int event__synthesize_attrs(struct perf_header *self,
102 event__handler_t process,
103 struct perf_session *session);
104int event__process_attr(event_t *self, struct perf_session *session);
105
106int event__synthesize_event_type(u64 event_id, char *name,
107 event__handler_t process,
108 struct perf_session *session);
109int event__synthesize_event_types(event__handler_t process,
110 struct perf_session *session);
111int event__process_event_type(event_t *self,
112 struct perf_session *session);
113
114int event__synthesize_tracing_data(int fd, struct perf_event_attr *pattrs,
115 int nb_events,
116 event__handler_t process,
117 struct perf_session *session);
118int event__process_tracing_data(event_t *self,
119 struct perf_session *session); 82 struct perf_session *session);
83int perf_session__synthesize_attrs(struct perf_session *session,
84 perf_event__handler_t process);
85int perf_event__process_attr(union perf_event *event, struct perf_session *session);
86
87int perf_event__synthesize_event_type(u64 event_id, char *name,
88 perf_event__handler_t process,
89 struct perf_session *session);
90int perf_event__synthesize_event_types(perf_event__handler_t process,
91 struct perf_session *session);
92int perf_event__process_event_type(union perf_event *event,
93 struct perf_session *session);
120 94
121int event__synthesize_build_id(struct dso *pos, u16 misc, 95int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist,
122 event__handler_t process, 96 perf_event__handler_t process,
123 struct machine *machine, 97 struct perf_session *session);
124 struct perf_session *session); 98int perf_event__process_tracing_data(union perf_event *event,
125int event__process_build_id(event_t *self, struct perf_session *session); 99 struct perf_session *session);
126 100
101int perf_event__synthesize_build_id(struct dso *pos, u16 misc,
102 perf_event__handler_t process,
103 struct machine *machine,
104 struct perf_session *session);
105int perf_event__process_build_id(union perf_event *event,
106 struct perf_session *session);
127#endif /* __PERF_HEADER_H */ 107#endif /* __PERF_HEADER_H */
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index be22ae6ef055..627a02e03c57 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -1,3 +1,4 @@
1#include "annotate.h"
1#include "util.h" 2#include "util.h"
2#include "build-id.h" 3#include "build-id.h"
3#include "hist.h" 4#include "hist.h"
@@ -49,6 +50,15 @@ static void hists__calc_col_len(struct hists *self, struct hist_entry *h)
49 50
50 if (h->ms.sym) 51 if (h->ms.sym)
51 hists__new_col_len(self, HISTC_SYMBOL, h->ms.sym->namelen); 52 hists__new_col_len(self, HISTC_SYMBOL, h->ms.sym->namelen);
53 else {
54 const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
55
56 if (hists__col_len(self, HISTC_DSO) < unresolved_col_width &&
57 !symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
58 !symbol_conf.dso_list)
59 hists__set_col_len(self, HISTC_DSO,
60 unresolved_col_width);
61 }
52 62
53 len = thread__comm_len(h->thread); 63 len = thread__comm_len(h->thread);
54 if (hists__new_col_len(self, HISTC_COMM, len)) 64 if (hists__new_col_len(self, HISTC_COMM, len))
@@ -87,7 +97,7 @@ static void hist_entry__add_cpumode_period(struct hist_entry *self,
87 97
88static struct hist_entry *hist_entry__new(struct hist_entry *template) 98static struct hist_entry *hist_entry__new(struct hist_entry *template)
89{ 99{
90 size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_node) : 0; 100 size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_root) : 0;
91 struct hist_entry *self = malloc(sizeof(*self) + callchain_size); 101 struct hist_entry *self = malloc(sizeof(*self) + callchain_size);
92 102
93 if (self != NULL) { 103 if (self != NULL) {
@@ -211,7 +221,9 @@ void hist_entry__free(struct hist_entry *he)
211 * collapse the histogram 221 * collapse the histogram
212 */ 222 */
213 223
214static bool collapse__insert_entry(struct rb_root *root, struct hist_entry *he) 224static bool hists__collapse_insert_entry(struct hists *self,
225 struct rb_root *root,
226 struct hist_entry *he)
215{ 227{
216 struct rb_node **p = &root->rb_node; 228 struct rb_node **p = &root->rb_node;
217 struct rb_node *parent = NULL; 229 struct rb_node *parent = NULL;
@@ -226,6 +238,11 @@ static bool collapse__insert_entry(struct rb_root *root, struct hist_entry *he)
226 238
227 if (!cmp) { 239 if (!cmp) {
228 iter->period += he->period; 240 iter->period += he->period;
241 if (symbol_conf.use_callchain) {
242 callchain_cursor_reset(&self->callchain_cursor);
243 callchain_merge(&self->callchain_cursor, iter->callchain,
244 he->callchain);
245 }
229 hist_entry__free(he); 246 hist_entry__free(he);
230 return false; 247 return false;
231 } 248 }
@@ -260,7 +277,7 @@ void hists__collapse_resort(struct hists *self)
260 next = rb_next(&n->rb_node); 277 next = rb_next(&n->rb_node);
261 278
262 rb_erase(&n->rb_node, &self->entries); 279 rb_erase(&n->rb_node, &self->entries);
263 if (collapse__insert_entry(&tmp, n)) 280 if (hists__collapse_insert_entry(self, &tmp, n))
264 hists__inc_nr_entries(self, n); 281 hists__inc_nr_entries(self, n);
265 } 282 }
266 283
@@ -354,7 +371,7 @@ static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
354 371
355static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, 372static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
356 int depth, int depth_mask, int period, 373 int depth, int depth_mask, int period,
357 u64 total_samples, int hits, 374 u64 total_samples, u64 hits,
358 int left_margin) 375 int left_margin)
359{ 376{
360 int i; 377 int i;
@@ -423,7 +440,7 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
423 u64 cumul; 440 u64 cumul;
424 441
425 child = rb_entry(node, struct callchain_node, rb_node); 442 child = rb_entry(node, struct callchain_node, rb_node);
426 cumul = cumul_hits(child); 443 cumul = callchain_cumul_hits(child);
427 remaining -= cumul; 444 remaining -= cumul;
428 445
429 /* 446 /*
@@ -583,6 +600,7 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
583{ 600{
584 struct sort_entry *se; 601 struct sort_entry *se;
585 u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us; 602 u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us;
603 u64 nr_events;
586 const char *sep = symbol_conf.field_sep; 604 const char *sep = symbol_conf.field_sep;
587 int ret; 605 int ret;
588 606
@@ -591,6 +609,7 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
591 609
592 if (pair_hists) { 610 if (pair_hists) {
593 period = self->pair ? self->pair->period : 0; 611 period = self->pair ? self->pair->period : 0;
612 nr_events = self->pair ? self->pair->nr_events : 0;
594 total = pair_hists->stats.total_period; 613 total = pair_hists->stats.total_period;
595 period_sys = self->pair ? self->pair->period_sys : 0; 614 period_sys = self->pair ? self->pair->period_sys : 0;
596 period_us = self->pair ? self->pair->period_us : 0; 615 period_us = self->pair ? self->pair->period_us : 0;
@@ -598,6 +617,7 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
598 period_guest_us = self->pair ? self->pair->period_guest_us : 0; 617 period_guest_us = self->pair ? self->pair->period_guest_us : 0;
599 } else { 618 } else {
600 period = self->period; 619 period = self->period;
620 nr_events = self->nr_events;
601 total = session_total; 621 total = session_total;
602 period_sys = self->period_sys; 622 period_sys = self->period_sys;
603 period_us = self->period_us; 623 period_us = self->period_us;
@@ -634,13 +654,13 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
634 } 654 }
635 } 655 }
636 } else 656 } else
637 ret = snprintf(s, size, sep ? "%lld" : "%12lld ", period); 657 ret = snprintf(s, size, sep ? "%" PRIu64 : "%12" PRIu64 " ", period);
638 658
639 if (symbol_conf.show_nr_samples) { 659 if (symbol_conf.show_nr_samples) {
640 if (sep) 660 if (sep)
641 ret += snprintf(s + ret, size - ret, "%c%lld", *sep, period); 661 ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, nr_events);
642 else 662 else
643 ret += snprintf(s + ret, size - ret, "%11lld", period); 663 ret += snprintf(s + ret, size - ret, "%11" PRIu64, nr_events);
644 } 664 }
645 665
646 if (pair_hists) { 666 if (pair_hists) {
@@ -942,216 +962,14 @@ void hists__filter_by_thread(struct hists *self, const struct thread *thread)
942 } 962 }
943} 963}
944 964
945static int symbol__alloc_hist(struct symbol *self) 965int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip)
946{
947 struct sym_priv *priv = symbol__priv(self);
948 const int size = (sizeof(*priv->hist) +
949 (self->end - self->start) * sizeof(u64));
950
951 priv->hist = zalloc(size);
952 return priv->hist == NULL ? -1 : 0;
953}
954
955int hist_entry__inc_addr_samples(struct hist_entry *self, u64 ip)
956{
957 unsigned int sym_size, offset;
958 struct symbol *sym = self->ms.sym;
959 struct sym_priv *priv;
960 struct sym_hist *h;
961
962 if (!sym || !self->ms.map)
963 return 0;
964
965 priv = symbol__priv(sym);
966 if (priv->hist == NULL && symbol__alloc_hist(sym) < 0)
967 return -ENOMEM;
968
969 sym_size = sym->end - sym->start;
970 offset = ip - sym->start;
971
972 pr_debug3("%s: ip=%#Lx\n", __func__, self->ms.map->unmap_ip(self->ms.map, ip));
973
974 if (offset >= sym_size)
975 return 0;
976
977 h = priv->hist;
978 h->sum++;
979 h->ip[offset]++;
980
981 pr_debug3("%#Lx %s: period++ [ip: %#Lx, %#Lx] => %Ld\n", self->ms.sym->start,
982 self->ms.sym->name, ip, ip - self->ms.sym->start, h->ip[offset]);
983 return 0;
984}
985
986static struct objdump_line *objdump_line__new(s64 offset, char *line, size_t privsize)
987{
988 struct objdump_line *self = malloc(sizeof(*self) + privsize);
989
990 if (self != NULL) {
991 self->offset = offset;
992 self->line = line;
993 }
994
995 return self;
996}
997
998void objdump_line__free(struct objdump_line *self)
999{
1000 free(self->line);
1001 free(self);
1002}
1003
1004static void objdump__add_line(struct list_head *head, struct objdump_line *line)
1005{
1006 list_add_tail(&line->node, head);
1007}
1008
1009struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
1010 struct objdump_line *pos)
1011{
1012 list_for_each_entry_continue(pos, head, node)
1013 if (pos->offset >= 0)
1014 return pos;
1015
1016 return NULL;
1017}
1018
1019static int hist_entry__parse_objdump_line(struct hist_entry *self, FILE *file,
1020 struct list_head *head, size_t privsize)
1021{ 966{
1022 struct symbol *sym = self->ms.sym; 967 return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip);
1023 struct objdump_line *objdump_line;
1024 char *line = NULL, *tmp, *tmp2, *c;
1025 size_t line_len;
1026 s64 line_ip, offset = -1;
1027
1028 if (getline(&line, &line_len, file) < 0)
1029 return -1;
1030
1031 if (!line)
1032 return -1;
1033
1034 while (line_len != 0 && isspace(line[line_len - 1]))
1035 line[--line_len] = '\0';
1036
1037 c = strchr(line, '\n');
1038 if (c)
1039 *c = 0;
1040
1041 line_ip = -1;
1042
1043 /*
1044 * Strip leading spaces:
1045 */
1046 tmp = line;
1047 while (*tmp) {
1048 if (*tmp != ' ')
1049 break;
1050 tmp++;
1051 }
1052
1053 if (*tmp) {
1054 /*
1055 * Parse hexa addresses followed by ':'
1056 */
1057 line_ip = strtoull(tmp, &tmp2, 16);
1058 if (*tmp2 != ':' || tmp == tmp2 || tmp2[1] == '\0')
1059 line_ip = -1;
1060 }
1061
1062 if (line_ip != -1) {
1063 u64 start = map__rip_2objdump(self->ms.map, sym->start),
1064 end = map__rip_2objdump(self->ms.map, sym->end);
1065
1066 offset = line_ip - start;
1067 if (offset < 0 || (u64)line_ip > end)
1068 offset = -1;
1069 }
1070
1071 objdump_line = objdump_line__new(offset, line, privsize);
1072 if (objdump_line == NULL) {
1073 free(line);
1074 return -1;
1075 }
1076 objdump__add_line(head, objdump_line);
1077
1078 return 0;
1079} 968}
1080 969
1081int hist_entry__annotate(struct hist_entry *self, struct list_head *head, 970int hist_entry__annotate(struct hist_entry *he, size_t privsize)
1082 size_t privsize)
1083{ 971{
1084 struct symbol *sym = self->ms.sym; 972 return symbol__annotate(he->ms.sym, he->ms.map, privsize);
1085 struct map *map = self->ms.map;
1086 struct dso *dso = map->dso;
1087 char *filename = dso__build_id_filename(dso, NULL, 0);
1088 bool free_filename = true;
1089 char command[PATH_MAX * 2];
1090 FILE *file;
1091 int err = 0;
1092 u64 len;
1093
1094 if (filename == NULL) {
1095 if (dso->has_build_id) {
1096 pr_err("Can't annotate %s: not enough memory\n",
1097 sym->name);
1098 return -ENOMEM;
1099 }
1100 goto fallback;
1101 } else if (readlink(filename, command, sizeof(command)) < 0 ||
1102 strstr(command, "[kernel.kallsyms]") ||
1103 access(filename, R_OK)) {
1104 free(filename);
1105fallback:
1106 /*
1107 * If we don't have build-ids or the build-id file isn't in the
1108 * cache, or is just a kallsyms file, well, lets hope that this
1109 * DSO is the same as when 'perf record' ran.
1110 */
1111 filename = dso->long_name;
1112 free_filename = false;
1113 }
1114
1115 if (dso->origin == DSO__ORIG_KERNEL) {
1116 if (dso->annotate_warned)
1117 goto out_free_filename;
1118 err = -ENOENT;
1119 dso->annotate_warned = 1;
1120 pr_err("Can't annotate %s: No vmlinux file was found in the "
1121 "path\n", sym->name);
1122 goto out_free_filename;
1123 }
1124
1125 pr_debug("%s: filename=%s, sym=%s, start=%#Lx, end=%#Lx\n", __func__,
1126 filename, sym->name, map->unmap_ip(map, sym->start),
1127 map->unmap_ip(map, sym->end));
1128
1129 len = sym->end - sym->start;
1130
1131 pr_debug("annotating [%p] %30s : [%p] %30s\n",
1132 dso, dso->long_name, sym, sym->name);
1133
1134 snprintf(command, sizeof(command),
1135 "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS -C %s|grep -v %s|expand",
1136 map__rip_2objdump(map, sym->start),
1137 map__rip_2objdump(map, sym->end),
1138 filename, filename);
1139
1140 pr_debug("Executing: %s\n", command);
1141
1142 file = popen(command, "r");
1143 if (!file)
1144 goto out_free_filename;
1145
1146 while (!feof(file))
1147 if (hist_entry__parse_objdump_line(self, file, head, privsize) < 0)
1148 break;
1149
1150 pclose(file);
1151out_free_filename:
1152 if (free_filename)
1153 free(filename);
1154 return err;
1155} 973}
1156 974
1157void hists__inc_nr_events(struct hists *self, u32 type) 975void hists__inc_nr_events(struct hists *self, u32 type)
@@ -1166,10 +984,17 @@ size_t hists__fprintf_nr_events(struct hists *self, FILE *fp)
1166 size_t ret = 0; 984 size_t ret = 0;
1167 985
1168 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) { 986 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
1169 if (!event__name[i]) 987 const char *name;
988
989 if (self->stats.nr_events[i] == 0)
990 continue;
991
992 name = perf_event__name(i);
993 if (!strcmp(name, "UNKNOWN"))
1170 continue; 994 continue;
1171 ret += fprintf(fp, "%10s events: %10d\n", 995
1172 event__name[i], self->stats.nr_events[i]); 996 ret += fprintf(fp, "%16s events: %10d\n", name,
997 self->stats.nr_events[i]);
1173 } 998 }
1174 999
1175 return ret; 1000 return ret;
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 587d375d3430..3beb97c4d822 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -9,33 +9,6 @@ extern struct callchain_param callchain_param;
9struct hist_entry; 9struct hist_entry;
10struct addr_location; 10struct addr_location;
11struct symbol; 11struct symbol;
12struct rb_root;
13
14struct objdump_line {
15 struct list_head node;
16 s64 offset;
17 char *line;
18};
19
20void objdump_line__free(struct objdump_line *self);
21struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
22 struct objdump_line *pos);
23
24struct sym_hist {
25 u64 sum;
26 u64 ip[0];
27};
28
29struct sym_ext {
30 struct rb_node node;
31 double percent;
32 char *path;
33};
34
35struct sym_priv {
36 struct sym_hist *hist;
37 struct sym_ext *ext;
38};
39 12
40/* 13/*
41 * The kernel collects the number of events it couldn't send in a stretch and 14 * The kernel collects the number of events it couldn't send in a stretch and
@@ -52,8 +25,11 @@ struct sym_priv {
52struct events_stats { 25struct events_stats {
53 u64 total_period; 26 u64 total_period;
54 u64 total_lost; 27 u64 total_lost;
28 u64 total_invalid_chains;
55 u32 nr_events[PERF_RECORD_HEADER_MAX]; 29 u32 nr_events[PERF_RECORD_HEADER_MAX];
56 u32 nr_unknown_events; 30 u32 nr_unknown_events;
31 u32 nr_invalid_chains;
32 u32 nr_unknown_id;
57}; 33};
58 34
59enum hist_column { 35enum hist_column {
@@ -67,14 +43,13 @@ enum hist_column {
67}; 43};
68 44
69struct hists { 45struct hists {
70 struct rb_node rb_node;
71 struct rb_root entries; 46 struct rb_root entries;
72 u64 nr_entries; 47 u64 nr_entries;
73 struct events_stats stats; 48 struct events_stats stats;
74 u64 config;
75 u64 event_stream; 49 u64 event_stream;
76 u32 type;
77 u16 col_len[HISTC_NR_COLS]; 50 u16 col_len[HISTC_NR_COLS];
51 /* Best would be to reuse the session callchain cursor */
52 struct callchain_cursor callchain_cursor;
78}; 53};
79 54
80struct hist_entry *__hists__add_entry(struct hists *self, 55struct hist_entry *__hists__add_entry(struct hists *self,
@@ -100,9 +75,8 @@ size_t hists__fprintf_nr_events(struct hists *self, FILE *fp);
100size_t hists__fprintf(struct hists *self, struct hists *pair, 75size_t hists__fprintf(struct hists *self, struct hists *pair,
101 bool show_displacement, FILE *fp); 76 bool show_displacement, FILE *fp);
102 77
103int hist_entry__inc_addr_samples(struct hist_entry *self, u64 ip); 78int hist_entry__inc_addr_samples(struct hist_entry *self, int evidx, u64 addr);
104int hist_entry__annotate(struct hist_entry *self, struct list_head *head, 79int hist_entry__annotate(struct hist_entry *self, size_t privsize);
105 size_t privsize);
106 80
107void hists__filter_by_dso(struct hists *self, const struct dso *dso); 81void hists__filter_by_dso(struct hists *self, const struct dso *dso);
108void hists__filter_by_thread(struct hists *self, const struct thread *thread); 82void hists__filter_by_thread(struct hists *self, const struct thread *thread);
@@ -111,21 +85,18 @@ u16 hists__col_len(struct hists *self, enum hist_column col);
111void hists__set_col_len(struct hists *self, enum hist_column col, u16 len); 85void hists__set_col_len(struct hists *self, enum hist_column col, u16 len);
112bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len); 86bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len);
113 87
114#ifdef NO_NEWT_SUPPORT 88struct perf_evlist;
115static inline int hists__browse(struct hists *self __used,
116 const char *helpline __used,
117 const char *ev_name __used)
118{
119 return 0;
120}
121 89
122static inline int hists__tui_browse_tree(struct rb_root *self __used, 90#ifdef NO_NEWT_SUPPORT
123 const char *help __used) 91static inline
92int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __used,
93 const char *help __used)
124{ 94{
125 return 0; 95 return 0;
126} 96}
127 97
128static inline int hist_entry__tui_annotate(struct hist_entry *self __used) 98static inline int hist_entry__tui_annotate(struct hist_entry *self __used,
99 int evidx __used)
129{ 100{
130 return 0; 101 return 0;
131} 102}
@@ -133,14 +104,12 @@ static inline int hist_entry__tui_annotate(struct hist_entry *self __used)
133#define KEY_RIGHT -2 104#define KEY_RIGHT -2
134#else 105#else
135#include <newt.h> 106#include <newt.h>
136int hists__browse(struct hists *self, const char *helpline, 107int hist_entry__tui_annotate(struct hist_entry *self, int evidx);
137 const char *ev_name);
138int hist_entry__tui_annotate(struct hist_entry *self);
139 108
140#define KEY_LEFT NEWT_KEY_LEFT 109#define KEY_LEFT NEWT_KEY_LEFT
141#define KEY_RIGHT NEWT_KEY_RIGHT 110#define KEY_RIGHT NEWT_KEY_RIGHT
142 111
143int hists__tui_browse_tree(struct rb_root *self, const char *help); 112int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help);
144#endif 113#endif
145 114
146unsigned int hists__sort_list_width(struct hists *self); 115unsigned int hists__sort_list_width(struct hists *self);
diff --git a/tools/perf/util/include/asm/alternative-asm.h b/tools/perf/util/include/asm/alternative-asm.h
new file mode 100644
index 000000000000..6789d788d494
--- /dev/null
+++ b/tools/perf/util/include/asm/alternative-asm.h
@@ -0,0 +1,8 @@
1#ifndef _PERF_ASM_ALTERNATIVE_ASM_H
2#define _PERF_ASM_ALTERNATIVE_ASM_H
3
4/* Just disable it so we can build arch/x86/lib/memcpy_64.S for perf bench: */
5
6#define altinstruction_entry #
7
8#endif
diff --git a/tools/perf/util/include/asm/cpufeature.h b/tools/perf/util/include/asm/cpufeature.h
new file mode 100644
index 000000000000..acffd5e4d1d4
--- /dev/null
+++ b/tools/perf/util/include/asm/cpufeature.h
@@ -0,0 +1,9 @@
1
2#ifndef PERF_CPUFEATURE_H
3#define PERF_CPUFEATURE_H
4
5/* cpufeature.h ... dummy header file for including arch/x86/lib/memcpy_64.S */
6
7#define X86_FEATURE_REP_GOOD 0
8
9#endif /* PERF_CPUFEATURE_H */
diff --git a/tools/perf/util/include/asm/dwarf2.h b/tools/perf/util/include/asm/dwarf2.h
new file mode 100644
index 000000000000..bb4198e7837a
--- /dev/null
+++ b/tools/perf/util/include/asm/dwarf2.h
@@ -0,0 +1,11 @@
1
2#ifndef PERF_DWARF2_H
3#define PERF_DWARF2_H
4
5/* dwarf2.h ... dummy header file for including arch/x86/lib/memcpy_64.S */
6
7#define CFI_STARTPROC
8#define CFI_ENDPROC
9
10#endif /* PERF_DWARF2_H */
11
diff --git a/tools/perf/util/include/linux/bitops.h b/tools/perf/util/include/linux/bitops.h
index bb4ac2e05385..305c8484f200 100644
--- a/tools/perf/util/include/linux/bitops.h
+++ b/tools/perf/util/include/linux/bitops.h
@@ -2,6 +2,7 @@
2#define _PERF_LINUX_BITOPS_H_ 2#define _PERF_LINUX_BITOPS_H_
3 3
4#include <linux/kernel.h> 4#include <linux/kernel.h>
5#include <linux/compiler.h>
5#include <asm/hweight.h> 6#include <asm/hweight.h>
6 7
7#define BITS_PER_LONG __WORDSIZE 8#define BITS_PER_LONG __WORDSIZE
@@ -13,6 +14,11 @@ static inline void set_bit(int nr, unsigned long *addr)
13 addr[nr / BITS_PER_LONG] |= 1UL << (nr % BITS_PER_LONG); 14 addr[nr / BITS_PER_LONG] |= 1UL << (nr % BITS_PER_LONG);
14} 15}
15 16
17static inline void clear_bit(int nr, unsigned long *addr)
18{
19 addr[nr / BITS_PER_LONG] &= ~(1UL << (nr % BITS_PER_LONG));
20}
21
16static __always_inline int test_bit(unsigned int nr, const unsigned long *addr) 22static __always_inline int test_bit(unsigned int nr, const unsigned long *addr)
17{ 23{
18 return ((1UL << (nr % BITS_PER_LONG)) & 24 return ((1UL << (nr % BITS_PER_LONG)) &
diff --git a/tools/perf/util/include/linux/const.h b/tools/perf/util/include/linux/const.h
new file mode 100644
index 000000000000..1b476c9ae649
--- /dev/null
+++ b/tools/perf/util/include/linux/const.h
@@ -0,0 +1 @@
#include "../../../../include/linux/const.h"
diff --git a/tools/perf/util/include/linux/linkage.h b/tools/perf/util/include/linux/linkage.h
new file mode 100644
index 000000000000..06387cffe125
--- /dev/null
+++ b/tools/perf/util/include/linux/linkage.h
@@ -0,0 +1,13 @@
1
2#ifndef PERF_LINUX_LINKAGE_H_
3#define PERF_LINUX_LINKAGE_H_
4
5/* linkage.h ... for including arch/x86/lib/memcpy_64.S */
6
7#define ENTRY(name) \
8 .globl name; \
9 name:
10
11#define ENDPROC(name)
12
13#endif /* PERF_LINUX_LINKAGE_H_ */
diff --git a/tools/perf/util/include/linux/list.h b/tools/perf/util/include/linux/list.h
index f5ca26e53fbb..1d928a0ce997 100644
--- a/tools/perf/util/include/linux/list.h
+++ b/tools/perf/util/include/linux/list.h
@@ -1,3 +1,6 @@
1#include <linux/kernel.h>
2#include <linux/prefetch.h>
3
1#include "../../../../include/linux/list.h" 4#include "../../../../include/linux/list.h"
2 5
3#ifndef PERF_LIST_H 6#ifndef PERF_LIST_H
@@ -22,5 +25,5 @@ static inline void list_del_range(struct list_head *begin,
22 * @head: the head for your list. 25 * @head: the head for your list.
23 */ 26 */
24#define list_for_each_from(pos, head) \ 27#define list_for_each_from(pos, head) \
25 for (; prefetch(pos->next), pos != (head); pos = pos->next) 28 for (; pos != (head); pos = pos->next)
26#endif 29#endif
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 3a7eb6ec0eec..a16ecab5229d 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -1,5 +1,6 @@
1#include "symbol.h" 1#include "symbol.h"
2#include <errno.h> 2#include <errno.h>
3#include <inttypes.h>
3#include <limits.h> 4#include <limits.h>
4#include <stdlib.h> 5#include <stdlib.h>
5#include <string.h> 6#include <string.h>
@@ -195,7 +196,7 @@ int map__overlap(struct map *l, struct map *r)
195 196
196size_t map__fprintf(struct map *self, FILE *fp) 197size_t map__fprintf(struct map *self, FILE *fp)
197{ 198{
198 return fprintf(fp, " %Lx-%Lx %Lx %s\n", 199 return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s\n",
199 self->start, self->end, self->pgoff, self->dso->name); 200 self->start, self->end, self->pgoff, self->dso->name);
200} 201}
201 202
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index 78575796d5f3..b397c0383728 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -215,6 +215,16 @@ struct symbol *map_groups__find_function_by_name(struct map_groups *self,
215 return map_groups__find_symbol_by_name(self, MAP__FUNCTION, name, mapp, filter); 215 return map_groups__find_symbol_by_name(self, MAP__FUNCTION, name, mapp, filter);
216} 216}
217 217
218static inline
219struct symbol *machine__find_kernel_function_by_name(struct machine *self,
220 const char *name,
221 struct map **mapp,
222 symbol_filter_t filter)
223{
224 return map_groups__find_function_by_name(&self->kmaps, name, mapp,
225 filter);
226}
227
218int map_groups__fixup_overlappings(struct map_groups *self, struct map *map, 228int map_groups__fixup_overlappings(struct map_groups *self, struct map *map,
219 int verbose, FILE *fp); 229 int verbose, FILE *fp);
220 230
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 4af5bd59cfd1..41982c373faf 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1,6 +1,8 @@
1#include "../../../include/linux/hw_breakpoint.h" 1#include "../../../include/linux/hw_breakpoint.h"
2#include "util.h" 2#include "util.h"
3#include "../perf.h" 3#include "../perf.h"
4#include "evlist.h"
5#include "evsel.h"
4#include "parse-options.h" 6#include "parse-options.h"
5#include "parse-events.h" 7#include "parse-events.h"
6#include "exec_cmd.h" 8#include "exec_cmd.h"
@@ -10,11 +12,6 @@
10#include "header.h" 12#include "header.h"
11#include "debugfs.h" 13#include "debugfs.h"
12 14
13int nr_counters;
14
15struct perf_event_attr attrs[MAX_COUNTERS];
16char *filters[MAX_COUNTERS];
17
18struct event_symbol { 15struct event_symbol {
19 u8 type; 16 u8 type;
20 u64 config; 17 u64 config;
@@ -34,34 +31,36 @@ char debugfs_path[MAXPATHLEN];
34#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x 31#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
35 32
36static struct event_symbol event_symbols[] = { 33static struct event_symbol event_symbols[] = {
37 { CHW(CPU_CYCLES), "cpu-cycles", "cycles" }, 34 { CHW(CPU_CYCLES), "cpu-cycles", "cycles" },
38 { CHW(INSTRUCTIONS), "instructions", "" }, 35 { CHW(STALLED_CYCLES_FRONTEND), "stalled-cycles-frontend", "idle-cycles-frontend" },
39 { CHW(CACHE_REFERENCES), "cache-references", "" }, 36 { CHW(STALLED_CYCLES_BACKEND), "stalled-cycles-backend", "idle-cycles-backend" },
40 { CHW(CACHE_MISSES), "cache-misses", "" }, 37 { CHW(INSTRUCTIONS), "instructions", "" },
41 { CHW(BRANCH_INSTRUCTIONS), "branch-instructions", "branches" }, 38 { CHW(CACHE_REFERENCES), "cache-references", "" },
42 { CHW(BRANCH_MISSES), "branch-misses", "" }, 39 { CHW(CACHE_MISSES), "cache-misses", "" },
43 { CHW(BUS_CYCLES), "bus-cycles", "" }, 40 { CHW(BRANCH_INSTRUCTIONS), "branch-instructions", "branches" },
44 41 { CHW(BRANCH_MISSES), "branch-misses", "" },
45 { CSW(CPU_CLOCK), "cpu-clock", "" }, 42 { CHW(BUS_CYCLES), "bus-cycles", "" },
46 { CSW(TASK_CLOCK), "task-clock", "" }, 43
47 { CSW(PAGE_FAULTS), "page-faults", "faults" }, 44 { CSW(CPU_CLOCK), "cpu-clock", "" },
48 { CSW(PAGE_FAULTS_MIN), "minor-faults", "" }, 45 { CSW(TASK_CLOCK), "task-clock", "" },
49 { CSW(PAGE_FAULTS_MAJ), "major-faults", "" }, 46 { CSW(PAGE_FAULTS), "page-faults", "faults" },
50 { CSW(CONTEXT_SWITCHES), "context-switches", "cs" }, 47 { CSW(PAGE_FAULTS_MIN), "minor-faults", "" },
51 { CSW(CPU_MIGRATIONS), "cpu-migrations", "migrations" }, 48 { CSW(PAGE_FAULTS_MAJ), "major-faults", "" },
52 { CSW(ALIGNMENT_FAULTS), "alignment-faults", "" }, 49 { CSW(CONTEXT_SWITCHES), "context-switches", "cs" },
53 { CSW(EMULATION_FAULTS), "emulation-faults", "" }, 50 { CSW(CPU_MIGRATIONS), "cpu-migrations", "migrations" },
51 { CSW(ALIGNMENT_FAULTS), "alignment-faults", "" },
52 { CSW(EMULATION_FAULTS), "emulation-faults", "" },
54}; 53};
55 54
56#define __PERF_EVENT_FIELD(config, name) \ 55#define __PERF_EVENT_FIELD(config, name) \
57 ((config & PERF_EVENT_##name##_MASK) >> PERF_EVENT_##name##_SHIFT) 56 ((config & PERF_EVENT_##name##_MASK) >> PERF_EVENT_##name##_SHIFT)
58 57
59#define PERF_EVENT_RAW(config) __PERF_EVENT_FIELD(config, RAW) 58#define PERF_EVENT_RAW(config) __PERF_EVENT_FIELD(config, RAW)
60#define PERF_EVENT_CONFIG(config) __PERF_EVENT_FIELD(config, CONFIG) 59#define PERF_EVENT_CONFIG(config) __PERF_EVENT_FIELD(config, CONFIG)
61#define PERF_EVENT_TYPE(config) __PERF_EVENT_FIELD(config, TYPE) 60#define PERF_EVENT_TYPE(config) __PERF_EVENT_FIELD(config, TYPE)
62#define PERF_EVENT_ID(config) __PERF_EVENT_FIELD(config, EVENT) 61#define PERF_EVENT_ID(config) __PERF_EVENT_FIELD(config, EVENT)
63 62
64static const char *hw_event_names[] = { 63static const char *hw_event_names[PERF_COUNT_HW_MAX] = {
65 "cycles", 64 "cycles",
66 "instructions", 65 "instructions",
67 "cache-references", 66 "cache-references",
@@ -69,11 +68,13 @@ static const char *hw_event_names[] = {
69 "branches", 68 "branches",
70 "branch-misses", 69 "branch-misses",
71 "bus-cycles", 70 "bus-cycles",
71 "stalled-cycles-frontend",
72 "stalled-cycles-backend",
72}; 73};
73 74
74static const char *sw_event_names[] = { 75static const char *sw_event_names[PERF_COUNT_SW_MAX] = {
75 "cpu-clock-msecs", 76 "cpu-clock",
76 "task-clock-msecs", 77 "task-clock",
77 "page-faults", 78 "page-faults",
78 "context-switches", 79 "context-switches",
79 "CPU-migrations", 80 "CPU-migrations",
@@ -266,10 +267,35 @@ static char *event_cache_name(u8 cache_type, u8 cache_op, u8 cache_result)
266 return name; 267 return name;
267} 268}
268 269
269const char *event_name(int counter) 270const char *event_type(int type)
270{ 271{
271 u64 config = attrs[counter].config; 272 switch (type) {
272 int type = attrs[counter].type; 273 case PERF_TYPE_HARDWARE:
274 return "hardware";
275
276 case PERF_TYPE_SOFTWARE:
277 return "software";
278
279 case PERF_TYPE_TRACEPOINT:
280 return "tracepoint";
281
282 case PERF_TYPE_HW_CACHE:
283 return "hardware-cache";
284
285 default:
286 break;
287 }
288
289 return "unknown";
290}
291
292const char *event_name(struct perf_evsel *evsel)
293{
294 u64 config = evsel->attr.config;
295 int type = evsel->attr.type;
296
297 if (evsel->name)
298 return evsel->name;
273 299
274 return __event_name(type, config); 300 return __event_name(type, config);
275} 301}
@@ -279,13 +305,13 @@ const char *__event_name(int type, u64 config)
279 static char buf[32]; 305 static char buf[32];
280 306
281 if (type == PERF_TYPE_RAW) { 307 if (type == PERF_TYPE_RAW) {
282 sprintf(buf, "raw 0x%llx", config); 308 sprintf(buf, "raw 0x%" PRIx64, config);
283 return buf; 309 return buf;
284 } 310 }
285 311
286 switch (type) { 312 switch (type) {
287 case PERF_TYPE_HARDWARE: 313 case PERF_TYPE_HARDWARE:
288 if (config < PERF_COUNT_HW_MAX) 314 if (config < PERF_COUNT_HW_MAX && hw_event_names[config])
289 return hw_event_names[config]; 315 return hw_event_names[config];
290 return "unknown-hardware"; 316 return "unknown-hardware";
291 317
@@ -311,7 +337,7 @@ const char *__event_name(int type, u64 config)
311 } 337 }
312 338
313 case PERF_TYPE_SOFTWARE: 339 case PERF_TYPE_SOFTWARE:
314 if (config < PERF_COUNT_SW_MAX) 340 if (config < PERF_COUNT_SW_MAX && sw_event_names[config])
315 return sw_event_names[config]; 341 return sw_event_names[config];
316 return "unknown-software"; 342 return "unknown-software";
317 343
@@ -434,7 +460,7 @@ parse_single_tracepoint_event(char *sys_name,
434 id = atoll(id_buf); 460 id = atoll(id_buf);
435 attr->config = id; 461 attr->config = id;
436 attr->type = PERF_TYPE_TRACEPOINT; 462 attr->type = PERF_TYPE_TRACEPOINT;
437 *strp = evt_name + evt_length; 463 *strp += strlen(sys_name) + evt_length + 1; /* + 1 for the ':' */
438 464
439 attr->sample_type |= PERF_SAMPLE_RAW; 465 attr->sample_type |= PERF_SAMPLE_RAW;
440 attr->sample_type |= PERF_SAMPLE_TIME; 466 attr->sample_type |= PERF_SAMPLE_TIME;
@@ -449,8 +475,8 @@ parse_single_tracepoint_event(char *sys_name,
449/* sys + ':' + event + ':' + flags*/ 475/* sys + ':' + event + ':' + flags*/
450#define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128) 476#define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128)
451static enum event_result 477static enum event_result
452parse_multiple_tracepoint_event(char *sys_name, const char *evt_exp, 478parse_multiple_tracepoint_event(const struct option *opt, char *sys_name,
453 char *flags) 479 const char *evt_exp, char *flags)
454{ 480{
455 char evt_path[MAXPATHLEN]; 481 char evt_path[MAXPATHLEN];
456 struct dirent *evt_ent; 482 struct dirent *evt_ent;
@@ -483,19 +509,19 @@ parse_multiple_tracepoint_event(char *sys_name, const char *evt_exp,
483 if (len < 0) 509 if (len < 0)
484 return EVT_FAILED; 510 return EVT_FAILED;
485 511
486 if (parse_events(NULL, event_opt, 0)) 512 if (parse_events(opt, event_opt, 0))
487 return EVT_FAILED; 513 return EVT_FAILED;
488 } 514 }
489 515
490 return EVT_HANDLED_ALL; 516 return EVT_HANDLED_ALL;
491} 517}
492 518
493 519static enum event_result
494static enum event_result parse_tracepoint_event(const char **strp, 520parse_tracepoint_event(const struct option *opt, const char **strp,
495 struct perf_event_attr *attr) 521 struct perf_event_attr *attr)
496{ 522{
497 const char *evt_name; 523 const char *evt_name;
498 char *flags; 524 char *flags = NULL, *comma_loc;
499 char sys_name[MAX_EVENT_LENGTH]; 525 char sys_name[MAX_EVENT_LENGTH];
500 unsigned int sys_length, evt_length; 526 unsigned int sys_length, evt_length;
501 527
@@ -514,6 +540,11 @@ static enum event_result parse_tracepoint_event(const char **strp,
514 sys_name[sys_length] = '\0'; 540 sys_name[sys_length] = '\0';
515 evt_name = evt_name + 1; 541 evt_name = evt_name + 1;
516 542
543 comma_loc = strchr(evt_name, ',');
544 if (comma_loc) {
545 /* take the event name up to the comma */
546 evt_name = strndup(evt_name, comma_loc - evt_name);
547 }
517 flags = strchr(evt_name, ':'); 548 flags = strchr(evt_name, ':');
518 if (flags) { 549 if (flags) {
519 /* split it out: */ 550 /* split it out: */
@@ -524,14 +555,14 @@ static enum event_result parse_tracepoint_event(const char **strp,
524 evt_length = strlen(evt_name); 555 evt_length = strlen(evt_name);
525 if (evt_length >= MAX_EVENT_LENGTH) 556 if (evt_length >= MAX_EVENT_LENGTH)
526 return EVT_FAILED; 557 return EVT_FAILED;
527
528 if (strpbrk(evt_name, "*?")) { 558 if (strpbrk(evt_name, "*?")) {
529 *strp = evt_name + evt_length; 559 *strp += strlen(sys_name) + evt_length + 1; /* 1 == the ':' */
530 return parse_multiple_tracepoint_event(sys_name, evt_name, 560 return parse_multiple_tracepoint_event(opt, sys_name, evt_name,
531 flags); 561 flags);
532 } else 562 } else {
533 return parse_single_tracepoint_event(sys_name, evt_name, 563 return parse_single_tracepoint_event(sys_name, evt_name,
534 evt_length, attr, strp); 564 evt_length, attr, strp);
565 }
535} 566}
536 567
537static enum event_result 568static enum event_result
@@ -621,13 +652,15 @@ static int check_events(const char *str, unsigned int i)
621 int n; 652 int n;
622 653
623 n = strlen(event_symbols[i].symbol); 654 n = strlen(event_symbols[i].symbol);
624 if (!strncmp(str, event_symbols[i].symbol, n)) 655 if (!strncasecmp(str, event_symbols[i].symbol, n))
625 return n; 656 return n;
626 657
627 n = strlen(event_symbols[i].alias); 658 n = strlen(event_symbols[i].alias);
628 if (n) 659 if (n) {
629 if (!strncmp(str, event_symbols[i].alias, n)) 660 if (!strncasecmp(str, event_symbols[i].alias, n))
630 return n; 661 return n;
662 }
663
631 return 0; 664 return 0;
632} 665}
633 666
@@ -691,15 +724,22 @@ parse_numeric_event(const char **strp, struct perf_event_attr *attr)
691 return EVT_FAILED; 724 return EVT_FAILED;
692} 725}
693 726
694static enum event_result 727static int
695parse_event_modifier(const char **strp, struct perf_event_attr *attr) 728parse_event_modifier(const char **strp, struct perf_event_attr *attr)
696{ 729{
697 const char *str = *strp; 730 const char *str = *strp;
698 int exclude = 0; 731 int exclude = 0;
699 int eu = 0, ek = 0, eh = 0, precise = 0; 732 int eu = 0, ek = 0, eh = 0, precise = 0;
700 733
701 if (*str++ != ':') 734 if (!*str)
702 return 0; 735 return 0;
736
737 if (*str == ',')
738 return 0;
739
740 if (*str++ != ':')
741 return -1;
742
703 while (*str) { 743 while (*str) {
704 if (*str == 'u') { 744 if (*str == 'u') {
705 if (!exclude) 745 if (!exclude)
@@ -720,14 +760,16 @@ parse_event_modifier(const char **strp, struct perf_event_attr *attr)
720 760
721 ++str; 761 ++str;
722 } 762 }
723 if (str >= *strp + 2) { 763 if (str < *strp + 2)
724 *strp = str; 764 return -1;
725 attr->exclude_user = eu; 765
726 attr->exclude_kernel = ek; 766 *strp = str;
727 attr->exclude_hv = eh; 767
728 attr->precise_ip = precise; 768 attr->exclude_user = eu;
729 return 1; 769 attr->exclude_kernel = ek;
730 } 770 attr->exclude_hv = eh;
771 attr->precise_ip = precise;
772
731 return 0; 773 return 0;
732} 774}
733 775
@@ -736,11 +778,12 @@ parse_event_modifier(const char **strp, struct perf_event_attr *attr)
736 * Symbolic names are (almost) exactly matched. 778 * Symbolic names are (almost) exactly matched.
737 */ 779 */
738static enum event_result 780static enum event_result
739parse_event_symbols(const char **str, struct perf_event_attr *attr) 781parse_event_symbols(const struct option *opt, const char **str,
782 struct perf_event_attr *attr)
740{ 783{
741 enum event_result ret; 784 enum event_result ret;
742 785
743 ret = parse_tracepoint_event(str, attr); 786 ret = parse_tracepoint_event(opt, str, attr);
744 if (ret != EVT_FAILED) 787 if (ret != EVT_FAILED)
745 goto modifier; 788 goto modifier;
746 789
@@ -769,52 +812,27 @@ parse_event_symbols(const char **str, struct perf_event_attr *attr)
769 return EVT_FAILED; 812 return EVT_FAILED;
770 813
771modifier: 814modifier:
772 parse_event_modifier(str, attr); 815 if (parse_event_modifier(str, attr) < 0) {
773 816 fprintf(stderr, "invalid event modifier: '%s'\n", *str);
774 return ret; 817 fprintf(stderr, "Run 'perf list' for a list of valid events and modifiers\n");
775}
776
777static int store_event_type(const char *orgname)
778{
779 char filename[PATH_MAX], *c;
780 FILE *file;
781 int id, n;
782 818
783 sprintf(filename, "%s/", debugfs_path); 819 return EVT_FAILED;
784 strncat(filename, orgname, strlen(orgname));
785 strcat(filename, "/id");
786
787 c = strchr(filename, ':');
788 if (c)
789 *c = '/';
790
791 file = fopen(filename, "r");
792 if (!file)
793 return 0;
794 n = fscanf(file, "%i", &id);
795 fclose(file);
796 if (n < 1) {
797 pr_err("cannot store event ID\n");
798 return -EINVAL;
799 } 820 }
800 return perf_header__push_event(id, orgname); 821
822 return ret;
801} 823}
802 824
803int parse_events(const struct option *opt __used, const char *str, int unset __used) 825int parse_events(const struct option *opt, const char *str, int unset __used)
804{ 826{
827 struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
805 struct perf_event_attr attr; 828 struct perf_event_attr attr;
806 enum event_result ret; 829 enum event_result ret;
807 830 const char *ostr;
808 if (strchr(str, ':'))
809 if (store_event_type(str) < 0)
810 return -1;
811 831
812 for (;;) { 832 for (;;) {
813 if (nr_counters == MAX_COUNTERS) 833 ostr = str;
814 return -1;
815
816 memset(&attr, 0, sizeof(attr)); 834 memset(&attr, 0, sizeof(attr));
817 ret = parse_event_symbols(&str, &attr); 835 ret = parse_event_symbols(opt, &str, &attr);
818 if (ret == EVT_FAILED) 836 if (ret == EVT_FAILED)
819 return -1; 837 return -1;
820 838
@@ -822,8 +840,16 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u
822 return -1; 840 return -1;
823 841
824 if (ret != EVT_HANDLED_ALL) { 842 if (ret != EVT_HANDLED_ALL) {
825 attrs[nr_counters] = attr; 843 struct perf_evsel *evsel;
826 nr_counters++; 844 evsel = perf_evsel__new(&attr, evlist->nr_entries);
845 if (evsel == NULL)
846 return -1;
847 perf_evlist__add(evlist, evsel);
848
849 evsel->name = calloc(str - ostr + 1, 1);
850 if (!evsel->name)
851 return -1;
852 strncpy(evsel->name, ostr, str - ostr);
827 } 853 }
828 854
829 if (*str == 0) 855 if (*str == 0)
@@ -837,24 +863,26 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u
837 return 0; 863 return 0;
838} 864}
839 865
840int parse_filter(const struct option *opt __used, const char *str, 866int parse_filter(const struct option *opt, const char *str,
841 int unset __used) 867 int unset __used)
842{ 868{
843 int i = nr_counters - 1; 869 struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
844 int len = strlen(str); 870 struct perf_evsel *last = NULL;
871
872 if (evlist->nr_entries > 0)
873 last = list_entry(evlist->entries.prev, struct perf_evsel, node);
845 874
846 if (i < 0 || attrs[i].type != PERF_TYPE_TRACEPOINT) { 875 if (last == NULL || last->attr.type != PERF_TYPE_TRACEPOINT) {
847 fprintf(stderr, 876 fprintf(stderr,
848 "-F option should follow a -e tracepoint option\n"); 877 "-F option should follow a -e tracepoint option\n");
849 return -1; 878 return -1;
850 } 879 }
851 880
852 filters[i] = malloc(len + 1); 881 last->filter = strdup(str);
853 if (!filters[i]) { 882 if (last->filter == NULL) {
854 fprintf(stderr, "not enough memory to hold filter string\n"); 883 fprintf(stderr, "not enough memory to hold filter string\n");
855 return -1; 884 return -1;
856 } 885 }
857 strcpy(filters[i], str);
858 886
859 return 0; 887 return 0;
860} 888}
@@ -872,7 +900,7 @@ static const char * const event_type_descriptors[] = {
872 * Print the events from <debugfs_mount_point>/tracing/events 900 * Print the events from <debugfs_mount_point>/tracing/events
873 */ 901 */
874 902
875static void print_tracepoint_events(void) 903void print_tracepoint_events(const char *subsys_glob, const char *event_glob)
876{ 904{
877 DIR *sys_dir, *evt_dir; 905 DIR *sys_dir, *evt_dir;
878 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; 906 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
@@ -887,6 +915,9 @@ static void print_tracepoint_events(void)
887 return; 915 return;
888 916
889 for_each_subsystem(sys_dir, sys_dirent, sys_next) { 917 for_each_subsystem(sys_dir, sys_dirent, sys_next) {
918 if (subsys_glob != NULL &&
919 !strglobmatch(sys_dirent.d_name, subsys_glob))
920 continue;
890 921
891 snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path, 922 snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path,
892 sys_dirent.d_name); 923 sys_dirent.d_name);
@@ -895,9 +926,13 @@ static void print_tracepoint_events(void)
895 continue; 926 continue;
896 927
897 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { 928 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) {
929 if (event_glob != NULL &&
930 !strglobmatch(evt_dirent.d_name, event_glob))
931 continue;
932
898 snprintf(evt_path, MAXPATHLEN, "%s:%s", 933 snprintf(evt_path, MAXPATHLEN, "%s:%s",
899 sys_dirent.d_name, evt_dirent.d_name); 934 sys_dirent.d_name, evt_dirent.d_name);
900 printf(" %-42s [%s]\n", evt_path, 935 printf(" %-50s [%s]\n", evt_path,
901 event_type_descriptors[PERF_TYPE_TRACEPOINT]); 936 event_type_descriptors[PERF_TYPE_TRACEPOINT]);
902 } 937 }
903 closedir(evt_dir); 938 closedir(evt_dir);
@@ -906,34 +941,71 @@ static void print_tracepoint_events(void)
906} 941}
907 942
908/* 943/*
909 * Print the help text for the event symbols: 944 * Check whether event is in <debugfs_mount_point>/tracing/events
910 */ 945 */
911void print_events(void) 946
947int is_valid_tracepoint(const char *event_string)
912{ 948{
913 struct event_symbol *syms = event_symbols; 949 DIR *sys_dir, *evt_dir;
914 unsigned int i, type, op, prev_type = -1; 950 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
915 char name[40]; 951 char evt_path[MAXPATHLEN];
952 char dir_path[MAXPATHLEN];
916 953
917 printf("\n"); 954 if (debugfs_valid_mountpoint(debugfs_path))
918 printf("List of pre-defined events (to be used in -e):\n"); 955 return 0;
919 956
920 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { 957 sys_dir = opendir(debugfs_path);
921 type = syms->type; 958 if (!sys_dir)
959 return 0;
922 960
923 if (type != prev_type) 961 for_each_subsystem(sys_dir, sys_dirent, sys_next) {
924 printf("\n"); 962
963 snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path,
964 sys_dirent.d_name);
965 evt_dir = opendir(dir_path);
966 if (!evt_dir)
967 continue;
968
969 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) {
970 snprintf(evt_path, MAXPATHLEN, "%s:%s",
971 sys_dirent.d_name, evt_dirent.d_name);
972 if (!strcmp(evt_path, event_string)) {
973 closedir(evt_dir);
974 closedir(sys_dir);
975 return 1;
976 }
977 }
978 closedir(evt_dir);
979 }
980 closedir(sys_dir);
981 return 0;
982}
983
984void print_events_type(u8 type)
985{
986 struct event_symbol *syms = event_symbols;
987 unsigned int i;
988 char name[64];
989
990 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
991 if (type != syms->type)
992 continue;
925 993
926 if (strlen(syms->alias)) 994 if (strlen(syms->alias))
927 sprintf(name, "%s OR %s", syms->symbol, syms->alias); 995 snprintf(name, sizeof(name), "%s OR %s",
996 syms->symbol, syms->alias);
928 else 997 else
929 strcpy(name, syms->symbol); 998 snprintf(name, sizeof(name), "%s", syms->symbol);
930 printf(" %-42s [%s]\n", name,
931 event_type_descriptors[type]);
932 999
933 prev_type = type; 1000 printf(" %-50s [%s]\n", name,
1001 event_type_descriptors[type]);
934 } 1002 }
1003}
1004
1005int print_hwcache_events(const char *event_glob)
1006{
1007 unsigned int type, op, i, printed = 0;
935 1008
936 printf("\n");
937 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { 1009 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
938 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { 1010 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
939 /* skip invalid cache type */ 1011 /* skip invalid cache type */
@@ -941,25 +1013,81 @@ void print_events(void)
941 continue; 1013 continue;
942 1014
943 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { 1015 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
944 printf(" %-42s [%s]\n", 1016 char *name = event_cache_name(type, op, i);
945 event_cache_name(type, op, i), 1017
1018 if (event_glob != NULL && !strglobmatch(name, event_glob))
1019 continue;
1020
1021 printf(" %-50s [%s]\n", name,
946 event_type_descriptors[PERF_TYPE_HW_CACHE]); 1022 event_type_descriptors[PERF_TYPE_HW_CACHE]);
1023 ++printed;
947 } 1024 }
948 } 1025 }
949 } 1026 }
950 1027
1028 return printed;
1029}
1030
1031#define MAX_NAME_LEN 100
1032
1033/*
1034 * Print the help text for the event symbols:
1035 */
1036void print_events(const char *event_glob)
1037{
1038 unsigned int i, type, prev_type = -1, printed = 0, ntypes_printed = 0;
1039 struct event_symbol *syms = event_symbols;
1040 char name[MAX_NAME_LEN];
1041
1042 printf("\n");
1043 printf("List of pre-defined events (to be used in -e):\n");
1044
1045 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
1046 type = syms->type;
1047
1048 if (type != prev_type && printed) {
1049 printf("\n");
1050 printed = 0;
1051 ntypes_printed++;
1052 }
1053
1054 if (event_glob != NULL &&
1055 !(strglobmatch(syms->symbol, event_glob) ||
1056 (syms->alias && strglobmatch(syms->alias, event_glob))))
1057 continue;
1058
1059 if (strlen(syms->alias))
1060 snprintf(name, MAX_NAME_LEN, "%s OR %s", syms->symbol, syms->alias);
1061 else
1062 strncpy(name, syms->symbol, MAX_NAME_LEN);
1063 printf(" %-50s [%s]\n", name,
1064 event_type_descriptors[type]);
1065
1066 prev_type = type;
1067 ++printed;
1068 }
1069
1070 if (ntypes_printed) {
1071 printed = 0;
1072 printf("\n");
1073 }
1074 print_hwcache_events(event_glob);
1075
1076 if (event_glob != NULL)
1077 return;
1078
951 printf("\n"); 1079 printf("\n");
952 printf(" %-42s [%s]\n", 1080 printf(" %-50s [%s]\n",
953 "rNNN (see 'perf list --help' on how to encode it)", 1081 "rNNN (see 'perf list --help' on how to encode it)",
954 event_type_descriptors[PERF_TYPE_RAW]); 1082 event_type_descriptors[PERF_TYPE_RAW]);
955 printf("\n"); 1083 printf("\n");
956 1084
957 printf(" %-42s [%s]\n", 1085 printf(" %-50s [%s]\n",
958 "mem:<addr>[:access]", 1086 "mem:<addr>[:access]",
959 event_type_descriptors[PERF_TYPE_BREAKPOINT]); 1087 event_type_descriptors[PERF_TYPE_BREAKPOINT]);
960 printf("\n"); 1088 printf("\n");
961 1089
962 print_tracepoint_events(); 1090 print_tracepoint_events(NULL, NULL);
963 1091
964 exit(129); 1092 exit(129);
965} 1093}
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index fc4ab3fe877a..746d3fcbfc2a 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -4,6 +4,11 @@
4 * Parse symbolic events/counts passed in as options: 4 * Parse symbolic events/counts passed in as options:
5 */ 5 */
6 6
7#include "../../../include/linux/perf_event.h"
8
9struct list_head;
10struct perf_evsel;
11
7struct option; 12struct option;
8 13
9struct tracepoint_path { 14struct tracepoint_path {
@@ -13,14 +18,10 @@ struct tracepoint_path {
13}; 18};
14 19
15extern struct tracepoint_path *tracepoint_id_to_path(u64 config); 20extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
16extern bool have_tracepoints(struct perf_event_attr *pattrs, int nb_events); 21extern bool have_tracepoints(struct list_head *evlist);
17
18extern int nr_counters;
19 22
20extern struct perf_event_attr attrs[MAX_COUNTERS]; 23const char *event_type(int type);
21extern char *filters[MAX_COUNTERS]; 24const char *event_name(struct perf_evsel *event);
22
23extern const char *event_name(int ctr);
24extern const char *__event_name(int type, u64 config); 25extern const char *__event_name(int type, u64 config);
25 26
26extern int parse_events(const struct option *opt, const char *str, int unset); 27extern int parse_events(const struct option *opt, const char *str, int unset);
@@ -28,10 +29,13 @@ extern int parse_filter(const struct option *opt, const char *str, int unset);
28 29
29#define EVENTS_HELP_MAX (128*1024) 30#define EVENTS_HELP_MAX (128*1024)
30 31
31extern void print_events(void); 32void print_events(const char *event_glob);
33void print_events_type(u8 type);
34void print_tracepoint_events(const char *subsys_glob, const char *event_glob);
35int print_hwcache_events(const char *event_glob);
36extern int is_valid_tracepoint(const char *event_string);
32 37
33extern char debugfs_path[]; 38extern char debugfs_path[];
34extern int valid_debugfs_mount(const char *debugfs); 39extern int valid_debugfs_mount(const char *debugfs);
35 40
36
37#endif /* __PERF_PARSE_EVENTS_H */ 41#endif /* __PERF_PARSE_EVENTS_H */
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h
index c7d72dce54b2..abc31a1dac1a 100644
--- a/tools/perf/util/parse-options.h
+++ b/tools/perf/util/parse-options.h
@@ -119,6 +119,10 @@ struct option {
119 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f), .flags = PARSE_OPT_NOARG } 119 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f), .flags = PARSE_OPT_NOARG }
120#define OPT_CALLBACK_DEFAULT(s, l, v, a, h, f, d) \ 120#define OPT_CALLBACK_DEFAULT(s, l, v, a, h, f, d) \
121 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d, .flags = PARSE_OPT_LASTARG_DEFAULT } 121 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d, .flags = PARSE_OPT_LASTARG_DEFAULT }
122#define OPT_CALLBACK_DEFAULT_NOOPT(s, l, v, a, h, f, d) \
123 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l),\
124 .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d,\
125 .flags = PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NOARG}
122 126
123/* parse_options() will filter out the processed options and leave the 127/* parse_options() will filter out the processed options and leave the
124 * non-option argments in argv[]. 128 * non-option argments in argv[].
diff --git a/tools/perf/util/path.c b/tools/perf/util/path.c
index 58a470d036dd..bd7497711424 100644
--- a/tools/perf/util/path.c
+++ b/tools/perf/util/path.c
@@ -22,6 +22,7 @@ static const char *get_perf_dir(void)
22 return "."; 22 return ".";
23} 23}
24 24
25#ifdef NO_STRLCPY
25size_t strlcpy(char *dest, const char *src, size_t size) 26size_t strlcpy(char *dest, const char *src, size_t size)
26{ 27{
27 size_t ret = strlen(src); 28 size_t ret = strlen(src);
@@ -33,7 +34,7 @@ size_t strlcpy(char *dest, const char *src, size_t size)
33 } 34 }
34 return ret; 35 return ret;
35} 36}
36 37#endif
37 38
38static char *get_pathname(void) 39static char *get_pathname(void)
39{ 40{
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index fcc16e4349df..f0223166e761 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -31,6 +31,7 @@
31#include <string.h> 31#include <string.h>
32#include <stdarg.h> 32#include <stdarg.h>
33#include <limits.h> 33#include <limits.h>
34#include <elf.h>
34 35
35#undef _GNU_SOURCE 36#undef _GNU_SOURCE
36#include "util.h" 37#include "util.h"
@@ -74,10 +75,9 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
74static char *synthesize_perf_probe_point(struct perf_probe_point *pp); 75static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
75static struct machine machine; 76static struct machine machine;
76 77
77/* Initialize symbol maps and path of vmlinux */ 78/* Initialize symbol maps and path of vmlinux/modules */
78static int init_vmlinux(void) 79static int init_vmlinux(void)
79{ 80{
80 struct dso *kernel;
81 int ret; 81 int ret;
82 82
83 symbol_conf.sort_by_name = true; 83 symbol_conf.sort_by_name = true;
@@ -91,33 +91,95 @@ static int init_vmlinux(void)
91 goto out; 91 goto out;
92 } 92 }
93 93
94 ret = machine__init(&machine, "/", 0); 94 ret = machine__init(&machine, "", HOST_KERNEL_ID);
95 if (ret < 0) 95 if (ret < 0)
96 goto out; 96 goto out;
97 97
98 kernel = dso__new_kernel(symbol_conf.vmlinux_name); 98 if (machine__create_kernel_maps(&machine) < 0) {
99 if (kernel == NULL) 99 pr_debug("machine__create_kernel_maps() failed.\n");
100 die("Failed to create kernel dso."); 100 goto out;
101 101 }
102 ret = __machine__create_kernel_maps(&machine, kernel);
103 if (ret < 0)
104 pr_debug("Failed to create kernel maps.\n");
105
106out: 102out:
107 if (ret < 0) 103 if (ret < 0)
108 pr_warning("Failed to init vmlinux path.\n"); 104 pr_warning("Failed to init vmlinux path.\n");
109 return ret; 105 return ret;
110} 106}
111 107
108static struct symbol *__find_kernel_function_by_name(const char *name,
109 struct map **mapp)
110{
111 return machine__find_kernel_function_by_name(&machine, name, mapp,
112 NULL);
113}
114
115static struct map *kernel_get_module_map(const char *module)
116{
117 struct rb_node *nd;
118 struct map_groups *grp = &machine.kmaps;
119
120 if (!module)
121 module = "kernel";
122
123 for (nd = rb_first(&grp->maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) {
124 struct map *pos = rb_entry(nd, struct map, rb_node);
125 if (strncmp(pos->dso->short_name + 1, module,
126 pos->dso->short_name_len - 2) == 0) {
127 return pos;
128 }
129 }
130 return NULL;
131}
132
133static struct dso *kernel_get_module_dso(const char *module)
134{
135 struct dso *dso;
136 struct map *map;
137 const char *vmlinux_name;
138
139 if (module) {
140 list_for_each_entry(dso, &machine.kernel_dsos, node) {
141 if (strncmp(dso->short_name + 1, module,
142 dso->short_name_len - 2) == 0)
143 goto found;
144 }
145 pr_debug("Failed to find module %s.\n", module);
146 return NULL;
147 }
148
149 map = machine.vmlinux_maps[MAP__FUNCTION];
150 dso = map->dso;
151
152 vmlinux_name = symbol_conf.vmlinux_name;
153 if (vmlinux_name) {
154 if (dso__load_vmlinux(dso, map, vmlinux_name, NULL) <= 0)
155 return NULL;
156 } else {
157 if (dso__load_vmlinux_path(dso, map, NULL) <= 0) {
158 pr_debug("Failed to load kernel map.\n");
159 return NULL;
160 }
161 }
162found:
163 return dso;
164}
165
166const char *kernel_get_module_path(const char *module)
167{
168 struct dso *dso = kernel_get_module_dso(module);
169 return (dso) ? dso->long_name : NULL;
170}
171
112#ifdef DWARF_SUPPORT 172#ifdef DWARF_SUPPORT
113static int open_vmlinux(void) 173static int open_vmlinux(const char *module)
114{ 174{
115 if (map__load(machine.vmlinux_maps[MAP__FUNCTION], NULL) < 0) { 175 const char *path = kernel_get_module_path(module);
116 pr_debug("Failed to load kernel map.\n"); 176 if (!path) {
117 return -EINVAL; 177 pr_err("Failed to find path of %s module.\n",
178 module ?: "kernel");
179 return -ENOENT;
118 } 180 }
119 pr_debug("Try to open %s\n", machine.vmlinux_maps[MAP__FUNCTION]->dso->long_name); 181 pr_debug("Try to open %s\n", path);
120 return open(machine.vmlinux_maps[MAP__FUNCTION]->dso->long_name, O_RDONLY); 182 return open(path, O_RDONLY);
121} 183}
122 184
123/* 185/*
@@ -125,20 +187,19 @@ static int open_vmlinux(void)
125 * Currently only handles kprobes. 187 * Currently only handles kprobes.
126 */ 188 */
127static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, 189static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
128 struct perf_probe_point *pp) 190 struct perf_probe_point *pp)
129{ 191{
130 struct symbol *sym; 192 struct symbol *sym;
131 int fd, ret = -ENOENT; 193 struct map *map;
194 u64 addr;
195 int ret = -ENOENT;
132 196
133 sym = map__find_symbol_by_name(machine.vmlinux_maps[MAP__FUNCTION], 197 sym = __find_kernel_function_by_name(tp->symbol, &map);
134 tp->symbol, NULL);
135 if (sym) { 198 if (sym) {
136 fd = open_vmlinux(); 199 addr = map->unmap_ip(map, sym->start + tp->offset);
137 if (fd >= 0) { 200 pr_debug("try to find %s+%ld@%" PRIx64 "\n", tp->symbol,
138 ret = find_perf_probe_point(fd, 201 tp->offset, addr);
139 sym->start + tp->offset, pp); 202 ret = find_perf_probe_point((unsigned long)addr, pp);
140 close(fd);
141 }
142 } 203 }
143 if (ret <= 0) { 204 if (ret <= 0) {
144 pr_debug("Failed to find corresponding probes from " 205 pr_debug("Failed to find corresponding probes from "
@@ -156,12 +217,12 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
156/* Try to find perf_probe_event with debuginfo */ 217/* Try to find perf_probe_event with debuginfo */
157static int try_to_find_probe_trace_events(struct perf_probe_event *pev, 218static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
158 struct probe_trace_event **tevs, 219 struct probe_trace_event **tevs,
159 int max_tevs) 220 int max_tevs, const char *module)
160{ 221{
161 bool need_dwarf = perf_probe_event_need_dwarf(pev); 222 bool need_dwarf = perf_probe_event_need_dwarf(pev);
162 int fd, ntevs; 223 int fd, ntevs;
163 224
164 fd = open_vmlinux(); 225 fd = open_vmlinux(module);
165 if (fd < 0) { 226 if (fd < 0) {
166 if (need_dwarf) { 227 if (need_dwarf) {
167 pr_warning("Failed to open debuginfo file.\n"); 228 pr_warning("Failed to open debuginfo file.\n");
@@ -173,7 +234,6 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
173 234
174 /* Searching trace events corresponding to probe event */ 235 /* Searching trace events corresponding to probe event */
175 ntevs = find_probe_trace_events(fd, pev, tevs, max_tevs); 236 ntevs = find_probe_trace_events(fd, pev, tevs, max_tevs);
176 close(fd);
177 237
178 if (ntevs > 0) { /* Succeeded to find trace events */ 238 if (ntevs > 0) { /* Succeeded to find trace events */
179 pr_debug("find %d probe_trace_events.\n", ntevs); 239 pr_debug("find %d probe_trace_events.\n", ntevs);
@@ -191,7 +251,7 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
191 pr_warning("Warning: No dwarf info found in the vmlinux - " 251 pr_warning("Warning: No dwarf info found in the vmlinux - "
192 "please rebuild kernel with CONFIG_DEBUG_INFO=y.\n"); 252 "please rebuild kernel with CONFIG_DEBUG_INFO=y.\n");
193 if (!need_dwarf) { 253 if (!need_dwarf) {
194 pr_debug("Trying to use symbols.\nn"); 254 pr_debug("Trying to use symbols.\n");
195 return 0; 255 return 0;
196 } 256 }
197 } 257 }
@@ -260,47 +320,54 @@ static int get_real_path(const char *raw_path, const char *comp_dir,
260#define LINEBUF_SIZE 256 320#define LINEBUF_SIZE 256
261#define NR_ADDITIONAL_LINES 2 321#define NR_ADDITIONAL_LINES 2
262 322
263static int show_one_line(FILE *fp, int l, bool skip, bool show_num) 323static int __show_one_line(FILE *fp, int l, bool skip, bool show_num)
264{ 324{
265 char buf[LINEBUF_SIZE]; 325 char buf[LINEBUF_SIZE];
266 const char *color = PERF_COLOR_BLUE; 326 const char *color = show_num ? "" : PERF_COLOR_BLUE;
267 327 const char *prefix = NULL;
268 if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
269 goto error;
270 if (!skip) {
271 if (show_num)
272 fprintf(stdout, "%7d %s", l, buf);
273 else
274 color_fprintf(stdout, color, " %s", buf);
275 }
276 328
277 while (strlen(buf) == LINEBUF_SIZE - 1 && 329 do {
278 buf[LINEBUF_SIZE - 2] != '\n') {
279 if (fgets(buf, LINEBUF_SIZE, fp) == NULL) 330 if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
280 goto error; 331 goto error;
281 if (!skip) { 332 if (skip)
282 if (show_num) 333 continue;
283 fprintf(stdout, "%s", buf); 334 if (!prefix) {
284 else 335 prefix = show_num ? "%7d " : " ";
285 color_fprintf(stdout, color, "%s", buf); 336 color_fprintf(stdout, color, prefix, l);
286 } 337 }
287 } 338 color_fprintf(stdout, color, "%s", buf);
288 339
289 return 0; 340 } while (strchr(buf, '\n') == NULL);
341
342 return 1;
290error: 343error:
291 if (feof(fp)) 344 if (ferror(fp)) {
292 pr_warning("Source file is shorter than expected.\n");
293 else
294 pr_warning("File read error: %s\n", strerror(errno)); 345 pr_warning("File read error: %s\n", strerror(errno));
346 return -1;
347 }
348 return 0;
349}
295 350
296 return -1; 351static int _show_one_line(FILE *fp, int l, bool skip, bool show_num)
352{
353 int rv = __show_one_line(fp, l, skip, show_num);
354 if (rv == 0) {
355 pr_warning("Source file is shorter than expected.\n");
356 rv = -1;
357 }
358 return rv;
297} 359}
298 360
361#define show_one_line_with_num(f,l) _show_one_line(f,l,false,true)
362#define show_one_line(f,l) _show_one_line(f,l,false,false)
363#define skip_one_line(f,l) _show_one_line(f,l,true,false)
364#define show_one_line_or_eof(f,l) __show_one_line(f,l,false,false)
365
299/* 366/*
300 * Show line-range always requires debuginfo to find source file and 367 * Show line-range always requires debuginfo to find source file and
301 * line number. 368 * line number.
302 */ 369 */
303int show_line_range(struct line_range *lr) 370int show_line_range(struct line_range *lr, const char *module)
304{ 371{
305 int l = 1; 372 int l = 1;
306 struct line_node *ln; 373 struct line_node *ln;
@@ -313,14 +380,13 @@ int show_line_range(struct line_range *lr)
313 if (ret < 0) 380 if (ret < 0)
314 return ret; 381 return ret;
315 382
316 fd = open_vmlinux(); 383 fd = open_vmlinux(module);
317 if (fd < 0) { 384 if (fd < 0) {
318 pr_warning("Failed to open debuginfo file.\n"); 385 pr_warning("Failed to open debuginfo file.\n");
319 return fd; 386 return fd;
320 } 387 }
321 388
322 ret = find_line_range(fd, lr); 389 ret = find_line_range(fd, lr);
323 close(fd);
324 if (ret == 0) { 390 if (ret == 0) {
325 pr_warning("Specified source line is not found.\n"); 391 pr_warning("Specified source line is not found.\n");
326 return -ENOENT; 392 return -ENOENT;
@@ -341,10 +407,10 @@ int show_line_range(struct line_range *lr)
341 setup_pager(); 407 setup_pager();
342 408
343 if (lr->function) 409 if (lr->function)
344 fprintf(stdout, "<%s:%d>\n", lr->function, 410 fprintf(stdout, "<%s@%s:%d>\n", lr->function, lr->path,
345 lr->start - lr->offset); 411 lr->start - lr->offset);
346 else 412 else
347 fprintf(stdout, "<%s:%d>\n", lr->file, lr->start); 413 fprintf(stdout, "<%s:%d>\n", lr->path, lr->start);
348 414
349 fp = fopen(lr->path, "r"); 415 fp = fopen(lr->path, "r");
350 if (fp == NULL) { 416 if (fp == NULL) {
@@ -353,36 +419,124 @@ int show_line_range(struct line_range *lr)
353 return -errno; 419 return -errno;
354 } 420 }
355 /* Skip to starting line number */ 421 /* Skip to starting line number */
356 while (l < lr->start && ret >= 0) 422 while (l < lr->start) {
357 ret = show_one_line(fp, l++, true, false); 423 ret = skip_one_line(fp, l++);
358 if (ret < 0) 424 if (ret < 0)
359 goto end; 425 goto end;
426 }
360 427
361 list_for_each_entry(ln, &lr->line_list, list) { 428 list_for_each_entry(ln, &lr->line_list, list) {
362 while (ln->line > l && ret >= 0) 429 for (; ln->line > l; l++) {
363 ret = show_one_line(fp, (l++) - lr->offset, 430 ret = show_one_line(fp, l - lr->offset);
364 false, false); 431 if (ret < 0)
365 if (ret >= 0) 432 goto end;
366 ret = show_one_line(fp, (l++) - lr->offset, 433 }
367 false, true); 434 ret = show_one_line_with_num(fp, l++ - lr->offset);
368 if (ret < 0) 435 if (ret < 0)
369 goto end; 436 goto end;
370 } 437 }
371 438
372 if (lr->end == INT_MAX) 439 if (lr->end == INT_MAX)
373 lr->end = l + NR_ADDITIONAL_LINES; 440 lr->end = l + NR_ADDITIONAL_LINES;
374 while (l <= lr->end && !feof(fp) && ret >= 0) 441 while (l <= lr->end) {
375 ret = show_one_line(fp, (l++) - lr->offset, false, false); 442 ret = show_one_line_or_eof(fp, l++ - lr->offset);
443 if (ret <= 0)
444 break;
445 }
376end: 446end:
377 fclose(fp); 447 fclose(fp);
378 return ret; 448 return ret;
379} 449}
380 450
451static int show_available_vars_at(int fd, struct perf_probe_event *pev,
452 int max_vls, struct strfilter *_filter,
453 bool externs)
454{
455 char *buf;
456 int ret, i, nvars;
457 struct str_node *node;
458 struct variable_list *vls = NULL, *vl;
459 const char *var;
460
461 buf = synthesize_perf_probe_point(&pev->point);
462 if (!buf)
463 return -EINVAL;
464 pr_debug("Searching variables at %s\n", buf);
465
466 ret = find_available_vars_at(fd, pev, &vls, max_vls, externs);
467 if (ret <= 0) {
468 pr_err("Failed to find variables at %s (%d)\n", buf, ret);
469 goto end;
470 }
471 /* Some variables are found */
472 fprintf(stdout, "Available variables at %s\n", buf);
473 for (i = 0; i < ret; i++) {
474 vl = &vls[i];
475 /*
476 * A probe point might be converted to
477 * several trace points.
478 */
479 fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol,
480 vl->point.offset);
481 free(vl->point.symbol);
482 nvars = 0;
483 if (vl->vars) {
484 strlist__for_each(node, vl->vars) {
485 var = strchr(node->s, '\t') + 1;
486 if (strfilter__compare(_filter, var)) {
487 fprintf(stdout, "\t\t%s\n", node->s);
488 nvars++;
489 }
490 }
491 strlist__delete(vl->vars);
492 }
493 if (nvars == 0)
494 fprintf(stdout, "\t\t(No matched variables)\n");
495 }
496 free(vls);
497end:
498 free(buf);
499 return ret;
500}
501
502/* Show available variables on given probe point */
503int show_available_vars(struct perf_probe_event *pevs, int npevs,
504 int max_vls, const char *module,
505 struct strfilter *_filter, bool externs)
506{
507 int i, fd, ret = 0;
508
509 ret = init_vmlinux();
510 if (ret < 0)
511 return ret;
512
513 setup_pager();
514
515 for (i = 0; i < npevs && ret >= 0; i++) {
516 fd = open_vmlinux(module);
517 if (fd < 0) {
518 pr_warning("Failed to open debug information file.\n");
519 ret = fd;
520 break;
521 }
522 ret = show_available_vars_at(fd, &pevs[i], max_vls, _filter,
523 externs);
524 }
525 return ret;
526}
527
381#else /* !DWARF_SUPPORT */ 528#else /* !DWARF_SUPPORT */
382 529
383static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, 530static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
384 struct perf_probe_point *pp) 531 struct perf_probe_point *pp)
385{ 532{
533 struct symbol *sym;
534
535 sym = __find_kernel_function_by_name(tp->symbol, NULL);
536 if (!sym) {
537 pr_err("Failed to find symbol %s in kernel.\n", tp->symbol);
538 return -ENOENT;
539 }
386 pp->function = strdup(tp->symbol); 540 pp->function = strdup(tp->symbol);
387 if (pp->function == NULL) 541 if (pp->function == NULL)
388 return -ENOMEM; 542 return -ENOMEM;
@@ -394,7 +548,7 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
394 548
395static int try_to_find_probe_trace_events(struct perf_probe_event *pev, 549static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
396 struct probe_trace_event **tevs __unused, 550 struct probe_trace_event **tevs __unused,
397 int max_tevs __unused) 551 int max_tevs __unused, const char *mod __unused)
398{ 552{
399 if (perf_probe_event_need_dwarf(pev)) { 553 if (perf_probe_event_need_dwarf(pev)) {
400 pr_warning("Debuginfo-analysis is not supported.\n"); 554 pr_warning("Debuginfo-analysis is not supported.\n");
@@ -403,64 +557,113 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
403 return 0; 557 return 0;
404} 558}
405 559
406int show_line_range(struct line_range *lr __unused) 560int show_line_range(struct line_range *lr __unused, const char *module __unused)
407{ 561{
408 pr_warning("Debuginfo-analysis is not supported.\n"); 562 pr_warning("Debuginfo-analysis is not supported.\n");
409 return -ENOSYS; 563 return -ENOSYS;
410} 564}
411 565
566int show_available_vars(struct perf_probe_event *pevs __unused,
567 int npevs __unused, int max_vls __unused,
568 const char *module __unused,
569 struct strfilter *filter __unused,
570 bool externs __unused)
571{
572 pr_warning("Debuginfo-analysis is not supported.\n");
573 return -ENOSYS;
574}
412#endif 575#endif
413 576
577static int parse_line_num(char **ptr, int *val, const char *what)
578{
579 const char *start = *ptr;
580
581 errno = 0;
582 *val = strtol(*ptr, ptr, 0);
583 if (errno || *ptr == start) {
584 semantic_error("'%s' is not a valid number.\n", what);
585 return -EINVAL;
586 }
587 return 0;
588}
589
590/*
591 * Stuff 'lr' according to the line range described by 'arg'.
592 * The line range syntax is described by:
593 *
594 * SRC[:SLN[+NUM|-ELN]]
595 * FNC[@SRC][:SLN[+NUM|-ELN]]
596 */
414int parse_line_range_desc(const char *arg, struct line_range *lr) 597int parse_line_range_desc(const char *arg, struct line_range *lr)
415{ 598{
416 const char *ptr; 599 char *range, *file, *name = strdup(arg);
417 char *tmp; 600 int err;
418 /* 601
419 * <Syntax> 602 if (!name)
420 * SRC:SLN[+NUM|-ELN] 603 return -ENOMEM;
421 * FUNC[:SLN[+NUM|-ELN]] 604
422 */ 605 lr->start = 0;
423 ptr = strchr(arg, ':'); 606 lr->end = INT_MAX;
424 if (ptr) { 607
425 lr->start = (int)strtoul(ptr + 1, &tmp, 0); 608 range = strchr(name, ':');
426 if (*tmp == '+') { 609 if (range) {
427 lr->end = lr->start + (int)strtoul(tmp + 1, &tmp, 0); 610 *range++ = '\0';
428 lr->end--; /* 611
429 * Adjust the number of lines here. 612 err = parse_line_num(&range, &lr->start, "start line");
430 * If the number of lines == 1, the 613 if (err)
431 * the end of line should be equal to 614 goto err;
432 * the start of line. 615
433 */ 616 if (*range == '+' || *range == '-') {
434 } else if (*tmp == '-') 617 const char c = *range++;
435 lr->end = (int)strtoul(tmp + 1, &tmp, 0); 618
436 else 619 err = parse_line_num(&range, &lr->end, "end line");
437 lr->end = INT_MAX; 620 if (err)
621 goto err;
622
623 if (c == '+') {
624 lr->end += lr->start;
625 /*
626 * Adjust the number of lines here.
627 * If the number of lines == 1, the
628 * the end of line should be equal to
629 * the start of line.
630 */
631 lr->end--;
632 }
633 }
634
438 pr_debug("Line range is %d to %d\n", lr->start, lr->end); 635 pr_debug("Line range is %d to %d\n", lr->start, lr->end);
636
637 err = -EINVAL;
439 if (lr->start > lr->end) { 638 if (lr->start > lr->end) {
440 semantic_error("Start line must be smaller" 639 semantic_error("Start line must be smaller"
441 " than end line.\n"); 640 " than end line.\n");
442 return -EINVAL; 641 goto err;
443 } 642 }
444 if (*tmp != '\0') { 643 if (*range != '\0') {
445 semantic_error("Tailing with invalid character '%d'.\n", 644 semantic_error("Tailing with invalid str '%s'.\n", range);
446 *tmp); 645 goto err;
447 return -EINVAL;
448 } 646 }
449 tmp = strndup(arg, (ptr - arg));
450 } else {
451 tmp = strdup(arg);
452 lr->end = INT_MAX;
453 } 647 }
454 648
455 if (tmp == NULL) 649 file = strchr(name, '@');
456 return -ENOMEM; 650 if (file) {
457 651 *file = '\0';
458 if (strchr(tmp, '.')) 652 lr->file = strdup(++file);
459 lr->file = tmp; 653 if (lr->file == NULL) {
654 err = -ENOMEM;
655 goto err;
656 }
657 lr->function = name;
658 } else if (strchr(name, '.'))
659 lr->file = name;
460 else 660 else
461 lr->function = tmp; 661 lr->function = name;
462 662
463 return 0; 663 return 0;
664err:
665 free(name);
666 return err;
464} 667}
465 668
466/* Check the name is good for event/group */ 669/* Check the name is good for event/group */
@@ -584,39 +787,40 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
584 787
585 /* Exclusion check */ 788 /* Exclusion check */
586 if (pp->lazy_line && pp->line) { 789 if (pp->lazy_line && pp->line) {
587 semantic_error("Lazy pattern can't be used with line number."); 790 semantic_error("Lazy pattern can't be used with"
791 " line number.\n");
588 return -EINVAL; 792 return -EINVAL;
589 } 793 }
590 794
591 if (pp->lazy_line && pp->offset) { 795 if (pp->lazy_line && pp->offset) {
592 semantic_error("Lazy pattern can't be used with offset."); 796 semantic_error("Lazy pattern can't be used with offset.\n");
593 return -EINVAL; 797 return -EINVAL;
594 } 798 }
595 799
596 if (pp->line && pp->offset) { 800 if (pp->line && pp->offset) {
597 semantic_error("Offset can't be used with line number."); 801 semantic_error("Offset can't be used with line number.\n");
598 return -EINVAL; 802 return -EINVAL;
599 } 803 }
600 804
601 if (!pp->line && !pp->lazy_line && pp->file && !pp->function) { 805 if (!pp->line && !pp->lazy_line && pp->file && !pp->function) {
602 semantic_error("File always requires line number or " 806 semantic_error("File always requires line number or "
603 "lazy pattern."); 807 "lazy pattern.\n");
604 return -EINVAL; 808 return -EINVAL;
605 } 809 }
606 810
607 if (pp->offset && !pp->function) { 811 if (pp->offset && !pp->function) {
608 semantic_error("Offset requires an entry function."); 812 semantic_error("Offset requires an entry function.\n");
609 return -EINVAL; 813 return -EINVAL;
610 } 814 }
611 815
612 if (pp->retprobe && !pp->function) { 816 if (pp->retprobe && !pp->function) {
613 semantic_error("Return probe requires an entry function."); 817 semantic_error("Return probe requires an entry function.\n");
614 return -EINVAL; 818 return -EINVAL;
615 } 819 }
616 820
617 if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe) { 821 if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe) {
618 semantic_error("Offset/Line/Lazy pattern can't be used with " 822 semantic_error("Offset/Line/Lazy pattern can't be used with "
619 "return probe."); 823 "return probe.\n");
620 return -EINVAL; 824 return -EINVAL;
621 } 825 }
622 826
@@ -890,7 +1094,7 @@ int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len)
890 1094
891 return tmp - buf; 1095 return tmp - buf;
892error: 1096error:
893 pr_debug("Failed to synthesize perf probe argument: %s", 1097 pr_debug("Failed to synthesize perf probe argument: %s\n",
894 strerror(-ret)); 1098 strerror(-ret));
895 return ret; 1099 return ret;
896} 1100}
@@ -918,13 +1122,13 @@ static char *synthesize_perf_probe_point(struct perf_probe_point *pp)
918 goto error; 1122 goto error;
919 } 1123 }
920 if (pp->file) { 1124 if (pp->file) {
921 len = strlen(pp->file) - 31; 1125 tmp = pp->file;
922 if (len < 0) 1126 len = strlen(tmp);
923 len = 0; 1127 if (len > 30) {
924 tmp = strchr(pp->file + len, '/'); 1128 tmp = strchr(pp->file + len - 30, '/');
925 if (!tmp) 1129 tmp = tmp ? tmp + 1 : pp->file + len - 30;
926 tmp = pp->file + len; 1130 }
927 ret = e_snprintf(file, 32, "@%s", tmp + 1); 1131 ret = e_snprintf(file, 32, "@%s", tmp);
928 if (ret <= 0) 1132 if (ret <= 0)
929 goto error; 1133 goto error;
930 } 1134 }
@@ -940,7 +1144,7 @@ static char *synthesize_perf_probe_point(struct perf_probe_point *pp)
940 1144
941 return buf; 1145 return buf;
942error: 1146error:
943 pr_debug("Failed to synthesize perf probe point: %s", 1147 pr_debug("Failed to synthesize perf probe point: %s\n",
944 strerror(-ret)); 1148 strerror(-ret));
945 if (buf) 1149 if (buf)
946 free(buf); 1150 free(buf);
@@ -1087,7 +1291,7 @@ error:
1087} 1291}
1088 1292
1089static int convert_to_perf_probe_event(struct probe_trace_event *tev, 1293static int convert_to_perf_probe_event(struct probe_trace_event *tev,
1090 struct perf_probe_event *pev) 1294 struct perf_probe_event *pev)
1091{ 1295{
1092 char buf[64] = ""; 1296 char buf[64] = "";
1093 int i, ret; 1297 int i, ret;
@@ -1516,14 +1720,14 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
1516 1720
1517static int convert_to_probe_trace_events(struct perf_probe_event *pev, 1721static int convert_to_probe_trace_events(struct perf_probe_event *pev,
1518 struct probe_trace_event **tevs, 1722 struct probe_trace_event **tevs,
1519 int max_tevs) 1723 int max_tevs, const char *module)
1520{ 1724{
1521 struct symbol *sym; 1725 struct symbol *sym;
1522 int ret = 0, i; 1726 int ret = 0, i;
1523 struct probe_trace_event *tev; 1727 struct probe_trace_event *tev;
1524 1728
1525 /* Convert perf_probe_event with debuginfo */ 1729 /* Convert perf_probe_event with debuginfo */
1526 ret = try_to_find_probe_trace_events(pev, tevs, max_tevs); 1730 ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, module);
1527 if (ret != 0) 1731 if (ret != 0)
1528 return ret; 1732 return ret;
1529 1733
@@ -1572,8 +1776,7 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
1572 } 1776 }
1573 1777
1574 /* Currently just checking function name from symbol map */ 1778 /* Currently just checking function name from symbol map */
1575 sym = map__find_symbol_by_name(machine.vmlinux_maps[MAP__FUNCTION], 1779 sym = __find_kernel_function_by_name(tev->point.symbol, NULL);
1576 tev->point.symbol, NULL);
1577 if (!sym) { 1780 if (!sym) {
1578 pr_warning("Kernel symbol \'%s\' not found.\n", 1781 pr_warning("Kernel symbol \'%s\' not found.\n",
1579 tev->point.symbol); 1782 tev->point.symbol);
@@ -1596,7 +1799,7 @@ struct __event_package {
1596}; 1799};
1597 1800
1598int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, 1801int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
1599 bool force_add, int max_tevs) 1802 int max_tevs, const char *module, bool force_add)
1600{ 1803{
1601 int i, j, ret; 1804 int i, j, ret;
1602 struct __event_package *pkgs; 1805 struct __event_package *pkgs;
@@ -1617,16 +1820,21 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
1617 pkgs[i].pev = &pevs[i]; 1820 pkgs[i].pev = &pevs[i];
1618 /* Convert with or without debuginfo */ 1821 /* Convert with or without debuginfo */
1619 ret = convert_to_probe_trace_events(pkgs[i].pev, 1822 ret = convert_to_probe_trace_events(pkgs[i].pev,
1620 &pkgs[i].tevs, max_tevs); 1823 &pkgs[i].tevs,
1824 max_tevs,
1825 module);
1621 if (ret < 0) 1826 if (ret < 0)
1622 goto end; 1827 goto end;
1623 pkgs[i].ntevs = ret; 1828 pkgs[i].ntevs = ret;
1624 } 1829 }
1625 1830
1626 /* Loop 2: add all events */ 1831 /* Loop 2: add all events */
1627 for (i = 0; i < npevs && ret >= 0; i++) 1832 for (i = 0; i < npevs; i++) {
1628 ret = __add_probe_trace_events(pkgs[i].pev, pkgs[i].tevs, 1833 ret = __add_probe_trace_events(pkgs[i].pev, pkgs[i].tevs,
1629 pkgs[i].ntevs, force_add); 1834 pkgs[i].ntevs, force_add);
1835 if (ret < 0)
1836 break;
1837 }
1630end: 1838end:
1631 /* Loop 3: cleanup and free trace events */ 1839 /* Loop 3: cleanup and free trace events */
1632 for (i = 0; i < npevs; i++) { 1840 for (i = 0; i < npevs; i++) {
@@ -1680,7 +1888,7 @@ static int del_trace_probe_event(int fd, const char *group,
1680 1888
1681 ret = e_snprintf(buf, 128, "%s:%s", group, event); 1889 ret = e_snprintf(buf, 128, "%s:%s", group, event);
1682 if (ret < 0) { 1890 if (ret < 0) {
1683 pr_err("Failed to copy event."); 1891 pr_err("Failed to copy event.\n");
1684 return ret; 1892 return ret;
1685 } 1893 }
1686 1894
@@ -1752,4 +1960,46 @@ int del_perf_probe_events(struct strlist *dellist)
1752 1960
1753 return ret; 1961 return ret;
1754} 1962}
1963/* TODO: don't use a global variable for filter ... */
1964static struct strfilter *available_func_filter;
1965
1966/*
1967 * If a symbol corresponds to a function with global binding and
1968 * matches filter return 0. For all others return 1.
1969 */
1970static int filter_available_functions(struct map *map __unused,
1971 struct symbol *sym)
1972{
1973 if (sym->binding == STB_GLOBAL &&
1974 strfilter__compare(available_func_filter, sym->name))
1975 return 0;
1976 return 1;
1977}
1755 1978
1979int show_available_funcs(const char *module, struct strfilter *_filter)
1980{
1981 struct map *map;
1982 int ret;
1983
1984 setup_pager();
1985
1986 ret = init_vmlinux();
1987 if (ret < 0)
1988 return ret;
1989
1990 map = kernel_get_module_map(module);
1991 if (!map) {
1992 pr_err("Failed to find %s map.\n", (module) ? : "kernel");
1993 return -EINVAL;
1994 }
1995 available_func_filter = _filter;
1996 if (map__load(map, filter_available_functions)) {
1997 pr_err("Failed to load map.\n");
1998 return -EINVAL;
1999 }
2000 if (!dso__sorted_by_name(map->dso, map->type))
2001 dso__sort_by_name(map->dso, map->type);
2002
2003 dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
2004 return 0;
2005}
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 5af39243a25b..3434fc9d79d5 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -3,6 +3,7 @@
3 3
4#include <stdbool.h> 4#include <stdbool.h>
5#include "strlist.h" 5#include "strlist.h"
6#include "strfilter.h"
6 7
7extern bool probe_event_dry_run; 8extern bool probe_event_dry_run;
8 9
@@ -90,6 +91,12 @@ struct line_range {
90 struct list_head line_list; /* Visible lines */ 91 struct list_head line_list; /* Visible lines */
91}; 92};
92 93
94/* List of variables */
95struct variable_list {
96 struct probe_trace_point point; /* Actual probepoint */
97 struct strlist *vars; /* Available variables */
98};
99
93/* Command string to events */ 100/* Command string to events */
94extern int parse_perf_probe_command(const char *cmd, 101extern int parse_perf_probe_command(const char *cmd,
95 struct perf_probe_event *pev); 102 struct perf_probe_event *pev);
@@ -109,12 +116,19 @@ extern void clear_perf_probe_event(struct perf_probe_event *pev);
109/* Command string to line-range */ 116/* Command string to line-range */
110extern int parse_line_range_desc(const char *cmd, struct line_range *lr); 117extern int parse_line_range_desc(const char *cmd, struct line_range *lr);
111 118
119/* Internal use: Return kernel/module path */
120extern const char *kernel_get_module_path(const char *module);
112 121
113extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, 122extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
114 bool force_add, int max_probe_points); 123 int max_probe_points, const char *module,
124 bool force_add);
115extern int del_perf_probe_events(struct strlist *dellist); 125extern int del_perf_probe_events(struct strlist *dellist);
116extern int show_perf_probe_events(void); 126extern int show_perf_probe_events(void);
117extern int show_line_range(struct line_range *lr); 127extern int show_line_range(struct line_range *lr, const char *module);
128extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
129 int max_probe_points, const char *module,
130 struct strfilter *filter, bool externs);
131extern int show_available_funcs(const char *module, struct strfilter *filter);
118 132
119 133
120/* Maximum index number of event-name postfix */ 134/* Maximum index number of event-name postfix */
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 32b81f707ff5..3b9d0b800d5c 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -33,6 +33,7 @@
33#include <ctype.h> 33#include <ctype.h>
34#include <dwarf-regs.h> 34#include <dwarf-regs.h>
35 35
36#include <linux/bitops.h>
36#include "event.h" 37#include "event.h"
37#include "debug.h" 38#include "debug.h"
38#include "util.h" 39#include "util.h"
@@ -116,6 +117,126 @@ static void line_list__free(struct list_head *head)
116 } 117 }
117} 118}
118 119
120/* Dwarf FL wrappers */
121static char *debuginfo_path; /* Currently dummy */
122
123static const Dwfl_Callbacks offline_callbacks = {
124 .find_debuginfo = dwfl_standard_find_debuginfo,
125 .debuginfo_path = &debuginfo_path,
126
127 .section_address = dwfl_offline_section_address,
128
129 /* We use this table for core files too. */
130 .find_elf = dwfl_build_id_find_elf,
131};
132
133/* Get a Dwarf from offline image */
134static Dwarf *dwfl_init_offline_dwarf(int fd, Dwfl **dwflp, Dwarf_Addr *bias)
135{
136 Dwfl_Module *mod;
137 Dwarf *dbg = NULL;
138
139 if (!dwflp)
140 return NULL;
141
142 *dwflp = dwfl_begin(&offline_callbacks);
143 if (!*dwflp)
144 return NULL;
145
146 mod = dwfl_report_offline(*dwflp, "", "", fd);
147 if (!mod)
148 goto error;
149
150 dbg = dwfl_module_getdwarf(mod, bias);
151 if (!dbg) {
152error:
153 dwfl_end(*dwflp);
154 *dwflp = NULL;
155 }
156 return dbg;
157}
158
159#if _ELFUTILS_PREREQ(0, 148)
160/* This method is buggy if elfutils is older than 0.148 */
161static int __linux_kernel_find_elf(Dwfl_Module *mod,
162 void **userdata,
163 const char *module_name,
164 Dwarf_Addr base,
165 char **file_name, Elf **elfp)
166{
167 int fd;
168 const char *path = kernel_get_module_path(module_name);
169
170 pr_debug2("Use file %s for %s\n", path, module_name);
171 if (path) {
172 fd = open(path, O_RDONLY);
173 if (fd >= 0) {
174 *file_name = strdup(path);
175 return fd;
176 }
177 }
178 /* If failed, try to call standard method */
179 return dwfl_linux_kernel_find_elf(mod, userdata, module_name, base,
180 file_name, elfp);
181}
182
183static const Dwfl_Callbacks kernel_callbacks = {
184 .find_debuginfo = dwfl_standard_find_debuginfo,
185 .debuginfo_path = &debuginfo_path,
186
187 .find_elf = __linux_kernel_find_elf,
188 .section_address = dwfl_linux_kernel_module_section_address,
189};
190
191/* Get a Dwarf from live kernel image */
192static Dwarf *dwfl_init_live_kernel_dwarf(Dwarf_Addr addr, Dwfl **dwflp,
193 Dwarf_Addr *bias)
194{
195 Dwarf *dbg;
196
197 if (!dwflp)
198 return NULL;
199
200 *dwflp = dwfl_begin(&kernel_callbacks);
201 if (!*dwflp)
202 return NULL;
203
204 /* Load the kernel dwarves: Don't care the result here */
205 dwfl_linux_kernel_report_kernel(*dwflp);
206 dwfl_linux_kernel_report_modules(*dwflp);
207
208 dbg = dwfl_addrdwarf(*dwflp, addr, bias);
209 /* Here, check whether we could get a real dwarf */
210 if (!dbg) {
211 pr_debug("Failed to find kernel dwarf at %lx\n",
212 (unsigned long)addr);
213 dwfl_end(*dwflp);
214 *dwflp = NULL;
215 }
216 return dbg;
217}
218#else
219/* With older elfutils, this just support kernel module... */
220static Dwarf *dwfl_init_live_kernel_dwarf(Dwarf_Addr addr __used, Dwfl **dwflp,
221 Dwarf_Addr *bias)
222{
223 int fd;
224 const char *path = kernel_get_module_path("kernel");
225
226 if (!path) {
227 pr_err("Failed to find vmlinux path\n");
228 return NULL;
229 }
230
231 pr_debug2("Use file %s for debuginfo\n", path);
232 fd = open(path, O_RDONLY);
233 if (fd < 0)
234 return NULL;
235
236 return dwfl_init_offline_dwarf(fd, dwflp, bias);
237}
238#endif
239
119/* Dwarf wrappers */ 240/* Dwarf wrappers */
120 241
121/* Find the realpath of the target file. */ 242/* Find the realpath of the target file. */
@@ -152,6 +273,25 @@ static const char *cu_get_comp_dir(Dwarf_Die *cu_die)
152 return dwarf_formstring(&attr); 273 return dwarf_formstring(&attr);
153} 274}
154 275
276/* Get a line number and file name for given address */
277static int cu_find_lineinfo(Dwarf_Die *cudie, unsigned long addr,
278 const char **fname, int *lineno)
279{
280 Dwarf_Line *line;
281 Dwarf_Addr laddr;
282
283 line = dwarf_getsrc_die(cudie, (Dwarf_Addr)addr);
284 if (line && dwarf_lineaddr(line, &laddr) == 0 &&
285 addr == (unsigned long)laddr && dwarf_lineno(line, lineno) == 0) {
286 *fname = dwarf_linesrc(line, NULL, NULL);
287 if (!*fname)
288 /* line number is useless without filename */
289 *lineno = 0;
290 }
291
292 return *lineno ?: -ENOENT;
293}
294
155/* Compare diename and tname */ 295/* Compare diename and tname */
156static bool die_compare_name(Dwarf_Die *dw_die, const char *tname) 296static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
157{ 297{
@@ -160,35 +300,76 @@ static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
160 return name ? (strcmp(tname, name) == 0) : false; 300 return name ? (strcmp(tname, name) == 0) : false;
161} 301}
162 302
163/* Get type die, but skip qualifiers and typedef */ 303/* Get callsite line number of inline-function instance */
164static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) 304static int die_get_call_lineno(Dwarf_Die *in_die)
165{ 305{
166 Dwarf_Attribute attr; 306 Dwarf_Attribute attr;
307 Dwarf_Word ret;
308
309 if (!dwarf_attr(in_die, DW_AT_call_line, &attr))
310 return -ENOENT;
311
312 dwarf_formudata(&attr, &ret);
313 return (int)ret;
314}
315
316/* Get type die */
317static Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
318{
319 Dwarf_Attribute attr;
320
321 if (dwarf_attr_integrate(vr_die, DW_AT_type, &attr) &&
322 dwarf_formref_die(&attr, die_mem))
323 return die_mem;
324 else
325 return NULL;
326}
327
328/* Get a type die, but skip qualifiers */
329static Dwarf_Die *__die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
330{
167 int tag; 331 int tag;
168 332
169 do { 333 do {
170 if (dwarf_attr(vr_die, DW_AT_type, &attr) == NULL || 334 vr_die = die_get_type(vr_die, die_mem);
171 dwarf_formref_die(&attr, die_mem) == NULL) 335 if (!vr_die)
172 return NULL; 336 break;
173 337 tag = dwarf_tag(vr_die);
174 tag = dwarf_tag(die_mem);
175 vr_die = die_mem;
176 } while (tag == DW_TAG_const_type || 338 } while (tag == DW_TAG_const_type ||
177 tag == DW_TAG_restrict_type || 339 tag == DW_TAG_restrict_type ||
178 tag == DW_TAG_volatile_type || 340 tag == DW_TAG_volatile_type ||
179 tag == DW_TAG_shared_type || 341 tag == DW_TAG_shared_type);
180 tag == DW_TAG_typedef);
181 342
182 return die_mem; 343 return vr_die;
183} 344}
184 345
185static bool die_is_signed_type(Dwarf_Die *tp_die) 346/* Get a type die, but skip qualifiers and typedef */
347static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
348{
349 do {
350 vr_die = __die_get_real_type(vr_die, die_mem);
351 } while (vr_die && dwarf_tag(vr_die) == DW_TAG_typedef);
352
353 return vr_die;
354}
355
356static int die_get_attr_udata(Dwarf_Die *tp_die, unsigned int attr_name,
357 Dwarf_Word *result)
186{ 358{
187 Dwarf_Attribute attr; 359 Dwarf_Attribute attr;
360
361 if (dwarf_attr(tp_die, attr_name, &attr) == NULL ||
362 dwarf_formudata(&attr, result) != 0)
363 return -ENOENT;
364
365 return 0;
366}
367
368static bool die_is_signed_type(Dwarf_Die *tp_die)
369{
188 Dwarf_Word ret; 370 Dwarf_Word ret;
189 371
190 if (dwarf_attr(tp_die, DW_AT_encoding, &attr) == NULL || 372 if (die_get_attr_udata(tp_die, DW_AT_encoding, &ret))
191 dwarf_formudata(&attr, &ret) != 0)
192 return false; 373 return false;
193 374
194 return (ret == DW_ATE_signed_char || ret == DW_ATE_signed || 375 return (ret == DW_ATE_signed_char || ret == DW_ATE_signed ||
@@ -197,11 +378,29 @@ static bool die_is_signed_type(Dwarf_Die *tp_die)
197 378
198static int die_get_byte_size(Dwarf_Die *tp_die) 379static int die_get_byte_size(Dwarf_Die *tp_die)
199{ 380{
200 Dwarf_Attribute attr;
201 Dwarf_Word ret; 381 Dwarf_Word ret;
202 382
203 if (dwarf_attr(tp_die, DW_AT_byte_size, &attr) == NULL || 383 if (die_get_attr_udata(tp_die, DW_AT_byte_size, &ret))
204 dwarf_formudata(&attr, &ret) != 0) 384 return 0;
385
386 return (int)ret;
387}
388
389static int die_get_bit_size(Dwarf_Die *tp_die)
390{
391 Dwarf_Word ret;
392
393 if (die_get_attr_udata(tp_die, DW_AT_bit_size, &ret))
394 return 0;
395
396 return (int)ret;
397}
398
399static int die_get_bit_offset(Dwarf_Die *tp_die)
400{
401 Dwarf_Word ret;
402
403 if (die_get_attr_udata(tp_die, DW_AT_bit_offset, &ret))
205 return 0; 404 return 0;
206 405
207 return (int)ret; 406 return (int)ret;
@@ -317,28 +516,196 @@ static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data)
317static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, 516static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
318 Dwarf_Die *die_mem) 517 Dwarf_Die *die_mem)
319{ 518{
320 return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem); 519 Dwarf_Die tmp_die;
520
521 sp_die = die_find_child(sp_die, __die_find_inline_cb, &addr, &tmp_die);
522 if (!sp_die)
523 return NULL;
524
525 /* Inlined function could be recursive. Trace it until fail */
526 while (sp_die) {
527 memcpy(die_mem, sp_die, sizeof(Dwarf_Die));
528 sp_die = die_find_child(sp_die, __die_find_inline_cb, &addr,
529 &tmp_die);
530 }
531
532 return die_mem;
533}
534
535/* Walker on lines (Note: line number will not be sorted) */
536typedef int (* line_walk_handler_t) (const char *fname, int lineno,
537 Dwarf_Addr addr, void *data);
538
539struct __line_walk_param {
540 const char *fname;
541 line_walk_handler_t handler;
542 void *data;
543 int retval;
544};
545
546static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data)
547{
548 struct __line_walk_param *lw = data;
549 Dwarf_Addr addr;
550 int lineno;
551
552 if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) {
553 lineno = die_get_call_lineno(in_die);
554 if (lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) {
555 lw->retval = lw->handler(lw->fname, lineno, addr,
556 lw->data);
557 if (lw->retval != 0)
558 return DIE_FIND_CB_FOUND;
559 }
560 }
561 return DIE_FIND_CB_SIBLING;
562}
563
564/* Walk on lines of blocks included in given DIE */
565static int __die_walk_funclines(Dwarf_Die *sp_die,
566 line_walk_handler_t handler, void *data)
567{
568 struct __line_walk_param lw = {
569 .handler = handler,
570 .data = data,
571 .retval = 0,
572 };
573 Dwarf_Die die_mem;
574 Dwarf_Addr addr;
575 int lineno;
576
577 /* Handle function declaration line */
578 lw.fname = dwarf_decl_file(sp_die);
579 if (lw.fname && dwarf_decl_line(sp_die, &lineno) == 0 &&
580 dwarf_entrypc(sp_die, &addr) == 0) {
581 lw.retval = handler(lw.fname, lineno, addr, data);
582 if (lw.retval != 0)
583 goto done;
584 }
585 die_find_child(sp_die, __die_walk_funclines_cb, &lw, &die_mem);
586done:
587 return lw.retval;
588}
589
590static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data)
591{
592 struct __line_walk_param *lw = data;
593
594 lw->retval = __die_walk_funclines(sp_die, lw->handler, lw->data);
595 if (lw->retval != 0)
596 return DWARF_CB_ABORT;
597
598 return DWARF_CB_OK;
321} 599}
322 600
601/*
602 * Walk on lines inside given PDIE. If the PDIE is subprogram, walk only on
603 * the lines inside the subprogram, otherwise PDIE must be a CU DIE.
604 */
605static int die_walk_lines(Dwarf_Die *pdie, line_walk_handler_t handler,
606 void *data)
607{
608 Dwarf_Lines *lines;
609 Dwarf_Line *line;
610 Dwarf_Addr addr;
611 const char *fname;
612 int lineno, ret = 0;
613 Dwarf_Die die_mem, *cu_die;
614 size_t nlines, i;
615
616 /* Get the CU die */
617 if (dwarf_tag(pdie) == DW_TAG_subprogram)
618 cu_die = dwarf_diecu(pdie, &die_mem, NULL, NULL);
619 else
620 cu_die = pdie;
621 if (!cu_die) {
622 pr_debug2("Failed to get CU from subprogram\n");
623 return -EINVAL;
624 }
625
626 /* Get lines list in the CU */
627 if (dwarf_getsrclines(cu_die, &lines, &nlines) != 0) {
628 pr_debug2("Failed to get source lines on this CU.\n");
629 return -ENOENT;
630 }
631 pr_debug2("Get %zd lines from this CU\n", nlines);
632
633 /* Walk on the lines on lines list */
634 for (i = 0; i < nlines; i++) {
635 line = dwarf_onesrcline(lines, i);
636 if (line == NULL ||
637 dwarf_lineno(line, &lineno) != 0 ||
638 dwarf_lineaddr(line, &addr) != 0) {
639 pr_debug2("Failed to get line info. "
640 "Possible error in debuginfo.\n");
641 continue;
642 }
643 /* Filter lines based on address */
644 if (pdie != cu_die)
645 /*
646 * Address filtering
647 * The line is included in given function, and
648 * no inline block includes it.
649 */
650 if (!dwarf_haspc(pdie, addr) ||
651 die_find_inlinefunc(pdie, addr, &die_mem))
652 continue;
653 /* Get source line */
654 fname = dwarf_linesrc(line, NULL, NULL);
655
656 ret = handler(fname, lineno, addr, data);
657 if (ret != 0)
658 return ret;
659 }
660
661 /*
662 * Dwarf lines doesn't include function declarations and inlined
663 * subroutines. We have to check functions list or given function.
664 */
665 if (pdie != cu_die)
666 ret = __die_walk_funclines(pdie, handler, data);
667 else {
668 struct __line_walk_param param = {
669 .handler = handler,
670 .data = data,
671 .retval = 0,
672 };
673 dwarf_getfuncs(cu_die, __die_walk_culines_cb, &param, 0);
674 ret = param.retval;
675 }
676
677 return ret;
678}
679
680struct __find_variable_param {
681 const char *name;
682 Dwarf_Addr addr;
683};
684
323static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data) 685static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data)
324{ 686{
325 const char *name = data; 687 struct __find_variable_param *fvp = data;
326 int tag; 688 int tag;
327 689
328 tag = dwarf_tag(die_mem); 690 tag = dwarf_tag(die_mem);
329 if ((tag == DW_TAG_formal_parameter || 691 if ((tag == DW_TAG_formal_parameter ||
330 tag == DW_TAG_variable) && 692 tag == DW_TAG_variable) &&
331 die_compare_name(die_mem, name)) 693 die_compare_name(die_mem, fvp->name))
332 return DIE_FIND_CB_FOUND; 694 return DIE_FIND_CB_FOUND;
333 695
334 return DIE_FIND_CB_CONTINUE; 696 if (dwarf_haspc(die_mem, fvp->addr))
697 return DIE_FIND_CB_CONTINUE;
698 else
699 return DIE_FIND_CB_SIBLING;
335} 700}
336 701
337/* Find a variable called 'name' */ 702/* Find a variable called 'name' at given address */
338static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name, 703static Dwarf_Die *die_find_variable_at(Dwarf_Die *sp_die, const char *name,
339 Dwarf_Die *die_mem) 704 Dwarf_Addr addr, Dwarf_Die *die_mem)
340{ 705{
341 return die_find_child(sp_die, __die_find_variable_cb, (void *)name, 706 struct __find_variable_param fvp = { .name = name, .addr = addr};
707
708 return die_find_child(sp_die, __die_find_variable_cb, (void *)&fvp,
342 die_mem); 709 die_mem);
343} 710}
344 711
@@ -361,6 +728,60 @@ static Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name,
361 die_mem); 728 die_mem);
362} 729}
363 730
731/* Get the name of given variable DIE */
732static int die_get_typename(Dwarf_Die *vr_die, char *buf, int len)
733{
734 Dwarf_Die type;
735 int tag, ret, ret2;
736 const char *tmp = "";
737
738 if (__die_get_real_type(vr_die, &type) == NULL)
739 return -ENOENT;
740
741 tag = dwarf_tag(&type);
742 if (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)
743 tmp = "*";
744 else if (tag == DW_TAG_subroutine_type) {
745 /* Function pointer */
746 ret = snprintf(buf, len, "(function_type)");
747 return (ret >= len) ? -E2BIG : ret;
748 } else {
749 if (!dwarf_diename(&type))
750 return -ENOENT;
751 if (tag == DW_TAG_union_type)
752 tmp = "union ";
753 else if (tag == DW_TAG_structure_type)
754 tmp = "struct ";
755 /* Write a base name */
756 ret = snprintf(buf, len, "%s%s", tmp, dwarf_diename(&type));
757 return (ret >= len) ? -E2BIG : ret;
758 }
759 ret = die_get_typename(&type, buf, len);
760 if (ret > 0) {
761 ret2 = snprintf(buf + ret, len - ret, "%s", tmp);
762 ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret;
763 }
764 return ret;
765}
766
767/* Get the name and type of given variable DIE, stored as "type\tname" */
768static int die_get_varname(Dwarf_Die *vr_die, char *buf, int len)
769{
770 int ret, ret2;
771
772 ret = die_get_typename(vr_die, buf, len);
773 if (ret < 0) {
774 pr_debug("Failed to get type, make it unknown.\n");
775 ret = snprintf(buf, len, "(unknown_type)");
776 }
777 if (ret > 0) {
778 ret2 = snprintf(buf + ret, len - ret, "\t%s",
779 dwarf_diename(vr_die));
780 ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret;
781 }
782 return ret;
783}
784
364/* 785/*
365 * Probe finder related functions 786 * Probe finder related functions
366 */ 787 */
@@ -374,8 +795,13 @@ static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs)
374 return ref; 795 return ref;
375} 796}
376 797
377/* Show a location */ 798/*
378static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf) 799 * Convert a location into trace_arg.
800 * If tvar == NULL, this just checks variable can be converted.
801 */
802static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr,
803 Dwarf_Op *fb_ops,
804 struct probe_trace_arg *tvar)
379{ 805{
380 Dwarf_Attribute attr; 806 Dwarf_Attribute attr;
381 Dwarf_Op *op; 807 Dwarf_Op *op;
@@ -384,20 +810,23 @@ static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf)
384 Dwarf_Word offs = 0; 810 Dwarf_Word offs = 0;
385 bool ref = false; 811 bool ref = false;
386 const char *regs; 812 const char *regs;
387 struct probe_trace_arg *tvar = pf->tvar;
388 int ret; 813 int ret;
389 814
815 if (dwarf_attr(vr_die, DW_AT_external, &attr) != NULL)
816 goto static_var;
817
390 /* TODO: handle more than 1 exprs */ 818 /* TODO: handle more than 1 exprs */
391 if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL || 819 if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL ||
392 dwarf_getlocation_addr(&attr, pf->addr, &op, &nops, 1) <= 0 || 820 dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0 ||
393 nops == 0) { 821 nops == 0) {
394 /* TODO: Support const_value */ 822 /* TODO: Support const_value */
395 pr_err("Failed to find the location of %s at this address.\n"
396 " Perhaps, it has been optimized out.\n", pf->pvar->var);
397 return -ENOENT; 823 return -ENOENT;
398 } 824 }
399 825
400 if (op->atom == DW_OP_addr) { 826 if (op->atom == DW_OP_addr) {
827static_var:
828 if (!tvar)
829 return 0;
401 /* Static variables on memory (not stack), make @varname */ 830 /* Static variables on memory (not stack), make @varname */
402 ret = strlen(dwarf_diename(vr_die)); 831 ret = strlen(dwarf_diename(vr_die));
403 tvar->value = zalloc(ret + 2); 832 tvar->value = zalloc(ret + 2);
@@ -412,14 +841,11 @@ static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf)
412 841
413 /* If this is based on frame buffer, set the offset */ 842 /* If this is based on frame buffer, set the offset */
414 if (op->atom == DW_OP_fbreg) { 843 if (op->atom == DW_OP_fbreg) {
415 if (pf->fb_ops == NULL) { 844 if (fb_ops == NULL)
416 pr_warning("The attribute of frame base is not "
417 "supported.\n");
418 return -ENOTSUP; 845 return -ENOTSUP;
419 }
420 ref = true; 846 ref = true;
421 offs = op->number; 847 offs = op->number;
422 op = &pf->fb_ops[0]; 848 op = &fb_ops[0];
423 } 849 }
424 850
425 if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) { 851 if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) {
@@ -435,13 +861,18 @@ static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf)
435 } else if (op->atom == DW_OP_regx) { 861 } else if (op->atom == DW_OP_regx) {
436 regn = op->number; 862 regn = op->number;
437 } else { 863 } else {
438 pr_warning("DW_OP %x is not supported.\n", op->atom); 864 pr_debug("DW_OP %x is not supported.\n", op->atom);
439 return -ENOTSUP; 865 return -ENOTSUP;
440 } 866 }
441 867
868 if (!tvar)
869 return 0;
870
442 regs = get_arch_regstr(regn); 871 regs = get_arch_regstr(regn);
443 if (!regs) { 872 if (!regs) {
444 pr_warning("Mapping for DWARF register number %u missing on this architecture.", regn); 873 /* This should be a bug in DWARF or this tool */
874 pr_warning("Mapping for the register number %u "
875 "missing on this architecture.\n", regn);
445 return -ERANGE; 876 return -ERANGE;
446 } 877 }
447 878
@@ -457,6 +888,8 @@ static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf)
457 return 0; 888 return 0;
458} 889}
459 890
891#define BYTES_TO_BITS(nb) ((nb) * BITS_PER_LONG / sizeof(long))
892
460static int convert_variable_type(Dwarf_Die *vr_die, 893static int convert_variable_type(Dwarf_Die *vr_die,
461 struct probe_trace_arg *tvar, 894 struct probe_trace_arg *tvar,
462 const char *cast) 895 const char *cast)
@@ -473,6 +906,14 @@ static int convert_variable_type(Dwarf_Die *vr_die,
473 return (tvar->type == NULL) ? -ENOMEM : 0; 906 return (tvar->type == NULL) ? -ENOMEM : 0;
474 } 907 }
475 908
909 if (die_get_bit_size(vr_die) != 0) {
910 /* This is a bitfield */
911 ret = snprintf(buf, 16, "b%d@%d/%zd", die_get_bit_size(vr_die),
912 die_get_bit_offset(vr_die),
913 BYTES_TO_BITS(die_get_byte_size(vr_die)));
914 goto formatted;
915 }
916
476 if (die_get_real_type(vr_die, &type) == NULL) { 917 if (die_get_real_type(vr_die, &type) == NULL) {
477 pr_warning("Failed to get a type information of %s.\n", 918 pr_warning("Failed to get a type information of %s.\n",
478 dwarf_diename(vr_die)); 919 dwarf_diename(vr_die));
@@ -487,13 +928,14 @@ static int convert_variable_type(Dwarf_Die *vr_die,
487 if (ret != DW_TAG_pointer_type && 928 if (ret != DW_TAG_pointer_type &&
488 ret != DW_TAG_array_type) { 929 ret != DW_TAG_array_type) {
489 pr_warning("Failed to cast into string: " 930 pr_warning("Failed to cast into string: "
490 "%s(%s) is not a pointer nor array.", 931 "%s(%s) is not a pointer nor array.\n",
491 dwarf_diename(vr_die), dwarf_diename(&type)); 932 dwarf_diename(vr_die), dwarf_diename(&type));
492 return -EINVAL; 933 return -EINVAL;
493 } 934 }
494 if (ret == DW_TAG_pointer_type) { 935 if (ret == DW_TAG_pointer_type) {
495 if (die_get_real_type(&type, &type) == NULL) { 936 if (die_get_real_type(&type, &type) == NULL) {
496 pr_warning("Failed to get a type information."); 937 pr_warning("Failed to get a type"
938 " information.\n");
497 return -ENOENT; 939 return -ENOENT;
498 } 940 }
499 while (*ref_ptr) 941 while (*ref_ptr)
@@ -508,7 +950,7 @@ static int convert_variable_type(Dwarf_Die *vr_die,
508 if (!die_compare_name(&type, "char") && 950 if (!die_compare_name(&type, "char") &&
509 !die_compare_name(&type, "unsigned char")) { 951 !die_compare_name(&type, "unsigned char")) {
510 pr_warning("Failed to cast into string: " 952 pr_warning("Failed to cast into string: "
511 "%s is not (unsigned) char *.", 953 "%s is not (unsigned) char *.\n",
512 dwarf_diename(vr_die)); 954 dwarf_diename(vr_die));
513 return -EINVAL; 955 return -EINVAL;
514 } 956 }
@@ -516,29 +958,31 @@ static int convert_variable_type(Dwarf_Die *vr_die,
516 return (tvar->type == NULL) ? -ENOMEM : 0; 958 return (tvar->type == NULL) ? -ENOMEM : 0;
517 } 959 }
518 960
519 ret = die_get_byte_size(&type) * 8; 961 ret = BYTES_TO_BITS(die_get_byte_size(&type));
520 if (ret) { 962 if (!ret)
521 /* Check the bitwidth */ 963 /* No size ... try to use default type */
522 if (ret > MAX_BASIC_TYPE_BITS) { 964 return 0;
523 pr_info("%s exceeds max-bitwidth."
524 " Cut down to %d bits.\n",
525 dwarf_diename(&type), MAX_BASIC_TYPE_BITS);
526 ret = MAX_BASIC_TYPE_BITS;
527 }
528 965
529 ret = snprintf(buf, 16, "%c%d", 966 /* Check the bitwidth */
530 die_is_signed_type(&type) ? 's' : 'u', ret); 967 if (ret > MAX_BASIC_TYPE_BITS) {
531 if (ret < 0 || ret >= 16) { 968 pr_info("%s exceeds max-bitwidth. Cut down to %d bits.\n",
532 if (ret >= 16) 969 dwarf_diename(&type), MAX_BASIC_TYPE_BITS);
533 ret = -E2BIG; 970 ret = MAX_BASIC_TYPE_BITS;
534 pr_warning("Failed to convert variable type: %s\n",
535 strerror(-ret));
536 return ret;
537 }
538 tvar->type = strdup(buf);
539 if (tvar->type == NULL)
540 return -ENOMEM;
541 } 971 }
972 ret = snprintf(buf, 16, "%c%d",
973 die_is_signed_type(&type) ? 's' : 'u', ret);
974
975formatted:
976 if (ret < 0 || ret >= 16) {
977 if (ret >= 16)
978 ret = -E2BIG;
979 pr_warning("Failed to convert variable type: %s\n",
980 strerror(-ret));
981 return ret;
982 }
983 tvar->type = strdup(buf);
984 if (tvar->type == NULL)
985 return -ENOMEM;
542 return 0; 986 return 0;
543} 987}
544 988
@@ -618,8 +1062,8 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
618 return -EINVAL; 1062 return -EINVAL;
619 } 1063 }
620 if (field->name[0] == '[') { 1064 if (field->name[0] == '[') {
621 pr_err("Semantic error: %s is not a pointor nor array.", 1065 pr_err("Semantic error: %s is not a pointor"
622 varname); 1066 " nor array.\n", varname);
623 return -EINVAL; 1067 return -EINVAL;
624 } 1068 }
625 if (field->ref) { 1069 if (field->ref) {
@@ -666,8 +1110,14 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
666 pr_debug("Converting variable %s into trace event.\n", 1110 pr_debug("Converting variable %s into trace event.\n",
667 dwarf_diename(vr_die)); 1111 dwarf_diename(vr_die));
668 1112
669 ret = convert_variable_location(vr_die, pf); 1113 ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops,
670 if (ret == 0 && pf->pvar->field) { 1114 pf->tvar);
1115 if (ret == -ENOENT)
1116 pr_err("Failed to find the location of %s at this address.\n"
1117 " Perhaps, it has been optimized out.\n", pf->pvar->var);
1118 else if (ret == -ENOTSUP)
1119 pr_err("Sorry, we don't support this variable location yet.\n");
1120 else if (pf->pvar->field) {
671 ret = convert_variable_fields(vr_die, pf->pvar->var, 1121 ret = convert_variable_fields(vr_die, pf->pvar->var,
672 pf->pvar->field, &pf->tvar->ref, 1122 pf->pvar->field, &pf->tvar->ref,
673 &die_mem); 1123 &die_mem);
@@ -722,85 +1172,87 @@ static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
722 pr_debug("Searching '%s' variable in context.\n", 1172 pr_debug("Searching '%s' variable in context.\n",
723 pf->pvar->var); 1173 pf->pvar->var);
724 /* Search child die for local variables and parameters. */ 1174 /* Search child die for local variables and parameters. */
725 if (die_find_variable(sp_die, pf->pvar->var, &vr_die)) 1175 if (die_find_variable_at(sp_die, pf->pvar->var, pf->addr, &vr_die))
726 ret = convert_variable(&vr_die, pf); 1176 ret = convert_variable(&vr_die, pf);
727 else { 1177 else {
728 /* Search upper class */ 1178 /* Search upper class */
729 nscopes = dwarf_getscopes_die(sp_die, &scopes); 1179 nscopes = dwarf_getscopes_die(sp_die, &scopes);
730 if (nscopes > 0) { 1180 while (nscopes-- > 1) {
731 ret = dwarf_getscopevar(scopes, nscopes, pf->pvar->var, 1181 pr_debug("Searching variables in %s\n",
732 0, NULL, 0, 0, &vr_die); 1182 dwarf_diename(&scopes[nscopes]));
733 if (ret >= 0) 1183 /* We should check this scope, so give dummy address */
1184 if (die_find_variable_at(&scopes[nscopes],
1185 pf->pvar->var, 0,
1186 &vr_die)) {
734 ret = convert_variable(&vr_die, pf); 1187 ret = convert_variable(&vr_die, pf);
735 else 1188 goto found;
736 ret = -ENOENT; 1189 }
1190 }
1191 if (scopes)
737 free(scopes); 1192 free(scopes);
738 } else 1193 ret = -ENOENT;
739 ret = -ENOENT;
740 } 1194 }
1195found:
741 if (ret < 0) 1196 if (ret < 0)
742 pr_warning("Failed to find '%s' in this function.\n", 1197 pr_warning("Failed to find '%s' in this function.\n",
743 pf->pvar->var); 1198 pf->pvar->var);
744 return ret; 1199 return ret;
745} 1200}
746 1201
747/* Show a probe point to output buffer */ 1202/* Convert subprogram DIE to trace point */
748static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) 1203static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr,
1204 bool retprobe, struct probe_trace_point *tp)
749{ 1205{
750 struct probe_trace_event *tev;
751 Dwarf_Addr eaddr; 1206 Dwarf_Addr eaddr;
752 Dwarf_Die die_mem;
753 const char *name; 1207 const char *name;
754 int ret, i;
755 Dwarf_Attribute fb_attr;
756 size_t nops;
757
758 if (pf->ntevs == pf->max_tevs) {
759 pr_warning("Too many( > %d) probe point found.\n",
760 pf->max_tevs);
761 return -ERANGE;
762 }
763 tev = &pf->tevs[pf->ntevs++];
764
765 /* If no real subprogram, find a real one */
766 if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) {
767 sp_die = die_find_real_subprogram(&pf->cu_die,
768 pf->addr, &die_mem);
769 if (!sp_die) {
770 pr_warning("Failed to find probe point in any "
771 "functions.\n");
772 return -ENOENT;
773 }
774 }
775 1208
776 /* Copy the name of probe point */ 1209 /* Copy the name of probe point */
777 name = dwarf_diename(sp_die); 1210 name = dwarf_diename(sp_die);
778 if (name) { 1211 if (name) {
779 if (dwarf_entrypc(sp_die, &eaddr) != 0) { 1212 if (dwarf_entrypc(sp_die, &eaddr) != 0) {
780 pr_warning("Failed to get entry pc of %s\n", 1213 pr_warning("Failed to get entry address of %s\n",
781 dwarf_diename(sp_die)); 1214 dwarf_diename(sp_die));
782 return -ENOENT; 1215 return -ENOENT;
783 } 1216 }
784 tev->point.symbol = strdup(name); 1217 tp->symbol = strdup(name);
785 if (tev->point.symbol == NULL) 1218 if (tp->symbol == NULL)
786 return -ENOMEM; 1219 return -ENOMEM;
787 tev->point.offset = (unsigned long)(pf->addr - eaddr); 1220 tp->offset = (unsigned long)(paddr - eaddr);
788 } else 1221 } else
789 /* This function has no name. */ 1222 /* This function has no name. */
790 tev->point.offset = (unsigned long)pf->addr; 1223 tp->offset = (unsigned long)paddr;
791 1224
792 /* Return probe must be on the head of a subprogram */ 1225 /* Return probe must be on the head of a subprogram */
793 if (pf->pev->point.retprobe) { 1226 if (retprobe) {
794 if (tev->point.offset != 0) { 1227 if (eaddr != paddr) {
795 pr_warning("Return probe must be on the head of" 1228 pr_warning("Return probe must be on the head of"
796 " a real function\n"); 1229 " a real function.\n");
797 return -EINVAL; 1230 return -EINVAL;
798 } 1231 }
799 tev->point.retprobe = true; 1232 tp->retprobe = true;
800 } 1233 }
801 1234
802 pr_debug("Probe point found: %s+%lu\n", tev->point.symbol, 1235 return 0;
803 tev->point.offset); 1236}
1237
1238/* Call probe_finder callback with real subprogram DIE */
1239static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf)
1240{
1241 Dwarf_Die die_mem;
1242 Dwarf_Attribute fb_attr;
1243 size_t nops;
1244 int ret;
1245
1246 /* If no real subprogram, find a real one */
1247 if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) {
1248 sp_die = die_find_real_subprogram(&pf->cu_die,
1249 pf->addr, &die_mem);
1250 if (!sp_die) {
1251 pr_warning("Failed to find probe point in any "
1252 "functions.\n");
1253 return -ENOENT;
1254 }
1255 }
804 1256
805 /* Get the frame base attribute/ops */ 1257 /* Get the frame base attribute/ops */
806 dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr); 1258 dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr);
@@ -813,182 +1265,118 @@ static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
813 Dwarf_Frame *frame; 1265 Dwarf_Frame *frame;
814 if (dwarf_cfi_addrframe(pf->cfi, pf->addr, &frame) != 0 || 1266 if (dwarf_cfi_addrframe(pf->cfi, pf->addr, &frame) != 0 ||
815 dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) { 1267 dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) {
816 pr_warning("Failed to get CFA on 0x%jx\n", 1268 pr_warning("Failed to get call frame on 0x%jx\n",
817 (uintmax_t)pf->addr); 1269 (uintmax_t)pf->addr);
818 return -ENOENT; 1270 return -ENOENT;
819 } 1271 }
820#endif 1272#endif
821 } 1273 }
822 1274
823 /* Find each argument */ 1275 /* Call finder's callback handler */
824 tev->nargs = pf->pev->nargs; 1276 ret = pf->callback(sp_die, pf);
825 tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
826 if (tev->args == NULL)
827 return -ENOMEM;
828 for (i = 0; i < pf->pev->nargs; i++) {
829 pf->pvar = &pf->pev->args[i];
830 pf->tvar = &tev->args[i];
831 ret = find_variable(sp_die, pf);
832 if (ret != 0)
833 return ret;
834 }
835 1277
836 /* *pf->fb_ops will be cached in libdw. Don't free it. */ 1278 /* *pf->fb_ops will be cached in libdw. Don't free it. */
837 pf->fb_ops = NULL; 1279 pf->fb_ops = NULL;
838 return 0; 1280
1281 return ret;
839} 1282}
840 1283
841/* Find probe point from its line number */ 1284static int probe_point_line_walker(const char *fname, int lineno,
842static int find_probe_point_by_line(struct probe_finder *pf) 1285 Dwarf_Addr addr, void *data)
843{ 1286{
844 Dwarf_Lines *lines; 1287 struct probe_finder *pf = data;
845 Dwarf_Line *line; 1288 int ret;
846 size_t nlines, i;
847 Dwarf_Addr addr;
848 int lineno;
849 int ret = 0;
850
851 if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) {
852 pr_warning("No source lines found in this CU.\n");
853 return -ENOENT;
854 }
855 1289
856 for (i = 0; i < nlines && ret == 0; i++) { 1290 if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0)
857 line = dwarf_onesrcline(lines, i); 1291 return 0;
858 if (dwarf_lineno(line, &lineno) != 0 ||
859 lineno != pf->lno)
860 continue;
861 1292
862 /* TODO: Get fileno from line, but how? */ 1293 pf->addr = addr;
863 if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0) 1294 ret = call_probe_finder(NULL, pf);
864 continue;
865 1295
866 if (dwarf_lineaddr(line, &addr) != 0) { 1296 /* Continue if no error, because the line will be in inline function */
867 pr_warning("Failed to get the address of the line.\n"); 1297 return ret < 0 ? ret : 0;
868 return -ENOENT; 1298}
869 }
870 pr_debug("Probe line found: line[%d]:%d addr:0x%jx\n",
871 (int)i, lineno, (uintmax_t)addr);
872 pf->addr = addr;
873 1299
874 ret = convert_probe_point(NULL, pf); 1300/* Find probe point from its line number */
875 /* Continuing, because target line might be inlined. */ 1301static int find_probe_point_by_line(struct probe_finder *pf)
876 } 1302{
877 return ret; 1303 return die_walk_lines(&pf->cu_die, probe_point_line_walker, pf);
878} 1304}
879 1305
880/* Find lines which match lazy pattern */ 1306/* Find lines which match lazy pattern */
881static int find_lazy_match_lines(struct list_head *head, 1307static int find_lazy_match_lines(struct list_head *head,
882 const char *fname, const char *pat) 1308 const char *fname, const char *pat)
883{ 1309{
884 char *fbuf, *p1, *p2; 1310 FILE *fp;
885 int fd, line, nlines = -1; 1311 char *line = NULL;
886 struct stat st; 1312 size_t line_len;
887 1313 ssize_t len;
888 fd = open(fname, O_RDONLY); 1314 int count = 0, linenum = 1;
889 if (fd < 0) { 1315
890 pr_warning("Failed to open %s: %s\n", fname, strerror(-fd)); 1316 fp = fopen(fname, "r");
1317 if (!fp) {
1318 pr_warning("Failed to open %s: %s\n", fname, strerror(errno));
891 return -errno; 1319 return -errno;
892 } 1320 }
893 1321
894 if (fstat(fd, &st) < 0) { 1322 while ((len = getline(&line, &line_len, fp)) > 0) {
895 pr_warning("Failed to get the size of %s: %s\n", 1323
896 fname, strerror(errno)); 1324 if (line[len - 1] == '\n')
897 nlines = -errno; 1325 line[len - 1] = '\0';
898 goto out_close; 1326
899 } 1327 if (strlazymatch(line, pat)) {
900 1328 line_list__add_line(head, linenum);
901 nlines = -ENOMEM; 1329 count++;
902 fbuf = malloc(st.st_size + 2);
903 if (fbuf == NULL)
904 goto out_close;
905 if (read(fd, fbuf, st.st_size) < 0) {
906 pr_warning("Failed to read %s: %s\n", fname, strerror(errno));
907 nlines = -errno;
908 goto out_free_fbuf;
909 }
910 fbuf[st.st_size] = '\n'; /* Dummy line */
911 fbuf[st.st_size + 1] = '\0';
912 p1 = fbuf;
913 line = 1;
914 nlines = 0;
915 while ((p2 = strchr(p1, '\n')) != NULL) {
916 *p2 = '\0';
917 if (strlazymatch(p1, pat)) {
918 line_list__add_line(head, line);
919 nlines++;
920 } 1330 }
921 line++; 1331 linenum++;
922 p1 = p2 + 1;
923 } 1332 }
924out_free_fbuf: 1333
925 free(fbuf); 1334 if (ferror(fp))
926out_close: 1335 count = -errno;
927 close(fd); 1336 free(line);
928 return nlines; 1337 fclose(fp);
1338
1339 if (count == 0)
1340 pr_debug("No matched lines found in %s.\n", fname);
1341 return count;
1342}
1343
1344static int probe_point_lazy_walker(const char *fname, int lineno,
1345 Dwarf_Addr addr, void *data)
1346{
1347 struct probe_finder *pf = data;
1348 int ret;
1349
1350 if (!line_list__has_line(&pf->lcache, lineno) ||
1351 strtailcmp(fname, pf->fname) != 0)
1352 return 0;
1353
1354 pr_debug("Probe line found: line:%d addr:0x%llx\n",
1355 lineno, (unsigned long long)addr);
1356 pf->addr = addr;
1357 ret = call_probe_finder(NULL, pf);
1358
1359 /*
1360 * Continue if no error, because the lazy pattern will match
1361 * to other lines
1362 */
1363 return ret < 0 ? ret : 0;
929} 1364}
930 1365
931/* Find probe points from lazy pattern */ 1366/* Find probe points from lazy pattern */
932static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) 1367static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
933{ 1368{
934 Dwarf_Lines *lines;
935 Dwarf_Line *line;
936 size_t nlines, i;
937 Dwarf_Addr addr;
938 Dwarf_Die die_mem;
939 int lineno;
940 int ret = 0; 1369 int ret = 0;
941 1370
942 if (list_empty(&pf->lcache)) { 1371 if (list_empty(&pf->lcache)) {
943 /* Matching lazy line pattern */ 1372 /* Matching lazy line pattern */
944 ret = find_lazy_match_lines(&pf->lcache, pf->fname, 1373 ret = find_lazy_match_lines(&pf->lcache, pf->fname,
945 pf->pev->point.lazy_line); 1374 pf->pev->point.lazy_line);
946 if (ret == 0) { 1375 if (ret <= 0)
947 pr_debug("No matched lines found in %s.\n", pf->fname);
948 return 0;
949 } else if (ret < 0)
950 return ret; 1376 return ret;
951 } 1377 }
952 1378
953 if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) { 1379 return die_walk_lines(sp_die, probe_point_lazy_walker, pf);
954 pr_warning("No source lines found in this CU.\n");
955 return -ENOENT;
956 }
957
958 for (i = 0; i < nlines && ret >= 0; i++) {
959 line = dwarf_onesrcline(lines, i);
960
961 if (dwarf_lineno(line, &lineno) != 0 ||
962 !line_list__has_line(&pf->lcache, lineno))
963 continue;
964
965 /* TODO: Get fileno from line, but how? */
966 if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
967 continue;
968
969 if (dwarf_lineaddr(line, &addr) != 0) {
970 pr_debug("Failed to get the address of line %d.\n",
971 lineno);
972 continue;
973 }
974 if (sp_die) {
975 /* Address filtering 1: does sp_die include addr? */
976 if (!dwarf_haspc(sp_die, addr))
977 continue;
978 /* Address filtering 2: No child include addr? */
979 if (die_find_inlinefunc(sp_die, addr, &die_mem))
980 continue;
981 }
982
983 pr_debug("Probe line found: line[%d]:%d addr:0x%llx\n",
984 (int)i, lineno, (unsigned long long)addr);
985 pf->addr = addr;
986
987 ret = convert_probe_point(sp_die, pf);
988 /* Continuing, because target line might be inlined. */
989 }
990 /* TODO: deallocate lines, but how? */
991 return ret;
992} 1380}
993 1381
994/* Callback parameter with return value */ 1382/* Callback parameter with return value */
@@ -1009,7 +1397,7 @@ static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
1009 else { 1397 else {
1010 /* Get probe address */ 1398 /* Get probe address */
1011 if (dwarf_entrypc(in_die, &addr) != 0) { 1399 if (dwarf_entrypc(in_die, &addr) != 0) {
1012 pr_warning("Failed to get entry pc of %s.\n", 1400 pr_warning("Failed to get entry address of %s.\n",
1013 dwarf_diename(in_die)); 1401 dwarf_diename(in_die));
1014 param->retval = -ENOENT; 1402 param->retval = -ENOENT;
1015 return DWARF_CB_ABORT; 1403 return DWARF_CB_ABORT;
@@ -1019,7 +1407,7 @@ static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
1019 pr_debug("found inline addr: 0x%jx\n", 1407 pr_debug("found inline addr: 0x%jx\n",
1020 (uintmax_t)pf->addr); 1408 (uintmax_t)pf->addr);
1021 1409
1022 param->retval = convert_probe_point(in_die, pf); 1410 param->retval = call_probe_finder(in_die, pf);
1023 if (param->retval < 0) 1411 if (param->retval < 0)
1024 return DWARF_CB_ABORT; 1412 return DWARF_CB_ABORT;
1025 } 1413 }
@@ -1039,6 +1427,10 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
1039 !die_compare_name(sp_die, pp->function)) 1427 !die_compare_name(sp_die, pp->function))
1040 return DWARF_CB_OK; 1428 return DWARF_CB_OK;
1041 1429
1430 /* Check declared file */
1431 if (pp->file && strtailcmp(pp->file, dwarf_decl_file(sp_die)))
1432 return DWARF_CB_OK;
1433
1042 pf->fname = dwarf_decl_file(sp_die); 1434 pf->fname = dwarf_decl_file(sp_die);
1043 if (pp->line) { /* Function relative line */ 1435 if (pp->line) { /* Function relative line */
1044 dwarf_decl_line(sp_die, &pf->lno); 1436 dwarf_decl_line(sp_die, &pf->lno);
@@ -1050,14 +1442,14 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
1050 param->retval = find_probe_point_lazy(sp_die, pf); 1442 param->retval = find_probe_point_lazy(sp_die, pf);
1051 else { 1443 else {
1052 if (dwarf_entrypc(sp_die, &pf->addr) != 0) { 1444 if (dwarf_entrypc(sp_die, &pf->addr) != 0) {
1053 pr_warning("Failed to get entry pc of %s.\n", 1445 pr_warning("Failed to get entry address of "
1054 dwarf_diename(sp_die)); 1446 "%s.\n", dwarf_diename(sp_die));
1055 param->retval = -ENOENT; 1447 param->retval = -ENOENT;
1056 return DWARF_CB_ABORT; 1448 return DWARF_CB_ABORT;
1057 } 1449 }
1058 pf->addr += pp->offset; 1450 pf->addr += pp->offset;
1059 /* TODO: Check the address in this function */ 1451 /* TODO: Check the address in this function */
1060 param->retval = convert_probe_point(sp_die, pf); 1452 param->retval = call_probe_finder(sp_die, pf);
1061 } 1453 }
1062 } else { 1454 } else {
1063 struct dwarf_callback_param _param = {.data = (void *)pf, 1455 struct dwarf_callback_param _param = {.data = (void *)pf,
@@ -1079,155 +1471,410 @@ static int find_probe_point_by_func(struct probe_finder *pf)
1079 return _param.retval; 1471 return _param.retval;
1080} 1472}
1081 1473
1082/* Find probe_trace_events specified by perf_probe_event from debuginfo */ 1474struct pubname_callback_param {
1083int find_probe_trace_events(int fd, struct perf_probe_event *pev, 1475 char *function;
1084 struct probe_trace_event **tevs, int max_tevs) 1476 char *file;
1477 Dwarf_Die *cu_die;
1478 Dwarf_Die *sp_die;
1479 int found;
1480};
1481
1482static int pubname_search_cb(Dwarf *dbg, Dwarf_Global *gl, void *data)
1483{
1484 struct pubname_callback_param *param = data;
1485
1486 if (dwarf_offdie(dbg, gl->die_offset, param->sp_die)) {
1487 if (dwarf_tag(param->sp_die) != DW_TAG_subprogram)
1488 return DWARF_CB_OK;
1489
1490 if (die_compare_name(param->sp_die, param->function)) {
1491 if (!dwarf_offdie(dbg, gl->cu_offset, param->cu_die))
1492 return DWARF_CB_OK;
1493
1494 if (param->file &&
1495 strtailcmp(param->file, dwarf_decl_file(param->sp_die)))
1496 return DWARF_CB_OK;
1497
1498 param->found = 1;
1499 return DWARF_CB_ABORT;
1500 }
1501 }
1502
1503 return DWARF_CB_OK;
1504}
1505
1506/* Find probe points from debuginfo */
1507static int find_probes(int fd, struct probe_finder *pf)
1085{ 1508{
1086 struct probe_finder pf = {.pev = pev, .max_tevs = max_tevs}; 1509 struct perf_probe_point *pp = &pf->pev->point;
1087 struct perf_probe_point *pp = &pev->point;
1088 Dwarf_Off off, noff; 1510 Dwarf_Off off, noff;
1089 size_t cuhl; 1511 size_t cuhl;
1090 Dwarf_Die *diep; 1512 Dwarf_Die *diep;
1091 Dwarf *dbg; 1513 Dwarf *dbg = NULL;
1514 Dwfl *dwfl;
1515 Dwarf_Addr bias; /* Currently ignored */
1092 int ret = 0; 1516 int ret = 0;
1093 1517
1094 pf.tevs = zalloc(sizeof(struct probe_trace_event) * max_tevs); 1518 dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias);
1095 if (pf.tevs == NULL)
1096 return -ENOMEM;
1097 *tevs = pf.tevs;
1098 pf.ntevs = 0;
1099
1100 dbg = dwarf_begin(fd, DWARF_C_READ);
1101 if (!dbg) { 1519 if (!dbg) {
1102 pr_warning("No dwarf info found in the vmlinux - " 1520 pr_warning("No debug information found in the vmlinux - "
1103 "please rebuild with CONFIG_DEBUG_INFO=y.\n"); 1521 "please rebuild with CONFIG_DEBUG_INFO=y.\n");
1104 free(pf.tevs); 1522 close(fd); /* Without dwfl_end(), fd isn't closed. */
1105 *tevs = NULL;
1106 return -EBADF; 1523 return -EBADF;
1107 } 1524 }
1108 1525
1109#if _ELFUTILS_PREREQ(0, 142) 1526#if _ELFUTILS_PREREQ(0, 142)
1110 /* Get the call frame information from this dwarf */ 1527 /* Get the call frame information from this dwarf */
1111 pf.cfi = dwarf_getcfi(dbg); 1528 pf->cfi = dwarf_getcfi(dbg);
1112#endif 1529#endif
1113 1530
1114 off = 0; 1531 off = 0;
1115 line_list__init(&pf.lcache); 1532 line_list__init(&pf->lcache);
1533
1534 /* Fastpath: lookup by function name from .debug_pubnames section */
1535 if (pp->function) {
1536 struct pubname_callback_param pubname_param = {
1537 .function = pp->function,
1538 .file = pp->file,
1539 .cu_die = &pf->cu_die,
1540 .sp_die = &pf->sp_die,
1541 .found = 0,
1542 };
1543 struct dwarf_callback_param probe_param = {
1544 .data = pf,
1545 };
1546
1547 dwarf_getpubnames(dbg, pubname_search_cb, &pubname_param, 0);
1548 if (pubname_param.found) {
1549 ret = probe_point_search_cb(&pf->sp_die, &probe_param);
1550 if (ret)
1551 goto found;
1552 }
1553 }
1554
1116 /* Loop on CUs (Compilation Unit) */ 1555 /* Loop on CUs (Compilation Unit) */
1117 while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) && 1556 while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL)) {
1118 ret >= 0) {
1119 /* Get the DIE(Debugging Information Entry) of this CU */ 1557 /* Get the DIE(Debugging Information Entry) of this CU */
1120 diep = dwarf_offdie(dbg, off + cuhl, &pf.cu_die); 1558 diep = dwarf_offdie(dbg, off + cuhl, &pf->cu_die);
1121 if (!diep) 1559 if (!diep)
1122 continue; 1560 continue;
1123 1561
1124 /* Check if target file is included. */ 1562 /* Check if target file is included. */
1125 if (pp->file) 1563 if (pp->file)
1126 pf.fname = cu_find_realpath(&pf.cu_die, pp->file); 1564 pf->fname = cu_find_realpath(&pf->cu_die, pp->file);
1127 else 1565 else
1128 pf.fname = NULL; 1566 pf->fname = NULL;
1129 1567
1130 if (!pp->file || pf.fname) { 1568 if (!pp->file || pf->fname) {
1131 if (pp->function) 1569 if (pp->function)
1132 ret = find_probe_point_by_func(&pf); 1570 ret = find_probe_point_by_func(pf);
1133 else if (pp->lazy_line) 1571 else if (pp->lazy_line)
1134 ret = find_probe_point_lazy(NULL, &pf); 1572 ret = find_probe_point_lazy(NULL, pf);
1135 else { 1573 else {
1136 pf.lno = pp->line; 1574 pf->lno = pp->line;
1137 ret = find_probe_point_by_line(&pf); 1575 ret = find_probe_point_by_line(pf);
1138 } 1576 }
1577 if (ret < 0)
1578 break;
1139 } 1579 }
1140 off = noff; 1580 off = noff;
1141 } 1581 }
1142 line_list__free(&pf.lcache);
1143 dwarf_end(dbg);
1144 1582
1145 return (ret < 0) ? ret : pf.ntevs; 1583found:
1584 line_list__free(&pf->lcache);
1585 if (dwfl)
1586 dwfl_end(dwfl);
1587
1588 return ret;
1589}
1590
1591/* Add a found probe point into trace event list */
1592static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf)
1593{
1594 struct trace_event_finder *tf =
1595 container_of(pf, struct trace_event_finder, pf);
1596 struct probe_trace_event *tev;
1597 int ret, i;
1598
1599 /* Check number of tevs */
1600 if (tf->ntevs == tf->max_tevs) {
1601 pr_warning("Too many( > %d) probe point found.\n",
1602 tf->max_tevs);
1603 return -ERANGE;
1604 }
1605 tev = &tf->tevs[tf->ntevs++];
1606
1607 ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe,
1608 &tev->point);
1609 if (ret < 0)
1610 return ret;
1611
1612 pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,
1613 tev->point.offset);
1614
1615 /* Find each argument */
1616 tev->nargs = pf->pev->nargs;
1617 tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
1618 if (tev->args == NULL)
1619 return -ENOMEM;
1620 for (i = 0; i < pf->pev->nargs; i++) {
1621 pf->pvar = &pf->pev->args[i];
1622 pf->tvar = &tev->args[i];
1623 ret = find_variable(sp_die, pf);
1624 if (ret != 0)
1625 return ret;
1626 }
1627
1628 return 0;
1629}
1630
1631/* Find probe_trace_events specified by perf_probe_event from debuginfo */
1632int find_probe_trace_events(int fd, struct perf_probe_event *pev,
1633 struct probe_trace_event **tevs, int max_tevs)
1634{
1635 struct trace_event_finder tf = {
1636 .pf = {.pev = pev, .callback = add_probe_trace_event},
1637 .max_tevs = max_tevs};
1638 int ret;
1639
1640 /* Allocate result tevs array */
1641 *tevs = zalloc(sizeof(struct probe_trace_event) * max_tevs);
1642 if (*tevs == NULL)
1643 return -ENOMEM;
1644
1645 tf.tevs = *tevs;
1646 tf.ntevs = 0;
1647
1648 ret = find_probes(fd, &tf.pf);
1649 if (ret < 0) {
1650 free(*tevs);
1651 *tevs = NULL;
1652 return ret;
1653 }
1654
1655 return (ret < 0) ? ret : tf.ntevs;
1656}
1657
1658#define MAX_VAR_LEN 64
1659
1660/* Collect available variables in this scope */
1661static int collect_variables_cb(Dwarf_Die *die_mem, void *data)
1662{
1663 struct available_var_finder *af = data;
1664 struct variable_list *vl;
1665 char buf[MAX_VAR_LEN];
1666 int tag, ret;
1667
1668 vl = &af->vls[af->nvls - 1];
1669
1670 tag = dwarf_tag(die_mem);
1671 if (tag == DW_TAG_formal_parameter ||
1672 tag == DW_TAG_variable) {
1673 ret = convert_variable_location(die_mem, af->pf.addr,
1674 af->pf.fb_ops, NULL);
1675 if (ret == 0) {
1676 ret = die_get_varname(die_mem, buf, MAX_VAR_LEN);
1677 pr_debug2("Add new var: %s\n", buf);
1678 if (ret > 0)
1679 strlist__add(vl->vars, buf);
1680 }
1681 }
1682
1683 if (af->child && dwarf_haspc(die_mem, af->pf.addr))
1684 return DIE_FIND_CB_CONTINUE;
1685 else
1686 return DIE_FIND_CB_SIBLING;
1687}
1688
1689/* Add a found vars into available variables list */
1690static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf)
1691{
1692 struct available_var_finder *af =
1693 container_of(pf, struct available_var_finder, pf);
1694 struct variable_list *vl;
1695 Dwarf_Die die_mem, *scopes = NULL;
1696 int ret, nscopes;
1697
1698 /* Check number of tevs */
1699 if (af->nvls == af->max_vls) {
1700 pr_warning("Too many( > %d) probe point found.\n", af->max_vls);
1701 return -ERANGE;
1702 }
1703 vl = &af->vls[af->nvls++];
1704
1705 ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe,
1706 &vl->point);
1707 if (ret < 0)
1708 return ret;
1709
1710 pr_debug("Probe point found: %s+%lu\n", vl->point.symbol,
1711 vl->point.offset);
1712
1713 /* Find local variables */
1714 vl->vars = strlist__new(true, NULL);
1715 if (vl->vars == NULL)
1716 return -ENOMEM;
1717 af->child = true;
1718 die_find_child(sp_die, collect_variables_cb, (void *)af, &die_mem);
1719
1720 /* Find external variables */
1721 if (!af->externs)
1722 goto out;
1723 /* Don't need to search child DIE for externs. */
1724 af->child = false;
1725 nscopes = dwarf_getscopes_die(sp_die, &scopes);
1726 while (nscopes-- > 1)
1727 die_find_child(&scopes[nscopes], collect_variables_cb,
1728 (void *)af, &die_mem);
1729 if (scopes)
1730 free(scopes);
1731
1732out:
1733 if (strlist__empty(vl->vars)) {
1734 strlist__delete(vl->vars);
1735 vl->vars = NULL;
1736 }
1737
1738 return ret;
1739}
1740
1741/* Find available variables at given probe point */
1742int find_available_vars_at(int fd, struct perf_probe_event *pev,
1743 struct variable_list **vls, int max_vls,
1744 bool externs)
1745{
1746 struct available_var_finder af = {
1747 .pf = {.pev = pev, .callback = add_available_vars},
1748 .max_vls = max_vls, .externs = externs};
1749 int ret;
1750
1751 /* Allocate result vls array */
1752 *vls = zalloc(sizeof(struct variable_list) * max_vls);
1753 if (*vls == NULL)
1754 return -ENOMEM;
1755
1756 af.vls = *vls;
1757 af.nvls = 0;
1758
1759 ret = find_probes(fd, &af.pf);
1760 if (ret < 0) {
1761 /* Free vlist for error */
1762 while (af.nvls--) {
1763 if (af.vls[af.nvls].point.symbol)
1764 free(af.vls[af.nvls].point.symbol);
1765 if (af.vls[af.nvls].vars)
1766 strlist__delete(af.vls[af.nvls].vars);
1767 }
1768 free(af.vls);
1769 *vls = NULL;
1770 return ret;
1771 }
1772
1773 return (ret < 0) ? ret : af.nvls;
1146} 1774}
1147 1775
1148/* Reverse search */ 1776/* Reverse search */
1149int find_perf_probe_point(int fd, unsigned long addr, 1777int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt)
1150 struct perf_probe_point *ppt)
1151{ 1778{
1152 Dwarf_Die cudie, spdie, indie; 1779 Dwarf_Die cudie, spdie, indie;
1153 Dwarf *dbg; 1780 Dwarf *dbg = NULL;
1154 Dwarf_Line *line; 1781 Dwfl *dwfl = NULL;
1155 Dwarf_Addr laddr, eaddr; 1782 Dwarf_Addr _addr, baseaddr, bias = 0;
1156 const char *tmp; 1783 const char *fname = NULL, *func = NULL, *tmp;
1157 int lineno, ret = 0; 1784 int baseline = 0, lineno = 0, ret = 0;
1158 bool found = false; 1785
1159 1786 /* Open the live linux kernel */
1160 dbg = dwarf_begin(fd, DWARF_C_READ); 1787 dbg = dwfl_init_live_kernel_dwarf(addr, &dwfl, &bias);
1161 if (!dbg) 1788 if (!dbg) {
1162 return -EBADF; 1789 pr_warning("No debug information found in the vmlinux - "
1790 "please rebuild with CONFIG_DEBUG_INFO=y.\n");
1791 ret = -EINVAL;
1792 goto end;
1793 }
1163 1794
1795 /* Adjust address with bias */
1796 addr += bias;
1164 /* Find cu die */ 1797 /* Find cu die */
1165 if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr, &cudie)) { 1798 if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr - bias, &cudie)) {
1799 pr_warning("Failed to find debug information for address %lx\n",
1800 addr);
1166 ret = -EINVAL; 1801 ret = -EINVAL;
1167 goto end; 1802 goto end;
1168 } 1803 }
1169 1804
1170 /* Find a corresponding line */ 1805 /* Find a corresponding line (filename and lineno) */
1171 line = dwarf_getsrc_die(&cudie, (Dwarf_Addr)addr); 1806 cu_find_lineinfo(&cudie, addr, &fname, &lineno);
1172 if (line) { 1807 /* Don't care whether it failed or not */
1173 if (dwarf_lineaddr(line, &laddr) == 0 &&
1174 (Dwarf_Addr)addr == laddr &&
1175 dwarf_lineno(line, &lineno) == 0) {
1176 tmp = dwarf_linesrc(line, NULL, NULL);
1177 if (tmp) {
1178 ppt->line = lineno;
1179 ppt->file = strdup(tmp);
1180 if (ppt->file == NULL) {
1181 ret = -ENOMEM;
1182 goto end;
1183 }
1184 found = true;
1185 }
1186 }
1187 }
1188 1808
1189 /* Find a corresponding function */ 1809 /* Find a corresponding function (name, baseline and baseaddr) */
1190 if (die_find_real_subprogram(&cudie, (Dwarf_Addr)addr, &spdie)) { 1810 if (die_find_real_subprogram(&cudie, (Dwarf_Addr)addr, &spdie)) {
1811 /* Get function entry information */
1191 tmp = dwarf_diename(&spdie); 1812 tmp = dwarf_diename(&spdie);
1192 if (!tmp || dwarf_entrypc(&spdie, &eaddr) != 0) 1813 if (!tmp ||
1193 goto end; 1814 dwarf_entrypc(&spdie, &baseaddr) != 0 ||
1194 1815 dwarf_decl_line(&spdie, &baseline) != 0)
1195 if (ppt->line) { 1816 goto post;
1196 if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr, 1817 func = tmp;
1197 &indie)) { 1818
1198 /* addr in an inline function */ 1819 if (addr == (unsigned long)baseaddr)
1820 /* Function entry - Relative line number is 0 */
1821 lineno = baseline;
1822 else if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr,
1823 &indie)) {
1824 if (dwarf_entrypc(&indie, &_addr) == 0 &&
1825 _addr == addr)
1826 /*
1827 * addr is at an inline function entry.
1828 * In this case, lineno should be the call-site
1829 * line number.
1830 */
1831 lineno = die_get_call_lineno(&indie);
1832 else {
1833 /*
1834 * addr is in an inline function body.
1835 * Since lineno points one of the lines
1836 * of the inline function, baseline should
1837 * be the entry line of the inline function.
1838 */
1199 tmp = dwarf_diename(&indie); 1839 tmp = dwarf_diename(&indie);
1200 if (!tmp) 1840 if (tmp &&
1201 goto end; 1841 dwarf_decl_line(&spdie, &baseline) == 0)
1202 ret = dwarf_decl_line(&indie, &lineno); 1842 func = tmp;
1203 } else {
1204 if (eaddr == addr) { /* Function entry */
1205 lineno = ppt->line;
1206 ret = 0;
1207 } else
1208 ret = dwarf_decl_line(&spdie, &lineno);
1209 }
1210 if (ret == 0) {
1211 /* Make a relative line number */
1212 ppt->line -= lineno;
1213 goto found;
1214 } 1843 }
1215 } 1844 }
1216 /* We don't have a line number, let's use offset */ 1845 }
1217 ppt->offset = addr - (unsigned long)eaddr; 1846
1218found: 1847post:
1219 ppt->function = strdup(tmp); 1848 /* Make a relative line number or an offset */
1849 if (lineno)
1850 ppt->line = lineno - baseline;
1851 else if (func)
1852 ppt->offset = addr - (unsigned long)baseaddr;
1853
1854 /* Duplicate strings */
1855 if (func) {
1856 ppt->function = strdup(func);
1220 if (ppt->function == NULL) { 1857 if (ppt->function == NULL) {
1221 ret = -ENOMEM; 1858 ret = -ENOMEM;
1222 goto end; 1859 goto end;
1223 } 1860 }
1224 found = true;
1225 } 1861 }
1226 1862 if (fname) {
1863 ppt->file = strdup(fname);
1864 if (ppt->file == NULL) {
1865 if (ppt->function) {
1866 free(ppt->function);
1867 ppt->function = NULL;
1868 }
1869 ret = -ENOMEM;
1870 goto end;
1871 }
1872 }
1227end: 1873end:
1228 dwarf_end(dbg); 1874 if (dwfl)
1229 if (ret >= 0) 1875 dwfl_end(dwfl);
1230 ret = found ? 1 : 0; 1876 if (ret == 0 && (fname || func))
1877 ret = 1; /* Found a point */
1231 return ret; 1878 return ret;
1232} 1879}
1233 1880
@@ -1244,91 +1891,28 @@ static int line_range_add_line(const char *src, unsigned int lineno,
1244 return line_list__add_line(&lr->line_list, lineno); 1891 return line_list__add_line(&lr->line_list, lineno);
1245} 1892}
1246 1893
1247/* Search function declaration lines */ 1894static int line_range_walk_cb(const char *fname, int lineno,
1248static int line_range_funcdecl_cb(Dwarf_Die *sp_die, void *data) 1895 Dwarf_Addr addr __used,
1896 void *data)
1249{ 1897{
1250 struct dwarf_callback_param *param = data; 1898 struct line_finder *lf = data;
1251 struct line_finder *lf = param->data;
1252 const char *src;
1253 int lineno;
1254 1899
1255 src = dwarf_decl_file(sp_die); 1900 if ((strtailcmp(fname, lf->fname) != 0) ||
1256 if (src && strtailcmp(src, lf->fname) != 0)
1257 return DWARF_CB_OK;
1258
1259 if (dwarf_decl_line(sp_die, &lineno) != 0 ||
1260 (lf->lno_s > lineno || lf->lno_e < lineno)) 1901 (lf->lno_s > lineno || lf->lno_e < lineno))
1261 return DWARF_CB_OK; 1902 return 0;
1262 1903
1263 param->retval = line_range_add_line(src, lineno, lf->lr); 1904 if (line_range_add_line(fname, lineno, lf->lr) < 0)
1264 if (param->retval < 0) 1905 return -EINVAL;
1265 return DWARF_CB_ABORT;
1266 return DWARF_CB_OK;
1267}
1268 1906
1269static int find_line_range_func_decl_lines(struct line_finder *lf) 1907 return 0;
1270{
1271 struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0};
1272 dwarf_getfuncs(&lf->cu_die, line_range_funcdecl_cb, &param, 0);
1273 return param.retval;
1274} 1908}
1275 1909
1276/* Find line range from its line number */ 1910/* Find line range from its line number */
1277static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) 1911static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
1278{ 1912{
1279 Dwarf_Lines *lines; 1913 int ret;
1280 Dwarf_Line *line;
1281 size_t nlines, i;
1282 Dwarf_Addr addr;
1283 int lineno, ret = 0;
1284 const char *src;
1285 Dwarf_Die die_mem;
1286
1287 line_list__init(&lf->lr->line_list);
1288 if (dwarf_getsrclines(&lf->cu_die, &lines, &nlines) != 0) {
1289 pr_warning("No source lines found in this CU.\n");
1290 return -ENOENT;
1291 }
1292
1293 /* Search probable lines on lines list */
1294 for (i = 0; i < nlines; i++) {
1295 line = dwarf_onesrcline(lines, i);
1296 if (dwarf_lineno(line, &lineno) != 0 ||
1297 (lf->lno_s > lineno || lf->lno_e < lineno))
1298 continue;
1299
1300 if (sp_die) {
1301 /* Address filtering 1: does sp_die include addr? */
1302 if (dwarf_lineaddr(line, &addr) != 0 ||
1303 !dwarf_haspc(sp_die, addr))
1304 continue;
1305
1306 /* Address filtering 2: No child include addr? */
1307 if (die_find_inlinefunc(sp_die, addr, &die_mem))
1308 continue;
1309 }
1310
1311 /* TODO: Get fileno from line, but how? */
1312 src = dwarf_linesrc(line, NULL, NULL);
1313 if (strtailcmp(src, lf->fname) != 0)
1314 continue;
1315 1914
1316 ret = line_range_add_line(src, lineno, lf->lr); 1915 ret = die_walk_lines(sp_die ?: &lf->cu_die, line_range_walk_cb, lf);
1317 if (ret < 0)
1318 return ret;
1319 }
1320
1321 /*
1322 * Dwarf lines doesn't include function declarations. We have to
1323 * check functions list or given function.
1324 */
1325 if (sp_die) {
1326 src = dwarf_decl_file(sp_die);
1327 if (src && dwarf_decl_line(sp_die, &lineno) == 0 &&
1328 (lf->lno_s <= lineno && lf->lno_e >= lineno))
1329 ret = line_range_add_line(src, lineno, lf->lr);
1330 } else
1331 ret = find_line_range_func_decl_lines(lf);
1332 1916
1333 /* Update status */ 1917 /* Update status */
1334 if (ret >= 0) 1918 if (ret >= 0)
@@ -1358,6 +1942,10 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
1358 struct line_finder *lf = param->data; 1942 struct line_finder *lf = param->data;
1359 struct line_range *lr = lf->lr; 1943 struct line_range *lr = lf->lr;
1360 1944
1945 /* Check declared file */
1946 if (lr->file && strtailcmp(lr->file, dwarf_decl_file(sp_die)))
1947 return DWARF_CB_OK;
1948
1361 if (dwarf_tag(sp_die) == DW_TAG_subprogram && 1949 if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
1362 die_compare_name(sp_die, lr->function)) { 1950 die_compare_name(sp_die, lr->function)) {
1363 lf->fname = dwarf_decl_file(sp_die); 1951 lf->fname = dwarf_decl_file(sp_die);
@@ -1401,16 +1989,35 @@ int find_line_range(int fd, struct line_range *lr)
1401 Dwarf_Off off = 0, noff; 1989 Dwarf_Off off = 0, noff;
1402 size_t cuhl; 1990 size_t cuhl;
1403 Dwarf_Die *diep; 1991 Dwarf_Die *diep;
1404 Dwarf *dbg; 1992 Dwarf *dbg = NULL;
1993 Dwfl *dwfl;
1994 Dwarf_Addr bias; /* Currently ignored */
1405 const char *comp_dir; 1995 const char *comp_dir;
1406 1996
1407 dbg = dwarf_begin(fd, DWARF_C_READ); 1997 dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias);
1408 if (!dbg) { 1998 if (!dbg) {
1409 pr_warning("No dwarf info found in the vmlinux - " 1999 pr_warning("No debug information found in the vmlinux - "
1410 "please rebuild with CONFIG_DEBUG_INFO=y.\n"); 2000 "please rebuild with CONFIG_DEBUG_INFO=y.\n");
2001 close(fd); /* Without dwfl_end(), fd isn't closed. */
1411 return -EBADF; 2002 return -EBADF;
1412 } 2003 }
1413 2004
2005 /* Fastpath: lookup by function name from .debug_pubnames section */
2006 if (lr->function) {
2007 struct pubname_callback_param pubname_param = {
2008 .function = lr->function, .file = lr->file,
2009 .cu_die = &lf.cu_die, .sp_die = &lf.sp_die, .found = 0};
2010 struct dwarf_callback_param line_range_param = {
2011 .data = (void *)&lf, .retval = 0};
2012
2013 dwarf_getpubnames(dbg, pubname_search_cb, &pubname_param, 0);
2014 if (pubname_param.found) {
2015 line_range_search_cb(&lf.sp_die, &line_range_param);
2016 if (lf.found)
2017 goto found;
2018 }
2019 }
2020
1414 /* Loop on CUs (Compilation Unit) */ 2021 /* Loop on CUs (Compilation Unit) */
1415 while (!lf.found && ret >= 0) { 2022 while (!lf.found && ret >= 0) {
1416 if (dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) != 0) 2023 if (dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) != 0)
@@ -1439,6 +2046,7 @@ int find_line_range(int fd, struct line_range *lr)
1439 off = noff; 2046 off = noff;
1440 } 2047 }
1441 2048
2049found:
1442 /* Store comp_dir */ 2050 /* Store comp_dir */
1443 if (lf.found) { 2051 if (lf.found) {
1444 comp_dir = cu_get_comp_dir(&lf.cu_die); 2052 comp_dir = cu_get_comp_dir(&lf.cu_die);
@@ -1450,8 +2058,7 @@ int find_line_range(int fd, struct line_range *lr)
1450 } 2058 }
1451 2059
1452 pr_debug("path: %s\n", lr->path); 2060 pr_debug("path: %s\n", lr->path);
1453 dwarf_end(dbg); 2061 dwfl_end(dwfl);
1454
1455 return (ret < 0) ? ret : lf.found; 2062 return (ret < 0) ? ret : lf.found;
1456} 2063}
1457 2064
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index 4507d519f183..605730a366db 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -22,26 +22,34 @@ extern int find_probe_trace_events(int fd, struct perf_probe_event *pev,
22 int max_tevs); 22 int max_tevs);
23 23
24/* Find a perf_probe_point from debuginfo */ 24/* Find a perf_probe_point from debuginfo */
25extern int find_perf_probe_point(int fd, unsigned long addr, 25extern int find_perf_probe_point(unsigned long addr,
26 struct perf_probe_point *ppt); 26 struct perf_probe_point *ppt);
27 27
28/* Find a line range */
28extern int find_line_range(int fd, struct line_range *lr); 29extern int find_line_range(int fd, struct line_range *lr);
29 30
31/* Find available variables */
32extern int find_available_vars_at(int fd, struct perf_probe_event *pev,
33 struct variable_list **vls, int max_points,
34 bool externs);
35
30#include <dwarf.h> 36#include <dwarf.h>
31#include <libdw.h> 37#include <elfutils/libdw.h>
32#include <version.h> 38#include <elfutils/libdwfl.h>
39#include <elfutils/version.h>
33 40
34struct probe_finder { 41struct probe_finder {
35 struct perf_probe_event *pev; /* Target probe event */ 42 struct perf_probe_event *pev; /* Target probe event */
36 struct probe_trace_event *tevs; /* Result trace events */ 43
37 int ntevs; /* Number of trace events */ 44 /* Callback when a probe point is found */
38 int max_tevs; /* Max number of trace events */ 45 int (*callback)(Dwarf_Die *sp_die, struct probe_finder *pf);
39 46
40 /* For function searching */ 47 /* For function searching */
41 int lno; /* Line number */ 48 int lno; /* Line number */
42 Dwarf_Addr addr; /* Address */ 49 Dwarf_Addr addr; /* Address */
43 const char *fname; /* Real file name */ 50 const char *fname; /* Real file name */
44 Dwarf_Die cu_die; /* Current CU */ 51 Dwarf_Die cu_die; /* Current CU */
52 Dwarf_Die sp_die;
45 struct list_head lcache; /* Line cache for lazy match */ 53 struct list_head lcache; /* Line cache for lazy match */
46 54
47 /* For variable searching */ 55 /* For variable searching */
@@ -53,6 +61,22 @@ struct probe_finder {
53 struct probe_trace_arg *tvar; /* Current result variable */ 61 struct probe_trace_arg *tvar; /* Current result variable */
54}; 62};
55 63
64struct trace_event_finder {
65 struct probe_finder pf;
66 struct probe_trace_event *tevs; /* Found trace events */
67 int ntevs; /* Number of trace events */
68 int max_tevs; /* Max number of trace events */
69};
70
71struct available_var_finder {
72 struct probe_finder pf;
73 struct variable_list *vls; /* Found variable lists */
74 int nvls; /* Number of variable lists */
75 int max_vls; /* Max no. of variable lists */
76 bool externs; /* Find external vars too */
77 bool child; /* Search child scopes */
78};
79
56struct line_finder { 80struct line_finder {
57 struct line_range *lr; /* Target line range */ 81 struct line_range *lr; /* Target line range */
58 82
@@ -60,6 +84,7 @@ struct line_finder {
60 int lno_s; /* Start line number */ 84 int lno_s; /* Start line number */
61 int lno_e; /* End line number */ 85 int lno_e; /* End line number */
62 Dwarf_Die cu_die; /* Current CU */ 86 Dwarf_Die cu_die; /* Current CU */
87 Dwarf_Die sp_die;
63 int found; 88 int found;
64}; 89};
65 90
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
new file mode 100644
index 000000000000..a9ac0504aabd
--- /dev/null
+++ b/tools/perf/util/python.c
@@ -0,0 +1,905 @@
1#include <Python.h>
2#include <structmember.h>
3#include <inttypes.h>
4#include <poll.h>
5#include "evlist.h"
6#include "evsel.h"
7#include "event.h"
8#include "cpumap.h"
9#include "thread_map.h"
10
11/* Define PyVarObject_HEAD_INIT for python 2.5 */
12#ifndef PyVarObject_HEAD_INIT
13# define PyVarObject_HEAD_INIT(type, size) PyObject_HEAD_INIT(type) size,
14#endif
15
16struct throttle_event {
17 struct perf_event_header header;
18 u64 time;
19 u64 id;
20 u64 stream_id;
21};
22
23PyMODINIT_FUNC initperf(void);
24
25#define member_def(type, member, ptype, help) \
26 { #member, ptype, \
27 offsetof(struct pyrf_event, event) + offsetof(struct type, member), \
28 0, help }
29
30#define sample_member_def(name, member, ptype, help) \
31 { #name, ptype, \
32 offsetof(struct pyrf_event, sample) + offsetof(struct perf_sample, member), \
33 0, help }
34
35struct pyrf_event {
36 PyObject_HEAD
37 struct perf_sample sample;
38 union perf_event event;
39};
40
41#define sample_members \
42 sample_member_def(sample_ip, ip, T_ULONGLONG, "event type"), \
43 sample_member_def(sample_pid, pid, T_INT, "event pid"), \
44 sample_member_def(sample_tid, tid, T_INT, "event tid"), \
45 sample_member_def(sample_time, time, T_ULONGLONG, "event timestamp"), \
46 sample_member_def(sample_addr, addr, T_ULONGLONG, "event addr"), \
47 sample_member_def(sample_id, id, T_ULONGLONG, "event id"), \
48 sample_member_def(sample_stream_id, stream_id, T_ULONGLONG, "event stream id"), \
49 sample_member_def(sample_period, period, T_ULONGLONG, "event period"), \
50 sample_member_def(sample_cpu, cpu, T_UINT, "event cpu"),
51
52static char pyrf_mmap_event__doc[] = PyDoc_STR("perf mmap event object.");
53
54static PyMemberDef pyrf_mmap_event__members[] = {
55 sample_members
56 member_def(perf_event_header, type, T_UINT, "event type"),
57 member_def(mmap_event, pid, T_UINT, "event pid"),
58 member_def(mmap_event, tid, T_UINT, "event tid"),
59 member_def(mmap_event, start, T_ULONGLONG, "start of the map"),
60 member_def(mmap_event, len, T_ULONGLONG, "map length"),
61 member_def(mmap_event, pgoff, T_ULONGLONG, "page offset"),
62 member_def(mmap_event, filename, T_STRING_INPLACE, "backing store"),
63 { .name = NULL, },
64};
65
66static PyObject *pyrf_mmap_event__repr(struct pyrf_event *pevent)
67{
68 PyObject *ret;
69 char *s;
70
71 if (asprintf(&s, "{ type: mmap, pid: %u, tid: %u, start: %#" PRIx64 ", "
72 "length: %#" PRIx64 ", offset: %#" PRIx64 ", "
73 "filename: %s }",
74 pevent->event.mmap.pid, pevent->event.mmap.tid,
75 pevent->event.mmap.start, pevent->event.mmap.len,
76 pevent->event.mmap.pgoff, pevent->event.mmap.filename) < 0) {
77 ret = PyErr_NoMemory();
78 } else {
79 ret = PyString_FromString(s);
80 free(s);
81 }
82 return ret;
83}
84
85static PyTypeObject pyrf_mmap_event__type = {
86 PyVarObject_HEAD_INIT(NULL, 0)
87 .tp_name = "perf.mmap_event",
88 .tp_basicsize = sizeof(struct pyrf_event),
89 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
90 .tp_doc = pyrf_mmap_event__doc,
91 .tp_members = pyrf_mmap_event__members,
92 .tp_repr = (reprfunc)pyrf_mmap_event__repr,
93};
94
95static char pyrf_task_event__doc[] = PyDoc_STR("perf task (fork/exit) event object.");
96
97static PyMemberDef pyrf_task_event__members[] = {
98 sample_members
99 member_def(perf_event_header, type, T_UINT, "event type"),
100 member_def(fork_event, pid, T_UINT, "event pid"),
101 member_def(fork_event, ppid, T_UINT, "event ppid"),
102 member_def(fork_event, tid, T_UINT, "event tid"),
103 member_def(fork_event, ptid, T_UINT, "event ptid"),
104 member_def(fork_event, time, T_ULONGLONG, "timestamp"),
105 { .name = NULL, },
106};
107
108static PyObject *pyrf_task_event__repr(struct pyrf_event *pevent)
109{
110 return PyString_FromFormat("{ type: %s, pid: %u, ppid: %u, tid: %u, "
111 "ptid: %u, time: %" PRIu64 "}",
112 pevent->event.header.type == PERF_RECORD_FORK ? "fork" : "exit",
113 pevent->event.fork.pid,
114 pevent->event.fork.ppid,
115 pevent->event.fork.tid,
116 pevent->event.fork.ptid,
117 pevent->event.fork.time);
118}
119
120static PyTypeObject pyrf_task_event__type = {
121 PyVarObject_HEAD_INIT(NULL, 0)
122 .tp_name = "perf.task_event",
123 .tp_basicsize = sizeof(struct pyrf_event),
124 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
125 .tp_doc = pyrf_task_event__doc,
126 .tp_members = pyrf_task_event__members,
127 .tp_repr = (reprfunc)pyrf_task_event__repr,
128};
129
130static char pyrf_comm_event__doc[] = PyDoc_STR("perf comm event object.");
131
132static PyMemberDef pyrf_comm_event__members[] = {
133 sample_members
134 member_def(perf_event_header, type, T_UINT, "event type"),
135 member_def(comm_event, pid, T_UINT, "event pid"),
136 member_def(comm_event, tid, T_UINT, "event tid"),
137 member_def(comm_event, comm, T_STRING_INPLACE, "process name"),
138 { .name = NULL, },
139};
140
141static PyObject *pyrf_comm_event__repr(struct pyrf_event *pevent)
142{
143 return PyString_FromFormat("{ type: comm, pid: %u, tid: %u, comm: %s }",
144 pevent->event.comm.pid,
145 pevent->event.comm.tid,
146 pevent->event.comm.comm);
147}
148
149static PyTypeObject pyrf_comm_event__type = {
150 PyVarObject_HEAD_INIT(NULL, 0)
151 .tp_name = "perf.comm_event",
152 .tp_basicsize = sizeof(struct pyrf_event),
153 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
154 .tp_doc = pyrf_comm_event__doc,
155 .tp_members = pyrf_comm_event__members,
156 .tp_repr = (reprfunc)pyrf_comm_event__repr,
157};
158
159static char pyrf_throttle_event__doc[] = PyDoc_STR("perf throttle event object.");
160
161static PyMemberDef pyrf_throttle_event__members[] = {
162 sample_members
163 member_def(perf_event_header, type, T_UINT, "event type"),
164 member_def(throttle_event, time, T_ULONGLONG, "timestamp"),
165 member_def(throttle_event, id, T_ULONGLONG, "event id"),
166 member_def(throttle_event, stream_id, T_ULONGLONG, "event stream id"),
167 { .name = NULL, },
168};
169
170static PyObject *pyrf_throttle_event__repr(struct pyrf_event *pevent)
171{
172 struct throttle_event *te = (struct throttle_event *)(&pevent->event.header + 1);
173
174 return PyString_FromFormat("{ type: %sthrottle, time: %" PRIu64 ", id: %" PRIu64
175 ", stream_id: %" PRIu64 " }",
176 pevent->event.header.type == PERF_RECORD_THROTTLE ? "" : "un",
177 te->time, te->id, te->stream_id);
178}
179
180static PyTypeObject pyrf_throttle_event__type = {
181 PyVarObject_HEAD_INIT(NULL, 0)
182 .tp_name = "perf.throttle_event",
183 .tp_basicsize = sizeof(struct pyrf_event),
184 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
185 .tp_doc = pyrf_throttle_event__doc,
186 .tp_members = pyrf_throttle_event__members,
187 .tp_repr = (reprfunc)pyrf_throttle_event__repr,
188};
189
190static int pyrf_event__setup_types(void)
191{
192 int err;
193 pyrf_mmap_event__type.tp_new =
194 pyrf_task_event__type.tp_new =
195 pyrf_comm_event__type.tp_new =
196 pyrf_throttle_event__type.tp_new = PyType_GenericNew;
197 err = PyType_Ready(&pyrf_mmap_event__type);
198 if (err < 0)
199 goto out;
200 err = PyType_Ready(&pyrf_task_event__type);
201 if (err < 0)
202 goto out;
203 err = PyType_Ready(&pyrf_comm_event__type);
204 if (err < 0)
205 goto out;
206 err = PyType_Ready(&pyrf_throttle_event__type);
207 if (err < 0)
208 goto out;
209out:
210 return err;
211}
212
213static PyTypeObject *pyrf_event__type[] = {
214 [PERF_RECORD_MMAP] = &pyrf_mmap_event__type,
215 [PERF_RECORD_LOST] = &pyrf_mmap_event__type,
216 [PERF_RECORD_COMM] = &pyrf_comm_event__type,
217 [PERF_RECORD_EXIT] = &pyrf_task_event__type,
218 [PERF_RECORD_THROTTLE] = &pyrf_throttle_event__type,
219 [PERF_RECORD_UNTHROTTLE] = &pyrf_throttle_event__type,
220 [PERF_RECORD_FORK] = &pyrf_task_event__type,
221 [PERF_RECORD_READ] = &pyrf_mmap_event__type,
222 [PERF_RECORD_SAMPLE] = &pyrf_mmap_event__type,
223};
224
225static PyObject *pyrf_event__new(union perf_event *event)
226{
227 struct pyrf_event *pevent;
228 PyTypeObject *ptype;
229
230 if (event->header.type < PERF_RECORD_MMAP ||
231 event->header.type > PERF_RECORD_SAMPLE)
232 return NULL;
233
234 ptype = pyrf_event__type[event->header.type];
235 pevent = PyObject_New(struct pyrf_event, ptype);
236 if (pevent != NULL)
237 memcpy(&pevent->event, event, event->header.size);
238 return (PyObject *)pevent;
239}
240
241struct pyrf_cpu_map {
242 PyObject_HEAD
243
244 struct cpu_map *cpus;
245};
246
247static int pyrf_cpu_map__init(struct pyrf_cpu_map *pcpus,
248 PyObject *args, PyObject *kwargs)
249{
250 static char *kwlist[] = { "cpustr", NULL, NULL, };
251 char *cpustr = NULL;
252
253 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|s",
254 kwlist, &cpustr))
255 return -1;
256
257 pcpus->cpus = cpu_map__new(cpustr);
258 if (pcpus->cpus == NULL)
259 return -1;
260 return 0;
261}
262
263static void pyrf_cpu_map__delete(struct pyrf_cpu_map *pcpus)
264{
265 cpu_map__delete(pcpus->cpus);
266 pcpus->ob_type->tp_free((PyObject*)pcpus);
267}
268
269static Py_ssize_t pyrf_cpu_map__length(PyObject *obj)
270{
271 struct pyrf_cpu_map *pcpus = (void *)obj;
272
273 return pcpus->cpus->nr;
274}
275
276static PyObject *pyrf_cpu_map__item(PyObject *obj, Py_ssize_t i)
277{
278 struct pyrf_cpu_map *pcpus = (void *)obj;
279
280 if (i >= pcpus->cpus->nr)
281 return NULL;
282
283 return Py_BuildValue("i", pcpus->cpus->map[i]);
284}
285
286static PySequenceMethods pyrf_cpu_map__sequence_methods = {
287 .sq_length = pyrf_cpu_map__length,
288 .sq_item = pyrf_cpu_map__item,
289};
290
291static char pyrf_cpu_map__doc[] = PyDoc_STR("cpu map object.");
292
293static PyTypeObject pyrf_cpu_map__type = {
294 PyVarObject_HEAD_INIT(NULL, 0)
295 .tp_name = "perf.cpu_map",
296 .tp_basicsize = sizeof(struct pyrf_cpu_map),
297 .tp_dealloc = (destructor)pyrf_cpu_map__delete,
298 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
299 .tp_doc = pyrf_cpu_map__doc,
300 .tp_as_sequence = &pyrf_cpu_map__sequence_methods,
301 .tp_init = (initproc)pyrf_cpu_map__init,
302};
303
304static int pyrf_cpu_map__setup_types(void)
305{
306 pyrf_cpu_map__type.tp_new = PyType_GenericNew;
307 return PyType_Ready(&pyrf_cpu_map__type);
308}
309
310struct pyrf_thread_map {
311 PyObject_HEAD
312
313 struct thread_map *threads;
314};
315
316static int pyrf_thread_map__init(struct pyrf_thread_map *pthreads,
317 PyObject *args, PyObject *kwargs)
318{
319 static char *kwlist[] = { "pid", "tid", NULL, NULL, };
320 int pid = -1, tid = -1;
321
322 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii",
323 kwlist, &pid, &tid))
324 return -1;
325
326 pthreads->threads = thread_map__new(pid, tid);
327 if (pthreads->threads == NULL)
328 return -1;
329 return 0;
330}
331
332static void pyrf_thread_map__delete(struct pyrf_thread_map *pthreads)
333{
334 thread_map__delete(pthreads->threads);
335 pthreads->ob_type->tp_free((PyObject*)pthreads);
336}
337
338static Py_ssize_t pyrf_thread_map__length(PyObject *obj)
339{
340 struct pyrf_thread_map *pthreads = (void *)obj;
341
342 return pthreads->threads->nr;
343}
344
345static PyObject *pyrf_thread_map__item(PyObject *obj, Py_ssize_t i)
346{
347 struct pyrf_thread_map *pthreads = (void *)obj;
348
349 if (i >= pthreads->threads->nr)
350 return NULL;
351
352 return Py_BuildValue("i", pthreads->threads->map[i]);
353}
354
355static PySequenceMethods pyrf_thread_map__sequence_methods = {
356 .sq_length = pyrf_thread_map__length,
357 .sq_item = pyrf_thread_map__item,
358};
359
360static char pyrf_thread_map__doc[] = PyDoc_STR("thread map object.");
361
362static PyTypeObject pyrf_thread_map__type = {
363 PyVarObject_HEAD_INIT(NULL, 0)
364 .tp_name = "perf.thread_map",
365 .tp_basicsize = sizeof(struct pyrf_thread_map),
366 .tp_dealloc = (destructor)pyrf_thread_map__delete,
367 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
368 .tp_doc = pyrf_thread_map__doc,
369 .tp_as_sequence = &pyrf_thread_map__sequence_methods,
370 .tp_init = (initproc)pyrf_thread_map__init,
371};
372
373static int pyrf_thread_map__setup_types(void)
374{
375 pyrf_thread_map__type.tp_new = PyType_GenericNew;
376 return PyType_Ready(&pyrf_thread_map__type);
377}
378
379struct pyrf_evsel {
380 PyObject_HEAD
381
382 struct perf_evsel evsel;
383};
384
385static int pyrf_evsel__init(struct pyrf_evsel *pevsel,
386 PyObject *args, PyObject *kwargs)
387{
388 struct perf_event_attr attr = {
389 .type = PERF_TYPE_HARDWARE,
390 .config = PERF_COUNT_HW_CPU_CYCLES,
391 .sample_type = PERF_SAMPLE_PERIOD | PERF_SAMPLE_TID,
392 };
393 static char *kwlist[] = {
394 "type",
395 "config",
396 "sample_freq",
397 "sample_period",
398 "sample_type",
399 "read_format",
400 "disabled",
401 "inherit",
402 "pinned",
403 "exclusive",
404 "exclude_user",
405 "exclude_kernel",
406 "exclude_hv",
407 "exclude_idle",
408 "mmap",
409 "comm",
410 "freq",
411 "inherit_stat",
412 "enable_on_exec",
413 "task",
414 "watermark",
415 "precise_ip",
416 "mmap_data",
417 "sample_id_all",
418 "wakeup_events",
419 "bp_type",
420 "bp_addr",
421 "bp_len", NULL, NULL, };
422 u64 sample_period = 0;
423 u32 disabled = 0,
424 inherit = 0,
425 pinned = 0,
426 exclusive = 0,
427 exclude_user = 0,
428 exclude_kernel = 0,
429 exclude_hv = 0,
430 exclude_idle = 0,
431 mmap = 0,
432 comm = 0,
433 freq = 1,
434 inherit_stat = 0,
435 enable_on_exec = 0,
436 task = 0,
437 watermark = 0,
438 precise_ip = 0,
439 mmap_data = 0,
440 sample_id_all = 1;
441 int idx = 0;
442
443 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
444 "|iKiKKiiiiiiiiiiiiiiiiiiiiiKK", kwlist,
445 &attr.type, &attr.config, &attr.sample_freq,
446 &sample_period, &attr.sample_type,
447 &attr.read_format, &disabled, &inherit,
448 &pinned, &exclusive, &exclude_user,
449 &exclude_kernel, &exclude_hv, &exclude_idle,
450 &mmap, &comm, &freq, &inherit_stat,
451 &enable_on_exec, &task, &watermark,
452 &precise_ip, &mmap_data, &sample_id_all,
453 &attr.wakeup_events, &attr.bp_type,
454 &attr.bp_addr, &attr.bp_len, &idx))
455 return -1;
456
457 /* union... */
458 if (sample_period != 0) {
459 if (attr.sample_freq != 0)
460 return -1; /* FIXME: throw right exception */
461 attr.sample_period = sample_period;
462 }
463
464 /* Bitfields */
465 attr.disabled = disabled;
466 attr.inherit = inherit;
467 attr.pinned = pinned;
468 attr.exclusive = exclusive;
469 attr.exclude_user = exclude_user;
470 attr.exclude_kernel = exclude_kernel;
471 attr.exclude_hv = exclude_hv;
472 attr.exclude_idle = exclude_idle;
473 attr.mmap = mmap;
474 attr.comm = comm;
475 attr.freq = freq;
476 attr.inherit_stat = inherit_stat;
477 attr.enable_on_exec = enable_on_exec;
478 attr.task = task;
479 attr.watermark = watermark;
480 attr.precise_ip = precise_ip;
481 attr.mmap_data = mmap_data;
482 attr.sample_id_all = sample_id_all;
483
484 perf_evsel__init(&pevsel->evsel, &attr, idx);
485 return 0;
486}
487
488static void pyrf_evsel__delete(struct pyrf_evsel *pevsel)
489{
490 perf_evsel__exit(&pevsel->evsel);
491 pevsel->ob_type->tp_free((PyObject*)pevsel);
492}
493
494static PyObject *pyrf_evsel__open(struct pyrf_evsel *pevsel,
495 PyObject *args, PyObject *kwargs)
496{
497 struct perf_evsel *evsel = &pevsel->evsel;
498 struct cpu_map *cpus = NULL;
499 struct thread_map *threads = NULL;
500 PyObject *pcpus = NULL, *pthreads = NULL;
501 int group = 0, inherit = 0;
502 static char *kwlist[] = {"cpus", "threads", "group", "inherit", NULL, NULL};
503
504 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOii", kwlist,
505 &pcpus, &pthreads, &group, &inherit))
506 return NULL;
507
508 if (pthreads != NULL)
509 threads = ((struct pyrf_thread_map *)pthreads)->threads;
510
511 if (pcpus != NULL)
512 cpus = ((struct pyrf_cpu_map *)pcpus)->cpus;
513
514 evsel->attr.inherit = inherit;
515 if (perf_evsel__open(evsel, cpus, threads, group) < 0) {
516 PyErr_SetFromErrno(PyExc_OSError);
517 return NULL;
518 }
519
520 Py_INCREF(Py_None);
521 return Py_None;
522}
523
524static PyMethodDef pyrf_evsel__methods[] = {
525 {
526 .ml_name = "open",
527 .ml_meth = (PyCFunction)pyrf_evsel__open,
528 .ml_flags = METH_VARARGS | METH_KEYWORDS,
529 .ml_doc = PyDoc_STR("open the event selector file descriptor table.")
530 },
531 { .ml_name = NULL, }
532};
533
534static char pyrf_evsel__doc[] = PyDoc_STR("perf event selector list object.");
535
536static PyTypeObject pyrf_evsel__type = {
537 PyVarObject_HEAD_INIT(NULL, 0)
538 .tp_name = "perf.evsel",
539 .tp_basicsize = sizeof(struct pyrf_evsel),
540 .tp_dealloc = (destructor)pyrf_evsel__delete,
541 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
542 .tp_doc = pyrf_evsel__doc,
543 .tp_methods = pyrf_evsel__methods,
544 .tp_init = (initproc)pyrf_evsel__init,
545};
546
547static int pyrf_evsel__setup_types(void)
548{
549 pyrf_evsel__type.tp_new = PyType_GenericNew;
550 return PyType_Ready(&pyrf_evsel__type);
551}
552
553struct pyrf_evlist {
554 PyObject_HEAD
555
556 struct perf_evlist evlist;
557};
558
559static int pyrf_evlist__init(struct pyrf_evlist *pevlist,
560 PyObject *args, PyObject *kwargs __used)
561{
562 PyObject *pcpus = NULL, *pthreads = NULL;
563 struct cpu_map *cpus;
564 struct thread_map *threads;
565
566 if (!PyArg_ParseTuple(args, "OO", &pcpus, &pthreads))
567 return -1;
568
569 threads = ((struct pyrf_thread_map *)pthreads)->threads;
570 cpus = ((struct pyrf_cpu_map *)pcpus)->cpus;
571 perf_evlist__init(&pevlist->evlist, cpus, threads);
572 return 0;
573}
574
575static void pyrf_evlist__delete(struct pyrf_evlist *pevlist)
576{
577 perf_evlist__exit(&pevlist->evlist);
578 pevlist->ob_type->tp_free((PyObject*)pevlist);
579}
580
581static PyObject *pyrf_evlist__mmap(struct pyrf_evlist *pevlist,
582 PyObject *args, PyObject *kwargs)
583{
584 struct perf_evlist *evlist = &pevlist->evlist;
585 static char *kwlist[] = {"pages", "overwrite",
586 NULL, NULL};
587 int pages = 128, overwrite = false;
588
589 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii", kwlist,
590 &pages, &overwrite))
591 return NULL;
592
593 if (perf_evlist__mmap(evlist, pages, overwrite) < 0) {
594 PyErr_SetFromErrno(PyExc_OSError);
595 return NULL;
596 }
597
598 Py_INCREF(Py_None);
599 return Py_None;
600}
601
602static PyObject *pyrf_evlist__poll(struct pyrf_evlist *pevlist,
603 PyObject *args, PyObject *kwargs)
604{
605 struct perf_evlist *evlist = &pevlist->evlist;
606 static char *kwlist[] = {"timeout", NULL, NULL};
607 int timeout = -1, n;
608
609 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i", kwlist, &timeout))
610 return NULL;
611
612 n = poll(evlist->pollfd, evlist->nr_fds, timeout);
613 if (n < 0) {
614 PyErr_SetFromErrno(PyExc_OSError);
615 return NULL;
616 }
617
618 return Py_BuildValue("i", n);
619}
620
621static PyObject *pyrf_evlist__get_pollfd(struct pyrf_evlist *pevlist,
622 PyObject *args __used, PyObject *kwargs __used)
623{
624 struct perf_evlist *evlist = &pevlist->evlist;
625 PyObject *list = PyList_New(0);
626 int i;
627
628 for (i = 0; i < evlist->nr_fds; ++i) {
629 PyObject *file;
630 FILE *fp = fdopen(evlist->pollfd[i].fd, "r");
631
632 if (fp == NULL)
633 goto free_list;
634
635 file = PyFile_FromFile(fp, "perf", "r", NULL);
636 if (file == NULL)
637 goto free_list;
638
639 if (PyList_Append(list, file) != 0) {
640 Py_DECREF(file);
641 goto free_list;
642 }
643
644 Py_DECREF(file);
645 }
646
647 return list;
648free_list:
649 return PyErr_NoMemory();
650}
651
652
653static PyObject *pyrf_evlist__add(struct pyrf_evlist *pevlist,
654 PyObject *args, PyObject *kwargs __used)
655{
656 struct perf_evlist *evlist = &pevlist->evlist;
657 PyObject *pevsel;
658 struct perf_evsel *evsel;
659
660 if (!PyArg_ParseTuple(args, "O", &pevsel))
661 return NULL;
662
663 Py_INCREF(pevsel);
664 evsel = &((struct pyrf_evsel *)pevsel)->evsel;
665 evsel->idx = evlist->nr_entries;
666 perf_evlist__add(evlist, evsel);
667
668 return Py_BuildValue("i", evlist->nr_entries);
669}
670
671static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
672 PyObject *args, PyObject *kwargs)
673{
674 struct perf_evlist *evlist = &pevlist->evlist;
675 union perf_event *event;
676 int sample_id_all = 1, cpu;
677 static char *kwlist[] = {"cpu", "sample_id_all", NULL, NULL};
678 int err;
679
680 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|i", kwlist,
681 &cpu, &sample_id_all))
682 return NULL;
683
684 event = perf_evlist__mmap_read(evlist, cpu);
685 if (event != NULL) {
686 struct perf_evsel *first;
687 PyObject *pyevent = pyrf_event__new(event);
688 struct pyrf_event *pevent = (struct pyrf_event *)pyevent;
689
690 if (pyevent == NULL)
691 return PyErr_NoMemory();
692
693 first = list_entry(evlist->entries.next, struct perf_evsel, node);
694 err = perf_event__parse_sample(event, first->attr.sample_type,
695 perf_evsel__sample_size(first),
696 sample_id_all, &pevent->sample);
697 if (err)
698 return PyErr_Format(PyExc_OSError,
699 "perf: can't parse sample, err=%d", err);
700 return pyevent;
701 }
702
703 Py_INCREF(Py_None);
704 return Py_None;
705}
706
707static PyMethodDef pyrf_evlist__methods[] = {
708 {
709 .ml_name = "mmap",
710 .ml_meth = (PyCFunction)pyrf_evlist__mmap,
711 .ml_flags = METH_VARARGS | METH_KEYWORDS,
712 .ml_doc = PyDoc_STR("mmap the file descriptor table.")
713 },
714 {
715 .ml_name = "poll",
716 .ml_meth = (PyCFunction)pyrf_evlist__poll,
717 .ml_flags = METH_VARARGS | METH_KEYWORDS,
718 .ml_doc = PyDoc_STR("poll the file descriptor table.")
719 },
720 {
721 .ml_name = "get_pollfd",
722 .ml_meth = (PyCFunction)pyrf_evlist__get_pollfd,
723 .ml_flags = METH_VARARGS | METH_KEYWORDS,
724 .ml_doc = PyDoc_STR("get the poll file descriptor table.")
725 },
726 {
727 .ml_name = "add",
728 .ml_meth = (PyCFunction)pyrf_evlist__add,
729 .ml_flags = METH_VARARGS | METH_KEYWORDS,
730 .ml_doc = PyDoc_STR("adds an event selector to the list.")
731 },
732 {
733 .ml_name = "read_on_cpu",
734 .ml_meth = (PyCFunction)pyrf_evlist__read_on_cpu,
735 .ml_flags = METH_VARARGS | METH_KEYWORDS,
736 .ml_doc = PyDoc_STR("reads an event.")
737 },
738 { .ml_name = NULL, }
739};
740
741static Py_ssize_t pyrf_evlist__length(PyObject *obj)
742{
743 struct pyrf_evlist *pevlist = (void *)obj;
744
745 return pevlist->evlist.nr_entries;
746}
747
748static PyObject *pyrf_evlist__item(PyObject *obj, Py_ssize_t i)
749{
750 struct pyrf_evlist *pevlist = (void *)obj;
751 struct perf_evsel *pos;
752
753 if (i >= pevlist->evlist.nr_entries)
754 return NULL;
755
756 list_for_each_entry(pos, &pevlist->evlist.entries, node)
757 if (i-- == 0)
758 break;
759
760 return Py_BuildValue("O", container_of(pos, struct pyrf_evsel, evsel));
761}
762
763static PySequenceMethods pyrf_evlist__sequence_methods = {
764 .sq_length = pyrf_evlist__length,
765 .sq_item = pyrf_evlist__item,
766};
767
768static char pyrf_evlist__doc[] = PyDoc_STR("perf event selector list object.");
769
770static PyTypeObject pyrf_evlist__type = {
771 PyVarObject_HEAD_INIT(NULL, 0)
772 .tp_name = "perf.evlist",
773 .tp_basicsize = sizeof(struct pyrf_evlist),
774 .tp_dealloc = (destructor)pyrf_evlist__delete,
775 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
776 .tp_as_sequence = &pyrf_evlist__sequence_methods,
777 .tp_doc = pyrf_evlist__doc,
778 .tp_methods = pyrf_evlist__methods,
779 .tp_init = (initproc)pyrf_evlist__init,
780};
781
782static int pyrf_evlist__setup_types(void)
783{
784 pyrf_evlist__type.tp_new = PyType_GenericNew;
785 return PyType_Ready(&pyrf_evlist__type);
786}
787
788static struct {
789 const char *name;
790 int value;
791} perf__constants[] = {
792 { "TYPE_HARDWARE", PERF_TYPE_HARDWARE },
793 { "TYPE_SOFTWARE", PERF_TYPE_SOFTWARE },
794 { "TYPE_TRACEPOINT", PERF_TYPE_TRACEPOINT },
795 { "TYPE_HW_CACHE", PERF_TYPE_HW_CACHE },
796 { "TYPE_RAW", PERF_TYPE_RAW },
797 { "TYPE_BREAKPOINT", PERF_TYPE_BREAKPOINT },
798
799 { "COUNT_HW_CPU_CYCLES", PERF_COUNT_HW_CPU_CYCLES },
800 { "COUNT_HW_INSTRUCTIONS", PERF_COUNT_HW_INSTRUCTIONS },
801 { "COUNT_HW_CACHE_REFERENCES", PERF_COUNT_HW_CACHE_REFERENCES },
802 { "COUNT_HW_CACHE_MISSES", PERF_COUNT_HW_CACHE_MISSES },
803 { "COUNT_HW_BRANCH_INSTRUCTIONS", PERF_COUNT_HW_BRANCH_INSTRUCTIONS },
804 { "COUNT_HW_BRANCH_MISSES", PERF_COUNT_HW_BRANCH_MISSES },
805 { "COUNT_HW_BUS_CYCLES", PERF_COUNT_HW_BUS_CYCLES },
806 { "COUNT_HW_CACHE_L1D", PERF_COUNT_HW_CACHE_L1D },
807 { "COUNT_HW_CACHE_L1I", PERF_COUNT_HW_CACHE_L1I },
808 { "COUNT_HW_CACHE_LL", PERF_COUNT_HW_CACHE_LL },
809 { "COUNT_HW_CACHE_DTLB", PERF_COUNT_HW_CACHE_DTLB },
810 { "COUNT_HW_CACHE_ITLB", PERF_COUNT_HW_CACHE_ITLB },
811 { "COUNT_HW_CACHE_BPU", PERF_COUNT_HW_CACHE_BPU },
812 { "COUNT_HW_CACHE_OP_READ", PERF_COUNT_HW_CACHE_OP_READ },
813 { "COUNT_HW_CACHE_OP_WRITE", PERF_COUNT_HW_CACHE_OP_WRITE },
814 { "COUNT_HW_CACHE_OP_PREFETCH", PERF_COUNT_HW_CACHE_OP_PREFETCH },
815 { "COUNT_HW_CACHE_RESULT_ACCESS", PERF_COUNT_HW_CACHE_RESULT_ACCESS },
816 { "COUNT_HW_CACHE_RESULT_MISS", PERF_COUNT_HW_CACHE_RESULT_MISS },
817
818 { "COUNT_HW_STALLED_CYCLES_FRONTEND", PERF_COUNT_HW_STALLED_CYCLES_FRONTEND },
819 { "COUNT_HW_STALLED_CYCLES_BACKEND", PERF_COUNT_HW_STALLED_CYCLES_BACKEND },
820
821 { "COUNT_SW_CPU_CLOCK", PERF_COUNT_SW_CPU_CLOCK },
822 { "COUNT_SW_TASK_CLOCK", PERF_COUNT_SW_TASK_CLOCK },
823 { "COUNT_SW_PAGE_FAULTS", PERF_COUNT_SW_PAGE_FAULTS },
824 { "COUNT_SW_CONTEXT_SWITCHES", PERF_COUNT_SW_CONTEXT_SWITCHES },
825 { "COUNT_SW_CPU_MIGRATIONS", PERF_COUNT_SW_CPU_MIGRATIONS },
826 { "COUNT_SW_PAGE_FAULTS_MIN", PERF_COUNT_SW_PAGE_FAULTS_MIN },
827 { "COUNT_SW_PAGE_FAULTS_MAJ", PERF_COUNT_SW_PAGE_FAULTS_MAJ },
828 { "COUNT_SW_ALIGNMENT_FAULTS", PERF_COUNT_SW_ALIGNMENT_FAULTS },
829 { "COUNT_SW_EMULATION_FAULTS", PERF_COUNT_SW_EMULATION_FAULTS },
830
831 { "SAMPLE_IP", PERF_SAMPLE_IP },
832 { "SAMPLE_TID", PERF_SAMPLE_TID },
833 { "SAMPLE_TIME", PERF_SAMPLE_TIME },
834 { "SAMPLE_ADDR", PERF_SAMPLE_ADDR },
835 { "SAMPLE_READ", PERF_SAMPLE_READ },
836 { "SAMPLE_CALLCHAIN", PERF_SAMPLE_CALLCHAIN },
837 { "SAMPLE_ID", PERF_SAMPLE_ID },
838 { "SAMPLE_CPU", PERF_SAMPLE_CPU },
839 { "SAMPLE_PERIOD", PERF_SAMPLE_PERIOD },
840 { "SAMPLE_STREAM_ID", PERF_SAMPLE_STREAM_ID },
841 { "SAMPLE_RAW", PERF_SAMPLE_RAW },
842
843 { "FORMAT_TOTAL_TIME_ENABLED", PERF_FORMAT_TOTAL_TIME_ENABLED },
844 { "FORMAT_TOTAL_TIME_RUNNING", PERF_FORMAT_TOTAL_TIME_RUNNING },
845 { "FORMAT_ID", PERF_FORMAT_ID },
846 { "FORMAT_GROUP", PERF_FORMAT_GROUP },
847
848 { "RECORD_MMAP", PERF_RECORD_MMAP },
849 { "RECORD_LOST", PERF_RECORD_LOST },
850 { "RECORD_COMM", PERF_RECORD_COMM },
851 { "RECORD_EXIT", PERF_RECORD_EXIT },
852 { "RECORD_THROTTLE", PERF_RECORD_THROTTLE },
853 { "RECORD_UNTHROTTLE", PERF_RECORD_UNTHROTTLE },
854 { "RECORD_FORK", PERF_RECORD_FORK },
855 { "RECORD_READ", PERF_RECORD_READ },
856 { "RECORD_SAMPLE", PERF_RECORD_SAMPLE },
857 { .name = NULL, },
858};
859
860static PyMethodDef perf__methods[] = {
861 { .ml_name = NULL, }
862};
863
864PyMODINIT_FUNC initperf(void)
865{
866 PyObject *obj;
867 int i;
868 PyObject *dict, *module = Py_InitModule("perf", perf__methods);
869
870 if (module == NULL ||
871 pyrf_event__setup_types() < 0 ||
872 pyrf_evlist__setup_types() < 0 ||
873 pyrf_evsel__setup_types() < 0 ||
874 pyrf_thread_map__setup_types() < 0 ||
875 pyrf_cpu_map__setup_types() < 0)
876 return;
877
878 Py_INCREF(&pyrf_evlist__type);
879 PyModule_AddObject(module, "evlist", (PyObject*)&pyrf_evlist__type);
880
881 Py_INCREF(&pyrf_evsel__type);
882 PyModule_AddObject(module, "evsel", (PyObject*)&pyrf_evsel__type);
883
884 Py_INCREF(&pyrf_thread_map__type);
885 PyModule_AddObject(module, "thread_map", (PyObject*)&pyrf_thread_map__type);
886
887 Py_INCREF(&pyrf_cpu_map__type);
888 PyModule_AddObject(module, "cpu_map", (PyObject*)&pyrf_cpu_map__type);
889
890 dict = PyModule_GetDict(module);
891 if (dict == NULL)
892 goto error;
893
894 for (i = 0; perf__constants[i].name != NULL; i++) {
895 obj = PyInt_FromLong(perf__constants[i].value);
896 if (obj == NULL)
897 goto error;
898 PyDict_SetItemString(dict, perf__constants[i].name, obj);
899 Py_DECREF(obj);
900 }
901
902error:
903 if (PyErr_Occurred())
904 PyErr_SetString(PyExc_ImportError, "perf: Init failed!");
905}
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index b059dc50cc2d..74350ffb57fe 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * trace-event-perl. Feed perf trace events to an embedded Perl interpreter. 2 * trace-event-perl. Feed perf script events to an embedded Perl interpreter.
3 * 3 *
4 * Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com> 4 * Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com>
5 * 5 *
@@ -245,9 +245,11 @@ static inline struct event *find_cache_event(int type)
245 return event; 245 return event;
246} 246}
247 247
248static void perl_process_event(int cpu, void *data, 248static void perl_process_event(union perf_event *pevent __unused,
249 int size __unused, 249 struct perf_sample *sample,
250 unsigned long long nsecs, char *comm) 250 struct perf_evsel *evsel,
251 struct perf_session *session __unused,
252 struct thread *thread)
251{ 253{
252 struct format_field *field; 254 struct format_field *field;
253 static char handler[256]; 255 static char handler[256];
@@ -256,6 +258,10 @@ static void perl_process_event(int cpu, void *data,
256 struct event *event; 258 struct event *event;
257 int type; 259 int type;
258 int pid; 260 int pid;
261 int cpu = sample->cpu;
262 void *data = sample->raw_data;
263 unsigned long long nsecs = sample->time;
264 char *comm = thread->comm;
259 265
260 dSP; 266 dSP;
261 267
@@ -411,8 +417,8 @@ static int perl_generate_script(const char *outfile)
411 return -1; 417 return -1;
412 } 418 }
413 419
414 fprintf(ofp, "# perf trace event handlers, " 420 fprintf(ofp, "# perf script event handlers, "
415 "generated by perf trace -g perl\n"); 421 "generated by perf script -g perl\n");
416 422
417 fprintf(ofp, "# Licensed under the terms of the GNU GPL" 423 fprintf(ofp, "# Licensed under the terms of the GNU GPL"
418 " License version 2\n\n"); 424 " License version 2\n\n");
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index 33a632523743..6ccf70e8d8f2 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -204,9 +204,11 @@ static inline struct event *find_cache_event(int type)
204 return event; 204 return event;
205} 205}
206 206
207static void python_process_event(int cpu, void *data, 207static void python_process_event(union perf_event *pevent __unused,
208 int size __unused, 208 struct perf_sample *sample,
209 unsigned long long nsecs, char *comm) 209 struct perf_evsel *evsel __unused,
210 struct perf_session *session __unused,
211 struct thread *thread)
210{ 212{
211 PyObject *handler, *retval, *context, *t, *obj, *dict = NULL; 213 PyObject *handler, *retval, *context, *t, *obj, *dict = NULL;
212 static char handler_name[256]; 214 static char handler_name[256];
@@ -217,6 +219,10 @@ static void python_process_event(int cpu, void *data,
217 unsigned n = 0; 219 unsigned n = 0;
218 int type; 220 int type;
219 int pid; 221 int pid;
222 int cpu = sample->cpu;
223 void *data = sample->raw_data;
224 unsigned long long nsecs = sample->time;
225 char *comm = thread->comm;
220 226
221 t = PyTuple_New(MAX_FIELDS); 227 t = PyTuple_New(MAX_FIELDS);
222 if (!t) 228 if (!t)
@@ -248,8 +254,7 @@ static void python_process_event(int cpu, void *data,
248 context = PyCObject_FromVoidPtr(scripting_context, NULL); 254 context = PyCObject_FromVoidPtr(scripting_context, NULL);
249 255
250 PyTuple_SetItem(t, n++, PyString_FromString(handler_name)); 256 PyTuple_SetItem(t, n++, PyString_FromString(handler_name));
251 PyTuple_SetItem(t, n++, 257 PyTuple_SetItem(t, n++, context);
252 PyCObject_FromVoidPtr(scripting_context, NULL));
253 258
254 if (handler) { 259 if (handler) {
255 PyTuple_SetItem(t, n++, PyInt_FromLong(cpu)); 260 PyTuple_SetItem(t, n++, PyInt_FromLong(cpu));
@@ -442,8 +447,8 @@ static int python_generate_script(const char *outfile)
442 fprintf(stderr, "couldn't open %s\n", fname); 447 fprintf(stderr, "couldn't open %s\n", fname);
443 return -1; 448 return -1;
444 } 449 }
445 fprintf(ofp, "# perf trace event handlers, " 450 fprintf(ofp, "# perf script event handlers, "
446 "generated by perf trace -g python\n"); 451 "generated by perf script -g python\n");
447 452
448 fprintf(ofp, "# Licensed under the terms of the GNU GPL" 453 fprintf(ofp, "# Licensed under the terms of the GNU GPL"
449 " License version 2\n\n"); 454 " License version 2\n\n");
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index fa9d652c2dc3..f5a8fbdd3f76 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -7,6 +7,8 @@
7#include <sys/types.h> 7#include <sys/types.h>
8#include <sys/mman.h> 8#include <sys/mman.h>
9 9
10#include "evlist.h"
11#include "evsel.h"
10#include "session.h" 12#include "session.h"
11#include "sort.h" 13#include "sort.h"
12#include "util.h" 14#include "util.h"
@@ -19,7 +21,7 @@ static int perf_session__open(struct perf_session *self, bool force)
19 self->fd_pipe = true; 21 self->fd_pipe = true;
20 self->fd = STDIN_FILENO; 22 self->fd = STDIN_FILENO;
21 23
22 if (perf_header__read(self, self->fd) < 0) 24 if (perf_session__read_header(self, self->fd) < 0)
23 pr_err("incompatible file format"); 25 pr_err("incompatible file format");
24 26
25 return 0; 27 return 0;
@@ -51,11 +53,21 @@ static int perf_session__open(struct perf_session *self, bool force)
51 goto out_close; 53 goto out_close;
52 } 54 }
53 55
54 if (perf_header__read(self, self->fd) < 0) { 56 if (perf_session__read_header(self, self->fd) < 0) {
55 pr_err("incompatible file format"); 57 pr_err("incompatible file format");
56 goto out_close; 58 goto out_close;
57 } 59 }
58 60
61 if (!perf_evlist__valid_sample_type(self->evlist)) {
62 pr_err("non matching sample_type");
63 goto out_close;
64 }
65
66 if (!perf_evlist__valid_sample_id_all(self->evlist)) {
67 pr_err("non matching sample_id_all");
68 goto out_close;
69 }
70
59 self->size = input_stat.st_size; 71 self->size = input_stat.st_size;
60 return 0; 72 return 0;
61 73
@@ -65,9 +77,39 @@ out_close:
65 return -1; 77 return -1;
66} 78}
67 79
80static void perf_session__id_header_size(struct perf_session *session)
81{
82 struct perf_sample *data;
83 u64 sample_type = session->sample_type;
84 u16 size = 0;
85
86 if (!session->sample_id_all)
87 goto out;
88
89 if (sample_type & PERF_SAMPLE_TID)
90 size += sizeof(data->tid) * 2;
91
92 if (sample_type & PERF_SAMPLE_TIME)
93 size += sizeof(data->time);
94
95 if (sample_type & PERF_SAMPLE_ID)
96 size += sizeof(data->id);
97
98 if (sample_type & PERF_SAMPLE_STREAM_ID)
99 size += sizeof(data->stream_id);
100
101 if (sample_type & PERF_SAMPLE_CPU)
102 size += sizeof(data->cpu) * 2;
103out:
104 session->id_hdr_size = size;
105}
106
68void perf_session__update_sample_type(struct perf_session *self) 107void perf_session__update_sample_type(struct perf_session *self)
69{ 108{
70 self->sample_type = perf_header__sample_type(&self->header); 109 self->sample_type = perf_evlist__sample_type(self->evlist);
110 self->sample_size = __perf_evsel__sample_size(self->sample_type);
111 self->sample_id_all = perf_evlist__sample_id_all(self->evlist);
112 perf_session__id_header_size(self);
71} 113}
72 114
73int perf_session__create_kernel_maps(struct perf_session *self) 115int perf_session__create_kernel_maps(struct perf_session *self)
@@ -85,7 +127,9 @@ static void perf_session__destroy_kernel_maps(struct perf_session *self)
85 machines__destroy_guest_kernel_maps(&self->machines); 127 machines__destroy_guest_kernel_maps(&self->machines);
86} 128}
87 129
88struct perf_session *perf_session__new(const char *filename, int mode, bool force, bool repipe) 130struct perf_session *perf_session__new(const char *filename, int mode,
131 bool force, bool repipe,
132 struct perf_event_ops *ops)
89{ 133{
90 size_t len = filename ? strlen(filename) + 1 : 0; 134 size_t len = filename ? strlen(filename) + 1 : 0;
91 struct perf_session *self = zalloc(sizeof(*self) + len); 135 struct perf_session *self = zalloc(sizeof(*self) + len);
@@ -93,38 +137,47 @@ struct perf_session *perf_session__new(const char *filename, int mode, bool forc
93 if (self == NULL) 137 if (self == NULL)
94 goto out; 138 goto out;
95 139
96 if (perf_header__init(&self->header) < 0)
97 goto out_free;
98
99 memcpy(self->filename, filename, len); 140 memcpy(self->filename, filename, len);
100 self->threads = RB_ROOT; 141 self->threads = RB_ROOT;
101 INIT_LIST_HEAD(&self->dead_threads); 142 INIT_LIST_HEAD(&self->dead_threads);
102 self->hists_tree = RB_ROOT;
103 self->last_match = NULL; 143 self->last_match = NULL;
104 self->mmap_window = 32; 144 /*
145 * On 64bit we can mmap the data file in one go. No need for tiny mmap
146 * slices. On 32bit we use 32MB.
147 */
148#if BITS_PER_LONG == 64
149 self->mmap_window = ULLONG_MAX;
150#else
151 self->mmap_window = 32 * 1024 * 1024ULL;
152#endif
105 self->machines = RB_ROOT; 153 self->machines = RB_ROOT;
106 self->repipe = repipe; 154 self->repipe = repipe;
107 INIT_LIST_HEAD(&self->ordered_samples.samples_head); 155 INIT_LIST_HEAD(&self->ordered_samples.samples);
156 INIT_LIST_HEAD(&self->ordered_samples.sample_cache);
157 INIT_LIST_HEAD(&self->ordered_samples.to_free);
108 machine__init(&self->host_machine, "", HOST_KERNEL_ID); 158 machine__init(&self->host_machine, "", HOST_KERNEL_ID);
109 159
110 if (mode == O_RDONLY) { 160 if (mode == O_RDONLY) {
111 if (perf_session__open(self, force) < 0) 161 if (perf_session__open(self, force) < 0)
112 goto out_delete; 162 goto out_delete;
163 perf_session__update_sample_type(self);
113 } else if (mode == O_WRONLY) { 164 } else if (mode == O_WRONLY) {
114 /* 165 /*
115 * In O_RDONLY mode this will be performed when reading the 166 * In O_RDONLY mode this will be performed when reading the
116 * kernel MMAP event, in event__process_mmap(). 167 * kernel MMAP event, in perf_event__process_mmap().
117 */ 168 */
118 if (perf_session__create_kernel_maps(self) < 0) 169 if (perf_session__create_kernel_maps(self) < 0)
119 goto out_delete; 170 goto out_delete;
120 } 171 }
121 172
122 perf_session__update_sample_type(self); 173 if (ops && ops->ordering_requires_timestamps &&
174 ops->ordered_samples && !self->sample_id_all) {
175 dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n");
176 ops->ordered_samples = false;
177 }
178
123out: 179out:
124 return self; 180 return self;
125out_free:
126 free(self);
127 return NULL;
128out_delete: 181out_delete:
129 perf_session__delete(self); 182 perf_session__delete(self);
130 return NULL; 183 return NULL;
@@ -155,7 +208,6 @@ static void perf_session__delete_threads(struct perf_session *self)
155 208
156void perf_session__delete(struct perf_session *self) 209void perf_session__delete(struct perf_session *self)
157{ 210{
158 perf_header__exit(&self->header);
159 perf_session__destroy_kernel_maps(self); 211 perf_session__destroy_kernel_maps(self);
160 perf_session__delete_dead_threads(self); 212 perf_session__delete_dead_threads(self);
161 perf_session__delete_threads(self); 213 perf_session__delete_threads(self);
@@ -183,17 +235,16 @@ static bool symbol__match_parent_regex(struct symbol *sym)
183 return 0; 235 return 0;
184} 236}
185 237
186struct map_symbol *perf_session__resolve_callchain(struct perf_session *self, 238int perf_session__resolve_callchain(struct perf_session *self,
187 struct thread *thread, 239 struct thread *thread,
188 struct ip_callchain *chain, 240 struct ip_callchain *chain,
189 struct symbol **parent) 241 struct symbol **parent)
190{ 242{
191 u8 cpumode = PERF_RECORD_MISC_USER; 243 u8 cpumode = PERF_RECORD_MISC_USER;
192 unsigned int i; 244 unsigned int i;
193 struct map_symbol *syms = calloc(chain->nr, sizeof(*syms)); 245 int err;
194 246
195 if (!syms) 247 callchain_cursor_reset(&self->callchain_cursor);
196 return NULL;
197 248
198 for (i = 0; i < chain->nr; i++) { 249 for (i = 0; i < chain->nr; i++) {
199 u64 ip = chain->ips[i]; 250 u64 ip = chain->ips[i];
@@ -222,22 +273,42 @@ struct map_symbol *perf_session__resolve_callchain(struct perf_session *self,
222 *parent = al.sym; 273 *parent = al.sym;
223 if (!symbol_conf.use_callchain) 274 if (!symbol_conf.use_callchain)
224 break; 275 break;
225 syms[i].map = al.map;
226 syms[i].sym = al.sym;
227 } 276 }
277
278 err = callchain_cursor_append(&self->callchain_cursor,
279 ip, al.map, al.sym);
280 if (err)
281 return err;
228 } 282 }
229 283
230 return syms; 284 return 0;
285}
286
287static int process_event_synth_stub(union perf_event *event __used,
288 struct perf_session *session __used)
289{
290 dump_printf(": unhandled!\n");
291 return 0;
292}
293
294static int process_event_sample_stub(union perf_event *event __used,
295 struct perf_sample *sample __used,
296 struct perf_evsel *evsel __used,
297 struct perf_session *session __used)
298{
299 dump_printf(": unhandled!\n");
300 return 0;
231} 301}
232 302
233static int process_event_stub(event_t *event __used, 303static int process_event_stub(union perf_event *event __used,
304 struct perf_sample *sample __used,
234 struct perf_session *session __used) 305 struct perf_session *session __used)
235{ 306{
236 dump_printf(": unhandled!\n"); 307 dump_printf(": unhandled!\n");
237 return 0; 308 return 0;
238} 309}
239 310
240static int process_finished_round_stub(event_t *event __used, 311static int process_finished_round_stub(union perf_event *event __used,
241 struct perf_session *session __used, 312 struct perf_session *session __used,
242 struct perf_event_ops *ops __used) 313 struct perf_event_ops *ops __used)
243{ 314{
@@ -245,14 +316,14 @@ static int process_finished_round_stub(event_t *event __used,
245 return 0; 316 return 0;
246} 317}
247 318
248static int process_finished_round(event_t *event, 319static int process_finished_round(union perf_event *event,
249 struct perf_session *session, 320 struct perf_session *session,
250 struct perf_event_ops *ops); 321 struct perf_event_ops *ops);
251 322
252static void perf_event_ops__fill_defaults(struct perf_event_ops *handler) 323static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
253{ 324{
254 if (handler->sample == NULL) 325 if (handler->sample == NULL)
255 handler->sample = process_event_stub; 326 handler->sample = process_event_sample_stub;
256 if (handler->mmap == NULL) 327 if (handler->mmap == NULL)
257 handler->mmap = process_event_stub; 328 handler->mmap = process_event_stub;
258 if (handler->comm == NULL) 329 if (handler->comm == NULL)
@@ -262,7 +333,7 @@ static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
262 if (handler->exit == NULL) 333 if (handler->exit == NULL)
263 handler->exit = process_event_stub; 334 handler->exit = process_event_stub;
264 if (handler->lost == NULL) 335 if (handler->lost == NULL)
265 handler->lost = process_event_stub; 336 handler->lost = perf_event__process_lost;
266 if (handler->read == NULL) 337 if (handler->read == NULL)
267 handler->read = process_event_stub; 338 handler->read = process_event_stub;
268 if (handler->throttle == NULL) 339 if (handler->throttle == NULL)
@@ -270,13 +341,13 @@ static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
270 if (handler->unthrottle == NULL) 341 if (handler->unthrottle == NULL)
271 handler->unthrottle = process_event_stub; 342 handler->unthrottle = process_event_stub;
272 if (handler->attr == NULL) 343 if (handler->attr == NULL)
273 handler->attr = process_event_stub; 344 handler->attr = process_event_synth_stub;
274 if (handler->event_type == NULL) 345 if (handler->event_type == NULL)
275 handler->event_type = process_event_stub; 346 handler->event_type = process_event_synth_stub;
276 if (handler->tracing_data == NULL) 347 if (handler->tracing_data == NULL)
277 handler->tracing_data = process_event_stub; 348 handler->tracing_data = process_event_synth_stub;
278 if (handler->build_id == NULL) 349 if (handler->build_id == NULL)
279 handler->build_id = process_event_stub; 350 handler->build_id = process_event_synth_stub;
280 if (handler->finished_round == NULL) { 351 if (handler->finished_round == NULL) {
281 if (handler->ordered_samples) 352 if (handler->ordered_samples)
282 handler->finished_round = process_finished_round; 353 handler->finished_round = process_finished_round;
@@ -296,123 +367,155 @@ void mem_bswap_64(void *src, int byte_size)
296 } 367 }
297} 368}
298 369
299static void event__all64_swap(event_t *self) 370static void perf_event__all64_swap(union perf_event *event)
300{ 371{
301 struct perf_event_header *hdr = &self->header; 372 struct perf_event_header *hdr = &event->header;
302 mem_bswap_64(hdr + 1, self->header.size - sizeof(*hdr)); 373 mem_bswap_64(hdr + 1, event->header.size - sizeof(*hdr));
303} 374}
304 375
305static void event__comm_swap(event_t *self) 376static void perf_event__comm_swap(union perf_event *event)
306{ 377{
307 self->comm.pid = bswap_32(self->comm.pid); 378 event->comm.pid = bswap_32(event->comm.pid);
308 self->comm.tid = bswap_32(self->comm.tid); 379 event->comm.tid = bswap_32(event->comm.tid);
309} 380}
310 381
311static void event__mmap_swap(event_t *self) 382static void perf_event__mmap_swap(union perf_event *event)
312{ 383{
313 self->mmap.pid = bswap_32(self->mmap.pid); 384 event->mmap.pid = bswap_32(event->mmap.pid);
314 self->mmap.tid = bswap_32(self->mmap.tid); 385 event->mmap.tid = bswap_32(event->mmap.tid);
315 self->mmap.start = bswap_64(self->mmap.start); 386 event->mmap.start = bswap_64(event->mmap.start);
316 self->mmap.len = bswap_64(self->mmap.len); 387 event->mmap.len = bswap_64(event->mmap.len);
317 self->mmap.pgoff = bswap_64(self->mmap.pgoff); 388 event->mmap.pgoff = bswap_64(event->mmap.pgoff);
318} 389}
319 390
320static void event__task_swap(event_t *self) 391static void perf_event__task_swap(union perf_event *event)
321{ 392{
322 self->fork.pid = bswap_32(self->fork.pid); 393 event->fork.pid = bswap_32(event->fork.pid);
323 self->fork.tid = bswap_32(self->fork.tid); 394 event->fork.tid = bswap_32(event->fork.tid);
324 self->fork.ppid = bswap_32(self->fork.ppid); 395 event->fork.ppid = bswap_32(event->fork.ppid);
325 self->fork.ptid = bswap_32(self->fork.ptid); 396 event->fork.ptid = bswap_32(event->fork.ptid);
326 self->fork.time = bswap_64(self->fork.time); 397 event->fork.time = bswap_64(event->fork.time);
327} 398}
328 399
329static void event__read_swap(event_t *self) 400static void perf_event__read_swap(union perf_event *event)
330{ 401{
331 self->read.pid = bswap_32(self->read.pid); 402 event->read.pid = bswap_32(event->read.pid);
332 self->read.tid = bswap_32(self->read.tid); 403 event->read.tid = bswap_32(event->read.tid);
333 self->read.value = bswap_64(self->read.value); 404 event->read.value = bswap_64(event->read.value);
334 self->read.time_enabled = bswap_64(self->read.time_enabled); 405 event->read.time_enabled = bswap_64(event->read.time_enabled);
335 self->read.time_running = bswap_64(self->read.time_running); 406 event->read.time_running = bswap_64(event->read.time_running);
336 self->read.id = bswap_64(self->read.id); 407 event->read.id = bswap_64(event->read.id);
337} 408}
338 409
339static void event__attr_swap(event_t *self) 410static void perf_event__attr_swap(union perf_event *event)
340{ 411{
341 size_t size; 412 size_t size;
342 413
343 self->attr.attr.type = bswap_32(self->attr.attr.type); 414 event->attr.attr.type = bswap_32(event->attr.attr.type);
344 self->attr.attr.size = bswap_32(self->attr.attr.size); 415 event->attr.attr.size = bswap_32(event->attr.attr.size);
345 self->attr.attr.config = bswap_64(self->attr.attr.config); 416 event->attr.attr.config = bswap_64(event->attr.attr.config);
346 self->attr.attr.sample_period = bswap_64(self->attr.attr.sample_period); 417 event->attr.attr.sample_period = bswap_64(event->attr.attr.sample_period);
347 self->attr.attr.sample_type = bswap_64(self->attr.attr.sample_type); 418 event->attr.attr.sample_type = bswap_64(event->attr.attr.sample_type);
348 self->attr.attr.read_format = bswap_64(self->attr.attr.read_format); 419 event->attr.attr.read_format = bswap_64(event->attr.attr.read_format);
349 self->attr.attr.wakeup_events = bswap_32(self->attr.attr.wakeup_events); 420 event->attr.attr.wakeup_events = bswap_32(event->attr.attr.wakeup_events);
350 self->attr.attr.bp_type = bswap_32(self->attr.attr.bp_type); 421 event->attr.attr.bp_type = bswap_32(event->attr.attr.bp_type);
351 self->attr.attr.bp_addr = bswap_64(self->attr.attr.bp_addr); 422 event->attr.attr.bp_addr = bswap_64(event->attr.attr.bp_addr);
352 self->attr.attr.bp_len = bswap_64(self->attr.attr.bp_len); 423 event->attr.attr.bp_len = bswap_64(event->attr.attr.bp_len);
353 424
354 size = self->header.size; 425 size = event->header.size;
355 size -= (void *)&self->attr.id - (void *)self; 426 size -= (void *)&event->attr.id - (void *)event;
356 mem_bswap_64(self->attr.id, size); 427 mem_bswap_64(event->attr.id, size);
357} 428}
358 429
359static void event__event_type_swap(event_t *self) 430static void perf_event__event_type_swap(union perf_event *event)
360{ 431{
361 self->event_type.event_type.event_id = 432 event->event_type.event_type.event_id =
362 bswap_64(self->event_type.event_type.event_id); 433 bswap_64(event->event_type.event_type.event_id);
363} 434}
364 435
365static void event__tracing_data_swap(event_t *self) 436static void perf_event__tracing_data_swap(union perf_event *event)
366{ 437{
367 self->tracing_data.size = bswap_32(self->tracing_data.size); 438 event->tracing_data.size = bswap_32(event->tracing_data.size);
368} 439}
369 440
370typedef void (*event__swap_op)(event_t *self); 441typedef void (*perf_event__swap_op)(union perf_event *event);
371 442
372static event__swap_op event__swap_ops[] = { 443static perf_event__swap_op perf_event__swap_ops[] = {
373 [PERF_RECORD_MMAP] = event__mmap_swap, 444 [PERF_RECORD_MMAP] = perf_event__mmap_swap,
374 [PERF_RECORD_COMM] = event__comm_swap, 445 [PERF_RECORD_COMM] = perf_event__comm_swap,
375 [PERF_RECORD_FORK] = event__task_swap, 446 [PERF_RECORD_FORK] = perf_event__task_swap,
376 [PERF_RECORD_EXIT] = event__task_swap, 447 [PERF_RECORD_EXIT] = perf_event__task_swap,
377 [PERF_RECORD_LOST] = event__all64_swap, 448 [PERF_RECORD_LOST] = perf_event__all64_swap,
378 [PERF_RECORD_READ] = event__read_swap, 449 [PERF_RECORD_READ] = perf_event__read_swap,
379 [PERF_RECORD_SAMPLE] = event__all64_swap, 450 [PERF_RECORD_SAMPLE] = perf_event__all64_swap,
380 [PERF_RECORD_HEADER_ATTR] = event__attr_swap, 451 [PERF_RECORD_HEADER_ATTR] = perf_event__attr_swap,
381 [PERF_RECORD_HEADER_EVENT_TYPE] = event__event_type_swap, 452 [PERF_RECORD_HEADER_EVENT_TYPE] = perf_event__event_type_swap,
382 [PERF_RECORD_HEADER_TRACING_DATA] = event__tracing_data_swap, 453 [PERF_RECORD_HEADER_TRACING_DATA] = perf_event__tracing_data_swap,
383 [PERF_RECORD_HEADER_BUILD_ID] = NULL, 454 [PERF_RECORD_HEADER_BUILD_ID] = NULL,
384 [PERF_RECORD_HEADER_MAX] = NULL, 455 [PERF_RECORD_HEADER_MAX] = NULL,
385}; 456};
386 457
387struct sample_queue { 458struct sample_queue {
388 u64 timestamp; 459 u64 timestamp;
389 struct sample_event *event; 460 u64 file_offset;
461 union perf_event *event;
390 struct list_head list; 462 struct list_head list;
391}; 463};
392 464
465static void perf_session_free_sample_buffers(struct perf_session *session)
466{
467 struct ordered_samples *os = &session->ordered_samples;
468
469 while (!list_empty(&os->to_free)) {
470 struct sample_queue *sq;
471
472 sq = list_entry(os->to_free.next, struct sample_queue, list);
473 list_del(&sq->list);
474 free(sq);
475 }
476}
477
478static int perf_session_deliver_event(struct perf_session *session,
479 union perf_event *event,
480 struct perf_sample *sample,
481 struct perf_event_ops *ops,
482 u64 file_offset);
483
393static void flush_sample_queue(struct perf_session *s, 484static void flush_sample_queue(struct perf_session *s,
394 struct perf_event_ops *ops) 485 struct perf_event_ops *ops)
395{ 486{
396 struct list_head *head = &s->ordered_samples.samples_head; 487 struct ordered_samples *os = &s->ordered_samples;
397 u64 limit = s->ordered_samples.next_flush; 488 struct list_head *head = &os->samples;
398 struct sample_queue *tmp, *iter; 489 struct sample_queue *tmp, *iter;
490 struct perf_sample sample;
491 u64 limit = os->next_flush;
492 u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL;
493 int ret;
399 494
400 if (!ops->ordered_samples || !limit) 495 if (!ops->ordered_samples || !limit)
401 return; 496 return;
402 497
403 list_for_each_entry_safe(iter, tmp, head, list) { 498 list_for_each_entry_safe(iter, tmp, head, list) {
404 if (iter->timestamp > limit) 499 if (iter->timestamp > limit)
405 return; 500 break;
406
407 if (iter == s->ordered_samples.last_inserted)
408 s->ordered_samples.last_inserted = NULL;
409 501
410 ops->sample((event_t *)iter->event, s); 502 ret = perf_session__parse_sample(s, iter->event, &sample);
503 if (ret)
504 pr_err("Can't parse sample, err = %d\n", ret);
505 else
506 perf_session_deliver_event(s, iter->event, &sample, ops,
507 iter->file_offset);
411 508
412 s->ordered_samples.last_flush = iter->timestamp; 509 os->last_flush = iter->timestamp;
413 list_del(&iter->list); 510 list_del(&iter->list);
414 free(iter->event); 511 list_add(&iter->list, &os->sample_cache);
415 free(iter); 512 }
513
514 if (list_empty(head)) {
515 os->last_sample = NULL;
516 } else if (last_ts <= limit) {
517 os->last_sample =
518 list_entry(head->prev, struct sample_queue, list);
416 } 519 }
417} 520}
418 521
@@ -455,7 +558,7 @@ static void flush_sample_queue(struct perf_session *s,
455 * Flush every events below timestamp 7 558 * Flush every events below timestamp 7
456 * etc... 559 * etc...
457 */ 560 */
458static int process_finished_round(event_t *event __used, 561static int process_finished_round(union perf_event *event __used,
459 struct perf_session *session, 562 struct perf_session *session,
460 struct perf_event_ops *ops) 563 struct perf_event_ops *ops)
461{ 564{
@@ -465,178 +568,277 @@ static int process_finished_round(event_t *event __used,
465 return 0; 568 return 0;
466} 569}
467 570
468static void __queue_sample_end(struct sample_queue *new, struct list_head *head)
469{
470 struct sample_queue *iter;
471
472 list_for_each_entry_reverse(iter, head, list) {
473 if (iter->timestamp < new->timestamp) {
474 list_add(&new->list, &iter->list);
475 return;
476 }
477 }
478
479 list_add(&new->list, head);
480}
481
482static void __queue_sample_before(struct sample_queue *new,
483 struct sample_queue *iter,
484 struct list_head *head)
485{
486 list_for_each_entry_continue_reverse(iter, head, list) {
487 if (iter->timestamp < new->timestamp) {
488 list_add(&new->list, &iter->list);
489 return;
490 }
491 }
492
493 list_add(&new->list, head);
494}
495
496static void __queue_sample_after(struct sample_queue *new,
497 struct sample_queue *iter,
498 struct list_head *head)
499{
500 list_for_each_entry_continue(iter, head, list) {
501 if (iter->timestamp > new->timestamp) {
502 list_add_tail(&new->list, &iter->list);
503 return;
504 }
505 }
506 list_add_tail(&new->list, head);
507}
508
509/* The queue is ordered by time */ 571/* The queue is ordered by time */
510static void __queue_sample_event(struct sample_queue *new, 572static void __queue_event(struct sample_queue *new, struct perf_session *s)
511 struct perf_session *s)
512{ 573{
513 struct sample_queue *last_inserted = s->ordered_samples.last_inserted; 574 struct ordered_samples *os = &s->ordered_samples;
514 struct list_head *head = &s->ordered_samples.samples_head; 575 struct sample_queue *sample = os->last_sample;
576 u64 timestamp = new->timestamp;
577 struct list_head *p;
515 578
579 os->last_sample = new;
516 580
517 if (!last_inserted) { 581 if (!sample) {
518 __queue_sample_end(new, head); 582 list_add(&new->list, &os->samples);
583 os->max_timestamp = timestamp;
519 return; 584 return;
520 } 585 }
521 586
522 /* 587 /*
523 * Most of the time the current event has a timestamp 588 * last_sample might point to some random place in the list as it's
524 * very close to the last event inserted, unless we just switched 589 * the last queued event. We expect that the new event is close to
525 * to another event buffer. Having a sorting based on a list and 590 * this.
526 * on the last inserted event that is close to the current one is
527 * probably more efficient than an rbtree based sorting.
528 */ 591 */
529 if (last_inserted->timestamp >= new->timestamp) 592 if (sample->timestamp <= timestamp) {
530 __queue_sample_before(new, last_inserted, head); 593 while (sample->timestamp <= timestamp) {
531 else 594 p = sample->list.next;
532 __queue_sample_after(new, last_inserted, head); 595 if (p == &os->samples) {
596 list_add_tail(&new->list, &os->samples);
597 os->max_timestamp = timestamp;
598 return;
599 }
600 sample = list_entry(p, struct sample_queue, list);
601 }
602 list_add_tail(&new->list, &sample->list);
603 } else {
604 while (sample->timestamp > timestamp) {
605 p = sample->list.prev;
606 if (p == &os->samples) {
607 list_add(&new->list, &os->samples);
608 return;
609 }
610 sample = list_entry(p, struct sample_queue, list);
611 }
612 list_add(&new->list, &sample->list);
613 }
533} 614}
534 615
535static int queue_sample_event(event_t *event, struct sample_data *data, 616#define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct sample_queue))
536 struct perf_session *s) 617
618static int perf_session_queue_event(struct perf_session *s, union perf_event *event,
619 struct perf_sample *sample, u64 file_offset)
537{ 620{
538 u64 timestamp = data->time; 621 struct ordered_samples *os = &s->ordered_samples;
622 struct list_head *sc = &os->sample_cache;
623 u64 timestamp = sample->time;
539 struct sample_queue *new; 624 struct sample_queue *new;
540 625
626 if (!timestamp || timestamp == ~0ULL)
627 return -ETIME;
541 628
542 if (timestamp < s->ordered_samples.last_flush) { 629 if (timestamp < s->ordered_samples.last_flush) {
543 printf("Warning: Timestamp below last timeslice flush\n"); 630 printf("Warning: Timestamp below last timeslice flush\n");
544 return -EINVAL; 631 return -EINVAL;
545 } 632 }
546 633
547 new = malloc(sizeof(*new)); 634 if (!list_empty(sc)) {
548 if (!new) 635 new = list_entry(sc->next, struct sample_queue, list);
549 return -ENOMEM; 636 list_del(&new->list);
637 } else if (os->sample_buffer) {
638 new = os->sample_buffer + os->sample_buffer_idx;
639 if (++os->sample_buffer_idx == MAX_SAMPLE_BUFFER)
640 os->sample_buffer = NULL;
641 } else {
642 os->sample_buffer = malloc(MAX_SAMPLE_BUFFER * sizeof(*new));
643 if (!os->sample_buffer)
644 return -ENOMEM;
645 list_add(&os->sample_buffer->list, &os->to_free);
646 os->sample_buffer_idx = 2;
647 new = os->sample_buffer + 1;
648 }
550 649
551 new->timestamp = timestamp; 650 new->timestamp = timestamp;
651 new->file_offset = file_offset;
652 new->event = event;
552 653
553 new->event = malloc(event->header.size); 654 __queue_event(new, s);
554 if (!new->event) {
555 free(new);
556 return -ENOMEM;
557 }
558 655
559 memcpy(new->event, event, event->header.size); 656 return 0;
657}
560 658
561 __queue_sample_event(new, s); 659static void callchain__printf(struct perf_sample *sample)
562 s->ordered_samples.last_inserted = new; 660{
661 unsigned int i;
563 662
564 if (new->timestamp > s->ordered_samples.max_timestamp) 663 printf("... chain: nr:%" PRIu64 "\n", sample->callchain->nr);
565 s->ordered_samples.max_timestamp = new->timestamp;
566 664
567 return 0; 665 for (i = 0; i < sample->callchain->nr; i++)
666 printf("..... %2d: %016" PRIx64 "\n",
667 i, sample->callchain->ips[i]);
568} 668}
569 669
570static int perf_session__process_sample(event_t *event, struct perf_session *s, 670static void perf_session__print_tstamp(struct perf_session *session,
571 struct perf_event_ops *ops) 671 union perf_event *event,
672 struct perf_sample *sample)
572{ 673{
573 struct sample_data data; 674 if (event->header.type != PERF_RECORD_SAMPLE &&
675 !session->sample_id_all) {
676 fputs("-1 -1 ", stdout);
677 return;
678 }
574 679
575 if (!ops->ordered_samples) 680 if ((session->sample_type & PERF_SAMPLE_CPU))
576 return ops->sample(event, s); 681 printf("%u ", sample->cpu);
577 682
578 bzero(&data, sizeof(struct sample_data)); 683 if (session->sample_type & PERF_SAMPLE_TIME)
579 event__parse_sample(event, s->sample_type, &data); 684 printf("%" PRIu64 " ", sample->time);
685}
580 686
581 queue_sample_event(event, &data, s); 687static void dump_event(struct perf_session *session, union perf_event *event,
688 u64 file_offset, struct perf_sample *sample)
689{
690 if (!dump_trace)
691 return;
582 692
583 return 0; 693 printf("\n%#" PRIx64 " [%#x]: event: %d\n",
694 file_offset, event->header.size, event->header.type);
695
696 trace_event(event);
697
698 if (sample)
699 perf_session__print_tstamp(session, event, sample);
700
701 printf("%#" PRIx64 " [%#x]: PERF_RECORD_%s", file_offset,
702 event->header.size, perf_event__name(event->header.type));
584} 703}
585 704
586static int perf_session__process_event(struct perf_session *self, 705static void dump_sample(struct perf_session *session, union perf_event *event,
587 event_t *event, 706 struct perf_sample *sample)
588 struct perf_event_ops *ops,
589 u64 offset, u64 head)
590{ 707{
591 trace_event(event); 708 if (!dump_trace)
709 return;
592 710
593 if (event->header.type < PERF_RECORD_HEADER_MAX) { 711 printf("(IP, %d): %d/%d: %#" PRIx64 " period: %" PRIu64 "\n",
594 dump_printf("%#Lx [%#x]: PERF_RECORD_%s", 712 event->header.misc, sample->pid, sample->tid, sample->ip,
595 offset + head, event->header.size, 713 sample->period);
596 event__name[event->header.type]);
597 hists__inc_nr_events(&self->hists, event->header.type);
598 }
599 714
600 if (self->header.needs_swap && event__swap_ops[event->header.type]) 715 if (session->sample_type & PERF_SAMPLE_CALLCHAIN)
601 event__swap_ops[event->header.type](event); 716 callchain__printf(sample);
717}
718
719static int perf_session_deliver_event(struct perf_session *session,
720 union perf_event *event,
721 struct perf_sample *sample,
722 struct perf_event_ops *ops,
723 u64 file_offset)
724{
725 struct perf_evsel *evsel;
726
727 dump_event(session, event, file_offset, sample);
602 728
603 switch (event->header.type) { 729 switch (event->header.type) {
604 case PERF_RECORD_SAMPLE: 730 case PERF_RECORD_SAMPLE:
605 return perf_session__process_sample(event, self, ops); 731 dump_sample(session, event, sample);
732 evsel = perf_evlist__id2evsel(session->evlist, sample->id);
733 if (evsel == NULL) {
734 ++session->hists.stats.nr_unknown_id;
735 return -1;
736 }
737 return ops->sample(event, sample, evsel, session);
606 case PERF_RECORD_MMAP: 738 case PERF_RECORD_MMAP:
607 return ops->mmap(event, self); 739 return ops->mmap(event, sample, session);
608 case PERF_RECORD_COMM: 740 case PERF_RECORD_COMM:
609 return ops->comm(event, self); 741 return ops->comm(event, sample, session);
610 case PERF_RECORD_FORK: 742 case PERF_RECORD_FORK:
611 return ops->fork(event, self); 743 return ops->fork(event, sample, session);
612 case PERF_RECORD_EXIT: 744 case PERF_RECORD_EXIT:
613 return ops->exit(event, self); 745 return ops->exit(event, sample, session);
614 case PERF_RECORD_LOST: 746 case PERF_RECORD_LOST:
615 return ops->lost(event, self); 747 return ops->lost(event, sample, session);
616 case PERF_RECORD_READ: 748 case PERF_RECORD_READ:
617 return ops->read(event, self); 749 return ops->read(event, sample, session);
618 case PERF_RECORD_THROTTLE: 750 case PERF_RECORD_THROTTLE:
619 return ops->throttle(event, self); 751 return ops->throttle(event, sample, session);
620 case PERF_RECORD_UNTHROTTLE: 752 case PERF_RECORD_UNTHROTTLE:
621 return ops->unthrottle(event, self); 753 return ops->unthrottle(event, sample, session);
754 default:
755 ++session->hists.stats.nr_unknown_events;
756 return -1;
757 }
758}
759
760static int perf_session__preprocess_sample(struct perf_session *session,
761 union perf_event *event, struct perf_sample *sample)
762{
763 if (event->header.type != PERF_RECORD_SAMPLE ||
764 !(session->sample_type & PERF_SAMPLE_CALLCHAIN))
765 return 0;
766
767 if (!ip_callchain__valid(sample->callchain, event)) {
768 pr_debug("call-chain problem with event, skipping it.\n");
769 ++session->hists.stats.nr_invalid_chains;
770 session->hists.stats.total_invalid_chains += sample->period;
771 return -EINVAL;
772 }
773 return 0;
774}
775
776static int perf_session__process_user_event(struct perf_session *session, union perf_event *event,
777 struct perf_event_ops *ops, u64 file_offset)
778{
779 dump_event(session, event, file_offset, NULL);
780
781 /* These events are processed right away */
782 switch (event->header.type) {
622 case PERF_RECORD_HEADER_ATTR: 783 case PERF_RECORD_HEADER_ATTR:
623 return ops->attr(event, self); 784 return ops->attr(event, session);
624 case PERF_RECORD_HEADER_EVENT_TYPE: 785 case PERF_RECORD_HEADER_EVENT_TYPE:
625 return ops->event_type(event, self); 786 return ops->event_type(event, session);
626 case PERF_RECORD_HEADER_TRACING_DATA: 787 case PERF_RECORD_HEADER_TRACING_DATA:
627 /* setup for reading amidst mmap */ 788 /* setup for reading amidst mmap */
628 lseek(self->fd, offset + head, SEEK_SET); 789 lseek(session->fd, file_offset, SEEK_SET);
629 return ops->tracing_data(event, self); 790 return ops->tracing_data(event, session);
630 case PERF_RECORD_HEADER_BUILD_ID: 791 case PERF_RECORD_HEADER_BUILD_ID:
631 return ops->build_id(event, self); 792 return ops->build_id(event, session);
632 case PERF_RECORD_FINISHED_ROUND: 793 case PERF_RECORD_FINISHED_ROUND:
633 return ops->finished_round(event, self, ops); 794 return ops->finished_round(event, session, ops);
634 default: 795 default:
635 ++self->hists.stats.nr_unknown_events; 796 return -EINVAL;
636 return -1;
637 } 797 }
638} 798}
639 799
800static int perf_session__process_event(struct perf_session *session,
801 union perf_event *event,
802 struct perf_event_ops *ops,
803 u64 file_offset)
804{
805 struct perf_sample sample;
806 int ret;
807
808 if (session->header.needs_swap &&
809 perf_event__swap_ops[event->header.type])
810 perf_event__swap_ops[event->header.type](event);
811
812 if (event->header.type >= PERF_RECORD_HEADER_MAX)
813 return -EINVAL;
814
815 hists__inc_nr_events(&session->hists, event->header.type);
816
817 if (event->header.type >= PERF_RECORD_USER_TYPE_START)
818 return perf_session__process_user_event(session, event, ops, file_offset);
819
820 /*
821 * For all kernel events we get the sample data
822 */
823 ret = perf_session__parse_sample(session, event, &sample);
824 if (ret)
825 return ret;
826
827 /* Preprocess sample records - precheck callchains */
828 if (perf_session__preprocess_sample(session, event, &sample))
829 return 0;
830
831 if (ops->ordered_samples) {
832 ret = perf_session_queue_event(session, event, &sample,
833 file_offset);
834 if (ret != -ETIME)
835 return ret;
836 }
837
838 return perf_session_deliver_event(session, event, &sample, ops,
839 file_offset);
840}
841
640void perf_event_header__bswap(struct perf_event_header *self) 842void perf_event_header__bswap(struct perf_event_header *self)
641{ 843{
642 self->type = bswap_32(self->type); 844 self->type = bswap_32(self->type);
@@ -656,21 +858,38 @@ static struct thread *perf_session__register_idle_thread(struct perf_session *se
656 return thread; 858 return thread;
657} 859}
658 860
659int do_read(int fd, void *buf, size_t size) 861static void perf_session__warn_about_errors(const struct perf_session *session,
862 const struct perf_event_ops *ops)
660{ 863{
661 void *buf_start = buf; 864 if (ops->lost == perf_event__process_lost &&
662 865 session->hists.stats.total_lost != 0) {
663 while (size) { 866 ui__warning("Processed %" PRIu64 " events and LOST %" PRIu64
664 int ret = read(fd, buf, size); 867 "!\n\nCheck IO/CPU overload!\n\n",
868 session->hists.stats.total_period,
869 session->hists.stats.total_lost);
870 }
665 871
666 if (ret <= 0) 872 if (session->hists.stats.nr_unknown_events != 0) {
667 return ret; 873 ui__warning("Found %u unknown events!\n\n"
874 "Is this an older tool processing a perf.data "
875 "file generated by a more recent tool?\n\n"
876 "If that is not the case, consider "
877 "reporting to linux-kernel@vger.kernel.org.\n\n",
878 session->hists.stats.nr_unknown_events);
879 }
668 880
669 size -= ret; 881 if (session->hists.stats.nr_unknown_id != 0) {
670 buf += ret; 882 ui__warning("%u samples with id not present in the header\n",
883 session->hists.stats.nr_unknown_id);
671 } 884 }
672 885
673 return buf - buf_start; 886 if (session->hists.stats.nr_invalid_chains != 0) {
887 ui__warning("Found invalid callchains!\n\n"
888 "%u out of %u events were discarded for this reason.\n\n"
889 "Consider reporting to linux-kernel@vger.kernel.org.\n\n",
890 session->hists.stats.nr_invalid_chains,
891 session->hists.stats.nr_events[PERF_RECORD_SAMPLE]);
892 }
674} 893}
675 894
676#define session_done() (*(volatile int *)(&session_done)) 895#define session_done() (*(volatile int *)(&session_done))
@@ -679,7 +898,7 @@ volatile int session_done;
679static int __perf_session__process_pipe_events(struct perf_session *self, 898static int __perf_session__process_pipe_events(struct perf_session *self,
680 struct perf_event_ops *ops) 899 struct perf_event_ops *ops)
681{ 900{
682 event_t event; 901 union perf_event event;
683 uint32_t size; 902 uint32_t size;
684 int skip = 0; 903 int skip = 0;
685 u64 head; 904 u64 head;
@@ -690,7 +909,7 @@ static int __perf_session__process_pipe_events(struct perf_session *self,
690 909
691 head = 0; 910 head = 0;
692more: 911more:
693 err = do_read(self->fd, &event, sizeof(struct perf_event_header)); 912 err = readn(self->fd, &event, sizeof(struct perf_event_header));
694 if (err <= 0) { 913 if (err <= 0) {
695 if (err == 0) 914 if (err == 0)
696 goto done; 915 goto done;
@@ -710,8 +929,7 @@ more:
710 p += sizeof(struct perf_event_header); 929 p += sizeof(struct perf_event_header);
711 930
712 if (size - sizeof(struct perf_event_header)) { 931 if (size - sizeof(struct perf_event_header)) {
713 err = do_read(self->fd, p, 932 err = readn(self->fd, p, size - sizeof(struct perf_event_header));
714 size - sizeof(struct perf_event_header));
715 if (err <= 0) { 933 if (err <= 0) {
716 if (err == 0) { 934 if (err == 0) {
717 pr_err("unexpected end of event stream\n"); 935 pr_err("unexpected end of event stream\n");
@@ -724,9 +942,8 @@ more:
724 } 942 }
725 943
726 if (size == 0 || 944 if (size == 0 ||
727 (skip = perf_session__process_event(self, &event, ops, 945 (skip = perf_session__process_event(self, &event, ops, head)) < 0) {
728 0, head)) < 0) { 946 dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n",
729 dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n",
730 head, event.header.size, event.header.type); 947 head, event.header.size, event.header.type);
731 /* 948 /*
732 * assume we lost track of the stream, check alignment, and 949 * assume we lost track of the stream, check alignment, and
@@ -740,9 +957,6 @@ more:
740 957
741 head += size; 958 head += size;
742 959
743 dump_printf("\n%#Lx [%#x]: event: %d\n",
744 head, event.header.size, event.header.type);
745
746 if (skip > 0) 960 if (skip > 0)
747 head += skip; 961 head += skip;
748 962
@@ -751,82 +965,108 @@ more:
751done: 965done:
752 err = 0; 966 err = 0;
753out_err: 967out_err:
968 perf_session__warn_about_errors(self, ops);
969 perf_session_free_sample_buffers(self);
754 return err; 970 return err;
755} 971}
756 972
757int __perf_session__process_events(struct perf_session *self, 973static union perf_event *
974fetch_mmaped_event(struct perf_session *session,
975 u64 head, size_t mmap_size, char *buf)
976{
977 union perf_event *event;
978
979 /*
980 * Ensure we have enough space remaining to read
981 * the size of the event in the headers.
982 */
983 if (head + sizeof(event->header) > mmap_size)
984 return NULL;
985
986 event = (union perf_event *)(buf + head);
987
988 if (session->header.needs_swap)
989 perf_event_header__bswap(&event->header);
990
991 if (head + event->header.size > mmap_size)
992 return NULL;
993
994 return event;
995}
996
997int __perf_session__process_events(struct perf_session *session,
758 u64 data_offset, u64 data_size, 998 u64 data_offset, u64 data_size,
759 u64 file_size, struct perf_event_ops *ops) 999 u64 file_size, struct perf_event_ops *ops)
760{ 1000{
761 int err, mmap_prot, mmap_flags; 1001 u64 head, page_offset, file_offset, file_pos, progress_next;
762 u64 head, shift; 1002 int err, mmap_prot, mmap_flags, map_idx = 0;
763 u64 offset = 0; 1003 struct ui_progress *progress;
764 size_t page_size; 1004 size_t page_size, mmap_size;
765 event_t *event; 1005 char *buf, *mmaps[8];
1006 union perf_event *event;
766 uint32_t size; 1007 uint32_t size;
767 char *buf;
768 struct ui_progress *progress = ui_progress__new("Processing events...",
769 self->size);
770 if (progress == NULL)
771 return -1;
772 1008
773 perf_event_ops__fill_defaults(ops); 1009 perf_event_ops__fill_defaults(ops);
774 1010
775 page_size = sysconf(_SC_PAGESIZE); 1011 page_size = sysconf(_SC_PAGESIZE);
776 1012
777 head = data_offset; 1013 page_offset = page_size * (data_offset / page_size);
778 shift = page_size * (head / page_size); 1014 file_offset = page_offset;
779 offset += shift; 1015 head = data_offset - page_offset;
780 head -= shift; 1016
1017 if (data_offset + data_size < file_size)
1018 file_size = data_offset + data_size;
1019
1020 progress_next = file_size / 16;
1021 progress = ui_progress__new("Processing events...", file_size);
1022 if (progress == NULL)
1023 return -1;
1024
1025 mmap_size = session->mmap_window;
1026 if (mmap_size > file_size)
1027 mmap_size = file_size;
1028
1029 memset(mmaps, 0, sizeof(mmaps));
781 1030
782 mmap_prot = PROT_READ; 1031 mmap_prot = PROT_READ;
783 mmap_flags = MAP_SHARED; 1032 mmap_flags = MAP_SHARED;
784 1033
785 if (self->header.needs_swap) { 1034 if (session->header.needs_swap) {
786 mmap_prot |= PROT_WRITE; 1035 mmap_prot |= PROT_WRITE;
787 mmap_flags = MAP_PRIVATE; 1036 mmap_flags = MAP_PRIVATE;
788 } 1037 }
789remap: 1038remap:
790 buf = mmap(NULL, page_size * self->mmap_window, mmap_prot, 1039 buf = mmap(NULL, mmap_size, mmap_prot, mmap_flags, session->fd,
791 mmap_flags, self->fd, offset); 1040 file_offset);
792 if (buf == MAP_FAILED) { 1041 if (buf == MAP_FAILED) {
793 pr_err("failed to mmap file\n"); 1042 pr_err("failed to mmap file\n");
794 err = -errno; 1043 err = -errno;
795 goto out_err; 1044 goto out_err;
796 } 1045 }
1046 mmaps[map_idx] = buf;
1047 map_idx = (map_idx + 1) & (ARRAY_SIZE(mmaps) - 1);
1048 file_pos = file_offset + head;
797 1049
798more: 1050more:
799 event = (event_t *)(buf + head); 1051 event = fetch_mmaped_event(session, head, mmap_size, buf);
800 ui_progress__update(progress, offset); 1052 if (!event) {
801 1053 if (mmaps[map_idx]) {
802 if (self->header.needs_swap) 1054 munmap(mmaps[map_idx], mmap_size);
803 perf_event_header__bswap(&event->header); 1055 mmaps[map_idx] = NULL;
804 size = event->header.size; 1056 }
805 if (size == 0)
806 size = 8;
807
808 if (head + event->header.size >= page_size * self->mmap_window) {
809 int munmap_ret;
810
811 shift = page_size * (head / page_size);
812
813 munmap_ret = munmap(buf, page_size * self->mmap_window);
814 assert(munmap_ret == 0);
815 1057
816 offset += shift; 1058 page_offset = page_size * (head / page_size);
817 head -= shift; 1059 file_offset += page_offset;
1060 head -= page_offset;
818 goto remap; 1061 goto remap;
819 } 1062 }
820 1063
821 size = event->header.size; 1064 size = event->header.size;
822 1065
823 dump_printf("\n%#Lx [%#x]: event: %d\n",
824 offset + head, event->header.size, event->header.type);
825
826 if (size == 0 || 1066 if (size == 0 ||
827 perf_session__process_event(self, event, ops, offset, head) < 0) { 1067 perf_session__process_event(session, event, ops, file_pos) < 0) {
828 dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n", 1068 dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n",
829 offset + head, event->header.size, 1069 file_offset + head, event->header.size,
830 event->header.type); 1070 event->header.type);
831 /* 1071 /*
832 * assume we lost track of the stream, check alignment, and 1072 * assume we lost track of the stream, check alignment, and
@@ -839,19 +1079,24 @@ more:
839 } 1079 }
840 1080
841 head += size; 1081 head += size;
1082 file_pos += size;
842 1083
843 if (offset + head >= data_offset + data_size) 1084 if (file_pos >= progress_next) {
844 goto done; 1085 progress_next += file_size / 16;
1086 ui_progress__update(progress, file_pos);
1087 }
845 1088
846 if (offset + head < file_size) 1089 if (file_pos < file_size)
847 goto more; 1090 goto more;
848done: 1091
849 err = 0; 1092 err = 0;
850 /* do the final flush for ordered samples */ 1093 /* do the final flush for ordered samples */
851 self->ordered_samples.next_flush = ULLONG_MAX; 1094 session->ordered_samples.next_flush = ULLONG_MAX;
852 flush_sample_queue(self, ops); 1095 flush_sample_queue(session, ops);
853out_err: 1096out_err:
854 ui_progress__delete(progress); 1097 ui_progress__delete(progress);
1098 perf_session__warn_about_errors(session, ops);
1099 perf_session_free_sample_buffers(session);
855 return err; 1100 return err;
856} 1101}
857 1102
@@ -929,3 +1174,91 @@ size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp,
929 size_t ret = machine__fprintf_dsos_buildid(&self->host_machine, fp, with_hits); 1174 size_t ret = machine__fprintf_dsos_buildid(&self->host_machine, fp, with_hits);
930 return ret + machines__fprintf_dsos_buildid(&self->machines, fp, with_hits); 1175 return ret + machines__fprintf_dsos_buildid(&self->machines, fp, with_hits);
931} 1176}
1177
1178size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
1179{
1180 struct perf_evsel *pos;
1181 size_t ret = fprintf(fp, "Aggregated stats:\n");
1182
1183 ret += hists__fprintf_nr_events(&session->hists, fp);
1184
1185 list_for_each_entry(pos, &session->evlist->entries, node) {
1186 ret += fprintf(fp, "%s stats:\n", event_name(pos));
1187 ret += hists__fprintf_nr_events(&pos->hists, fp);
1188 }
1189
1190 return ret;
1191}
1192
1193struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
1194 unsigned int type)
1195{
1196 struct perf_evsel *pos;
1197
1198 list_for_each_entry(pos, &session->evlist->entries, node) {
1199 if (pos->attr.type == type)
1200 return pos;
1201 }
1202 return NULL;
1203}
1204
1205void perf_session__print_symbols(union perf_event *event,
1206 struct perf_sample *sample,
1207 struct perf_session *session)
1208{
1209 struct addr_location al;
1210 const char *symname, *dsoname;
1211 struct callchain_cursor *cursor = &session->callchain_cursor;
1212 struct callchain_cursor_node *node;
1213
1214 if (perf_event__preprocess_sample(event, session, &al, sample,
1215 NULL) < 0) {
1216 error("problem processing %d event, skipping it.\n",
1217 event->header.type);
1218 return;
1219 }
1220
1221 if (symbol_conf.use_callchain && sample->callchain) {
1222
1223 if (perf_session__resolve_callchain(session, al.thread,
1224 sample->callchain, NULL) != 0) {
1225 if (verbose)
1226 error("Failed to resolve callchain. Skipping\n");
1227 return;
1228 }
1229 callchain_cursor_commit(cursor);
1230
1231 while (1) {
1232 node = callchain_cursor_current(cursor);
1233 if (!node)
1234 break;
1235
1236 if (node->sym && node->sym->name)
1237 symname = node->sym->name;
1238 else
1239 symname = "";
1240
1241 if (node->map && node->map->dso && node->map->dso->name)
1242 dsoname = node->map->dso->name;
1243 else
1244 dsoname = "";
1245
1246 printf("\t%16" PRIx64 " %s (%s)\n", node->ip, symname, dsoname);
1247
1248 callchain_cursor_advance(cursor);
1249 }
1250
1251 } else {
1252 if (al.sym && al.sym->name)
1253 symname = al.sym->name;
1254 else
1255 symname = "";
1256
1257 if (al.map && al.map->dso && al.map->dso->name)
1258 dsoname = al.map->dso->name;
1259 else
1260 dsoname = "";
1261
1262 printf("%16" PRIx64 " %s (%s)", al.addr, symname, dsoname);
1263 }
1264}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 9fa0fc2a863f..66d4e1490879 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -17,8 +17,12 @@ struct ordered_samples {
17 u64 last_flush; 17 u64 last_flush;
18 u64 next_flush; 18 u64 next_flush;
19 u64 max_timestamp; 19 u64 max_timestamp;
20 struct list_head samples_head; 20 struct list_head samples;
21 struct sample_queue *last_inserted; 21 struct list_head sample_cache;
22 struct list_head to_free;
23 struct sample_queue *sample_buffer;
24 struct sample_queue *last_sample;
25 int sample_buffer_idx;
22}; 26};
23 27
24struct perf_session { 28struct perf_session {
@@ -30,49 +34,62 @@ struct perf_session {
30 struct thread *last_match; 34 struct thread *last_match;
31 struct machine host_machine; 35 struct machine host_machine;
32 struct rb_root machines; 36 struct rb_root machines;
33 struct rb_root hists_tree; 37 struct perf_evlist *evlist;
34 /* 38 /*
35 * FIXME: should point to the first entry in hists_tree and 39 * FIXME: Need to split this up further, we need global
36 * be a hists instance. Right now its only 'report' 40 * stats + per event stats. 'perf diff' also needs
37 * that is using ->hists_tree while all the rest use 41 * to properly support multiple events in a single
38 * ->hists. 42 * perf.data file.
39 */ 43 */
40 struct hists hists; 44 struct hists hists;
41 u64 sample_type; 45 u64 sample_type;
46 int sample_size;
42 int fd; 47 int fd;
43 bool fd_pipe; 48 bool fd_pipe;
44 bool repipe; 49 bool repipe;
50 bool sample_id_all;
51 u16 id_hdr_size;
45 int cwdlen; 52 int cwdlen;
46 char *cwd; 53 char *cwd;
47 struct ordered_samples ordered_samples; 54 struct ordered_samples ordered_samples;
48 char filename[0]; 55 struct callchain_cursor callchain_cursor;
56 char filename[0];
49}; 57};
50 58
59struct perf_evsel;
51struct perf_event_ops; 60struct perf_event_ops;
52 61
53typedef int (*event_op)(event_t *self, struct perf_session *session); 62typedef int (*event_sample)(union perf_event *event, struct perf_sample *sample,
54typedef int (*event_op2)(event_t *self, struct perf_session *session, 63 struct perf_evsel *evsel, struct perf_session *session);
64typedef int (*event_op)(union perf_event *self, struct perf_sample *sample,
65 struct perf_session *session);
66typedef int (*event_synth_op)(union perf_event *self,
67 struct perf_session *session);
68typedef int (*event_op2)(union perf_event *self, struct perf_session *session,
55 struct perf_event_ops *ops); 69 struct perf_event_ops *ops);
56 70
57struct perf_event_ops { 71struct perf_event_ops {
58 event_op sample, 72 event_sample sample;
59 mmap, 73 event_op mmap,
60 comm, 74 comm,
61 fork, 75 fork,
62 exit, 76 exit,
63 lost, 77 lost,
64 read, 78 read,
65 throttle, 79 throttle,
66 unthrottle, 80 unthrottle;
67 attr, 81 event_synth_op attr,
68 event_type, 82 event_type,
69 tracing_data, 83 tracing_data,
70 build_id; 84 build_id;
71 event_op2 finished_round; 85 event_op2 finished_round;
72 bool ordered_samples; 86 bool ordered_samples;
87 bool ordering_requires_timestamps;
73}; 88};
74 89
75struct perf_session *perf_session__new(const char *filename, int mode, bool force, bool repipe); 90struct perf_session *perf_session__new(const char *filename, int mode,
91 bool force, bool repipe,
92 struct perf_event_ops *ops);
76void perf_session__delete(struct perf_session *self); 93void perf_session__delete(struct perf_session *self);
77 94
78void perf_event_header__bswap(struct perf_event_header *self); 95void perf_event_header__bswap(struct perf_event_header *self);
@@ -83,10 +100,10 @@ int __perf_session__process_events(struct perf_session *self,
83int perf_session__process_events(struct perf_session *self, 100int perf_session__process_events(struct perf_session *self,
84 struct perf_event_ops *event_ops); 101 struct perf_event_ops *event_ops);
85 102
86struct map_symbol *perf_session__resolve_callchain(struct perf_session *self, 103int perf_session__resolve_callchain(struct perf_session *self,
87 struct thread *thread, 104 struct thread *thread,
88 struct ip_callchain *chain, 105 struct ip_callchain *chain,
89 struct symbol **parent); 106 struct symbol **parent);
90 107
91bool perf_session__has_traces(struct perf_session *self, const char *msg); 108bool perf_session__has_traces(struct perf_session *self, const char *msg);
92 109
@@ -98,7 +115,6 @@ void mem_bswap_64(void *src, int byte_size);
98 115
99int perf_session__create_kernel_maps(struct perf_session *self); 116int perf_session__create_kernel_maps(struct perf_session *self);
100 117
101int do_read(int fd, void *buf, size_t size);
102void perf_session__update_sample_type(struct perf_session *self); 118void perf_session__update_sample_type(struct perf_session *self);
103void perf_session__remove_thread(struct perf_session *self, struct thread *th); 119void perf_session__remove_thread(struct perf_session *self, struct thread *th);
104 120
@@ -137,9 +153,22 @@ size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp);
137size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, 153size_t perf_session__fprintf_dsos_buildid(struct perf_session *self,
138 FILE *fp, bool with_hits); 154 FILE *fp, bool with_hits);
139 155
140static inline 156size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp);
141size_t perf_session__fprintf_nr_events(struct perf_session *self, FILE *fp) 157
158static inline int perf_session__parse_sample(struct perf_session *session,
159 const union perf_event *event,
160 struct perf_sample *sample)
142{ 161{
143 return hists__fprintf_nr_events(&self->hists, fp); 162 return perf_event__parse_sample(event, session->sample_type,
163 session->sample_size,
164 session->sample_id_all, sample);
144} 165}
166
167struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
168 unsigned int type);
169
170void perf_session__print_symbols(union perf_event *event,
171 struct perf_sample *sample,
172 struct perf_session *session);
173
145#endif /* __PERF_SESSION_H */ 174#endif /* __PERF_SESSION_H */
diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py
new file mode 100644
index 000000000000..bbc982f5dd8b
--- /dev/null
+++ b/tools/perf/util/setup.py
@@ -0,0 +1,24 @@
1#!/usr/bin/python2
2
3from distutils.core import setup, Extension
4from os import getenv
5
6cflags = ['-fno-strict-aliasing', '-Wno-write-strings']
7cflags += getenv('CFLAGS', '').split()
8
9perf = Extension('perf',
10 sources = ['util/python.c', 'util/ctype.c', 'util/evlist.c',
11 'util/evsel.c', 'util/cpumap.c', 'util/thread_map.c',
12 'util/util.c', 'util/xyarray.c', 'util/cgroup.c'],
13 include_dirs = ['util/include'],
14 extra_compile_args = cflags,
15 )
16
17setup(name='perf',
18 version='0.1',
19 description='Interface with the Linux profiling infrastructure',
20 author='Arnaldo Carvalho de Melo',
21 author_email='acme@redhat.com',
22 license='GPLv2',
23 url='http://perf.wiki.kernel.org',
24 ext_modules=[perf])
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index b62a553cc67d..f44fa541d56e 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -170,7 +170,7 @@ static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf,
170 return repsep_snprintf(bf, size, "%-*s", width, dso_name); 170 return repsep_snprintf(bf, size, "%-*s", width, dso_name);
171 } 171 }
172 172
173 return repsep_snprintf(bf, size, "%*Lx", width, self->ip); 173 return repsep_snprintf(bf, size, "%-*s", width, "[unknown]");
174} 174}
175 175
176/* --sort symbol */ 176/* --sort symbol */
@@ -196,7 +196,7 @@ static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
196 196
197 if (verbose) { 197 if (verbose) {
198 char o = self->ms.map ? dso__symtab_origin(self->ms.map->dso) : '!'; 198 char o = self->ms.map ? dso__symtab_origin(self->ms.map->dso) : '!';
199 ret += repsep_snprintf(bf, size, "%*Lx %c ", 199 ret += repsep_snprintf(bf, size, "%-#*llx %c ",
200 BITS_PER_LONG / 4, self->ip, o); 200 BITS_PER_LONG / 4, self->ip, o);
201 } 201 }
202 202
@@ -205,7 +205,7 @@ static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
205 ret += repsep_snprintf(bf + ret, size - ret, "%s", 205 ret += repsep_snprintf(bf + ret, size - ret, "%s",
206 self->ms.sym->name); 206 self->ms.sym->name);
207 else 207 else
208 ret += repsep_snprintf(bf + ret, size - ret, "%*Lx", 208 ret += repsep_snprintf(bf + ret, size - ret, "%-#*llx",
209 BITS_PER_LONG / 4, self->ip); 209 BITS_PER_LONG / 4, self->ip);
210 210
211 return ret; 211 return ret;
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 46e531d09e8b..0b91053a7d11 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -70,7 +70,7 @@ struct hist_entry {
70 struct hist_entry *pair; 70 struct hist_entry *pair;
71 struct rb_root sorted_chain; 71 struct rb_root sorted_chain;
72 }; 72 };
73 struct callchain_node callchain[0]; 73 struct callchain_root callchain[0];
74}; 74};
75 75
76enum sort_type { 76enum sort_type {
diff --git a/tools/perf/util/strfilter.c b/tools/perf/util/strfilter.c
new file mode 100644
index 000000000000..834c8ebfe38e
--- /dev/null
+++ b/tools/perf/util/strfilter.c
@@ -0,0 +1,199 @@
1#include "util.h"
2#include "string.h"
3#include "strfilter.h"
4
5/* Operators */
6static const char *OP_and = "&"; /* Logical AND */
7static const char *OP_or = "|"; /* Logical OR */
8static const char *OP_not = "!"; /* Logical NOT */
9
10#define is_operator(c) ((c) == '|' || (c) == '&' || (c) == '!')
11#define is_separator(c) (is_operator(c) || (c) == '(' || (c) == ')')
12
13static void strfilter_node__delete(struct strfilter_node *self)
14{
15 if (self) {
16 if (self->p && !is_operator(*self->p))
17 free((char *)self->p);
18 strfilter_node__delete(self->l);
19 strfilter_node__delete(self->r);
20 free(self);
21 }
22}
23
24void strfilter__delete(struct strfilter *self)
25{
26 if (self) {
27 strfilter_node__delete(self->root);
28 free(self);
29 }
30}
31
32static const char *get_token(const char *s, const char **e)
33{
34 const char *p;
35
36 while (isspace(*s)) /* Skip spaces */
37 s++;
38
39 if (*s == '\0') {
40 p = s;
41 goto end;
42 }
43
44 p = s + 1;
45 if (!is_separator(*s)) {
46 /* End search */
47retry:
48 while (*p && !is_separator(*p) && !isspace(*p))
49 p++;
50 /* Escape and special case: '!' is also used in glob pattern */
51 if (*(p - 1) == '\\' || (*p == '!' && *(p - 1) == '[')) {
52 p++;
53 goto retry;
54 }
55 }
56end:
57 *e = p;
58 return s;
59}
60
61static struct strfilter_node *strfilter_node__alloc(const char *op,
62 struct strfilter_node *l,
63 struct strfilter_node *r)
64{
65 struct strfilter_node *ret = zalloc(sizeof(struct strfilter_node));
66
67 if (ret) {
68 ret->p = op;
69 ret->l = l;
70 ret->r = r;
71 }
72
73 return ret;
74}
75
76static struct strfilter_node *strfilter_node__new(const char *s,
77 const char **ep)
78{
79 struct strfilter_node root, *cur, *last_op;
80 const char *e;
81
82 if (!s)
83 return NULL;
84
85 memset(&root, 0, sizeof(root));
86 last_op = cur = &root;
87
88 s = get_token(s, &e);
89 while (*s != '\0' && *s != ')') {
90 switch (*s) {
91 case '&': /* Exchg last OP->r with AND */
92 if (!cur->r || !last_op->r)
93 goto error;
94 cur = strfilter_node__alloc(OP_and, last_op->r, NULL);
95 if (!cur)
96 goto nomem;
97 last_op->r = cur;
98 last_op = cur;
99 break;
100 case '|': /* Exchg the root with OR */
101 if (!cur->r || !root.r)
102 goto error;
103 cur = strfilter_node__alloc(OP_or, root.r, NULL);
104 if (!cur)
105 goto nomem;
106 root.r = cur;
107 last_op = cur;
108 break;
109 case '!': /* Add NOT as a leaf node */
110 if (cur->r)
111 goto error;
112 cur->r = strfilter_node__alloc(OP_not, NULL, NULL);
113 if (!cur->r)
114 goto nomem;
115 cur = cur->r;
116 break;
117 case '(': /* Recursively parses inside the parenthesis */
118 if (cur->r)
119 goto error;
120 cur->r = strfilter_node__new(s + 1, &s);
121 if (!s)
122 goto nomem;
123 if (!cur->r || *s != ')')
124 goto error;
125 e = s + 1;
126 break;
127 default:
128 if (cur->r)
129 goto error;
130 cur->r = strfilter_node__alloc(NULL, NULL, NULL);
131 if (!cur->r)
132 goto nomem;
133 cur->r->p = strndup(s, e - s);
134 if (!cur->r->p)
135 goto nomem;
136 }
137 s = get_token(e, &e);
138 }
139 if (!cur->r)
140 goto error;
141 *ep = s;
142 return root.r;
143nomem:
144 s = NULL;
145error:
146 *ep = s;
147 strfilter_node__delete(root.r);
148 return NULL;
149}
150
151/*
152 * Parse filter rule and return new strfilter.
153 * Return NULL if fail, and *ep == NULL if memory allocation failed.
154 */
155struct strfilter *strfilter__new(const char *rules, const char **err)
156{
157 struct strfilter *ret = zalloc(sizeof(struct strfilter));
158 const char *ep = NULL;
159
160 if (ret)
161 ret->root = strfilter_node__new(rules, &ep);
162
163 if (!ret || !ret->root || *ep != '\0') {
164 if (err)
165 *err = ep;
166 strfilter__delete(ret);
167 ret = NULL;
168 }
169
170 return ret;
171}
172
173static bool strfilter_node__compare(struct strfilter_node *self,
174 const char *str)
175{
176 if (!self || !self->p)
177 return false;
178
179 switch (*self->p) {
180 case '|': /* OR */
181 return strfilter_node__compare(self->l, str) ||
182 strfilter_node__compare(self->r, str);
183 case '&': /* AND */
184 return strfilter_node__compare(self->l, str) &&
185 strfilter_node__compare(self->r, str);
186 case '!': /* NOT */
187 return !strfilter_node__compare(self->r, str);
188 default:
189 return strglobmatch(str, self->p);
190 }
191}
192
193/* Return true if STR matches the filter rules */
194bool strfilter__compare(struct strfilter *self, const char *str)
195{
196 if (!self)
197 return false;
198 return strfilter_node__compare(self->root, str);
199}
diff --git a/tools/perf/util/strfilter.h b/tools/perf/util/strfilter.h
new file mode 100644
index 000000000000..00f58a7506de
--- /dev/null
+++ b/tools/perf/util/strfilter.h
@@ -0,0 +1,48 @@
1#ifndef __PERF_STRFILTER_H
2#define __PERF_STRFILTER_H
3/* General purpose glob matching filter */
4
5#include <linux/list.h>
6#include <stdbool.h>
7
8/* A node of string filter */
9struct strfilter_node {
10 struct strfilter_node *l; /* Tree left branche (for &,|) */
11 struct strfilter_node *r; /* Tree right branche (for !,&,|) */
12 const char *p; /* Operator or rule */
13};
14
15/* String filter */
16struct strfilter {
17 struct strfilter_node *root;
18};
19
20/**
21 * strfilter__new - Create a new string filter
22 * @rules: Filter rule, which is a combination of glob expressions.
23 * @err: Pointer which points an error detected on @rules
24 *
25 * Parse @rules and return new strfilter. Return NULL if an error detected.
26 * In that case, *@err will indicate where it is detected, and *@err is NULL
27 * if a memory allocation is failed.
28 */
29struct strfilter *strfilter__new(const char *rules, const char **err);
30
31/**
32 * strfilter__compare - compare given string and a string filter
33 * @self: String filter
34 * @str: target string
35 *
36 * Compare @str and @self. Return true if the str match the rule
37 */
38bool strfilter__compare(struct strfilter *self, const char *str);
39
40/**
41 * strfilter__delete - delete a string filter
42 * @self: String filter to delete
43 *
44 * Delete @self.
45 */
46void strfilter__delete(struct strfilter *self);
47
48#endif
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index 0409fc7c0058..b9a985dadd08 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -85,7 +85,7 @@ out:
85 85
86/* 86/*
87 * Helper function for splitting a string into an argv-like array. 87 * Helper function for splitting a string into an argv-like array.
88 * originaly copied from lib/argv_split.c 88 * originally copied from lib/argv_split.c
89 */ 89 */
90static const char *skip_sep(const char *cp) 90static const char *skip_sep(const char *cp)
91{ 91{
@@ -259,7 +259,7 @@ static bool __match_glob(const char *str, const char *pat, bool ignore_space)
259 if (!*pat) /* Tail wild card matches all */ 259 if (!*pat) /* Tail wild card matches all */
260 return true; 260 return true;
261 while (*str) 261 while (*str)
262 if (strglobmatch(str++, pat)) 262 if (__match_glob(str++, pat, ignore_space))
263 return true; 263 return true;
264 } 264 }
265 return !*str && !*pat; 265 return !*str && !*pat;
diff --git a/tools/perf/util/svghelper.c b/tools/perf/util/svghelper.c
index b3637db025a2..96c866045d60 100644
--- a/tools/perf/util/svghelper.c
+++ b/tools/perf/util/svghelper.c
@@ -12,6 +12,7 @@
12 * of the License. 12 * of the License.
13 */ 13 */
14 14
15#include <inttypes.h>
15#include <stdio.h> 16#include <stdio.h>
16#include <stdlib.h> 17#include <stdlib.h>
17#include <unistd.h> 18#include <unistd.h>
@@ -43,11 +44,11 @@ static double cpu2y(int cpu)
43 return cpu2slot(cpu) * SLOT_MULT; 44 return cpu2slot(cpu) * SLOT_MULT;
44} 45}
45 46
46static double time2pixels(u64 time) 47static double time2pixels(u64 __time)
47{ 48{
48 double X; 49 double X;
49 50
50 X = 1.0 * svg_page_width * (time - first_time) / (last_time - first_time); 51 X = 1.0 * svg_page_width * (__time - first_time) / (last_time - first_time);
51 return X; 52 return X;
52} 53}
53 54
@@ -94,7 +95,7 @@ void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end)
94 95
95 total_height = (1 + rows + cpu2slot(cpus)) * SLOT_MULT; 96 total_height = (1 + rows + cpu2slot(cpus)) * SLOT_MULT;
96 fprintf(svgfile, "<?xml version=\"1.0\" standalone=\"no\"?> \n"); 97 fprintf(svgfile, "<?xml version=\"1.0\" standalone=\"no\"?> \n");
97 fprintf(svgfile, "<svg width=\"%i\" height=\"%llu\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n", svg_page_width, total_height); 98 fprintf(svgfile, "<svg width=\"%i\" height=\"%" PRIu64 "\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n", svg_page_width, total_height);
98 99
99 fprintf(svgfile, "<defs>\n <style type=\"text/css\">\n <![CDATA[\n"); 100 fprintf(svgfile, "<defs>\n <style type=\"text/css\">\n <![CDATA[\n");
100 101
@@ -455,9 +456,9 @@ void svg_legenda(void)
455 return; 456 return;
456 457
457 svg_legenda_box(0, "Running", "sample"); 458 svg_legenda_box(0, "Running", "sample");
458 svg_legenda_box(100, "Idle","rect.c1"); 459 svg_legenda_box(100, "Idle","c1");
459 svg_legenda_box(200, "Deeper Idle", "rect.c3"); 460 svg_legenda_box(200, "Deeper Idle", "c3");
460 svg_legenda_box(350, "Deepest Idle", "rect.c6"); 461 svg_legenda_box(350, "Deepest Idle", "c6");
461 svg_legenda_box(550, "Sleeping", "process2"); 462 svg_legenda_box(550, "Sleeping", "process2");
462 svg_legenda_box(650, "Waiting for cpu", "waiting"); 463 svg_legenda_box(650, "Waiting for cpu", "waiting");
463 svg_legenda_box(800, "Blocked on IO", "blocked"); 464 svg_legenda_box(800, "Blocked on IO", "blocked");
@@ -483,7 +484,7 @@ void svg_time_grid(void)
483 color = 128; 484 color = 128;
484 } 485 }
485 486
486 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%llu\" style=\"stroke:rgb(%i,%i,%i);stroke-width:%1.3f\"/>\n", 487 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%" PRIu64 "\" style=\"stroke:rgb(%i,%i,%i);stroke-width:%1.3f\"/>\n",
487 time2pixels(i), SLOT_MULT/2, time2pixels(i), total_height, color, color, color, thickness); 488 time2pixels(i), SLOT_MULT/2, time2pixels(i), total_height, color, color, color, thickness);
488 489
489 i += 10000000; 490 i += 10000000;
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index b2f5ae97f33d..eec196329fd9 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -11,6 +11,7 @@
11#include <sys/param.h> 11#include <sys/param.h>
12#include <fcntl.h> 12#include <fcntl.h>
13#include <unistd.h> 13#include <unistd.h>
14#include <inttypes.h>
14#include "build-id.h" 15#include "build-id.h"
15#include "debug.h" 16#include "debug.h"
16#include "symbol.h" 17#include "symbol.h"
@@ -22,17 +23,21 @@
22#include <limits.h> 23#include <limits.h>
23#include <sys/utsname.h> 24#include <sys/utsname.h>
24 25
26#ifndef KSYM_NAME_LEN
27#define KSYM_NAME_LEN 128
28#endif
29
25#ifndef NT_GNU_BUILD_ID 30#ifndef NT_GNU_BUILD_ID
26#define NT_GNU_BUILD_ID 3 31#define NT_GNU_BUILD_ID 3
27#endif 32#endif
28 33
29static bool dso__build_id_equal(const struct dso *self, u8 *build_id); 34static bool dso__build_id_equal(const struct dso *dso, u8 *build_id);
30static int elf_read_build_id(Elf *elf, void *bf, size_t size); 35static int elf_read_build_id(Elf *elf, void *bf, size_t size);
31static void dsos__add(struct list_head *head, struct dso *dso); 36static void dsos__add(struct list_head *head, struct dso *dso);
32static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 37static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
33static int dso__load_kernel_sym(struct dso *self, struct map *map, 38static int dso__load_kernel_sym(struct dso *dso, struct map *map,
34 symbol_filter_t filter); 39 symbol_filter_t filter);
35static int dso__load_guest_kernel_sym(struct dso *self, struct map *map, 40static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
36 symbol_filter_t filter); 41 symbol_filter_t filter);
37static int vmlinux_path__nr_entries; 42static int vmlinux_path__nr_entries;
38static char **vmlinux_path; 43static char **vmlinux_path;
@@ -41,29 +46,30 @@ struct symbol_conf symbol_conf = {
41 .exclude_other = true, 46 .exclude_other = true,
42 .use_modules = true, 47 .use_modules = true,
43 .try_vmlinux_path = true, 48 .try_vmlinux_path = true,
49 .symfs = "",
44}; 50};
45 51
46int dso__name_len(const struct dso *self) 52int dso__name_len(const struct dso *dso)
47{ 53{
48 if (verbose) 54 if (verbose)
49 return self->long_name_len; 55 return dso->long_name_len;
50 56
51 return self->short_name_len; 57 return dso->short_name_len;
52} 58}
53 59
54bool dso__loaded(const struct dso *self, enum map_type type) 60bool dso__loaded(const struct dso *dso, enum map_type type)
55{ 61{
56 return self->loaded & (1 << type); 62 return dso->loaded & (1 << type);
57} 63}
58 64
59bool dso__sorted_by_name(const struct dso *self, enum map_type type) 65bool dso__sorted_by_name(const struct dso *dso, enum map_type type)
60{ 66{
61 return self->sorted_by_name & (1 << type); 67 return dso->sorted_by_name & (1 << type);
62} 68}
63 69
64static void dso__set_sorted_by_name(struct dso *self, enum map_type type) 70static void dso__set_sorted_by_name(struct dso *dso, enum map_type type)
65{ 71{
66 self->sorted_by_name |= (1 << type); 72 dso->sorted_by_name |= (1 << type);
67} 73}
68 74
69bool symbol_type__is_a(char symbol_type, enum map_type map_type) 75bool symbol_type__is_a(char symbol_type, enum map_type map_type)
@@ -78,9 +84,9 @@ bool symbol_type__is_a(char symbol_type, enum map_type map_type)
78 } 84 }
79} 85}
80 86
81static void symbols__fixup_end(struct rb_root *self) 87static void symbols__fixup_end(struct rb_root *symbols)
82{ 88{
83 struct rb_node *nd, *prevnd = rb_first(self); 89 struct rb_node *nd, *prevnd = rb_first(symbols);
84 struct symbol *curr, *prev; 90 struct symbol *curr, *prev;
85 91
86 if (prevnd == NULL) 92 if (prevnd == NULL)
@@ -92,7 +98,7 @@ static void symbols__fixup_end(struct rb_root *self)
92 prev = curr; 98 prev = curr;
93 curr = rb_entry(nd, struct symbol, rb_node); 99 curr = rb_entry(nd, struct symbol, rb_node);
94 100
95 if (prev->end == prev->start) 101 if (prev->end == prev->start && prev->end != curr->start)
96 prev->end = curr->start - 1; 102 prev->end = curr->start - 1;
97 } 103 }
98 104
@@ -101,10 +107,10 @@ static void symbols__fixup_end(struct rb_root *self)
101 curr->end = roundup(curr->start, 4096); 107 curr->end = roundup(curr->start, 4096);
102} 108}
103 109
104static void __map_groups__fixup_end(struct map_groups *self, enum map_type type) 110static void __map_groups__fixup_end(struct map_groups *mg, enum map_type type)
105{ 111{
106 struct map *prev, *curr; 112 struct map *prev, *curr;
107 struct rb_node *nd, *prevnd = rb_first(&self->maps[type]); 113 struct rb_node *nd, *prevnd = rb_first(&mg->maps[type]);
108 114
109 if (prevnd == NULL) 115 if (prevnd == NULL)
110 return; 116 return;
@@ -121,132 +127,131 @@ static void __map_groups__fixup_end(struct map_groups *self, enum map_type type)
121 * We still haven't the actual symbols, so guess the 127 * We still haven't the actual symbols, so guess the
122 * last map final address. 128 * last map final address.
123 */ 129 */
124 curr->end = ~0UL; 130 curr->end = ~0ULL;
125} 131}
126 132
127static void map_groups__fixup_end(struct map_groups *self) 133static void map_groups__fixup_end(struct map_groups *mg)
128{ 134{
129 int i; 135 int i;
130 for (i = 0; i < MAP__NR_TYPES; ++i) 136 for (i = 0; i < MAP__NR_TYPES; ++i)
131 __map_groups__fixup_end(self, i); 137 __map_groups__fixup_end(mg, i);
132} 138}
133 139
134static struct symbol *symbol__new(u64 start, u64 len, u8 binding, 140static struct symbol *symbol__new(u64 start, u64 len, u8 binding,
135 const char *name) 141 const char *name)
136{ 142{
137 size_t namelen = strlen(name) + 1; 143 size_t namelen = strlen(name) + 1;
138 struct symbol *self = calloc(1, (symbol_conf.priv_size + 144 struct symbol *sym = calloc(1, (symbol_conf.priv_size +
139 sizeof(*self) + namelen)); 145 sizeof(*sym) + namelen));
140 if (self == NULL) 146 if (sym == NULL)
141 return NULL; 147 return NULL;
142 148
143 if (symbol_conf.priv_size) 149 if (symbol_conf.priv_size)
144 self = ((void *)self) + symbol_conf.priv_size; 150 sym = ((void *)sym) + symbol_conf.priv_size;
145
146 self->start = start;
147 self->end = len ? start + len - 1 : start;
148 self->binding = binding;
149 self->namelen = namelen - 1;
150 151
151 pr_debug4("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end); 152 sym->start = start;
153 sym->end = len ? start + len - 1 : start;
154 sym->binding = binding;
155 sym->namelen = namelen - 1;
152 156
153 memcpy(self->name, name, namelen); 157 pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n",
158 __func__, name, start, sym->end);
159 memcpy(sym->name, name, namelen);
154 160
155 return self; 161 return sym;
156} 162}
157 163
158void symbol__delete(struct symbol *self) 164void symbol__delete(struct symbol *sym)
159{ 165{
160 free(((void *)self) - symbol_conf.priv_size); 166 free(((void *)sym) - symbol_conf.priv_size);
161} 167}
162 168
163static size_t symbol__fprintf(struct symbol *self, FILE *fp) 169static size_t symbol__fprintf(struct symbol *sym, FILE *fp)
164{ 170{
165 return fprintf(fp, " %llx-%llx %c %s\n", 171 return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n",
166 self->start, self->end, 172 sym->start, sym->end,
167 self->binding == STB_GLOBAL ? 'g' : 173 sym->binding == STB_GLOBAL ? 'g' :
168 self->binding == STB_LOCAL ? 'l' : 'w', 174 sym->binding == STB_LOCAL ? 'l' : 'w',
169 self->name); 175 sym->name);
170} 176}
171 177
172void dso__set_long_name(struct dso *self, char *name) 178void dso__set_long_name(struct dso *dso, char *name)
173{ 179{
174 if (name == NULL) 180 if (name == NULL)
175 return; 181 return;
176 self->long_name = name; 182 dso->long_name = name;
177 self->long_name_len = strlen(name); 183 dso->long_name_len = strlen(name);
178} 184}
179 185
180static void dso__set_short_name(struct dso *self, const char *name) 186static void dso__set_short_name(struct dso *dso, const char *name)
181{ 187{
182 if (name == NULL) 188 if (name == NULL)
183 return; 189 return;
184 self->short_name = name; 190 dso->short_name = name;
185 self->short_name_len = strlen(name); 191 dso->short_name_len = strlen(name);
186} 192}
187 193
188static void dso__set_basename(struct dso *self) 194static void dso__set_basename(struct dso *dso)
189{ 195{
190 dso__set_short_name(self, basename(self->long_name)); 196 dso__set_short_name(dso, basename(dso->long_name));
191} 197}
192 198
193struct dso *dso__new(const char *name) 199struct dso *dso__new(const char *name)
194{ 200{
195 struct dso *self = calloc(1, sizeof(*self) + strlen(name) + 1); 201 struct dso *dso = calloc(1, sizeof(*dso) + strlen(name) + 1);
196 202
197 if (self != NULL) { 203 if (dso != NULL) {
198 int i; 204 int i;
199 strcpy(self->name, name); 205 strcpy(dso->name, name);
200 dso__set_long_name(self, self->name); 206 dso__set_long_name(dso, dso->name);
201 dso__set_short_name(self, self->name); 207 dso__set_short_name(dso, dso->name);
202 for (i = 0; i < MAP__NR_TYPES; ++i) 208 for (i = 0; i < MAP__NR_TYPES; ++i)
203 self->symbols[i] = self->symbol_names[i] = RB_ROOT; 209 dso->symbols[i] = dso->symbol_names[i] = RB_ROOT;
204 self->slen_calculated = 0; 210 dso->symtab_type = SYMTAB__NOT_FOUND;
205 self->origin = DSO__ORIG_NOT_FOUND; 211 dso->loaded = 0;
206 self->loaded = 0; 212 dso->sorted_by_name = 0;
207 self->sorted_by_name = 0; 213 dso->has_build_id = 0;
208 self->has_build_id = 0; 214 dso->kernel = DSO_TYPE_USER;
209 self->kernel = DSO_TYPE_USER; 215 INIT_LIST_HEAD(&dso->node);
210 INIT_LIST_HEAD(&self->node);
211 } 216 }
212 217
213 return self; 218 return dso;
214} 219}
215 220
216static void symbols__delete(struct rb_root *self) 221static void symbols__delete(struct rb_root *symbols)
217{ 222{
218 struct symbol *pos; 223 struct symbol *pos;
219 struct rb_node *next = rb_first(self); 224 struct rb_node *next = rb_first(symbols);
220 225
221 while (next) { 226 while (next) {
222 pos = rb_entry(next, struct symbol, rb_node); 227 pos = rb_entry(next, struct symbol, rb_node);
223 next = rb_next(&pos->rb_node); 228 next = rb_next(&pos->rb_node);
224 rb_erase(&pos->rb_node, self); 229 rb_erase(&pos->rb_node, symbols);
225 symbol__delete(pos); 230 symbol__delete(pos);
226 } 231 }
227} 232}
228 233
229void dso__delete(struct dso *self) 234void dso__delete(struct dso *dso)
230{ 235{
231 int i; 236 int i;
232 for (i = 0; i < MAP__NR_TYPES; ++i) 237 for (i = 0; i < MAP__NR_TYPES; ++i)
233 symbols__delete(&self->symbols[i]); 238 symbols__delete(&dso->symbols[i]);
234 if (self->sname_alloc) 239 if (dso->sname_alloc)
235 free((char *)self->short_name); 240 free((char *)dso->short_name);
236 if (self->lname_alloc) 241 if (dso->lname_alloc)
237 free(self->long_name); 242 free(dso->long_name);
238 free(self); 243 free(dso);
239} 244}
240 245
241void dso__set_build_id(struct dso *self, void *build_id) 246void dso__set_build_id(struct dso *dso, void *build_id)
242{ 247{
243 memcpy(self->build_id, build_id, sizeof(self->build_id)); 248 memcpy(dso->build_id, build_id, sizeof(dso->build_id));
244 self->has_build_id = 1; 249 dso->has_build_id = 1;
245} 250}
246 251
247static void symbols__insert(struct rb_root *self, struct symbol *sym) 252static void symbols__insert(struct rb_root *symbols, struct symbol *sym)
248{ 253{
249 struct rb_node **p = &self->rb_node; 254 struct rb_node **p = &symbols->rb_node;
250 struct rb_node *parent = NULL; 255 struct rb_node *parent = NULL;
251 const u64 ip = sym->start; 256 const u64 ip = sym->start;
252 struct symbol *s; 257 struct symbol *s;
@@ -260,17 +265,17 @@ static void symbols__insert(struct rb_root *self, struct symbol *sym)
260 p = &(*p)->rb_right; 265 p = &(*p)->rb_right;
261 } 266 }
262 rb_link_node(&sym->rb_node, parent, p); 267 rb_link_node(&sym->rb_node, parent, p);
263 rb_insert_color(&sym->rb_node, self); 268 rb_insert_color(&sym->rb_node, symbols);
264} 269}
265 270
266static struct symbol *symbols__find(struct rb_root *self, u64 ip) 271static struct symbol *symbols__find(struct rb_root *symbols, u64 ip)
267{ 272{
268 struct rb_node *n; 273 struct rb_node *n;
269 274
270 if (self == NULL) 275 if (symbols == NULL)
271 return NULL; 276 return NULL;
272 277
273 n = self->rb_node; 278 n = symbols->rb_node;
274 279
275 while (n) { 280 while (n) {
276 struct symbol *s = rb_entry(n, struct symbol, rb_node); 281 struct symbol *s = rb_entry(n, struct symbol, rb_node);
@@ -291,11 +296,13 @@ struct symbol_name_rb_node {
291 struct symbol sym; 296 struct symbol sym;
292}; 297};
293 298
294static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym) 299static void symbols__insert_by_name(struct rb_root *symbols, struct symbol *sym)
295{ 300{
296 struct rb_node **p = &self->rb_node; 301 struct rb_node **p = &symbols->rb_node;
297 struct rb_node *parent = NULL; 302 struct rb_node *parent = NULL;
298 struct symbol_name_rb_node *symn = ((void *)sym) - sizeof(*parent), *s; 303 struct symbol_name_rb_node *symn, *s;
304
305 symn = container_of(sym, struct symbol_name_rb_node, sym);
299 306
300 while (*p != NULL) { 307 while (*p != NULL) {
301 parent = *p; 308 parent = *p;
@@ -306,27 +313,29 @@ static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym)
306 p = &(*p)->rb_right; 313 p = &(*p)->rb_right;
307 } 314 }
308 rb_link_node(&symn->rb_node, parent, p); 315 rb_link_node(&symn->rb_node, parent, p);
309 rb_insert_color(&symn->rb_node, self); 316 rb_insert_color(&symn->rb_node, symbols);
310} 317}
311 318
312static void symbols__sort_by_name(struct rb_root *self, struct rb_root *source) 319static void symbols__sort_by_name(struct rb_root *symbols,
320 struct rb_root *source)
313{ 321{
314 struct rb_node *nd; 322 struct rb_node *nd;
315 323
316 for (nd = rb_first(source); nd; nd = rb_next(nd)) { 324 for (nd = rb_first(source); nd; nd = rb_next(nd)) {
317 struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 325 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
318 symbols__insert_by_name(self, pos); 326 symbols__insert_by_name(symbols, pos);
319 } 327 }
320} 328}
321 329
322static struct symbol *symbols__find_by_name(struct rb_root *self, const char *name) 330static struct symbol *symbols__find_by_name(struct rb_root *symbols,
331 const char *name)
323{ 332{
324 struct rb_node *n; 333 struct rb_node *n;
325 334
326 if (self == NULL) 335 if (symbols == NULL)
327 return NULL; 336 return NULL;
328 337
329 n = self->rb_node; 338 n = symbols->rb_node;
330 339
331 while (n) { 340 while (n) {
332 struct symbol_name_rb_node *s; 341 struct symbol_name_rb_node *s;
@@ -346,29 +355,29 @@ static struct symbol *symbols__find_by_name(struct rb_root *self, const char *na
346 return NULL; 355 return NULL;
347} 356}
348 357
349struct symbol *dso__find_symbol(struct dso *self, 358struct symbol *dso__find_symbol(struct dso *dso,
350 enum map_type type, u64 addr) 359 enum map_type type, u64 addr)
351{ 360{
352 return symbols__find(&self->symbols[type], addr); 361 return symbols__find(&dso->symbols[type], addr);
353} 362}
354 363
355struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type, 364struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
356 const char *name) 365 const char *name)
357{ 366{
358 return symbols__find_by_name(&self->symbol_names[type], name); 367 return symbols__find_by_name(&dso->symbol_names[type], name);
359} 368}
360 369
361void dso__sort_by_name(struct dso *self, enum map_type type) 370void dso__sort_by_name(struct dso *dso, enum map_type type)
362{ 371{
363 dso__set_sorted_by_name(self, type); 372 dso__set_sorted_by_name(dso, type);
364 return symbols__sort_by_name(&self->symbol_names[type], 373 return symbols__sort_by_name(&dso->symbol_names[type],
365 &self->symbols[type]); 374 &dso->symbols[type]);
366} 375}
367 376
368int build_id__sprintf(const u8 *self, int len, char *bf) 377int build_id__sprintf(const u8 *build_id, int len, char *bf)
369{ 378{
370 char *bid = bf; 379 char *bid = bf;
371 const u8 *raw = self; 380 const u8 *raw = build_id;
372 int i; 381 int i;
373 382
374 for (i = 0; i < len; ++i) { 383 for (i = 0; i < len; ++i) {
@@ -377,29 +386,44 @@ int build_id__sprintf(const u8 *self, int len, char *bf)
377 bid += 2; 386 bid += 2;
378 } 387 }
379 388
380 return raw - self; 389 return raw - build_id;
381} 390}
382 391
383size_t dso__fprintf_buildid(struct dso *self, FILE *fp) 392size_t dso__fprintf_buildid(struct dso *dso, FILE *fp)
384{ 393{
385 char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 394 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
386 395
387 build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id); 396 build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
388 return fprintf(fp, "%s", sbuild_id); 397 return fprintf(fp, "%s", sbuild_id);
389} 398}
390 399
391size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp) 400size_t dso__fprintf_symbols_by_name(struct dso *dso,
401 enum map_type type, FILE *fp)
402{
403 size_t ret = 0;
404 struct rb_node *nd;
405 struct symbol_name_rb_node *pos;
406
407 for (nd = rb_first(&dso->symbol_names[type]); nd; nd = rb_next(nd)) {
408 pos = rb_entry(nd, struct symbol_name_rb_node, rb_node);
409 fprintf(fp, "%s\n", pos->sym.name);
410 }
411
412 return ret;
413}
414
415size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp)
392{ 416{
393 struct rb_node *nd; 417 struct rb_node *nd;
394 size_t ret = fprintf(fp, "dso: %s (", self->short_name); 418 size_t ret = fprintf(fp, "dso: %s (", dso->short_name);
395 419
396 if (self->short_name != self->long_name) 420 if (dso->short_name != dso->long_name)
397 ret += fprintf(fp, "%s, ", self->long_name); 421 ret += fprintf(fp, "%s, ", dso->long_name);
398 ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type], 422 ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type],
399 self->loaded ? "" : "NOT "); 423 dso->loaded ? "" : "NOT ");
400 ret += dso__fprintf_buildid(self, fp); 424 ret += dso__fprintf_buildid(dso, fp);
401 ret += fprintf(fp, ")\n"); 425 ret += fprintf(fp, ")\n");
402 for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) { 426 for (nd = rb_first(&dso->symbols[type]); nd; nd = rb_next(nd)) {
403 struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 427 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
404 ret += symbol__fprintf(pos, fp); 428 ret += symbol__fprintf(pos, fp);
405 } 429 }
@@ -409,16 +433,25 @@ size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
409 433
410int kallsyms__parse(const char *filename, void *arg, 434int kallsyms__parse(const char *filename, void *arg,
411 int (*process_symbol)(void *arg, const char *name, 435 int (*process_symbol)(void *arg, const char *name,
412 char type, u64 start)) 436 char type, u64 start, u64 end))
413{ 437{
414 char *line = NULL; 438 char *line = NULL;
415 size_t n; 439 size_t n;
416 int err = 0; 440 int err = -1;
441 u64 prev_start = 0;
442 char prev_symbol_type = 0;
443 char *prev_symbol_name;
417 FILE *file = fopen(filename, "r"); 444 FILE *file = fopen(filename, "r");
418 445
419 if (file == NULL) 446 if (file == NULL)
420 goto out_failure; 447 goto out_failure;
421 448
449 prev_symbol_name = malloc(KSYM_NAME_LEN);
450 if (prev_symbol_name == NULL)
451 goto out_close;
452
453 err = 0;
454
422 while (!feof(file)) { 455 while (!feof(file)) {
423 u64 start; 456 u64 start;
424 int line_len, len; 457 int line_len, len;
@@ -438,14 +471,33 @@ int kallsyms__parse(const char *filename, void *arg,
438 continue; 471 continue;
439 472
440 symbol_type = toupper(line[len]); 473 symbol_type = toupper(line[len]);
441 symbol_name = line + len + 2; 474 len += 2;
475 symbol_name = line + len;
476 len = line_len - len;
442 477
443 err = process_symbol(arg, symbol_name, symbol_type, start); 478 if (len >= KSYM_NAME_LEN) {
444 if (err) 479 err = -1;
445 break; 480 break;
481 }
482
483 if (prev_symbol_type) {
484 u64 end = start;
485 if (end != prev_start)
486 --end;
487 err = process_symbol(arg, prev_symbol_name,
488 prev_symbol_type, prev_start, end);
489 if (err)
490 break;
491 }
492
493 memcpy(prev_symbol_name, symbol_name, len + 1);
494 prev_symbol_type = symbol_type;
495 prev_start = start;
446 } 496 }
447 497
498 free(prev_symbol_name);
448 free(line); 499 free(line);
500out_close:
449 fclose(file); 501 fclose(file);
450 return err; 502 return err;
451 503
@@ -467,7 +519,7 @@ static u8 kallsyms2elf_type(char type)
467} 519}
468 520
469static int map__process_kallsym_symbol(void *arg, const char *name, 521static int map__process_kallsym_symbol(void *arg, const char *name,
470 char type, u64 start) 522 char type, u64 start, u64 end)
471{ 523{
472 struct symbol *sym; 524 struct symbol *sym;
473 struct process_kallsyms_args *a = arg; 525 struct process_kallsyms_args *a = arg;
@@ -476,11 +528,8 @@ static int map__process_kallsym_symbol(void *arg, const char *name,
476 if (!symbol_type__is_a(type, a->map->type)) 528 if (!symbol_type__is_a(type, a->map->type))
477 return 0; 529 return 0;
478 530
479 /* 531 sym = symbol__new(start, end - start + 1,
480 * Will fix up the end later, when we have all symbols sorted. 532 kallsyms2elf_type(type), name);
481 */
482 sym = symbol__new(start, 0, kallsyms2elf_type(type), name);
483
484 if (sym == NULL) 533 if (sym == NULL)
485 return -ENOMEM; 534 return -ENOMEM;
486 /* 535 /*
@@ -497,10 +546,10 @@ static int map__process_kallsym_symbol(void *arg, const char *name,
497 * so that we can in the next step set the symbol ->end address and then 546 * so that we can in the next step set the symbol ->end address and then
498 * call kernel_maps__split_kallsyms. 547 * call kernel_maps__split_kallsyms.
499 */ 548 */
500static int dso__load_all_kallsyms(struct dso *self, const char *filename, 549static int dso__load_all_kallsyms(struct dso *dso, const char *filename,
501 struct map *map) 550 struct map *map)
502{ 551{
503 struct process_kallsyms_args args = { .map = map, .dso = self, }; 552 struct process_kallsyms_args args = { .map = map, .dso = dso, };
504 return kallsyms__parse(filename, &args, map__process_kallsym_symbol); 553 return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
505} 554}
506 555
@@ -509,15 +558,15 @@ static int dso__load_all_kallsyms(struct dso *self, const char *filename,
509 * kernel range is broken in several maps, named [kernel].N, as we don't have 558 * kernel range is broken in several maps, named [kernel].N, as we don't have
510 * the original ELF section names vmlinux have. 559 * the original ELF section names vmlinux have.
511 */ 560 */
512static int dso__split_kallsyms(struct dso *self, struct map *map, 561static int dso__split_kallsyms(struct dso *dso, struct map *map,
513 symbol_filter_t filter) 562 symbol_filter_t filter)
514{ 563{
515 struct map_groups *kmaps = map__kmap(map)->kmaps; 564 struct map_groups *kmaps = map__kmap(map)->kmaps;
516 struct machine *machine = kmaps->machine; 565 struct machine *machine = kmaps->machine;
517 struct map *curr_map = map; 566 struct map *curr_map = map;
518 struct symbol *pos; 567 struct symbol *pos;
519 int count = 0; 568 int count = 0, moved = 0;
520 struct rb_root *root = &self->symbols[map->type]; 569 struct rb_root *root = &dso->symbols[map->type];
521 struct rb_node *next = rb_first(root); 570 struct rb_node *next = rb_first(root);
522 int kernel_range = 0; 571 int kernel_range = 0;
523 572
@@ -536,7 +585,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
536 585
537 if (strcmp(curr_map->dso->short_name, module)) { 586 if (strcmp(curr_map->dso->short_name, module)) {
538 if (curr_map != map && 587 if (curr_map != map &&
539 self->kernel == DSO_TYPE_GUEST_KERNEL && 588 dso->kernel == DSO_TYPE_GUEST_KERNEL &&
540 machine__is_default_guest(machine)) { 589 machine__is_default_guest(machine)) {
541 /* 590 /*
542 * We assume all symbols of a module are 591 * We assume all symbols of a module are
@@ -572,9 +621,14 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
572 pos->end = curr_map->map_ip(curr_map, pos->end); 621 pos->end = curr_map->map_ip(curr_map, pos->end);
573 } else if (curr_map != map) { 622 } else if (curr_map != map) {
574 char dso_name[PATH_MAX]; 623 char dso_name[PATH_MAX];
575 struct dso *dso; 624 struct dso *ndso;
576 625
577 if (self->kernel == DSO_TYPE_GUEST_KERNEL) 626 if (count == 0) {
627 curr_map = map;
628 goto filter_symbol;
629 }
630
631 if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
578 snprintf(dso_name, sizeof(dso_name), 632 snprintf(dso_name, sizeof(dso_name),
579 "[guest.kernel].%d", 633 "[guest.kernel].%d",
580 kernel_range++); 634 kernel_range++);
@@ -583,15 +637,15 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
583 "[kernel].%d", 637 "[kernel].%d",
584 kernel_range++); 638 kernel_range++);
585 639
586 dso = dso__new(dso_name); 640 ndso = dso__new(dso_name);
587 if (dso == NULL) 641 if (ndso == NULL)
588 return -1; 642 return -1;
589 643
590 dso->kernel = self->kernel; 644 ndso->kernel = dso->kernel;
591 645
592 curr_map = map__new2(pos->start, dso, map->type); 646 curr_map = map__new2(pos->start, ndso, map->type);
593 if (curr_map == NULL) { 647 if (curr_map == NULL) {
594 dso__delete(dso); 648 dso__delete(ndso);
595 return -1; 649 return -1;
596 } 650 }
597 651
@@ -599,7 +653,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
599 map_groups__insert(kmaps, curr_map); 653 map_groups__insert(kmaps, curr_map);
600 ++kernel_range; 654 ++kernel_range;
601 } 655 }
602 656filter_symbol:
603 if (filter && filter(curr_map, pos)) { 657 if (filter && filter(curr_map, pos)) {
604discard_symbol: rb_erase(&pos->rb_node, root); 658discard_symbol: rb_erase(&pos->rb_node, root);
605 symbol__delete(pos); 659 symbol__delete(pos);
@@ -607,36 +661,57 @@ discard_symbol: rb_erase(&pos->rb_node, root);
607 if (curr_map != map) { 661 if (curr_map != map) {
608 rb_erase(&pos->rb_node, root); 662 rb_erase(&pos->rb_node, root);
609 symbols__insert(&curr_map->dso->symbols[curr_map->type], pos); 663 symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
610 } 664 ++moved;
611 count++; 665 } else
666 ++count;
612 } 667 }
613 } 668 }
614 669
615 if (curr_map != map && 670 if (curr_map != map &&
616 self->kernel == DSO_TYPE_GUEST_KERNEL && 671 dso->kernel == DSO_TYPE_GUEST_KERNEL &&
617 machine__is_default_guest(kmaps->machine)) { 672 machine__is_default_guest(kmaps->machine)) {
618 dso__set_loaded(curr_map->dso, curr_map->type); 673 dso__set_loaded(curr_map->dso, curr_map->type);
619 } 674 }
620 675
621 return count; 676 return count + moved;
622} 677}
623 678
624int dso__load_kallsyms(struct dso *self, const char *filename, 679static bool symbol__restricted_filename(const char *filename,
680 const char *restricted_filename)
681{
682 bool restricted = false;
683
684 if (symbol_conf.kptr_restrict) {
685 char *r = realpath(filename, NULL);
686
687 if (r != NULL) {
688 restricted = strcmp(r, restricted_filename) == 0;
689 free(r);
690 return restricted;
691 }
692 }
693
694 return restricted;
695}
696
697int dso__load_kallsyms(struct dso *dso, const char *filename,
625 struct map *map, symbol_filter_t filter) 698 struct map *map, symbol_filter_t filter)
626{ 699{
627 if (dso__load_all_kallsyms(self, filename, map) < 0) 700 if (symbol__restricted_filename(filename, "/proc/kallsyms"))
701 return -1;
702
703 if (dso__load_all_kallsyms(dso, filename, map) < 0)
628 return -1; 704 return -1;
629 705
630 symbols__fixup_end(&self->symbols[map->type]); 706 if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
631 if (self->kernel == DSO_TYPE_GUEST_KERNEL) 707 dso->symtab_type = SYMTAB__GUEST_KALLSYMS;
632 self->origin = DSO__ORIG_GUEST_KERNEL;
633 else 708 else
634 self->origin = DSO__ORIG_KERNEL; 709 dso->symtab_type = SYMTAB__KALLSYMS;
635 710
636 return dso__split_kallsyms(self, map, filter); 711 return dso__split_kallsyms(dso, map, filter);
637} 712}
638 713
639static int dso__load_perf_map(struct dso *self, struct map *map, 714static int dso__load_perf_map(struct dso *dso, struct map *map,
640 symbol_filter_t filter) 715 symbol_filter_t filter)
641{ 716{
642 char *line = NULL; 717 char *line = NULL;
@@ -644,7 +719,7 @@ static int dso__load_perf_map(struct dso *self, struct map *map,
644 FILE *file; 719 FILE *file;
645 int nr_syms = 0; 720 int nr_syms = 0;
646 721
647 file = fopen(self->long_name, "r"); 722 file = fopen(dso->long_name, "r");
648 if (file == NULL) 723 if (file == NULL)
649 goto out_failure; 724 goto out_failure;
650 725
@@ -682,7 +757,7 @@ static int dso__load_perf_map(struct dso *self, struct map *map,
682 if (filter && filter(map, sym)) 757 if (filter && filter(map, sym))
683 symbol__delete(sym); 758 symbol__delete(sym);
684 else { 759 else {
685 symbols__insert(&self->symbols[map->type], sym); 760 symbols__insert(&dso->symbols[map->type], sym);
686 nr_syms++; 761 nr_syms++;
687 } 762 }
688 } 763 }
@@ -701,7 +776,7 @@ out_failure:
701/** 776/**
702 * elf_symtab__for_each_symbol - iterate thru all the symbols 777 * elf_symtab__for_each_symbol - iterate thru all the symbols
703 * 778 *
704 * @self: struct elf_symtab instance to iterate 779 * @syms: struct elf_symtab instance to iterate
705 * @idx: uint32_t idx 780 * @idx: uint32_t idx
706 * @sym: GElf_Sym iterator 781 * @sym: GElf_Sym iterator
707 */ 782 */
@@ -801,7 +876,7 @@ static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
801 * And always look at the original dso, not at debuginfo packages, that 876 * And always look at the original dso, not at debuginfo packages, that
802 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). 877 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
803 */ 878 */
804static int dso__synthesize_plt_symbols(struct dso *self, struct map *map, 879static int dso__synthesize_plt_symbols(struct dso *dso, struct map *map,
805 symbol_filter_t filter) 880 symbol_filter_t filter)
806{ 881{
807 uint32_t nr_rel_entries, idx; 882 uint32_t nr_rel_entries, idx;
@@ -817,8 +892,11 @@ static int dso__synthesize_plt_symbols(struct dso *self, struct map *map,
817 char sympltname[1024]; 892 char sympltname[1024];
818 Elf *elf; 893 Elf *elf;
819 int nr = 0, symidx, fd, err = 0; 894 int nr = 0, symidx, fd, err = 0;
895 char name[PATH_MAX];
820 896
821 fd = open(self->long_name, O_RDONLY); 897 snprintf(name, sizeof(name), "%s%s",
898 symbol_conf.symfs, dso->long_name);
899 fd = open(name, O_RDONLY);
822 if (fd < 0) 900 if (fd < 0)
823 goto out; 901 goto out;
824 902
@@ -893,7 +971,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, struct map *map,
893 if (filter && filter(map, f)) 971 if (filter && filter(map, f))
894 symbol__delete(f); 972 symbol__delete(f);
895 else { 973 else {
896 symbols__insert(&self->symbols[map->type], f); 974 symbols__insert(&dso->symbols[map->type], f);
897 ++nr; 975 ++nr;
898 } 976 }
899 } 977 }
@@ -915,7 +993,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, struct map *map,
915 if (filter && filter(map, f)) 993 if (filter && filter(map, f))
916 symbol__delete(f); 994 symbol__delete(f);
917 else { 995 else {
918 symbols__insert(&self->symbols[map->type], f); 996 symbols__insert(&dso->symbols[map->type], f);
919 ++nr; 997 ++nr;
920 } 998 }
921 } 999 }
@@ -931,29 +1009,30 @@ out_close:
931 return nr; 1009 return nr;
932out: 1010out:
933 pr_debug("%s: problems reading %s PLT info.\n", 1011 pr_debug("%s: problems reading %s PLT info.\n",
934 __func__, self->long_name); 1012 __func__, dso->long_name);
935 return 0; 1013 return 0;
936} 1014}
937 1015
938static bool elf_sym__is_a(GElf_Sym *self, enum map_type type) 1016static bool elf_sym__is_a(GElf_Sym *sym, enum map_type type)
939{ 1017{
940 switch (type) { 1018 switch (type) {
941 case MAP__FUNCTION: 1019 case MAP__FUNCTION:
942 return elf_sym__is_function(self); 1020 return elf_sym__is_function(sym);
943 case MAP__VARIABLE: 1021 case MAP__VARIABLE:
944 return elf_sym__is_object(self); 1022 return elf_sym__is_object(sym);
945 default: 1023 default:
946 return false; 1024 return false;
947 } 1025 }
948} 1026}
949 1027
950static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type) 1028static bool elf_sec__is_a(GElf_Shdr *shdr, Elf_Data *secstrs,
1029 enum map_type type)
951{ 1030{
952 switch (type) { 1031 switch (type) {
953 case MAP__FUNCTION: 1032 case MAP__FUNCTION:
954 return elf_sec__is_text(self, secstrs); 1033 return elf_sec__is_text(shdr, secstrs);
955 case MAP__VARIABLE: 1034 case MAP__VARIABLE:
956 return elf_sec__is_data(self, secstrs); 1035 return elf_sec__is_data(shdr, secstrs);
957 default: 1036 default:
958 return false; 1037 return false;
959 } 1038 }
@@ -978,13 +1057,13 @@ static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr)
978 return -1; 1057 return -1;
979} 1058}
980 1059
981static int dso__load_sym(struct dso *self, struct map *map, const char *name, 1060static int dso__load_sym(struct dso *dso, struct map *map, const char *name,
982 int fd, symbol_filter_t filter, int kmodule, 1061 int fd, symbol_filter_t filter, int kmodule,
983 int want_symtab) 1062 int want_symtab)
984{ 1063{
985 struct kmap *kmap = self->kernel ? map__kmap(map) : NULL; 1064 struct kmap *kmap = dso->kernel ? map__kmap(map) : NULL;
986 struct map *curr_map = map; 1065 struct map *curr_map = map;
987 struct dso *curr_dso = self; 1066 struct dso *curr_dso = dso;
988 Elf_Data *symstrs, *secstrs; 1067 Elf_Data *symstrs, *secstrs;
989 uint32_t nr_syms; 1068 uint32_t nr_syms;
990 int err = -1; 1069 int err = -1;
@@ -1010,14 +1089,14 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
1010 } 1089 }
1011 1090
1012 /* Always reject images with a mismatched build-id: */ 1091 /* Always reject images with a mismatched build-id: */
1013 if (self->has_build_id) { 1092 if (dso->has_build_id) {
1014 u8 build_id[BUILD_ID_SIZE]; 1093 u8 build_id[BUILD_ID_SIZE];
1015 1094
1016 if (elf_read_build_id(elf, build_id, 1095 if (elf_read_build_id(elf, build_id,
1017 BUILD_ID_SIZE) != BUILD_ID_SIZE) 1096 BUILD_ID_SIZE) != BUILD_ID_SIZE)
1018 goto out_elf_end; 1097 goto out_elf_end;
1019 1098
1020 if (!dso__build_id_equal(self, build_id)) 1099 if (!dso__build_id_equal(dso, build_id))
1021 goto out_elf_end; 1100 goto out_elf_end;
1022 } 1101 }
1023 1102
@@ -1058,13 +1137,14 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
1058 nr_syms = shdr.sh_size / shdr.sh_entsize; 1137 nr_syms = shdr.sh_size / shdr.sh_entsize;
1059 1138
1060 memset(&sym, 0, sizeof(sym)); 1139 memset(&sym, 0, sizeof(sym));
1061 if (self->kernel == DSO_TYPE_USER) { 1140 if (dso->kernel == DSO_TYPE_USER) {
1062 self->adjust_symbols = (ehdr.e_type == ET_EXEC || 1141 dso->adjust_symbols = (ehdr.e_type == ET_EXEC ||
1063 elf_section_by_name(elf, &ehdr, &shdr, 1142 elf_section_by_name(elf, &ehdr, &shdr,
1064 ".gnu.prelink_undo", 1143 ".gnu.prelink_undo",
1065 NULL) != NULL); 1144 NULL) != NULL);
1066 } else self->adjust_symbols = 0; 1145 } else {
1067 1146 dso->adjust_symbols = 0;
1147 }
1068 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 1148 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
1069 struct symbol *f; 1149 struct symbol *f;
1070 const char *elf_name = elf_sym__name(&sym, symstrs); 1150 const char *elf_name = elf_sym__name(&sym, symstrs);
@@ -1107,22 +1187,29 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
1107 1187
1108 section_name = elf_sec__name(&shdr, secstrs); 1188 section_name = elf_sec__name(&shdr, secstrs);
1109 1189
1110 if (self->kernel != DSO_TYPE_USER || kmodule) { 1190 /* On ARM, symbols for thumb functions have 1 added to
1191 * the symbol address as a flag - remove it */
1192 if ((ehdr.e_machine == EM_ARM) &&
1193 (map->type == MAP__FUNCTION) &&
1194 (sym.st_value & 1))
1195 --sym.st_value;
1196
1197 if (dso->kernel != DSO_TYPE_USER || kmodule) {
1111 char dso_name[PATH_MAX]; 1198 char dso_name[PATH_MAX];
1112 1199
1113 if (strcmp(section_name, 1200 if (strcmp(section_name,
1114 (curr_dso->short_name + 1201 (curr_dso->short_name +
1115 self->short_name_len)) == 0) 1202 dso->short_name_len)) == 0)
1116 goto new_symbol; 1203 goto new_symbol;
1117 1204
1118 if (strcmp(section_name, ".text") == 0) { 1205 if (strcmp(section_name, ".text") == 0) {
1119 curr_map = map; 1206 curr_map = map;
1120 curr_dso = self; 1207 curr_dso = dso;
1121 goto new_symbol; 1208 goto new_symbol;
1122 } 1209 }
1123 1210
1124 snprintf(dso_name, sizeof(dso_name), 1211 snprintf(dso_name, sizeof(dso_name),
1125 "%s%s", self->short_name, section_name); 1212 "%s%s", dso->short_name, section_name);
1126 1213
1127 curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name); 1214 curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name);
1128 if (curr_map == NULL) { 1215 if (curr_map == NULL) {
@@ -1134,7 +1221,9 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
1134 curr_dso = dso__new(dso_name); 1221 curr_dso = dso__new(dso_name);
1135 if (curr_dso == NULL) 1222 if (curr_dso == NULL)
1136 goto out_elf_end; 1223 goto out_elf_end;
1137 curr_dso->kernel = self->kernel; 1224 curr_dso->kernel = dso->kernel;
1225 curr_dso->long_name = dso->long_name;
1226 curr_dso->long_name_len = dso->long_name_len;
1138 curr_map = map__new2(start, curr_dso, 1227 curr_map = map__new2(start, curr_dso,
1139 map->type); 1228 map->type);
1140 if (curr_map == NULL) { 1229 if (curr_map == NULL) {
@@ -1143,9 +1232,9 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
1143 } 1232 }
1144 curr_map->map_ip = identity__map_ip; 1233 curr_map->map_ip = identity__map_ip;
1145 curr_map->unmap_ip = identity__map_ip; 1234 curr_map->unmap_ip = identity__map_ip;
1146 curr_dso->origin = self->origin; 1235 curr_dso->symtab_type = dso->symtab_type;
1147 map_groups__insert(kmap->kmaps, curr_map); 1236 map_groups__insert(kmap->kmaps, curr_map);
1148 dsos__add(&self->node, curr_dso); 1237 dsos__add(&dso->node, curr_dso);
1149 dso__set_loaded(curr_dso, map->type); 1238 dso__set_loaded(curr_dso, map->type);
1150 } else 1239 } else
1151 curr_dso = curr_map->dso; 1240 curr_dso = curr_map->dso;
@@ -1154,8 +1243,8 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
1154 } 1243 }
1155 1244
1156 if (curr_dso->adjust_symbols) { 1245 if (curr_dso->adjust_symbols) {
1157 pr_debug4("%s: adjusting symbol: st_value: %#Lx " 1246 pr_debug4("%s: adjusting symbol: st_value: %#" PRIx64 " "
1158 "sh_addr: %#Lx sh_offset: %#Lx\n", __func__, 1247 "sh_addr: %#" PRIx64 " sh_offset: %#" PRIx64 "\n", __func__,
1159 (u64)sym.st_value, (u64)shdr.sh_addr, 1248 (u64)sym.st_value, (u64)shdr.sh_addr,
1160 (u64)shdr.sh_offset); 1249 (u64)shdr.sh_offset);
1161 sym.st_value -= shdr.sh_addr - shdr.sh_offset; 1250 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
@@ -1187,7 +1276,7 @@ new_symbol:
1187 * For misannotated, zeroed, ASM function sizes. 1276 * For misannotated, zeroed, ASM function sizes.
1188 */ 1277 */
1189 if (nr > 0) { 1278 if (nr > 0) {
1190 symbols__fixup_end(&self->symbols[map->type]); 1279 symbols__fixup_end(&dso->symbols[map->type]);
1191 if (kmap) { 1280 if (kmap) {
1192 /* 1281 /*
1193 * We need to fixup this here too because we create new 1282 * We need to fixup this here too because we create new
@@ -1203,9 +1292,9 @@ out_close:
1203 return err; 1292 return err;
1204} 1293}
1205 1294
1206static bool dso__build_id_equal(const struct dso *self, u8 *build_id) 1295static bool dso__build_id_equal(const struct dso *dso, u8 *build_id)
1207{ 1296{
1208 return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0; 1297 return memcmp(dso->build_id, build_id, sizeof(dso->build_id)) == 0;
1209} 1298}
1210 1299
1211bool __dsos__read_build_ids(struct list_head *head, bool with_hits) 1300bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
@@ -1366,27 +1455,27 @@ out:
1366 return err; 1455 return err;
1367} 1456}
1368 1457
1369char dso__symtab_origin(const struct dso *self) 1458char dso__symtab_origin(const struct dso *dso)
1370{ 1459{
1371 static const char origin[] = { 1460 static const char origin[] = {
1372 [DSO__ORIG_KERNEL] = 'k', 1461 [SYMTAB__KALLSYMS] = 'k',
1373 [DSO__ORIG_JAVA_JIT] = 'j', 1462 [SYMTAB__JAVA_JIT] = 'j',
1374 [DSO__ORIG_BUILD_ID_CACHE] = 'B', 1463 [SYMTAB__BUILD_ID_CACHE] = 'B',
1375 [DSO__ORIG_FEDORA] = 'f', 1464 [SYMTAB__FEDORA_DEBUGINFO] = 'f',
1376 [DSO__ORIG_UBUNTU] = 'u', 1465 [SYMTAB__UBUNTU_DEBUGINFO] = 'u',
1377 [DSO__ORIG_BUILDID] = 'b', 1466 [SYMTAB__BUILDID_DEBUGINFO] = 'b',
1378 [DSO__ORIG_DSO] = 'd', 1467 [SYMTAB__SYSTEM_PATH_DSO] = 'd',
1379 [DSO__ORIG_KMODULE] = 'K', 1468 [SYMTAB__SYSTEM_PATH_KMODULE] = 'K',
1380 [DSO__ORIG_GUEST_KERNEL] = 'g', 1469 [SYMTAB__GUEST_KALLSYMS] = 'g',
1381 [DSO__ORIG_GUEST_KMODULE] = 'G', 1470 [SYMTAB__GUEST_KMODULE] = 'G',
1382 }; 1471 };
1383 1472
1384 if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) 1473 if (dso == NULL || dso->symtab_type == SYMTAB__NOT_FOUND)
1385 return '!'; 1474 return '!';
1386 return origin[self->origin]; 1475 return origin[dso->symtab_type];
1387} 1476}
1388 1477
1389int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) 1478int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
1390{ 1479{
1391 int size = PATH_MAX; 1480 int size = PATH_MAX;
1392 char *name; 1481 char *name;
@@ -1396,12 +1485,12 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
1396 const char *root_dir; 1485 const char *root_dir;
1397 int want_symtab; 1486 int want_symtab;
1398 1487
1399 dso__set_loaded(self, map->type); 1488 dso__set_loaded(dso, map->type);
1400 1489
1401 if (self->kernel == DSO_TYPE_KERNEL) 1490 if (dso->kernel == DSO_TYPE_KERNEL)
1402 return dso__load_kernel_sym(self, map, filter); 1491 return dso__load_kernel_sym(dso, map, filter);
1403 else if (self->kernel == DSO_TYPE_GUEST_KERNEL) 1492 else if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
1404 return dso__load_guest_kernel_sym(self, map, filter); 1493 return dso__load_guest_kernel_sym(dso, map, filter);
1405 1494
1406 if (map->groups && map->groups->machine) 1495 if (map->groups && map->groups->machine)
1407 machine = map->groups->machine; 1496 machine = map->groups->machine;
@@ -1412,12 +1501,12 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
1412 if (!name) 1501 if (!name)
1413 return -1; 1502 return -1;
1414 1503
1415 self->adjust_symbols = 0; 1504 dso->adjust_symbols = 0;
1416 1505
1417 if (strncmp(self->name, "/tmp/perf-", 10) == 0) { 1506 if (strncmp(dso->name, "/tmp/perf-", 10) == 0) {
1418 ret = dso__load_perf_map(self, map, filter); 1507 ret = dso__load_perf_map(dso, map, filter);
1419 self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : 1508 dso->symtab_type = ret > 0 ? SYMTAB__JAVA_JIT :
1420 DSO__ORIG_NOT_FOUND; 1509 SYMTAB__NOT_FOUND;
1421 return ret; 1510 return ret;
1422 } 1511 }
1423 1512
@@ -1425,57 +1514,59 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
1425 * On the first pass, only load images if they have a full symtab. 1514 * On the first pass, only load images if they have a full symtab.
1426 * Failing that, do a second pass where we accept .dynsym also 1515 * Failing that, do a second pass where we accept .dynsym also
1427 */ 1516 */
1428 for (self->origin = DSO__ORIG_BUILD_ID_CACHE, want_symtab = 1; 1517 want_symtab = 1;
1429 self->origin != DSO__ORIG_NOT_FOUND; 1518restart:
1430 self->origin++) { 1519 for (dso->symtab_type = SYMTAB__BUILD_ID_CACHE;
1431 switch (self->origin) { 1520 dso->symtab_type != SYMTAB__NOT_FOUND;
1432 case DSO__ORIG_BUILD_ID_CACHE: 1521 dso->symtab_type++) {
1433 if (dso__build_id_filename(self, name, size) == NULL) 1522 switch (dso->symtab_type) {
1523 case SYMTAB__BUILD_ID_CACHE:
1524 /* skip the locally configured cache if a symfs is given */
1525 if (symbol_conf.symfs[0] ||
1526 (dso__build_id_filename(dso, name, size) == NULL)) {
1434 continue; 1527 continue;
1528 }
1435 break; 1529 break;
1436 case DSO__ORIG_FEDORA: 1530 case SYMTAB__FEDORA_DEBUGINFO:
1437 snprintf(name, size, "/usr/lib/debug%s.debug", 1531 snprintf(name, size, "%s/usr/lib/debug%s.debug",
1438 self->long_name); 1532 symbol_conf.symfs, dso->long_name);
1439 break; 1533 break;
1440 case DSO__ORIG_UBUNTU: 1534 case SYMTAB__UBUNTU_DEBUGINFO:
1441 snprintf(name, size, "/usr/lib/debug%s", 1535 snprintf(name, size, "%s/usr/lib/debug%s",
1442 self->long_name); 1536 symbol_conf.symfs, dso->long_name);
1443 break; 1537 break;
1444 case DSO__ORIG_BUILDID: { 1538 case SYMTAB__BUILDID_DEBUGINFO: {
1445 char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 1539 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
1446 1540
1447 if (!self->has_build_id) 1541 if (!dso->has_build_id)
1448 continue; 1542 continue;
1449 1543
1450 build_id__sprintf(self->build_id, 1544 build_id__sprintf(dso->build_id,
1451 sizeof(self->build_id), 1545 sizeof(dso->build_id),
1452 build_id_hex); 1546 build_id_hex);
1453 snprintf(name, size, 1547 snprintf(name, size,
1454 "/usr/lib/debug/.build-id/%.2s/%s.debug", 1548 "%s/usr/lib/debug/.build-id/%.2s/%s.debug",
1455 build_id_hex, build_id_hex + 2); 1549 symbol_conf.symfs, build_id_hex, build_id_hex + 2);
1456 } 1550 }
1457 break; 1551 break;
1458 case DSO__ORIG_DSO: 1552 case SYMTAB__SYSTEM_PATH_DSO:
1459 snprintf(name, size, "%s", self->long_name); 1553 snprintf(name, size, "%s%s",
1554 symbol_conf.symfs, dso->long_name);
1460 break; 1555 break;
1461 case DSO__ORIG_GUEST_KMODULE: 1556 case SYMTAB__GUEST_KMODULE:
1462 if (map->groups && map->groups->machine) 1557 if (map->groups && machine)
1463 root_dir = map->groups->machine->root_dir; 1558 root_dir = machine->root_dir;
1464 else 1559 else
1465 root_dir = ""; 1560 root_dir = "";
1466 snprintf(name, size, "%s%s", root_dir, self->long_name); 1561 snprintf(name, size, "%s%s%s", symbol_conf.symfs,
1562 root_dir, dso->long_name);
1467 break; 1563 break;
1468 1564
1469 default: 1565 case SYMTAB__SYSTEM_PATH_KMODULE:
1470 /* 1566 snprintf(name, size, "%s%s", symbol_conf.symfs,
1471 * If we wanted a full symtab but no image had one, 1567 dso->long_name);
1472 * relax our requirements and repeat the search. 1568 break;
1473 */ 1569 default:;
1474 if (want_symtab) {
1475 want_symtab = 0;
1476 self->origin = DSO__ORIG_BUILD_ID_CACHE;
1477 } else
1478 continue;
1479 } 1570 }
1480 1571
1481 /* Name is now the name of the next image to try */ 1572 /* Name is now the name of the next image to try */
@@ -1483,7 +1574,7 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
1483 if (fd < 0) 1574 if (fd < 0)
1484 continue; 1575 continue;
1485 1576
1486 ret = dso__load_sym(self, map, name, fd, filter, 0, 1577 ret = dso__load_sym(dso, map, name, fd, filter, 0,
1487 want_symtab); 1578 want_symtab);
1488 close(fd); 1579 close(fd);
1489 1580
@@ -1495,25 +1586,35 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
1495 continue; 1586 continue;
1496 1587
1497 if (ret > 0) { 1588 if (ret > 0) {
1498 int nr_plt = dso__synthesize_plt_symbols(self, map, filter); 1589 int nr_plt = dso__synthesize_plt_symbols(dso, map,
1590 filter);
1499 if (nr_plt > 0) 1591 if (nr_plt > 0)
1500 ret += nr_plt; 1592 ret += nr_plt;
1501 break; 1593 break;
1502 } 1594 }
1503 } 1595 }
1504 1596
1597 /*
1598 * If we wanted a full symtab but no image had one,
1599 * relax our requirements and repeat the search.
1600 */
1601 if (ret <= 0 && want_symtab) {
1602 want_symtab = 0;
1603 goto restart;
1604 }
1605
1505 free(name); 1606 free(name);
1506 if (ret < 0 && strstr(self->name, " (deleted)") != NULL) 1607 if (ret < 0 && strstr(dso->name, " (deleted)") != NULL)
1507 return 0; 1608 return 0;
1508 return ret; 1609 return ret;
1509} 1610}
1510 1611
1511struct map *map_groups__find_by_name(struct map_groups *self, 1612struct map *map_groups__find_by_name(struct map_groups *mg,
1512 enum map_type type, const char *name) 1613 enum map_type type, const char *name)
1513{ 1614{
1514 struct rb_node *nd; 1615 struct rb_node *nd;
1515 1616
1516 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { 1617 for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) {
1517 struct map *map = rb_entry(nd, struct map, rb_node); 1618 struct map *map = rb_entry(nd, struct map, rb_node);
1518 1619
1519 if (map->dso && strcmp(map->dso->short_name, name) == 0) 1620 if (map->dso && strcmp(map->dso->short_name, name) == 0)
@@ -1523,28 +1624,28 @@ struct map *map_groups__find_by_name(struct map_groups *self,
1523 return NULL; 1624 return NULL;
1524} 1625}
1525 1626
1526static int dso__kernel_module_get_build_id(struct dso *self, 1627static int dso__kernel_module_get_build_id(struct dso *dso,
1527 const char *root_dir) 1628 const char *root_dir)
1528{ 1629{
1529 char filename[PATH_MAX]; 1630 char filename[PATH_MAX];
1530 /* 1631 /*
1531 * kernel module short names are of the form "[module]" and 1632 * kernel module short names are of the form "[module]" and
1532 * we need just "module" here. 1633 * we need just "module" here.
1533 */ 1634 */
1534 const char *name = self->short_name + 1; 1635 const char *name = dso->short_name + 1;
1535 1636
1536 snprintf(filename, sizeof(filename), 1637 snprintf(filename, sizeof(filename),
1537 "%s/sys/module/%.*s/notes/.note.gnu.build-id", 1638 "%s/sys/module/%.*s/notes/.note.gnu.build-id",
1538 root_dir, (int)strlen(name) - 1, name); 1639 root_dir, (int)strlen(name) - 1, name);
1539 1640
1540 if (sysfs__read_build_id(filename, self->build_id, 1641 if (sysfs__read_build_id(filename, dso->build_id,
1541 sizeof(self->build_id)) == 0) 1642 sizeof(dso->build_id)) == 0)
1542 self->has_build_id = true; 1643 dso->has_build_id = true;
1543 1644
1544 return 0; 1645 return 0;
1545} 1646}
1546 1647
1547static int map_groups__set_modules_path_dir(struct map_groups *self, 1648static int map_groups__set_modules_path_dir(struct map_groups *mg,
1548 const char *dir_name) 1649 const char *dir_name)
1549{ 1650{
1550 struct dirent *dent; 1651 struct dirent *dent;
@@ -1572,7 +1673,7 @@ static int map_groups__set_modules_path_dir(struct map_groups *self,
1572 1673
1573 snprintf(path, sizeof(path), "%s/%s", 1674 snprintf(path, sizeof(path), "%s/%s",
1574 dir_name, dent->d_name); 1675 dir_name, dent->d_name);
1575 ret = map_groups__set_modules_path_dir(self, path); 1676 ret = map_groups__set_modules_path_dir(mg, path);
1576 if (ret < 0) 1677 if (ret < 0)
1577 goto out; 1678 goto out;
1578 } else { 1679 } else {
@@ -1587,7 +1688,8 @@ static int map_groups__set_modules_path_dir(struct map_groups *self,
1587 (int)(dot - dent->d_name), dent->d_name); 1688 (int)(dot - dent->d_name), dent->d_name);
1588 1689
1589 strxfrchar(dso_name, '-', '_'); 1690 strxfrchar(dso_name, '-', '_');
1590 map = map_groups__find_by_name(self, MAP__FUNCTION, dso_name); 1691 map = map_groups__find_by_name(mg, MAP__FUNCTION,
1692 dso_name);
1591 if (map == NULL) 1693 if (map == NULL)
1592 continue; 1694 continue;
1593 1695
@@ -1637,20 +1739,20 @@ static char *get_kernel_version(const char *root_dir)
1637 return strdup(name); 1739 return strdup(name);
1638} 1740}
1639 1741
1640static int machine__set_modules_path(struct machine *self) 1742static int machine__set_modules_path(struct machine *machine)
1641{ 1743{
1642 char *version; 1744 char *version;
1643 char modules_path[PATH_MAX]; 1745 char modules_path[PATH_MAX];
1644 1746
1645 version = get_kernel_version(self->root_dir); 1747 version = get_kernel_version(machine->root_dir);
1646 if (!version) 1748 if (!version)
1647 return -1; 1749 return -1;
1648 1750
1649 snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel", 1751 snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel",
1650 self->root_dir, version); 1752 machine->root_dir, version);
1651 free(version); 1753 free(version);
1652 1754
1653 return map_groups__set_modules_path_dir(&self->kmaps, modules_path); 1755 return map_groups__set_modules_path_dir(&machine->kmaps, modules_path);
1654} 1756}
1655 1757
1656/* 1758/*
@@ -1660,23 +1762,23 @@ static int machine__set_modules_path(struct machine *self)
1660 */ 1762 */
1661static struct map *map__new2(u64 start, struct dso *dso, enum map_type type) 1763static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1662{ 1764{
1663 struct map *self = calloc(1, (sizeof(*self) + 1765 struct map *map = calloc(1, (sizeof(*map) +
1664 (dso->kernel ? sizeof(struct kmap) : 0))); 1766 (dso->kernel ? sizeof(struct kmap) : 0)));
1665 if (self != NULL) { 1767 if (map != NULL) {
1666 /* 1768 /*
1667 * ->end will be filled after we load all the symbols 1769 * ->end will be filled after we load all the symbols
1668 */ 1770 */
1669 map__init(self, type, start, 0, 0, dso); 1771 map__init(map, type, start, 0, 0, dso);
1670 } 1772 }
1671 1773
1672 return self; 1774 return map;
1673} 1775}
1674 1776
1675struct map *machine__new_module(struct machine *self, u64 start, 1777struct map *machine__new_module(struct machine *machine, u64 start,
1676 const char *filename) 1778 const char *filename)
1677{ 1779{
1678 struct map *map; 1780 struct map *map;
1679 struct dso *dso = __dsos__findnew(&self->kernel_dsos, filename); 1781 struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename);
1680 1782
1681 if (dso == NULL) 1783 if (dso == NULL)
1682 return NULL; 1784 return NULL;
@@ -1685,15 +1787,15 @@ struct map *machine__new_module(struct machine *self, u64 start,
1685 if (map == NULL) 1787 if (map == NULL)
1686 return NULL; 1788 return NULL;
1687 1789
1688 if (machine__is_host(self)) 1790 if (machine__is_host(machine))
1689 dso->origin = DSO__ORIG_KMODULE; 1791 dso->symtab_type = SYMTAB__SYSTEM_PATH_KMODULE;
1690 else 1792 else
1691 dso->origin = DSO__ORIG_GUEST_KMODULE; 1793 dso->symtab_type = SYMTAB__GUEST_KMODULE;
1692 map_groups__insert(&self->kmaps, map); 1794 map_groups__insert(&machine->kmaps, map);
1693 return map; 1795 return map;
1694} 1796}
1695 1797
1696static int machine__create_modules(struct machine *self) 1798static int machine__create_modules(struct machine *machine)
1697{ 1799{
1698 char *line = NULL; 1800 char *line = NULL;
1699 size_t n; 1801 size_t n;
@@ -1702,13 +1804,16 @@ static int machine__create_modules(struct machine *self)
1702 const char *modules; 1804 const char *modules;
1703 char path[PATH_MAX]; 1805 char path[PATH_MAX];
1704 1806
1705 if (machine__is_default_guest(self)) 1807 if (machine__is_default_guest(machine))
1706 modules = symbol_conf.default_guest_modules; 1808 modules = symbol_conf.default_guest_modules;
1707 else { 1809 else {
1708 sprintf(path, "%s/proc/modules", self->root_dir); 1810 sprintf(path, "%s/proc/modules", machine->root_dir);
1709 modules = path; 1811 modules = path;
1710 } 1812 }
1711 1813
1814 if (symbol__restricted_filename(path, "/proc/modules"))
1815 return -1;
1816
1712 file = fopen(modules, "r"); 1817 file = fopen(modules, "r");
1713 if (file == NULL) 1818 if (file == NULL)
1714 return -1; 1819 return -1;
@@ -1741,16 +1846,16 @@ static int machine__create_modules(struct machine *self)
1741 *sep = '\0'; 1846 *sep = '\0';
1742 1847
1743 snprintf(name, sizeof(name), "[%s]", line); 1848 snprintf(name, sizeof(name), "[%s]", line);
1744 map = machine__new_module(self, start, name); 1849 map = machine__new_module(machine, start, name);
1745 if (map == NULL) 1850 if (map == NULL)
1746 goto out_delete_line; 1851 goto out_delete_line;
1747 dso__kernel_module_get_build_id(map->dso, self->root_dir); 1852 dso__kernel_module_get_build_id(map->dso, machine->root_dir);
1748 } 1853 }
1749 1854
1750 free(line); 1855 free(line);
1751 fclose(file); 1856 fclose(file);
1752 1857
1753 return machine__set_modules_path(self); 1858 return machine__set_modules_path(machine);
1754 1859
1755out_delete_line: 1860out_delete_line:
1756 free(line); 1861 free(line);
@@ -1758,26 +1863,30 @@ out_failure:
1758 return -1; 1863 return -1;
1759} 1864}
1760 1865
1761static int dso__load_vmlinux(struct dso *self, struct map *map, 1866int dso__load_vmlinux(struct dso *dso, struct map *map,
1762 const char *vmlinux, symbol_filter_t filter) 1867 const char *vmlinux, symbol_filter_t filter)
1763{ 1868{
1764 int err = -1, fd; 1869 int err = -1, fd;
1870 char symfs_vmlinux[PATH_MAX];
1765 1871
1766 fd = open(vmlinux, O_RDONLY); 1872 snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s",
1873 symbol_conf.symfs, vmlinux);
1874 fd = open(symfs_vmlinux, O_RDONLY);
1767 if (fd < 0) 1875 if (fd < 0)
1768 return -1; 1876 return -1;
1769 1877
1770 dso__set_loaded(self, map->type); 1878 dso__set_long_name(dso, (char *)vmlinux);
1771 err = dso__load_sym(self, map, vmlinux, fd, filter, 0, 0); 1879 dso__set_loaded(dso, map->type);
1880 err = dso__load_sym(dso, map, symfs_vmlinux, fd, filter, 0, 0);
1772 close(fd); 1881 close(fd);
1773 1882
1774 if (err > 0) 1883 if (err > 0)
1775 pr_debug("Using %s for symbols\n", vmlinux); 1884 pr_debug("Using %s for symbols\n", symfs_vmlinux);
1776 1885
1777 return err; 1886 return err;
1778} 1887}
1779 1888
1780int dso__load_vmlinux_path(struct dso *self, struct map *map, 1889int dso__load_vmlinux_path(struct dso *dso, struct map *map,
1781 symbol_filter_t filter) 1890 symbol_filter_t filter)
1782{ 1891{
1783 int i, err = 0; 1892 int i, err = 0;
@@ -1786,20 +1895,20 @@ int dso__load_vmlinux_path(struct dso *self, struct map *map,
1786 pr_debug("Looking at the vmlinux_path (%d entries long)\n", 1895 pr_debug("Looking at the vmlinux_path (%d entries long)\n",
1787 vmlinux_path__nr_entries + 1); 1896 vmlinux_path__nr_entries + 1);
1788 1897
1789 filename = dso__build_id_filename(self, NULL, 0); 1898 filename = dso__build_id_filename(dso, NULL, 0);
1790 if (filename != NULL) { 1899 if (filename != NULL) {
1791 err = dso__load_vmlinux(self, map, filename, filter); 1900 err = dso__load_vmlinux(dso, map, filename, filter);
1792 if (err > 0) { 1901 if (err > 0) {
1793 dso__set_long_name(self, filename); 1902 dso__set_long_name(dso, filename);
1794 goto out; 1903 goto out;
1795 } 1904 }
1796 free(filename); 1905 free(filename);
1797 } 1906 }
1798 1907
1799 for (i = 0; i < vmlinux_path__nr_entries; ++i) { 1908 for (i = 0; i < vmlinux_path__nr_entries; ++i) {
1800 err = dso__load_vmlinux(self, map, vmlinux_path[i], filter); 1909 err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter);
1801 if (err > 0) { 1910 if (err > 0) {
1802 dso__set_long_name(self, strdup(vmlinux_path[i])); 1911 dso__set_long_name(dso, strdup(vmlinux_path[i]));
1803 break; 1912 break;
1804 } 1913 }
1805 } 1914 }
@@ -1807,15 +1916,15 @@ out:
1807 return err; 1916 return err;
1808} 1917}
1809 1918
1810static int dso__load_kernel_sym(struct dso *self, struct map *map, 1919static int dso__load_kernel_sym(struct dso *dso, struct map *map,
1811 symbol_filter_t filter) 1920 symbol_filter_t filter)
1812{ 1921{
1813 int err; 1922 int err;
1814 const char *kallsyms_filename = NULL; 1923 const char *kallsyms_filename = NULL;
1815 char *kallsyms_allocated_filename = NULL; 1924 char *kallsyms_allocated_filename = NULL;
1816 /* 1925 /*
1817 * Step 1: if the user specified a vmlinux filename, use it and only 1926 * Step 1: if the user specified a kallsyms or vmlinux filename, use
1818 * it, reporting errors to the user if it cannot be used. 1927 * it and only it, reporting errors to the user if it cannot be used.
1819 * 1928 *
1820 * For instance, try to analyse an ARM perf.data file _without_ a 1929 * For instance, try to analyse an ARM perf.data file _without_ a
1821 * build-id, or if the user specifies the wrong path to the right 1930 * build-id, or if the user specifies the wrong path to the right
@@ -1828,11 +1937,16 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
1828 * validation in dso__load_vmlinux and will bail out if they don't 1937 * validation in dso__load_vmlinux and will bail out if they don't
1829 * match. 1938 * match.
1830 */ 1939 */
1940 if (symbol_conf.kallsyms_name != NULL) {
1941 kallsyms_filename = symbol_conf.kallsyms_name;
1942 goto do_kallsyms;
1943 }
1944
1831 if (symbol_conf.vmlinux_name != NULL) { 1945 if (symbol_conf.vmlinux_name != NULL) {
1832 err = dso__load_vmlinux(self, map, 1946 err = dso__load_vmlinux(dso, map,
1833 symbol_conf.vmlinux_name, filter); 1947 symbol_conf.vmlinux_name, filter);
1834 if (err > 0) { 1948 if (err > 0) {
1835 dso__set_long_name(self, 1949 dso__set_long_name(dso,
1836 strdup(symbol_conf.vmlinux_name)); 1950 strdup(symbol_conf.vmlinux_name));
1837 goto out_fixup; 1951 goto out_fixup;
1838 } 1952 }
@@ -1840,23 +1954,27 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
1840 } 1954 }
1841 1955
1842 if (vmlinux_path != NULL) { 1956 if (vmlinux_path != NULL) {
1843 err = dso__load_vmlinux_path(self, map, filter); 1957 err = dso__load_vmlinux_path(dso, map, filter);
1844 if (err > 0) 1958 if (err > 0)
1845 goto out_fixup; 1959 goto out_fixup;
1846 } 1960 }
1847 1961
1962 /* do not try local files if a symfs was given */
1963 if (symbol_conf.symfs[0] != 0)
1964 return -1;
1965
1848 /* 1966 /*
1849 * Say the kernel DSO was created when processing the build-id header table, 1967 * Say the kernel DSO was created when processing the build-id header table,
1850 * we have a build-id, so check if it is the same as the running kernel, 1968 * we have a build-id, so check if it is the same as the running kernel,
1851 * using it if it is. 1969 * using it if it is.
1852 */ 1970 */
1853 if (self->has_build_id) { 1971 if (dso->has_build_id) {
1854 u8 kallsyms_build_id[BUILD_ID_SIZE]; 1972 u8 kallsyms_build_id[BUILD_ID_SIZE];
1855 char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 1973 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
1856 1974
1857 if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id, 1975 if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
1858 sizeof(kallsyms_build_id)) == 0) { 1976 sizeof(kallsyms_build_id)) == 0) {
1859 if (dso__build_id_equal(self, kallsyms_build_id)) { 1977 if (dso__build_id_equal(dso, kallsyms_build_id)) {
1860 kallsyms_filename = "/proc/kallsyms"; 1978 kallsyms_filename = "/proc/kallsyms";
1861 goto do_kallsyms; 1979 goto do_kallsyms;
1862 } 1980 }
@@ -1865,7 +1983,7 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
1865 * Now look if we have it on the build-id cache in 1983 * Now look if we have it on the build-id cache in
1866 * $HOME/.debug/[kernel.kallsyms]. 1984 * $HOME/.debug/[kernel.kallsyms].
1867 */ 1985 */
1868 build_id__sprintf(self->build_id, sizeof(self->build_id), 1986 build_id__sprintf(dso->build_id, sizeof(dso->build_id),
1869 sbuild_id); 1987 sbuild_id);
1870 1988
1871 if (asprintf(&kallsyms_allocated_filename, 1989 if (asprintf(&kallsyms_allocated_filename,
@@ -1892,7 +2010,7 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
1892 } 2010 }
1893 2011
1894do_kallsyms: 2012do_kallsyms:
1895 err = dso__load_kallsyms(self, kallsyms_filename, map, filter); 2013 err = dso__load_kallsyms(dso, kallsyms_filename, map, filter);
1896 if (err > 0) 2014 if (err > 0)
1897 pr_debug("Using %s for symbols\n", kallsyms_filename); 2015 pr_debug("Using %s for symbols\n", kallsyms_filename);
1898 free(kallsyms_allocated_filename); 2016 free(kallsyms_allocated_filename);
@@ -1900,7 +2018,7 @@ do_kallsyms:
1900 if (err > 0) { 2018 if (err > 0) {
1901out_fixup: 2019out_fixup:
1902 if (kallsyms_filename != NULL) 2020 if (kallsyms_filename != NULL)
1903 dso__set_long_name(self, strdup("[kernel.kallsyms]")); 2021 dso__set_long_name(dso, strdup("[kernel.kallsyms]"));
1904 map__fixup_start(map); 2022 map__fixup_start(map);
1905 map__fixup_end(map); 2023 map__fixup_end(map);
1906 } 2024 }
@@ -1908,8 +2026,8 @@ out_fixup:
1908 return err; 2026 return err;
1909} 2027}
1910 2028
1911static int dso__load_guest_kernel_sym(struct dso *self, struct map *map, 2029static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
1912 symbol_filter_t filter) 2030 symbol_filter_t filter)
1913{ 2031{
1914 int err; 2032 int err;
1915 const char *kallsyms_filename = NULL; 2033 const char *kallsyms_filename = NULL;
@@ -1929,7 +2047,7 @@ static int dso__load_guest_kernel_sym(struct dso *self, struct map *map,
1929 * Or use file guest_kallsyms inputted by user on commandline 2047 * Or use file guest_kallsyms inputted by user on commandline
1930 */ 2048 */
1931 if (symbol_conf.default_guest_vmlinux_name != NULL) { 2049 if (symbol_conf.default_guest_vmlinux_name != NULL) {
1932 err = dso__load_vmlinux(self, map, 2050 err = dso__load_vmlinux(dso, map,
1933 symbol_conf.default_guest_vmlinux_name, filter); 2051 symbol_conf.default_guest_vmlinux_name, filter);
1934 goto out_try_fixup; 2052 goto out_try_fixup;
1935 } 2053 }
@@ -1942,7 +2060,7 @@ static int dso__load_guest_kernel_sym(struct dso *self, struct map *map,
1942 kallsyms_filename = path; 2060 kallsyms_filename = path;
1943 } 2061 }
1944 2062
1945 err = dso__load_kallsyms(self, kallsyms_filename, map, filter); 2063 err = dso__load_kallsyms(dso, kallsyms_filename, map, filter);
1946 if (err > 0) 2064 if (err > 0)
1947 pr_debug("Using %s for symbols\n", kallsyms_filename); 2065 pr_debug("Using %s for symbols\n", kallsyms_filename);
1948 2066
@@ -1950,7 +2068,7 @@ out_try_fixup:
1950 if (err > 0) { 2068 if (err > 0) {
1951 if (kallsyms_filename != NULL) { 2069 if (kallsyms_filename != NULL) {
1952 machine__mmap_name(machine, path, sizeof(path)); 2070 machine__mmap_name(machine, path, sizeof(path));
1953 dso__set_long_name(self, strdup(path)); 2071 dso__set_long_name(dso, strdup(path));
1954 } 2072 }
1955 map__fixup_start(map); 2073 map__fixup_start(map);
1956 map__fixup_end(map); 2074 map__fixup_end(map);
@@ -2003,12 +2121,12 @@ size_t __dsos__fprintf(struct list_head *head, FILE *fp)
2003 return ret; 2121 return ret;
2004} 2122}
2005 2123
2006size_t machines__fprintf_dsos(struct rb_root *self, FILE *fp) 2124size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp)
2007{ 2125{
2008 struct rb_node *nd; 2126 struct rb_node *nd;
2009 size_t ret = 0; 2127 size_t ret = 0;
2010 2128
2011 for (nd = rb_first(self); nd; nd = rb_next(nd)) { 2129 for (nd = rb_first(machines); nd; nd = rb_next(nd)) {
2012 struct machine *pos = rb_entry(nd, struct machine, rb_node); 2130 struct machine *pos = rb_entry(nd, struct machine, rb_node);
2013 ret += __dsos__fprintf(&pos->kernel_dsos, fp); 2131 ret += __dsos__fprintf(&pos->kernel_dsos, fp);
2014 ret += __dsos__fprintf(&pos->user_dsos, fp); 2132 ret += __dsos__fprintf(&pos->user_dsos, fp);
@@ -2032,18 +2150,20 @@ static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
2032 return ret; 2150 return ret;
2033} 2151}
2034 2152
2035size_t machine__fprintf_dsos_buildid(struct machine *self, FILE *fp, bool with_hits) 2153size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp,
2154 bool with_hits)
2036{ 2155{
2037 return __dsos__fprintf_buildid(&self->kernel_dsos, fp, with_hits) + 2156 return __dsos__fprintf_buildid(&machine->kernel_dsos, fp, with_hits) +
2038 __dsos__fprintf_buildid(&self->user_dsos, fp, with_hits); 2157 __dsos__fprintf_buildid(&machine->user_dsos, fp, with_hits);
2039} 2158}
2040 2159
2041size_t machines__fprintf_dsos_buildid(struct rb_root *self, FILE *fp, bool with_hits) 2160size_t machines__fprintf_dsos_buildid(struct rb_root *machines,
2161 FILE *fp, bool with_hits)
2042{ 2162{
2043 struct rb_node *nd; 2163 struct rb_node *nd;
2044 size_t ret = 0; 2164 size_t ret = 0;
2045 2165
2046 for (nd = rb_first(self); nd; nd = rb_next(nd)) { 2166 for (nd = rb_first(machines); nd; nd = rb_next(nd)) {
2047 struct machine *pos = rb_entry(nd, struct machine, rb_node); 2167 struct machine *pos = rb_entry(nd, struct machine, rb_node);
2048 ret += machine__fprintf_dsos_buildid(pos, fp, with_hits); 2168 ret += machine__fprintf_dsos_buildid(pos, fp, with_hits);
2049 } 2169 }
@@ -2052,97 +2172,143 @@ size_t machines__fprintf_dsos_buildid(struct rb_root *self, FILE *fp, bool with_
2052 2172
2053struct dso *dso__new_kernel(const char *name) 2173struct dso *dso__new_kernel(const char *name)
2054{ 2174{
2055 struct dso *self = dso__new(name ?: "[kernel.kallsyms]"); 2175 struct dso *dso = dso__new(name ?: "[kernel.kallsyms]");
2056 2176
2057 if (self != NULL) { 2177 if (dso != NULL) {
2058 dso__set_short_name(self, "[kernel]"); 2178 dso__set_short_name(dso, "[kernel]");
2059 self->kernel = DSO_TYPE_KERNEL; 2179 dso->kernel = DSO_TYPE_KERNEL;
2060 } 2180 }
2061 2181
2062 return self; 2182 return dso;
2063} 2183}
2064 2184
2065static struct dso *dso__new_guest_kernel(struct machine *machine, 2185static struct dso *dso__new_guest_kernel(struct machine *machine,
2066 const char *name) 2186 const char *name)
2067{ 2187{
2068 char bf[PATH_MAX]; 2188 char bf[PATH_MAX];
2069 struct dso *self = dso__new(name ?: machine__mmap_name(machine, bf, sizeof(bf))); 2189 struct dso *dso = dso__new(name ?: machine__mmap_name(machine, bf,
2070 2190 sizeof(bf)));
2071 if (self != NULL) { 2191 if (dso != NULL) {
2072 dso__set_short_name(self, "[guest.kernel]"); 2192 dso__set_short_name(dso, "[guest.kernel]");
2073 self->kernel = DSO_TYPE_GUEST_KERNEL; 2193 dso->kernel = DSO_TYPE_GUEST_KERNEL;
2074 } 2194 }
2075 2195
2076 return self; 2196 return dso;
2077} 2197}
2078 2198
2079void dso__read_running_kernel_build_id(struct dso *self, struct machine *machine) 2199void dso__read_running_kernel_build_id(struct dso *dso, struct machine *machine)
2080{ 2200{
2081 char path[PATH_MAX]; 2201 char path[PATH_MAX];
2082 2202
2083 if (machine__is_default_guest(machine)) 2203 if (machine__is_default_guest(machine))
2084 return; 2204 return;
2085 sprintf(path, "%s/sys/kernel/notes", machine->root_dir); 2205 sprintf(path, "%s/sys/kernel/notes", machine->root_dir);
2086 if (sysfs__read_build_id(path, self->build_id, 2206 if (sysfs__read_build_id(path, dso->build_id,
2087 sizeof(self->build_id)) == 0) 2207 sizeof(dso->build_id)) == 0)
2088 self->has_build_id = true; 2208 dso->has_build_id = true;
2089} 2209}
2090 2210
2091static struct dso *machine__create_kernel(struct machine *self) 2211static struct dso *machine__create_kernel(struct machine *machine)
2092{ 2212{
2093 const char *vmlinux_name = NULL; 2213 const char *vmlinux_name = NULL;
2094 struct dso *kernel; 2214 struct dso *kernel;
2095 2215
2096 if (machine__is_host(self)) { 2216 if (machine__is_host(machine)) {
2097 vmlinux_name = symbol_conf.vmlinux_name; 2217 vmlinux_name = symbol_conf.vmlinux_name;
2098 kernel = dso__new_kernel(vmlinux_name); 2218 kernel = dso__new_kernel(vmlinux_name);
2099 } else { 2219 } else {
2100 if (machine__is_default_guest(self)) 2220 if (machine__is_default_guest(machine))
2101 vmlinux_name = symbol_conf.default_guest_vmlinux_name; 2221 vmlinux_name = symbol_conf.default_guest_vmlinux_name;
2102 kernel = dso__new_guest_kernel(self, vmlinux_name); 2222 kernel = dso__new_guest_kernel(machine, vmlinux_name);
2103 } 2223 }
2104 2224
2105 if (kernel != NULL) { 2225 if (kernel != NULL) {
2106 dso__read_running_kernel_build_id(kernel, self); 2226 dso__read_running_kernel_build_id(kernel, machine);
2107 dsos__add(&self->kernel_dsos, kernel); 2227 dsos__add(&machine->kernel_dsos, kernel);
2108 } 2228 }
2109 return kernel; 2229 return kernel;
2110} 2230}
2111 2231
2112int __machine__create_kernel_maps(struct machine *self, struct dso *kernel) 2232struct process_args {
2233 u64 start;
2234};
2235
2236static int symbol__in_kernel(void *arg, const char *name,
2237 char type __used, u64 start, u64 end __used)
2238{
2239 struct process_args *args = arg;
2240
2241 if (strchr(name, '['))
2242 return 0;
2243
2244 args->start = start;
2245 return 1;
2246}
2247
2248/* Figure out the start address of kernel map from /proc/kallsyms */
2249static u64 machine__get_kernel_start_addr(struct machine *machine)
2250{
2251 const char *filename;
2252 char path[PATH_MAX];
2253 struct process_args args;
2254
2255 if (machine__is_host(machine)) {
2256 filename = "/proc/kallsyms";
2257 } else {
2258 if (machine__is_default_guest(machine))
2259 filename = (char *)symbol_conf.default_guest_kallsyms;
2260 else {
2261 sprintf(path, "%s/proc/kallsyms", machine->root_dir);
2262 filename = path;
2263 }
2264 }
2265
2266 if (symbol__restricted_filename(filename, "/proc/kallsyms"))
2267 return 0;
2268
2269 if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0)
2270 return 0;
2271
2272 return args.start;
2273}
2274
2275int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel)
2113{ 2276{
2114 enum map_type type; 2277 enum map_type type;
2278 u64 start = machine__get_kernel_start_addr(machine);
2115 2279
2116 for (type = 0; type < MAP__NR_TYPES; ++type) { 2280 for (type = 0; type < MAP__NR_TYPES; ++type) {
2117 struct kmap *kmap; 2281 struct kmap *kmap;
2118 2282
2119 self->vmlinux_maps[type] = map__new2(0, kernel, type); 2283 machine->vmlinux_maps[type] = map__new2(start, kernel, type);
2120 if (self->vmlinux_maps[type] == NULL) 2284 if (machine->vmlinux_maps[type] == NULL)
2121 return -1; 2285 return -1;
2122 2286
2123 self->vmlinux_maps[type]->map_ip = 2287 machine->vmlinux_maps[type]->map_ip =
2124 self->vmlinux_maps[type]->unmap_ip = identity__map_ip; 2288 machine->vmlinux_maps[type]->unmap_ip =
2125 2289 identity__map_ip;
2126 kmap = map__kmap(self->vmlinux_maps[type]); 2290 kmap = map__kmap(machine->vmlinux_maps[type]);
2127 kmap->kmaps = &self->kmaps; 2291 kmap->kmaps = &machine->kmaps;
2128 map_groups__insert(&self->kmaps, self->vmlinux_maps[type]); 2292 map_groups__insert(&machine->kmaps,
2293 machine->vmlinux_maps[type]);
2129 } 2294 }
2130 2295
2131 return 0; 2296 return 0;
2132} 2297}
2133 2298
2134void machine__destroy_kernel_maps(struct machine *self) 2299void machine__destroy_kernel_maps(struct machine *machine)
2135{ 2300{
2136 enum map_type type; 2301 enum map_type type;
2137 2302
2138 for (type = 0; type < MAP__NR_TYPES; ++type) { 2303 for (type = 0; type < MAP__NR_TYPES; ++type) {
2139 struct kmap *kmap; 2304 struct kmap *kmap;
2140 2305
2141 if (self->vmlinux_maps[type] == NULL) 2306 if (machine->vmlinux_maps[type] == NULL)
2142 continue; 2307 continue;
2143 2308
2144 kmap = map__kmap(self->vmlinux_maps[type]); 2309 kmap = map__kmap(machine->vmlinux_maps[type]);
2145 map_groups__remove(&self->kmaps, self->vmlinux_maps[type]); 2310 map_groups__remove(&machine->kmaps,
2311 machine->vmlinux_maps[type]);
2146 if (kmap->ref_reloc_sym) { 2312 if (kmap->ref_reloc_sym) {
2147 /* 2313 /*
2148 * ref_reloc_sym is shared among all maps, so free just 2314 * ref_reloc_sym is shared among all maps, so free just
@@ -2156,25 +2322,25 @@ void machine__destroy_kernel_maps(struct machine *self)
2156 kmap->ref_reloc_sym = NULL; 2322 kmap->ref_reloc_sym = NULL;
2157 } 2323 }
2158 2324
2159 map__delete(self->vmlinux_maps[type]); 2325 map__delete(machine->vmlinux_maps[type]);
2160 self->vmlinux_maps[type] = NULL; 2326 machine->vmlinux_maps[type] = NULL;
2161 } 2327 }
2162} 2328}
2163 2329
2164int machine__create_kernel_maps(struct machine *self) 2330int machine__create_kernel_maps(struct machine *machine)
2165{ 2331{
2166 struct dso *kernel = machine__create_kernel(self); 2332 struct dso *kernel = machine__create_kernel(machine);
2167 2333
2168 if (kernel == NULL || 2334 if (kernel == NULL ||
2169 __machine__create_kernel_maps(self, kernel) < 0) 2335 __machine__create_kernel_maps(machine, kernel) < 0)
2170 return -1; 2336 return -1;
2171 2337
2172 if (symbol_conf.use_modules && machine__create_modules(self) < 0) 2338 if (symbol_conf.use_modules && machine__create_modules(machine) < 0)
2173 pr_debug("Problems creating module maps, continuing anyway...\n"); 2339 pr_debug("Problems creating module maps, continuing anyway...\n");
2174 /* 2340 /*
2175 * Now that we have all the maps created, just set the ->end of them: 2341 * Now that we have all the maps created, just set the ->end of them:
2176 */ 2342 */
2177 map_groups__fixup_end(&self->kmaps); 2343 map_groups__fixup_end(&machine->kmaps);
2178 return 0; 2344 return 0;
2179} 2345}
2180 2346
@@ -2194,9 +2360,6 @@ static int vmlinux_path__init(void)
2194 struct utsname uts; 2360 struct utsname uts;
2195 char bf[PATH_MAX]; 2361 char bf[PATH_MAX];
2196 2362
2197 if (uname(&uts) < 0)
2198 return -1;
2199
2200 vmlinux_path = malloc(sizeof(char *) * 5); 2363 vmlinux_path = malloc(sizeof(char *) * 5);
2201 if (vmlinux_path == NULL) 2364 if (vmlinux_path == NULL)
2202 return -1; 2365 return -1;
@@ -2209,6 +2372,14 @@ static int vmlinux_path__init(void)
2209 if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2372 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2210 goto out_fail; 2373 goto out_fail;
2211 ++vmlinux_path__nr_entries; 2374 ++vmlinux_path__nr_entries;
2375
2376 /* only try running kernel version if no symfs was given */
2377 if (symbol_conf.symfs[0] != 0)
2378 return 0;
2379
2380 if (uname(&uts) < 0)
2381 return -1;
2382
2212 snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release); 2383 snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
2213 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 2384 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
2214 if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2385 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
@@ -2233,11 +2404,11 @@ out_fail:
2233 return -1; 2404 return -1;
2234} 2405}
2235 2406
2236size_t machine__fprintf_vmlinux_path(struct machine *self, FILE *fp) 2407size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp)
2237{ 2408{
2238 int i; 2409 int i;
2239 size_t printed = 0; 2410 size_t printed = 0;
2240 struct dso *kdso = self->vmlinux_maps[MAP__FUNCTION]->dso; 2411 struct dso *kdso = machine->vmlinux_maps[MAP__FUNCTION]->dso;
2241 2412
2242 if (kdso->has_build_id) { 2413 if (kdso->has_build_id) {
2243 char filename[PATH_MAX]; 2414 char filename[PATH_MAX];
@@ -2266,11 +2437,34 @@ static int setup_list(struct strlist **list, const char *list_str,
2266 return 0; 2437 return 0;
2267} 2438}
2268 2439
2440static bool symbol__read_kptr_restrict(void)
2441{
2442 bool value = false;
2443
2444 if (geteuid() != 0) {
2445 FILE *fp = fopen("/proc/sys/kernel/kptr_restrict", "r");
2446 if (fp != NULL) {
2447 char line[8];
2448
2449 if (fgets(line, sizeof(line), fp) != NULL)
2450 value = atoi(line) != 0;
2451
2452 fclose(fp);
2453 }
2454 }
2455
2456 return value;
2457}
2458
2269int symbol__init(void) 2459int symbol__init(void)
2270{ 2460{
2461 const char *symfs;
2462
2271 if (symbol_conf.initialized) 2463 if (symbol_conf.initialized)
2272 return 0; 2464 return 0;
2273 2465
2466 symbol_conf.priv_size = ALIGN(symbol_conf.priv_size, sizeof(u64));
2467
2274 elf_version(EV_CURRENT); 2468 elf_version(EV_CURRENT);
2275 if (symbol_conf.sort_by_name) 2469 if (symbol_conf.sort_by_name)
2276 symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - 2470 symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
@@ -2296,6 +2490,20 @@ int symbol__init(void)
2296 symbol_conf.sym_list_str, "symbol") < 0) 2490 symbol_conf.sym_list_str, "symbol") < 0)
2297 goto out_free_comm_list; 2491 goto out_free_comm_list;
2298 2492
2493 /*
2494 * A path to symbols of "/" is identical to ""
2495 * reset here for simplicity.
2496 */
2497 symfs = realpath(symbol_conf.symfs, NULL);
2498 if (symfs == NULL)
2499 symfs = symbol_conf.symfs;
2500 if (strcmp(symfs, "/") == 0)
2501 symbol_conf.symfs = "";
2502 if (symfs != symbol_conf.symfs)
2503 free((void *)symfs);
2504
2505 symbol_conf.kptr_restrict = symbol__read_kptr_restrict();
2506
2299 symbol_conf.initialized = true; 2507 symbol_conf.initialized = true;
2300 return 0; 2508 return 0;
2301 2509
@@ -2318,9 +2526,9 @@ void symbol__exit(void)
2318 symbol_conf.initialized = false; 2526 symbol_conf.initialized = false;
2319} 2527}
2320 2528
2321int machines__create_kernel_maps(struct rb_root *self, pid_t pid) 2529int machines__create_kernel_maps(struct rb_root *machines, pid_t pid)
2322{ 2530{
2323 struct machine *machine = machines__findnew(self, pid); 2531 struct machine *machine = machines__findnew(machines, pid);
2324 2532
2325 if (machine == NULL) 2533 if (machine == NULL)
2326 return -1; 2534 return -1;
@@ -2371,7 +2579,7 @@ char *strxfrchar(char *s, char from, char to)
2371 return s; 2579 return s;
2372} 2580}
2373 2581
2374int machines__create_guest_kernel_maps(struct rb_root *self) 2582int machines__create_guest_kernel_maps(struct rb_root *machines)
2375{ 2583{
2376 int ret = 0; 2584 int ret = 0;
2377 struct dirent **namelist = NULL; 2585 struct dirent **namelist = NULL;
@@ -2382,7 +2590,7 @@ int machines__create_guest_kernel_maps(struct rb_root *self)
2382 if (symbol_conf.default_guest_vmlinux_name || 2590 if (symbol_conf.default_guest_vmlinux_name ||
2383 symbol_conf.default_guest_modules || 2591 symbol_conf.default_guest_modules ||
2384 symbol_conf.default_guest_kallsyms) { 2592 symbol_conf.default_guest_kallsyms) {
2385 machines__create_kernel_maps(self, DEFAULT_GUEST_KERNEL_ID); 2593 machines__create_kernel_maps(machines, DEFAULT_GUEST_KERNEL_ID);
2386 } 2594 }
2387 2595
2388 if (symbol_conf.guestmount) { 2596 if (symbol_conf.guestmount) {
@@ -2403,7 +2611,7 @@ int machines__create_guest_kernel_maps(struct rb_root *self)
2403 pr_debug("Can't access file %s\n", path); 2611 pr_debug("Can't access file %s\n", path);
2404 goto failure; 2612 goto failure;
2405 } 2613 }
2406 machines__create_kernel_maps(self, pid); 2614 machines__create_kernel_maps(machines, pid);
2407 } 2615 }
2408failure: 2616failure:
2409 free(namelist); 2617 free(namelist);
@@ -2412,23 +2620,23 @@ failure:
2412 return ret; 2620 return ret;
2413} 2621}
2414 2622
2415void machines__destroy_guest_kernel_maps(struct rb_root *self) 2623void machines__destroy_guest_kernel_maps(struct rb_root *machines)
2416{ 2624{
2417 struct rb_node *next = rb_first(self); 2625 struct rb_node *next = rb_first(machines);
2418 2626
2419 while (next) { 2627 while (next) {
2420 struct machine *pos = rb_entry(next, struct machine, rb_node); 2628 struct machine *pos = rb_entry(next, struct machine, rb_node);
2421 2629
2422 next = rb_next(&pos->rb_node); 2630 next = rb_next(&pos->rb_node);
2423 rb_erase(&pos->rb_node, self); 2631 rb_erase(&pos->rb_node, machines);
2424 machine__delete(pos); 2632 machine__delete(pos);
2425 } 2633 }
2426} 2634}
2427 2635
2428int machine__load_kallsyms(struct machine *self, const char *filename, 2636int machine__load_kallsyms(struct machine *machine, const char *filename,
2429 enum map_type type, symbol_filter_t filter) 2637 enum map_type type, symbol_filter_t filter)
2430{ 2638{
2431 struct map *map = self->vmlinux_maps[type]; 2639 struct map *map = machine->vmlinux_maps[type];
2432 int ret = dso__load_kallsyms(map->dso, filename, map, filter); 2640 int ret = dso__load_kallsyms(map->dso, filename, map, filter);
2433 2641
2434 if (ret > 0) { 2642 if (ret > 0) {
@@ -2438,16 +2646,16 @@ int machine__load_kallsyms(struct machine *self, const char *filename,
2438 * kernel, with modules between them, fixup the end of all 2646 * kernel, with modules between them, fixup the end of all
2439 * sections. 2647 * sections.
2440 */ 2648 */
2441 __map_groups__fixup_end(&self->kmaps, type); 2649 __map_groups__fixup_end(&machine->kmaps, type);
2442 } 2650 }
2443 2651
2444 return ret; 2652 return ret;
2445} 2653}
2446 2654
2447int machine__load_vmlinux_path(struct machine *self, enum map_type type, 2655int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
2448 symbol_filter_t filter) 2656 symbol_filter_t filter)
2449{ 2657{
2450 struct map *map = self->vmlinux_maps[type]; 2658 struct map *map = machine->vmlinux_maps[type];
2451 int ret = dso__load_vmlinux_path(map->dso, map, filter); 2659 int ret = dso__load_vmlinux_path(map->dso, map, filter);
2452 2660
2453 if (ret > 0) { 2661 if (ret > 0) {
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index ea95c2756f05..325ee36a9d29 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -48,16 +48,21 @@ char *strxfrchar(char *s, char from, char to);
48 48
49#define BUILD_ID_SIZE 20 49#define BUILD_ID_SIZE 20
50 50
51/** struct symbol - symtab entry
52 *
53 * @ignore - resolvable but tools ignore it (e.g. idle routines)
54 */
51struct symbol { 55struct symbol {
52 struct rb_node rb_node; 56 struct rb_node rb_node;
53 u64 start; 57 u64 start;
54 u64 end; 58 u64 end;
55 u16 namelen; 59 u16 namelen;
56 u8 binding; 60 u8 binding;
61 bool ignore;
57 char name[0]; 62 char name[0];
58}; 63};
59 64
60void symbol__delete(struct symbol *self); 65void symbol__delete(struct symbol *sym);
61 66
62struct strlist; 67struct strlist;
63 68
@@ -70,8 +75,10 @@ struct symbol_conf {
70 use_callchain, 75 use_callchain,
71 exclude_other, 76 exclude_other,
72 show_cpu_utilization, 77 show_cpu_utilization,
73 initialized; 78 initialized,
79 kptr_restrict;
74 const char *vmlinux_name, 80 const char *vmlinux_name,
81 *kallsyms_name,
75 *source_prefix, 82 *source_prefix,
76 *field_sep; 83 *field_sep;
77 const char *default_guest_vmlinux_name, 84 const char *default_guest_vmlinux_name,
@@ -85,13 +92,14 @@ struct symbol_conf {
85 struct strlist *dso_list, 92 struct strlist *dso_list,
86 *comm_list, 93 *comm_list,
87 *sym_list; 94 *sym_list;
95 const char *symfs;
88}; 96};
89 97
90extern struct symbol_conf symbol_conf; 98extern struct symbol_conf symbol_conf;
91 99
92static inline void *symbol__priv(struct symbol *self) 100static inline void *symbol__priv(struct symbol *sym)
93{ 101{
94 return ((void *)self) - symbol_conf.priv_size; 102 return ((void *)sym) - symbol_conf.priv_size;
95} 103}
96 104
97struct ref_reloc_sym { 105struct ref_reloc_sym {
@@ -130,13 +138,12 @@ struct dso {
130 struct rb_root symbol_names[MAP__NR_TYPES]; 138 struct rb_root symbol_names[MAP__NR_TYPES];
131 enum dso_kernel_type kernel; 139 enum dso_kernel_type kernel;
132 u8 adjust_symbols:1; 140 u8 adjust_symbols:1;
133 u8 slen_calculated:1;
134 u8 has_build_id:1; 141 u8 has_build_id:1;
135 u8 hit:1; 142 u8 hit:1;
136 u8 annotate_warned:1; 143 u8 annotate_warned:1;
137 u8 sname_alloc:1; 144 u8 sname_alloc:1;
138 u8 lname_alloc:1; 145 u8 lname_alloc:1;
139 unsigned char origin; 146 unsigned char symtab_type;
140 u8 sorted_by_name; 147 u8 sorted_by_name;
141 u8 loaded; 148 u8 loaded;
142 u8 build_id[BUILD_ID_SIZE]; 149 u8 build_id[BUILD_ID_SIZE];
@@ -149,83 +156,90 @@ struct dso {
149 156
150struct dso *dso__new(const char *name); 157struct dso *dso__new(const char *name);
151struct dso *dso__new_kernel(const char *name); 158struct dso *dso__new_kernel(const char *name);
152void dso__delete(struct dso *self); 159void dso__delete(struct dso *dso);
153 160
154int dso__name_len(const struct dso *self); 161int dso__name_len(const struct dso *dso);
155 162
156bool dso__loaded(const struct dso *self, enum map_type type); 163bool dso__loaded(const struct dso *dso, enum map_type type);
157bool dso__sorted_by_name(const struct dso *self, enum map_type type); 164bool dso__sorted_by_name(const struct dso *dso, enum map_type type);
158 165
159static inline void dso__set_loaded(struct dso *self, enum map_type type) 166static inline void dso__set_loaded(struct dso *dso, enum map_type type)
160{ 167{
161 self->loaded |= (1 << type); 168 dso->loaded |= (1 << type);
162} 169}
163 170
164void dso__sort_by_name(struct dso *self, enum map_type type); 171void dso__sort_by_name(struct dso *dso, enum map_type type);
165 172
166struct dso *__dsos__findnew(struct list_head *head, const char *name); 173struct dso *__dsos__findnew(struct list_head *head, const char *name);
167 174
168int dso__load(struct dso *self, struct map *map, symbol_filter_t filter); 175int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter);
169int dso__load_vmlinux_path(struct dso *self, struct map *map, 176int dso__load_vmlinux(struct dso *dso, struct map *map,
177 const char *vmlinux, symbol_filter_t filter);
178int dso__load_vmlinux_path(struct dso *dso, struct map *map,
170 symbol_filter_t filter); 179 symbol_filter_t filter);
171int dso__load_kallsyms(struct dso *self, const char *filename, struct map *map, 180int dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map,
172 symbol_filter_t filter); 181 symbol_filter_t filter);
173int machine__load_kallsyms(struct machine *self, const char *filename, 182int machine__load_kallsyms(struct machine *machine, const char *filename,
174 enum map_type type, symbol_filter_t filter); 183 enum map_type type, symbol_filter_t filter);
175int machine__load_vmlinux_path(struct machine *self, enum map_type type, 184int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
176 symbol_filter_t filter); 185 symbol_filter_t filter);
177 186
178size_t __dsos__fprintf(struct list_head *head, FILE *fp); 187size_t __dsos__fprintf(struct list_head *head, FILE *fp);
179 188
180size_t machine__fprintf_dsos_buildid(struct machine *self, FILE *fp, bool with_hits); 189size_t machine__fprintf_dsos_buildid(struct machine *machine,
181size_t machines__fprintf_dsos(struct rb_root *self, FILE *fp); 190 FILE *fp, bool with_hits);
182size_t machines__fprintf_dsos_buildid(struct rb_root *self, FILE *fp, bool with_hits); 191size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp);
183 192size_t machines__fprintf_dsos_buildid(struct rb_root *machines,
184size_t dso__fprintf_buildid(struct dso *self, FILE *fp); 193 FILE *fp, bool with_hits);
185size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp); 194size_t dso__fprintf_buildid(struct dso *dso, FILE *fp);
186 195size_t dso__fprintf_symbols_by_name(struct dso *dso,
187enum dso_origin { 196 enum map_type type, FILE *fp);
188 DSO__ORIG_KERNEL = 0, 197size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp);
189 DSO__ORIG_GUEST_KERNEL, 198
190 DSO__ORIG_JAVA_JIT, 199enum symtab_type {
191 DSO__ORIG_BUILD_ID_CACHE, 200 SYMTAB__KALLSYMS = 0,
192 DSO__ORIG_FEDORA, 201 SYMTAB__GUEST_KALLSYMS,
193 DSO__ORIG_UBUNTU, 202 SYMTAB__JAVA_JIT,
194 DSO__ORIG_BUILDID, 203 SYMTAB__BUILD_ID_CACHE,
195 DSO__ORIG_DSO, 204 SYMTAB__FEDORA_DEBUGINFO,
196 DSO__ORIG_GUEST_KMODULE, 205 SYMTAB__UBUNTU_DEBUGINFO,
197 DSO__ORIG_KMODULE, 206 SYMTAB__BUILDID_DEBUGINFO,
198 DSO__ORIG_NOT_FOUND, 207 SYMTAB__SYSTEM_PATH_DSO,
208 SYMTAB__GUEST_KMODULE,
209 SYMTAB__SYSTEM_PATH_KMODULE,
210 SYMTAB__NOT_FOUND,
199}; 211};
200 212
201char dso__symtab_origin(const struct dso *self); 213char dso__symtab_origin(const struct dso *dso);
202void dso__set_long_name(struct dso *self, char *name); 214void dso__set_long_name(struct dso *dso, char *name);
203void dso__set_build_id(struct dso *self, void *build_id); 215void dso__set_build_id(struct dso *dso, void *build_id);
204void dso__read_running_kernel_build_id(struct dso *self, struct machine *machine); 216void dso__read_running_kernel_build_id(struct dso *dso,
205struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr); 217 struct machine *machine);
206struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type, 218struct symbol *dso__find_symbol(struct dso *dso, enum map_type type,
219 u64 addr);
220struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
207 const char *name); 221 const char *name);
208 222
209int filename__read_build_id(const char *filename, void *bf, size_t size); 223int filename__read_build_id(const char *filename, void *bf, size_t size);
210int sysfs__read_build_id(const char *filename, void *bf, size_t size); 224int sysfs__read_build_id(const char *filename, void *bf, size_t size);
211bool __dsos__read_build_ids(struct list_head *head, bool with_hits); 225bool __dsos__read_build_ids(struct list_head *head, bool with_hits);
212int build_id__sprintf(const u8 *self, int len, char *bf); 226int build_id__sprintf(const u8 *build_id, int len, char *bf);
213int kallsyms__parse(const char *filename, void *arg, 227int kallsyms__parse(const char *filename, void *arg,
214 int (*process_symbol)(void *arg, const char *name, 228 int (*process_symbol)(void *arg, const char *name,
215 char type, u64 start)); 229 char type, u64 start, u64 end));
216 230
217void machine__destroy_kernel_maps(struct machine *self); 231void machine__destroy_kernel_maps(struct machine *machine);
218int __machine__create_kernel_maps(struct machine *self, struct dso *kernel); 232int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel);
219int machine__create_kernel_maps(struct machine *self); 233int machine__create_kernel_maps(struct machine *machine);
220 234
221int machines__create_kernel_maps(struct rb_root *self, pid_t pid); 235int machines__create_kernel_maps(struct rb_root *machines, pid_t pid);
222int machines__create_guest_kernel_maps(struct rb_root *self); 236int machines__create_guest_kernel_maps(struct rb_root *machines);
223void machines__destroy_guest_kernel_maps(struct rb_root *self); 237void machines__destroy_guest_kernel_maps(struct rb_root *machines);
224 238
225int symbol__init(void); 239int symbol__init(void);
226void symbol__exit(void); 240void symbol__exit(void);
227bool symbol_type__is_a(char symbol_type, enum map_type map_type); 241bool symbol_type__is_a(char symbol_type, enum map_type map_type);
228 242
229size_t machine__fprintf_vmlinux_path(struct machine *self, FILE *fp); 243size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp);
230 244
231#endif /* __PERF_SYMBOL */ 245#endif /* __PERF_SYMBOL */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 8c72d888e449..d5d3b22250f3 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -7,46 +7,6 @@
7#include "util.h" 7#include "util.h"
8#include "debug.h" 8#include "debug.h"
9 9
10/* Skip "." and ".." directories */
11static int filter(const struct dirent *dir)
12{
13 if (dir->d_name[0] == '.')
14 return 0;
15 else
16 return 1;
17}
18
19int find_all_tid(int pid, pid_t ** all_tid)
20{
21 char name[256];
22 int items;
23 struct dirent **namelist = NULL;
24 int ret = 0;
25 int i;
26
27 sprintf(name, "/proc/%d/task", pid);
28 items = scandir(name, &namelist, filter, NULL);
29 if (items <= 0)
30 return -ENOENT;
31 *all_tid = malloc(sizeof(pid_t) * items);
32 if (!*all_tid) {
33 ret = -ENOMEM;
34 goto failure;
35 }
36
37 for (i = 0; i < items; i++)
38 (*all_tid)[i] = atoi(namelist[i]->d_name);
39
40 ret = items;
41
42failure:
43 for (i=0; i<items; i++)
44 free(namelist[i]);
45 free(namelist);
46
47 return ret;
48}
49
50static struct thread *thread__new(pid_t pid) 10static struct thread *thread__new(pid_t pid)
51{ 11{
52 struct thread *self = zalloc(sizeof(*self)); 12 struct thread *self = zalloc(sizeof(*self));
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 688500ff826f..e5f2401c1b5e 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -22,7 +22,6 @@ struct perf_session;
22 22
23void thread__delete(struct thread *self); 23void thread__delete(struct thread *self);
24 24
25int find_all_tid(int pid, pid_t ** all_tid);
26int thread__set_comm(struct thread *self, const char *comm); 25int thread__set_comm(struct thread *self, const char *comm);
27int thread__comm_len(struct thread *self); 26int thread__comm_len(struct thread *self);
28struct thread *perf_session__findnew(struct perf_session *self, pid_t pid); 27struct thread *perf_session__findnew(struct perf_session *self, pid_t pid);
diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c
new file mode 100644
index 000000000000..a5df131b77c3
--- /dev/null
+++ b/tools/perf/util/thread_map.c
@@ -0,0 +1,64 @@
1#include <dirent.h>
2#include <stdlib.h>
3#include <stdio.h>
4#include "thread_map.h"
5
6/* Skip "." and ".." directories */
7static int filter(const struct dirent *dir)
8{
9 if (dir->d_name[0] == '.')
10 return 0;
11 else
12 return 1;
13}
14
15struct thread_map *thread_map__new_by_pid(pid_t pid)
16{
17 struct thread_map *threads;
18 char name[256];
19 int items;
20 struct dirent **namelist = NULL;
21 int i;
22
23 sprintf(name, "/proc/%d/task", pid);
24 items = scandir(name, &namelist, filter, NULL);
25 if (items <= 0)
26 return NULL;
27
28 threads = malloc(sizeof(*threads) + sizeof(pid_t) * items);
29 if (threads != NULL) {
30 for (i = 0; i < items; i++)
31 threads->map[i] = atoi(namelist[i]->d_name);
32 threads->nr = items;
33 }
34
35 for (i=0; i<items; i++)
36 free(namelist[i]);
37 free(namelist);
38
39 return threads;
40}
41
42struct thread_map *thread_map__new_by_tid(pid_t tid)
43{
44 struct thread_map *threads = malloc(sizeof(*threads) + sizeof(pid_t));
45
46 if (threads != NULL) {
47 threads->map[0] = tid;
48 threads->nr = 1;
49 }
50
51 return threads;
52}
53
54struct thread_map *thread_map__new(pid_t pid, pid_t tid)
55{
56 if (pid != -1)
57 return thread_map__new_by_pid(pid);
58 return thread_map__new_by_tid(tid);
59}
60
61void thread_map__delete(struct thread_map *threads)
62{
63 free(threads);
64}
diff --git a/tools/perf/util/thread_map.h b/tools/perf/util/thread_map.h
new file mode 100644
index 000000000000..3cb907311409
--- /dev/null
+++ b/tools/perf/util/thread_map.h
@@ -0,0 +1,15 @@
1#ifndef __PERF_THREAD_MAP_H
2#define __PERF_THREAD_MAP_H
3
4#include <sys/types.h>
5
6struct thread_map {
7 int nr;
8 int map[];
9};
10
11struct 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(pid_t pid, pid_t tid);
14void thread_map__delete(struct thread_map *threads);
15#endif /* __PERF_THREAD_MAP_H */
diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c
new file mode 100644
index 000000000000..a11f60735a18
--- /dev/null
+++ b/tools/perf/util/top.c
@@ -0,0 +1,238 @@
1/*
2 * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
3 *
4 * Refactored from builtin-top.c, see that files for further copyright notes.
5 *
6 * Released under the GPL v2. (and only v2, not any later version)
7 */
8
9#include "cpumap.h"
10#include "event.h"
11#include "evlist.h"
12#include "evsel.h"
13#include "parse-events.h"
14#include "symbol.h"
15#include "top.h"
16#include <inttypes.h>
17
18/*
19 * Ordering weight: count-1 * count-2 * ... / count-n
20 */
21static double sym_weight(const struct sym_entry *sym, struct perf_top *top)
22{
23 double weight = sym->snap_count;
24 int counter;
25
26 if (!top->display_weighted)
27 return weight;
28
29 for (counter = 1; counter < top->evlist->nr_entries - 1; counter++)
30 weight *= sym->count[counter];
31
32 weight /= (sym->count[counter] + 1);
33
34 return weight;
35}
36
37static void perf_top__remove_active_sym(struct perf_top *top, struct sym_entry *syme)
38{
39 pthread_mutex_lock(&top->active_symbols_lock);
40 list_del_init(&syme->node);
41 pthread_mutex_unlock(&top->active_symbols_lock);
42}
43
44static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se)
45{
46 struct rb_node **p = &tree->rb_node;
47 struct rb_node *parent = NULL;
48 struct sym_entry *iter;
49
50 while (*p != NULL) {
51 parent = *p;
52 iter = rb_entry(parent, struct sym_entry, rb_node);
53
54 if (se->weight > iter->weight)
55 p = &(*p)->rb_left;
56 else
57 p = &(*p)->rb_right;
58 }
59
60 rb_link_node(&se->rb_node, parent, p);
61 rb_insert_color(&se->rb_node, tree);
62}
63
64#define SNPRINTF(buf, size, fmt, args...) \
65({ \
66 size_t r = snprintf(buf, size, fmt, ## args); \
67 r > size ? size : r; \
68})
69
70size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
71{
72 struct perf_evsel *counter;
73 float samples_per_sec = top->samples / top->delay_secs;
74 float ksamples_per_sec = top->kernel_samples / top->delay_secs;
75 float esamples_percent = (100.0 * top->exact_samples) / top->samples;
76 size_t ret = 0;
77
78 if (!perf_guest) {
79 ret = SNPRINTF(bf, size,
80 " PerfTop:%8.0f irqs/sec kernel:%4.1f%%"
81 " exact: %4.1f%% [", samples_per_sec,
82 100.0 - (100.0 * ((samples_per_sec - ksamples_per_sec) /
83 samples_per_sec)),
84 esamples_percent);
85 } else {
86 float us_samples_per_sec = top->us_samples / top->delay_secs;
87 float guest_kernel_samples_per_sec = top->guest_kernel_samples / top->delay_secs;
88 float guest_us_samples_per_sec = top->guest_us_samples / top->delay_secs;
89
90 ret = SNPRINTF(bf, size,
91 " PerfTop:%8.0f irqs/sec kernel:%4.1f%% us:%4.1f%%"
92 " guest kernel:%4.1f%% guest us:%4.1f%%"
93 " exact: %4.1f%% [", samples_per_sec,
94 100.0 - (100.0 * ((samples_per_sec - ksamples_per_sec) /
95 samples_per_sec)),
96 100.0 - (100.0 * ((samples_per_sec - us_samples_per_sec) /
97 samples_per_sec)),
98 100.0 - (100.0 * ((samples_per_sec -
99 guest_kernel_samples_per_sec) /
100 samples_per_sec)),
101 100.0 - (100.0 * ((samples_per_sec -
102 guest_us_samples_per_sec) /
103 samples_per_sec)),
104 esamples_percent);
105 }
106
107 if (top->evlist->nr_entries == 1 || !top->display_weighted) {
108 struct perf_evsel *first;
109 first = list_entry(top->evlist->entries.next, struct perf_evsel, node);
110 ret += SNPRINTF(bf + ret, size - ret, "%" PRIu64 "%s ",
111 (uint64_t)first->attr.sample_period,
112 top->freq ? "Hz" : "");
113 }
114
115 if (!top->display_weighted) {
116 ret += SNPRINTF(bf + ret, size - ret, "%s",
117 event_name(top->sym_evsel));
118 } else {
119 /*
120 * Don't let events eat all the space. Leaving 30 bytes
121 * for the rest should be enough.
122 */
123 size_t last_pos = size - 30;
124
125 list_for_each_entry(counter, &top->evlist->entries, node) {
126 ret += SNPRINTF(bf + ret, size - ret, "%s%s",
127 counter->idx ? "/" : "",
128 event_name(counter));
129 if (ret > last_pos) {
130 sprintf(bf + last_pos - 3, "..");
131 ret = last_pos - 1;
132 break;
133 }
134 }
135 }
136
137 ret += SNPRINTF(bf + ret, size - ret, "], ");
138
139 if (top->target_pid != -1)
140 ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %d",
141 top->target_pid);
142 else if (top->target_tid != -1)
143 ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %d",
144 top->target_tid);
145 else
146 ret += SNPRINTF(bf + ret, size - ret, " (all");
147
148 if (top->cpu_list)
149 ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)",
150 top->evlist->cpus->nr > 1 ? "s" : "", top->cpu_list);
151 else {
152 if (top->target_tid != -1)
153 ret += SNPRINTF(bf + ret, size - ret, ")");
154 else
155 ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)",
156 top->evlist->cpus->nr,
157 top->evlist->cpus->nr > 1 ? "s" : "");
158 }
159
160 return ret;
161}
162
163void perf_top__reset_sample_counters(struct perf_top *top)
164{
165 top->samples = top->us_samples = top->kernel_samples =
166 top->exact_samples = top->guest_kernel_samples =
167 top->guest_us_samples = 0;
168}
169
170float perf_top__decay_samples(struct perf_top *top, struct rb_root *root)
171{
172 struct sym_entry *syme, *n;
173 float sum_ksamples = 0.0;
174 int snap = !top->display_weighted ? top->sym_evsel->idx : 0, j;
175
176 /* Sort the active symbols */
177 pthread_mutex_lock(&top->active_symbols_lock);
178 syme = list_entry(top->active_symbols.next, struct sym_entry, node);
179 pthread_mutex_unlock(&top->active_symbols_lock);
180
181 top->rb_entries = 0;
182 list_for_each_entry_safe_from(syme, n, &top->active_symbols, node) {
183 syme->snap_count = syme->count[snap];
184 if (syme->snap_count != 0) {
185
186 if ((top->hide_user_symbols &&
187 syme->map->dso->kernel == DSO_TYPE_USER) ||
188 (top->hide_kernel_symbols &&
189 syme->map->dso->kernel == DSO_TYPE_KERNEL)) {
190 perf_top__remove_active_sym(top, syme);
191 continue;
192 }
193 syme->weight = sym_weight(syme, top);
194
195 if ((int)syme->snap_count >= top->count_filter) {
196 rb_insert_active_sym(root, syme);
197 ++top->rb_entries;
198 }
199 sum_ksamples += syme->snap_count;
200
201 for (j = 0; j < top->evlist->nr_entries; j++)
202 syme->count[j] = top->zero ? 0 : syme->count[j] * 7 / 8;
203 } else
204 perf_top__remove_active_sym(top, syme);
205 }
206
207 return sum_ksamples;
208}
209
210/*
211 * Find the longest symbol name that will be displayed
212 */
213void perf_top__find_widths(struct perf_top *top, struct rb_root *root,
214 int *dso_width, int *dso_short_width, int *sym_width)
215{
216 struct rb_node *nd;
217 int printed = 0;
218
219 *sym_width = *dso_width = *dso_short_width = 0;
220
221 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
222 struct sym_entry *syme = rb_entry(nd, struct sym_entry, rb_node);
223 struct symbol *sym = sym_entry__symbol(syme);
224
225 if (++printed > top->print_entries ||
226 (int)syme->snap_count < top->count_filter)
227 continue;
228
229 if (syme->map->dso->long_name_len > *dso_width)
230 *dso_width = syme->map->dso->long_name_len;
231
232 if (syme->map->dso->short_name_len > *dso_short_width)
233 *dso_short_width = syme->map->dso->short_name_len;
234
235 if (sym->namelen > *sym_width)
236 *sym_width = sym->namelen;
237 }
238}
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
new file mode 100644
index 000000000000..bfbf95bcc603
--- /dev/null
+++ b/tools/perf/util/top.h
@@ -0,0 +1,64 @@
1#ifndef __PERF_TOP_H
2#define __PERF_TOP_H 1
3
4#include "types.h"
5#include "../perf.h"
6#include <stddef.h>
7#include <pthread.h>
8#include <linux/list.h>
9#include <linux/rbtree.h>
10
11struct perf_evlist;
12struct perf_evsel;
13
14struct sym_entry {
15 struct rb_node rb_node;
16 struct list_head node;
17 unsigned long snap_count;
18 double weight;
19 struct map *map;
20 unsigned long count[0];
21};
22
23static inline struct symbol *sym_entry__symbol(struct sym_entry *self)
24{
25 return ((void *)self) + symbol_conf.priv_size;
26}
27
28struct perf_top {
29 struct perf_evlist *evlist;
30 /*
31 * Symbols will be added here in perf_event__process_sample and will
32 * get out after decayed.
33 */
34 struct list_head active_symbols;
35 pthread_mutex_t active_symbols_lock;
36 pthread_cond_t active_symbols_cond;
37 u64 samples;
38 u64 kernel_samples, us_samples;
39 u64 exact_samples;
40 u64 guest_us_samples, guest_kernel_samples;
41 int print_entries, count_filter, delay_secs;
42 int display_weighted, freq, rb_entries;
43 pid_t target_pid, target_tid;
44 bool hide_kernel_symbols, hide_user_symbols, zero;
45 const char *cpu_list;
46 struct sym_entry *sym_filter_entry;
47 struct perf_evsel *sym_evsel;
48};
49
50size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size);
51void perf_top__reset_sample_counters(struct perf_top *top);
52float perf_top__decay_samples(struct perf_top *top, struct rb_root *root);
53void perf_top__find_widths(struct perf_top *top, struct rb_root *root,
54 int *dso_width, int *dso_short_width, int *sym_width);
55
56#ifdef NO_NEWT_SUPPORT
57static inline int perf_top__tui_browser(struct perf_top *top __used)
58{
59 return 0;
60}
61#else
62int perf_top__tui_browser(struct perf_top *top);
63#endif
64#endif /* __PERF_TOP_H */
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index b1572601286c..35729f4c40cb 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -34,11 +34,13 @@
34#include <ctype.h> 34#include <ctype.h>
35#include <errno.h> 35#include <errno.h>
36#include <stdbool.h> 36#include <stdbool.h>
37#include <linux/list.h>
37#include <linux/kernel.h> 38#include <linux/kernel.h>
38 39
39#include "../perf.h" 40#include "../perf.h"
40#include "trace-event.h" 41#include "trace-event.h"
41#include "debugfs.h" 42#include "debugfs.h"
43#include "evsel.h"
42 44
43#define VERSION "0.5" 45#define VERSION "0.5"
44 46
@@ -469,16 +471,17 @@ out:
469} 471}
470 472
471static struct tracepoint_path * 473static struct tracepoint_path *
472get_tracepoints_path(struct perf_event_attr *pattrs, int nb_events) 474get_tracepoints_path(struct list_head *pattrs)
473{ 475{
474 struct tracepoint_path path, *ppath = &path; 476 struct tracepoint_path path, *ppath = &path;
475 int i, nr_tracepoints = 0; 477 struct perf_evsel *pos;
478 int nr_tracepoints = 0;
476 479
477 for (i = 0; i < nb_events; i++) { 480 list_for_each_entry(pos, pattrs, node) {
478 if (pattrs[i].type != PERF_TYPE_TRACEPOINT) 481 if (pos->attr.type != PERF_TYPE_TRACEPOINT)
479 continue; 482 continue;
480 ++nr_tracepoints; 483 ++nr_tracepoints;
481 ppath->next = tracepoint_id_to_path(pattrs[i].config); 484 ppath->next = tracepoint_id_to_path(pos->attr.config);
482 if (!ppath->next) 485 if (!ppath->next)
483 die("%s\n", "No memory to alloc tracepoints list"); 486 die("%s\n", "No memory to alloc tracepoints list");
484 ppath = ppath->next; 487 ppath = ppath->next;
@@ -487,21 +490,21 @@ get_tracepoints_path(struct perf_event_attr *pattrs, int nb_events)
487 return nr_tracepoints > 0 ? path.next : NULL; 490 return nr_tracepoints > 0 ? path.next : NULL;
488} 491}
489 492
490bool have_tracepoints(struct perf_event_attr *pattrs, int nb_events) 493bool have_tracepoints(struct list_head *pattrs)
491{ 494{
492 int i; 495 struct perf_evsel *pos;
493 496
494 for (i = 0; i < nb_events; i++) 497 list_for_each_entry(pos, pattrs, node)
495 if (pattrs[i].type == PERF_TYPE_TRACEPOINT) 498 if (pos->attr.type == PERF_TYPE_TRACEPOINT)
496 return true; 499 return true;
497 500
498 return false; 501 return false;
499} 502}
500 503
501int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events) 504int read_tracing_data(int fd, struct list_head *pattrs)
502{ 505{
503 char buf[BUFSIZ]; 506 char buf[BUFSIZ];
504 struct tracepoint_path *tps = get_tracepoints_path(pattrs, nb_events); 507 struct tracepoint_path *tps = get_tracepoints_path(pattrs);
505 508
506 /* 509 /*
507 * What? No tracepoints? No sense writing anything here, bail out. 510 * What? No tracepoints? No sense writing anything here, bail out.
@@ -545,14 +548,13 @@ int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events)
545 return 0; 548 return 0;
546} 549}
547 550
548ssize_t read_tracing_data_size(int fd, struct perf_event_attr *pattrs, 551ssize_t read_tracing_data_size(int fd, struct list_head *pattrs)
549 int nb_events)
550{ 552{
551 ssize_t size; 553 ssize_t size;
552 int err = 0; 554 int err = 0;
553 555
554 calc_data_size = 1; 556 calc_data_size = 1;
555 err = read_tracing_data(fd, pattrs, nb_events); 557 err = read_tracing_data(fd, pattrs);
556 size = calc_data_size - 1; 558 size = calc_data_size - 1;
557 calc_data_size = 0; 559 calc_data_size = 0;
558 560
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index 73a02223c629..0a7ed5b5e281 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -153,7 +153,7 @@ void parse_proc_kallsyms(char *file, unsigned int size __unused)
153 char *next = NULL; 153 char *next = NULL;
154 char *addr_str; 154 char *addr_str;
155 char ch; 155 char ch;
156 int ret; 156 int ret __used;
157 int i; 157 int i;
158 158
159 line = strtok_r(file, "\n", &next); 159 line = strtok_r(file, "\n", &next);
@@ -2643,68 +2643,13 @@ static void print_lat_fmt(void *data, int size __unused)
2643 printf("."); 2643 printf(".");
2644 2644
2645 if (lock_depth < 0) 2645 if (lock_depth < 0)
2646 printf("."); 2646 printf(". ");
2647 else 2647 else
2648 printf("%d", lock_depth); 2648 printf("%d ", lock_depth);
2649}
2650
2651/* taken from Linux, written by Frederic Weisbecker */
2652static void print_graph_cpu(int cpu)
2653{
2654 int i;
2655 int log10_this = log10_cpu(cpu);
2656 int log10_all = log10_cpu(cpus);
2657
2658
2659 /*
2660 * Start with a space character - to make it stand out
2661 * to the right a bit when trace output is pasted into
2662 * email:
2663 */
2664 printf(" ");
2665
2666 /*
2667 * Tricky - we space the CPU field according to the max
2668 * number of online CPUs. On a 2-cpu system it would take
2669 * a maximum of 1 digit - on a 128 cpu system it would
2670 * take up to 3 digits:
2671 */
2672 for (i = 0; i < log10_all - log10_this; i++)
2673 printf(" ");
2674
2675 printf("%d) ", cpu);
2676} 2649}
2677 2650
2678#define TRACE_GRAPH_PROCINFO_LENGTH 14
2679#define TRACE_GRAPH_INDENT 2 2651#define TRACE_GRAPH_INDENT 2
2680 2652
2681static void print_graph_proc(int pid, const char *comm)
2682{
2683 /* sign + log10(MAX_INT) + '\0' */
2684 char pid_str[11];
2685 int spaces = 0;
2686 int len;
2687 int i;
2688
2689 sprintf(pid_str, "%d", pid);
2690
2691 /* 1 stands for the "-" character */
2692 len = strlen(comm) + strlen(pid_str) + 1;
2693
2694 if (len < TRACE_GRAPH_PROCINFO_LENGTH)
2695 spaces = TRACE_GRAPH_PROCINFO_LENGTH - len;
2696
2697 /* First spaces to align center */
2698 for (i = 0; i < spaces / 2; i++)
2699 printf(" ");
2700
2701 printf("%s-%s", comm, pid_str);
2702
2703 /* Last spaces to align center */
2704 for (i = 0; i < spaces - (spaces / 2); i++)
2705 printf(" ");
2706}
2707
2708static struct record * 2653static struct record *
2709get_return_for_leaf(int cpu, int cur_pid, unsigned long long cur_func, 2654get_return_for_leaf(int cpu, int cur_pid, unsigned long long cur_func,
2710 struct record *next) 2655 struct record *next)
@@ -2876,21 +2821,13 @@ static void print_graph_nested(struct event *event, void *data)
2876 2821
2877static void 2822static void
2878pretty_print_func_ent(void *data, int size, struct event *event, 2823pretty_print_func_ent(void *data, int size, struct event *event,
2879 int cpu, int pid, const char *comm, 2824 int cpu, int pid)
2880 unsigned long secs, unsigned long usecs)
2881{ 2825{
2882 struct format_field *field; 2826 struct format_field *field;
2883 struct record *rec; 2827 struct record *rec;
2884 void *copy_data; 2828 void *copy_data;
2885 unsigned long val; 2829 unsigned long val;
2886 2830
2887 printf("%5lu.%06lu | ", secs, usecs);
2888
2889 print_graph_cpu(cpu);
2890 print_graph_proc(pid, comm);
2891
2892 printf(" | ");
2893
2894 if (latency_format) { 2831 if (latency_format) {
2895 print_lat_fmt(data, size); 2832 print_lat_fmt(data, size);
2896 printf(" | "); 2833 printf(" | ");
@@ -2923,22 +2860,13 @@ out_free:
2923} 2860}
2924 2861
2925static void 2862static void
2926pretty_print_func_ret(void *data, int size __unused, struct event *event, 2863pretty_print_func_ret(void *data, int size __unused, struct event *event)
2927 int cpu, int pid, const char *comm,
2928 unsigned long secs, unsigned long usecs)
2929{ 2864{
2930 unsigned long long rettime, calltime; 2865 unsigned long long rettime, calltime;
2931 unsigned long long duration, depth; 2866 unsigned long long duration, depth;
2932 struct format_field *field; 2867 struct format_field *field;
2933 int i; 2868 int i;
2934 2869
2935 printf("%5lu.%06lu | ", secs, usecs);
2936
2937 print_graph_cpu(cpu);
2938 print_graph_proc(pid, comm);
2939
2940 printf(" | ");
2941
2942 if (latency_format) { 2870 if (latency_format) {
2943 print_lat_fmt(data, size); 2871 print_lat_fmt(data, size);
2944 printf(" | "); 2872 printf(" | ");
@@ -2976,31 +2904,21 @@ pretty_print_func_ret(void *data, int size __unused, struct event *event,
2976 2904
2977static void 2905static void
2978pretty_print_func_graph(void *data, int size, struct event *event, 2906pretty_print_func_graph(void *data, int size, struct event *event,
2979 int cpu, int pid, const char *comm, 2907 int cpu, int pid)
2980 unsigned long secs, unsigned long usecs)
2981{ 2908{
2982 if (event->flags & EVENT_FL_ISFUNCENT) 2909 if (event->flags & EVENT_FL_ISFUNCENT)
2983 pretty_print_func_ent(data, size, event, 2910 pretty_print_func_ent(data, size, event, cpu, pid);
2984 cpu, pid, comm, secs, usecs);
2985 else if (event->flags & EVENT_FL_ISFUNCRET) 2911 else if (event->flags & EVENT_FL_ISFUNCRET)
2986 pretty_print_func_ret(data, size, event, 2912 pretty_print_func_ret(data, size, event);
2987 cpu, pid, comm, secs, usecs);
2988 printf("\n"); 2913 printf("\n");
2989} 2914}
2990 2915
2991void print_event(int cpu, void *data, int size, unsigned long long nsecs, 2916void print_trace_event(int cpu, void *data, int size)
2992 char *comm)
2993{ 2917{
2994 struct event *event; 2918 struct event *event;
2995 unsigned long secs;
2996 unsigned long usecs;
2997 int type; 2919 int type;
2998 int pid; 2920 int pid;
2999 2921
3000 secs = nsecs / NSECS_PER_SEC;
3001 nsecs -= secs * NSECS_PER_SEC;
3002 usecs = nsecs / NSECS_PER_USEC;
3003
3004 type = trace_parse_common_type(data); 2922 type = trace_parse_common_type(data);
3005 2923
3006 event = trace_find_event(type); 2924 event = trace_find_event(type);
@@ -3012,17 +2930,10 @@ void print_event(int cpu, void *data, int size, unsigned long long nsecs,
3012 pid = trace_parse_common_pid(data); 2930 pid = trace_parse_common_pid(data);
3013 2931
3014 if (event->flags & (EVENT_FL_ISFUNCENT | EVENT_FL_ISFUNCRET)) 2932 if (event->flags & (EVENT_FL_ISFUNCENT | EVENT_FL_ISFUNCRET))
3015 return pretty_print_func_graph(data, size, event, cpu, 2933 return pretty_print_func_graph(data, size, event, cpu, pid);
3016 pid, comm, secs, usecs);
3017 2934
3018 if (latency_format) { 2935 if (latency_format)
3019 printf("%8.8s-%-5d %3d",
3020 comm, pid, cpu);
3021 print_lat_fmt(data, size); 2936 print_lat_fmt(data, size);
3022 } else
3023 printf("%16s-%-5d [%03d]", comm, pid, cpu);
3024
3025 printf(" %5lu.%06lu: %s: ", secs, usecs, event->name);
3026 2937
3027 if (event->flags & EVENT_FL_FAILED) { 2938 if (event->flags & EVENT_FL_FAILED) {
3028 printf("EVENT '%s' FAILED TO PARSE\n", 2939 printf("EVENT '%s' FAILED TO PARSE\n",
@@ -3031,7 +2942,6 @@ void print_event(int cpu, void *data, int size, unsigned long long nsecs,
3031 } 2942 }
3032 2943
3033 pretty_print(data, size, event); 2944 pretty_print(data, size, event);
3034 printf("\n");
3035} 2945}
3036 2946
3037static void print_fields(struct print_flag_sym *field) 2947static void print_fields(struct print_flag_sym *field)
diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c
index f7af2fca965d..c9dcbec7d800 100644
--- a/tools/perf/util/trace-event-scripting.c
+++ b/tools/perf/util/trace-event-scripting.c
@@ -36,11 +36,11 @@ static int stop_script_unsupported(void)
36 return 0; 36 return 0;
37} 37}
38 38
39static void process_event_unsupported(int cpu __unused, 39static void process_event_unsupported(union perf_event *event __unused,
40 void *data __unused, 40 struct perf_sample *sample __unused,
41 int size __unused, 41 struct perf_evsel *evsel __unused,
42 unsigned long long nsecs __unused, 42 struct perf_session *session __unused,
43 char *comm __unused) 43 struct thread *thread __unused)
44{ 44{
45} 45}
46 46
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index b3e86b1e4444..f674dda3363b 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -3,6 +3,7 @@
3 3
4#include <stdbool.h> 4#include <stdbool.h>
5#include "parse-events.h" 5#include "parse-events.h"
6#include "session.h"
6 7
7#define __unused __attribute__((unused)) 8#define __unused __attribute__((unused))
8 9
@@ -176,8 +177,7 @@ void print_printk(void);
176 177
177int parse_ftrace_file(char *buf, unsigned long size); 178int parse_ftrace_file(char *buf, unsigned long size);
178int parse_event_file(char *buf, unsigned long size, char *sys); 179int parse_event_file(char *buf, unsigned long size, char *sys);
179void print_event(int cpu, void *data, int size, unsigned long long nsecs, 180void print_trace_event(int cpu, void *data, int size);
180 char *comm);
181 181
182extern int file_bigendian; 182extern int file_bigendian;
183extern int host_bigendian; 183extern int host_bigendian;
@@ -262,9 +262,8 @@ raw_field_value(struct event *event, const char *name, void *data);
262void *raw_field_ptr(struct event *event, const char *name, void *data); 262void *raw_field_ptr(struct event *event, const char *name, void *data);
263unsigned long long eval_flag(const char *flag); 263unsigned long long eval_flag(const char *flag);
264 264
265int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events); 265int read_tracing_data(int fd, struct list_head *pattrs);
266ssize_t read_tracing_data_size(int fd, struct perf_event_attr *pattrs, 266ssize_t read_tracing_data_size(int fd, struct list_head *pattrs);
267 int nb_events);
268 267
269/* taken from kernel/trace/trace.h */ 268/* taken from kernel/trace/trace.h */
270enum trace_flag_type { 269enum trace_flag_type {
@@ -279,8 +278,11 @@ struct scripting_ops {
279 const char *name; 278 const char *name;
280 int (*start_script) (const char *script, int argc, const char **argv); 279 int (*start_script) (const char *script, int argc, const char **argv);
281 int (*stop_script) (void); 280 int (*stop_script) (void);
282 void (*process_event) (int cpu, void *data, int size, 281 void (*process_event) (union perf_event *event,
283 unsigned long long nsecs, char *comm); 282 struct perf_sample *sample,
283 struct perf_evsel *evsel,
284 struct perf_session *session,
285 struct thread *thread);
284 int (*generate_script) (const char *outfile); 286 int (*generate_script) (const char *outfile);
285}; 287};
286 288
diff --git a/tools/perf/util/types.h b/tools/perf/util/types.h
index 7d6b8331f898..5f3689a3d085 100644
--- a/tools/perf/util/types.h
+++ b/tools/perf/util/types.h
@@ -1,12 +1,14 @@
1#ifndef __PERF_TYPES_H 1#ifndef __PERF_TYPES_H
2#define __PERF_TYPES_H 2#define __PERF_TYPES_H
3 3
4#include <stdint.h>
5
4/* 6/*
5 * We define u64 as unsigned long long for every architecture 7 * We define u64 as uint64_t for every architecture
6 * so that we can print it with %Lx without getting warnings. 8 * so that we can print it with "%"PRIx64 without getting warnings.
7 */ 9 */
8typedef unsigned long long u64; 10typedef uint64_t u64;
9typedef signed long long s64; 11typedef int64_t s64;
10typedef unsigned int u32; 12typedef unsigned int u32;
11typedef signed int s32; 13typedef signed int s32;
12typedef unsigned short u16; 14typedef unsigned short u16;
diff --git a/tools/perf/util/ui/browser.c b/tools/perf/util/ui/browser.c
index 66f2d583d8c4..611219f80680 100644
--- a/tools/perf/util/ui/browser.c
+++ b/tools/perf/util/ui/browser.c
@@ -1,16 +1,6 @@
1#define _GNU_SOURCE 1#include "libslang.h"
2#include <stdio.h> 2#include "ui.h"
3#undef _GNU_SOURCE 3#include <linux/compiler.h>
4/*
5 * slang versions <= 2.0.6 have a "#if HAVE_LONG_LONG" that breaks
6 * the build if it isn't defined. Use the equivalent one that glibc
7 * has on features.h.
8 */
9#include <features.h>
10#ifndef HAVE_LONG_LONG
11#define HAVE_LONG_LONG __GLIBC_HAVE_LONG_LONG
12#endif
13#include <slang.h>
14#include <linux/list.h> 4#include <linux/list.h>
15#include <linux/rbtree.h> 5#include <linux/rbtree.h>
16#include <stdlib.h> 6#include <stdlib.h>
@@ -19,17 +9,9 @@
19#include "helpline.h" 9#include "helpline.h"
20#include "../color.h" 10#include "../color.h"
21#include "../util.h" 11#include "../util.h"
12#include <stdio.h>
22 13
23#if SLANG_VERSION < 20104 14static int ui_browser__percent_color(double percent, bool current)
24#define sltt_set_color(obj, name, fg, bg) \
25 SLtt_set_color(obj,(char *)name, (char *)fg, (char *)bg)
26#else
27#define sltt_set_color SLtt_set_color
28#endif
29
30newtComponent newt_form__new(void);
31
32int ui_browser__percent_color(double percent, bool current)
33{ 15{
34 if (current) 16 if (current)
35 return HE_COLORSET_SELECTED; 17 return HE_COLORSET_SELECTED;
@@ -40,6 +22,23 @@ int ui_browser__percent_color(double percent, bool current)
40 return HE_COLORSET_NORMAL; 22 return HE_COLORSET_NORMAL;
41} 23}
42 24
25void ui_browser__set_color(struct ui_browser *self __used, int color)
26{
27 SLsmg_set_color(color);
28}
29
30void ui_browser__set_percent_color(struct ui_browser *self,
31 double percent, bool current)
32{
33 int color = ui_browser__percent_color(percent, current);
34 ui_browser__set_color(self, color);
35}
36
37void ui_browser__gotorc(struct ui_browser *self, int y, int x)
38{
39 SLsmg_gotorc(self->y + y, self->x + x);
40}
41
43void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence) 42void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence)
44{ 43{
45 struct list_head *head = self->entries; 44 struct list_head *head = self->entries;
@@ -111,7 +110,7 @@ unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self)
111 nd = self->top; 110 nd = self->top;
112 111
113 while (nd != NULL) { 112 while (nd != NULL) {
114 SLsmg_gotorc(self->y + row, self->x); 113 ui_browser__gotorc(self, row, 0);
115 self->write(self, nd, row); 114 self->write(self, nd, row);
116 if (++row == self->height) 115 if (++row == self->height)
117 break; 116 break;
@@ -131,13 +130,10 @@ void ui_browser__refresh_dimensions(struct ui_browser *self)
131 int cols, rows; 130 int cols, rows;
132 newtGetScreenSize(&cols, &rows); 131 newtGetScreenSize(&cols, &rows);
133 132
134 if (self->width > cols - 4) 133 self->width = cols - 1;
135 self->width = cols - 4; 134 self->height = rows - 2;
136 self->height = rows - 5; 135 self->y = 1;
137 if (self->height > self->nr_entries) 136 self->x = 0;
138 self->height = self->nr_entries;
139 self->y = (rows - self->height) / 2;
140 self->x = (cols - self->width) / 2;
141} 137}
142 138
143void ui_browser__reset_index(struct ui_browser *self) 139void ui_browser__reset_index(struct ui_browser *self)
@@ -146,78 +142,109 @@ void ui_browser__reset_index(struct ui_browser *self)
146 self->seek(self, 0, SEEK_SET); 142 self->seek(self, 0, SEEK_SET);
147} 143}
148 144
145void ui_browser__add_exit_key(struct ui_browser *self, int key)
146{
147 newtFormAddHotKey(self->form, key);
148}
149
150void ui_browser__add_exit_keys(struct ui_browser *self, int keys[])
151{
152 int i = 0;
153
154 while (keys[i] && i < 64) {
155 ui_browser__add_exit_key(self, keys[i]);
156 ++i;
157 }
158}
159
160void __ui_browser__show_title(struct ui_browser *browser, const char *title)
161{
162 SLsmg_gotorc(0, 0);
163 ui_browser__set_color(browser, NEWT_COLORSET_ROOT);
164 slsmg_write_nstring(title, browser->width);
165}
166
167void ui_browser__show_title(struct ui_browser *browser, const char *title)
168{
169 pthread_mutex_lock(&ui__lock);
170 __ui_browser__show_title(browser, title);
171 pthread_mutex_unlock(&ui__lock);
172}
173
149int ui_browser__show(struct ui_browser *self, const char *title, 174int ui_browser__show(struct ui_browser *self, const char *title,
150 const char *helpline, ...) 175 const char *helpline, ...)
151{ 176{
152 va_list ap; 177 va_list ap;
178 int keys[] = { NEWT_KEY_UP, NEWT_KEY_DOWN, NEWT_KEY_PGUP,
179 NEWT_KEY_PGDN, NEWT_KEY_HOME, NEWT_KEY_END, ' ',
180 NEWT_KEY_LEFT, NEWT_KEY_ESCAPE, 'q', CTRL('c'), 0 };
153 181
154 if (self->form != NULL) { 182 if (self->form != NULL)
155 newtFormDestroy(self->form); 183 newtFormDestroy(self->form);
156 newtPopWindow(); 184
157 }
158 ui_browser__refresh_dimensions(self); 185 ui_browser__refresh_dimensions(self);
159 newtCenteredWindow(self->width, self->height, title); 186 self->form = newtForm(NULL, NULL, 0);
160 self->form = newt_form__new();
161 if (self->form == NULL) 187 if (self->form == NULL)
162 return -1; 188 return -1;
163 189
164 self->sb = newtVerticalScrollbar(self->width, 0, self->height, 190 self->sb = newtVerticalScrollbar(self->width, 1, self->height,
165 HE_COLORSET_NORMAL, 191 HE_COLORSET_NORMAL,
166 HE_COLORSET_SELECTED); 192 HE_COLORSET_SELECTED);
167 if (self->sb == NULL) 193 if (self->sb == NULL)
168 return -1; 194 return -1;
169 195
170 newtFormAddHotKey(self->form, NEWT_KEY_UP); 196 pthread_mutex_lock(&ui__lock);
171 newtFormAddHotKey(self->form, NEWT_KEY_DOWN); 197 __ui_browser__show_title(self, title);
172 newtFormAddHotKey(self->form, NEWT_KEY_PGUP); 198
173 newtFormAddHotKey(self->form, NEWT_KEY_PGDN); 199 ui_browser__add_exit_keys(self, keys);
174 newtFormAddHotKey(self->form, NEWT_KEY_HOME);
175 newtFormAddHotKey(self->form, NEWT_KEY_END);
176 newtFormAddHotKey(self->form, ' ');
177 newtFormAddComponent(self->form, self->sb); 200 newtFormAddComponent(self->form, self->sb);
178 201
179 va_start(ap, helpline); 202 va_start(ap, helpline);
180 ui_helpline__vpush(helpline, ap); 203 ui_helpline__vpush(helpline, ap);
181 va_end(ap); 204 va_end(ap);
205 pthread_mutex_unlock(&ui__lock);
182 return 0; 206 return 0;
183} 207}
184 208
185void ui_browser__hide(struct ui_browser *self) 209void ui_browser__hide(struct ui_browser *self)
186{ 210{
211 pthread_mutex_lock(&ui__lock);
187 newtFormDestroy(self->form); 212 newtFormDestroy(self->form);
188 newtPopWindow();
189 self->form = NULL; 213 self->form = NULL;
190 ui_helpline__pop(); 214 ui_helpline__pop();
215 pthread_mutex_unlock(&ui__lock);
191} 216}
192 217
193int ui_browser__refresh(struct ui_browser *self) 218int ui_browser__refresh(struct ui_browser *self)
194{ 219{
195 int row; 220 int row;
196 221
222 pthread_mutex_lock(&ui__lock);
197 newtScrollbarSet(self->sb, self->index, self->nr_entries - 1); 223 newtScrollbarSet(self->sb, self->index, self->nr_entries - 1);
198 row = self->refresh(self); 224 row = self->refresh(self);
199 SLsmg_set_color(HE_COLORSET_NORMAL); 225 ui_browser__set_color(self, HE_COLORSET_NORMAL);
200 SLsmg_fill_region(self->y + row, self->x, 226 SLsmg_fill_region(self->y + row, self->x,
201 self->height - row, self->width, ' '); 227 self->height - row, self->width, ' ');
228 pthread_mutex_unlock(&ui__lock);
202 229
203 return 0; 230 return 0;
204} 231}
205 232
206int ui_browser__run(struct ui_browser *self, struct newtExitStruct *es) 233int ui_browser__run(struct ui_browser *self)
207{ 234{
235 struct newtExitStruct es;
236
208 if (ui_browser__refresh(self) < 0) 237 if (ui_browser__refresh(self) < 0)
209 return -1; 238 return -1;
210 239
211 while (1) { 240 while (1) {
212 off_t offset; 241 off_t offset;
213 242
214 newtFormRun(self->form, es); 243 newtFormRun(self->form, &es);
215 244
216 if (es->reason != NEWT_EXIT_HOTKEY) 245 if (es.reason != NEWT_EXIT_HOTKEY)
217 break; 246 break;
218 if (is_exit_key(es->u.key)) 247 switch (es.u.key) {
219 return es->u.key;
220 switch (es->u.key) {
221 case NEWT_KEY_DOWN: 248 case NEWT_KEY_DOWN:
222 if (self->index == self->nr_entries - 1) 249 if (self->index == self->nr_entries - 1)
223 break; 250 break;
@@ -274,12 +301,12 @@ int ui_browser__run(struct ui_browser *self, struct newtExitStruct *es)
274 self->seek(self, -offset, SEEK_END); 301 self->seek(self, -offset, SEEK_END);
275 break; 302 break;
276 default: 303 default:
277 return es->u.key; 304 return es.u.key;
278 } 305 }
279 if (ui_browser__refresh(self) < 0) 306 if (ui_browser__refresh(self) < 0)
280 return -1; 307 return -1;
281 } 308 }
282 return 0; 309 return -1;
283} 310}
284 311
285unsigned int ui_browser__list_head_refresh(struct ui_browser *self) 312unsigned int ui_browser__list_head_refresh(struct ui_browser *self)
@@ -294,7 +321,7 @@ unsigned int ui_browser__list_head_refresh(struct ui_browser *self)
294 pos = self->top; 321 pos = self->top;
295 322
296 list_for_each_from(pos, head) { 323 list_for_each_from(pos, head) {
297 SLsmg_gotorc(self->y + row, self->x); 324 ui_browser__gotorc(self, row, 0);
298 self->write(self, pos, row); 325 self->write(self, pos, row);
299 if (++row == self->height) 326 if (++row == self->height)
300 break; 327 break;
diff --git a/tools/perf/util/ui/browser.h b/tools/perf/util/ui/browser.h
index 0b9f829214f7..fc63dda10910 100644
--- a/tools/perf/util/ui/browser.h
+++ b/tools/perf/util/ui/browser.h
@@ -24,17 +24,23 @@ struct ui_browser {
24 u32 nr_entries; 24 u32 nr_entries;
25}; 25};
26 26
27 27void ui_browser__set_color(struct ui_browser *self, int color);
28int ui_browser__percent_color(double percent, bool current); 28void ui_browser__set_percent_color(struct ui_browser *self,
29 double percent, bool current);
29bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row); 30bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row);
30void ui_browser__refresh_dimensions(struct ui_browser *self); 31void ui_browser__refresh_dimensions(struct ui_browser *self);
31void ui_browser__reset_index(struct ui_browser *self); 32void ui_browser__reset_index(struct ui_browser *self);
32 33
34void ui_browser__gotorc(struct ui_browser *self, int y, int x);
35void ui_browser__add_exit_key(struct ui_browser *self, int key);
36void ui_browser__add_exit_keys(struct ui_browser *self, int keys[]);
37void __ui_browser__show_title(struct ui_browser *browser, const char *title);
38void ui_browser__show_title(struct ui_browser *browser, const char *title);
33int ui_browser__show(struct ui_browser *self, const char *title, 39int ui_browser__show(struct ui_browser *self, const char *title,
34 const char *helpline, ...); 40 const char *helpline, ...);
35void ui_browser__hide(struct ui_browser *self); 41void ui_browser__hide(struct ui_browser *self);
36int ui_browser__refresh(struct ui_browser *self); 42int ui_browser__refresh(struct ui_browser *self);
37int ui_browser__run(struct ui_browser *self, struct newtExitStruct *es); 43int ui_browser__run(struct ui_browser *self);
38 44
39void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence); 45void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence);
40unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self); 46unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self);
diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c
index a90273e63f4f..0229723aceb3 100644
--- a/tools/perf/util/ui/browsers/annotate.c
+++ b/tools/perf/util/ui/browsers/annotate.c
@@ -1,9 +1,11 @@
1#include "../browser.h" 1#include "../browser.h"
2#include "../helpline.h" 2#include "../helpline.h"
3#include "../libslang.h" 3#include "../libslang.h"
4#include "../../annotate.h"
4#include "../../hist.h" 5#include "../../hist.h"
5#include "../../sort.h" 6#include "../../sort.h"
6#include "../../symbol.h" 7#include "../../symbol.h"
8#include <pthread.h>
7 9
8static void ui__error_window(const char *fmt, ...) 10static void ui__error_window(const char *fmt, ...)
9{ 11{
@@ -40,14 +42,10 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro
40 42
41 if (ol->offset != -1) { 43 if (ol->offset != -1) {
42 struct objdump_line_rb_node *olrb = objdump_line__rb(ol); 44 struct objdump_line_rb_node *olrb = objdump_line__rb(ol);
43 int color = ui_browser__percent_color(olrb->percent, current_entry); 45 ui_browser__set_percent_color(self, olrb->percent, current_entry);
44 SLsmg_set_color(color);
45 slsmg_printf(" %7.2f ", olrb->percent); 46 slsmg_printf(" %7.2f ", olrb->percent);
46 if (!current_entry)
47 SLsmg_set_color(HE_COLORSET_CODE);
48 } else { 47 } else {
49 int color = ui_browser__percent_color(0, current_entry); 48 ui_browser__set_percent_color(self, 0, current_entry);
50 SLsmg_set_color(color);
51 slsmg_write_nstring(" ", 9); 49 slsmg_write_nstring(" ", 9);
52 } 50 }
53 51
@@ -57,35 +55,40 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro
57 slsmg_write_nstring(" ", width - 18); 55 slsmg_write_nstring(" ", width - 18);
58 else 56 else
59 slsmg_write_nstring(ol->line, width - 18); 57 slsmg_write_nstring(ol->line, width - 18);
58
59 if (!current_entry)
60 ui_browser__set_color(self, HE_COLORSET_CODE);
60} 61}
61 62
62static double objdump_line__calc_percent(struct objdump_line *self, 63static double objdump_line__calc_percent(struct objdump_line *self,
63 struct list_head *head, 64 struct symbol *sym, int evidx)
64 struct symbol *sym)
65{ 65{
66 double percent = 0.0; 66 double percent = 0.0;
67 67
68 if (self->offset != -1) { 68 if (self->offset != -1) {
69 int len = sym->end - sym->start; 69 int len = sym->end - sym->start;
70 unsigned int hits = 0; 70 unsigned int hits = 0;
71 struct sym_priv *priv = symbol__priv(sym); 71 struct annotation *notes = symbol__annotation(sym);
72 struct sym_ext *sym_ext = priv->ext; 72 struct source_line *src_line = notes->src->lines;
73 struct sym_hist *h = priv->hist; 73 struct sym_hist *h = annotation__histogram(notes, evidx);
74 s64 offset = self->offset; 74 s64 offset = self->offset;
75 struct objdump_line *next = objdump__get_next_ip_line(head, self); 75 struct objdump_line *next;
76
77 76
77 next = objdump__get_next_ip_line(&notes->src->source, self);
78 while (offset < (s64)len && 78 while (offset < (s64)len &&
79 (next == NULL || offset < next->offset)) { 79 (next == NULL || offset < next->offset)) {
80 if (sym_ext) { 80 if (src_line) {
81 percent += sym_ext[offset].percent; 81 percent += src_line[offset].percent;
82 } else 82 } else
83 hits += h->ip[offset]; 83 hits += h->addr[offset];
84 84
85 ++offset; 85 ++offset;
86 } 86 }
87 87 /*
88 if (sym_ext == NULL && h->sum) 88 * If the percentage wasn't already calculated in
89 * symbol__get_source_line, do it now:
90 */
91 if (src_line == NULL && h->sum)
89 percent = 100.0 * hits / h->sum; 92 percent = 100.0 * hits / h->sum;
90 } 93 }
91 94
@@ -135,105 +138,163 @@ static void annotate_browser__set_top(struct annotate_browser *self,
135 self->curr_hot = nd; 138 self->curr_hot = nd;
136} 139}
137 140
138static int annotate_browser__run(struct annotate_browser *self, 141static void annotate_browser__calc_percent(struct annotate_browser *browser,
139 struct newtExitStruct *es) 142 int evidx)
143{
144 struct symbol *sym = browser->b.priv;
145 struct annotation *notes = symbol__annotation(sym);
146 struct objdump_line *pos;
147
148 browser->entries = RB_ROOT;
149
150 pthread_mutex_lock(&notes->lock);
151
152 list_for_each_entry(pos, &notes->src->source, node) {
153 struct objdump_line_rb_node *rbpos = objdump_line__rb(pos);
154 rbpos->percent = objdump_line__calc_percent(pos, sym, evidx);
155 if (rbpos->percent < 0.01) {
156 RB_CLEAR_NODE(&rbpos->rb_node);
157 continue;
158 }
159 objdump__insert_line(&browser->entries, rbpos);
160 }
161 pthread_mutex_unlock(&notes->lock);
162
163 browser->curr_hot = rb_last(&browser->entries);
164}
165
166static int annotate_browser__run(struct annotate_browser *self, int evidx,
167 int refresh)
140{ 168{
141 struct rb_node *nd; 169 struct rb_node *nd = NULL;
142 struct hist_entry *he = self->b.priv; 170 struct symbol *sym = self->b.priv;
171 /*
172 * RIGHT To allow builtin-annotate to cycle thru multiple symbols by
173 * examining the exit key for this function.
174 */
175 int exit_keys[] = { 'H', NEWT_KEY_TAB, NEWT_KEY_UNTAB,
176 NEWT_KEY_RIGHT, 0 };
177 int key;
143 178
144 if (ui_browser__show(&self->b, he->ms.sym->name, 179 if (ui_browser__show(&self->b, sym->name,
145 "<- or ESC: exit, TAB/shift+TAB: cycle thru samples") < 0) 180 "<-, -> or ESC: exit, TAB/shift+TAB: "
181 "cycle hottest lines, H: Hottest") < 0)
146 return -1; 182 return -1;
147 183
148 newtFormAddHotKey(self->b.form, NEWT_KEY_LEFT); 184 ui_browser__add_exit_keys(&self->b, exit_keys);
149 newtFormAddHotKey(self->b.form, NEWT_KEY_RIGHT); 185 annotate_browser__calc_percent(self, evidx);
186
187 if (self->curr_hot)
188 annotate_browser__set_top(self, self->curr_hot);
150 189
151 nd = self->curr_hot; 190 nd = self->curr_hot;
152 if (nd) {
153 newtFormAddHotKey(self->b.form, NEWT_KEY_TAB);
154 newtFormAddHotKey(self->b.form, NEWT_KEY_UNTAB);
155 }
156 191
157 while (1) { 192 if (refresh != 0)
158 ui_browser__run(&self->b, es); 193 newtFormSetTimer(self->b.form, refresh);
159 194
160 if (es->reason != NEWT_EXIT_HOTKEY) 195 while (1) {
161 break; 196 key = ui_browser__run(&self->b);
197
198 if (refresh != 0) {
199 annotate_browser__calc_percent(self, evidx);
200 /*
201 * Current line focus got out of the list of most active
202 * lines, NULL it so that if TAB|UNTAB is pressed, we
203 * move to curr_hot (current hottest line).
204 */
205 if (nd != NULL && RB_EMPTY_NODE(nd))
206 nd = NULL;
207 }
162 208
163 switch (es->u.key) { 209 switch (key) {
210 case -1:
211 /*
212 * FIXME we need to check if it was
213 * es.reason == NEWT_EXIT_TIMER
214 */
215 if (refresh != 0)
216 symbol__annotate_decay_histogram(sym, evidx);
217 continue;
164 case NEWT_KEY_TAB: 218 case NEWT_KEY_TAB:
165 nd = rb_prev(nd); 219 if (nd != NULL) {
166 if (nd == NULL) 220 nd = rb_prev(nd);
167 nd = rb_last(&self->entries); 221 if (nd == NULL)
168 annotate_browser__set_top(self, nd); 222 nd = rb_last(&self->entries);
223 } else
224 nd = self->curr_hot;
169 break; 225 break;
170 case NEWT_KEY_UNTAB: 226 case NEWT_KEY_UNTAB:
171 nd = rb_next(nd); 227 if (nd != NULL)
172 if (nd == NULL) 228 nd = rb_next(nd);
173 nd = rb_first(&self->entries); 229 if (nd == NULL)
174 annotate_browser__set_top(self, nd); 230 nd = rb_first(&self->entries);
231 else
232 nd = self->curr_hot;
233 break;
234 case 'H':
235 nd = self->curr_hot;
175 break; 236 break;
176 default: 237 default:
177 goto out; 238 goto out;
178 } 239 }
240
241 if (nd != NULL)
242 annotate_browser__set_top(self, nd);
179 } 243 }
180out: 244out:
181 ui_browser__hide(&self->b); 245 ui_browser__hide(&self->b);
182 return es->u.key; 246 return key;
183} 247}
184 248
185int hist_entry__tui_annotate(struct hist_entry *self) 249int hist_entry__tui_annotate(struct hist_entry *he, int evidx)
250{
251 return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, 0);
252}
253
254int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
255 int refresh)
186{ 256{
187 struct newtExitStruct es;
188 struct objdump_line *pos, *n; 257 struct objdump_line *pos, *n;
189 struct objdump_line_rb_node *rbpos; 258 struct annotation *notes;
190 LIST_HEAD(head);
191 struct annotate_browser browser = { 259 struct annotate_browser browser = {
192 .b = { 260 .b = {
193 .entries = &head,
194 .refresh = ui_browser__list_head_refresh, 261 .refresh = ui_browser__list_head_refresh,
195 .seek = ui_browser__list_head_seek, 262 .seek = ui_browser__list_head_seek,
196 .write = annotate_browser__write, 263 .write = annotate_browser__write,
197 .priv = self, 264 .priv = sym,
198 }, 265 },
199 }; 266 };
200 int ret; 267 int ret;
201 268
202 if (self->ms.sym == NULL) 269 if (sym == NULL)
203 return -1; 270 return -1;
204 271
205 if (self->ms.map->dso->annotate_warned) 272 if (map->dso->annotate_warned)
206 return -1; 273 return -1;
207 274
208 if (hist_entry__annotate(self, &head, sizeof(*rbpos)) < 0) { 275 if (symbol__annotate(sym, map, sizeof(struct objdump_line_rb_node)) < 0) {
209 ui__error_window(ui_helpline__last_msg); 276 ui__error_window(ui_helpline__last_msg);
210 return -1; 277 return -1;
211 } 278 }
212 279
213 ui_helpline__push("Press <- or ESC to exit"); 280 ui_helpline__push("Press <- or ESC to exit");
214 281
215 list_for_each_entry(pos, &head, node) { 282 notes = symbol__annotation(sym);
283
284 list_for_each_entry(pos, &notes->src->source, node) {
285 struct objdump_line_rb_node *rbpos;
216 size_t line_len = strlen(pos->line); 286 size_t line_len = strlen(pos->line);
287
217 if (browser.b.width < line_len) 288 if (browser.b.width < line_len)
218 browser.b.width = line_len; 289 browser.b.width = line_len;
219 rbpos = objdump_line__rb(pos); 290 rbpos = objdump_line__rb(pos);
220 rbpos->idx = browser.b.nr_entries++; 291 rbpos->idx = browser.b.nr_entries++;
221 rbpos->percent = objdump_line__calc_percent(pos, &head, self->ms.sym);
222 if (rbpos->percent < 0.01)
223 continue;
224 objdump__insert_line(&browser.entries, rbpos);
225 } 292 }
226 293
227 /* 294 browser.b.entries = &notes->src->source,
228 * Position the browser at the hottest line.
229 */
230 browser.curr_hot = rb_last(&browser.entries);
231 if (browser.curr_hot)
232 annotate_browser__set_top(&browser, browser.curr_hot);
233
234 browser.b.width += 18; /* Percentage */ 295 browser.b.width += 18; /* Percentage */
235 ret = annotate_browser__run(&browser, &es); 296 ret = annotate_browser__run(&browser, evidx, refresh);
236 list_for_each_entry_safe(pos, n, &head, node) { 297 list_for_each_entry_safe(pos, n, &notes->src->source, node) {
237 list_del(&pos->node); 298 list_del(&pos->node);
238 objdump_line__free(pos); 299 objdump_line__free(pos);
239 } 300 }
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c
index 6866aa4c41e0..5d767c622dfc 100644
--- a/tools/perf/util/ui/browsers/hists.c
+++ b/tools/perf/util/ui/browsers/hists.c
@@ -7,6 +7,8 @@
7#include <newt.h> 7#include <newt.h>
8#include <linux/rbtree.h> 8#include <linux/rbtree.h>
9 9
10#include "../../evsel.h"
11#include "../../evlist.h"
10#include "../../hist.h" 12#include "../../hist.h"
11#include "../../pstack.h" 13#include "../../pstack.h"
12#include "../../sort.h" 14#include "../../sort.h"
@@ -58,6 +60,11 @@ static char callchain_list__folded(const struct callchain_list *self)
58 return map_symbol__folded(&self->ms); 60 return map_symbol__folded(&self->ms);
59} 61}
60 62
63static void map_symbol__set_folding(struct map_symbol *self, bool unfold)
64{
65 self->unfolded = unfold ? self->has_children : false;
66}
67
61static int callchain_node__count_rows_rb_tree(struct callchain_node *self) 68static int callchain_node__count_rows_rb_tree(struct callchain_node *self)
62{ 69{
63 int n = 0; 70 int n = 0;
@@ -129,16 +136,16 @@ static void callchain_node__init_have_children_rb_tree(struct callchain_node *se
129 for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) { 136 for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) {
130 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node); 137 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
131 struct callchain_list *chain; 138 struct callchain_list *chain;
132 int first = true; 139 bool first = true;
133 140
134 list_for_each_entry(chain, &child->val, list) { 141 list_for_each_entry(chain, &child->val, list) {
135 if (first) { 142 if (first) {
136 first = false; 143 first = false;
137 chain->ms.has_children = chain->list.next != &child->val || 144 chain->ms.has_children = chain->list.next != &child->val ||
138 rb_first(&child->rb_root) != NULL; 145 !RB_EMPTY_ROOT(&child->rb_root);
139 } else 146 } else
140 chain->ms.has_children = chain->list.next == &child->val && 147 chain->ms.has_children = chain->list.next == &child->val &&
141 rb_first(&child->rb_root) != NULL; 148 !RB_EMPTY_ROOT(&child->rb_root);
142 } 149 }
143 150
144 callchain_node__init_have_children_rb_tree(child); 151 callchain_node__init_have_children_rb_tree(child);
@@ -150,7 +157,7 @@ static void callchain_node__init_have_children(struct callchain_node *self)
150 struct callchain_list *chain; 157 struct callchain_list *chain;
151 158
152 list_for_each_entry(chain, &self->val, list) 159 list_for_each_entry(chain, &self->val, list)
153 chain->ms.has_children = rb_first(&self->rb_root) != NULL; 160 chain->ms.has_children = !RB_EMPTY_ROOT(&self->rb_root);
154 161
155 callchain_node__init_have_children_rb_tree(self); 162 callchain_node__init_have_children_rb_tree(self);
156} 163}
@@ -168,6 +175,7 @@ static void callchain__init_have_children(struct rb_root *self)
168static void hist_entry__init_have_children(struct hist_entry *self) 175static void hist_entry__init_have_children(struct hist_entry *self)
169{ 176{
170 if (!self->init_have_children) { 177 if (!self->init_have_children) {
178 self->ms.has_children = !RB_EMPTY_ROOT(&self->sorted_chain);
171 callchain__init_have_children(&self->sorted_chain); 179 callchain__init_have_children(&self->sorted_chain);
172 self->init_have_children = true; 180 self->init_have_children = true;
173 } 181 }
@@ -195,43 +203,115 @@ static bool hist_browser__toggle_fold(struct hist_browser *self)
195 return false; 203 return false;
196} 204}
197 205
198static int hist_browser__run(struct hist_browser *self, const char *title, 206static int callchain_node__set_folding_rb_tree(struct callchain_node *self, bool unfold)
199 struct newtExitStruct *es)
200{ 207{
201 char str[256], unit; 208 int n = 0;
202 unsigned long nr_events = self->hists->stats.nr_events[PERF_RECORD_SAMPLE]; 209 struct rb_node *nd;
210
211 for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) {
212 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
213 struct callchain_list *chain;
214 bool has_children = false;
215
216 list_for_each_entry(chain, &child->val, list) {
217 ++n;
218 map_symbol__set_folding(&chain->ms, unfold);
219 has_children = chain->ms.has_children;
220 }
221
222 if (has_children)
223 n += callchain_node__set_folding_rb_tree(child, unfold);
224 }
225
226 return n;
227}
228
229static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
230{
231 struct callchain_list *chain;
232 bool has_children = false;
233 int n = 0;
234
235 list_for_each_entry(chain, &node->val, list) {
236 ++n;
237 map_symbol__set_folding(&chain->ms, unfold);
238 has_children = chain->ms.has_children;
239 }
240
241 if (has_children)
242 n += callchain_node__set_folding_rb_tree(node, unfold);
243
244 return n;
245}
246
247static int callchain__set_folding(struct rb_root *chain, bool unfold)
248{
249 struct rb_node *nd;
250 int n = 0;
251
252 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
253 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
254 n += callchain_node__set_folding(node, unfold);
255 }
256
257 return n;
258}
259
260static void hist_entry__set_folding(struct hist_entry *self, bool unfold)
261{
262 hist_entry__init_have_children(self);
263 map_symbol__set_folding(&self->ms, unfold);
264
265 if (self->ms.has_children) {
266 int n = callchain__set_folding(&self->sorted_chain, unfold);
267 self->nr_rows = unfold ? n : 0;
268 } else
269 self->nr_rows = 0;
270}
271
272static void hists__set_folding(struct hists *self, bool unfold)
273{
274 struct rb_node *nd;
275
276 self->nr_entries = 0;
277
278 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
279 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
280 hist_entry__set_folding(he, unfold);
281 self->nr_entries += 1 + he->nr_rows;
282 }
283}
284
285static void hist_browser__set_folding(struct hist_browser *self, bool unfold)
286{
287 hists__set_folding(self->hists, unfold);
288 self->b.nr_entries = self->hists->nr_entries;
289 /* Go to the start, we may be way after valid entries after a collapse */
290 ui_browser__reset_index(&self->b);
291}
292
293static int hist_browser__run(struct hist_browser *self, const char *title)
294{
295 int key;
296 int exit_keys[] = { 'a', '?', 'h', 'C', 'd', 'D', 'E', 't',
297 NEWT_KEY_ENTER, NEWT_KEY_RIGHT, NEWT_KEY_LEFT,
298 NEWT_KEY_TAB, NEWT_KEY_UNTAB, 0, };
203 299
204 self->b.entries = &self->hists->entries; 300 self->b.entries = &self->hists->entries;
205 self->b.nr_entries = self->hists->nr_entries; 301 self->b.nr_entries = self->hists->nr_entries;
206 302
207 hist_browser__refresh_dimensions(self); 303 hist_browser__refresh_dimensions(self);
208 304
209 nr_events = convert_unit(nr_events, &unit);
210 snprintf(str, sizeof(str), "Events: %lu%c ",
211 nr_events, unit);
212 newtDrawRootText(0, 0, str);
213
214 if (ui_browser__show(&self->b, title, 305 if (ui_browser__show(&self->b, title,
215 "Press '?' for help on key bindings") < 0) 306 "Press '?' for help on key bindings") < 0)
216 return -1; 307 return -1;
217 308
218 newtFormAddHotKey(self->b.form, 'a'); 309 ui_browser__add_exit_keys(&self->b, exit_keys);
219 newtFormAddHotKey(self->b.form, '?');
220 newtFormAddHotKey(self->b.form, 'h');
221 newtFormAddHotKey(self->b.form, 'd');
222 newtFormAddHotKey(self->b.form, 'D');
223 newtFormAddHotKey(self->b.form, 't');
224
225 newtFormAddHotKey(self->b.form, NEWT_KEY_LEFT);
226 newtFormAddHotKey(self->b.form, NEWT_KEY_RIGHT);
227 newtFormAddHotKey(self->b.form, NEWT_KEY_ENTER);
228 310
229 while (1) { 311 while (1) {
230 ui_browser__run(&self->b, es); 312 key = ui_browser__run(&self->b);
231 313
232 if (es->reason != NEWT_EXIT_HOTKEY) 314 switch (key) {
233 break;
234 switch (es->u.key) {
235 case 'D': { /* Debug */ 315 case 'D': { /* Debug */
236 static int seq; 316 static int seq;
237 struct hist_entry *h = rb_entry(self->b.top, 317 struct hist_entry *h = rb_entry(self->b.top,
@@ -245,18 +325,26 @@ static int hist_browser__run(struct hist_browser *self, const char *title,
245 self->b.top_idx, 325 self->b.top_idx,
246 h->row_offset, h->nr_rows); 326 h->row_offset, h->nr_rows);
247 } 327 }
248 continue; 328 break;
329 case 'C':
330 /* Collapse the whole world. */
331 hist_browser__set_folding(self, false);
332 break;
333 case 'E':
334 /* Expand the whole world. */
335 hist_browser__set_folding(self, true);
336 break;
249 case NEWT_KEY_ENTER: 337 case NEWT_KEY_ENTER:
250 if (hist_browser__toggle_fold(self)) 338 if (hist_browser__toggle_fold(self))
251 break; 339 break;
252 /* fall thru */ 340 /* fall thru */
253 default: 341 default:
254 return 0; 342 goto out;
255 } 343 }
256 } 344 }
257 345out:
258 ui_browser__hide(&self->b); 346 ui_browser__hide(&self->b);
259 return 0; 347 return key;
260} 348}
261 349
262static char *callchain_list__sym_name(struct callchain_list *self, 350static char *callchain_list__sym_name(struct callchain_list *self,
@@ -265,7 +353,7 @@ static char *callchain_list__sym_name(struct callchain_list *self,
265 if (self->ms.sym) 353 if (self->ms.sym)
266 return self->ms.sym->name; 354 return self->ms.sym->name;
267 355
268 snprintf(bf, bfsize, "%#Lx", self->ip); 356 snprintf(bf, bfsize, "%#" PRIx64, self->ip);
269 return bf; 357 return bf;
270} 358}
271 359
@@ -292,7 +380,7 @@ static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *self,
292 while (node) { 380 while (node) {
293 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); 381 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
294 struct rb_node *next = rb_next(node); 382 struct rb_node *next = rb_next(node);
295 u64 cumul = cumul_hits(child); 383 u64 cumul = callchain_cumul_hits(child);
296 struct callchain_list *chain; 384 struct callchain_list *chain;
297 char folded_sign = ' '; 385 char folded_sign = ' ';
298 int first = true; 386 int first = true;
@@ -306,15 +394,10 @@ static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *self,
306 int color; 394 int color;
307 bool was_first = first; 395 bool was_first = first;
308 396
309 if (first) { 397 if (first)
310 first = false; 398 first = false;
311 chain->ms.has_children = chain->list.next != &child->val || 399 else
312 rb_first(&child->rb_root) != NULL;
313 } else {
314 extra_offset = LEVEL_OFFSET_STEP; 400 extra_offset = LEVEL_OFFSET_STEP;
315 chain->ms.has_children = chain->list.next == &child->val &&
316 rb_first(&child->rb_root) != NULL;
317 }
318 401
319 folded_sign = callchain_list__folded(chain); 402 folded_sign = callchain_list__folded(chain);
320 if (*row_offset != 0) { 403 if (*row_offset != 0) {
@@ -341,8 +424,8 @@ static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *self,
341 *is_current_entry = true; 424 *is_current_entry = true;
342 } 425 }
343 426
344 SLsmg_set_color(color); 427 ui_browser__set_color(&self->b, color);
345 SLsmg_gotorc(self->b.y + row, self->b.x); 428 ui_browser__gotorc(&self->b, row, 0);
346 slsmg_write_nstring(" ", offset + extra_offset); 429 slsmg_write_nstring(" ", offset + extra_offset);
347 slsmg_printf("%c ", folded_sign); 430 slsmg_printf("%c ", folded_sign);
348 slsmg_write_nstring(str, width); 431 slsmg_write_nstring(str, width);
@@ -384,12 +467,7 @@ static int hist_browser__show_callchain_node(struct hist_browser *self,
384 list_for_each_entry(chain, &node->val, list) { 467 list_for_each_entry(chain, &node->val, list) {
385 char ipstr[BITS_PER_LONG / 4 + 1], *s; 468 char ipstr[BITS_PER_LONG / 4 + 1], *s;
386 int color; 469 int color;
387 /* 470
388 * FIXME: This should be moved to somewhere else,
389 * probably when the callchain is created, so as not to
390 * traverse it all over again
391 */
392 chain->ms.has_children = rb_first(&node->rb_root) != NULL;
393 folded_sign = callchain_list__folded(chain); 471 folded_sign = callchain_list__folded(chain);
394 472
395 if (*row_offset != 0) { 473 if (*row_offset != 0) {
@@ -405,8 +483,8 @@ static int hist_browser__show_callchain_node(struct hist_browser *self,
405 } 483 }
406 484
407 s = callchain_list__sym_name(chain, ipstr, sizeof(ipstr)); 485 s = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
408 SLsmg_gotorc(self->b.y + row, self->b.x); 486 ui_browser__gotorc(&self->b, row, 0);
409 SLsmg_set_color(color); 487 ui_browser__set_color(&self->b, color);
410 slsmg_write_nstring(" ", offset); 488 slsmg_write_nstring(" ", offset);
411 slsmg_printf("%c ", folded_sign); 489 slsmg_printf("%c ", folded_sign);
412 slsmg_write_nstring(s, width - 2); 490 slsmg_write_nstring(s, width - 2);
@@ -465,7 +543,7 @@ static int hist_browser__show_entry(struct hist_browser *self,
465 } 543 }
466 544
467 if (symbol_conf.use_callchain) { 545 if (symbol_conf.use_callchain) {
468 entry->ms.has_children = !RB_EMPTY_ROOT(&entry->sorted_chain); 546 hist_entry__init_have_children(entry);
469 folded_sign = hist_entry__folded(entry); 547 folded_sign = hist_entry__folded(entry);
470 } 548 }
471 549
@@ -484,8 +562,8 @@ static int hist_browser__show_entry(struct hist_browser *self,
484 color = HE_COLORSET_NORMAL; 562 color = HE_COLORSET_NORMAL;
485 } 563 }
486 564
487 SLsmg_set_color(color); 565 ui_browser__set_color(&self->b, color);
488 SLsmg_gotorc(self->b.y + row, self->b.x); 566 ui_browser__gotorc(&self->b, row, 0);
489 if (symbol_conf.use_callchain) { 567 if (symbol_conf.use_callchain) {
490 slsmg_printf("%c ", folded_sign); 568 slsmg_printf("%c ", folded_sign);
491 width -= 2; 569 width -= 2;
@@ -563,6 +641,9 @@ static void ui_browser__hists_seek(struct ui_browser *self,
563 struct rb_node *nd; 641 struct rb_node *nd;
564 bool first = true; 642 bool first = true;
565 643
644 if (self->nr_entries == 0)
645 return;
646
566 switch (whence) { 647 switch (whence) {
567 case SEEK_SET: 648 case SEEK_SET:
568 nd = hists__filter_entries(rb_first(self->entries)); 649 nd = hists__filter_entries(rb_first(self->entries));
@@ -687,8 +768,6 @@ static struct hist_browser *hist_browser__new(struct hists *hists)
687 768
688static void hist_browser__delete(struct hist_browser *self) 769static void hist_browser__delete(struct hist_browser *self)
689{ 770{
690 newtFormDestroy(self->b.form);
691 newtPopWindow();
692 free(self); 771 free(self);
693} 772}
694 773
@@ -702,30 +781,37 @@ static struct thread *hist_browser__selected_thread(struct hist_browser *self)
702 return self->he_selection->thread; 781 return self->he_selection->thread;
703} 782}
704 783
705static int hist_browser__title(char *bf, size_t size, const char *ev_name, 784static int hists__browser_title(struct hists *self, char *bf, size_t size,
706 const struct dso *dso, const struct thread *thread) 785 const char *ev_name, const struct dso *dso,
786 const struct thread *thread)
707{ 787{
708 int printed = 0; 788 char unit;
789 int printed;
790 unsigned long nr_events = self->stats.nr_events[PERF_RECORD_SAMPLE];
791
792 nr_events = convert_unit(nr_events, &unit);
793 printed = snprintf(bf, size, "Events: %lu%c %s", nr_events, unit, ev_name);
709 794
710 if (thread) 795 if (thread)
711 printed += snprintf(bf + printed, size - printed, 796 printed += snprintf(bf + printed, size - printed,
712 "Thread: %s(%d)", 797 ", Thread: %s(%d)",
713 (thread->comm_set ? thread->comm : ""), 798 (thread->comm_set ? thread->comm : ""),
714 thread->pid); 799 thread->pid);
715 if (dso) 800 if (dso)
716 printed += snprintf(bf + printed, size - printed, 801 printed += snprintf(bf + printed, size - printed,
717 "%sDSO: %s", thread ? " " : "", 802 ", DSO: %s", dso->short_name);
718 dso->short_name); 803 return printed;
719 return printed ?: snprintf(bf, size, "Event: %s", ev_name);
720} 804}
721 805
722int hists__browse(struct hists *self, const char *helpline, const char *ev_name) 806static int perf_evsel__hists_browse(struct perf_evsel *evsel,
807 const char *helpline, const char *ev_name,
808 bool left_exits)
723{ 809{
810 struct hists *self = &evsel->hists;
724 struct hist_browser *browser = hist_browser__new(self); 811 struct hist_browser *browser = hist_browser__new(self);
725 struct pstack *fstack; 812 struct pstack *fstack;
726 const struct thread *thread_filter = NULL; 813 const struct thread *thread_filter = NULL;
727 const struct dso *dso_filter = NULL; 814 const struct dso *dso_filter = NULL;
728 struct newtExitStruct es;
729 char msg[160]; 815 char msg[160];
730 int key = -1; 816 int key = -1;
731 817
@@ -738,84 +824,88 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
738 824
739 ui_helpline__push(helpline); 825 ui_helpline__push(helpline);
740 826
741 hist_browser__title(msg, sizeof(msg), ev_name, 827 hists__browser_title(self, msg, sizeof(msg), ev_name,
742 dso_filter, thread_filter); 828 dso_filter, thread_filter);
743
744 while (1) { 829 while (1) {
745 const struct thread *thread; 830 const struct thread *thread = NULL;
746 const struct dso *dso; 831 const struct dso *dso = NULL;
747 char *options[16]; 832 char *options[16];
748 int nr_options = 0, choice = 0, i, 833 int nr_options = 0, choice = 0, i,
749 annotate = -2, zoom_dso = -2, zoom_thread = -2, 834 annotate = -2, zoom_dso = -2, zoom_thread = -2,
750 browse_map = -2; 835 browse_map = -2;
751 836
752 if (hist_browser__run(browser, msg, &es)) 837 key = hist_browser__run(browser, msg);
753 break;
754 838
755 thread = hist_browser__selected_thread(browser); 839 if (browser->he_selection != NULL) {
756 dso = browser->selection->map ? browser->selection->map->dso : NULL; 840 thread = hist_browser__selected_thread(browser);
841 dso = browser->selection->map ? browser->selection->map->dso : NULL;
842 }
757 843
758 if (es.reason == NEWT_EXIT_HOTKEY) { 844 switch (key) {
759 key = es.u.key; 845 case NEWT_KEY_TAB:
846 case NEWT_KEY_UNTAB:
847 /*
848 * Exit the browser, let hists__browser_tree
849 * go to the next or previous
850 */
851 goto out_free_stack;
852 case 'a':
853 if (browser->selection == NULL ||
854 browser->selection->sym == NULL ||
855 browser->selection->map->dso->annotate_warned)
856 continue;
857 goto do_annotate;
858 case 'd':
859 goto zoom_dso;
860 case 't':
861 goto zoom_thread;
862 case NEWT_KEY_F1:
863 case 'h':
864 case '?':
865 ui__help_window("-> Zoom into DSO/Threads & Annotate current symbol\n"
866 "<- Zoom out\n"
867 "a Annotate current symbol\n"
868 "h/?/F1 Show this window\n"
869 "C Collapse all callchains\n"
870 "E Expand all callchains\n"
871 "d Zoom into current DSO\n"
872 "t Zoom into current Thread\n"
873 "TAB/UNTAB Switch events\n"
874 "q/CTRL+C Exit browser");
875 continue;
876 case NEWT_KEY_ENTER:
877 case NEWT_KEY_RIGHT:
878 /* menu */
879 break;
880 case NEWT_KEY_LEFT: {
881 const void *top;
760 882
761 switch (key) { 883 if (pstack__empty(fstack)) {
762 case NEWT_KEY_F1:
763 goto do_help;
764 case NEWT_KEY_TAB:
765 case NEWT_KEY_UNTAB:
766 /* 884 /*
767 * Exit the browser, let hists__browser_tree 885 * Go back to the perf_evsel_menu__run or other user
768 * go to the next or previous
769 */ 886 */
770 goto out_free_stack; 887 if (left_exits)
771 default:; 888 goto out_free_stack;
772 }
773
774 switch (key) {
775 case 'a':
776 if (browser->selection->map == NULL ||
777 browser->selection->map->dso->annotate_warned)
778 continue;
779 goto do_annotate;
780 case 'd':
781 goto zoom_dso;
782 case 't':
783 goto zoom_thread;
784 case 'h':
785 case '?':
786do_help:
787 ui__help_window("-> Zoom into DSO/Threads & Annotate current symbol\n"
788 "<- Zoom out\n"
789 "a Annotate current symbol\n"
790 "h/?/F1 Show this window\n"
791 "d Zoom into current DSO\n"
792 "t Zoom into current Thread\n"
793 "q/CTRL+C Exit browser");
794 continue; 889 continue;
795 default:;
796 } 890 }
797 if (is_exit_key(key)) { 891 top = pstack__pop(fstack);
798 if (key == NEWT_KEY_ESCAPE && 892 if (top == &dso_filter)
799 !ui__dialog_yesno("Do you really want to exit?")) 893 goto zoom_out_dso;
800 continue; 894 if (top == &thread_filter)
801 break; 895 goto zoom_out_thread;
802 } 896 continue;
803 897 }
804 if (es.u.key == NEWT_KEY_LEFT) { 898 case NEWT_KEY_ESCAPE:
805 const void *top; 899 if (!left_exits &&
806 900 !ui__dialog_yesno("Do you really want to exit?"))
807 if (pstack__empty(fstack))
808 continue;
809 top = pstack__pop(fstack);
810 if (top == &dso_filter)
811 goto zoom_out_dso;
812 if (top == &thread_filter)
813 goto zoom_out_thread;
814 continue; 901 continue;
815 } 902 /* Fall thru */
903 default:
904 goto out_free_stack;
816 } 905 }
817 906
818 if (browser->selection->sym != NULL && 907 if (browser->selection != NULL &&
908 browser->selection->sym != NULL &&
819 !browser->selection->map->dso->annotate_warned && 909 !browser->selection->map->dso->annotate_warned &&
820 asprintf(&options[nr_options], "Annotate %s", 910 asprintf(&options[nr_options], "Annotate %s",
821 browser->selection->sym->name) > 0) 911 browser->selection->sym->name) > 0)
@@ -834,7 +924,8 @@ do_help:
834 (dso->kernel ? "the Kernel" : dso->short_name)) > 0) 924 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
835 zoom_dso = nr_options++; 925 zoom_dso = nr_options++;
836 926
837 if (browser->selection->map != NULL && 927 if (browser->selection != NULL &&
928 browser->selection->map != NULL &&
838 asprintf(&options[nr_options], "Browse map details") > 0) 929 asprintf(&options[nr_options], "Browse map details") > 0)
839 browse_map = nr_options++; 930 browse_map = nr_options++;
840 931
@@ -854,19 +945,11 @@ do_help:
854 if (choice == annotate) { 945 if (choice == annotate) {
855 struct hist_entry *he; 946 struct hist_entry *he;
856do_annotate: 947do_annotate:
857 if (browser->selection->map->dso->origin == DSO__ORIG_KERNEL) {
858 browser->selection->map->dso->annotate_warned = 1;
859 ui_helpline__puts("No vmlinux file found, can't "
860 "annotate with just a "
861 "kallsyms file");
862 continue;
863 }
864
865 he = hist_browser__selected_entry(browser); 948 he = hist_browser__selected_entry(browser);
866 if (he == NULL) 949 if (he == NULL)
867 continue; 950 continue;
868 951
869 hist_entry__tui_annotate(he); 952 hist_entry__tui_annotate(he, evsel->idx);
870 } else if (choice == browse_map) 953 } else if (choice == browse_map)
871 map__browse(browser->selection->map); 954 map__browse(browser->selection->map);
872 else if (choice == zoom_dso) { 955 else if (choice == zoom_dso) {
@@ -885,8 +968,8 @@ zoom_out_dso:
885 pstack__push(fstack, &dso_filter); 968 pstack__push(fstack, &dso_filter);
886 } 969 }
887 hists__filter_by_dso(self, dso_filter); 970 hists__filter_by_dso(self, dso_filter);
888 hist_browser__title(msg, sizeof(msg), ev_name, 971 hists__browser_title(self, msg, sizeof(msg), ev_name,
889 dso_filter, thread_filter); 972 dso_filter, thread_filter);
890 hist_browser__reset(browser); 973 hist_browser__reset(browser);
891 } else if (choice == zoom_thread) { 974 } else if (choice == zoom_thread) {
892zoom_thread: 975zoom_thread:
@@ -903,8 +986,8 @@ zoom_out_thread:
903 pstack__push(fstack, &thread_filter); 986 pstack__push(fstack, &thread_filter);
904 } 987 }
905 hists__filter_by_thread(self, thread_filter); 988 hists__filter_by_thread(self, thread_filter);
906 hist_browser__title(msg, sizeof(msg), ev_name, 989 hists__browser_title(self, msg, sizeof(msg), ev_name,
907 dso_filter, thread_filter); 990 dso_filter, thread_filter);
908 hist_browser__reset(browser); 991 hist_browser__reset(browser);
909 } 992 }
910 } 993 }
@@ -915,34 +998,141 @@ out:
915 return key; 998 return key;
916} 999}
917 1000
918int hists__tui_browse_tree(struct rb_root *self, const char *help) 1001struct perf_evsel_menu {
1002 struct ui_browser b;
1003 struct perf_evsel *selection;
1004};
1005
1006static void perf_evsel_menu__write(struct ui_browser *browser,
1007 void *entry, int row)
919{ 1008{
920 struct rb_node *first = rb_first(self), *nd = first, *next; 1009 struct perf_evsel_menu *menu = container_of(browser,
921 int key = 0; 1010 struct perf_evsel_menu, b);
1011 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1012 bool current_entry = ui_browser__is_current_entry(browser, row);
1013 unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1014 const char *ev_name = event_name(evsel);
1015 char bf[256], unit;
1016
1017 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
1018 HE_COLORSET_NORMAL);
1019
1020 nr_events = convert_unit(nr_events, &unit);
1021 snprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
1022 unit, unit == ' ' ? "" : " ", ev_name);
1023 slsmg_write_nstring(bf, browser->width);
922 1024
923 while (nd) { 1025 if (current_entry)
924 struct hists *hists = rb_entry(nd, struct hists, rb_node); 1026 menu->selection = evsel;
925 const char *ev_name = __event_name(hists->type, hists->config); 1027}
926 1028
927 key = hists__browse(hists, help, ev_name); 1029static int perf_evsel_menu__run(struct perf_evsel_menu *menu, const char *help)
1030{
1031 int exit_keys[] = { NEWT_KEY_ENTER, NEWT_KEY_RIGHT, 0, };
1032 struct perf_evlist *evlist = menu->b.priv;
1033 struct perf_evsel *pos;
1034 const char *ev_name, *title = "Available samples";
1035 int key;
1036
1037 if (ui_browser__show(&menu->b, title,
1038 "ESC: exit, ENTER|->: Browse histograms") < 0)
1039 return -1;
928 1040
929 if (is_exit_key(key)) 1041 ui_browser__add_exit_keys(&menu->b, exit_keys);
1042
1043 while (1) {
1044 key = ui_browser__run(&menu->b);
1045
1046 switch (key) {
1047 case NEWT_KEY_RIGHT:
1048 case NEWT_KEY_ENTER:
1049 if (!menu->selection)
1050 continue;
1051 pos = menu->selection;
1052browse_hists:
1053 ev_name = event_name(pos);
1054 key = perf_evsel__hists_browse(pos, help, ev_name, true);
1055 ui_browser__show_title(&menu->b, title);
930 break; 1056 break;
1057 case NEWT_KEY_LEFT:
1058 continue;
1059 case NEWT_KEY_ESCAPE:
1060 if (!ui__dialog_yesno("Do you really want to exit?"))
1061 continue;
1062 /* Fall thru */
1063 default:
1064 goto out;
1065 }
931 1066
932 switch (key) { 1067 switch (key) {
933 case NEWT_KEY_TAB: 1068 case NEWT_KEY_TAB:
934 next = rb_next(nd); 1069 if (pos->node.next == &evlist->entries)
935 if (next) 1070 pos = list_entry(evlist->entries.next, struct perf_evsel, node);
936 nd = next; 1071 else
937 break; 1072 pos = list_entry(pos->node.next, struct perf_evsel, node);
1073 goto browse_hists;
938 case NEWT_KEY_UNTAB: 1074 case NEWT_KEY_UNTAB:
939 if (nd == first) 1075 if (pos->node.prev == &evlist->entries)
940 continue; 1076 pos = list_entry(evlist->entries.prev, struct perf_evsel, node);
941 nd = rb_prev(nd); 1077 else
1078 pos = list_entry(pos->node.prev, struct perf_evsel, node);
1079 goto browse_hists;
1080 case 'q':
1081 case CTRL('c'):
1082 goto out;
942 default: 1083 default:
943 break; 1084 break;
944 } 1085 }
945 } 1086 }
946 1087
1088out:
1089 ui_browser__hide(&menu->b);
947 return key; 1090 return key;
948} 1091}
1092
1093static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
1094 const char *help)
1095{
1096 struct perf_evsel *pos;
1097 struct perf_evsel_menu menu = {
1098 .b = {
1099 .entries = &evlist->entries,
1100 .refresh = ui_browser__list_head_refresh,
1101 .seek = ui_browser__list_head_seek,
1102 .write = perf_evsel_menu__write,
1103 .nr_entries = evlist->nr_entries,
1104 .priv = evlist,
1105 },
1106 };
1107
1108 ui_helpline__push("Press ESC to exit");
1109
1110 list_for_each_entry(pos, &evlist->entries, node) {
1111 const char *ev_name = event_name(pos);
1112 size_t line_len = strlen(ev_name) + 7;
1113
1114 if (menu.b.width < line_len)
1115 menu.b.width = line_len;
1116 /*
1117 * Cache the evsel name, tracepoints have a _high_ cost per
1118 * event_name() call.
1119 */
1120 if (pos->name == NULL)
1121 pos->name = strdup(ev_name);
1122 }
1123
1124 return perf_evsel_menu__run(&menu, help);
1125}
1126
1127int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help)
1128{
1129
1130 if (evlist->nr_entries == 1) {
1131 struct perf_evsel *first = list_entry(evlist->entries.next,
1132 struct perf_evsel, node);
1133 const char *ev_name = event_name(first);
1134 return perf_evsel__hists_browse(first, help, ev_name, false);
1135 }
1136
1137 return __perf_evlist__tui_browse_hists(evlist, help);
1138}
diff --git a/tools/perf/util/ui/browsers/map.c b/tools/perf/util/ui/browsers/map.c
index 142b825b42bf..8462bffe20bc 100644
--- a/tools/perf/util/ui/browsers/map.c
+++ b/tools/perf/util/ui/browsers/map.c
@@ -1,6 +1,6 @@
1#include "../libslang.h" 1#include "../libslang.h"
2#include <elf.h> 2#include <elf.h>
3#include <newt.h> 3#include <inttypes.h>
4#include <sys/ttydefaults.h> 4#include <sys/ttydefaults.h>
5#include <ctype.h> 5#include <ctype.h>
6#include <string.h> 6#include <string.h>
@@ -41,13 +41,12 @@ static int ui_entry__read(const char *title, char *bf, size_t size, int width)
41out_free_form: 41out_free_form:
42 newtPopWindow(); 42 newtPopWindow();
43 newtFormDestroy(form); 43 newtFormDestroy(form);
44 return 0; 44 return err;
45} 45}
46 46
47struct map_browser { 47struct map_browser {
48 struct ui_browser b; 48 struct ui_browser b;
49 struct map *map; 49 struct map *map;
50 u16 namelen;
51 u8 addrlen; 50 u8 addrlen;
52}; 51};
53 52
@@ -56,14 +55,16 @@ static void map_browser__write(struct ui_browser *self, void *nd, int row)
56 struct symbol *sym = rb_entry(nd, struct symbol, rb_node); 55 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
57 struct map_browser *mb = container_of(self, struct map_browser, b); 56 struct map_browser *mb = container_of(self, struct map_browser, b);
58 bool current_entry = ui_browser__is_current_entry(self, row); 57 bool current_entry = ui_browser__is_current_entry(self, row);
59 int color = ui_browser__percent_color(0, current_entry); 58 int width;
60 59
61 SLsmg_set_color(color); 60 ui_browser__set_percent_color(self, 0, current_entry);
62 slsmg_printf("%*llx %*llx %c ", 61 slsmg_printf("%*" PRIx64 " %*" PRIx64 " %c ",
63 mb->addrlen, sym->start, mb->addrlen, sym->end, 62 mb->addrlen, sym->start, mb->addrlen, sym->end,
64 sym->binding == STB_GLOBAL ? 'g' : 63 sym->binding == STB_GLOBAL ? 'g' :
65 sym->binding == STB_LOCAL ? 'l' : 'w'); 64 sym->binding == STB_LOCAL ? 'l' : 'w');
66 slsmg_write_nstring(sym->name, mb->namelen); 65 width = self->width - ((mb->addrlen * 2) + 4);
66 if (width > 0)
67 slsmg_write_nstring(sym->name, width);
67} 68}
68 69
69/* FIXME uber-kludgy, see comment on cmd_report... */ 70/* FIXME uber-kludgy, see comment on cmd_report... */
@@ -98,31 +99,29 @@ static int map_browser__search(struct map_browser *self)
98 return 0; 99 return 0;
99} 100}
100 101
101static int map_browser__run(struct map_browser *self, struct newtExitStruct *es) 102static int map_browser__run(struct map_browser *self)
102{ 103{
104 int key;
105
103 if (ui_browser__show(&self->b, self->map->dso->long_name, 106 if (ui_browser__show(&self->b, self->map->dso->long_name,
104 "Press <- or ESC to exit, %s / to search", 107 "Press <- or ESC to exit, %s / to search",
105 verbose ? "" : "restart with -v to use") < 0) 108 verbose ? "" : "restart with -v to use") < 0)
106 return -1; 109 return -1;
107 110
108 newtFormAddHotKey(self->b.form, NEWT_KEY_LEFT);
109 newtFormAddHotKey(self->b.form, NEWT_KEY_ENTER);
110 if (verbose) 111 if (verbose)
111 newtFormAddHotKey(self->b.form, '/'); 112 ui_browser__add_exit_key(&self->b, '/');
112 113
113 while (1) { 114 while (1) {
114 ui_browser__run(&self->b, es); 115 key = ui_browser__run(&self->b);
115 116
116 if (es->reason != NEWT_EXIT_HOTKEY) 117 if (verbose && key == '/')
117 break;
118 if (verbose && es->u.key == '/')
119 map_browser__search(self); 118 map_browser__search(self);
120 else 119 else
121 break; 120 break;
122 } 121 }
123 122
124 ui_browser__hide(&self->b); 123 ui_browser__hide(&self->b);
125 return 0; 124 return key;
126} 125}
127 126
128int map__browse(struct map *self) 127int map__browse(struct map *self)
@@ -136,7 +135,6 @@ int map__browse(struct map *self)
136 }, 135 },
137 .map = self, 136 .map = self,
138 }; 137 };
139 struct newtExitStruct es;
140 struct rb_node *nd; 138 struct rb_node *nd;
141 char tmp[BITS_PER_LONG / 4]; 139 char tmp[BITS_PER_LONG / 4];
142 u64 maxaddr = 0; 140 u64 maxaddr = 0;
@@ -144,8 +142,6 @@ int map__browse(struct map *self)
144 for (nd = rb_first(mb.b.entries); nd; nd = rb_next(nd)) { 142 for (nd = rb_first(mb.b.entries); nd; nd = rb_next(nd)) {
145 struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 143 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
146 144
147 if (mb.namelen < pos->namelen)
148 mb.namelen = pos->namelen;
149 if (maxaddr < pos->end) 145 if (maxaddr < pos->end)
150 maxaddr = pos->end; 146 maxaddr = pos->end;
151 if (verbose) { 147 if (verbose) {
@@ -155,7 +151,6 @@ int map__browse(struct map *self)
155 ++mb.b.nr_entries; 151 ++mb.b.nr_entries;
156 } 152 }
157 153
158 mb.addrlen = snprintf(tmp, sizeof(tmp), "%llx", maxaddr); 154 mb.addrlen = snprintf(tmp, sizeof(tmp), "%" PRIx64, maxaddr);
159 mb.b.width += mb.addrlen * 2 + 4 + mb.namelen; 155 return map_browser__run(&mb);
160 return map_browser__run(&mb, &es);
161} 156}
diff --git a/tools/perf/util/ui/browsers/top.c b/tools/perf/util/ui/browsers/top.c
new file mode 100644
index 000000000000..5a06538532af
--- /dev/null
+++ b/tools/perf/util/ui/browsers/top.c
@@ -0,0 +1,213 @@
1/*
2 * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
3 *
4 * Parts came from builtin-{top,stat,record}.c, see those files for further
5 * copyright notes.
6 *
7 * Released under the GPL v2. (and only v2, not any later version)
8 */
9#include "../browser.h"
10#include "../../annotate.h"
11#include "../helpline.h"
12#include "../libslang.h"
13#include "../util.h"
14#include "../../evlist.h"
15#include "../../hist.h"
16#include "../../sort.h"
17#include "../../symbol.h"
18#include "../../top.h"
19
20struct perf_top_browser {
21 struct ui_browser b;
22 struct rb_root root;
23 struct sym_entry *selection;
24 float sum_ksamples;
25 int dso_width;
26 int dso_short_width;
27 int sym_width;
28};
29
30static void perf_top_browser__write(struct ui_browser *browser, void *entry, int row)
31{
32 struct perf_top_browser *top_browser = container_of(browser, struct perf_top_browser, b);
33 struct sym_entry *syme = rb_entry(entry, struct sym_entry, rb_node);
34 bool current_entry = ui_browser__is_current_entry(browser, row);
35 struct symbol *symbol = sym_entry__symbol(syme);
36 struct perf_top *top = browser->priv;
37 int width = browser->width;
38 double pcnt;
39
40 pcnt = 100.0 - (100.0 * ((top_browser->sum_ksamples - syme->snap_count) /
41 top_browser->sum_ksamples));
42 ui_browser__set_percent_color(browser, pcnt, current_entry);
43
44 if (top->evlist->nr_entries == 1 || !top->display_weighted) {
45 slsmg_printf("%20.2f ", syme->weight);
46 width -= 24;
47 } else {
48 slsmg_printf("%9.1f %10ld ", syme->weight, syme->snap_count);
49 width -= 23;
50 }
51
52 slsmg_printf("%4.1f%%", pcnt);
53 width -= 7;
54
55 if (verbose) {
56 slsmg_printf(" %016" PRIx64, symbol->start);
57 width -= 17;
58 }
59
60 slsmg_printf(" %-*.*s ", top_browser->sym_width, top_browser->sym_width,
61 symbol->name);
62 width -= top_browser->sym_width;
63 slsmg_write_nstring(width >= syme->map->dso->long_name_len ?
64 syme->map->dso->long_name :
65 syme->map->dso->short_name, width);
66
67 if (current_entry)
68 top_browser->selection = syme;
69}
70
71static void perf_top_browser__update_rb_tree(struct perf_top_browser *browser)
72{
73 struct perf_top *top = browser->b.priv;
74 u64 top_idx = browser->b.top_idx;
75
76 browser->root = RB_ROOT;
77 browser->b.top = NULL;
78 browser->sum_ksamples = perf_top__decay_samples(top, &browser->root);
79 /*
80 * No active symbols
81 */
82 if (top->rb_entries == 0)
83 return;
84
85 perf_top__find_widths(top, &browser->root, &browser->dso_width,
86 &browser->dso_short_width,
87 &browser->sym_width);
88 if (browser->sym_width + browser->dso_width > browser->b.width - 29) {
89 browser->dso_width = browser->dso_short_width;
90 if (browser->sym_width + browser->dso_width > browser->b.width - 29)
91 browser->sym_width = browser->b.width - browser->dso_width - 29;
92 }
93
94 /*
95 * Adjust the ui_browser indexes since the entries in the browser->root
96 * rb_tree may have changed, then seek it from start, so that we get a
97 * possible new top of the screen.
98 */
99 browser->b.nr_entries = top->rb_entries;
100
101 if (top_idx >= browser->b.nr_entries) {
102 if (browser->b.height >= browser->b.nr_entries)
103 top_idx = browser->b.nr_entries - browser->b.height;
104 else
105 top_idx = 0;
106 }
107
108 if (browser->b.index >= top_idx + browser->b.height)
109 browser->b.index = top_idx + browser->b.index - browser->b.top_idx;
110
111 if (browser->b.index >= browser->b.nr_entries)
112 browser->b.index = browser->b.nr_entries - 1;
113
114 browser->b.top_idx = top_idx;
115 browser->b.seek(&browser->b, top_idx, SEEK_SET);
116}
117
118static void perf_top_browser__annotate(struct perf_top_browser *browser)
119{
120 struct sym_entry *syme = browser->selection;
121 struct symbol *sym = sym_entry__symbol(syme);
122 struct annotation *notes = symbol__annotation(sym);
123 struct perf_top *top = browser->b.priv;
124
125 if (notes->src != NULL)
126 goto do_annotation;
127
128 pthread_mutex_lock(&notes->lock);
129
130 top->sym_filter_entry = NULL;
131
132 if (symbol__alloc_hist(sym, top->evlist->nr_entries) < 0) {
133 pr_err("Not enough memory for annotating '%s' symbol!\n",
134 sym->name);
135 pthread_mutex_unlock(&notes->lock);
136 return;
137 }
138
139 top->sym_filter_entry = syme;
140
141 pthread_mutex_unlock(&notes->lock);
142do_annotation:
143 symbol__tui_annotate(sym, syme->map, 0, top->delay_secs * 1000);
144}
145
146static int perf_top_browser__run(struct perf_top_browser *browser)
147{
148 int key;
149 char title[160];
150 struct perf_top *top = browser->b.priv;
151 int delay_msecs = top->delay_secs * 1000;
152 int exit_keys[] = { 'a', NEWT_KEY_ENTER, NEWT_KEY_RIGHT, 0, };
153
154 perf_top_browser__update_rb_tree(browser);
155 perf_top__header_snprintf(top, title, sizeof(title));
156 perf_top__reset_sample_counters(top);
157
158 if (ui_browser__show(&browser->b, title,
159 "ESC: exit, ENTER|->|a: Live Annotate") < 0)
160 return -1;
161
162 newtFormSetTimer(browser->b.form, delay_msecs);
163 ui_browser__add_exit_keys(&browser->b, exit_keys);
164
165 while (1) {
166 key = ui_browser__run(&browser->b);
167
168 switch (key) {
169 case -1:
170 /* FIXME we need to check if it was es.reason == NEWT_EXIT_TIMER */
171 perf_top_browser__update_rb_tree(browser);
172 perf_top__header_snprintf(top, title, sizeof(title));
173 perf_top__reset_sample_counters(top);
174 ui_browser__set_color(&browser->b, NEWT_COLORSET_ROOT);
175 SLsmg_gotorc(0, 0);
176 slsmg_write_nstring(title, browser->b.width);
177 break;
178 case 'a':
179 case NEWT_KEY_RIGHT:
180 case NEWT_KEY_ENTER:
181 if (browser->selection)
182 perf_top_browser__annotate(browser);
183 break;
184 case NEWT_KEY_LEFT:
185 continue;
186 case NEWT_KEY_ESCAPE:
187 if (!ui__dialog_yesno("Do you really want to exit?"))
188 continue;
189 /* Fall thru */
190 default:
191 goto out;
192 }
193 }
194out:
195 ui_browser__hide(&browser->b);
196 return key;
197}
198
199int perf_top__tui_browser(struct perf_top *top)
200{
201 struct perf_top_browser browser = {
202 .b = {
203 .entries = &browser.root,
204 .refresh = ui_browser__rb_tree_refresh,
205 .seek = ui_browser__rb_tree_seek,
206 .write = perf_top_browser__write,
207 .priv = top,
208 },
209 };
210
211 ui_helpline__push("Press <- or ESC to exit");
212 return perf_top_browser__run(&browser);
213}
diff --git a/tools/perf/util/ui/helpline.c b/tools/perf/util/ui/helpline.c
index 8d79daa4458a..f36d2ff509ed 100644
--- a/tools/perf/util/ui/helpline.c
+++ b/tools/perf/util/ui/helpline.c
@@ -5,6 +5,7 @@
5 5
6#include "../debug.h" 6#include "../debug.h"
7#include "helpline.h" 7#include "helpline.h"
8#include "ui.h"
8 9
9void ui_helpline__pop(void) 10void ui_helpline__pop(void)
10{ 11{
@@ -55,7 +56,8 @@ int ui_helpline__show_help(const char *format, va_list ap)
55 int ret; 56 int ret;
56 static int backlog; 57 static int backlog;
57 58
58 ret = vsnprintf(ui_helpline__last_msg + backlog, 59 pthread_mutex_lock(&ui__lock);
60 ret = vsnprintf(ui_helpline__last_msg + backlog,
59 sizeof(ui_helpline__last_msg) - backlog, format, ap); 61 sizeof(ui_helpline__last_msg) - backlog, format, ap);
60 backlog += ret; 62 backlog += ret;
61 63
@@ -64,6 +66,7 @@ int ui_helpline__show_help(const char *format, va_list ap)
64 newtRefresh(); 66 newtRefresh();
65 backlog = 0; 67 backlog = 0;
66 } 68 }
69 pthread_mutex_unlock(&ui__lock);
67 70
68 return ret; 71 return ret;
69} 72}
diff --git a/tools/perf/util/ui/libslang.h b/tools/perf/util/ui/libslang.h
index 5623da8e8080..2b63e1c9b181 100644
--- a/tools/perf/util/ui/libslang.h
+++ b/tools/perf/util/ui/libslang.h
@@ -13,11 +13,11 @@
13 13
14#if SLANG_VERSION < 20104 14#if SLANG_VERSION < 20104
15#define slsmg_printf(msg, args...) \ 15#define slsmg_printf(msg, args...) \
16 SLsmg_printf((char *)msg, ##args) 16 SLsmg_printf((char *)(msg), ##args)
17#define slsmg_write_nstring(msg, len) \ 17#define slsmg_write_nstring(msg, len) \
18 SLsmg_write_nstring((char *)msg, len) 18 SLsmg_write_nstring((char *)(msg), len)
19#define sltt_set_color(obj, name, fg, bg) \ 19#define sltt_set_color(obj, name, fg, bg) \
20 SLtt_set_color(obj,(char *)name, (char *)fg, (char *)bg) 20 SLtt_set_color(obj,(char *)(name), (char *)(fg), (char *)(bg))
21#else 21#else
22#define slsmg_printf SLsmg_printf 22#define slsmg_printf SLsmg_printf
23#define slsmg_write_nstring SLsmg_write_nstring 23#define slsmg_write_nstring SLsmg_write_nstring
diff --git a/tools/perf/util/ui/setup.c b/tools/perf/util/ui/setup.c
index 662085032eb7..ee46d671db59 100644
--- a/tools/perf/util/ui/setup.c
+++ b/tools/perf/util/ui/setup.c
@@ -6,6 +6,9 @@
6#include "../debug.h" 6#include "../debug.h"
7#include "browser.h" 7#include "browser.h"
8#include "helpline.h" 8#include "helpline.h"
9#include "ui.h"
10
11pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER;
9 12
10static void newt_suspend(void *d __used) 13static void newt_suspend(void *d __used)
11{ 14{
@@ -14,11 +17,12 @@ static void newt_suspend(void *d __used)
14 newtResume(); 17 newtResume();
15} 18}
16 19
17void setup_browser(void) 20void setup_browser(bool fallback_to_pager)
18{ 21{
19 if (!isatty(1) || !use_browser || dump_trace) { 22 if (!isatty(1) || !use_browser || dump_trace) {
20 use_browser = 0; 23 use_browser = 0;
21 setup_pager(); 24 if (fallback_to_pager)
25 setup_pager();
22 return; 26 return;
23 } 27 }
24 28
diff --git a/tools/perf/util/ui/ui.h b/tools/perf/util/ui/ui.h
new file mode 100644
index 000000000000..d264e059c829
--- /dev/null
+++ b/tools/perf/util/ui/ui.h
@@ -0,0 +1,8 @@
1#ifndef _PERF_UI_H_
2#define _PERF_UI_H_ 1
3
4#include <pthread.h>
5
6extern pthread_mutex_t ui__lock;
7
8#endif /* _PERF_UI_H_ */
diff --git a/tools/perf/util/ui/util.c b/tools/perf/util/ui/util.c
index 04600e26ceea..fdf1fc8f08bc 100644
--- a/tools/perf/util/ui/util.c
+++ b/tools/perf/util/ui/util.c
@@ -9,10 +9,9 @@
9#include "../debug.h" 9#include "../debug.h"
10#include "browser.h" 10#include "browser.h"
11#include "helpline.h" 11#include "helpline.h"
12#include "ui.h"
12#include "util.h" 13#include "util.h"
13 14
14newtComponent newt_form__new(void);
15
16static void newt_form__set_exit_keys(newtComponent self) 15static void newt_form__set_exit_keys(newtComponent self)
17{ 16{
18 newtFormAddHotKey(self, NEWT_KEY_LEFT); 17 newtFormAddHotKey(self, NEWT_KEY_LEFT);
@@ -22,7 +21,7 @@ static void newt_form__set_exit_keys(newtComponent self)
22 newtFormAddHotKey(self, CTRL('c')); 21 newtFormAddHotKey(self, CTRL('c'));
23} 22}
24 23
25newtComponent newt_form__new(void) 24static newtComponent newt_form__new(void)
26{ 25{
27 newtComponent self = newtForm(NULL, NULL, 0); 26 newtComponent self = newtForm(NULL, NULL, 0);
28 if (self) 27 if (self)
@@ -106,9 +105,26 @@ out_destroy_form:
106 return rc; 105 return rc;
107} 106}
108 107
108static const char yes[] = "Yes", no[] = "No",
109 warning_str[] = "Warning!", ok[] = "Ok";
110
109bool ui__dialog_yesno(const char *msg) 111bool ui__dialog_yesno(const char *msg)
110{ 112{
111 /* newtWinChoice should really be accepting const char pointers... */ 113 /* newtWinChoice should really be accepting const char pointers... */
112 char yes[] = "Yes", no[] = "No"; 114 return newtWinChoice(NULL, (char *)yes, (char *)no, (char *)msg) == 1;
113 return newtWinChoice(NULL, yes, no, (char *)msg) == 1; 115}
116
117void ui__warning(const char *format, ...)
118{
119 va_list args;
120
121 va_start(args, format);
122 if (use_browser > 0) {
123 pthread_mutex_lock(&ui__lock);
124 newtWinMessagev((char *)warning_str, (char *)ok,
125 (char *)format, args);
126 pthread_mutex_unlock(&ui__lock);
127 } else
128 vfprintf(stderr, format, args);
129 va_end(args);
114} 130}
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 214265674ddd..5b3ea49aa63e 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -114,3 +114,20 @@ unsigned long convert_unit(unsigned long value, char *unit)
114 114
115 return value; 115 return value;
116} 116}
117
118int readn(int fd, void *buf, size_t n)
119{
120 void *buf_start = buf;
121
122 while (n) {
123 int ret = read(fd, buf, n);
124
125 if (ret <= 0)
126 return ret;
127
128 n -= ret;
129 buf += ret;
130 }
131
132 return buf - buf_start;
133}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index f380fed74359..fc784284ac8b 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -70,9 +70,7 @@
70#include <sys/poll.h> 70#include <sys/poll.h>
71#include <sys/socket.h> 71#include <sys/socket.h>
72#include <sys/ioctl.h> 72#include <sys/ioctl.h>
73#ifndef NO_SYS_SELECT_H
74#include <sys/select.h> 73#include <sys/select.h>
75#endif
76#include <netinet/in.h> 74#include <netinet/in.h>
77#include <netinet/tcp.h> 75#include <netinet/tcp.h>
78#include <arpa/inet.h> 76#include <arpa/inet.h>
@@ -83,10 +81,6 @@
83#include "types.h" 81#include "types.h"
84#include <sys/ttydefaults.h> 82#include <sys/ttydefaults.h>
85 83
86#ifndef NO_ICONV
87#include <iconv.h>
88#endif
89
90extern const char *graph_line; 84extern const char *graph_line;
91extern const char *graph_dotted_line; 85extern const char *graph_dotted_line;
92extern char buildid_dir[]; 86extern char buildid_dir[];
@@ -236,26 +230,6 @@ static inline int sane_case(int x, int high)
236 return x; 230 return x;
237} 231}
238 232
239#ifndef DIR_HAS_BSD_GROUP_SEMANTICS
240# define FORCE_DIR_SET_GID S_ISGID
241#else
242# define FORCE_DIR_SET_GID 0
243#endif
244
245#ifdef NO_NSEC
246#undef USE_NSEC
247#define ST_CTIME_NSEC(st) 0
248#define ST_MTIME_NSEC(st) 0
249#else
250#ifdef USE_ST_TIMESPEC
251#define ST_CTIME_NSEC(st) ((unsigned int)((st).st_ctimespec.tv_nsec))
252#define ST_MTIME_NSEC(st) ((unsigned int)((st).st_mtimespec.tv_nsec))
253#else
254#define ST_CTIME_NSEC(st) ((unsigned int)((st).st_ctim.tv_nsec))
255#define ST_MTIME_NSEC(st) ((unsigned int)((st).st_mtim.tv_nsec))
256#endif
257#endif
258
259int mkdir_p(char *path, mode_t mode); 233int mkdir_p(char *path, mode_t mode);
260int copyfile(const char *from, const char *to); 234int copyfile(const char *from, const char *to);
261 235
@@ -265,19 +239,7 @@ void argv_free(char **argv);
265bool strglobmatch(const char *str, const char *pat); 239bool strglobmatch(const char *str, const char *pat);
266bool strlazymatch(const char *str, const char *pat); 240bool strlazymatch(const char *str, const char *pat);
267unsigned long convert_unit(unsigned long value, char *unit); 241unsigned long convert_unit(unsigned long value, char *unit);
268 242int readn(int fd, void *buf, size_t size);
269#ifndef ESC
270#define ESC 27
271#endif
272
273static inline bool is_exit_key(int key)
274{
275 char up;
276 if (key == CTRL('c') || key == ESC)
277 return true;
278 up = toupper(key);
279 return up == 'Q';
280}
281 243
282#define _STR(x) #x 244#define _STR(x) #x
283#define STR(x) _STR(x) 245#define STR(x) _STR(x)
diff --git a/tools/perf/util/values.c b/tools/perf/util/values.c
index cfa55d686e3b..bdd33470b235 100644
--- a/tools/perf/util/values.c
+++ b/tools/perf/util/values.c
@@ -150,7 +150,7 @@ static void perf_read_values__display_pretty(FILE *fp,
150 if (width > tidwidth) 150 if (width > tidwidth)
151 tidwidth = width; 151 tidwidth = width;
152 for (j = 0; j < values->counters; j++) { 152 for (j = 0; j < values->counters; j++) {
153 width = snprintf(NULL, 0, "%Lu", values->value[i][j]); 153 width = snprintf(NULL, 0, "%" PRIu64, values->value[i][j]);
154 if (width > counterwidth[j]) 154 if (width > counterwidth[j])
155 counterwidth[j] = width; 155 counterwidth[j] = width;
156 } 156 }
@@ -165,7 +165,7 @@ static void perf_read_values__display_pretty(FILE *fp,
165 fprintf(fp, " %*d %*d", pidwidth, values->pid[i], 165 fprintf(fp, " %*d %*d", pidwidth, values->pid[i],
166 tidwidth, values->tid[i]); 166 tidwidth, values->tid[i]);
167 for (j = 0; j < values->counters; j++) 167 for (j = 0; j < values->counters; j++)
168 fprintf(fp, " %*Lu", 168 fprintf(fp, " %*" PRIu64,
169 counterwidth[j], values->value[i][j]); 169 counterwidth[j], values->value[i][j]);
170 fprintf(fp, "\n"); 170 fprintf(fp, "\n");
171 } 171 }
@@ -196,13 +196,13 @@ static void perf_read_values__display_raw(FILE *fp,
196 width = strlen(values->countername[j]); 196 width = strlen(values->countername[j]);
197 if (width > namewidth) 197 if (width > namewidth)
198 namewidth = width; 198 namewidth = width;
199 width = snprintf(NULL, 0, "%llx", values->counterrawid[j]); 199 width = snprintf(NULL, 0, "%" PRIx64, values->counterrawid[j]);
200 if (width > rawwidth) 200 if (width > rawwidth)
201 rawwidth = width; 201 rawwidth = width;
202 } 202 }
203 for (i = 0; i < values->threads; i++) { 203 for (i = 0; i < values->threads; i++) {
204 for (j = 0; j < values->counters; j++) { 204 for (j = 0; j < values->counters; j++) {
205 width = snprintf(NULL, 0, "%Lu", values->value[i][j]); 205 width = snprintf(NULL, 0, "%" PRIu64, values->value[i][j]);
206 if (width > countwidth) 206 if (width > countwidth)
207 countwidth = width; 207 countwidth = width;
208 } 208 }
@@ -214,7 +214,7 @@ static void perf_read_values__display_raw(FILE *fp,
214 countwidth, "Count"); 214 countwidth, "Count");
215 for (i = 0; i < values->threads; i++) 215 for (i = 0; i < values->threads; i++)
216 for (j = 0; j < values->counters; j++) 216 for (j = 0; j < values->counters; j++)
217 fprintf(fp, " %*d %*d %*s %*llx %*Lu\n", 217 fprintf(fp, " %*d %*d %*s %*" PRIx64 " %*" PRIu64,
218 pidwidth, values->pid[i], 218 pidwidth, values->pid[i],
219 tidwidth, values->tid[i], 219 tidwidth, values->tid[i],
220 namewidth, values->countername[j], 220 namewidth, values->countername[j],
diff --git a/tools/perf/util/xyarray.c b/tools/perf/util/xyarray.c
new file mode 100644
index 000000000000..22afbf6c536a
--- /dev/null
+++ b/tools/perf/util/xyarray.c
@@ -0,0 +1,20 @@
1#include "xyarray.h"
2#include "util.h"
3
4struct xyarray *xyarray__new(int xlen, int ylen, size_t entry_size)
5{
6 size_t row_size = ylen * entry_size;
7 struct xyarray *xy = zalloc(sizeof(*xy) + xlen * row_size);
8
9 if (xy != NULL) {
10 xy->entry_size = entry_size;
11 xy->row_size = row_size;
12 }
13
14 return xy;
15}
16
17void xyarray__delete(struct xyarray *xy)
18{
19 free(xy);
20}
diff --git a/tools/perf/util/xyarray.h b/tools/perf/util/xyarray.h
new file mode 100644
index 000000000000..c488a07275dd
--- /dev/null
+++ b/tools/perf/util/xyarray.h
@@ -0,0 +1,20 @@
1#ifndef _PERF_XYARRAY_H_
2#define _PERF_XYARRAY_H_ 1
3
4#include <sys/types.h>
5
6struct xyarray {
7 size_t row_size;
8 size_t entry_size;
9 char contents[];
10};
11
12struct xyarray *xyarray__new(int xlen, int ylen, size_t entry_size);
13void xyarray__delete(struct xyarray *xy);
14
15static inline void *xyarray__entry(struct xyarray *xy, int x, int y)
16{
17 return &xy->contents[x * xy->row_size + y * xy->entry_size];
18}
19
20#endif /* _PERF_XYARRAY_H_ */
diff --git a/tools/power/x86/turbostat/Makefile b/tools/power/x86/turbostat/Makefile
new file mode 100644
index 000000000000..fd8e1f1297aa
--- /dev/null
+++ b/tools/power/x86/turbostat/Makefile
@@ -0,0 +1,8 @@
1turbostat : turbostat.c
2
3clean :
4 rm -f turbostat
5
6install :
7 install turbostat /usr/bin/turbostat
8 install turbostat.8 /usr/share/man/man8
diff --git a/tools/power/x86/turbostat/turbostat.8 b/tools/power/x86/turbostat/turbostat.8
new file mode 100644
index 000000000000..ff75125deed0
--- /dev/null
+++ b/tools/power/x86/turbostat/turbostat.8
@@ -0,0 +1,172 @@
1.TH TURBOSTAT 8
2.SH NAME
3turbostat \- Report processor frequency and idle statistics
4.SH SYNOPSIS
5.ft B
6.B turbostat
7.RB [ "\-v" ]
8.RB [ "\-M MSR#" ]
9.RB command
10.br
11.B turbostat
12.RB [ "\-v" ]
13.RB [ "\-M MSR#" ]
14.RB [ "\-i interval_sec" ]
15.SH DESCRIPTION
16\fBturbostat \fP reports processor topology, frequency
17and idle power state statistics on modern X86 processors.
18Either \fBcommand\fP is forked and statistics are printed
19upon its completion, or statistics are printed periodically.
20
21\fBturbostat \fP
22requires that the processor
23supports an "invariant" TSC, plus the APERF and MPERF MSRs.
24\fBturbostat \fP will report idle cpu power state residency
25on processors that additionally support C-state residency counters.
26
27.SS Options
28The \fB-v\fP option increases verbosity.
29.PP
30The \fB-M MSR#\fP option dumps the specified MSR,
31in addition to the usual frequency and idle statistics.
32.PP
33The \fB-i interval_sec\fP option prints statistics every \fiinterval_sec\fP seconds.
34The default is 5 seconds.
35.PP
36The \fBcommand\fP parameter forks \fBcommand\fP and upon its exit,
37displays the statistics gathered since it was forked.
38.PP
39.SH FIELD DESCRIPTIONS
40.nf
41\fBpkg\fP processor package number.
42\fBcore\fP processor core number.
43\fBCPU\fP Linux CPU (logical processor) number.
44\fB%c0\fP percent of the interval that the CPU retired instructions.
45\fBGHz\fP average clock rate while the CPU was in c0 state.
46\fBTSC\fP average GHz that the TSC ran during the entire interval.
47\fB%c1, %c3, %c6\fP show the percentage residency in hardware core idle states.
48\fB%pc3, %pc6\fP percentage residency in hardware package idle states.
49.fi
50.PP
51.SH EXAMPLE
52Without any parameters, turbostat prints out counters ever 5 seconds.
53(override interval with "-i sec" option, or specify a command
54for turbostat to fork).
55
56The first row of statistics reflect the average for the entire system.
57Subsequent rows show per-CPU statistics.
58
59.nf
60[root@x980]# ./turbostat
61core CPU %c0 GHz TSC %c1 %c3 %c6 %pc3 %pc6
62 0.04 1.62 3.38 0.11 0.00 99.85 0.00 95.07
63 0 0 0.04 1.62 3.38 0.06 0.00 99.90 0.00 95.07
64 0 6 0.02 1.62 3.38 0.08 0.00 99.90 0.00 95.07
65 1 2 0.10 1.62 3.38 0.29 0.00 99.61 0.00 95.07
66 1 8 0.11 1.62 3.38 0.28 0.00 99.61 0.00 95.07
67 2 4 0.01 1.62 3.38 0.01 0.00 99.98 0.00 95.07
68 2 10 0.01 1.61 3.38 0.02 0.00 99.98 0.00 95.07
69 8 1 0.07 1.62 3.38 0.15 0.00 99.78 0.00 95.07
70 8 7 0.03 1.62 3.38 0.19 0.00 99.78 0.00 95.07
71 9 3 0.01 1.62 3.38 0.02 0.00 99.98 0.00 95.07
72 9 9 0.01 1.62 3.38 0.02 0.00 99.98 0.00 95.07
73 10 5 0.01 1.62 3.38 0.13 0.00 99.86 0.00 95.07
74 10 11 0.08 1.62 3.38 0.05 0.00 99.86 0.00 95.07
75.fi
76.SH VERBOSE EXAMPLE
77The "-v" option adds verbosity to the output:
78
79.nf
80GenuineIntel 11 CPUID levels; family:model:stepping 0x6:2c:2 (6:44:2)
8112 * 133 = 1600 MHz max efficiency
8225 * 133 = 3333 MHz TSC frequency
8326 * 133 = 3467 MHz max turbo 4 active cores
8426 * 133 = 3467 MHz max turbo 3 active cores
8527 * 133 = 3600 MHz max turbo 2 active cores
8627 * 133 = 3600 MHz max turbo 1 active cores
87
88.fi
89The \fBmax efficiency\fP frequency, a.k.a. Low Frequency Mode, is the frequency
90available at the minimum package voltage. The \fBTSC frequency\fP is the nominal
91maximum frequency of the processor if turbo-mode were not available. This frequency
92should be sustainable on all CPUs indefinitely, given nominal power and cooling.
93The remaining rows show what maximum turbo frequency is possible
94depending on the number of idle cores. Note that this information is
95not available on all processors.
96.SH FORK EXAMPLE
97If turbostat is invoked with a command, it will fork that command
98and output the statistics gathered when the command exits.
99eg. Here a cycle soaker is run on 1 CPU (see %c0) for a few seconds
100until ^C while the other CPUs are mostly idle:
101
102.nf
103[root@x980 lenb]# ./turbostat cat /dev/zero > /dev/null
104
105^Ccore CPU %c0 GHz TSC %c1 %c3 %c6 %pc3 %pc6
106 8.49 3.63 3.38 16.23 0.66 74.63 0.00 0.00
107 0 0 1.22 3.62 3.38 32.18 0.00 66.60 0.00 0.00
108 0 6 0.40 3.61 3.38 33.00 0.00 66.60 0.00 0.00
109 1 2 0.11 3.14 3.38 0.19 3.95 95.75 0.00 0.00
110 1 8 0.05 2.88 3.38 0.25 3.95 95.75 0.00 0.00
111 2 4 0.00 3.13 3.38 0.02 0.00 99.98 0.00 0.00
112 2 10 0.00 3.09 3.38 0.02 0.00 99.98 0.00 0.00
113 8 1 0.04 3.50 3.38 14.43 0.00 85.54 0.00 0.00
114 8 7 0.03 2.98 3.38 14.43 0.00 85.54 0.00 0.00
115 9 3 0.00 3.16 3.38 100.00 0.00 0.00 0.00 0.00
116 9 9 99.93 3.63 3.38 0.06 0.00 0.00 0.00 0.00
117 10 5 0.01 2.82 3.38 0.08 0.00 99.91 0.00 0.00
118 10 11 0.02 3.36 3.38 0.06 0.00 99.91 0.00 0.00
1196.950866 sec
120
121.fi
122Above the cycle soaker drives cpu9 up 3.6 Ghz turbo limit
123while the other processors are generally in various states of idle.
124
125Note that cpu3 is an HT sibling sharing core9
126with cpu9, and thus it is unable to get to an idle state
127deeper than c1 while cpu9 is busy.
128
129Note that turbostat reports average GHz of 3.61, while
130the arithmetic average of the GHz column above is 3.24.
131This is a weighted average, where the weight is %c0. ie. it is the total number of
132un-halted cycles elapsed per time divided by the number of CPUs.
133.SH NOTES
134
135.B "turbostat "
136must be run as root.
137
138.B "turbostat "
139reads hardware counters, but doesn't write them.
140So it will not interfere with the OS or other programs, including
141multiple invocations of itself.
142
143\fBturbostat \fP
144may work poorly on Linux-2.6.20 through 2.6.29,
145as \fBacpi-cpufreq \fPperiodically cleared the APERF and MPERF
146in those kernels.
147
148The APERF, MPERF MSRs are defined to count non-halted cycles.
149Although it is not guaranteed by the architecture, turbostat assumes
150that they count at TSC rate, which is true on all processors tested to date.
151
152.SH REFERENCES
153"Intel® Turbo Boost Technology
154in Intel® Core™ Microarchitecture (Nehalem) Based Processors"
155http://download.intel.com/design/processor/applnots/320354.pdf
156
157"Intel® 64 and IA-32 Architectures Software Developer's Manual
158Volume 3B: System Programming Guide"
159http://www.intel.com/products/processor/manuals/
160
161.SH FILES
162.ta
163.nf
164/dev/cpu/*/msr
165.fi
166
167.SH "SEE ALSO"
168msr(4), vmstat(8)
169.PP
170.SH AUTHORS
171.nf
172Written by Len Brown <len.brown@intel.com>
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
new file mode 100644
index 000000000000..6d8ef4a3a9b5
--- /dev/null
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -0,0 +1,1044 @@
1/*
2 * turbostat -- show CPU frequency and C-state residency
3 * on modern Intel turbo-capable processors.
4 *
5 * Copyright (c) 2010, Intel Corporation.
6 * Len Brown <len.brown@intel.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21
22#include <stdio.h>
23#include <unistd.h>
24#include <sys/types.h>
25#include <sys/wait.h>
26#include <sys/stat.h>
27#include <sys/resource.h>
28#include <fcntl.h>
29#include <signal.h>
30#include <sys/time.h>
31#include <stdlib.h>
32#include <dirent.h>
33#include <string.h>
34#include <ctype.h>
35
36#define MSR_TSC 0x10
37#define MSR_NEHALEM_PLATFORM_INFO 0xCE
38#define MSR_NEHALEM_TURBO_RATIO_LIMIT 0x1AD
39#define MSR_APERF 0xE8
40#define MSR_MPERF 0xE7
41#define MSR_PKG_C2_RESIDENCY 0x60D /* SNB only */
42#define MSR_PKG_C3_RESIDENCY 0x3F8
43#define MSR_PKG_C6_RESIDENCY 0x3F9
44#define MSR_PKG_C7_RESIDENCY 0x3FA /* SNB only */
45#define MSR_CORE_C3_RESIDENCY 0x3FC
46#define MSR_CORE_C6_RESIDENCY 0x3FD
47#define MSR_CORE_C7_RESIDENCY 0x3FE /* SNB only */
48
49char *proc_stat = "/proc/stat";
50unsigned int interval_sec = 5; /* set with -i interval_sec */
51unsigned int verbose; /* set with -v */
52unsigned int skip_c0;
53unsigned int skip_c1;
54unsigned int do_nhm_cstates;
55unsigned int do_snb_cstates;
56unsigned int has_aperf;
57unsigned int units = 1000000000; /* Ghz etc */
58unsigned int genuine_intel;
59unsigned int has_invariant_tsc;
60unsigned int do_nehalem_platform_info;
61unsigned int do_nehalem_turbo_ratio_limit;
62unsigned int extra_msr_offset;
63double bclk;
64unsigned int show_pkg;
65unsigned int show_core;
66unsigned int show_cpu;
67
68int aperf_mperf_unstable;
69int backwards_count;
70char *progname;
71int need_reinitialize;
72
73int num_cpus;
74
75struct counters {
76 unsigned long long tsc; /* per thread */
77 unsigned long long aperf; /* per thread */
78 unsigned long long mperf; /* per thread */
79 unsigned long long c1; /* per thread (calculated) */
80 unsigned long long c3; /* per core */
81 unsigned long long c6; /* per core */
82 unsigned long long c7; /* per core */
83 unsigned long long pc2; /* per package */
84 unsigned long long pc3; /* per package */
85 unsigned long long pc6; /* per package */
86 unsigned long long pc7; /* per package */
87 unsigned long long extra_msr; /* per thread */
88 int pkg;
89 int core;
90 int cpu;
91 struct counters *next;
92};
93
94struct counters *cnt_even;
95struct counters *cnt_odd;
96struct counters *cnt_delta;
97struct counters *cnt_average;
98struct timeval tv_even;
99struct timeval tv_odd;
100struct timeval tv_delta;
101
102unsigned long long get_msr(int cpu, off_t offset)
103{
104 ssize_t retval;
105 unsigned long long msr;
106 char pathname[32];
107 int fd;
108
109 sprintf(pathname, "/dev/cpu/%d/msr", cpu);
110 fd = open(pathname, O_RDONLY);
111 if (fd < 0) {
112 perror(pathname);
113 need_reinitialize = 1;
114 return 0;
115 }
116
117 retval = pread(fd, &msr, sizeof msr, offset);
118 if (retval != sizeof msr) {
119 fprintf(stderr, "cpu%d pread(..., 0x%zx) = %jd\n",
120 cpu, offset, retval);
121 exit(-2);
122 }
123
124 close(fd);
125 return msr;
126}
127
128void print_header(void)
129{
130 if (show_pkg)
131 fprintf(stderr, "pkg ");
132 if (show_core)
133 fprintf(stderr, "core");
134 if (show_cpu)
135 fprintf(stderr, " CPU");
136 if (do_nhm_cstates)
137 fprintf(stderr, " %%c0 ");
138 if (has_aperf)
139 fprintf(stderr, " GHz");
140 fprintf(stderr, " TSC");
141 if (do_nhm_cstates)
142 fprintf(stderr, " %%c1 ");
143 if (do_nhm_cstates)
144 fprintf(stderr, " %%c3 ");
145 if (do_nhm_cstates)
146 fprintf(stderr, " %%c6 ");
147 if (do_snb_cstates)
148 fprintf(stderr, " %%c7 ");
149 if (do_snb_cstates)
150 fprintf(stderr, " %%pc2 ");
151 if (do_nhm_cstates)
152 fprintf(stderr, " %%pc3 ");
153 if (do_nhm_cstates)
154 fprintf(stderr, " %%pc6 ");
155 if (do_snb_cstates)
156 fprintf(stderr, " %%pc7 ");
157 if (extra_msr_offset)
158 fprintf(stderr, " MSR 0x%x ", extra_msr_offset);
159
160 putc('\n', stderr);
161}
162
163void dump_cnt(struct counters *cnt)
164{
165 fprintf(stderr, "package: %d ", cnt->pkg);
166 fprintf(stderr, "core:: %d ", cnt->core);
167 fprintf(stderr, "CPU: %d ", cnt->cpu);
168 fprintf(stderr, "TSC: %016llX\n", cnt->tsc);
169 fprintf(stderr, "c3: %016llX\n", cnt->c3);
170 fprintf(stderr, "c6: %016llX\n", cnt->c6);
171 fprintf(stderr, "c7: %016llX\n", cnt->c7);
172 fprintf(stderr, "aperf: %016llX\n", cnt->aperf);
173 fprintf(stderr, "pc2: %016llX\n", cnt->pc2);
174 fprintf(stderr, "pc3: %016llX\n", cnt->pc3);
175 fprintf(stderr, "pc6: %016llX\n", cnt->pc6);
176 fprintf(stderr, "pc7: %016llX\n", cnt->pc7);
177 fprintf(stderr, "msr0x%x: %016llX\n", extra_msr_offset, cnt->extra_msr);
178}
179
180void dump_list(struct counters *cnt)
181{
182 printf("dump_list 0x%p\n", cnt);
183
184 for (; cnt; cnt = cnt->next)
185 dump_cnt(cnt);
186}
187
188void print_cnt(struct counters *p)
189{
190 double interval_float;
191
192 interval_float = tv_delta.tv_sec + tv_delta.tv_usec/1000000.0;
193
194 /* topology columns, print blanks on 1st (average) line */
195 if (p == cnt_average) {
196 if (show_pkg)
197 fprintf(stderr, " ");
198 if (show_core)
199 fprintf(stderr, " ");
200 if (show_cpu)
201 fprintf(stderr, " ");
202 } else {
203 if (show_pkg)
204 fprintf(stderr, "%4d", p->pkg);
205 if (show_core)
206 fprintf(stderr, "%4d", p->core);
207 if (show_cpu)
208 fprintf(stderr, "%4d", p->cpu);
209 }
210
211 /* %c0 */
212 if (do_nhm_cstates) {
213 if (!skip_c0)
214 fprintf(stderr, "%7.2f", 100.0 * p->mperf/p->tsc);
215 else
216 fprintf(stderr, " ****");
217 }
218
219 /* GHz */
220 if (has_aperf) {
221 if (!aperf_mperf_unstable) {
222 fprintf(stderr, "%5.2f",
223 1.0 * p->tsc / units * p->aperf /
224 p->mperf / interval_float);
225 } else {
226 if (p->aperf > p->tsc || p->mperf > p->tsc) {
227 fprintf(stderr, " ****");
228 } else {
229 fprintf(stderr, "%4.1f*",
230 1.0 * p->tsc /
231 units * p->aperf /
232 p->mperf / interval_float);
233 }
234 }
235 }
236
237 /* TSC */
238 fprintf(stderr, "%5.2f", 1.0 * p->tsc/units/interval_float);
239
240 if (do_nhm_cstates) {
241 if (!skip_c1)
242 fprintf(stderr, "%7.2f", 100.0 * p->c1/p->tsc);
243 else
244 fprintf(stderr, " ****");
245 }
246 if (do_nhm_cstates)
247 fprintf(stderr, "%7.2f", 100.0 * p->c3/p->tsc);
248 if (do_nhm_cstates)
249 fprintf(stderr, "%7.2f", 100.0 * p->c6/p->tsc);
250 if (do_snb_cstates)
251 fprintf(stderr, "%7.2f", 100.0 * p->c7/p->tsc);
252 if (do_snb_cstates)
253 fprintf(stderr, "%7.2f", 100.0 * p->pc2/p->tsc);
254 if (do_nhm_cstates)
255 fprintf(stderr, "%7.2f", 100.0 * p->pc3/p->tsc);
256 if (do_nhm_cstates)
257 fprintf(stderr, "%7.2f", 100.0 * p->pc6/p->tsc);
258 if (do_snb_cstates)
259 fprintf(stderr, "%7.2f", 100.0 * p->pc7/p->tsc);
260 if (extra_msr_offset)
261 fprintf(stderr, " 0x%016llx", p->extra_msr);
262 putc('\n', stderr);
263}
264
265void print_counters(struct counters *counters)
266{
267 struct counters *cnt;
268
269 print_header();
270
271 if (num_cpus > 1)
272 print_cnt(cnt_average);
273
274 for (cnt = counters; cnt != NULL; cnt = cnt->next)
275 print_cnt(cnt);
276
277}
278
279#define SUBTRACT_COUNTER(after, before, delta) (delta = (after - before), (before > after))
280
281int compute_delta(struct counters *after,
282 struct counters *before, struct counters *delta)
283{
284 int errors = 0;
285 int perf_err = 0;
286
287 skip_c0 = skip_c1 = 0;
288
289 for ( ; after && before && delta;
290 after = after->next, before = before->next, delta = delta->next) {
291 if (before->cpu != after->cpu) {
292 printf("cpu configuration changed: %d != %d\n",
293 before->cpu, after->cpu);
294 return -1;
295 }
296
297 if (SUBTRACT_COUNTER(after->tsc, before->tsc, delta->tsc)) {
298 fprintf(stderr, "cpu%d TSC went backwards %llX to %llX\n",
299 before->cpu, before->tsc, after->tsc);
300 errors++;
301 }
302 /* check for TSC < 1 Mcycles over interval */
303 if (delta->tsc < (1000 * 1000)) {
304 fprintf(stderr, "Insanely slow TSC rate,"
305 " TSC stops in idle?\n");
306 fprintf(stderr, "You can disable all c-states"
307 " by booting with \"idle=poll\"\n");
308 fprintf(stderr, "or just the deep ones with"
309 " \"processor.max_cstate=1\"\n");
310 exit(-3);
311 }
312 if (SUBTRACT_COUNTER(after->c3, before->c3, delta->c3)) {
313 fprintf(stderr, "cpu%d c3 counter went backwards %llX to %llX\n",
314 before->cpu, before->c3, after->c3);
315 errors++;
316 }
317 if (SUBTRACT_COUNTER(after->c6, before->c6, delta->c6)) {
318 fprintf(stderr, "cpu%d c6 counter went backwards %llX to %llX\n",
319 before->cpu, before->c6, after->c6);
320 errors++;
321 }
322 if (SUBTRACT_COUNTER(after->c7, before->c7, delta->c7)) {
323 fprintf(stderr, "cpu%d c7 counter went backwards %llX to %llX\n",
324 before->cpu, before->c7, after->c7);
325 errors++;
326 }
327 if (SUBTRACT_COUNTER(after->pc2, before->pc2, delta->pc2)) {
328 fprintf(stderr, "cpu%d pc2 counter went backwards %llX to %llX\n",
329 before->cpu, before->pc2, after->pc2);
330 errors++;
331 }
332 if (SUBTRACT_COUNTER(after->pc3, before->pc3, delta->pc3)) {
333 fprintf(stderr, "cpu%d pc3 counter went backwards %llX to %llX\n",
334 before->cpu, before->pc3, after->pc3);
335 errors++;
336 }
337 if (SUBTRACT_COUNTER(after->pc6, before->pc6, delta->pc6)) {
338 fprintf(stderr, "cpu%d pc6 counter went backwards %llX to %llX\n",
339 before->cpu, before->pc6, after->pc6);
340 errors++;
341 }
342 if (SUBTRACT_COUNTER(after->pc7, before->pc7, delta->pc7)) {
343 fprintf(stderr, "cpu%d pc7 counter went backwards %llX to %llX\n",
344 before->cpu, before->pc7, after->pc7);
345 errors++;
346 }
347
348 perf_err = SUBTRACT_COUNTER(after->aperf, before->aperf, delta->aperf);
349 if (perf_err) {
350 fprintf(stderr, "cpu%d aperf counter went backwards %llX to %llX\n",
351 before->cpu, before->aperf, after->aperf);
352 }
353 perf_err |= SUBTRACT_COUNTER(after->mperf, before->mperf, delta->mperf);
354 if (perf_err) {
355 fprintf(stderr, "cpu%d mperf counter went backwards %llX to %llX\n",
356 before->cpu, before->mperf, after->mperf);
357 }
358 if (perf_err) {
359 if (!aperf_mperf_unstable) {
360 fprintf(stderr, "%s: APERF or MPERF went backwards *\n", progname);
361 fprintf(stderr, "* Frequency results do not cover entire interval *\n");
362 fprintf(stderr, "* fix this by running Linux-2.6.30 or later *\n");
363
364 aperf_mperf_unstable = 1;
365 }
366 /*
367 * mperf delta is likely a huge "positive" number
368 * can not use it for calculating c0 time
369 */
370 skip_c0 = 1;
371 skip_c1 = 1;
372 }
373
374 /*
375 * As mperf and tsc collection are not atomic,
376 * it is possible for mperf's non-halted cycles
377 * to exceed TSC's all cycles: show c1 = 0% in that case.
378 */
379 if (delta->mperf > delta->tsc)
380 delta->c1 = 0;
381 else /* normal case, derive c1 */
382 delta->c1 = delta->tsc - delta->mperf
383 - delta->c3 - delta->c6 - delta->c7;
384
385 if (delta->mperf == 0)
386 delta->mperf = 1; /* divide by 0 protection */
387
388 /*
389 * for "extra msr", just copy the latest w/o subtracting
390 */
391 delta->extra_msr = after->extra_msr;
392 if (errors) {
393 fprintf(stderr, "ERROR cpu%d before:\n", before->cpu);
394 dump_cnt(before);
395 fprintf(stderr, "ERROR cpu%d after:\n", before->cpu);
396 dump_cnt(after);
397 errors = 0;
398 }
399 }
400 return 0;
401}
402
403void compute_average(struct counters *delta, struct counters *avg)
404{
405 struct counters *sum;
406
407 sum = calloc(1, sizeof(struct counters));
408 if (sum == NULL) {
409 perror("calloc sum");
410 exit(1);
411 }
412
413 for (; delta; delta = delta->next) {
414 sum->tsc += delta->tsc;
415 sum->c1 += delta->c1;
416 sum->c3 += delta->c3;
417 sum->c6 += delta->c6;
418 sum->c7 += delta->c7;
419 sum->aperf += delta->aperf;
420 sum->mperf += delta->mperf;
421 sum->pc2 += delta->pc2;
422 sum->pc3 += delta->pc3;
423 sum->pc6 += delta->pc6;
424 sum->pc7 += delta->pc7;
425 }
426 avg->tsc = sum->tsc/num_cpus;
427 avg->c1 = sum->c1/num_cpus;
428 avg->c3 = sum->c3/num_cpus;
429 avg->c6 = sum->c6/num_cpus;
430 avg->c7 = sum->c7/num_cpus;
431 avg->aperf = sum->aperf/num_cpus;
432 avg->mperf = sum->mperf/num_cpus;
433 avg->pc2 = sum->pc2/num_cpus;
434 avg->pc3 = sum->pc3/num_cpus;
435 avg->pc6 = sum->pc6/num_cpus;
436 avg->pc7 = sum->pc7/num_cpus;
437
438 free(sum);
439}
440
441void get_counters(struct counters *cnt)
442{
443 for ( ; cnt; cnt = cnt->next) {
444 cnt->tsc = get_msr(cnt->cpu, MSR_TSC);
445 if (do_nhm_cstates)
446 cnt->c3 = get_msr(cnt->cpu, MSR_CORE_C3_RESIDENCY);
447 if (do_nhm_cstates)
448 cnt->c6 = get_msr(cnt->cpu, MSR_CORE_C6_RESIDENCY);
449 if (do_snb_cstates)
450 cnt->c7 = get_msr(cnt->cpu, MSR_CORE_C7_RESIDENCY);
451 if (has_aperf)
452 cnt->aperf = get_msr(cnt->cpu, MSR_APERF);
453 if (has_aperf)
454 cnt->mperf = get_msr(cnt->cpu, MSR_MPERF);
455 if (do_snb_cstates)
456 cnt->pc2 = get_msr(cnt->cpu, MSR_PKG_C2_RESIDENCY);
457 if (do_nhm_cstates)
458 cnt->pc3 = get_msr(cnt->cpu, MSR_PKG_C3_RESIDENCY);
459 if (do_nhm_cstates)
460 cnt->pc6 = get_msr(cnt->cpu, MSR_PKG_C6_RESIDENCY);
461 if (do_snb_cstates)
462 cnt->pc7 = get_msr(cnt->cpu, MSR_PKG_C7_RESIDENCY);
463 if (extra_msr_offset)
464 cnt->extra_msr = get_msr(cnt->cpu, extra_msr_offset);
465 }
466}
467
468void print_nehalem_info(void)
469{
470 unsigned long long msr;
471 unsigned int ratio;
472
473 if (!do_nehalem_platform_info)
474 return;
475
476 msr = get_msr(0, MSR_NEHALEM_PLATFORM_INFO);
477
478 ratio = (msr >> 40) & 0xFF;
479 fprintf(stderr, "%d * %.0f = %.0f MHz max efficiency\n",
480 ratio, bclk, ratio * bclk);
481
482 ratio = (msr >> 8) & 0xFF;
483 fprintf(stderr, "%d * %.0f = %.0f MHz TSC frequency\n",
484 ratio, bclk, ratio * bclk);
485
486 if (verbose > 1)
487 fprintf(stderr, "MSR_NEHALEM_PLATFORM_INFO: 0x%llx\n", msr);
488
489 if (!do_nehalem_turbo_ratio_limit)
490 return;
491
492 msr = get_msr(0, MSR_NEHALEM_TURBO_RATIO_LIMIT);
493
494 ratio = (msr >> 24) & 0xFF;
495 if (ratio)
496 fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 4 active cores\n",
497 ratio, bclk, ratio * bclk);
498
499 ratio = (msr >> 16) & 0xFF;
500 if (ratio)
501 fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 3 active cores\n",
502 ratio, bclk, ratio * bclk);
503
504 ratio = (msr >> 8) & 0xFF;
505 if (ratio)
506 fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 2 active cores\n",
507 ratio, bclk, ratio * bclk);
508
509 ratio = (msr >> 0) & 0xFF;
510 if (ratio)
511 fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 1 active cores\n",
512 ratio, bclk, ratio * bclk);
513
514}
515
516void free_counter_list(struct counters *list)
517{
518 struct counters *p;
519
520 for (p = list; p; ) {
521 struct counters *free_me;
522
523 free_me = p;
524 p = p->next;
525 free(free_me);
526 }
527}
528
529void free_all_counters(void)
530{
531 free_counter_list(cnt_even);
532 cnt_even = NULL;
533
534 free_counter_list(cnt_odd);
535 cnt_odd = NULL;
536
537 free_counter_list(cnt_delta);
538 cnt_delta = NULL;
539
540 free_counter_list(cnt_average);
541 cnt_average = NULL;
542}
543
544void insert_counters(struct counters **list,
545 struct counters *new)
546{
547 struct counters *prev;
548
549 /*
550 * list was empty
551 */
552 if (*list == NULL) {
553 new->next = *list;
554 *list = new;
555 return;
556 }
557
558 show_cpu = 1; /* there is more than one CPU */
559
560 /*
561 * insert on front of list.
562 * It is sorted by ascending package#, core#, cpu#
563 */
564 if (((*list)->pkg > new->pkg) ||
565 (((*list)->pkg == new->pkg) && ((*list)->core > new->core)) ||
566 (((*list)->pkg == new->pkg) && ((*list)->core == new->core) && ((*list)->cpu > new->cpu))) {
567 new->next = *list;
568 *list = new;
569 return;
570 }
571
572 prev = *list;
573
574 while (prev->next && (prev->next->pkg < new->pkg)) {
575 prev = prev->next;
576 show_pkg = 1; /* there is more than 1 package */
577 }
578
579 while (prev->next && (prev->next->pkg == new->pkg)
580 && (prev->next->core < new->core)) {
581 prev = prev->next;
582 show_core = 1; /* there is more than 1 core */
583 }
584
585 while (prev->next && (prev->next->pkg == new->pkg)
586 && (prev->next->core == new->core)
587 && (prev->next->cpu < new->cpu)) {
588 prev = prev->next;
589 }
590
591 /*
592 * insert after "prev"
593 */
594 new->next = prev->next;
595 prev->next = new;
596}
597
598void alloc_new_counters(int pkg, int core, int cpu)
599{
600 struct counters *new;
601
602 if (verbose > 1)
603 printf("pkg%d core%d, cpu%d\n", pkg, core, cpu);
604
605 new = (struct counters *)calloc(1, sizeof(struct counters));
606 if (new == NULL) {
607 perror("calloc");
608 exit(1);
609 }
610 new->pkg = pkg;
611 new->core = core;
612 new->cpu = cpu;
613 insert_counters(&cnt_odd, new);
614
615 new = (struct counters *)calloc(1,
616 sizeof(struct counters));
617 if (new == NULL) {
618 perror("calloc");
619 exit(1);
620 }
621 new->pkg = pkg;
622 new->core = core;
623 new->cpu = cpu;
624 insert_counters(&cnt_even, new);
625
626 new = (struct counters *)calloc(1, sizeof(struct counters));
627 if (new == NULL) {
628 perror("calloc");
629 exit(1);
630 }
631 new->pkg = pkg;
632 new->core = core;
633 new->cpu = cpu;
634 insert_counters(&cnt_delta, new);
635
636 new = (struct counters *)calloc(1, sizeof(struct counters));
637 if (new == NULL) {
638 perror("calloc");
639 exit(1);
640 }
641 new->pkg = pkg;
642 new->core = core;
643 new->cpu = cpu;
644 cnt_average = new;
645}
646
647int get_physical_package_id(int cpu)
648{
649 char path[64];
650 FILE *filep;
651 int pkg;
652
653 sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/physical_package_id", cpu);
654 filep = fopen(path, "r");
655 if (filep == NULL) {
656 perror(path);
657 exit(1);
658 }
659 fscanf(filep, "%d", &pkg);
660 fclose(filep);
661 return pkg;
662}
663
664int get_core_id(int cpu)
665{
666 char path[64];
667 FILE *filep;
668 int core;
669
670 sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/core_id", cpu);
671 filep = fopen(path, "r");
672 if (filep == NULL) {
673 perror(path);
674 exit(1);
675 }
676 fscanf(filep, "%d", &core);
677 fclose(filep);
678 return core;
679}
680
681/*
682 * run func(index, cpu) on every cpu in /proc/stat
683 */
684
685int for_all_cpus(void (func)(int, int, int))
686{
687 FILE *fp;
688 int cpu_count;
689 int retval;
690
691 fp = fopen(proc_stat, "r");
692 if (fp == NULL) {
693 perror(proc_stat);
694 exit(1);
695 }
696
697 retval = fscanf(fp, "cpu %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n");
698 if (retval != 0) {
699 perror("/proc/stat format");
700 exit(1);
701 }
702
703 for (cpu_count = 0; ; cpu_count++) {
704 int cpu;
705
706 retval = fscanf(fp, "cpu%u %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n", &cpu);
707 if (retval != 1)
708 break;
709
710 func(get_physical_package_id(cpu), get_core_id(cpu), cpu);
711 }
712 fclose(fp);
713 return cpu_count;
714}
715
716void re_initialize(void)
717{
718 printf("turbostat: topology changed, re-initializing.\n");
719 free_all_counters();
720 num_cpus = for_all_cpus(alloc_new_counters);
721 need_reinitialize = 0;
722 printf("num_cpus is now %d\n", num_cpus);
723}
724
725void dummy(int pkg, int core, int cpu) { return; }
726/*
727 * check to see if a cpu came on-line
728 */
729void verify_num_cpus(void)
730{
731 int new_num_cpus;
732
733 new_num_cpus = for_all_cpus(dummy);
734
735 if (new_num_cpus != num_cpus) {
736 if (verbose)
737 printf("num_cpus was %d, is now %d\n",
738 num_cpus, new_num_cpus);
739 need_reinitialize = 1;
740 }
741}
742
743void turbostat_loop()
744{
745restart:
746 get_counters(cnt_even);
747 gettimeofday(&tv_even, (struct timezone *)NULL);
748
749 while (1) {
750 verify_num_cpus();
751 if (need_reinitialize) {
752 re_initialize();
753 goto restart;
754 }
755 sleep(interval_sec);
756 get_counters(cnt_odd);
757 gettimeofday(&tv_odd, (struct timezone *)NULL);
758
759 compute_delta(cnt_odd, cnt_even, cnt_delta);
760 timersub(&tv_odd, &tv_even, &tv_delta);
761 compute_average(cnt_delta, cnt_average);
762 print_counters(cnt_delta);
763 if (need_reinitialize) {
764 re_initialize();
765 goto restart;
766 }
767 sleep(interval_sec);
768 get_counters(cnt_even);
769 gettimeofday(&tv_even, (struct timezone *)NULL);
770 compute_delta(cnt_even, cnt_odd, cnt_delta);
771 timersub(&tv_even, &tv_odd, &tv_delta);
772 compute_average(cnt_delta, cnt_average);
773 print_counters(cnt_delta);
774 }
775}
776
777void check_dev_msr()
778{
779 struct stat sb;
780
781 if (stat("/dev/cpu/0/msr", &sb)) {
782 fprintf(stderr, "no /dev/cpu/0/msr\n");
783 fprintf(stderr, "Try \"# modprobe msr\"\n");
784 exit(-5);
785 }
786}
787
788void check_super_user()
789{
790 if (getuid() != 0) {
791 fprintf(stderr, "must be root\n");
792 exit(-6);
793 }
794}
795
796int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model)
797{
798 if (!genuine_intel)
799 return 0;
800
801 if (family != 6)
802 return 0;
803
804 switch (model) {
805 case 0x1A: /* Core i7, Xeon 5500 series - Bloomfield, Gainstown NHM-EP */
806 case 0x1E: /* Core i7 and i5 Processor - Clarksfield, Lynnfield, Jasper Forest */
807 case 0x1F: /* Core i7 and i5 Processor - Nehalem */
808 case 0x25: /* Westmere Client - Clarkdale, Arrandale */
809 case 0x2C: /* Westmere EP - Gulftown */
810 case 0x2A: /* SNB */
811 case 0x2D: /* SNB Xeon */
812 return 1;
813 case 0x2E: /* Nehalem-EX Xeon - Beckton */
814 case 0x2F: /* Westmere-EX Xeon - Eagleton */
815 default:
816 return 0;
817 }
818}
819
820int is_snb(unsigned int family, unsigned int model)
821{
822 if (!genuine_intel)
823 return 0;
824
825 switch (model) {
826 case 0x2A:
827 case 0x2D:
828 return 1;
829 }
830 return 0;
831}
832
833double discover_bclk(unsigned int family, unsigned int model)
834{
835 if (is_snb(family, model))
836 return 100.00;
837 else
838 return 133.33;
839}
840
841void check_cpuid()
842{
843 unsigned int eax, ebx, ecx, edx, max_level;
844 unsigned int fms, family, model, stepping;
845
846 eax = ebx = ecx = edx = 0;
847
848 asm("cpuid" : "=a" (max_level), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0));
849
850 if (ebx == 0x756e6547 && edx == 0x49656e69 && ecx == 0x6c65746e)
851 genuine_intel = 1;
852
853 if (verbose)
854 fprintf(stderr, "%.4s%.4s%.4s ",
855 (char *)&ebx, (char *)&edx, (char *)&ecx);
856
857 asm("cpuid" : "=a" (fms), "=c" (ecx), "=d" (edx) : "a" (1) : "ebx");
858 family = (fms >> 8) & 0xf;
859 model = (fms >> 4) & 0xf;
860 stepping = fms & 0xf;
861 if (family == 6 || family == 0xf)
862 model += ((fms >> 16) & 0xf) << 4;
863
864 if (verbose)
865 fprintf(stderr, "%d CPUID levels; family:model:stepping 0x%x:%x:%x (%d:%d:%d)\n",
866 max_level, family, model, stepping, family, model, stepping);
867
868 if (!(edx & (1 << 5))) {
869 fprintf(stderr, "CPUID: no MSR\n");
870 exit(1);
871 }
872
873 /*
874 * check max extended function levels of CPUID.
875 * This is needed to check for invariant TSC.
876 * This check is valid for both Intel and AMD.
877 */
878 ebx = ecx = edx = 0;
879 asm("cpuid" : "=a" (max_level), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x80000000));
880
881 if (max_level < 0x80000007) {
882 fprintf(stderr, "CPUID: no invariant TSC (max_level 0x%x)\n", max_level);
883 exit(1);
884 }
885
886 /*
887 * Non-Stop TSC is advertised by CPUID.EAX=0x80000007: EDX.bit8
888 * this check is valid for both Intel and AMD
889 */
890 asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x80000007));
891 has_invariant_tsc = edx & (1 << 8);
892
893 if (!has_invariant_tsc) {
894 fprintf(stderr, "No invariant TSC\n");
895 exit(1);
896 }
897
898 /*
899 * APERF/MPERF is advertised by CPUID.EAX=0x6: ECX.bit0
900 * this check is valid for both Intel and AMD
901 */
902
903 asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x6));
904 has_aperf = ecx & (1 << 0);
905 if (!has_aperf) {
906 fprintf(stderr, "No APERF MSR\n");
907 exit(1);
908 }
909
910 do_nehalem_platform_info = genuine_intel && has_invariant_tsc;
911 do_nhm_cstates = genuine_intel; /* all Intel w/ non-stop TSC have NHM counters */
912 do_snb_cstates = is_snb(family, model);
913 bclk = discover_bclk(family, model);
914
915 do_nehalem_turbo_ratio_limit = has_nehalem_turbo_ratio_limit(family, model);
916}
917
918
919void usage()
920{
921 fprintf(stderr, "%s: [-v] [-M MSR#] [-i interval_sec | command ...]\n",
922 progname);
923 exit(1);
924}
925
926
927/*
928 * in /dev/cpu/ return success for names that are numbers
929 * ie. filter out ".", "..", "microcode".
930 */
931int dir_filter(const struct dirent *dirp)
932{
933 if (isdigit(dirp->d_name[0]))
934 return 1;
935 else
936 return 0;
937}
938
939int open_dev_cpu_msr(int dummy1)
940{
941 return 0;
942}
943
944void turbostat_init()
945{
946 check_cpuid();
947
948 check_dev_msr();
949 check_super_user();
950
951 num_cpus = for_all_cpus(alloc_new_counters);
952
953 if (verbose)
954 print_nehalem_info();
955}
956
957int fork_it(char **argv)
958{
959 int retval;
960 pid_t child_pid;
961 get_counters(cnt_even);
962 gettimeofday(&tv_even, (struct timezone *)NULL);
963
964 child_pid = fork();
965 if (!child_pid) {
966 /* child */
967 execvp(argv[0], argv);
968 } else {
969 int status;
970
971 /* parent */
972 if (child_pid == -1) {
973 perror("fork");
974 exit(1);
975 }
976
977 signal(SIGINT, SIG_IGN);
978 signal(SIGQUIT, SIG_IGN);
979 if (waitpid(child_pid, &status, 0) == -1) {
980 perror("wait");
981 exit(1);
982 }
983 }
984 get_counters(cnt_odd);
985 gettimeofday(&tv_odd, (struct timezone *)NULL);
986 retval = compute_delta(cnt_odd, cnt_even, cnt_delta);
987
988 timersub(&tv_odd, &tv_even, &tv_delta);
989 compute_average(cnt_delta, cnt_average);
990 if (!retval)
991 print_counters(cnt_delta);
992
993 fprintf(stderr, "%.6f sec\n", tv_delta.tv_sec + tv_delta.tv_usec/1000000.0);
994
995 return 0;
996}
997
998void cmdline(int argc, char **argv)
999{
1000 int opt;
1001
1002 progname = argv[0];
1003
1004 while ((opt = getopt(argc, argv, "+vi:M:")) != -1) {
1005 switch (opt) {
1006 case 'v':
1007 verbose++;
1008 break;
1009 case 'i':
1010 interval_sec = atoi(optarg);
1011 break;
1012 case 'M':
1013 sscanf(optarg, "%x", &extra_msr_offset);
1014 if (verbose > 1)
1015 fprintf(stderr, "MSR 0x%X\n", extra_msr_offset);
1016 break;
1017 default:
1018 usage();
1019 }
1020 }
1021}
1022
1023int main(int argc, char **argv)
1024{
1025 cmdline(argc, argv);
1026
1027 if (verbose > 1)
1028 fprintf(stderr, "turbostat Dec 6, 2010"
1029 " - Len Brown <lenb@kernel.org>\n");
1030 if (verbose > 1)
1031 fprintf(stderr, "http://userweb.kernel.org/~lenb/acpi/utils/pmtools/turbostat/\n");
1032
1033 turbostat_init();
1034
1035 /*
1036 * if any params left, it must be a command to fork
1037 */
1038 if (argc - optind)
1039 return fork_it(argv + optind);
1040 else
1041 turbostat_loop();
1042
1043 return 0;
1044}
diff --git a/tools/power/x86/x86_energy_perf_policy/Makefile b/tools/power/x86/x86_energy_perf_policy/Makefile
new file mode 100644
index 000000000000..f458237fdd79
--- /dev/null
+++ b/tools/power/x86/x86_energy_perf_policy/Makefile
@@ -0,0 +1,8 @@
1x86_energy_perf_policy : x86_energy_perf_policy.c
2
3clean :
4 rm -f x86_energy_perf_policy
5
6install :
7 install x86_energy_perf_policy /usr/bin/
8 install x86_energy_perf_policy.8 /usr/share/man/man8/
diff --git a/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.8 b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.8
new file mode 100644
index 000000000000..8eaaad648cdb
--- /dev/null
+++ b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.8
@@ -0,0 +1,104 @@
1.\" This page Copyright (C) 2010 Len Brown <len.brown@intel.com>
2.\" Distributed under the GPL, Copyleft 1994.
3.TH X86_ENERGY_PERF_POLICY 8
4.SH NAME
5x86_energy_perf_policy \- read or write MSR_IA32_ENERGY_PERF_BIAS
6.SH SYNOPSIS
7.ft B
8.B x86_energy_perf_policy
9.RB [ "\-c cpu" ]
10.RB [ "\-v" ]
11.RB "\-r"
12.br
13.B x86_energy_perf_policy
14.RB [ "\-c cpu" ]
15.RB [ "\-v" ]
16.RB 'performance'
17.br
18.B x86_energy_perf_policy
19.RB [ "\-c cpu" ]
20.RB [ "\-v" ]
21.RB 'normal'
22.br
23.B x86_energy_perf_policy
24.RB [ "\-c cpu" ]
25.RB [ "\-v" ]
26.RB 'powersave'
27.br
28.B x86_energy_perf_policy
29.RB [ "\-c cpu" ]
30.RB [ "\-v" ]
31.RB n
32.br
33.SH DESCRIPTION
34\fBx86_energy_perf_policy\fP
35allows software to convey
36its policy for the relative importance of performance
37versus energy savings to the processor.
38
39The processor uses this information in model-specific ways
40when it must select trade-offs between performance and
41energy efficiency.
42
43This policy hint does not supersede Processor Performance states
44(P-states) or CPU Idle power states (C-states), but allows
45software to have influence where it would otherwise be unable
46to express a preference.
47
48For example, this setting may tell the hardware how
49aggressively or conservatively to control frequency
50in the "turbo range" above the explicitly OS-controlled
51P-state frequency range. It may also tell the hardware
52how aggressively is should enter the OS requested C-states.
53
54Support for this feature is indicated by CPUID.06H.ECX.bit3
55per the Intel Architectures Software Developer's Manual.
56
57.SS Options
58\fB-c\fP limits operation to a single CPU.
59The default is to operate on all CPUs.
60Note that MSR_IA32_ENERGY_PERF_BIAS is defined per
61logical processor, but that the initial implementations
62of the MSR were shared among all processors in each package.
63.PP
64\fB-v\fP increases verbosity. By default
65x86_energy_perf_policy is silent.
66.PP
67\fB-r\fP is for "read-only" mode - the unchanged state
68is read and displayed.
69.PP
70.I performance
71Set a policy where performance is paramount.
72The processor will be unwilling to sacrifice any performance
73for the sake of energy saving. This is the hardware default.
74.PP
75.I normal
76Set a policy with a normal balance between performance and energy efficiency.
77The processor will tolerate minor performance compromise
78for potentially significant energy savings.
79This reasonable default for most desktops and servers.
80.PP
81.I powersave
82Set a policy where the processor can accept
83a measurable performance hit to maximize energy efficiency.
84.PP
85.I n
86Set MSR_IA32_ENERGY_PERF_BIAS to the specified number.
87The range of valid numbers is 0-15, where 0 is maximum
88performance and 15 is maximum energy efficiency.
89
90.SH NOTES
91.B "x86_energy_perf_policy "
92runs only as root.
93.SH FILES
94.ta
95.nf
96/dev/cpu/*/msr
97.fi
98
99.SH "SEE ALSO"
100msr(4)
101.PP
102.SH AUTHORS
103.nf
104Written by Len Brown <len.brown@intel.com>
diff --git a/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c
new file mode 100644
index 000000000000..2618ef2ba31f
--- /dev/null
+++ b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c
@@ -0,0 +1,325 @@
1/*
2 * x86_energy_perf_policy -- set the energy versus performance
3 * policy preference bias on recent X86 processors.
4 */
5/*
6 * Copyright (c) 2010, Intel Corporation.
7 * Len Brown <len.brown@intel.com>
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms and conditions of the GNU General Public License,
11 * version 2, as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along with
19 * this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22
23#include <stdio.h>
24#include <unistd.h>
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <sys/resource.h>
28#include <fcntl.h>
29#include <signal.h>
30#include <sys/time.h>
31#include <stdlib.h>
32#include <string.h>
33
34unsigned int verbose; /* set with -v */
35unsigned int read_only; /* set with -r */
36char *progname;
37unsigned long long new_bias;
38int cpu = -1;
39
40/*
41 * Usage:
42 *
43 * -c cpu: limit action to a single CPU (default is all CPUs)
44 * -v: verbose output (can invoke more than once)
45 * -r: read-only, don't change any settings
46 *
47 * performance
48 * Performance is paramount.
49 * Unwilling to sacrifice any performance
50 * for the sake of energy saving. (hardware default)
51 *
52 * normal
53 * Can tolerate minor performance compromise
54 * for potentially significant energy savings.
55 * (reasonable default for most desktops and servers)
56 *
57 * powersave
58 * Can tolerate significant performance hit
59 * to maximize energy savings.
60 *
61 * n
62 * a numerical value to write to the underlying MSR.
63 */
64void usage(void)
65{
66 printf("%s: [-c cpu] [-v] "
67 "(-r | 'performance' | 'normal' | 'powersave' | n)\n",
68 progname);
69 exit(1);
70}
71
72#define MSR_IA32_ENERGY_PERF_BIAS 0x000001b0
73
74#define BIAS_PERFORMANCE 0
75#define BIAS_BALANCE 6
76#define BIAS_POWERSAVE 15
77
78void cmdline(int argc, char **argv)
79{
80 int opt;
81
82 progname = argv[0];
83
84 while ((opt = getopt(argc, argv, "+rvc:")) != -1) {
85 switch (opt) {
86 case 'c':
87 cpu = atoi(optarg);
88 break;
89 case 'r':
90 read_only = 1;
91 break;
92 case 'v':
93 verbose++;
94 break;
95 default:
96 usage();
97 }
98 }
99 /* if -r, then should be no additional optind */
100 if (read_only && (argc > optind))
101 usage();
102
103 /*
104 * if no -r , then must be one additional optind
105 */
106 if (!read_only) {
107
108 if (argc != optind + 1) {
109 printf("must supply -r or policy param\n");
110 usage();
111 }
112
113 if (!strcmp("performance", argv[optind])) {
114 new_bias = BIAS_PERFORMANCE;
115 } else if (!strcmp("normal", argv[optind])) {
116 new_bias = BIAS_BALANCE;
117 } else if (!strcmp("powersave", argv[optind])) {
118 new_bias = BIAS_POWERSAVE;
119 } else {
120 char *endptr;
121
122 new_bias = strtoull(argv[optind], &endptr, 0);
123 if (endptr == argv[optind] ||
124 new_bias > BIAS_POWERSAVE) {
125 fprintf(stderr, "invalid value: %s\n",
126 argv[optind]);
127 usage();
128 }
129 }
130 }
131}
132
133/*
134 * validate_cpuid()
135 * returns on success, quietly exits on failure (make verbose with -v)
136 */
137void validate_cpuid(void)
138{
139 unsigned int eax, ebx, ecx, edx, max_level;
140 char brand[16];
141 unsigned int fms, family, model, stepping;
142
143 eax = ebx = ecx = edx = 0;
144
145 asm("cpuid" : "=a" (max_level), "=b" (ebx), "=c" (ecx),
146 "=d" (edx) : "a" (0));
147
148 if (ebx != 0x756e6547 || edx != 0x49656e69 || ecx != 0x6c65746e) {
149 if (verbose)
150 fprintf(stderr, "%.4s%.4s%.4s != GenuineIntel",
151 (char *)&ebx, (char *)&edx, (char *)&ecx);
152 exit(1);
153 }
154
155 asm("cpuid" : "=a" (fms), "=c" (ecx), "=d" (edx) : "a" (1) : "ebx");
156 family = (fms >> 8) & 0xf;
157 model = (fms >> 4) & 0xf;
158 stepping = fms & 0xf;
159 if (family == 6 || family == 0xf)
160 model += ((fms >> 16) & 0xf) << 4;
161
162 if (verbose > 1)
163 printf("CPUID %s %d levels family:model:stepping "
164 "0x%x:%x:%x (%d:%d:%d)\n", brand, max_level,
165 family, model, stepping, family, model, stepping);
166
167 if (!(edx & (1 << 5))) {
168 if (verbose)
169 printf("CPUID: no MSR\n");
170 exit(1);
171 }
172
173 /*
174 * Support for MSR_IA32_ENERGY_PERF_BIAS
175 * is indicated by CPUID.06H.ECX.bit3
176 */
177 asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (6));
178 if (verbose)
179 printf("CPUID.06H.ECX: 0x%x\n", ecx);
180 if (!(ecx & (1 << 3))) {
181 if (verbose)
182 printf("CPUID: No MSR_IA32_ENERGY_PERF_BIAS\n");
183 exit(1);
184 }
185 return; /* success */
186}
187
188unsigned long long get_msr(int cpu, int offset)
189{
190 unsigned long long msr;
191 char msr_path[32];
192 int retval;
193 int fd;
194
195 sprintf(msr_path, "/dev/cpu/%d/msr", cpu);
196 fd = open(msr_path, O_RDONLY);
197 if (fd < 0) {
198 printf("Try \"# modprobe msr\"\n");
199 perror(msr_path);
200 exit(1);
201 }
202
203 retval = pread(fd, &msr, sizeof msr, offset);
204
205 if (retval != sizeof msr) {
206 printf("pread cpu%d 0x%x = %d\n", cpu, offset, retval);
207 exit(-2);
208 }
209 close(fd);
210 return msr;
211}
212
213unsigned long long put_msr(int cpu, unsigned long long new_msr, int offset)
214{
215 unsigned long long old_msr;
216 char msr_path[32];
217 int retval;
218 int fd;
219
220 sprintf(msr_path, "/dev/cpu/%d/msr", cpu);
221 fd = open(msr_path, O_RDWR);
222 if (fd < 0) {
223 perror(msr_path);
224 exit(1);
225 }
226
227 retval = pread(fd, &old_msr, sizeof old_msr, offset);
228 if (retval != sizeof old_msr) {
229 perror("pwrite");
230 printf("pread cpu%d 0x%x = %d\n", cpu, offset, retval);
231 exit(-2);
232 }
233
234 retval = pwrite(fd, &new_msr, sizeof new_msr, offset);
235 if (retval != sizeof new_msr) {
236 perror("pwrite");
237 printf("pwrite cpu%d 0x%x = %d\n", cpu, offset, retval);
238 exit(-2);
239 }
240
241 close(fd);
242
243 return old_msr;
244}
245
246void print_msr(int cpu)
247{
248 printf("cpu%d: 0x%016llx\n",
249 cpu, get_msr(cpu, MSR_IA32_ENERGY_PERF_BIAS));
250}
251
252void update_msr(int cpu)
253{
254 unsigned long long previous_msr;
255
256 previous_msr = put_msr(cpu, new_bias, MSR_IA32_ENERGY_PERF_BIAS);
257
258 if (verbose)
259 printf("cpu%d msr0x%x 0x%016llx -> 0x%016llx\n",
260 cpu, MSR_IA32_ENERGY_PERF_BIAS, previous_msr, new_bias);
261
262 return;
263}
264
265char *proc_stat = "/proc/stat";
266/*
267 * run func() on every cpu in /dev/cpu
268 */
269void for_every_cpu(void (func)(int))
270{
271 FILE *fp;
272 int retval;
273
274 fp = fopen(proc_stat, "r");
275 if (fp == NULL) {
276 perror(proc_stat);
277 exit(1);
278 }
279
280 retval = fscanf(fp, "cpu %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n");
281 if (retval != 0) {
282 perror("/proc/stat format");
283 exit(1);
284 }
285
286 while (1) {
287 int cpu;
288
289 retval = fscanf(fp,
290 "cpu%u %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n",
291 &cpu);
292 if (retval != 1)
293 return;
294
295 func(cpu);
296 }
297 fclose(fp);
298}
299
300int main(int argc, char **argv)
301{
302 cmdline(argc, argv);
303
304 if (verbose > 1)
305 printf("x86_energy_perf_policy Nov 24, 2010"
306 " - Len Brown <lenb@kernel.org>\n");
307 if (verbose > 1 && !read_only)
308 printf("new_bias %lld\n", new_bias);
309
310 validate_cpuid();
311
312 if (cpu != -1) {
313 if (read_only)
314 print_msr(cpu);
315 else
316 update_msr(cpu);
317 } else {
318 if (read_only)
319 for_every_cpu(print_msr);
320 else
321 for_every_cpu(update_msr);
322 }
323
324 return 0;
325}
diff --git a/tools/slub/slabinfo.c b/tools/slub/slabinfo.c
new file mode 100644
index 000000000000..516551c9f172
--- /dev/null
+++ b/tools/slub/slabinfo.c
@@ -0,0 +1,1364 @@
1/*
2 * Slabinfo: Tool to get reports about slabs
3 *
4 * (C) 2007 sgi, Christoph Lameter
5 *
6 * Compile by:
7 *
8 * gcc -o slabinfo slabinfo.c
9 */
10#include <stdio.h>
11#include <stdlib.h>
12#include <sys/types.h>
13#include <dirent.h>
14#include <strings.h>
15#include <string.h>
16#include <unistd.h>
17#include <stdarg.h>
18#include <getopt.h>
19#include <regex.h>
20#include <errno.h>
21
22#define MAX_SLABS 500
23#define MAX_ALIASES 500
24#define MAX_NODES 1024
25
26struct slabinfo {
27 char *name;
28 int alias;
29 int refs;
30 int aliases, align, cache_dma, cpu_slabs, destroy_by_rcu;
31 int hwcache_align, object_size, objs_per_slab;
32 int sanity_checks, slab_size, store_user, trace;
33 int order, poison, reclaim_account, red_zone;
34 unsigned long partial, objects, slabs, objects_partial, objects_total;
35 unsigned long alloc_fastpath, alloc_slowpath;
36 unsigned long free_fastpath, free_slowpath;
37 unsigned long free_frozen, free_add_partial, free_remove_partial;
38 unsigned long alloc_from_partial, alloc_slab, free_slab, alloc_refill;
39 unsigned long cpuslab_flush, deactivate_full, deactivate_empty;
40 unsigned long deactivate_to_head, deactivate_to_tail;
41 unsigned long deactivate_remote_frees, order_fallback;
42 int numa[MAX_NODES];
43 int numa_partial[MAX_NODES];
44} slabinfo[MAX_SLABS];
45
46struct aliasinfo {
47 char *name;
48 char *ref;
49 struct slabinfo *slab;
50} aliasinfo[MAX_ALIASES];
51
52int slabs = 0;
53int actual_slabs = 0;
54int aliases = 0;
55int alias_targets = 0;
56int highest_node = 0;
57
58char buffer[4096];
59
60int show_empty = 0;
61int show_report = 0;
62int show_alias = 0;
63int show_slab = 0;
64int skip_zero = 1;
65int show_numa = 0;
66int show_track = 0;
67int show_first_alias = 0;
68int validate = 0;
69int shrink = 0;
70int show_inverted = 0;
71int show_single_ref = 0;
72int show_totals = 0;
73int sort_size = 0;
74int sort_active = 0;
75int set_debug = 0;
76int show_ops = 0;
77int show_activity = 0;
78
79/* Debug options */
80int sanity = 0;
81int redzone = 0;
82int poison = 0;
83int tracking = 0;
84int tracing = 0;
85
86int page_size;
87
88regex_t pattern;
89
90static void fatal(const char *x, ...)
91{
92 va_list ap;
93
94 va_start(ap, x);
95 vfprintf(stderr, x, ap);
96 va_end(ap);
97 exit(EXIT_FAILURE);
98}
99
100static void usage(void)
101{
102 printf("slabinfo 5/7/2007. (c) 2007 sgi.\n\n"
103 "slabinfo [-ahnpvtsz] [-d debugopts] [slab-regexp]\n"
104 "-a|--aliases Show aliases\n"
105 "-A|--activity Most active slabs first\n"
106 "-d<options>|--debug=<options> Set/Clear Debug options\n"
107 "-D|--display-active Switch line format to activity\n"
108 "-e|--empty Show empty slabs\n"
109 "-f|--first-alias Show first alias\n"
110 "-h|--help Show usage information\n"
111 "-i|--inverted Inverted list\n"
112 "-l|--slabs Show slabs\n"
113 "-n|--numa Show NUMA information\n"
114 "-o|--ops Show kmem_cache_ops\n"
115 "-s|--shrink Shrink slabs\n"
116 "-r|--report Detailed report on single slabs\n"
117 "-S|--Size Sort by size\n"
118 "-t|--tracking Show alloc/free information\n"
119 "-T|--Totals Show summary information\n"
120 "-v|--validate Validate slabs\n"
121 "-z|--zero Include empty slabs\n"
122 "-1|--1ref Single reference\n"
123 "\nValid debug options (FZPUT may be combined)\n"
124 "a / A Switch on all debug options (=FZUP)\n"
125 "- Switch off all debug options\n"
126 "f / F Sanity Checks (SLAB_DEBUG_FREE)\n"
127 "z / Z Redzoning\n"
128 "p / P Poisoning\n"
129 "u / U Tracking\n"
130 "t / T Tracing\n"
131 );
132}
133
134static unsigned long read_obj(const char *name)
135{
136 FILE *f = fopen(name, "r");
137
138 if (!f)
139 buffer[0] = 0;
140 else {
141 if (!fgets(buffer, sizeof(buffer), f))
142 buffer[0] = 0;
143 fclose(f);
144 if (buffer[strlen(buffer)] == '\n')
145 buffer[strlen(buffer)] = 0;
146 }
147 return strlen(buffer);
148}
149
150
151/*
152 * Get the contents of an attribute
153 */
154static unsigned long get_obj(const char *name)
155{
156 if (!read_obj(name))
157 return 0;
158
159 return atol(buffer);
160}
161
162static unsigned long get_obj_and_str(const char *name, char **x)
163{
164 unsigned long result = 0;
165 char *p;
166
167 *x = NULL;
168
169 if (!read_obj(name)) {
170 x = NULL;
171 return 0;
172 }
173 result = strtoul(buffer, &p, 10);
174 while (*p == ' ')
175 p++;
176 if (*p)
177 *x = strdup(p);
178 return result;
179}
180
181static void set_obj(struct slabinfo *s, const char *name, int n)
182{
183 char x[100];
184 FILE *f;
185
186 snprintf(x, 100, "%s/%s", s->name, name);
187 f = fopen(x, "w");
188 if (!f)
189 fatal("Cannot write to %s\n", x);
190
191 fprintf(f, "%d\n", n);
192 fclose(f);
193}
194
195static unsigned long read_slab_obj(struct slabinfo *s, const char *name)
196{
197 char x[100];
198 FILE *f;
199 size_t l;
200
201 snprintf(x, 100, "%s/%s", s->name, name);
202 f = fopen(x, "r");
203 if (!f) {
204 buffer[0] = 0;
205 l = 0;
206 } else {
207 l = fread(buffer, 1, sizeof(buffer), f);
208 buffer[l] = 0;
209 fclose(f);
210 }
211 return l;
212}
213
214
215/*
216 * Put a size string together
217 */
218static int store_size(char *buffer, unsigned long value)
219{
220 unsigned long divisor = 1;
221 char trailer = 0;
222 int n;
223
224 if (value > 1000000000UL) {
225 divisor = 100000000UL;
226 trailer = 'G';
227 } else if (value > 1000000UL) {
228 divisor = 100000UL;
229 trailer = 'M';
230 } else if (value > 1000UL) {
231 divisor = 100;
232 trailer = 'K';
233 }
234
235 value /= divisor;
236 n = sprintf(buffer, "%ld",value);
237 if (trailer) {
238 buffer[n] = trailer;
239 n++;
240 buffer[n] = 0;
241 }
242 if (divisor != 1) {
243 memmove(buffer + n - 2, buffer + n - 3, 4);
244 buffer[n-2] = '.';
245 n++;
246 }
247 return n;
248}
249
250static void decode_numa_list(int *numa, char *t)
251{
252 int node;
253 int nr;
254
255 memset(numa, 0, MAX_NODES * sizeof(int));
256
257 if (!t)
258 return;
259
260 while (*t == 'N') {
261 t++;
262 node = strtoul(t, &t, 10);
263 if (*t == '=') {
264 t++;
265 nr = strtoul(t, &t, 10);
266 numa[node] = nr;
267 if (node > highest_node)
268 highest_node = node;
269 }
270 while (*t == ' ')
271 t++;
272 }
273}
274
275static void slab_validate(struct slabinfo *s)
276{
277 if (strcmp(s->name, "*") == 0)
278 return;
279
280 set_obj(s, "validate", 1);
281}
282
283static void slab_shrink(struct slabinfo *s)
284{
285 if (strcmp(s->name, "*") == 0)
286 return;
287
288 set_obj(s, "shrink", 1);
289}
290
291int line = 0;
292
293static void first_line(void)
294{
295 if (show_activity)
296 printf("Name Objects Alloc Free %%Fast Fallb O\n");
297 else
298 printf("Name Objects Objsize Space "
299 "Slabs/Part/Cpu O/S O %%Fr %%Ef Flg\n");
300}
301
302/*
303 * Find the shortest alias of a slab
304 */
305static struct aliasinfo *find_one_alias(struct slabinfo *find)
306{
307 struct aliasinfo *a;
308 struct aliasinfo *best = NULL;
309
310 for(a = aliasinfo;a < aliasinfo + aliases; a++) {
311 if (a->slab == find &&
312 (!best || strlen(best->name) < strlen(a->name))) {
313 best = a;
314 if (strncmp(a->name,"kmall", 5) == 0)
315 return best;
316 }
317 }
318 return best;
319}
320
321static unsigned long slab_size(struct slabinfo *s)
322{
323 return s->slabs * (page_size << s->order);
324}
325
326static unsigned long slab_activity(struct slabinfo *s)
327{
328 return s->alloc_fastpath + s->free_fastpath +
329 s->alloc_slowpath + s->free_slowpath;
330}
331
332static void slab_numa(struct slabinfo *s, int mode)
333{
334 int node;
335
336 if (strcmp(s->name, "*") == 0)
337 return;
338
339 if (!highest_node) {
340 printf("\n%s: No NUMA information available.\n", s->name);
341 return;
342 }
343
344 if (skip_zero && !s->slabs)
345 return;
346
347 if (!line) {
348 printf("\n%-21s:", mode ? "NUMA nodes" : "Slab");
349 for(node = 0; node <= highest_node; node++)
350 printf(" %4d", node);
351 printf("\n----------------------");
352 for(node = 0; node <= highest_node; node++)
353 printf("-----");
354 printf("\n");
355 }
356 printf("%-21s ", mode ? "All slabs" : s->name);
357 for(node = 0; node <= highest_node; node++) {
358 char b[20];
359
360 store_size(b, s->numa[node]);
361 printf(" %4s", b);
362 }
363 printf("\n");
364 if (mode) {
365 printf("%-21s ", "Partial slabs");
366 for(node = 0; node <= highest_node; node++) {
367 char b[20];
368
369 store_size(b, s->numa_partial[node]);
370 printf(" %4s", b);
371 }
372 printf("\n");
373 }
374 line++;
375}
376
377static void show_tracking(struct slabinfo *s)
378{
379 printf("\n%s: Kernel object allocation\n", s->name);
380 printf("-----------------------------------------------------------------------\n");
381 if (read_slab_obj(s, "alloc_calls"))
382 printf(buffer);
383 else
384 printf("No Data\n");
385
386 printf("\n%s: Kernel object freeing\n", s->name);
387 printf("------------------------------------------------------------------------\n");
388 if (read_slab_obj(s, "free_calls"))
389 printf(buffer);
390 else
391 printf("No Data\n");
392
393}
394
395static void ops(struct slabinfo *s)
396{
397 if (strcmp(s->name, "*") == 0)
398 return;
399
400 if (read_slab_obj(s, "ops")) {
401 printf("\n%s: kmem_cache operations\n", s->name);
402 printf("--------------------------------------------\n");
403 printf(buffer);
404 } else
405 printf("\n%s has no kmem_cache operations\n", s->name);
406}
407
408static const char *onoff(int x)
409{
410 if (x)
411 return "On ";
412 return "Off";
413}
414
415static void slab_stats(struct slabinfo *s)
416{
417 unsigned long total_alloc;
418 unsigned long total_free;
419 unsigned long total;
420
421 if (!s->alloc_slab)
422 return;
423
424 total_alloc = s->alloc_fastpath + s->alloc_slowpath;
425 total_free = s->free_fastpath + s->free_slowpath;
426
427 if (!total_alloc)
428 return;
429
430 printf("\n");
431 printf("Slab Perf Counter Alloc Free %%Al %%Fr\n");
432 printf("--------------------------------------------------\n");
433 printf("Fastpath %8lu %8lu %3lu %3lu\n",
434 s->alloc_fastpath, s->free_fastpath,
435 s->alloc_fastpath * 100 / total_alloc,
436 s->free_fastpath * 100 / total_free);
437 printf("Slowpath %8lu %8lu %3lu %3lu\n",
438 total_alloc - s->alloc_fastpath, s->free_slowpath,
439 (total_alloc - s->alloc_fastpath) * 100 / total_alloc,
440 s->free_slowpath * 100 / total_free);
441 printf("Page Alloc %8lu %8lu %3lu %3lu\n",
442 s->alloc_slab, s->free_slab,
443 s->alloc_slab * 100 / total_alloc,
444 s->free_slab * 100 / total_free);
445 printf("Add partial %8lu %8lu %3lu %3lu\n",
446 s->deactivate_to_head + s->deactivate_to_tail,
447 s->free_add_partial,
448 (s->deactivate_to_head + s->deactivate_to_tail) * 100 / total_alloc,
449 s->free_add_partial * 100 / total_free);
450 printf("Remove partial %8lu %8lu %3lu %3lu\n",
451 s->alloc_from_partial, s->free_remove_partial,
452 s->alloc_from_partial * 100 / total_alloc,
453 s->free_remove_partial * 100 / total_free);
454
455 printf("RemoteObj/SlabFrozen %8lu %8lu %3lu %3lu\n",
456 s->deactivate_remote_frees, s->free_frozen,
457 s->deactivate_remote_frees * 100 / total_alloc,
458 s->free_frozen * 100 / total_free);
459
460 printf("Total %8lu %8lu\n\n", total_alloc, total_free);
461
462 if (s->cpuslab_flush)
463 printf("Flushes %8lu\n", s->cpuslab_flush);
464
465 if (s->alloc_refill)
466 printf("Refill %8lu\n", s->alloc_refill);
467
468 total = s->deactivate_full + s->deactivate_empty +
469 s->deactivate_to_head + s->deactivate_to_tail;
470
471 if (total)
472 printf("Deactivate Full=%lu(%lu%%) Empty=%lu(%lu%%) "
473 "ToHead=%lu(%lu%%) ToTail=%lu(%lu%%)\n",
474 s->deactivate_full, (s->deactivate_full * 100) / total,
475 s->deactivate_empty, (s->deactivate_empty * 100) / total,
476 s->deactivate_to_head, (s->deactivate_to_head * 100) / total,
477 s->deactivate_to_tail, (s->deactivate_to_tail * 100) / total);
478}
479
480static void report(struct slabinfo *s)
481{
482 if (strcmp(s->name, "*") == 0)
483 return;
484
485 printf("\nSlabcache: %-20s Aliases: %2d Order : %2d Objects: %lu\n",
486 s->name, s->aliases, s->order, s->objects);
487 if (s->hwcache_align)
488 printf("** Hardware cacheline aligned\n");
489 if (s->cache_dma)
490 printf("** Memory is allocated in a special DMA zone\n");
491 if (s->destroy_by_rcu)
492 printf("** Slabs are destroyed via RCU\n");
493 if (s->reclaim_account)
494 printf("** Reclaim accounting active\n");
495
496 printf("\nSizes (bytes) Slabs Debug Memory\n");
497 printf("------------------------------------------------------------------------\n");
498 printf("Object : %7d Total : %7ld Sanity Checks : %s Total: %7ld\n",
499 s->object_size, s->slabs, onoff(s->sanity_checks),
500 s->slabs * (page_size << s->order));
501 printf("SlabObj: %7d Full : %7ld Redzoning : %s Used : %7ld\n",
502 s->slab_size, s->slabs - s->partial - s->cpu_slabs,
503 onoff(s->red_zone), s->objects * s->object_size);
504 printf("SlabSiz: %7d Partial: %7ld Poisoning : %s Loss : %7ld\n",
505 page_size << s->order, s->partial, onoff(s->poison),
506 s->slabs * (page_size << s->order) - s->objects * s->object_size);
507 printf("Loss : %7d CpuSlab: %7d Tracking : %s Lalig: %7ld\n",
508 s->slab_size - s->object_size, s->cpu_slabs, onoff(s->store_user),
509 (s->slab_size - s->object_size) * s->objects);
510 printf("Align : %7d Objects: %7d Tracing : %s Lpadd: %7ld\n",
511 s->align, s->objs_per_slab, onoff(s->trace),
512 ((page_size << s->order) - s->objs_per_slab * s->slab_size) *
513 s->slabs);
514
515 ops(s);
516 show_tracking(s);
517 slab_numa(s, 1);
518 slab_stats(s);
519}
520
521static void slabcache(struct slabinfo *s)
522{
523 char size_str[20];
524 char dist_str[40];
525 char flags[20];
526 char *p = flags;
527
528 if (strcmp(s->name, "*") == 0)
529 return;
530
531 if (actual_slabs == 1) {
532 report(s);
533 return;
534 }
535
536 if (skip_zero && !show_empty && !s->slabs)
537 return;
538
539 if (show_empty && s->slabs)
540 return;
541
542 store_size(size_str, slab_size(s));
543 snprintf(dist_str, 40, "%lu/%lu/%d", s->slabs - s->cpu_slabs,
544 s->partial, s->cpu_slabs);
545
546 if (!line++)
547 first_line();
548
549 if (s->aliases)
550 *p++ = '*';
551 if (s->cache_dma)
552 *p++ = 'd';
553 if (s->hwcache_align)
554 *p++ = 'A';
555 if (s->poison)
556 *p++ = 'P';
557 if (s->reclaim_account)
558 *p++ = 'a';
559 if (s->red_zone)
560 *p++ = 'Z';
561 if (s->sanity_checks)
562 *p++ = 'F';
563 if (s->store_user)
564 *p++ = 'U';
565 if (s->trace)
566 *p++ = 'T';
567
568 *p = 0;
569 if (show_activity) {
570 unsigned long total_alloc;
571 unsigned long total_free;
572
573 total_alloc = s->alloc_fastpath + s->alloc_slowpath;
574 total_free = s->free_fastpath + s->free_slowpath;
575
576 printf("%-21s %8ld %10ld %10ld %3ld %3ld %5ld %1d\n",
577 s->name, s->objects,
578 total_alloc, total_free,
579 total_alloc ? (s->alloc_fastpath * 100 / total_alloc) : 0,
580 total_free ? (s->free_fastpath * 100 / total_free) : 0,
581 s->order_fallback, s->order);
582 }
583 else
584 printf("%-21s %8ld %7d %8s %14s %4d %1d %3ld %3ld %s\n",
585 s->name, s->objects, s->object_size, size_str, dist_str,
586 s->objs_per_slab, s->order,
587 s->slabs ? (s->partial * 100) / s->slabs : 100,
588 s->slabs ? (s->objects * s->object_size * 100) /
589 (s->slabs * (page_size << s->order)) : 100,
590 flags);
591}
592
593/*
594 * Analyze debug options. Return false if something is amiss.
595 */
596static int debug_opt_scan(char *opt)
597{
598 if (!opt || !opt[0] || strcmp(opt, "-") == 0)
599 return 1;
600
601 if (strcasecmp(opt, "a") == 0) {
602 sanity = 1;
603 poison = 1;
604 redzone = 1;
605 tracking = 1;
606 return 1;
607 }
608
609 for ( ; *opt; opt++)
610 switch (*opt) {
611 case 'F' : case 'f':
612 if (sanity)
613 return 0;
614 sanity = 1;
615 break;
616 case 'P' : case 'p':
617 if (poison)
618 return 0;
619 poison = 1;
620 break;
621
622 case 'Z' : case 'z':
623 if (redzone)
624 return 0;
625 redzone = 1;
626 break;
627
628 case 'U' : case 'u':
629 if (tracking)
630 return 0;
631 tracking = 1;
632 break;
633
634 case 'T' : case 't':
635 if (tracing)
636 return 0;
637 tracing = 1;
638 break;
639 default:
640 return 0;
641 }
642 return 1;
643}
644
645static int slab_empty(struct slabinfo *s)
646{
647 if (s->objects > 0)
648 return 0;
649
650 /*
651 * We may still have slabs even if there are no objects. Shrinking will
652 * remove them.
653 */
654 if (s->slabs != 0)
655 set_obj(s, "shrink", 1);
656
657 return 1;
658}
659
660static void slab_debug(struct slabinfo *s)
661{
662 if (strcmp(s->name, "*") == 0)
663 return;
664
665 if (sanity && !s->sanity_checks) {
666 set_obj(s, "sanity", 1);
667 }
668 if (!sanity && s->sanity_checks) {
669 if (slab_empty(s))
670 set_obj(s, "sanity", 0);
671 else
672 fprintf(stderr, "%s not empty cannot disable sanity checks\n", s->name);
673 }
674 if (redzone && !s->red_zone) {
675 if (slab_empty(s))
676 set_obj(s, "red_zone", 1);
677 else
678 fprintf(stderr, "%s not empty cannot enable redzoning\n", s->name);
679 }
680 if (!redzone && s->red_zone) {
681 if (slab_empty(s))
682 set_obj(s, "red_zone", 0);
683 else
684 fprintf(stderr, "%s not empty cannot disable redzoning\n", s->name);
685 }
686 if (poison && !s->poison) {
687 if (slab_empty(s))
688 set_obj(s, "poison", 1);
689 else
690 fprintf(stderr, "%s not empty cannot enable poisoning\n", s->name);
691 }
692 if (!poison && s->poison) {
693 if (slab_empty(s))
694 set_obj(s, "poison", 0);
695 else
696 fprintf(stderr, "%s not empty cannot disable poisoning\n", s->name);
697 }
698 if (tracking && !s->store_user) {
699 if (slab_empty(s))
700 set_obj(s, "store_user", 1);
701 else
702 fprintf(stderr, "%s not empty cannot enable tracking\n", s->name);
703 }
704 if (!tracking && s->store_user) {
705 if (slab_empty(s))
706 set_obj(s, "store_user", 0);
707 else
708 fprintf(stderr, "%s not empty cannot disable tracking\n", s->name);
709 }
710 if (tracing && !s->trace) {
711 if (slabs == 1)
712 set_obj(s, "trace", 1);
713 else
714 fprintf(stderr, "%s can only enable trace for one slab at a time\n", s->name);
715 }
716 if (!tracing && s->trace)
717 set_obj(s, "trace", 1);
718}
719
720static void totals(void)
721{
722 struct slabinfo *s;
723
724 int used_slabs = 0;
725 char b1[20], b2[20], b3[20], b4[20];
726 unsigned long long max = 1ULL << 63;
727
728 /* Object size */
729 unsigned long long min_objsize = max, max_objsize = 0, avg_objsize;
730
731 /* Number of partial slabs in a slabcache */
732 unsigned long long min_partial = max, max_partial = 0,
733 avg_partial, total_partial = 0;
734
735 /* Number of slabs in a slab cache */
736 unsigned long long min_slabs = max, max_slabs = 0,
737 avg_slabs, total_slabs = 0;
738
739 /* Size of the whole slab */
740 unsigned long long min_size = max, max_size = 0,
741 avg_size, total_size = 0;
742
743 /* Bytes used for object storage in a slab */
744 unsigned long long min_used = max, max_used = 0,
745 avg_used, total_used = 0;
746
747 /* Waste: Bytes used for alignment and padding */
748 unsigned long long min_waste = max, max_waste = 0,
749 avg_waste, total_waste = 0;
750 /* Number of objects in a slab */
751 unsigned long long min_objects = max, max_objects = 0,
752 avg_objects, total_objects = 0;
753 /* Waste per object */
754 unsigned long long min_objwaste = max,
755 max_objwaste = 0, avg_objwaste,
756 total_objwaste = 0;
757
758 /* Memory per object */
759 unsigned long long min_memobj = max,
760 max_memobj = 0, avg_memobj,
761 total_objsize = 0;
762
763 /* Percentage of partial slabs per slab */
764 unsigned long min_ppart = 100, max_ppart = 0,
765 avg_ppart, total_ppart = 0;
766
767 /* Number of objects in partial slabs */
768 unsigned long min_partobj = max, max_partobj = 0,
769 avg_partobj, total_partobj = 0;
770
771 /* Percentage of partial objects of all objects in a slab */
772 unsigned long min_ppartobj = 100, max_ppartobj = 0,
773 avg_ppartobj, total_ppartobj = 0;
774
775
776 for (s = slabinfo; s < slabinfo + slabs; s++) {
777 unsigned long long size;
778 unsigned long used;
779 unsigned long long wasted;
780 unsigned long long objwaste;
781 unsigned long percentage_partial_slabs;
782 unsigned long percentage_partial_objs;
783
784 if (!s->slabs || !s->objects)
785 continue;
786
787 used_slabs++;
788
789 size = slab_size(s);
790 used = s->objects * s->object_size;
791 wasted = size - used;
792 objwaste = s->slab_size - s->object_size;
793
794 percentage_partial_slabs = s->partial * 100 / s->slabs;
795 if (percentage_partial_slabs > 100)
796 percentage_partial_slabs = 100;
797
798 percentage_partial_objs = s->objects_partial * 100
799 / s->objects;
800
801 if (percentage_partial_objs > 100)
802 percentage_partial_objs = 100;
803
804 if (s->object_size < min_objsize)
805 min_objsize = s->object_size;
806 if (s->partial < min_partial)
807 min_partial = s->partial;
808 if (s->slabs < min_slabs)
809 min_slabs = s->slabs;
810 if (size < min_size)
811 min_size = size;
812 if (wasted < min_waste)
813 min_waste = wasted;
814 if (objwaste < min_objwaste)
815 min_objwaste = objwaste;
816 if (s->objects < min_objects)
817 min_objects = s->objects;
818 if (used < min_used)
819 min_used = used;
820 if (s->objects_partial < min_partobj)
821 min_partobj = s->objects_partial;
822 if (percentage_partial_slabs < min_ppart)
823 min_ppart = percentage_partial_slabs;
824 if (percentage_partial_objs < min_ppartobj)
825 min_ppartobj = percentage_partial_objs;
826 if (s->slab_size < min_memobj)
827 min_memobj = s->slab_size;
828
829 if (s->object_size > max_objsize)
830 max_objsize = s->object_size;
831 if (s->partial > max_partial)
832 max_partial = s->partial;
833 if (s->slabs > max_slabs)
834 max_slabs = s->slabs;
835 if (size > max_size)
836 max_size = size;
837 if (wasted > max_waste)
838 max_waste = wasted;
839 if (objwaste > max_objwaste)
840 max_objwaste = objwaste;
841 if (s->objects > max_objects)
842 max_objects = s->objects;
843 if (used > max_used)
844 max_used = used;
845 if (s->objects_partial > max_partobj)
846 max_partobj = s->objects_partial;
847 if (percentage_partial_slabs > max_ppart)
848 max_ppart = percentage_partial_slabs;
849 if (percentage_partial_objs > max_ppartobj)
850 max_ppartobj = percentage_partial_objs;
851 if (s->slab_size > max_memobj)
852 max_memobj = s->slab_size;
853
854 total_partial += s->partial;
855 total_slabs += s->slabs;
856 total_size += size;
857 total_waste += wasted;
858
859 total_objects += s->objects;
860 total_used += used;
861 total_partobj += s->objects_partial;
862 total_ppart += percentage_partial_slabs;
863 total_ppartobj += percentage_partial_objs;
864
865 total_objwaste += s->objects * objwaste;
866 total_objsize += s->objects * s->slab_size;
867 }
868
869 if (!total_objects) {
870 printf("No objects\n");
871 return;
872 }
873 if (!used_slabs) {
874 printf("No slabs\n");
875 return;
876 }
877
878 /* Per slab averages */
879 avg_partial = total_partial / used_slabs;
880 avg_slabs = total_slabs / used_slabs;
881 avg_size = total_size / used_slabs;
882 avg_waste = total_waste / used_slabs;
883
884 avg_objects = total_objects / used_slabs;
885 avg_used = total_used / used_slabs;
886 avg_partobj = total_partobj / used_slabs;
887 avg_ppart = total_ppart / used_slabs;
888 avg_ppartobj = total_ppartobj / used_slabs;
889
890 /* Per object object sizes */
891 avg_objsize = total_used / total_objects;
892 avg_objwaste = total_objwaste / total_objects;
893 avg_partobj = total_partobj * 100 / total_objects;
894 avg_memobj = total_objsize / total_objects;
895
896 printf("Slabcache Totals\n");
897 printf("----------------\n");
898 printf("Slabcaches : %3d Aliases : %3d->%-3d Active: %3d\n",
899 slabs, aliases, alias_targets, used_slabs);
900
901 store_size(b1, total_size);store_size(b2, total_waste);
902 store_size(b3, total_waste * 100 / total_used);
903 printf("Memory used: %6s # Loss : %6s MRatio:%6s%%\n", b1, b2, b3);
904
905 store_size(b1, total_objects);store_size(b2, total_partobj);
906 store_size(b3, total_partobj * 100 / total_objects);
907 printf("# Objects : %6s # PartObj: %6s ORatio:%6s%%\n", b1, b2, b3);
908
909 printf("\n");
910 printf("Per Cache Average Min Max Total\n");
911 printf("---------------------------------------------------------\n");
912
913 store_size(b1, avg_objects);store_size(b2, min_objects);
914 store_size(b3, max_objects);store_size(b4, total_objects);
915 printf("#Objects %10s %10s %10s %10s\n",
916 b1, b2, b3, b4);
917
918 store_size(b1, avg_slabs);store_size(b2, min_slabs);
919 store_size(b3, max_slabs);store_size(b4, total_slabs);
920 printf("#Slabs %10s %10s %10s %10s\n",
921 b1, b2, b3, b4);
922
923 store_size(b1, avg_partial);store_size(b2, min_partial);
924 store_size(b3, max_partial);store_size(b4, total_partial);
925 printf("#PartSlab %10s %10s %10s %10s\n",
926 b1, b2, b3, b4);
927 store_size(b1, avg_ppart);store_size(b2, min_ppart);
928 store_size(b3, max_ppart);
929 store_size(b4, total_partial * 100 / total_slabs);
930 printf("%%PartSlab%10s%% %10s%% %10s%% %10s%%\n",
931 b1, b2, b3, b4);
932
933 store_size(b1, avg_partobj);store_size(b2, min_partobj);
934 store_size(b3, max_partobj);
935 store_size(b4, total_partobj);
936 printf("PartObjs %10s %10s %10s %10s\n",
937 b1, b2, b3, b4);
938
939 store_size(b1, avg_ppartobj);store_size(b2, min_ppartobj);
940 store_size(b3, max_ppartobj);
941 store_size(b4, total_partobj * 100 / total_objects);
942 printf("%% PartObj%10s%% %10s%% %10s%% %10s%%\n",
943 b1, b2, b3, b4);
944
945 store_size(b1, avg_size);store_size(b2, min_size);
946 store_size(b3, max_size);store_size(b4, total_size);
947 printf("Memory %10s %10s %10s %10s\n",
948 b1, b2, b3, b4);
949
950 store_size(b1, avg_used);store_size(b2, min_used);
951 store_size(b3, max_used);store_size(b4, total_used);
952 printf("Used %10s %10s %10s %10s\n",
953 b1, b2, b3, b4);
954
955 store_size(b1, avg_waste);store_size(b2, min_waste);
956 store_size(b3, max_waste);store_size(b4, total_waste);
957 printf("Loss %10s %10s %10s %10s\n",
958 b1, b2, b3, b4);
959
960 printf("\n");
961 printf("Per Object Average Min Max\n");
962 printf("---------------------------------------------\n");
963
964 store_size(b1, avg_memobj);store_size(b2, min_memobj);
965 store_size(b3, max_memobj);
966 printf("Memory %10s %10s %10s\n",
967 b1, b2, b3);
968 store_size(b1, avg_objsize);store_size(b2, min_objsize);
969 store_size(b3, max_objsize);
970 printf("User %10s %10s %10s\n",
971 b1, b2, b3);
972
973 store_size(b1, avg_objwaste);store_size(b2, min_objwaste);
974 store_size(b3, max_objwaste);
975 printf("Loss %10s %10s %10s\n",
976 b1, b2, b3);
977}
978
979static void sort_slabs(void)
980{
981 struct slabinfo *s1,*s2;
982
983 for (s1 = slabinfo; s1 < slabinfo + slabs; s1++) {
984 for (s2 = s1 + 1; s2 < slabinfo + slabs; s2++) {
985 int result;
986
987 if (sort_size)
988 result = slab_size(s1) < slab_size(s2);
989 else if (sort_active)
990 result = slab_activity(s1) < slab_activity(s2);
991 else
992 result = strcasecmp(s1->name, s2->name);
993
994 if (show_inverted)
995 result = -result;
996
997 if (result > 0) {
998 struct slabinfo t;
999
1000 memcpy(&t, s1, sizeof(struct slabinfo));
1001 memcpy(s1, s2, sizeof(struct slabinfo));
1002 memcpy(s2, &t, sizeof(struct slabinfo));
1003 }
1004 }
1005 }
1006}
1007
1008static void sort_aliases(void)
1009{
1010 struct aliasinfo *a1,*a2;
1011
1012 for (a1 = aliasinfo; a1 < aliasinfo + aliases; a1++) {
1013 for (a2 = a1 + 1; a2 < aliasinfo + aliases; a2++) {
1014 char *n1, *n2;
1015
1016 n1 = a1->name;
1017 n2 = a2->name;
1018 if (show_alias && !show_inverted) {
1019 n1 = a1->ref;
1020 n2 = a2->ref;
1021 }
1022 if (strcasecmp(n1, n2) > 0) {
1023 struct aliasinfo t;
1024
1025 memcpy(&t, a1, sizeof(struct aliasinfo));
1026 memcpy(a1, a2, sizeof(struct aliasinfo));
1027 memcpy(a2, &t, sizeof(struct aliasinfo));
1028 }
1029 }
1030 }
1031}
1032
1033static void link_slabs(void)
1034{
1035 struct aliasinfo *a;
1036 struct slabinfo *s;
1037
1038 for (a = aliasinfo; a < aliasinfo + aliases; a++) {
1039
1040 for (s = slabinfo; s < slabinfo + slabs; s++)
1041 if (strcmp(a->ref, s->name) == 0) {
1042 a->slab = s;
1043 s->refs++;
1044 break;
1045 }
1046 if (s == slabinfo + slabs)
1047 fatal("Unresolved alias %s\n", a->ref);
1048 }
1049}
1050
1051static void alias(void)
1052{
1053 struct aliasinfo *a;
1054 char *active = NULL;
1055
1056 sort_aliases();
1057 link_slabs();
1058
1059 for(a = aliasinfo; a < aliasinfo + aliases; a++) {
1060
1061 if (!show_single_ref && a->slab->refs == 1)
1062 continue;
1063
1064 if (!show_inverted) {
1065 if (active) {
1066 if (strcmp(a->slab->name, active) == 0) {
1067 printf(" %s", a->name);
1068 continue;
1069 }
1070 }
1071 printf("\n%-12s <- %s", a->slab->name, a->name);
1072 active = a->slab->name;
1073 }
1074 else
1075 printf("%-20s -> %s\n", a->name, a->slab->name);
1076 }
1077 if (active)
1078 printf("\n");
1079}
1080
1081
1082static void rename_slabs(void)
1083{
1084 struct slabinfo *s;
1085 struct aliasinfo *a;
1086
1087 for (s = slabinfo; s < slabinfo + slabs; s++) {
1088 if (*s->name != ':')
1089 continue;
1090
1091 if (s->refs > 1 && !show_first_alias)
1092 continue;
1093
1094 a = find_one_alias(s);
1095
1096 if (a)
1097 s->name = a->name;
1098 else {
1099 s->name = "*";
1100 actual_slabs--;
1101 }
1102 }
1103}
1104
1105static int slab_mismatch(char *slab)
1106{
1107 return regexec(&pattern, slab, 0, NULL, 0);
1108}
1109
1110static void read_slab_dir(void)
1111{
1112 DIR *dir;
1113 struct dirent *de;
1114 struct slabinfo *slab = slabinfo;
1115 struct aliasinfo *alias = aliasinfo;
1116 char *p;
1117 char *t;
1118 int count;
1119
1120 if (chdir("/sys/kernel/slab") && chdir("/sys/slab"))
1121 fatal("SYSFS support for SLUB not active\n");
1122
1123 dir = opendir(".");
1124 while ((de = readdir(dir))) {
1125 if (de->d_name[0] == '.' ||
1126 (de->d_name[0] != ':' && slab_mismatch(de->d_name)))
1127 continue;
1128 switch (de->d_type) {
1129 case DT_LNK:
1130 alias->name = strdup(de->d_name);
1131 count = readlink(de->d_name, buffer, sizeof(buffer));
1132
1133 if (count < 0)
1134 fatal("Cannot read symlink %s\n", de->d_name);
1135
1136 buffer[count] = 0;
1137 p = buffer + count;
1138 while (p > buffer && p[-1] != '/')
1139 p--;
1140 alias->ref = strdup(p);
1141 alias++;
1142 break;
1143 case DT_DIR:
1144 if (chdir(de->d_name))
1145 fatal("Unable to access slab %s\n", slab->name);
1146 slab->name = strdup(de->d_name);
1147 slab->alias = 0;
1148 slab->refs = 0;
1149 slab->aliases = get_obj("aliases");
1150 slab->align = get_obj("align");
1151 slab->cache_dma = get_obj("cache_dma");
1152 slab->cpu_slabs = get_obj("cpu_slabs");
1153 slab->destroy_by_rcu = get_obj("destroy_by_rcu");
1154 slab->hwcache_align = get_obj("hwcache_align");
1155 slab->object_size = get_obj("object_size");
1156 slab->objects = get_obj("objects");
1157 slab->objects_partial = get_obj("objects_partial");
1158 slab->objects_total = get_obj("objects_total");
1159 slab->objs_per_slab = get_obj("objs_per_slab");
1160 slab->order = get_obj("order");
1161 slab->partial = get_obj("partial");
1162 slab->partial = get_obj_and_str("partial", &t);
1163 decode_numa_list(slab->numa_partial, t);
1164 free(t);
1165 slab->poison = get_obj("poison");
1166 slab->reclaim_account = get_obj("reclaim_account");
1167 slab->red_zone = get_obj("red_zone");
1168 slab->sanity_checks = get_obj("sanity_checks");
1169 slab->slab_size = get_obj("slab_size");
1170 slab->slabs = get_obj_and_str("slabs", &t);
1171 decode_numa_list(slab->numa, t);
1172 free(t);
1173 slab->store_user = get_obj("store_user");
1174 slab->trace = get_obj("trace");
1175 slab->alloc_fastpath = get_obj("alloc_fastpath");
1176 slab->alloc_slowpath = get_obj("alloc_slowpath");
1177 slab->free_fastpath = get_obj("free_fastpath");
1178 slab->free_slowpath = get_obj("free_slowpath");
1179 slab->free_frozen= get_obj("free_frozen");
1180 slab->free_add_partial = get_obj("free_add_partial");
1181 slab->free_remove_partial = get_obj("free_remove_partial");
1182 slab->alloc_from_partial = get_obj("alloc_from_partial");
1183 slab->alloc_slab = get_obj("alloc_slab");
1184 slab->alloc_refill = get_obj("alloc_refill");
1185 slab->free_slab = get_obj("free_slab");
1186 slab->cpuslab_flush = get_obj("cpuslab_flush");
1187 slab->deactivate_full = get_obj("deactivate_full");
1188 slab->deactivate_empty = get_obj("deactivate_empty");
1189 slab->deactivate_to_head = get_obj("deactivate_to_head");
1190 slab->deactivate_to_tail = get_obj("deactivate_to_tail");
1191 slab->deactivate_remote_frees = get_obj("deactivate_remote_frees");
1192 slab->order_fallback = get_obj("order_fallback");
1193 chdir("..");
1194 if (slab->name[0] == ':')
1195 alias_targets++;
1196 slab++;
1197 break;
1198 default :
1199 fatal("Unknown file type %lx\n", de->d_type);
1200 }
1201 }
1202 closedir(dir);
1203 slabs = slab - slabinfo;
1204 actual_slabs = slabs;
1205 aliases = alias - aliasinfo;
1206 if (slabs > MAX_SLABS)
1207 fatal("Too many slabs\n");
1208 if (aliases > MAX_ALIASES)
1209 fatal("Too many aliases\n");
1210}
1211
1212static void output_slabs(void)
1213{
1214 struct slabinfo *slab;
1215
1216 for (slab = slabinfo; slab < slabinfo + slabs; slab++) {
1217
1218 if (slab->alias)
1219 continue;
1220
1221
1222 if (show_numa)
1223 slab_numa(slab, 0);
1224 else if (show_track)
1225 show_tracking(slab);
1226 else if (validate)
1227 slab_validate(slab);
1228 else if (shrink)
1229 slab_shrink(slab);
1230 else if (set_debug)
1231 slab_debug(slab);
1232 else if (show_ops)
1233 ops(slab);
1234 else if (show_slab)
1235 slabcache(slab);
1236 else if (show_report)
1237 report(slab);
1238 }
1239}
1240
1241struct option opts[] = {
1242 { "aliases", 0, NULL, 'a' },
1243 { "activity", 0, NULL, 'A' },
1244 { "debug", 2, NULL, 'd' },
1245 { "display-activity", 0, NULL, 'D' },
1246 { "empty", 0, NULL, 'e' },
1247 { "first-alias", 0, NULL, 'f' },
1248 { "help", 0, NULL, 'h' },
1249 { "inverted", 0, NULL, 'i'},
1250 { "numa", 0, NULL, 'n' },
1251 { "ops", 0, NULL, 'o' },
1252 { "report", 0, NULL, 'r' },
1253 { "shrink", 0, NULL, 's' },
1254 { "slabs", 0, NULL, 'l' },
1255 { "track", 0, NULL, 't'},
1256 { "validate", 0, NULL, 'v' },
1257 { "zero", 0, NULL, 'z' },
1258 { "1ref", 0, NULL, '1'},
1259 { NULL, 0, NULL, 0 }
1260};
1261
1262int main(int argc, char *argv[])
1263{
1264 int c;
1265 int err;
1266 char *pattern_source;
1267
1268 page_size = getpagesize();
1269
1270 while ((c = getopt_long(argc, argv, "aAd::Defhil1noprstvzTS",
1271 opts, NULL)) != -1)
1272 switch (c) {
1273 case '1':
1274 show_single_ref = 1;
1275 break;
1276 case 'a':
1277 show_alias = 1;
1278 break;
1279 case 'A':
1280 sort_active = 1;
1281 break;
1282 case 'd':
1283 set_debug = 1;
1284 if (!debug_opt_scan(optarg))
1285 fatal("Invalid debug option '%s'\n", optarg);
1286 break;
1287 case 'D':
1288 show_activity = 1;
1289 break;
1290 case 'e':
1291 show_empty = 1;
1292 break;
1293 case 'f':
1294 show_first_alias = 1;
1295 break;
1296 case 'h':
1297 usage();
1298 return 0;
1299 case 'i':
1300 show_inverted = 1;
1301 break;
1302 case 'n':
1303 show_numa = 1;
1304 break;
1305 case 'o':
1306 show_ops = 1;
1307 break;
1308 case 'r':
1309 show_report = 1;
1310 break;
1311 case 's':
1312 shrink = 1;
1313 break;
1314 case 'l':
1315 show_slab = 1;
1316 break;
1317 case 't':
1318 show_track = 1;
1319 break;
1320 case 'v':
1321 validate = 1;
1322 break;
1323 case 'z':
1324 skip_zero = 0;
1325 break;
1326 case 'T':
1327 show_totals = 1;
1328 break;
1329 case 'S':
1330 sort_size = 1;
1331 break;
1332
1333 default:
1334 fatal("%s: Invalid option '%c'\n", argv[0], optopt);
1335
1336 }
1337
1338 if (!show_slab && !show_alias && !show_track && !show_report
1339 && !validate && !shrink && !set_debug && !show_ops)
1340 show_slab = 1;
1341
1342 if (argc > optind)
1343 pattern_source = argv[optind];
1344 else
1345 pattern_source = ".*";
1346
1347 err = regcomp(&pattern, pattern_source, REG_ICASE|REG_NOSUB);
1348 if (err)
1349 fatal("%s: Invalid pattern '%s' code %d\n",
1350 argv[0], pattern_source, err);
1351 read_slab_dir();
1352 if (show_alias)
1353 alias();
1354 else
1355 if (show_totals)
1356 totals();
1357 else {
1358 link_slabs();
1359 rename_slabs();
1360 sort_slabs();
1361 output_slabs();
1362 }
1363 return 0;
1364}
diff --git a/tools/testing/ktest/compare-ktest-sample.pl b/tools/testing/ktest/compare-ktest-sample.pl
new file mode 100755
index 000000000000..9a571e71683c
--- /dev/null
+++ b/tools/testing/ktest/compare-ktest-sample.pl
@@ -0,0 +1,30 @@
1#!/usr/bin/perl
2
3open (IN,"ktest.pl");
4while (<IN>) {
5 if (/\$opt\{"?([A-Z].*?)(\[.*\])?"?\}/ ||
6 /set_test_option\("(.*?)"/) {
7 $opt{$1} = 1;
8 }
9}
10close IN;
11
12open (IN, "sample.conf");
13while (<IN>) {
14 if (/^\s*#?\s*(\S+)\s*=/) {
15 $samp{$1} = 1;
16 }
17}
18close IN;
19
20foreach $opt (keys %opt) {
21 if (!defined($samp{$opt})) {
22 print "opt = $opt\n";
23 }
24}
25
26foreach $samp (keys %samp) {
27 if (!defined($opt{$samp})) {
28 print "samp = $samp\n";
29 }
30}
diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl
new file mode 100755
index 000000000000..cef28e6632b9
--- /dev/null
+++ b/tools/testing/ktest/ktest.pl
@@ -0,0 +1,2264 @@
1#!/usr/bin/perl -w
2#
3# Copyright 2010 - Steven Rostedt <srostedt@redhat.com>, Red Hat Inc.
4# Licensed under the terms of the GNU GPL License version 2
5#
6
7use strict;
8use IPC::Open2;
9use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK);
10use File::Path qw(mkpath);
11use File::Copy qw(cp);
12use FileHandle;
13
14my $VERSION = "0.2";
15
16$| = 1;
17
18my %opt;
19my %repeat_tests;
20my %repeats;
21my %default;
22
23#default opts
24$default{"NUM_TESTS"} = 1;
25$default{"REBOOT_TYPE"} = "grub";
26$default{"TEST_TYPE"} = "test";
27$default{"BUILD_TYPE"} = "randconfig";
28$default{"MAKE_CMD"} = "make";
29$default{"TIMEOUT"} = 120;
30$default{"TMP_DIR"} = "/tmp/ktest";
31$default{"SLEEP_TIME"} = 60; # sleep time between tests
32$default{"BUILD_NOCLEAN"} = 0;
33$default{"REBOOT_ON_ERROR"} = 0;
34$default{"POWEROFF_ON_ERROR"} = 0;
35$default{"REBOOT_ON_SUCCESS"} = 1;
36$default{"POWEROFF_ON_SUCCESS"} = 0;
37$default{"BUILD_OPTIONS"} = "";
38$default{"BISECT_SLEEP_TIME"} = 60; # sleep time between bisects
39$default{"PATCHCHECK_SLEEP_TIME"} = 60; # sleep time between patch checks
40$default{"CLEAR_LOG"} = 0;
41$default{"BISECT_MANUAL"} = 0;
42$default{"BISECT_SKIP"} = 1;
43$default{"SUCCESS_LINE"} = "login:";
44$default{"BOOTED_TIMEOUT"} = 1;
45$default{"DIE_ON_FAILURE"} = 1;
46$default{"SSH_EXEC"} = "ssh \$SSH_USER\@\$MACHINE \$SSH_COMMAND";
47$default{"SCP_TO_TARGET"} = "scp \$SRC_FILE \$SSH_USER\@\$MACHINE:\$DST_FILE";
48$default{"REBOOT"} = "ssh \$SSH_USER\@\$MACHINE reboot";
49$default{"STOP_AFTER_SUCCESS"} = 10;
50$default{"STOP_AFTER_FAILURE"} = 60;
51$default{"STOP_TEST_AFTER"} = 600;
52$default{"LOCALVERSION"} = "-test";
53
54my $ktest_config;
55my $version;
56my $machine;
57my $ssh_user;
58my $tmpdir;
59my $builddir;
60my $outputdir;
61my $output_config;
62my $test_type;
63my $build_type;
64my $build_options;
65my $reboot_type;
66my $reboot_script;
67my $power_cycle;
68my $reboot;
69my $reboot_on_error;
70my $poweroff_on_error;
71my $die_on_failure;
72my $powercycle_after_reboot;
73my $poweroff_after_halt;
74my $ssh_exec;
75my $scp_to_target;
76my $power_off;
77my $grub_menu;
78my $grub_number;
79my $target;
80my $make;
81my $post_install;
82my $noclean;
83my $minconfig;
84my $addconfig;
85my $in_bisect = 0;
86my $bisect_bad = "";
87my $reverse_bisect;
88my $bisect_manual;
89my $bisect_skip;
90my $in_patchcheck = 0;
91my $run_test;
92my $redirect;
93my $buildlog;
94my $dmesg;
95my $monitor_fp;
96my $monitor_pid;
97my $monitor_cnt = 0;
98my $sleep_time;
99my $bisect_sleep_time;
100my $patchcheck_sleep_time;
101my $store_failures;
102my $timeout;
103my $booted_timeout;
104my $console;
105my $success_line;
106my $stop_after_success;
107my $stop_after_failure;
108my $stop_test_after;
109my $build_target;
110my $target_image;
111my $localversion;
112my $iteration = 0;
113my $successes = 0;
114
115my %entered_configs;
116my %config_help;
117my %variable;
118
119$config_help{"MACHINE"} = << "EOF"
120 The machine hostname that you will test.
121EOF
122 ;
123$config_help{"SSH_USER"} = << "EOF"
124 The box is expected to have ssh on normal bootup, provide the user
125 (most likely root, since you need privileged operations)
126EOF
127 ;
128$config_help{"BUILD_DIR"} = << "EOF"
129 The directory that contains the Linux source code (full path).
130EOF
131 ;
132$config_help{"OUTPUT_DIR"} = << "EOF"
133 The directory that the objects will be built (full path).
134 (can not be same as BUILD_DIR)
135EOF
136 ;
137$config_help{"BUILD_TARGET"} = << "EOF"
138 The location of the compiled file to copy to the target.
139 (relative to OUTPUT_DIR)
140EOF
141 ;
142$config_help{"TARGET_IMAGE"} = << "EOF"
143 The place to put your image on the test machine.
144EOF
145 ;
146$config_help{"POWER_CYCLE"} = << "EOF"
147 A script or command to reboot the box.
148
149 Here is a digital loggers power switch example
150 POWER_CYCLE = wget --no-proxy -O /dev/null -q --auth-no-challenge 'http://admin:admin\@power/outlet?5=CCL'
151
152 Here is an example to reboot a virtual box on the current host
153 with the name "Guest".
154 POWER_CYCLE = virsh destroy Guest; sleep 5; virsh start Guest
155EOF
156 ;
157$config_help{"CONSOLE"} = << "EOF"
158 The script or command that reads the console
159
160 If you use ttywatch server, something like the following would work.
161CONSOLE = nc -d localhost 3001
162
163 For a virtual machine with guest name "Guest".
164CONSOLE = virsh console Guest
165EOF
166 ;
167$config_help{"LOCALVERSION"} = << "EOF"
168 Required version ending to differentiate the test
169 from other linux builds on the system.
170EOF
171 ;
172$config_help{"REBOOT_TYPE"} = << "EOF"
173 Way to reboot the box to the test kernel.
174 Only valid options so far are "grub" and "script".
175
176 If you specify grub, it will assume grub version 1
177 and will search in /boot/grub/menu.lst for the title \$GRUB_MENU
178 and select that target to reboot to the kernel. If this is not
179 your setup, then specify "script" and have a command or script
180 specified in REBOOT_SCRIPT to boot to the target.
181
182 The entry in /boot/grub/menu.lst must be entered in manually.
183 The test will not modify that file.
184EOF
185 ;
186$config_help{"GRUB_MENU"} = << "EOF"
187 The grub title name for the test kernel to boot
188 (Only mandatory if REBOOT_TYPE = grub)
189
190 Note, ktest.pl will not update the grub menu.lst, you need to
191 manually add an option for the test. ktest.pl will search
192 the grub menu.lst for this option to find what kernel to
193 reboot into.
194
195 For example, if in the /boot/grub/menu.lst the test kernel title has:
196 title Test Kernel
197 kernel vmlinuz-test
198 GRUB_MENU = Test Kernel
199EOF
200 ;
201$config_help{"REBOOT_SCRIPT"} = << "EOF"
202 A script to reboot the target into the test kernel
203 (Only mandatory if REBOOT_TYPE = script)
204EOF
205 ;
206
207
208sub get_ktest_config {
209 my ($config) = @_;
210
211 return if (defined($opt{$config}));
212
213 if (defined($config_help{$config})) {
214 print "\n";
215 print $config_help{$config};
216 }
217
218 for (;;) {
219 print "$config = ";
220 if (defined($default{$config})) {
221 print "\[$default{$config}\] ";
222 }
223 $entered_configs{$config} = <STDIN>;
224 $entered_configs{$config} =~ s/^\s*(.*\S)\s*$/$1/;
225 if ($entered_configs{$config} =~ /^\s*$/) {
226 if ($default{$config}) {
227 $entered_configs{$config} = $default{$config};
228 } else {
229 print "Your answer can not be blank\n";
230 next;
231 }
232 }
233 last;
234 }
235}
236
237sub get_ktest_configs {
238 get_ktest_config("MACHINE");
239 get_ktest_config("SSH_USER");
240 get_ktest_config("BUILD_DIR");
241 get_ktest_config("OUTPUT_DIR");
242 get_ktest_config("BUILD_TARGET");
243 get_ktest_config("TARGET_IMAGE");
244 get_ktest_config("POWER_CYCLE");
245 get_ktest_config("CONSOLE");
246 get_ktest_config("LOCALVERSION");
247
248 my $rtype = $opt{"REBOOT_TYPE"};
249
250 if (!defined($rtype)) {
251 if (!defined($opt{"GRUB_MENU"})) {
252 get_ktest_config("REBOOT_TYPE");
253 $rtype = $entered_configs{"REBOOT_TYPE"};
254 } else {
255 $rtype = "grub";
256 }
257 }
258
259 if ($rtype eq "grub") {
260 get_ktest_config("GRUB_MENU");
261 } else {
262 get_ktest_config("REBOOT_SCRIPT");
263 }
264}
265
266sub process_variables {
267 my ($value) = @_;
268 my $retval = "";
269
270 # We want to check for '\', and it is just easier
271 # to check the previous characet of '$' and not need
272 # to worry if '$' is the first character. By adding
273 # a space to $value, we can just check [^\\]\$ and
274 # it will still work.
275 $value = " $value";
276
277 while ($value =~ /(.*?[^\\])\$\{(.*?)\}(.*)/) {
278 my $begin = $1;
279 my $var = $2;
280 my $end = $3;
281 # append beginning of value to retval
282 $retval = "$retval$begin";
283 if (defined($variable{$var})) {
284 $retval = "$retval$variable{$var}";
285 } else {
286 # put back the origin piece.
287 $retval = "$retval\$\{$var\}";
288 }
289 $value = $end;
290 }
291 $retval = "$retval$value";
292
293 # remove the space added in the beginning
294 $retval =~ s/ //;
295
296 return "$retval"
297}
298
299sub set_value {
300 my ($lvalue, $rvalue) = @_;
301
302 if (defined($opt{$lvalue})) {
303 die "Error: Option $lvalue defined more than once!\n";
304 }
305 if ($rvalue =~ /^\s*$/) {
306 delete $opt{$lvalue};
307 } else {
308 $rvalue = process_variables($rvalue);
309 $opt{$lvalue} = $rvalue;
310 }
311}
312
313sub set_variable {
314 my ($lvalue, $rvalue) = @_;
315
316 if ($rvalue =~ /^\s*$/) {
317 delete $variable{$lvalue};
318 } else {
319 $rvalue = process_variables($rvalue);
320 $variable{$lvalue} = $rvalue;
321 }
322}
323
324sub read_config {
325 my ($config) = @_;
326
327 open(IN, $config) || die "can't read file $config";
328
329 my $name = $config;
330 $name =~ s,.*/(.*),$1,;
331
332 my $test_num = 0;
333 my $default = 1;
334 my $repeat = 1;
335 my $num_tests_set = 0;
336 my $skip = 0;
337 my $rest;
338
339 while (<IN>) {
340
341 # ignore blank lines and comments
342 next if (/^\s*$/ || /\s*\#/);
343
344 if (/^\s*TEST_START(.*)/) {
345
346 $rest = $1;
347
348 if ($num_tests_set) {
349 die "$name: $.: Can not specify both NUM_TESTS and TEST_START\n";
350 }
351
352 my $old_test_num = $test_num;
353 my $old_repeat = $repeat;
354
355 $test_num += $repeat;
356 $default = 0;
357 $repeat = 1;
358
359 if ($rest =~ /\s+SKIP(.*)/) {
360 $rest = $1;
361 $skip = 1;
362 } else {
363 $skip = 0;
364 }
365
366 if ($rest =~ /\s+ITERATE\s+(\d+)(.*)$/) {
367 $repeat = $1;
368 $rest = $2;
369 $repeat_tests{"$test_num"} = $repeat;
370 }
371
372 if ($rest =~ /\s+SKIP(.*)/) {
373 $rest = $1;
374 $skip = 1;
375 }
376
377 if ($rest !~ /^\s*$/) {
378 die "$name: $.: Gargbage found after TEST_START\n$_";
379 }
380
381 if ($skip) {
382 $test_num = $old_test_num;
383 $repeat = $old_repeat;
384 }
385
386 } elsif (/^\s*DEFAULTS(.*)$/) {
387 $default = 1;
388
389 $rest = $1;
390
391 if ($rest =~ /\s+SKIP(.*)/) {
392 $rest = $1;
393 $skip = 1;
394 } else {
395 $skip = 0;
396 }
397
398 if ($rest !~ /^\s*$/) {
399 die "$name: $.: Gargbage found after DEFAULTS\n$_";
400 }
401
402 } elsif (/^\s*([A-Z_\[\]\d]+)\s*=\s*(.*?)\s*$/) {
403
404 next if ($skip);
405
406 my $lvalue = $1;
407 my $rvalue = $2;
408
409 if (!$default &&
410 ($lvalue eq "NUM_TESTS" ||
411 $lvalue eq "LOG_FILE" ||
412 $lvalue eq "CLEAR_LOG")) {
413 die "$name: $.: $lvalue must be set in DEFAULTS section\n";
414 }
415
416 if ($lvalue eq "NUM_TESTS") {
417 if ($test_num) {
418 die "$name: $.: Can not specify both NUM_TESTS and TEST_START\n";
419 }
420 if (!$default) {
421 die "$name: $.: NUM_TESTS must be set in default section\n";
422 }
423 $num_tests_set = 1;
424 }
425
426 if ($default || $lvalue =~ /\[\d+\]$/) {
427 set_value($lvalue, $rvalue);
428 } else {
429 my $val = "$lvalue\[$test_num\]";
430 set_value($val, $rvalue);
431
432 if ($repeat > 1) {
433 $repeats{$val} = $repeat;
434 }
435 }
436 } elsif (/^\s*([A-Z_\[\]\d]+)\s*:=\s*(.*?)\s*$/) {
437 next if ($skip);
438
439 my $lvalue = $1;
440 my $rvalue = $2;
441
442 # process config variables.
443 # Config variables are only active while reading the
444 # config and can be defined anywhere. They also ignore
445 # TEST_START and DEFAULTS, but are skipped if they are in
446 # on of these sections that have SKIP defined.
447 # The save variable can be
448 # defined multiple times and the new one simply overrides
449 # the prevous one.
450 set_variable($lvalue, $rvalue);
451
452 } else {
453 die "$name: $.: Garbage found in config\n$_";
454 }
455 }
456
457 close(IN);
458
459 if ($test_num) {
460 $test_num += $repeat - 1;
461 $opt{"NUM_TESTS"} = $test_num;
462 }
463
464 # make sure we have all mandatory configs
465 get_ktest_configs;
466
467 # set any defaults
468
469 foreach my $default (keys %default) {
470 if (!defined($opt{$default})) {
471 $opt{$default} = $default{$default};
472 }
473 }
474}
475
476sub _logit {
477 if (defined($opt{"LOG_FILE"})) {
478 open(OUT, ">> $opt{LOG_FILE}") or die "Can't write to $opt{LOG_FILE}";
479 print OUT @_;
480 close(OUT);
481 }
482}
483
484sub logit {
485 if (defined($opt{"LOG_FILE"})) {
486 _logit @_;
487 } else {
488 print @_;
489 }
490}
491
492sub doprint {
493 print @_;
494 _logit @_;
495}
496
497sub run_command;
498
499sub reboot {
500 # try to reboot normally
501 if (run_command $reboot) {
502 if (defined($powercycle_after_reboot)) {
503 sleep $powercycle_after_reboot;
504 run_command "$power_cycle";
505 }
506 } else {
507 # nope? power cycle it.
508 run_command "$power_cycle";
509 }
510}
511
512sub do_not_reboot {
513 my $i = $iteration;
514
515 return $test_type eq "build" ||
516 ($test_type eq "patchcheck" && $opt{"PATCHCHECK_TYPE[$i]"} eq "build") ||
517 ($test_type eq "bisect" && $opt{"BISECT_TYPE[$i]"} eq "build");
518}
519
520sub dodie {
521 doprint "CRITICAL FAILURE... ", @_, "\n";
522
523 my $i = $iteration;
524
525 if ($reboot_on_error && !do_not_reboot) {
526
527 doprint "REBOOTING\n";
528 reboot;
529
530 } elsif ($poweroff_on_error && defined($power_off)) {
531 doprint "POWERING OFF\n";
532 `$power_off`;
533 }
534
535 if (defined($opt{"LOG_FILE"})) {
536 print " See $opt{LOG_FILE} for more info.\n";
537 }
538
539 die @_, "\n";
540}
541
542sub open_console {
543 my ($fp) = @_;
544
545 my $flags;
546
547 my $pid = open($fp, "$console|") or
548 dodie "Can't open console $console";
549
550 $flags = fcntl($fp, F_GETFL, 0) or
551 dodie "Can't get flags for the socket: $!";
552 $flags = fcntl($fp, F_SETFL, $flags | O_NONBLOCK) or
553 dodie "Can't set flags for the socket: $!";
554
555 return $pid;
556}
557
558sub close_console {
559 my ($fp, $pid) = @_;
560
561 doprint "kill child process $pid\n";
562 kill 2, $pid;
563
564 print "closing!\n";
565 close($fp);
566}
567
568sub start_monitor {
569 if ($monitor_cnt++) {
570 return;
571 }
572 $monitor_fp = \*MONFD;
573 $monitor_pid = open_console $monitor_fp;
574
575 return;
576
577 open(MONFD, "Stop perl from warning about single use of MONFD");
578}
579
580sub end_monitor {
581 if (--$monitor_cnt) {
582 return;
583 }
584 close_console($monitor_fp, $monitor_pid);
585}
586
587sub wait_for_monitor {
588 my ($time) = @_;
589 my $line;
590
591 doprint "** Wait for monitor to settle down **\n";
592
593 # read the monitor and wait for the system to calm down
594 do {
595 $line = wait_for_input($monitor_fp, $time);
596 print "$line" if (defined($line));
597 } while (defined($line));
598 print "** Monitor flushed **\n";
599}
600
601sub fail {
602
603 if ($die_on_failure) {
604 dodie @_;
605 }
606
607 doprint "FAILED\n";
608
609 my $i = $iteration;
610
611 # no need to reboot for just building.
612 if (!do_not_reboot) {
613 doprint "REBOOTING\n";
614 reboot;
615 start_monitor;
616 wait_for_monitor $sleep_time;
617 end_monitor;
618 }
619
620 doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
621 doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
622 doprint "KTEST RESULT: TEST $i Failed: ", @_, "\n";
623 doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
624 doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
625
626 return 1 if (!defined($store_failures));
627
628 my @t = localtime;
629 my $date = sprintf "%04d%02d%02d%02d%02d%02d",
630 1900+$t[5],$t[4],$t[3],$t[2],$t[1],$t[0];
631
632 my $type = $build_type;
633 if ($type =~ /useconfig/) {
634 $type = "useconfig";
635 }
636
637 my $dir = "$machine-$test_type-$type-fail-$date";
638 my $faildir = "$store_failures/$dir";
639
640 if (!-d $faildir) {
641 mkpath($faildir) or
642 die "can't create $faildir";
643 }
644 if (-f "$output_config") {
645 cp "$output_config", "$faildir/config" or
646 die "failed to copy .config";
647 }
648 if (-f $buildlog) {
649 cp $buildlog, "$faildir/buildlog" or
650 die "failed to move $buildlog";
651 }
652 if (-f $dmesg) {
653 cp $dmesg, "$faildir/dmesg" or
654 die "failed to move $dmesg";
655 }
656
657 doprint "*** Saved info to $faildir ***\n";
658
659 return 1;
660}
661
662sub run_command {
663 my ($command) = @_;
664 my $dolog = 0;
665 my $dord = 0;
666 my $pid;
667
668 $command =~ s/\$SSH_USER/$ssh_user/g;
669 $command =~ s/\$MACHINE/$machine/g;
670
671 doprint("$command ... ");
672
673 $pid = open(CMD, "$command 2>&1 |") or
674 (fail "unable to exec $command" and return 0);
675
676 if (defined($opt{"LOG_FILE"})) {
677 open(LOG, ">>$opt{LOG_FILE}") or
678 dodie "failed to write to log";
679 $dolog = 1;
680 }
681
682 if (defined($redirect)) {
683 open (RD, ">$redirect") or
684 dodie "failed to write to redirect $redirect";
685 $dord = 1;
686 }
687
688 while (<CMD>) {
689 print LOG if ($dolog);
690 print RD if ($dord);
691 }
692
693 waitpid($pid, 0);
694 my $failed = $?;
695
696 close(CMD);
697 close(LOG) if ($dolog);
698 close(RD) if ($dord);
699
700 if ($failed) {
701 doprint "FAILED!\n";
702 } else {
703 doprint "SUCCESS\n";
704 }
705
706 return !$failed;
707}
708
709sub run_ssh {
710 my ($cmd) = @_;
711 my $cp_exec = $ssh_exec;
712
713 $cp_exec =~ s/\$SSH_COMMAND/$cmd/g;
714 return run_command "$cp_exec";
715}
716
717sub run_scp {
718 my ($src, $dst) = @_;
719 my $cp_scp = $scp_to_target;
720
721 $cp_scp =~ s/\$SRC_FILE/$src/g;
722 $cp_scp =~ s/\$DST_FILE/$dst/g;
723
724 return run_command "$cp_scp";
725}
726
727sub get_grub_index {
728
729 if ($reboot_type ne "grub") {
730 return;
731 }
732 return if (defined($grub_number));
733
734 doprint "Find grub menu ... ";
735 $grub_number = -1;
736
737 my $ssh_grub = $ssh_exec;
738 $ssh_grub =~ s,\$SSH_COMMAND,cat /boot/grub/menu.lst,g;
739
740 open(IN, "$ssh_grub |")
741 or die "unable to get menu.lst";
742
743 while (<IN>) {
744 if (/^\s*title\s+$grub_menu\s*$/) {
745 $grub_number++;
746 last;
747 } elsif (/^\s*title\s/) {
748 $grub_number++;
749 }
750 }
751 close(IN);
752
753 die "Could not find '$grub_menu' in /boot/grub/menu on $machine"
754 if ($grub_number < 0);
755 doprint "$grub_number\n";
756}
757
758sub wait_for_input
759{
760 my ($fp, $time) = @_;
761 my $rin;
762 my $ready;
763 my $line;
764 my $ch;
765
766 if (!defined($time)) {
767 $time = $timeout;
768 }
769
770 $rin = '';
771 vec($rin, fileno($fp), 1) = 1;
772 $ready = select($rin, undef, undef, $time);
773
774 $line = "";
775
776 # try to read one char at a time
777 while (sysread $fp, $ch, 1) {
778 $line .= $ch;
779 last if ($ch eq "\n");
780 }
781
782 if (!length($line)) {
783 return undef;
784 }
785
786 return $line;
787}
788
789sub reboot_to {
790 if ($reboot_type eq "grub") {
791 run_ssh "'(echo \"savedefault --default=$grub_number --once\" | grub --batch && reboot)'";
792 return;
793 }
794
795 run_command "$reboot_script";
796}
797
798sub get_sha1 {
799 my ($commit) = @_;
800
801 doprint "git rev-list --max-count=1 $commit ... ";
802 my $sha1 = `git rev-list --max-count=1 $commit`;
803 my $ret = $?;
804
805 logit $sha1;
806
807 if ($ret) {
808 doprint "FAILED\n";
809 dodie "Failed to get git $commit";
810 }
811
812 print "SUCCESS\n";
813
814 chomp $sha1;
815
816 return $sha1;
817}
818
819sub monitor {
820 my $booted = 0;
821 my $bug = 0;
822 my $skip_call_trace = 0;
823 my $loops;
824
825 wait_for_monitor 5;
826
827 my $line;
828 my $full_line = "";
829
830 open(DMESG, "> $dmesg") or
831 die "unable to write to $dmesg";
832
833 reboot_to;
834
835 my $success_start;
836 my $failure_start;
837 my $monitor_start = time;
838 my $done = 0;
839
840 while (!$done) {
841
842 if ($booted) {
843 $line = wait_for_input($monitor_fp, $booted_timeout);
844 } else {
845 $line = wait_for_input($monitor_fp);
846 }
847
848 last if (!defined($line));
849
850 doprint $line;
851 print DMESG $line;
852
853 # we are not guaranteed to get a full line
854 $full_line .= $line;
855
856 if ($full_line =~ /$success_line/) {
857 $booted = 1;
858 $success_start = time;
859 }
860
861 if ($booted && defined($stop_after_success) &&
862 $stop_after_success >= 0) {
863 my $now = time;
864 if ($now - $success_start >= $stop_after_success) {
865 doprint "Test forced to stop after $stop_after_success seconds after success\n";
866 last;
867 }
868 }
869
870 if ($full_line =~ /\[ backtrace testing \]/) {
871 $skip_call_trace = 1;
872 }
873
874 if ($full_line =~ /call trace:/i) {
875 if (!$bug && !$skip_call_trace) {
876 $bug = 1;
877 $failure_start = time;
878 }
879 }
880
881 if ($bug && defined($stop_after_failure) &&
882 $stop_after_failure >= 0) {
883 my $now = time;
884 if ($now - $failure_start >= $stop_after_failure) {
885 doprint "Test forced to stop after $stop_after_failure seconds after failure\n";
886 last;
887 }
888 }
889
890 if ($full_line =~ /\[ end of backtrace testing \]/) {
891 $skip_call_trace = 0;
892 }
893
894 if ($full_line =~ /Kernel panic -/) {
895 $failure_start = time;
896 $bug = 1;
897 }
898
899 if ($line =~ /\n/) {
900 $full_line = "";
901 }
902
903 if ($stop_test_after > 0 && !$booted && !$bug) {
904 if (time - $monitor_start > $stop_test_after) {
905 doprint "STOP_TEST_AFTER ($stop_test_after seconds) timed out\n";
906 $done = 1;
907 }
908 }
909 }
910
911 close(DMESG);
912
913 if ($bug) {
914 return 0 if ($in_bisect);
915 fail "failed - got a bug report" and return 0;
916 }
917
918 if (!$booted) {
919 return 0 if ($in_bisect);
920 fail "failed - never got a boot prompt." and return 0;
921 }
922
923 return 1;
924}
925
926sub install {
927
928 run_scp "$outputdir/$build_target", "$target_image" or
929 dodie "failed to copy image";
930
931 my $install_mods = 0;
932
933 # should we process modules?
934 $install_mods = 0;
935 open(IN, "$output_config") or dodie("Can't read config file");
936 while (<IN>) {
937 if (/CONFIG_MODULES(=y)?/) {
938 $install_mods = 1 if (defined($1));
939 last;
940 }
941 }
942 close(IN);
943
944 if (!$install_mods) {
945 doprint "No modules needed\n";
946 return;
947 }
948
949 run_command "$make INSTALL_MOD_PATH=$tmpdir modules_install" or
950 dodie "Failed to install modules";
951
952 my $modlib = "/lib/modules/$version";
953 my $modtar = "ktest-mods.tar.bz2";
954
955 run_ssh "rm -rf $modlib" or
956 dodie "failed to remove old mods: $modlib";
957
958 # would be nice if scp -r did not follow symbolic links
959 run_command "cd $tmpdir && tar -cjf $modtar lib/modules/$version" or
960 dodie "making tarball";
961
962 run_scp "$tmpdir/$modtar", "/tmp" or
963 dodie "failed to copy modules";
964
965 unlink "$tmpdir/$modtar";
966
967 run_ssh "'(cd / && tar xf /tmp/$modtar)'" or
968 dodie "failed to tar modules";
969
970 run_ssh "rm -f /tmp/$modtar";
971
972 return if (!defined($post_install));
973
974 my $cp_post_install = $post_install;
975 $cp_post_install =~ s/\$KERNEL_VERSION/$version/g;
976 run_command "$cp_post_install" or
977 dodie "Failed to run post install";
978}
979
980sub check_buildlog {
981 my ($patch) = @_;
982
983 my @files = `git show $patch | diffstat -l`;
984
985 open(IN, "git show $patch |") or
986 dodie "failed to show $patch";
987 while (<IN>) {
988 if (m,^--- a/(.*),) {
989 chomp $1;
990 $files[$#files] = $1;
991 }
992 }
993 close(IN);
994
995 open(IN, $buildlog) or dodie "Can't open $buildlog";
996 while (<IN>) {
997 if (/^\s*(.*?):.*(warning|error)/) {
998 my $err = $1;
999 foreach my $file (@files) {
1000 my $fullpath = "$builddir/$file";
1001 if ($file eq $err || $fullpath eq $err) {
1002 fail "$file built with warnings" and return 0;
1003 }
1004 }
1005 }
1006 }
1007 close(IN);
1008
1009 return 1;
1010}
1011
1012sub make_oldconfig {
1013 my ($defconfig) = @_;
1014
1015 if (!run_command "$defconfig $make oldnoconfig") {
1016 # Perhaps oldnoconfig doesn't exist in this version of the kernel
1017 # try a yes '' | oldconfig
1018 doprint "oldnoconfig failed, trying yes '' | make oldconfig\n";
1019 run_command "yes '' | $defconfig $make oldconfig" or
1020 dodie "failed make config oldconfig";
1021 }
1022}
1023
1024sub build {
1025 my ($type) = @_;
1026 my $defconfig = "";
1027
1028 unlink $buildlog;
1029
1030 if ($type =~ /^useconfig:(.*)/) {
1031 run_command "cp $1 $output_config" or
1032 dodie "could not copy $1 to .config";
1033
1034 $type = "oldconfig";
1035 }
1036
1037 # old config can ask questions
1038 if ($type eq "oldconfig") {
1039 $type = "oldnoconfig";
1040
1041 # allow for empty configs
1042 run_command "touch $output_config";
1043
1044 run_command "mv $output_config $outputdir/config_temp" or
1045 dodie "moving .config";
1046
1047 if (!$noclean && !run_command "$make mrproper") {
1048 dodie "make mrproper";
1049 }
1050
1051 run_command "mv $outputdir/config_temp $output_config" or
1052 dodie "moving config_temp";
1053
1054 } elsif (!$noclean) {
1055 unlink "$output_config";
1056 run_command "$make mrproper" or
1057 dodie "make mrproper";
1058 }
1059
1060 # add something to distinguish this build
1061 open(OUT, "> $outputdir/localversion") or dodie("Can't make localversion file");
1062 print OUT "$localversion\n";
1063 close(OUT);
1064
1065 if (defined($minconfig)) {
1066 $defconfig = "KCONFIG_ALLCONFIG=$minconfig";
1067 }
1068
1069 if ($type eq "oldnoconfig") {
1070 make_oldconfig $defconfig;
1071 } else {
1072 run_command "$defconfig $make $type" or
1073 dodie "failed make config";
1074 }
1075
1076 $redirect = "$buildlog";
1077 if (!run_command "$make $build_options") {
1078 undef $redirect;
1079 # bisect may need this to pass
1080 return 0 if ($in_bisect);
1081 fail "failed build" and return 0;
1082 }
1083 undef $redirect;
1084
1085 return 1;
1086}
1087
1088sub halt {
1089 if (!run_ssh "halt" or defined($power_off)) {
1090 if (defined($poweroff_after_halt)) {
1091 sleep $poweroff_after_halt;
1092 run_command "$power_off";
1093 }
1094 } else {
1095 # nope? the zap it!
1096 run_command "$power_off";
1097 }
1098}
1099
1100sub success {
1101 my ($i) = @_;
1102
1103 $successes++;
1104
1105 doprint "\n\n*******************************************\n";
1106 doprint "*******************************************\n";
1107 doprint "KTEST RESULT: TEST $i SUCCESS!!!! **\n";
1108 doprint "*******************************************\n";
1109 doprint "*******************************************\n";
1110
1111 if ($i != $opt{"NUM_TESTS"} && !do_not_reboot) {
1112 doprint "Reboot and wait $sleep_time seconds\n";
1113 reboot;
1114 start_monitor;
1115 wait_for_monitor $sleep_time;
1116 end_monitor;
1117 }
1118}
1119
1120sub get_version {
1121 # get the release name
1122 doprint "$make kernelrelease ... ";
1123 $version = `$make kernelrelease | tail -1`;
1124 chomp($version);
1125 doprint "$version\n";
1126}
1127
1128sub answer_bisect {
1129 for (;;) {
1130 doprint "Pass or fail? [p/f]";
1131 my $ans = <STDIN>;
1132 chomp $ans;
1133 if ($ans eq "p" || $ans eq "P") {
1134 return 1;
1135 } elsif ($ans eq "f" || $ans eq "F") {
1136 return 0;
1137 } else {
1138 print "Please answer 'P' or 'F'\n";
1139 }
1140 }
1141}
1142
1143sub child_run_test {
1144 my $failed = 0;
1145
1146 # child should have no power
1147 $reboot_on_error = 0;
1148 $poweroff_on_error = 0;
1149 $die_on_failure = 1;
1150
1151 run_command $run_test or $failed = 1;
1152 exit $failed;
1153}
1154
1155my $child_done;
1156
1157sub child_finished {
1158 $child_done = 1;
1159}
1160
1161sub do_run_test {
1162 my $child_pid;
1163 my $child_exit;
1164 my $line;
1165 my $full_line;
1166 my $bug = 0;
1167
1168 wait_for_monitor 1;
1169
1170 doprint "run test $run_test\n";
1171
1172 $child_done = 0;
1173
1174 $SIG{CHLD} = qw(child_finished);
1175
1176 $child_pid = fork;
1177
1178 child_run_test if (!$child_pid);
1179
1180 $full_line = "";
1181
1182 do {
1183 $line = wait_for_input($monitor_fp, 1);
1184 if (defined($line)) {
1185
1186 # we are not guaranteed to get a full line
1187 $full_line .= $line;
1188 doprint $line;
1189
1190 if ($full_line =~ /call trace:/i) {
1191 $bug = 1;
1192 }
1193
1194 if ($full_line =~ /Kernel panic -/) {
1195 $bug = 1;
1196 }
1197
1198 if ($line =~ /\n/) {
1199 $full_line = "";
1200 }
1201 }
1202 } while (!$child_done && !$bug);
1203
1204 if ($bug) {
1205 my $failure_start = time;
1206 my $now;
1207 do {
1208 $line = wait_for_input($monitor_fp, 1);
1209 if (defined($line)) {
1210 doprint $line;
1211 }
1212 $now = time;
1213 if ($now - $failure_start >= $stop_after_failure) {
1214 last;
1215 }
1216 } while (defined($line));
1217
1218 doprint "Detected kernel crash!\n";
1219 # kill the child with extreme prejudice
1220 kill 9, $child_pid;
1221 }
1222
1223 waitpid $child_pid, 0;
1224 $child_exit = $?;
1225
1226 if ($bug || $child_exit) {
1227 return 0 if $in_bisect;
1228 fail "test failed" and return 0;
1229 }
1230 return 1;
1231}
1232
1233sub run_git_bisect {
1234 my ($command) = @_;
1235
1236 doprint "$command ... ";
1237
1238 my $output = `$command 2>&1`;
1239 my $ret = $?;
1240
1241 logit $output;
1242
1243 if ($ret) {
1244 doprint "FAILED\n";
1245 dodie "Failed to git bisect";
1246 }
1247
1248 doprint "SUCCESS\n";
1249 if ($output =~ m/^(Bisecting: .*\(roughly \d+ steps?\))\s+\[([[:xdigit:]]+)\]/) {
1250 doprint "$1 [$2]\n";
1251 } elsif ($output =~ m/^([[:xdigit:]]+) is the first bad commit/) {
1252 $bisect_bad = $1;
1253 doprint "Found bad commit... $1\n";
1254 return 0;
1255 } else {
1256 # we already logged it, just print it now.
1257 print $output;
1258 }
1259
1260 return 1;
1261}
1262
1263sub bisect_reboot {
1264 doprint "Reboot and sleep $bisect_sleep_time seconds\n";
1265 reboot;
1266 start_monitor;
1267 wait_for_monitor $bisect_sleep_time;
1268 end_monitor;
1269}
1270
1271# returns 1 on success, 0 on failure, -1 on skip
1272sub run_bisect_test {
1273 my ($type, $buildtype) = @_;
1274
1275 my $failed = 0;
1276 my $result;
1277 my $output;
1278 my $ret;
1279
1280 $in_bisect = 1;
1281
1282 build $buildtype or $failed = 1;
1283
1284 if ($type ne "build") {
1285 if ($failed && $bisect_skip) {
1286 $in_bisect = 0;
1287 return -1;
1288 }
1289 dodie "Failed on build" if $failed;
1290
1291 # Now boot the box
1292 get_grub_index;
1293 get_version;
1294 install;
1295
1296 start_monitor;
1297 monitor or $failed = 1;
1298
1299 if ($type ne "boot") {
1300 if ($failed && $bisect_skip) {
1301 end_monitor;
1302 bisect_reboot;
1303 $in_bisect = 0;
1304 return -1;
1305 }
1306 dodie "Failed on boot" if $failed;
1307
1308 do_run_test or $failed = 1;
1309 }
1310 end_monitor;
1311 }
1312
1313 if ($failed) {
1314 $result = 0;
1315 } else {
1316 $result = 1;
1317 }
1318
1319 # reboot the box to a kernel we can ssh to
1320 if ($type ne "build") {
1321 bisect_reboot;
1322 }
1323 $in_bisect = 0;
1324
1325 return $result;
1326}
1327
1328sub run_bisect {
1329 my ($type) = @_;
1330 my $buildtype = "oldconfig";
1331
1332 # We should have a minconfig to use?
1333 if (defined($minconfig)) {
1334 $buildtype = "useconfig:$minconfig";
1335 }
1336
1337 my $ret = run_bisect_test $type, $buildtype;
1338
1339 if ($bisect_manual) {
1340 $ret = answer_bisect;
1341 }
1342
1343 # Are we looking for where it worked, not failed?
1344 if ($reverse_bisect) {
1345 $ret = !$ret;
1346 }
1347
1348 if ($ret > 0) {
1349 return "good";
1350 } elsif ($ret == 0) {
1351 return "bad";
1352 } elsif ($bisect_skip) {
1353 doprint "HIT A BAD COMMIT ... SKIPPING\n";
1354 return "skip";
1355 }
1356}
1357
1358sub bisect {
1359 my ($i) = @_;
1360
1361 my $result;
1362
1363 die "BISECT_GOOD[$i] not defined\n" if (!defined($opt{"BISECT_GOOD[$i]"}));
1364 die "BISECT_BAD[$i] not defined\n" if (!defined($opt{"BISECT_BAD[$i]"}));
1365 die "BISECT_TYPE[$i] not defined\n" if (!defined($opt{"BISECT_TYPE[$i]"}));
1366
1367 my $good = $opt{"BISECT_GOOD[$i]"};
1368 my $bad = $opt{"BISECT_BAD[$i]"};
1369 my $type = $opt{"BISECT_TYPE[$i]"};
1370 my $start = $opt{"BISECT_START[$i]"};
1371 my $replay = $opt{"BISECT_REPLAY[$i]"};
1372 my $start_files = $opt{"BISECT_FILES[$i]"};
1373
1374 if (defined($start_files)) {
1375 $start_files = " -- " . $start_files;
1376 } else {
1377 $start_files = "";
1378 }
1379
1380 # convert to true sha1's
1381 $good = get_sha1($good);
1382 $bad = get_sha1($bad);
1383
1384 if (defined($opt{"BISECT_REVERSE[$i]"}) &&
1385 $opt{"BISECT_REVERSE[$i]"} == 1) {
1386 doprint "Performing a reverse bisect (bad is good, good is bad!)\n";
1387 $reverse_bisect = 1;
1388 } else {
1389 $reverse_bisect = 0;
1390 }
1391
1392 # Can't have a test without having a test to run
1393 if ($type eq "test" && !defined($run_test)) {
1394 $type = "boot";
1395 }
1396
1397 my $check = $opt{"BISECT_CHECK[$i]"};
1398 if (defined($check) && $check ne "0") {
1399
1400 # get current HEAD
1401 my $head = get_sha1("HEAD");
1402
1403 if ($check ne "good") {
1404 doprint "TESTING BISECT BAD [$bad]\n";
1405 run_command "git checkout $bad" or
1406 die "Failed to checkout $bad";
1407
1408 $result = run_bisect $type;
1409
1410 if ($result ne "bad") {
1411 fail "Tested BISECT_BAD [$bad] and it succeeded" and return 0;
1412 }
1413 }
1414
1415 if ($check ne "bad") {
1416 doprint "TESTING BISECT GOOD [$good]\n";
1417 run_command "git checkout $good" or
1418 die "Failed to checkout $good";
1419
1420 $result = run_bisect $type;
1421
1422 if ($result ne "good") {
1423 fail "Tested BISECT_GOOD [$good] and it failed" and return 0;
1424 }
1425 }
1426
1427 # checkout where we started
1428 run_command "git checkout $head" or
1429 die "Failed to checkout $head";
1430 }
1431
1432 run_command "git bisect start$start_files" or
1433 dodie "could not start bisect";
1434
1435 run_command "git bisect good $good" or
1436 dodie "could not set bisect good to $good";
1437
1438 run_git_bisect "git bisect bad $bad" or
1439 dodie "could not set bisect bad to $bad";
1440
1441 if (defined($replay)) {
1442 run_command "git bisect replay $replay" or
1443 dodie "failed to run replay";
1444 }
1445
1446 if (defined($start)) {
1447 run_command "git checkout $start" or
1448 dodie "failed to checkout $start";
1449 }
1450
1451 my $test;
1452 do {
1453 $result = run_bisect $type;
1454 $test = run_git_bisect "git bisect $result";
1455 } while ($test);
1456
1457 run_command "git bisect log" or
1458 dodie "could not capture git bisect log";
1459
1460 run_command "git bisect reset" or
1461 dodie "could not reset git bisect";
1462
1463 doprint "Bad commit was [$bisect_bad]\n";
1464
1465 success $i;
1466}
1467
1468my %config_ignore;
1469my %config_set;
1470
1471my %config_list;
1472my %null_config;
1473
1474my %dependency;
1475
1476sub process_config_ignore {
1477 my ($config) = @_;
1478
1479 open (IN, $config)
1480 or dodie "Failed to read $config";
1481
1482 while (<IN>) {
1483 if (/^((CONFIG\S*)=.*)/) {
1484 $config_ignore{$2} = $1;
1485 }
1486 }
1487
1488 close(IN);
1489}
1490
1491sub read_current_config {
1492 my ($config_ref) = @_;
1493
1494 %{$config_ref} = ();
1495 undef %{$config_ref};
1496
1497 my @key = keys %{$config_ref};
1498 if ($#key >= 0) {
1499 print "did not delete!\n";
1500 exit;
1501 }
1502 open (IN, "$output_config");
1503
1504 while (<IN>) {
1505 if (/^(CONFIG\S+)=(.*)/) {
1506 ${$config_ref}{$1} = $2;
1507 }
1508 }
1509 close(IN);
1510}
1511
1512sub get_dependencies {
1513 my ($config) = @_;
1514
1515 my $arr = $dependency{$config};
1516 if (!defined($arr)) {
1517 return ();
1518 }
1519
1520 my @deps = @{$arr};
1521
1522 foreach my $dep (@{$arr}) {
1523 print "ADD DEP $dep\n";
1524 @deps = (@deps, get_dependencies $dep);
1525 }
1526
1527 return @deps;
1528}
1529
1530sub create_config {
1531 my @configs = @_;
1532
1533 open(OUT, ">$output_config") or dodie "Can not write to $output_config";
1534
1535 foreach my $config (@configs) {
1536 print OUT "$config_set{$config}\n";
1537 my @deps = get_dependencies $config;
1538 foreach my $dep (@deps) {
1539 print OUT "$config_set{$dep}\n";
1540 }
1541 }
1542
1543 foreach my $config (keys %config_ignore) {
1544 print OUT "$config_ignore{$config}\n";
1545 }
1546 close(OUT);
1547
1548# exit;
1549 make_oldconfig "";
1550}
1551
1552sub compare_configs {
1553 my (%a, %b) = @_;
1554
1555 foreach my $item (keys %a) {
1556 if (!defined($b{$item})) {
1557 print "diff $item\n";
1558 return 1;
1559 }
1560 delete $b{$item};
1561 }
1562
1563 my @keys = keys %b;
1564 if ($#keys) {
1565 print "diff2 $keys[0]\n";
1566 }
1567 return -1 if ($#keys >= 0);
1568
1569 return 0;
1570}
1571
1572sub run_config_bisect_test {
1573 my ($type) = @_;
1574
1575 return run_bisect_test $type, "oldconfig";
1576}
1577
1578sub process_passed {
1579 my (%configs) = @_;
1580
1581 doprint "These configs had no failure: (Enabling them for further compiles)\n";
1582 # Passed! All these configs are part of a good compile.
1583 # Add them to the min options.
1584 foreach my $config (keys %configs) {
1585 if (defined($config_list{$config})) {
1586 doprint " removing $config\n";
1587 $config_ignore{$config} = $config_list{$config};
1588 delete $config_list{$config};
1589 }
1590 }
1591 doprint "config copied to $outputdir/config_good\n";
1592 run_command "cp -f $output_config $outputdir/config_good";
1593}
1594
1595sub process_failed {
1596 my ($config) = @_;
1597
1598 doprint "\n\n***************************************\n";
1599 doprint "Found bad config: $config\n";
1600 doprint "***************************************\n\n";
1601}
1602
1603sub run_config_bisect {
1604
1605 my @start_list = keys %config_list;
1606
1607 if ($#start_list < 0) {
1608 doprint "No more configs to test!!!\n";
1609 return -1;
1610 }
1611
1612 doprint "***** RUN TEST ***\n";
1613 my $type = $opt{"CONFIG_BISECT_TYPE[$iteration]"};
1614 my $ret;
1615 my %current_config;
1616
1617 my $count = $#start_list + 1;
1618 doprint " $count configs to test\n";
1619
1620 my $half = int($#start_list / 2);
1621
1622 do {
1623 my @tophalf = @start_list[0 .. $half];
1624
1625 create_config @tophalf;
1626 read_current_config \%current_config;
1627
1628 $count = $#tophalf + 1;
1629 doprint "Testing $count configs\n";
1630 my $found = 0;
1631 # make sure we test something
1632 foreach my $config (@tophalf) {
1633 if (defined($current_config{$config})) {
1634 logit " $config\n";
1635 $found = 1;
1636 }
1637 }
1638 if (!$found) {
1639 # try the other half
1640 doprint "Top half produced no set configs, trying bottom half\n";
1641 @tophalf = @start_list[$half + 1 .. $#start_list];
1642 create_config @tophalf;
1643 read_current_config \%current_config;
1644 foreach my $config (@tophalf) {
1645 if (defined($current_config{$config})) {
1646 logit " $config\n";
1647 $found = 1;
1648 }
1649 }
1650 if (!$found) {
1651 doprint "Failed: Can't make new config with current configs\n";
1652 foreach my $config (@start_list) {
1653 doprint " CONFIG: $config\n";
1654 }
1655 return -1;
1656 }
1657 $count = $#tophalf + 1;
1658 doprint "Testing $count configs\n";
1659 }
1660
1661 $ret = run_config_bisect_test $type;
1662 if ($bisect_manual) {
1663 $ret = answer_bisect;
1664 }
1665 if ($ret) {
1666 process_passed %current_config;
1667 return 0;
1668 }
1669
1670 doprint "This config had a failure.\n";
1671 doprint "Removing these configs that were not set in this config:\n";
1672 doprint "config copied to $outputdir/config_bad\n";
1673 run_command "cp -f $output_config $outputdir/config_bad";
1674
1675 # A config exists in this group that was bad.
1676 foreach my $config (keys %config_list) {
1677 if (!defined($current_config{$config})) {
1678 doprint " removing $config\n";
1679 delete $config_list{$config};
1680 }
1681 }
1682
1683 @start_list = @tophalf;
1684
1685 if ($#start_list == 0) {
1686 process_failed $start_list[0];
1687 return 1;
1688 }
1689
1690 # remove half the configs we are looking at and see if
1691 # they are good.
1692 $half = int($#start_list / 2);
1693 } while ($#start_list > 0);
1694
1695 # we found a single config, try it again unless we are running manually
1696
1697 if ($bisect_manual) {
1698 process_failed $start_list[0];
1699 return 1;
1700 }
1701
1702 my @tophalf = @start_list[0 .. 0];
1703
1704 $ret = run_config_bisect_test $type;
1705 if ($ret) {
1706 process_passed %current_config;
1707 return 0;
1708 }
1709
1710 process_failed $start_list[0];
1711 return 1;
1712}
1713
1714sub config_bisect {
1715 my ($i) = @_;
1716
1717 my $start_config = $opt{"CONFIG_BISECT[$i]"};
1718
1719 my $tmpconfig = "$tmpdir/use_config";
1720
1721 # Make the file with the bad config and the min config
1722 if (defined($minconfig)) {
1723 # read the min config for things to ignore
1724 run_command "cp $minconfig $tmpconfig" or
1725 dodie "failed to copy $minconfig to $tmpconfig";
1726 } else {
1727 unlink $tmpconfig;
1728 }
1729
1730 # Add other configs
1731 if (defined($addconfig)) {
1732 run_command "cat $addconfig >> $tmpconfig" or
1733 dodie "failed to append $addconfig";
1734 }
1735
1736 my $defconfig = "";
1737 if (-f $tmpconfig) {
1738 $defconfig = "KCONFIG_ALLCONFIG=$tmpconfig";
1739 process_config_ignore $tmpconfig;
1740 }
1741
1742 # now process the start config
1743 run_command "cp $start_config $output_config" or
1744 dodie "failed to copy $start_config to $output_config";
1745
1746 # read directly what we want to check
1747 my %config_check;
1748 open (IN, $output_config)
1749 or dodie "faied to open $output_config";
1750
1751 while (<IN>) {
1752 if (/^((CONFIG\S*)=.*)/) {
1753 $config_check{$2} = $1;
1754 }
1755 }
1756 close(IN);
1757
1758 # Now run oldconfig with the minconfig (and addconfigs)
1759 make_oldconfig $defconfig;
1760
1761 # check to see what we lost (or gained)
1762 open (IN, $output_config)
1763 or dodie "Failed to read $start_config";
1764
1765 my %removed_configs;
1766 my %added_configs;
1767
1768 while (<IN>) {
1769 if (/^((CONFIG\S*)=.*)/) {
1770 # save off all options
1771 $config_set{$2} = $1;
1772 if (defined($config_check{$2})) {
1773 if (defined($config_ignore{$2})) {
1774 $removed_configs{$2} = $1;
1775 } else {
1776 $config_list{$2} = $1;
1777 }
1778 } elsif (!defined($config_ignore{$2})) {
1779 $added_configs{$2} = $1;
1780 $config_list{$2} = $1;
1781 }
1782 }
1783 }
1784 close(IN);
1785
1786 my @confs = keys %removed_configs;
1787 if ($#confs >= 0) {
1788 doprint "Configs overridden by default configs and removed from check:\n";
1789 foreach my $config (@confs) {
1790 doprint " $config\n";
1791 }
1792 }
1793 @confs = keys %added_configs;
1794 if ($#confs >= 0) {
1795 doprint "Configs appearing in make oldconfig and added:\n";
1796 foreach my $config (@confs) {
1797 doprint " $config\n";
1798 }
1799 }
1800
1801 my %config_test;
1802 my $once = 0;
1803
1804 # Sometimes kconfig does weird things. We must make sure
1805 # that the config we autocreate has everything we need
1806 # to test, otherwise we may miss testing configs, or
1807 # may not be able to create a new config.
1808 # Here we create a config with everything set.
1809 create_config (keys %config_list);
1810 read_current_config \%config_test;
1811 foreach my $config (keys %config_list) {
1812 if (!defined($config_test{$config})) {
1813 if (!$once) {
1814 $once = 1;
1815 doprint "Configs not produced by kconfig (will not be checked):\n";
1816 }
1817 doprint " $config\n";
1818 delete $config_list{$config};
1819 }
1820 }
1821 my $ret;
1822 do {
1823 $ret = run_config_bisect;
1824 } while (!$ret);
1825
1826 return $ret if ($ret < 0);
1827
1828 success $i;
1829}
1830
1831sub patchcheck_reboot {
1832 doprint "Reboot and sleep $patchcheck_sleep_time seconds\n";
1833 reboot;
1834 start_monitor;
1835 wait_for_monitor $patchcheck_sleep_time;
1836 end_monitor;
1837}
1838
1839sub patchcheck {
1840 my ($i) = @_;
1841
1842 die "PATCHCHECK_START[$i] not defined\n"
1843 if (!defined($opt{"PATCHCHECK_START[$i]"}));
1844 die "PATCHCHECK_TYPE[$i] not defined\n"
1845 if (!defined($opt{"PATCHCHECK_TYPE[$i]"}));
1846
1847 my $start = $opt{"PATCHCHECK_START[$i]"};
1848
1849 my $end = "HEAD";
1850 if (defined($opt{"PATCHCHECK_END[$i]"})) {
1851 $end = $opt{"PATCHCHECK_END[$i]"};
1852 }
1853
1854 # Get the true sha1's since we can use things like HEAD~3
1855 $start = get_sha1($start);
1856 $end = get_sha1($end);
1857
1858 my $type = $opt{"PATCHCHECK_TYPE[$i]"};
1859
1860 # Can't have a test without having a test to run
1861 if ($type eq "test" && !defined($run_test)) {
1862 $type = "boot";
1863 }
1864
1865 open (IN, "git log --pretty=oneline $end|") or
1866 dodie "could not get git list";
1867
1868 my @list;
1869
1870 while (<IN>) {
1871 chomp;
1872 $list[$#list+1] = $_;
1873 last if (/^$start/);
1874 }
1875 close(IN);
1876
1877 if ($list[$#list] !~ /^$start/) {
1878 fail "SHA1 $start not found";
1879 }
1880
1881 # go backwards in the list
1882 @list = reverse @list;
1883
1884 my $save_clean = $noclean;
1885
1886 $in_patchcheck = 1;
1887 foreach my $item (@list) {
1888 my $sha1 = $item;
1889 $sha1 =~ s/^([[:xdigit:]]+).*/$1/;
1890
1891 doprint "\nProcessing commit $item\n\n";
1892
1893 run_command "git checkout $sha1" or
1894 die "Failed to checkout $sha1";
1895
1896 # only clean on the first and last patch
1897 if ($item eq $list[0] ||
1898 $item eq $list[$#list]) {
1899 $noclean = $save_clean;
1900 } else {
1901 $noclean = 1;
1902 }
1903
1904 if (defined($minconfig)) {
1905 build "useconfig:$minconfig" or return 0;
1906 } else {
1907 # ?? no config to use?
1908 build "oldconfig" or return 0;
1909 }
1910
1911 check_buildlog $sha1 or return 0;
1912
1913 next if ($type eq "build");
1914
1915 get_grub_index;
1916 get_version;
1917 install;
1918
1919 my $failed = 0;
1920
1921 start_monitor;
1922 monitor or $failed = 1;
1923
1924 if (!$failed && $type ne "boot"){
1925 do_run_test or $failed = 1;
1926 }
1927 end_monitor;
1928 return 0 if ($failed);
1929
1930 patchcheck_reboot;
1931
1932 }
1933 $in_patchcheck = 0;
1934 success $i;
1935
1936 return 1;
1937}
1938
1939$#ARGV < 1 or die "ktest.pl version: $VERSION\n usage: ktest.pl config-file\n";
1940
1941if ($#ARGV == 0) {
1942 $ktest_config = $ARGV[0];
1943 if (! -f $ktest_config) {
1944 print "$ktest_config does not exist.\n";
1945 my $ans;
1946 for (;;) {
1947 print "Create it? [Y/n] ";
1948 $ans = <STDIN>;
1949 chomp $ans;
1950 if ($ans =~ /^\s*$/) {
1951 $ans = "y";
1952 }
1953 last if ($ans =~ /^y$/i || $ans =~ /^n$/i);
1954 print "Please answer either 'y' or 'n'.\n";
1955 }
1956 if ($ans !~ /^y$/i) {
1957 exit 0;
1958 }
1959 }
1960} else {
1961 $ktest_config = "ktest.conf";
1962}
1963
1964if (! -f $ktest_config) {
1965 open(OUT, ">$ktest_config") or die "Can not create $ktest_config";
1966 print OUT << "EOF"
1967# Generated by ktest.pl
1968#
1969# Define each test with TEST_START
1970# The config options below it will override the defaults
1971TEST_START
1972
1973DEFAULTS
1974EOF
1975;
1976 close(OUT);
1977}
1978read_config $ktest_config;
1979
1980# Append any configs entered in manually to the config file.
1981my @new_configs = keys %entered_configs;
1982if ($#new_configs >= 0) {
1983 print "\nAppending entered in configs to $ktest_config\n";
1984 open(OUT, ">>$ktest_config") or die "Can not append to $ktest_config";
1985 foreach my $config (@new_configs) {
1986 print OUT "$config = $entered_configs{$config}\n";
1987 $opt{$config} = $entered_configs{$config};
1988 }
1989}
1990
1991if ($opt{"CLEAR_LOG"} && defined($opt{"LOG_FILE"})) {
1992 unlink $opt{"LOG_FILE"};
1993}
1994
1995doprint "\n\nSTARTING AUTOMATED TESTS\n\n";
1996
1997for (my $i = 0, my $repeat = 1; $i <= $opt{"NUM_TESTS"}; $i += $repeat) {
1998
1999 if (!$i) {
2000 doprint "DEFAULT OPTIONS:\n";
2001 } else {
2002 doprint "\nTEST $i OPTIONS";
2003 if (defined($repeat_tests{$i})) {
2004 $repeat = $repeat_tests{$i};
2005 doprint " ITERATE $repeat";
2006 }
2007 doprint "\n";
2008 }
2009
2010 foreach my $option (sort keys %opt) {
2011
2012 if ($option =~ /\[(\d+)\]$/) {
2013 next if ($i != $1);
2014 } else {
2015 next if ($i);
2016 }
2017
2018 doprint "$option = $opt{$option}\n";
2019 }
2020}
2021
2022sub __set_test_option {
2023 my ($name, $i) = @_;
2024
2025 my $option = "$name\[$i\]";
2026
2027 if (defined($opt{$option})) {
2028 return $opt{$option};
2029 }
2030
2031 foreach my $test (keys %repeat_tests) {
2032 if ($i >= $test &&
2033 $i < $test + $repeat_tests{$test}) {
2034 $option = "$name\[$test\]";
2035 if (defined($opt{$option})) {
2036 return $opt{$option};
2037 }
2038 }
2039 }
2040
2041 if (defined($opt{$name})) {
2042 return $opt{$name};
2043 }
2044
2045 return undef;
2046}
2047
2048sub eval_option {
2049 my ($option, $i) = @_;
2050
2051 # Add space to evaluate the character before $
2052 $option = " $option";
2053 my $retval = "";
2054
2055 while ($option =~ /(.*?[^\\])\$\{(.*?)\}(.*)/) {
2056 my $start = $1;
2057 my $var = $2;
2058 my $end = $3;
2059
2060 # Append beginning of line
2061 $retval = "$retval$start";
2062
2063 # If the iteration option OPT[$i] exists, then use that.
2064 # otherwise see if the default OPT (without [$i]) exists.
2065
2066 my $o = "$var\[$i\]";
2067
2068 if (defined($opt{$o})) {
2069 $o = $opt{$o};
2070 $retval = "$retval$o";
2071 } elsif (defined($opt{$var})) {
2072 $o = $opt{$var};
2073 $retval = "$retval$o";
2074 } else {
2075 $retval = "$retval\$\{$var\}";
2076 }
2077
2078 $option = $end;
2079 }
2080
2081 $retval = "$retval$option";
2082
2083 $retval =~ s/^ //;
2084
2085 return $retval;
2086}
2087
2088sub set_test_option {
2089 my ($name, $i) = @_;
2090
2091 my $option = __set_test_option($name, $i);
2092 return $option if (!defined($option));
2093
2094 my $prev = "";
2095
2096 # Since an option can evaluate to another option,
2097 # keep iterating until we do not evaluate any more
2098 # options.
2099 my $r = 0;
2100 while ($prev ne $option) {
2101 # Check for recursive evaluations.
2102 # 100 deep should be more than enough.
2103 if ($r++ > 100) {
2104 die "Over 100 evaluations accurred with $name\n" .
2105 "Check for recursive variables\n";
2106 }
2107 $prev = $option;
2108 $option = eval_option($option, $i);
2109 }
2110
2111 return $option;
2112}
2113
2114# First we need to do is the builds
2115for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
2116
2117 $iteration = $i;
2118
2119 my $makecmd = set_test_option("MAKE_CMD", $i);
2120
2121 $machine = set_test_option("MACHINE", $i);
2122 $ssh_user = set_test_option("SSH_USER", $i);
2123 $tmpdir = set_test_option("TMP_DIR", $i);
2124 $outputdir = set_test_option("OUTPUT_DIR", $i);
2125 $builddir = set_test_option("BUILD_DIR", $i);
2126 $test_type = set_test_option("TEST_TYPE", $i);
2127 $build_type = set_test_option("BUILD_TYPE", $i);
2128 $build_options = set_test_option("BUILD_OPTIONS", $i);
2129 $power_cycle = set_test_option("POWER_CYCLE", $i);
2130 $reboot = set_test_option("REBOOT", $i);
2131 $noclean = set_test_option("BUILD_NOCLEAN", $i);
2132 $minconfig = set_test_option("MIN_CONFIG", $i);
2133 $run_test = set_test_option("TEST", $i);
2134 $addconfig = set_test_option("ADD_CONFIG", $i);
2135 $reboot_type = set_test_option("REBOOT_TYPE", $i);
2136 $grub_menu = set_test_option("GRUB_MENU", $i);
2137 $post_install = set_test_option("POST_INSTALL", $i);
2138 $reboot_script = set_test_option("REBOOT_SCRIPT", $i);
2139 $reboot_on_error = set_test_option("REBOOT_ON_ERROR", $i);
2140 $poweroff_on_error = set_test_option("POWEROFF_ON_ERROR", $i);
2141 $die_on_failure = set_test_option("DIE_ON_FAILURE", $i);
2142 $power_off = set_test_option("POWER_OFF", $i);
2143 $powercycle_after_reboot = set_test_option("POWERCYCLE_AFTER_REBOOT", $i);
2144 $poweroff_after_halt = set_test_option("POWEROFF_AFTER_HALT", $i);
2145 $sleep_time = set_test_option("SLEEP_TIME", $i);
2146 $bisect_sleep_time = set_test_option("BISECT_SLEEP_TIME", $i);
2147 $patchcheck_sleep_time = set_test_option("PATCHCHECK_SLEEP_TIME", $i);
2148 $bisect_manual = set_test_option("BISECT_MANUAL", $i);
2149 $bisect_skip = set_test_option("BISECT_SKIP", $i);
2150 $store_failures = set_test_option("STORE_FAILURES", $i);
2151 $timeout = set_test_option("TIMEOUT", $i);
2152 $booted_timeout = set_test_option("BOOTED_TIMEOUT", $i);
2153 $console = set_test_option("CONSOLE", $i);
2154 $success_line = set_test_option("SUCCESS_LINE", $i);
2155 $stop_after_success = set_test_option("STOP_AFTER_SUCCESS", $i);
2156 $stop_after_failure = set_test_option("STOP_AFTER_FAILURE", $i);
2157 $stop_test_after = set_test_option("STOP_TEST_AFTER", $i);
2158 $build_target = set_test_option("BUILD_TARGET", $i);
2159 $ssh_exec = set_test_option("SSH_EXEC", $i);
2160 $scp_to_target = set_test_option("SCP_TO_TARGET", $i);
2161 $target_image = set_test_option("TARGET_IMAGE", $i);
2162 $localversion = set_test_option("LOCALVERSION", $i);
2163
2164 chdir $builddir || die "can't change directory to $builddir";
2165
2166 if (!-d $tmpdir) {
2167 mkpath($tmpdir) or
2168 die "can't create $tmpdir";
2169 }
2170
2171 $ENV{"SSH_USER"} = $ssh_user;
2172 $ENV{"MACHINE"} = $machine;
2173
2174 $target = "$ssh_user\@$machine";
2175
2176 $buildlog = "$tmpdir/buildlog-$machine";
2177 $dmesg = "$tmpdir/dmesg-$machine";
2178 $make = "$makecmd O=$outputdir";
2179 $output_config = "$outputdir/.config";
2180
2181 if ($reboot_type eq "grub") {
2182 dodie "GRUB_MENU not defined" if (!defined($grub_menu));
2183 } elsif (!defined($reboot_script)) {
2184 dodie "REBOOT_SCRIPT not defined"
2185 }
2186
2187 my $run_type = $build_type;
2188 if ($test_type eq "patchcheck") {
2189 $run_type = $opt{"PATCHCHECK_TYPE[$i]"};
2190 } elsif ($test_type eq "bisect") {
2191 $run_type = $opt{"BISECT_TYPE[$i]"};
2192 } elsif ($test_type eq "config_bisect") {
2193 $run_type = $opt{"CONFIG_BISECT_TYPE[$i]"};
2194 }
2195
2196 # mistake in config file?
2197 if (!defined($run_type)) {
2198 $run_type = "ERROR";
2199 }
2200
2201 doprint "\n\n";
2202 doprint "RUNNING TEST $i of $opt{NUM_TESTS} with option $test_type $run_type\n\n";
2203
2204 unlink $dmesg;
2205 unlink $buildlog;
2206
2207 if (!defined($minconfig)) {
2208 $minconfig = $addconfig;
2209
2210 } elsif (defined($addconfig)) {
2211 run_command "cat $addconfig $minconfig > $tmpdir/add_config" or
2212 dodie "Failed to create temp config";
2213 $minconfig = "$tmpdir/add_config";
2214 }
2215
2216 my $checkout = $opt{"CHECKOUT[$i]"};
2217 if (defined($checkout)) {
2218 run_command "git checkout $checkout" or
2219 die "failed to checkout $checkout";
2220 }
2221
2222 if ($test_type eq "bisect") {
2223 bisect $i;
2224 next;
2225 } elsif ($test_type eq "config_bisect") {
2226 config_bisect $i;
2227 next;
2228 } elsif ($test_type eq "patchcheck") {
2229 patchcheck $i;
2230 next;
2231 }
2232
2233 if ($build_type ne "nobuild") {
2234 build $build_type or next;
2235 }
2236
2237 if ($test_type ne "build") {
2238 get_grub_index;
2239 get_version;
2240 install;
2241
2242 my $failed = 0;
2243 start_monitor;
2244 monitor or $failed = 1;;
2245
2246 if (!$failed && $test_type ne "boot" && defined($run_test)) {
2247 do_run_test or $failed = 1;
2248 }
2249 end_monitor;
2250 next if ($failed);
2251 }
2252
2253 success $i;
2254}
2255
2256if ($opt{"POWEROFF_ON_SUCCESS"}) {
2257 halt;
2258} elsif ($opt{"REBOOT_ON_SUCCESS"} && !do_not_reboot) {
2259 reboot;
2260}
2261
2262doprint "\n $successes of $opt{NUM_TESTS} tests were successful\n\n";
2263
2264exit 0;
diff --git a/tools/testing/ktest/sample.conf b/tools/testing/ktest/sample.conf
new file mode 100644
index 000000000000..48cbcc80602a
--- /dev/null
+++ b/tools/testing/ktest/sample.conf
@@ -0,0 +1,757 @@
1#
2# Config file for ktest.pl
3#
4# Note, all paths must be absolute
5#
6
7# Options set in the beginning of the file are considered to be
8# default options. These options can be overriden by test specific
9# options, with the following exceptions:
10#
11# LOG_FILE
12# CLEAR_LOG
13# POWEROFF_ON_SUCCESS
14# REBOOT_ON_SUCCESS
15#
16# Test specific options are set after the label:
17#
18# TEST_START
19#
20# The options after a TEST_START label are specific to that test.
21# Each TEST_START label will set up a new test. If you want to
22# perform a test more than once, you can add the ITERATE label
23# to it followed by the number of times you want that test
24# to iterate. If the ITERATE is left off, the test will only
25# be performed once.
26#
27# TEST_START ITERATE 10
28#
29# You can skip a test by adding SKIP (before or after the ITERATE
30# and number)
31#
32# TEST_START SKIP
33#
34# TEST_START SKIP ITERATE 10
35#
36# TEST_START ITERATE 10 SKIP
37#
38# The SKIP label causes the options and the test itself to be ignored.
39# This is useful to set up several different tests in one config file, and
40# only enabling the ones you want to use for a current test run.
41#
42# You can add default options anywhere in the file as well
43# with the DEFAULTS tag. This allows you to have default options
44# after the test options to keep the test options at the top
45# of the file. You can even place the DEFAULTS tag between
46# test cases (but not in the middle of a single test case)
47#
48# TEST_START
49# MIN_CONFIG = /home/test/config-test1
50#
51# DEFAULTS
52# MIN_CONFIG = /home/test/config-default
53#
54# TEST_START ITERATE 10
55#
56# The above will run the first test with MIN_CONFIG set to
57# /home/test/config-test-1. Then 10 tests will be executed
58# with MIN_CONFIG with /home/test/config-default.
59#
60# You can also disable defaults with the SKIP option
61#
62# DEFAULTS SKIP
63# MIN_CONFIG = /home/test/config-use-sometimes
64#
65# DEFAULTS
66# MIN_CONFIG = /home/test/config-most-times
67#
68# The above will ignore the first MIN_CONFIG. If you want to
69# use the first MIN_CONFIG, remove the SKIP from the first
70# DEFAULTS tag and add it to the second. Be careful, options
71# may only be declared once per test or default. If you have
72# the same option name under the same test or as default
73# ktest will fail to execute, and no tests will run.
74#
75
76#### Config variables ####
77#
78# This config file can also contain "config variables".
79# These are assigned with ":=" instead of the ktest option
80# assigment "=".
81#
82# The difference between ktest options and config variables
83# is that config variables can be used multiple times,
84# where each instance will override the previous instance.
85# And that they only live at time of processing this config.
86#
87# The advantage to config variables are that they can be used
88# by any option or any other config variables to define thing
89# that you may use over and over again in the options.
90#
91# For example:
92#
93# USER := root
94# TARGET := mybox
95# TEST_CASE := ssh ${USER}@${TARGET} /path/to/my/test
96#
97# TEST_START
98# MIN_CONFIG = config1
99# TEST = ${TEST_CASE}
100#
101# TEST_START
102# MIN_CONFIG = config2
103# TEST = ${TEST_CASE}
104#
105# TEST_CASE := ssh ${USER}@${TARGET} /path/to/my/test2
106#
107# TEST_START
108# MIN_CONFIG = config1
109# TEST = ${TEST_CASE}
110#
111# TEST_START
112# MIN_CONFIG = config2
113# TEST = ${TEST_CASE}
114#
115# TEST_DIR := /home/me/test
116#
117# BUILD_DIR = ${TEST_DIR}/linux.git
118# OUTPUT_DIR = ${TEST_DIR}/test
119#
120# Note, the config variables are evaluated immediately, thus
121# updating TARGET after TEST_CASE has been assigned does nothing
122# to TEST_CASE.
123#
124# As shown in the example, to evaluate a config variable, you
125# use the ${X} convention. Simple $X will not work.
126#
127# If the config variable does not exist, the ${X} will not
128# be evaluated. Thus:
129#
130# MAKE_CMD = PATH=/mypath:${PATH} make
131#
132# If PATH is not a config variable, then the ${PATH} in
133# the MAKE_CMD option will be evaluated by the shell when
134# the MAKE_CMD option is passed into shell processing.
135
136#### Using options in other options ####
137#
138# Options that are defined in the config file may also be used
139# by other options. All options are evaulated at time of
140# use (except that config variables are evaluated at config
141# processing time).
142#
143# If an ktest option is used within another option, instead of
144# typing it again in that option you can simply use the option
145# just like you can config variables.
146#
147# MACHINE = mybox
148#
149# TEST = ssh root@${MACHINE} /path/to/test
150#
151# The option will be used per test case. Thus:
152#
153# TEST_TYPE = test
154# TEST = ssh root@{MACHINE}
155#
156# TEST_START
157# MACHINE = box1
158#
159# TEST_START
160# MACHINE = box2
161#
162# For both test cases, MACHINE will be evaluated at the time
163# of the test case. The first test will run ssh root@box1
164# and the second will run ssh root@box2.
165
166#### Mandatory Default Options ####
167
168# These options must be in the default section, although most
169# may be overridden by test options.
170
171# The machine hostname that you will test
172#MACHINE = target
173
174# The box is expected to have ssh on normal bootup, provide the user
175# (most likely root, since you need privileged operations)
176#SSH_USER = root
177
178# The directory that contains the Linux source code
179#BUILD_DIR = /home/test/linux.git
180
181# The directory that the objects will be built
182# (can not be same as BUILD_DIR)
183#OUTPUT_DIR = /home/test/build/target
184
185# The location of the compiled file to copy to the target
186# (relative to OUTPUT_DIR)
187#BUILD_TARGET = arch/x86/boot/bzImage
188
189# The place to put your image on the test machine
190#TARGET_IMAGE = /boot/vmlinuz-test
191
192# A script or command to reboot the box
193#
194# Here is a digital loggers power switch example
195#POWER_CYCLE = wget --no-proxy -O /dev/null -q --auth-no-challenge 'http://admin:admin@power/outlet?5=CCL'
196#
197# Here is an example to reboot a virtual box on the current host
198# with the name "Guest".
199#POWER_CYCLE = virsh destroy Guest; sleep 5; virsh start Guest
200
201# The script or command that reads the console
202#
203# If you use ttywatch server, something like the following would work.
204#CONSOLE = nc -d localhost 3001
205#
206# For a virtual machine with guest name "Guest".
207#CONSOLE = virsh console Guest
208
209# Required version ending to differentiate the test
210# from other linux builds on the system.
211#LOCALVERSION = -test
212
213# The grub title name for the test kernel to boot
214# (Only mandatory if REBOOT_TYPE = grub)
215#
216# Note, ktest.pl will not update the grub menu.lst, you need to
217# manually add an option for the test. ktest.pl will search
218# the grub menu.lst for this option to find what kernel to
219# reboot into.
220#
221# For example, if in the /boot/grub/menu.lst the test kernel title has:
222# title Test Kernel
223# kernel vmlinuz-test
224#GRUB_MENU = Test Kernel
225
226# A script to reboot the target into the test kernel
227# (Only mandatory if REBOOT_TYPE = script)
228#REBOOT_SCRIPT =
229
230#### Optional Config Options (all have defaults) ####
231
232# Start a test setup. If you leave this off, all options
233# will be default and the test will run once.
234# This is a label and not really an option (it takes no value).
235# You can append ITERATE and a number after it to iterate the
236# test a number of times, or SKIP to ignore this test.
237#
238#TEST_START
239#TEST_START ITERATE 5
240#TEST_START SKIP
241
242# Have the following options as default again. Used after tests
243# have already been defined by TEST_START. Optionally, you can
244# just define all default options before the first TEST_START
245# and you do not need this option.
246#
247# This is a label and not really an option (it takes no value).
248# You can append SKIP to this label and the options within this
249# section will be ignored.
250#
251# DEFAULTS
252# DEFAULTS SKIP
253
254# The default test type (default test)
255# The test types may be:
256# build - only build the kernel, do nothing else
257# boot - build and boot the kernel
258# test - build, boot and if TEST is set, run the test script
259# (If TEST is not set, it defaults back to boot)
260# bisect - Perform a bisect on the kernel (see BISECT_TYPE below)
261# patchcheck - Do a test on a series of commits in git (see PATCHCHECK below)
262#TEST_TYPE = test
263
264# Test to run if there is a successful boot and TEST_TYPE is test.
265# Must exit with 0 on success and non zero on error
266# default (undefined)
267#TEST = ssh user@machine /root/run_test
268
269# The build type is any make config type or special command
270# (default randconfig)
271# nobuild - skip the clean and build step
272# useconfig:/path/to/config - use the given config and run
273# oldconfig on it.
274# This option is ignored if TEST_TYPE is patchcheck or bisect
275#BUILD_TYPE = randconfig
276
277# The make command (default make)
278# If you are building a 32bit x86 on a 64 bit host
279#MAKE_CMD = CC=i386-gcc AS=i386-as make ARCH=i386
280
281# Any build options for the make of the kernel (not for other makes, like configs)
282# (default "")
283#BUILD_OPTIONS = -j20
284
285# If you need an initrd, you can add a script or code here to install
286# it. The environment variable KERNEL_VERSION will be set to the
287# kernel version that is used. Remember to add the initrd line
288# to your grub menu.lst file.
289#
290# Here's a couple of examples to use:
291#POST_INSTALL = ssh user@target /sbin/mkinitrd --allow-missing -f /boot/initramfs-test.img $KERNEL_VERSION
292#
293# or on some systems:
294#POST_INSTALL = ssh user@target /sbin/dracut -f /boot/initramfs-test.img $KERNEL_VERSION
295
296# Way to reboot the box to the test kernel.
297# Only valid options so far are "grub" and "script"
298# (default grub)
299# If you specify grub, it will assume grub version 1
300# and will search in /boot/grub/menu.lst for the title $GRUB_MENU
301# and select that target to reboot to the kernel. If this is not
302# your setup, then specify "script" and have a command or script
303# specified in REBOOT_SCRIPT to boot to the target.
304#
305# The entry in /boot/grub/menu.lst must be entered in manually.
306# The test will not modify that file.
307#REBOOT_TYPE = grub
308
309# The min config that is needed to build for the machine
310# A nice way to create this is with the following:
311#
312# $ ssh target
313# $ lsmod > mymods
314# $ scp mymods host:/tmp
315# $ exit
316# $ cd linux.git
317# $ rm .config
318# $ make LSMOD=mymods localyesconfig
319# $ grep '^CONFIG' .config > /home/test/config-min
320#
321# If you want even less configs:
322#
323# log in directly to target (do not ssh)
324#
325# $ su
326# # lsmod | cut -d' ' -f1 | xargs rmmod
327#
328# repeat the above several times
329#
330# # lsmod > mymods
331# # reboot
332#
333# May need to reboot to get your network back to copy the mymods
334# to the host, and then remove the previous .config and run the
335# localyesconfig again. The CONFIG_MIN generated like this will
336# not guarantee network activity to the box so the TEST_TYPE of
337# test may fail.
338#
339# You might also want to set:
340# CONFIG_CMDLINE="<your options here>"
341# randconfig may set the above and override your real command
342# line options.
343# (default undefined)
344#MIN_CONFIG = /home/test/config-min
345
346# Sometimes there's options that just break the boot and
347# you do not care about. Here are a few:
348# # CONFIG_STAGING is not set
349# Staging drivers are horrible, and can break the build.
350# # CONFIG_SCSI_DEBUG is not set
351# SCSI_DEBUG may change your root partition
352# # CONFIG_KGDB_SERIAL_CONSOLE is not set
353# KGDB may cause oops waiting for a connection that's not there.
354# This option points to the file containing config options that will be prepended
355# to the MIN_CONFIG (or be the MIN_CONFIG if it is not set)
356#
357# Note, config options in MIN_CONFIG will override these options.
358#
359# (default undefined)
360#ADD_CONFIG = /home/test/config-broken
361
362# The location on the host where to write temp files
363# (default /tmp/ktest)
364#TMP_DIR = /tmp/ktest
365
366# Optional log file to write the status (recommended)
367# Note, this is a DEFAULT section only option.
368# (default undefined)
369#LOG_FILE = /home/test/logfiles/target.log
370
371# Remove old logfile if it exists before starting all tests.
372# Note, this is a DEFAULT section only option.
373# (default 0)
374#CLEAR_LOG = 0
375
376# Line to define a successful boot up in console output.
377# This is what the line contains, not the entire line. If you need
378# the entire line to match, then use regural expression syntax like:
379# (do not add any quotes around it)
380#
381# SUCCESS_LINE = ^MyBox Login:$
382#
383# (default "login:")
384#SUCCESS_LINE = login:
385
386# In case the console constantly fills the screen, having
387# a specified time to stop the test after success is recommended.
388# (in seconds)
389# (default 10)
390#STOP_AFTER_SUCCESS = 10
391
392# In case the console constantly fills the screen, having
393# a specified time to stop the test after failure is recommended.
394# (in seconds)
395# (default 60)
396#STOP_AFTER_FAILURE = 60
397
398# In case the console constantly fills the screen, having
399# a specified time to stop the test if it never succeeds nor fails
400# is recommended.
401# Note: this is ignored if a success or failure is detected.
402# (in seconds)
403# (default 600, -1 is to never stop)
404#STOP_TEST_AFTER = 600
405
406# Stop testing if a build fails. If set, the script will end if
407# a failure is detected, otherwise it will save off the .config,
408# dmesg and bootlog in a directory called
409# MACHINE-TEST_TYPE_BUILD_TYPE-fail-yyyymmddhhmmss
410# if the STORE_FAILURES directory is set.
411# (default 1)
412# Note, even if this is set to zero, there are some errors that still
413# stop the tests.
414#DIE_ON_FAILURE = 1
415
416# Directory to store failure directories on failure. If this is not
417# set, DIE_ON_FAILURE=0 will not save off the .config, dmesg and
418# bootlog. This option is ignored if DIE_ON_FAILURE is not set.
419# (default undefined)
420#STORE_FAILURES = /home/test/failures
421
422# Build without doing a make mrproper, or removing .config
423# (default 0)
424#BUILD_NOCLEAN = 0
425
426# As the test reads the console, after it hits the SUCCESS_LINE
427# the time it waits for the monitor to settle down between reads
428# can usually be lowered.
429# (in seconds) (default 1)
430#BOOTED_TIMEOUT = 1
431
432# The timeout in seconds when we consider the box hung after
433# the console stop producing output. Be sure to leave enough
434# time here to get pass a reboot. Some machines may not produce
435# any console output for a long time during a reboot. You do
436# not want the test to fail just because the system was in
437# the process of rebooting to the test kernel.
438# (default 120)
439#TIMEOUT = 120
440
441# In between tests, a reboot of the box may occur, and this
442# is the time to wait for the console after it stops producing
443# output. Some machines may not produce a large lag on reboot
444# so this should accommodate it.
445# The difference between this and TIMEOUT, is that TIMEOUT happens
446# when rebooting to the test kernel. This sleep time happens
447# after a test has completed and we are about to start running
448# another test. If a reboot to the reliable kernel happens,
449# we wait SLEEP_TIME for the console to stop producing output
450# before starting the next test.
451# (default 60)
452#SLEEP_TIME = 60
453
454# The time in between bisects to sleep (in seconds)
455# (default 60)
456#BISECT_SLEEP_TIME = 60
457
458# The time in between patch checks to sleep (in seconds)
459# (default 60)
460#PATCHCHECK_SLEEP_TIME = 60
461
462# Reboot the target box on error (default 0)
463#REBOOT_ON_ERROR = 0
464
465# Power off the target on error (ignored if REBOOT_ON_ERROR is set)
466# Note, this is a DEFAULT section only option.
467# (default 0)
468#POWEROFF_ON_ERROR = 0
469
470# Power off the target after all tests have completed successfully
471# Note, this is a DEFAULT section only option.
472# (default 0)
473#POWEROFF_ON_SUCCESS = 0
474
475# Reboot the target after all test completed successfully (default 1)
476# (ignored if POWEROFF_ON_SUCCESS is set)
477#REBOOT_ON_SUCCESS = 1
478
479# In case there are isses with rebooting, you can specify this
480# to always powercycle after this amount of time after calling
481# reboot.
482# Note, POWERCYCLE_AFTER_REBOOT = 0 does NOT disable it. It just
483# makes it powercycle immediately after rebooting. Do not define
484# it if you do not want it.
485# (default undefined)
486#POWERCYCLE_AFTER_REBOOT = 5
487
488# In case there's isses with halting, you can specify this
489# to always poweroff after this amount of time after calling
490# halt.
491# Note, POWEROFF_AFTER_HALT = 0 does NOT disable it. It just
492# makes it poweroff immediately after halting. Do not define
493# it if you do not want it.
494# (default undefined)
495#POWEROFF_AFTER_HALT = 20
496
497# A script or command to power off the box (default undefined)
498# Needed for POWEROFF_ON_ERROR and SUCCESS
499#
500# Example for digital loggers power switch:
501#POWER_OFF = wget --no-proxy -O /dev/null -q --auth-no-challenge 'http://admin:admin@power/outlet?5=OFF'
502#
503# Example for a virtual guest call "Guest".
504#POWER_OFF = virsh destroy Guest
505
506# The way to execute a command on the target
507# (default ssh $SSH_USER@$MACHINE $SSH_COMMAND";)
508# The variables SSH_USER, MACHINE and SSH_COMMAND are defined
509#SSH_EXEC = ssh $SSH_USER@$MACHINE $SSH_COMMAND";
510
511# The way to copy a file to the target
512# (default scp $SRC_FILE $SSH_USER@$MACHINE:$DST_FILE)
513# The variables SSH_USER, MACHINE, SRC_FILE and DST_FILE are defined.
514#SCP_TO_TARGET = scp $SRC_FILE $SSH_USER@$MACHINE:$DST_FILE
515
516# The nice way to reboot the target
517# (default ssh $SSH_USER@$MACHINE reboot)
518# The variables SSH_USER and MACHINE are defined.
519#REBOOT = ssh $SSH_USER@$MACHINE reboot
520
521#### Per test run options ####
522# The following options are only allowed in TEST_START sections.
523# They are ignored in the DEFAULTS sections.
524#
525# All of these are optional and undefined by default, although
526# some of these options are required for TEST_TYPE of patchcheck
527# and bisect.
528#
529#
530# CHECKOUT = branch
531#
532# If the BUILD_DIR is a git repository, then you can set this option
533# to checkout the given branch before running the TEST. If you
534# specify this for the first run, that branch will be used for
535# all preceding tests until a new CHECKOUT is set.
536#
537#
538#
539# For TEST_TYPE = patchcheck
540#
541# This expects the BUILD_DIR to be a git repository, and
542# will checkout the PATCHCHECK_START commit.
543#
544# The option BUILD_TYPE will be ignored.
545#
546# The MIN_CONFIG will be used for all builds of the patchcheck. The build type
547# used for patchcheck is oldconfig.
548#
549# PATCHCHECK_START is required and is the first patch to
550# test (the SHA1 of the commit). You may also specify anything
551# that git checkout allows (branch name, tage, HEAD~3).
552#
553# PATCHCHECK_END is the last patch to check (default HEAD)
554#
555# PATCHCHECK_TYPE is required and is the type of test to run:
556# build, boot, test.
557#
558# Note, the build test will look for warnings, if a warning occurred
559# in a file that a commit touches, the build will fail.
560#
561# If BUILD_NOCLEAN is set, then make mrproper will not be run on
562# any of the builds, just like all other TEST_TYPE tests. But
563# what makes patchcheck different from the other tests, is if
564# BUILD_NOCLEAN is not set, only the first and last patch run
565# make mrproper. This helps speed up the test.
566#
567# Example:
568# TEST_START
569# TEST_TYPE = patchcheck
570# CHECKOUT = mybranch
571# PATCHCHECK_TYPE = boot
572# PATCHCHECK_START = 747e94ae3d1b4c9bf5380e569f614eb9040b79e7
573# PATCHCHECK_END = HEAD~2
574#
575#
576#
577# For TEST_TYPE = bisect
578#
579# You can specify a git bisect if the BUILD_DIR is a git repository.
580# The MIN_CONFIG will be used for all builds of the bisect. The build type
581# used for bisecting is oldconfig.
582#
583# The option BUILD_TYPE will be ignored.
584#
585# BISECT_TYPE is the type of test to perform:
586# build - bad fails to build
587# boot - bad builds but fails to boot
588# test - bad boots but fails a test
589#
590# BISECT_GOOD is the commit (SHA1) to label as good (accepts all git good commit types)
591# BISECT_BAD is the commit to label as bad (accepts all git bad commit types)
592#
593# The above three options are required for a bisect operation.
594#
595# BISECT_REPLAY = /path/to/replay/file (optional, default undefined)
596#
597# If an operation failed in the bisect that was not expected to
598# fail. Then the test ends. The state of the BUILD_DIR will be
599# left off at where the failure occurred. You can examine the
600# reason for the failure, and perhaps even find a git commit
601# that would work to continue with. You can run:
602#
603# git bisect log > /path/to/replay/file
604#
605# The adding:
606#
607# BISECT_REPLAY= /path/to/replay/file
608#
609# And running the test again. The test will perform the initial
610# git bisect start, git bisect good, and git bisect bad, and
611# then it will run git bisect replay on this file, before
612# continuing with the bisect.
613#
614# BISECT_START = commit (optional, default undefined)
615#
616# As with BISECT_REPLAY, if the test failed on a commit that
617# just happen to have a bad commit in the middle of the bisect,
618# and you need to skip it. If BISECT_START is defined, it
619# will checkout that commit after doing the initial git bisect start,
620# git bisect good, git bisect bad, and running the git bisect replay
621# if the BISECT_REPLAY is set.
622#
623# BISECT_SKIP = 1 (optional, default 0)
624#
625# If BISECT_TYPE is set to test but the build fails, ktest will
626# simply fail the test and end their. You could use BISECT_REPLAY
627# and BISECT_START to resume after you found a new starting point,
628# or you could set BISECT_SKIP to 1. If BISECT_SKIP is set to 1,
629# when something other than the BISECT_TYPE fails, ktest.pl will
630# run "git bisect skip" and try again.
631#
632# BISECT_FILES = <path> (optional, default undefined)
633#
634# To just run the git bisect on a specific path, set BISECT_FILES.
635# For example:
636#
637# BISECT_FILES = arch/x86 kernel/time
638#
639# Will run the bisect with "git bisect start -- arch/x86 kernel/time"
640#
641# BISECT_REVERSE = 1 (optional, default 0)
642#
643# In those strange instances where it was broken forever
644# and you are trying to find where it started to work!
645# Set BISECT_GOOD to the commit that was last known to fail
646# Set BISECT_BAD to the commit that is known to start working.
647# With BISECT_REVERSE = 1, The test will consider failures as
648# good, and success as bad.
649#
650# BISECT_MANUAL = 1 (optional, default 0)
651#
652# In case there's a problem with automating the bisect for
653# whatever reason. (Can't reboot, want to inspect each iteration)
654# Doing a BISECT_MANUAL will have the test wait for you to
655# tell it if the test passed or failed after each iteration.
656# This is basicall the same as running git bisect yourself
657# but ktest will rebuild and install the kernel for you.
658#
659# BISECT_CHECK = 1 (optional, default 0)
660#
661# Just to be sure the good is good and bad is bad, setting
662# BISECT_CHECK to 1 will start the bisect by first checking
663# out BISECT_BAD and makes sure it fails, then it will check
664# out BISECT_GOOD and makes sure it succeeds before starting
665# the bisect (it works for BISECT_REVERSE too).
666#
667# You can limit the test to just check BISECT_GOOD or
668# BISECT_BAD with BISECT_CHECK = good or
669# BISECT_CHECK = bad, respectively.
670#
671# Example:
672# TEST_START
673# TEST_TYPE = bisect
674# BISECT_GOOD = v2.6.36
675# BISECT_BAD = b5153163ed580e00c67bdfecb02b2e3843817b3e
676# BISECT_TYPE = build
677# MIN_CONFIG = /home/test/config-bisect
678#
679#
680#
681# For TEST_TYPE = config_bisect
682#
683# In those cases that you have two different configs. One of them
684# work, the other does not, and you do not know what config causes
685# the problem.
686# The TEST_TYPE config_bisect will bisect the bad config looking for
687# what config causes the failure.
688#
689# The way it works is this:
690#
691# First it finds a config to work with. Since a different version, or
692# MIN_CONFIG may cause different dependecies, it must run through this
693# preparation.
694#
695# Overwrites any config set in the bad config with a config set in
696# either the MIN_CONFIG or ADD_CONFIG. Thus, make sure these configs
697# are minimal and do not disable configs you want to test:
698# (ie. # CONFIG_FOO is not set).
699#
700# An oldconfig is run on the bad config and any new config that
701# appears will be added to the configs to test.
702#
703# Finally, it generates a config with the above result and runs it
704# again through make oldconfig to produce a config that should be
705# satisfied by kconfig.
706#
707# Then it starts the bisect.
708#
709# The configs to test are cut in half. If all the configs in this
710# half depend on a config in the other half, then the other half
711# is tested instead. If no configs are enabled by either half, then
712# this means a circular dependency exists and the test fails.
713#
714# A config is created with the test half, and the bisect test is run.
715#
716# If the bisect succeeds, then all configs in the generated config
717# are removed from the configs to test and added to the configs that
718# will be enabled for all builds (they will be enabled, but not be part
719# of the configs to examine).
720#
721# If the bisect fails, then all test configs that were not enabled by
722# the config file are removed from the test. These configs will not
723# be enabled in future tests. Since current config failed, we consider
724# this to be a subset of the config that we started with.
725#
726# When we are down to one config, it is considered the bad config.
727#
728# Note, the config chosen may not be the true bad config. Due to
729# dependencies and selections of the kbuild system, mulitple
730# configs may be needed to cause a failure. If you disable the
731# config that was found and restart the test, if the test fails
732# again, it is recommended to rerun the config_bisect with a new
733# bad config without the found config enabled.
734#
735# The option BUILD_TYPE will be ignored.
736#
737# CONFIG_BISECT_TYPE is the type of test to perform:
738# build - bad fails to build
739# boot - bad builds but fails to boot
740# test - bad boots but fails a test
741#
742# CONFIG_BISECT is the config that failed to boot
743#
744# If BISECT_MANUAL is set, it will pause between iterations.
745# This is useful to use just ktest.pl just for the config bisect.
746# If you set it to build, it will run the bisect and you can
747# control what happens in between iterations. It will ask you if
748# the test succeeded or not and continue the config bisect.
749#
750# Example:
751# TEST_START
752# TEST_TYPE = config_bisect
753# CONFIG_BISECT_TYPE = build
754# CONFIG_BISECT = /home/test/¢onfig-bad
755# MIN_CONFIG = /home/test/config-min
756# BISECT_MANUAL = 1
757#
diff --git a/tools/usb/Makefile b/tools/usb/Makefile
new file mode 100644
index 000000000000..8b704af14349
--- /dev/null
+++ b/tools/usb/Makefile
@@ -0,0 +1,13 @@
1# Makefile for USB tools
2
3CC = $(CROSS_COMPILE)gcc
4PTHREAD_LIBS = -lpthread
5WARNINGS = -Wall -Wextra
6CFLAGS = $(WARNINGS) -g $(PTHREAD_LIBS)
7
8all: testusb ffs-test
9%: %.c
10 $(CC) $(CFLAGS) -o $@ $^
11
12clean:
13 $(RM) testusb ffs-test
diff --git a/tools/usb/ffs-test.c b/tools/usb/ffs-test.c
index bbe2e3a2ea62..b9c798631699 100644
--- a/tools/usb/ffs-test.c
+++ b/tools/usb/ffs-test.c
@@ -37,7 +37,7 @@
37#include <sys/types.h> 37#include <sys/types.h>
38#include <unistd.h> 38#include <unistd.h>
39 39
40#include <linux/usb/functionfs.h> 40#include "../../include/linux/usb/functionfs.h"
41 41
42 42
43/******************** Little Endian Handling ********************************/ 43/******************** Little Endian Handling ********************************/
@@ -450,7 +450,7 @@ invalid:
450 len, expected, *p); 450 len, expected, *p);
451 for (p = buf, len = 0; len < nbytes; ++p, ++len) { 451 for (p = buf, len = 0; len < nbytes; ++p, ++len) {
452 if (0 == (len % 32)) 452 if (0 == (len % 32))
453 fprintf(stderr, "%4d:", len); 453 fprintf(stderr, "%4zd:", len);
454 fprintf(stderr, " %02x", *p); 454 fprintf(stderr, " %02x", *p);
455 if (31 == (len % 32)) 455 if (31 == (len % 32))
456 fprintf(stderr, "\n"); 456 fprintf(stderr, "\n");
diff --git a/tools/usb/hcd-tests.sh b/tools/usb/hcd-tests.sh
new file mode 100644
index 000000000000..b30b3dc4c788
--- /dev/null
+++ b/tools/usb/hcd-tests.sh
@@ -0,0 +1,275 @@
1#!/bin/sh
2#
3# test types can be passed on the command line:
4#
5# - control: any device can do this
6# - out, in: out needs 'bulk sink' firmware, in needs 'bulk src'
7# - iso-out, iso-in: out needs 'iso sink' firmware, in needs 'iso src'
8# - halt: needs bulk sink+src, tests halt set/clear from host
9# - unlink: needs bulk sink and/or src, test HCD unlink processing
10# - loop: needs firmware that will buffer N transfers
11#
12# run it for hours, days, weeks.
13#
14
15#
16# this default provides a steady test load for a bulk device
17#
18TYPES='control out in'
19#TYPES='control out in halt'
20
21#
22# to test HCD code
23#
24# - include unlink tests
25# - add some ${RANDOM}ness
26# - connect several devices concurrently (same HC)
27# - keep HC's IRQ lines busy with unrelated traffic (IDE, net, ...)
28# - add other concurrent system loads
29#
30
31declare -i COUNT BUFLEN
32
33COUNT=50000
34BUFLEN=2048
35
36# NOTE: the 'in' and 'out' cases are usually bulk, but can be
37# set up to use interrupt transfers by 'usbtest' module options
38
39
40if [ "$DEVICE" = "" ]; then
41 echo "testing ALL recognized usbtest devices"
42 echo ""
43 TEST_ARGS="-a"
44else
45 TEST_ARGS=""
46fi
47
48do_test ()
49{
50 if ! ./testusb $TEST_ARGS -s $BUFLEN -c $COUNT $* 2>/dev/null
51 then
52 echo "FAIL"
53 exit 1
54 fi
55}
56
57ARGS="$*"
58
59if [ "$ARGS" = "" ];
60then
61 ARGS="$TYPES"
62fi
63
64# FIXME use /sys/bus/usb/device/$THIS/bConfigurationValue to
65# check and change configs
66
67CONFIG=''
68
69check_config ()
70{
71 if [ "$CONFIG" = "" ]; then
72 CONFIG=$1
73 echo "assuming $CONFIG configuration"
74 return
75 fi
76 if [ "$CONFIG" = $1 ]; then
77 return
78 fi
79
80 echo "** device must be in $1 config, but it's $CONFIG instead"
81 exit 1
82}
83
84
85echo "TESTING: $ARGS"
86
87while : true
88do
89 echo $(date)
90
91 for TYPE in $ARGS
92 do
93 # restore defaults
94 COUNT=5000
95 BUFLEN=2048
96
97 # FIXME automatically multiply COUNT by 10 when
98 # /sys/bus/usb/device/$THIS/speed == "480"
99
100# COUNT=50000
101
102 case $TYPE in
103 control)
104 # any device, in any configuration, can use this.
105 echo '** Control test cases:'
106
107 echo "test 9: ch9 postconfig"
108 do_test -t 9 -c 5000
109 echo "test 10: control queueing"
110 do_test -t 10 -c 5000
111
112 # this relies on some vendor-specific commands
113 echo "test 14: control writes"
114 do_test -t 14 -c 15000 -s 256 -v 1
115
116 echo "test 21: control writes, unaligned"
117 do_test -t 21 -c 100 -s 256 -v 1
118
119 ;;
120
121 out)
122 check_config sink-src
123 echo '** Host Write (OUT) test cases:'
124
125 echo "test 1: $COUNT transfers, same size"
126 do_test -t 1
127 echo "test 3: $COUNT transfers, variable/short size"
128 do_test -t 3 -v 421
129
130 COUNT=100
131 echo "test 17: $COUNT transfers, unaligned DMA map by core"
132 do_test -t 17
133
134 echo "test 19: $COUNT transfers, unaligned DMA map by usb_alloc_coherent"
135 do_test -t 19
136
137 COUNT=2000
138 echo "test 5: $COUNT scatterlists, same size entries"
139 do_test -t 5
140
141 # try to trigger short OUT processing bugs
142 echo "test 7a: $COUNT scatterlists, variable size/short entries"
143 do_test -t 7 -v 579
144 BUFLEN=4096
145 echo "test 7b: $COUNT scatterlists, variable size/bigger entries"
146 do_test -t 7 -v 41
147 BUFLEN=64
148 echo "test 7c: $COUNT scatterlists, variable size/micro entries"
149 do_test -t 7 -v 63
150 ;;
151
152 iso-out)
153 check_config sink-src
154 echo '** Host ISOCHRONOUS Write (OUT) test cases:'
155
156 # at peak iso transfer rates:
157 # - usb 2.0 high bandwidth, this is one frame.
158 # - usb 1.1, it's twenty-four frames.
159 BUFLEN=24500
160
161 COUNT=1000
162
163# COUNT=10000
164
165 echo "test 15: $COUNT transfers, same size"
166 # do_test -t 15 -g 3 -v 0
167 BUFLEN=32768
168 do_test -t 15 -g 8 -v 0
169
170 # FIXME it'd make sense to have an iso OUT test issuing
171 # short writes on more packets than the last one
172
173 COUNT=100
174 echo "test 22: $COUNT transfers, non aligned"
175 do_test -t 22 -g 8 -v 0
176
177 ;;
178
179 in)
180 check_config sink-src
181 echo '** Host Read (IN) test cases:'
182
183 # NOTE: these "variable size" reads are just multiples
184 # of 512 bytes, no EOVERFLOW testing is done yet
185
186 echo "test 2: $COUNT transfers, same size"
187 do_test -t 2
188 echo "test 4: $COUNT transfers, variable size"
189 do_test -t 4
190
191 COUNT=100
192 echo "test 18: $COUNT transfers, unaligned DMA map by core"
193 do_test -t 18
194
195 echo "test 20: $COUNT transfers, unaligned DMA map by usb_alloc_coherent"
196 do_test -t 20
197
198 COUNT=2000
199 echo "test 6: $COUNT scatterlists, same size entries"
200 do_test -t 6
201 echo "test 8: $COUNT scatterlists, variable size entries"
202 do_test -t 8
203 ;;
204
205 iso-in)
206 check_config sink-src
207 echo '** Host ISOCHRONOUS Read (IN) test cases:'
208
209 # at peak iso transfer rates:
210 # - usb 2.0 high bandwidth, this is one frame.
211 # - usb 1.1, it's twenty-four frames.
212 BUFLEN=24500
213
214 COUNT=1000
215
216# COUNT=10000
217
218 echo "test 16: $COUNT transfers, same size"
219 # do_test -t 16 -g 3 -v 0
220 BUFLEN=32768
221 do_test -t 16 -g 8 -v 0
222
223 # FIXME since iso expects faults, it'd make sense
224 # to have an iso IN test issuing short reads ...
225
226 COUNT=100
227 echo "test 23: $COUNT transfers, unaligned"
228 do_test -t 23 -g 8 -v 0
229
230 ;;
231
232 halt)
233 # NOTE: sometimes hardware doesn't cooperate well with halting
234 # endpoints from the host side. so long as mass-storage class
235 # firmware can halt them from the device, don't worry much if
236 # you can't make this test work on your device.
237 COUNT=2000
238 echo "test 13: $COUNT halt set/clear"
239 do_test -t 13
240 ;;
241
242 unlink)
243 COUNT=2000
244 echo "test 11: $COUNT read unlinks"
245 do_test -t 11
246
247 echo "test 12: $COUNT write unlinks"
248 do_test -t 12
249 ;;
250
251 loop)
252 # defaults need too much buffering for ez-usb devices
253 BUFLEN=2048
254 COUNT=32
255
256 # modprobe g_zero qlen=$COUNT buflen=$BUFLEN loopdefault
257 check_config loopback
258
259 # FIXME someone needs to write and merge a version of this
260
261 echo "write $COUNT buffers of $BUFLEN bytes, read them back"
262
263 echo "write $COUNT variable size buffers, read them back"
264
265 ;;
266
267 *)
268 echo "Don't understand test type $TYPE"
269 exit 1;
270 esac
271 echo ''
272 done
273done
274
275# vim: sw=4
diff --git a/tools/virtio/Makefile b/tools/virtio/Makefile
new file mode 100644
index 000000000000..d1d442ed106a
--- /dev/null
+++ b/tools/virtio/Makefile
@@ -0,0 +1,12 @@
1all: test mod
2test: virtio_test
3virtio_test: virtio_ring.o virtio_test.o
4CFLAGS += -g -O2 -Wall -I. -I ../../usr/include/ -Wno-pointer-sign -fno-strict-overflow -MMD
5vpath %.c ../../drivers/virtio
6mod:
7 ${MAKE} -C `pwd`/../.. M=`pwd`/vhost_test
8.PHONY: all test mod clean
9clean:
10 ${RM} *.o vhost_test/*.o vhost_test/.*.cmd \
11 vhost_test/Module.symvers vhost_test/modules.order *.d
12-include *.d
diff --git a/tools/virtio/linux/device.h b/tools/virtio/linux/device.h
new file mode 100644
index 000000000000..4ad7e1df0db5
--- /dev/null
+++ b/tools/virtio/linux/device.h
@@ -0,0 +1,2 @@
1#ifndef LINUX_DEVICE_H
2#endif
diff --git a/tools/virtio/linux/slab.h b/tools/virtio/linux/slab.h
new file mode 100644
index 000000000000..81baeac8ae40
--- /dev/null
+++ b/tools/virtio/linux/slab.h
@@ -0,0 +1,2 @@
1#ifndef LINUX_SLAB_H
2#endif
diff --git a/tools/virtio/linux/virtio.h b/tools/virtio/linux/virtio.h
new file mode 100644
index 000000000000..669bcdd45805
--- /dev/null
+++ b/tools/virtio/linux/virtio.h
@@ -0,0 +1,223 @@
1#ifndef LINUX_VIRTIO_H
2#define LINUX_VIRTIO_H
3
4#include <stdbool.h>
5#include <stdlib.h>
6#include <stddef.h>
7#include <stdio.h>
8#include <string.h>
9#include <assert.h>
10
11#include <linux/types.h>
12#include <errno.h>
13
14typedef unsigned long long dma_addr_t;
15
16struct scatterlist {
17 unsigned long page_link;
18 unsigned int offset;
19 unsigned int length;
20 dma_addr_t dma_address;
21};
22
23struct page {
24 unsigned long long dummy;
25};
26
27#define BUG_ON(__BUG_ON_cond) assert(!(__BUG_ON_cond))
28
29/* Physical == Virtual */
30#define virt_to_phys(p) ((unsigned long)p)
31#define phys_to_virt(a) ((void *)(unsigned long)(a))
32/* Page address: Virtual / 4K */
33#define virt_to_page(p) ((struct page*)((virt_to_phys(p) / 4096) * \
34 sizeof(struct page)))
35#define offset_in_page(p) (((unsigned long)p) % 4096)
36#define sg_phys(sg) ((sg->page_link & ~0x3) / sizeof(struct page) * 4096 + \
37 sg->offset)
38static inline void sg_mark_end(struct scatterlist *sg)
39{
40 /*
41 * Set termination bit, clear potential chain bit
42 */
43 sg->page_link |= 0x02;
44 sg->page_link &= ~0x01;
45}
46static inline void sg_init_table(struct scatterlist *sgl, unsigned int nents)
47{
48 memset(sgl, 0, sizeof(*sgl) * nents);
49 sg_mark_end(&sgl[nents - 1]);
50}
51static inline void sg_assign_page(struct scatterlist *sg, struct page *page)
52{
53 unsigned long page_link = sg->page_link & 0x3;
54
55 /*
56 * In order for the low bit stealing approach to work, pages
57 * must be aligned at a 32-bit boundary as a minimum.
58 */
59 BUG_ON((unsigned long) page & 0x03);
60 sg->page_link = page_link | (unsigned long) page;
61}
62
63static inline void sg_set_page(struct scatterlist *sg, struct page *page,
64 unsigned int len, unsigned int offset)
65{
66 sg_assign_page(sg, page);
67 sg->offset = offset;
68 sg->length = len;
69}
70
71static inline void sg_set_buf(struct scatterlist *sg, const void *buf,
72 unsigned int buflen)
73{
74 sg_set_page(sg, virt_to_page(buf), buflen, offset_in_page(buf));
75}
76
77static inline void sg_init_one(struct scatterlist *sg, const void *buf, unsigned int buflen)
78{
79 sg_init_table(sg, 1);
80 sg_set_buf(sg, buf, buflen);
81}
82
83typedef __u16 u16;
84
85typedef enum {
86 GFP_KERNEL,
87 GFP_ATOMIC,
88} gfp_t;
89typedef enum {
90 IRQ_NONE,
91 IRQ_HANDLED
92} irqreturn_t;
93
94static inline void *kmalloc(size_t s, gfp_t gfp)
95{
96 return malloc(s);
97}
98
99static inline void kfree(void *p)
100{
101 free(p);
102}
103
104#define container_of(ptr, type, member) ({ \
105 const typeof( ((type *)0)->member ) *__mptr = (ptr); \
106 (type *)( (char *)__mptr - offsetof(type,member) );})
107
108#define uninitialized_var(x) x = x
109
110# ifndef likely
111# define likely(x) (__builtin_expect(!!(x), 1))
112# endif
113# ifndef unlikely
114# define unlikely(x) (__builtin_expect(!!(x), 0))
115# endif
116
117#define pr_err(format, ...) fprintf (stderr, format, ## __VA_ARGS__)
118#ifdef DEBUG
119#define pr_debug(format, ...) fprintf (stderr, format, ## __VA_ARGS__)
120#else
121#define pr_debug(format, ...) do {} while (0)
122#endif
123#define dev_err(dev, format, ...) fprintf (stderr, format, ## __VA_ARGS__)
124#define dev_warn(dev, format, ...) fprintf (stderr, format, ## __VA_ARGS__)
125
126/* TODO: empty stubs for now. Broken but enough for virtio_ring.c */
127#define list_add_tail(a, b) do {} while (0)
128#define list_del(a) do {} while (0)
129
130#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
131#define BITS_PER_BYTE 8
132#define BITS_PER_LONG (sizeof(long) * BITS_PER_BYTE)
133#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
134/* TODO: Not atomic as it should be:
135 * we don't use this for anything important. */
136static inline void clear_bit(int nr, volatile unsigned long *addr)
137{
138 unsigned long mask = BIT_MASK(nr);
139 unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
140
141 *p &= ~mask;
142}
143
144static inline int test_bit(int nr, const volatile unsigned long *addr)
145{
146 return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1)));
147}
148
149/* The only feature we care to support */
150#define virtio_has_feature(dev, feature) \
151 test_bit((feature), (dev)->features)
152/* end of stubs */
153
154struct virtio_device {
155 void *dev;
156 unsigned long features[1];
157};
158
159struct virtqueue {
160 /* TODO: commented as list macros are empty stubs for now.
161 * Broken but enough for virtio_ring.c
162 * struct list_head list; */
163 void (*callback)(struct virtqueue *vq);
164 const char *name;
165 struct virtio_device *vdev;
166 void *priv;
167};
168
169#define EXPORT_SYMBOL_GPL(__EXPORT_SYMBOL_GPL_name) \
170 void __EXPORT_SYMBOL_GPL##__EXPORT_SYMBOL_GPL_name() { \
171}
172#define MODULE_LICENSE(__MODULE_LICENSE_value) \
173 const char *__MODULE_LICENSE_name = __MODULE_LICENSE_value
174
175#define CONFIG_SMP
176
177#if defined(__i386__) || defined(__x86_64__)
178#define barrier() asm volatile("" ::: "memory")
179#define mb() __sync_synchronize()
180
181#define smp_mb() mb()
182# define smp_rmb() barrier()
183# define smp_wmb() barrier()
184#else
185#error Please fill in barrier macros
186#endif
187
188/* Interfaces exported by virtio_ring. */
189int virtqueue_add_buf_gfp(struct virtqueue *vq,
190 struct scatterlist sg[],
191 unsigned int out_num,
192 unsigned int in_num,
193 void *data,
194 gfp_t gfp);
195
196static inline int virtqueue_add_buf(struct virtqueue *vq,
197 struct scatterlist sg[],
198 unsigned int out_num,
199 unsigned int in_num,
200 void *data)
201{
202 return virtqueue_add_buf_gfp(vq, sg, out_num, in_num, data, GFP_ATOMIC);
203}
204
205void virtqueue_kick(struct virtqueue *vq);
206
207void *virtqueue_get_buf(struct virtqueue *vq, unsigned int *len);
208
209void virtqueue_disable_cb(struct virtqueue *vq);
210
211bool virtqueue_enable_cb(struct virtqueue *vq);
212
213void *virtqueue_detach_unused_buf(struct virtqueue *vq);
214struct virtqueue *vring_new_virtqueue(unsigned int num,
215 unsigned int vring_align,
216 struct virtio_device *vdev,
217 void *pages,
218 void (*notify)(struct virtqueue *vq),
219 void (*callback)(struct virtqueue *vq),
220 const char *name);
221void vring_del_virtqueue(struct virtqueue *vq);
222
223#endif
diff --git a/tools/virtio/vhost_test/Makefile b/tools/virtio/vhost_test/Makefile
new file mode 100644
index 000000000000..a1d35b81b314
--- /dev/null
+++ b/tools/virtio/vhost_test/Makefile
@@ -0,0 +1,2 @@
1obj-m += vhost_test.o
2EXTRA_CFLAGS += -Idrivers/vhost
diff --git a/tools/virtio/vhost_test/vhost_test.c b/tools/virtio/vhost_test/vhost_test.c
new file mode 100644
index 000000000000..18735189e62b
--- /dev/null
+++ b/tools/virtio/vhost_test/vhost_test.c
@@ -0,0 +1 @@
#include "test.c"
diff --git a/tools/virtio/virtio_test.c b/tools/virtio/virtio_test.c
new file mode 100644
index 000000000000..74d3331bdaf9
--- /dev/null
+++ b/tools/virtio/virtio_test.c
@@ -0,0 +1,263 @@
1#define _GNU_SOURCE
2#include <getopt.h>
3#include <string.h>
4#include <poll.h>
5#include <sys/eventfd.h>
6#include <stdlib.h>
7#include <assert.h>
8#include <unistd.h>
9#include <sys/ioctl.h>
10#include <sys/stat.h>
11#include <sys/types.h>
12#include <fcntl.h>
13#include <linux/vhost.h>
14#include <linux/virtio.h>
15#include <linux/virtio_ring.h>
16#include "../../drivers/vhost/test.h"
17
18struct vq_info {
19 int kick;
20 int call;
21 int num;
22 int idx;
23 void *ring;
24 /* copy used for control */
25 struct vring vring;
26 struct virtqueue *vq;
27};
28
29struct vdev_info {
30 struct virtio_device vdev;
31 int control;
32 struct pollfd fds[1];
33 struct vq_info vqs[1];
34 int nvqs;
35 void *buf;
36 size_t buf_size;
37 struct vhost_memory *mem;
38};
39
40void vq_notify(struct virtqueue *vq)
41{
42 struct vq_info *info = vq->priv;
43 unsigned long long v = 1;
44 int r;
45 r = write(info->kick, &v, sizeof v);
46 assert(r == sizeof v);
47}
48
49void vq_callback(struct virtqueue *vq)
50{
51}
52
53
54void vhost_vq_setup(struct vdev_info *dev, struct vq_info *info)
55{
56 struct vhost_vring_state state = { .index = info->idx };
57 struct vhost_vring_file file = { .index = info->idx };
58 unsigned long long features = dev->vdev.features[0];
59 struct vhost_vring_addr addr = {
60 .index = info->idx,
61 .desc_user_addr = (uint64_t)(unsigned long)info->vring.desc,
62 .avail_user_addr = (uint64_t)(unsigned long)info->vring.avail,
63 .used_user_addr = (uint64_t)(unsigned long)info->vring.used,
64 };
65 int r;
66 r = ioctl(dev->control, VHOST_SET_FEATURES, &features);
67 assert(r >= 0);
68 state.num = info->vring.num;
69 r = ioctl(dev->control, VHOST_SET_VRING_NUM, &state);
70 assert(r >= 0);
71 state.num = 0;
72 r = ioctl(dev->control, VHOST_SET_VRING_BASE, &state);
73 assert(r >= 0);
74 r = ioctl(dev->control, VHOST_SET_VRING_ADDR, &addr);
75 assert(r >= 0);
76 file.fd = info->kick;
77 r = ioctl(dev->control, VHOST_SET_VRING_KICK, &file);
78 assert(r >= 0);
79 file.fd = info->call;
80 r = ioctl(dev->control, VHOST_SET_VRING_CALL, &file);
81 assert(r >= 0);
82}
83
84static void vq_info_add(struct vdev_info *dev, int num)
85{
86 struct vq_info *info = &dev->vqs[dev->nvqs];
87 int r;
88 info->idx = dev->nvqs;
89 info->kick = eventfd(0, EFD_NONBLOCK);
90 info->call = eventfd(0, EFD_NONBLOCK);
91 r = posix_memalign(&info->ring, 4096, vring_size(num, 4096));
92 assert(r >= 0);
93 memset(info->ring, 0, vring_size(num, 4096));
94 vring_init(&info->vring, num, info->ring, 4096);
95 info->vq = vring_new_virtqueue(info->vring.num, 4096, &dev->vdev, info->ring,
96 vq_notify, vq_callback, "test");
97 assert(info->vq);
98 info->vq->priv = info;
99 vhost_vq_setup(dev, info);
100 dev->fds[info->idx].fd = info->call;
101 dev->fds[info->idx].events = POLLIN;
102 dev->nvqs++;
103}
104
105static void vdev_info_init(struct vdev_info* dev, unsigned long long features)
106{
107 int r;
108 memset(dev, 0, sizeof *dev);
109 dev->vdev.features[0] = features;
110 dev->vdev.features[1] = features >> 32;
111 dev->buf_size = 1024;
112 dev->buf = malloc(dev->buf_size);
113 assert(dev->buf);
114 dev->control = open("/dev/vhost-test", O_RDWR);
115 assert(dev->control >= 0);
116 r = ioctl(dev->control, VHOST_SET_OWNER, NULL);
117 assert(r >= 0);
118 dev->mem = malloc(offsetof(struct vhost_memory, regions) +
119 sizeof dev->mem->regions[0]);
120 assert(dev->mem);
121 memset(dev->mem, 0, offsetof(struct vhost_memory, regions) +
122 sizeof dev->mem->regions[0]);
123 dev->mem->nregions = 1;
124 dev->mem->regions[0].guest_phys_addr = (long)dev->buf;
125 dev->mem->regions[0].userspace_addr = (long)dev->buf;
126 dev->mem->regions[0].memory_size = dev->buf_size;
127 r = ioctl(dev->control, VHOST_SET_MEM_TABLE, dev->mem);
128 assert(r >= 0);
129}
130
131/* TODO: this is pretty bad: we get a cache line bounce
132 * for the wait queue on poll and another one on read,
133 * plus the read which is there just to clear the
134 * current state. */
135static void wait_for_interrupt(struct vdev_info *dev)
136{
137 int i;
138 unsigned long long val;
139 poll(dev->fds, dev->nvqs, -1);
140 for (i = 0; i < dev->nvqs; ++i)
141 if (dev->fds[i].revents & POLLIN) {
142 read(dev->fds[i].fd, &val, sizeof val);
143 }
144}
145
146static void run_test(struct vdev_info *dev, struct vq_info *vq, int bufs)
147{
148 struct scatterlist sl;
149 long started = 0, completed = 0;
150 long completed_before;
151 int r, test = 1;
152 unsigned len;
153 long long spurious = 0;
154 r = ioctl(dev->control, VHOST_TEST_RUN, &test);
155 assert(r >= 0);
156 for (;;) {
157 virtqueue_disable_cb(vq->vq);
158 completed_before = completed;
159 do {
160 if (started < bufs) {
161 sg_init_one(&sl, dev->buf, dev->buf_size);
162 r = virtqueue_add_buf(vq->vq, &sl, 1, 0,
163 dev->buf + started);
164 if (likely(r >= 0)) {
165 ++started;
166 virtqueue_kick(vq->vq);
167 }
168 } else
169 r = -1;
170
171 /* Flush out completed bufs if any */
172 if (virtqueue_get_buf(vq->vq, &len)) {
173 ++completed;
174 r = 0;
175 }
176
177 } while (r >= 0);
178 if (completed == completed_before)
179 ++spurious;
180 assert(completed <= bufs);
181 assert(started <= bufs);
182 if (completed == bufs)
183 break;
184 if (virtqueue_enable_cb(vq->vq)) {
185 wait_for_interrupt(dev);
186 }
187 }
188 test = 0;
189 r = ioctl(dev->control, VHOST_TEST_RUN, &test);
190 assert(r >= 0);
191 fprintf(stderr, "spurious wakeus: 0x%llx\n", spurious);
192}
193
194const char optstring[] = "h";
195const struct option longopts[] = {
196 {
197 .name = "help",
198 .val = 'h',
199 },
200 {
201 .name = "event-idx",
202 .val = 'E',
203 },
204 {
205 .name = "no-event-idx",
206 .val = 'e',
207 },
208 {
209 .name = "indirect",
210 .val = 'I',
211 },
212 {
213 .name = "no-indirect",
214 .val = 'i',
215 },
216 {
217 }
218};
219
220static void help()
221{
222 fprintf(stderr, "Usage: virtio_test [--help]"
223 " [--no-indirect]"
224 " [--no-event-idx]"
225 "\n");
226}
227
228int main(int argc, char **argv)
229{
230 struct vdev_info dev;
231 unsigned long long features = (1ULL << VIRTIO_RING_F_INDIRECT_DESC) |
232 (1ULL << VIRTIO_RING_F_EVENT_IDX);
233 int o;
234
235 for (;;) {
236 o = getopt_long(argc, argv, optstring, longopts, NULL);
237 switch (o) {
238 case -1:
239 goto done;
240 case '?':
241 help();
242 exit(2);
243 case 'e':
244 features &= ~(1ULL << VIRTIO_RING_F_EVENT_IDX);
245 break;
246 case 'h':
247 help();
248 goto done;
249 case 'i':
250 features &= ~(1ULL << VIRTIO_RING_F_INDIRECT_DESC);
251 break;
252 default:
253 assert(0);
254 break;
255 }
256 }
257
258done:
259 vdev_info_init(&dev, features);
260 vq_info_add(&dev, 256);
261 run_test(&dev, &dev.vqs[0], 0x100000);
262 return 0;
263}