aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorStefan Richter <stefanr@s5r6.in-berlin.de>2011-05-10 14:52:07 -0400
committerStefan Richter <stefanr@s5r6.in-berlin.de>2011-05-10 16:50:41 -0400
commit020abf03cd659388f94cb328e1e1df0656e0d7ff (patch)
tree40d05011708ad1b4a05928d167eb120420581aa6 /tools
parent0ff8fbc61727c926883eec381fbd3d32d1fab504 (diff)
parent693d92a1bbc9e42681c42ed190bd42b636ca876f (diff)
Merge tag 'v2.6.39-rc7'
in order to pull in changes in drivers/media/dvb/firewire/ and sound/firewire/.
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.txt37
-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.txt23
-rw-r--r--tools/perf/Documentation/perf-lock.txt23
-rw-r--r--tools/perf/Documentation/perf-probe.txt28
-rw-r--r--tools/perf/Documentation/perf-record.txt36
-rw-r--r--tools/perf/Documentation/perf-report.txt55
-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)28
-rw-r--r--tools/perf/Documentation/perf-script-python.txt (renamed from tools/perf/Documentation/perf-trace-python.txt)88
-rw-r--r--tools/perf/Documentation/perf-script.txt (renamed from tools/perf/Documentation/perf-trace.txt)83
-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/MANIFEST1
-rw-r--r--tools/perf/Makefile698
-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.c347
-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.c75
-rw-r--r--tools/perf/builtin-record.c551
-rw-r--r--tools/perf/builtin-report.c227
-rw-r--r--tools/perf/builtin-sched.c100
-rw-r--r--tools/perf/builtin-script.c (renamed from tools/perf/builtin-trace.c)431
-rw-r--r--tools/perf/builtin-stat.c576
-rw-r--r--tools/perf/builtin-test.c408
-rw-r--r--tools/perf/builtin-timechart.c152
-rw-r--r--tools/perf/builtin-top.c1093
-rw-r--r--tools/perf/builtin.h3
-rw-r--r--tools/perf/command-list.txt3
-rw-r--r--tools/perf/feature-tests.mak4
-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-report2
-rw-r--r--tools/perf/scripts/perl/bin/rw-by-file-report5
-rw-r--r--tools/perf/scripts/perl/bin/rw-by-pid-report5
-rw-r--r--tools/perf/scripts/perl/bin/rwtop-report5
-rw-r--r--tools/perf/scripts/perl/bin/wakeup-latency-report5
-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.py2
-rw-r--r--tools/perf/scripts/python/bin/failed-syscalls-by-pid-report2
-rw-r--r--tools/perf/scripts/python/bin/futex-contention-report2
-rw-r--r--tools/perf/scripts/python/bin/netdev-times-report2
-rw-r--r--tools/perf/scripts/python/bin/sched-migration-report2
-rw-r--r--tools/perf/scripts/python/bin/sctop-report2
-rw-r--r--tools/perf/scripts/python/bin/syscall-counts-by-pid-report2
-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.py2
-rw-r--r--tools/perf/scripts/python/sched-migration.py2
-rw-r--r--tools/perf/scripts/python/sctop.py2
-rw-r--r--tools/perf/scripts/python/syscall-counts-by-pid.py2
-rw-r--r--tools/perf/scripts/python/syscall-counts.py2
-rwxr-xr-xtools/perf/util/PERF-VERSION-GEN8
-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.h7
-rw-r--r--tools/perf/util/callchain.c227
-rw-r--r--tools/perf/util/callchain.h76
-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.c52
-rw-r--r--tools/perf/util/debug.h5
-rw-r--r--tools/perf/util/event.c555
-rw-r--r--tools/perf/util/event.h74
-rw-r--r--tools/perf/util/evlist.c400
-rw-r--r--tools/perf/util/evlist.h68
-rw-r--r--tools/perf/util/evsel.c384
-rw-r--r--tools/perf/util/evsel.h152
-rw-r--r--tools/perf/util/exec_cmd.c19
-rw-r--r--tools/perf/util/header.c614
-rw-r--r--tools/perf/util/header.h94
-rw-r--r--tools/perf/util/hist.c259
-rw-r--r--tools/perf/util/hist.h63
-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/linkage.h13
-rw-r--r--tools/perf/util/include/linux/list.h1
-rw-r--r--tools/perf/util/map.c3
-rw-r--r--tools/perf/util/parse-events.c277
-rw-r--r--tools/perf/util/parse-events.h22
-rw-r--r--tools/perf/util/parse-options.h4
-rw-r--r--tools/perf/util/probe-event.c421
-rw-r--r--tools/perf/util/probe-event.h4
-rw-r--r--tools/perf/util/probe-finder.c813
-rw-r--r--tools/perf/util/probe-finder.h6
-rw-r--r--tools/perf/util/python.c897
-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.c847
-rw-r--r--tools/perf/util/session.h70
-rw-r--r--tools/perf/util/setup.py24
-rw-r--r--tools/perf/util/sort.c6
-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.c307
-rw-r--r--tools/perf/util/symbol.h38
-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.c25
-rw-r--r--tools/perf/util/ui/browser.h3
-rw-r--r--tools/perf/util/ui/browsers/annotate.c180
-rw-r--r--tools/perf/util/ui/browsers/hists.c199
-rw-r--r--tools/perf/util/ui/browsers/map.c7
-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.c19
-rw-r--r--tools/perf/util/util.c17
-rw-r--r--tools/perf/util/util.h27
-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.pl2122
-rw-r--r--tools/testing/ktest/sample.conf664
-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.c248
181 files changed, 16973 insertions, 5209 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 b2c63309a651..6f5a498608b2 100644
--- a/tools/perf/Documentation/perf-annotate.txt
+++ b/tools/perf/Documentation/perf-annotate.txt
@@ -24,12 +24,47 @@ 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
27--stdio:: Use the stdio interface. 62--stdio:: Use the stdio interface.
28 63
29--tui:: Use the TUI interface Use of --tui requires a tty, if one is not 64--tui:: Use the TUI interface Use of --tui requires a tty, if one is not
30 present, as when piping to other commands, the stdio interface is 65 present, as when piping to other commands, the stdio interface is
31 used. This interfaces starts by centering on the line with more 66 used. This interfaces starts by centering on the line with more
32 samples, TAB/UNTAB cycles thru the lines with more samples. 67 samples, TAB/UNTAB cycles through the lines with more samples.
33 68
34SEE ALSO 69SEE ALSO
35-------- 70--------
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 399751befeed..7a527f7e9da9 100644
--- a/tools/perf/Documentation/perf-list.txt
+++ b/tools/perf/Documentation/perf-list.txt
@@ -8,7 +8,7 @@ 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-----------
@@ -63,7 +63,26 @@ details. Some of them are referenced in the SEE ALSO section below.
63 63
64OPTIONS 64OPTIONS
65------- 65-------
66None 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.
67 86
68SEE ALSO 87SEE ALSO
69-------- 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 62de1b7f4e76..02bafce4b341 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -16,7 +16,7 @@ or
16or 16or
17'perf probe' --list 17'perf probe' --list
18or 18or
19'perf probe' [options] --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]' 19'perf probe' [options] --line='LINE'
20or 20or
21'perf probe' [options] --vars='PROBEPOINT' 21'perf probe' [options] --vars='PROBEPOINT'
22 22
@@ -73,6 +73,17 @@ OPTIONS
73 (Only for --vars) Show external defined variables in addition to local 73 (Only for --vars) Show external defined variables in addition to local
74 variables. 74 variables.
75 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
76-f:: 87-f::
77--force:: 88--force::
78 Forcibly add events with existing name. 89 Forcibly add events with existing name.
@@ -115,15 +126,16 @@ Each probe argument follows below syntax.
115 126
116LINE SYNTAX 127LINE SYNTAX
117----------- 128-----------
118Line range is descripted by following syntax. 129Line range is described by following syntax.
119 130
120 "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]" 131 "FUNC[@SRC][:RLN[+NUM|-RLN2]]|SRC[:ALN[+NUM|-ALN2]]"
121 132
122FUNC 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
123number 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
124probe 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,
125and '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
126many 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.
127So, "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.
128 140
129LAZY MATCHING 141LAZY MATCHING
@@ -135,6 +147,14 @@ e.g.
135 147
136This 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.)
137 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.
138 158
139EXAMPLES 159EXAMPLES
140-------- 160--------
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index a91f9f9e6e5c..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.
@@ -99,6 +111,11 @@ OPTIONS
99--data:: 111--data::
100 Sample addresses. 112 Sample addresses.
101 113
114-T::
115--timestamp::
116 Sample timestamps. Use it with 'perf report -D' to see the timestamps,
117 for instance.
118
102-n:: 119-n::
103--no-samples:: 120--no-samples::
104 Don't sample. 121 Don't sample.
@@ -109,8 +126,8 @@ Collect raw sample records from all opened counters (default for tracepoint coun
109 126
110-C:: 127-C::
111--cpu:: 128--cpu::
112Collect 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
113comma-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.
114In 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
115the 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.
116 133
@@ -120,6 +137,17 @@ Do not update the builid cache. This saves some overhead in situations
120where the information in the perf.data file (which includes buildids) 137where the information in the perf.data file (which includes buildids)
121is sufficient. 138is sufficient.
122 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
123SEE ALSO 151SEE ALSO
124-------- 152--------
125linkperf: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 12052c9ed0ba..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,26 @@ 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
68--stdio:: Use the stdio interface. 96--stdio:: Use the stdio interface.
69 97
70--tui:: Use the TUI interface, that is integrated with annotate and allows 98--tui:: Use the TUI interface, that is integrated with annotate and allows
@@ -72,6 +100,25 @@ OPTIONS
72 requires a tty, if one is not present, as when piping to other 100 requires a tty, if one is not present, as when piping to other
73 commands, the stdio interface is used. 101 commands, the stdio interface is used.
74 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
75SEE ALSO 122SEE ALSO
76-------- 123--------
77linkperf: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..5bb41e55a3ac 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
@@ -112,13 +112,13 @@ write a useful trace script. The sections below cover the rest.
112SCRIPT LAYOUT 112SCRIPT LAYOUT
113------------- 113-------------
114 114
115Every perf trace Perl script should start by setting up a Perl module 115Every perf script Perl script should start by setting up a Perl module
116search path and 'use'ing a few support modules (see module 116search path and 'use'ing a few support modules (see module
117descriptions below): 117descriptions below):
118 118
119---- 119----
120 use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib"; 120 use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/perf-script-Util/lib";
121 use lib "./Perf-Trace-Util/lib"; 121 use lib "./perf-script-Util/lib";
122 use Perf::Trace::Core; 122 use Perf::Trace::Core;
123 use Perf::Trace::Context; 123 use Perf::Trace::Context;
124 use Perf::Trace::Util; 124 use Perf::Trace::Util;
@@ -162,7 +162,7 @@ sub trace_unhandled
162---- 162----
163 163
164The remaining sections provide descriptions of each of the available 164The remaining sections provide descriptions of each of the available
165built-in perf trace Perl modules and their associated functions. 165built-in perf script Perl modules and their associated functions.
166 166
167AVAILABLE MODULES AND FUNCTIONS 167AVAILABLE MODULES AND FUNCTIONS
168------------------------------- 168-------------------------------
@@ -170,7 +170,7 @@ AVAILABLE MODULES AND FUNCTIONS
170The following sections describe the functions and variables available 170The following sections describe the functions and variables available
171via the various Perf::Trace::* Perl modules. To use the functions and 171via the various Perf::Trace::* Perl modules. To use the functions and
172variables from the given module, add the corresponding 'use 172variables from the given module, add the corresponding 'use
173Perf::Trace::XXX' line to your perf trace script. 173Perf::Trace::XXX' line to your perf script script.
174 174
175Perf::Trace::Core Module 175Perf::Trace::Core Module
176~~~~~~~~~~~~~~~~~~~~~~~~ 176~~~~~~~~~~~~~~~~~~~~~~~~
@@ -204,7 +204,7 @@ argument.
204Perf::Trace::Util Module 204Perf::Trace::Util Module
205~~~~~~~~~~~~~~~~~~~~~~~~ 205~~~~~~~~~~~~~~~~~~~~~~~~
206 206
207Various utility functions for use with perf trace: 207Various utility functions for use with perf script:
208 208
209 nsecs($secs, $nsecs) - returns total nsecs given secs/nsecs pair 209 nsecs($secs, $nsecs) - returns total nsecs given secs/nsecs pair
210 nsecs_secs($nsecs) - returns whole secs portion given nsecs 210 nsecs_secs($nsecs) - returns whole secs portion given nsecs
@@ -214,4 +214,4 @@ Various utility functions for use with perf trace:
214 214
215SEE ALSO 215SEE ALSO
216-------- 216--------
217linkperf:perf-trace[1] 217linkperf:perf-script[1]
diff --git a/tools/perf/Documentation/perf-trace-python.txt b/tools/perf/Documentation/perf-script-python.txt
index 693be804dd3d..36b38277422c 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
@@ -510,7 +510,7 @@ write a useful trace script. The sections below cover the rest.
510SCRIPT LAYOUT 510SCRIPT LAYOUT
511------------- 511-------------
512 512
513Every perf trace Python script should start by setting up a Python 513Every perf script Python script should start by setting up a Python
514module search path and 'import'ing a few support modules (see module 514module search path and 'import'ing a few support modules (see module
515descriptions below): 515descriptions below):
516 516
@@ -519,7 +519,7 @@ descriptions below):
519 import sys 519 import sys
520 520
521 sys.path.append(os.environ['PERF_EXEC_PATH'] + \ 521 sys.path.append(os.environ['PERF_EXEC_PATH'] + \
522 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') 522 '/scripts/python/perf-script-Util/lib/Perf/Trace')
523 523
524 from perf_trace_context import * 524 from perf_trace_context import *
525 from Core import * 525 from Core import *
@@ -559,15 +559,15 @@ def trace_unhandled(event_name, context, common_cpu, common_secs,
559---- 559----
560 560
561The remaining sections provide descriptions of each of the available 561The remaining sections provide descriptions of each of the available
562built-in perf trace Python modules and their associated functions. 562built-in perf script Python modules and their associated functions.
563 563
564AVAILABLE MODULES AND FUNCTIONS 564AVAILABLE MODULES AND FUNCTIONS
565------------------------------- 565-------------------------------
566 566
567The following sections describe the functions and variables available 567The following sections describe the functions and variables available
568via the various perf trace Python modules. To use the functions and 568via the various perf script Python modules. To use the functions and
569variables from the given module, add the corresponding 'from XXXX 569variables from the given module, add the corresponding 'from XXXX
570import' line to your perf trace script. 570import' line to your perf script script.
571 571
572Core.py Module 572Core.py Module
573~~~~~~~~~~~~~~ 573~~~~~~~~~~~~~~
@@ -610,7 +610,7 @@ argument.
610Util.py Module 610Util.py Module
611~~~~~~~~~~~~~~ 611~~~~~~~~~~~~~~
612 612
613Various utility functions for use with perf trace: 613Various utility functions for use with perf script:
614 614
615 nsecs(secs, nsecs) - returns total nsecs given secs/nsecs pair 615 nsecs(secs, nsecs) - returns total nsecs given secs/nsecs pair
616 nsecs_secs(nsecs) - returns whole secs portion given nsecs 616 nsecs_secs(nsecs) - returns whole secs portion given nsecs
@@ -620,4 +620,4 @@ Various utility functions for use with perf trace:
620 620
621SEE ALSO 621SEE ALSO
622-------- 622--------
623linkperf:perf-trace[1] 623linkperf:perf-script[1]
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-script.txt
index 26aff6bf9e50..66f040b30729 100644
--- a/tools/perf/Documentation/perf-trace.txt
+++ b/tools/perf/Documentation/perf-script.txt
@@ -1,71 +1,71 @@
1perf-trace(1) 1perf-script(1)
2============= 2=============
3 3
4NAME 4NAME
5---- 5----
6perf-trace - Read perf.data (created by perf record) and display trace output 6perf-script - Read perf.data (created by perf record) and display trace output
7 7
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf trace' [<options>] 11'perf script' [<options>]
12'perf trace' [<options>] record <script> [<record-options>] <command> 12'perf script' [<options>] record <script> [<record-options>] <command>
13'perf trace' [<options>] report <script> [script-args] 13'perf script' [<options>] report <script> [script-args]
14'perf trace' [<options>] <script> <required-script-args> [<record-options>] <command> 14'perf script' [<options>] <script> <required-script-args> [<record-options>] <command>
15'perf trace' [<options>] <top-script> [script-args] 15'perf script' [<options>] <top-script> [script-args]
16 16
17DESCRIPTION 17DESCRIPTION
18----------- 18-----------
19This command reads the input file and displays the trace recorded. 19This command reads the input file and displays the trace recorded.
20 20
21There are several variants of perf trace: 21There are several variants of perf script:
22 22
23 'perf trace' to see a detailed trace of the workload that was 23 'perf script' to see a detailed trace of the workload that was
24 recorded. 24 recorded.
25 25
26 You can also run a set of pre-canned scripts that aggregate and 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 27 summarize the raw trace data in various ways (the list of scripts is
28 available via 'perf trace -l'). The following variants allow you to 28 available via 'perf script -l'). The following variants allow you to
29 record and run those scripts: 29 record and run those scripts:
30 30
31 'perf trace record <script> <command>' to record the events required 31 'perf script record <script> <command>' to record the events required
32 for 'perf trace report'. <script> is the name displayed in the 32 for 'perf script report'. <script> is the name displayed in the
33 output of 'perf trace --list' i.e. the actual script name minus any 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 34 language extension. If <command> is not specified, the events are
35 recorded using the -a (system-wide) 'perf record' option. 35 recorded using the -a (system-wide) 'perf record' option.
36 36
37 'perf trace report <script> [args]' to run and display the results 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 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 39 trace --list' i.e. the actual script name minus any language
40 extension. The perf.data output from a previous run of 'perf trace 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 41 record <script>' is used and should be present for this command to
42 succeed. [args] refers to the (mainly optional) args expected by 42 succeed. [args] refers to the (mainly optional) args expected by
43 the script. 43 the script.
44 44
45 'perf trace <script> <required-script-args> <command>' to both 45 'perf script <script> <required-script-args> <command>' to both
46 record the events required for <script> and to run the <script> 46 record the events required for <script> and to run the <script>
47 using 'live-mode' i.e. without writing anything to disk. <script> 47 using 'live-mode' i.e. without writing anything to disk. <script>
48 is the name displayed in the output of 'perf trace --list' i.e. the 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 49 actual script name minus any language extension. If <command> is
50 not specified, the events are recorded using the -a (system-wide) 50 not specified, the events are recorded using the -a (system-wide)
51 'perf record' option. If <script> has any required args, they 51 'perf record' option. If <script> has any required args, they
52 should be specified before <command>. This mode doesn't allow for 52 should be specified before <command>. This mode doesn't allow for
53 optional script args to be specified; if optional script args are 53 optional script args to be specified; if optional script args are
54 desired, they can be specified using separate 'perf trace record' 54 desired, they can be specified using separate 'perf script record'
55 and 'perf trace report' commands, with the stdout of the record step 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 -' 56 piped to the stdin of the report script, using the '-o -' and '-i -'
57 options of the corresponding commands. 57 options of the corresponding commands.
58 58
59 'perf trace <top-script>' to both record the events required for 59 'perf script <top-script>' to both record the events required for
60 <top-script> and to run the <top-script> using 'live-mode' 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 61 i.e. without writing anything to disk. <top-script> is the name
62 displayed in the output of 'perf trace --list' i.e. the actual 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 63 script name minus any language extension; a <top-script> is defined
64 as any script name ending with the string 'top'. 64 as any script name ending with the string 'top'.
65 65
66 [<record-options>] can be passed to the record steps of 'perf trace 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 67 record' and 'live-mode' variants; this isn't possible however for
68 <top-script> 'live-mode' or 'perf trace report' variants. 68 <top-script> 'live-mode' or 'perf script report' variants.
69 69
70 See the 'SEE ALSO' section for links to language-specific 70 See the 'SEE ALSO' section for links to language-specific
71 information on how to write and run your own trace scripts. 71 information on how to write and run your own trace scripts.
@@ -76,7 +76,7 @@ OPTIONS
76 Any command you can specify in a shell. 76 Any command you can specify in a shell.
77 77
78-D:: 78-D::
79--dump-raw-trace=:: 79--dump-raw-script=::
80 Display verbose dump of the trace data. 80 Display verbose dump of the trace data.
81 81
82-L:: 82-L::
@@ -95,7 +95,7 @@ OPTIONS
95 95
96-g:: 96-g::
97--gen-script=:: 97--gen-script=::
98 Generate perf-trace.[ext] starter script for given language, 98 Generate perf-script.[ext] starter script for given language,
99 using current perf.data. 99 using current perf.data.
100 100
101-a:: 101-a::
@@ -104,8 +104,37 @@ OPTIONS
104 normally don't - this option allows the latter to be run in 104 normally don't - this option allows the latter to be run in
105 system-wide mode. 105 system-wide mode.
106 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 must 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-k::
124--vmlinux=<file>::
125 vmlinux pathname
126
127--kallsyms=<file>::
128 kallsyms pathname
129
130--symfs=<directory>::
131 Look for files with symbols relative to this directory.
132
133-G::
134--hide-call-graph::
135 When printing symbols do not display call chain.
107 136
108SEE ALSO 137SEE ALSO
109-------- 138--------
110linkperf:perf-record[1], linkperf:perf-trace-perl[1], 139linkperf:perf-record[1], linkperf:perf-script-perl[1],
111linkperf:perf-trace-python[1] 140linkperf: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/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 d1db0f676a4b..0c542563ea6c 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -3,7 +3,7 @@ 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 7
8ifneq ($(OUTPUT),) 8ifneq ($(OUTPUT),)
9# check that the output directory actually exists 9# check that the output directory actually exists
@@ -11,152 +11,12 @@ OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd)
11$(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist)) 11$(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist))
12endif 12endif
13 13
14# Define V=1 to have a more verbose compile. 14# 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#
89# Define NEEDS_SSL_WITH_CRYPTO if you need -lcrypto with -lssl (Darwin).
90#
91# Define NEEDS_LIBICONV if linking with libc is not enough (Darwin).
92#
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# 15#
143# Define ASCIIDOC8 if you want to format documentation with AsciiDoc 8 16# Define ASCIIDOC8 if you want to format documentation with AsciiDoc 8
144# 17#
145# Define DOCBOOK_XSL_172 if you want to format man pages with DocBook XSL v1.72. 18# Define DOCBOOK_XSL_172 if you want to format man pages with DocBook XSL v1.72.
146# 19#
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. 20# Define LDFLAGS=-static to build a static binary.
161# 21#
162# Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds. 22# Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds.
@@ -167,12 +27,7 @@ $(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
167 @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT) 27 @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT)
168-include $(OUTPUT)PERF-VERSION-FILE 28-include $(OUTPUT)PERF-VERSION-FILE
169 29
170uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') 30uname_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 31
177ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \ 32ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
178 -e s/arm.*/arm/ -e s/sa110/arm/ \ 33 -e s/arm.*/arm/ -e s/sa110/arm/ \
@@ -180,16 +35,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/ \ 35 -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
181 -e s/sh[234].*/sh/ ) 36 -e s/sh[234].*/sh/ )
182 37
38CC = $(CROSS_COMPILE)gcc
39AR = $(CROSS_COMPILE)ar
40
183# Additional ARCH settings for x86 41# Additional ARCH settings for x86
184ifeq ($(ARCH),i386) 42ifeq ($(ARCH),i386)
185 ARCH := x86 43 ARCH := x86
186endif 44endif
187ifeq ($(ARCH),x86_64) 45ifeq ($(ARCH),x86_64)
188 ARCH := x86 46 ARCH := x86
47 IS_X86_64 := $(shell echo __x86_64__ | ${CC} -E -xc - | tail -n 1)
48 ifeq (${IS_X86_64}, 1)
49 RAW_ARCH := x86_64
50 ARCH_CFLAGS := -DARCH_X86_64
51 ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S
52 endif
189endif 53endif
190 54
191# CFLAGS and LDFLAGS are for the users to override from the command line.
192
193# 55#
194# Include saner warnings here, which can catch bugs: 56# Include saner warnings here, which can catch bugs:
195# 57#
@@ -201,13 +63,11 @@ EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wshadow
201EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Winit-self 63EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Winit-self
202EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wpacked 64EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wpacked
203EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wredundant-decls 65EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wredundant-decls
204EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstack-protector
205EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-aliasing=3 66EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-aliasing=3
206EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wswitch-default 67EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wswitch-default
207EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wswitch-enum 68EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wswitch-enum
208EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wno-system-headers 69EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wno-system-headers
209EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wundef 70EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wundef
210EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wvolatile-register-var
211EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wwrite-strings 71EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wwrite-strings
212EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wbad-function-cast 72EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wbad-function-cast
213EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wmissing-declarations 73EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wmissing-declarations
@@ -224,7 +84,7 @@ ifndef PERF_DEBUG
224 CFLAGS_OPTIMIZE = -O6 84 CFLAGS_OPTIMIZE = -O6
225endif 85endif
226 86
227CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) 87CFLAGS = -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 88EXTLIBS = -lpthread -lrt -lelf -lm
229ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 89ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
230ALL_LDFLAGS = $(LDFLAGS) 90ALL_LDFLAGS = $(LDFLAGS)
@@ -265,32 +125,28 @@ lib = lib
265 125
266export prefix bindir sharedir sysconfdir 126export prefix bindir sharedir sysconfdir
267 127
268CC = $(CROSS_COMPILE)gcc
269AR = $(CROSS_COMPILE)ar
270RM = rm -f 128RM = rm -f
271MKDIR = mkdir 129MKDIR = mkdir
272TAR = tar
273FIND = find 130FIND = find
274INSTALL = install 131INSTALL = install
275RPMBUILD = rpmbuild
276PTHREAD_LIBS = -lpthread
277 132
278# sparse is architecture-neutral, which means that we need to tell it 133# sparse is architecture-neutral, which means that we need to tell it
279# explicitly what architecture to check for. Fix this up for yours.. 134# explicitly what architecture to check for. Fix this up for yours..
280SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__ 135SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
281 136
282ifeq ($(V), 2)
283 QUIET_STDERR = ">/dev/null"
284else
285 QUIET_STDERR = ">/dev/null 2>&1"
286endif
287
288-include feature-tests.mak 137-include feature-tests.mak
289 138
290ifeq ($(call try-cc,$(SOURCE_HELLO),-Werror -fstack-protector-all),y) 139ifeq ($(call try-cc,$(SOURCE_HELLO),-Werror -fstack-protector-all),y)
291 CFLAGS := $(CFLAGS) -fstack-protector-all 140 CFLAGS := $(CFLAGS) -fstack-protector-all
292endif 141endif
293 142
143ifeq ($(call try-cc,$(SOURCE_HELLO),-Werror -Wstack-protector),y)
144 CFLAGS := $(CFLAGS) -Wstack-protector
145endif
146
147ifeq ($(call try-cc,$(SOURCE_HELLO),-Werror -Wvolatile-register-var),y)
148 CFLAGS := $(CFLAGS) -Wvolatile-register-var
149endif
294 150
295### --- END CONFIGURATION SECTION --- 151### --- END CONFIGURATION SECTION ---
296 152
@@ -302,49 +158,41 @@ BASIC_LDFLAGS =
302 158
303# Guard against environment variables 159# Guard against environment variables
304BUILTIN_OBJS = 160BUILTIN_OBJS =
305BUILT_INS =
306COMPAT_CFLAGS =
307COMPAT_OBJS =
308LIB_H = 161LIB_H =
309LIB_OBJS = 162LIB_OBJS =
310SCRIPT_PERL = 163PYRF_OBJS =
311SCRIPT_SH = 164SCRIPT_SH =
312TEST_PROGRAMS =
313 165
314SCRIPT_SH += perf-archive.sh 166SCRIPT_SH += perf-archive.sh
315 167
316grep-libs = $(filter -l%,$(1)) 168grep-libs = $(filter -l%,$(1))
317strip-libs = $(filter-out -l%,$(1)) 169strip-libs = $(filter-out -l%,$(1))
318 170
171$(OUTPUT)python/perf.so: $(PYRF_OBJS)
172 $(QUIET_GEN)( \
173 export CFLAGS="$(BASIC_CFLAGS)"; \
174 python util/setup.py --quiet build_ext --build-lib='$(OUTPUT)python' \
175 --build-temp='$(OUTPUT)python/temp' \
176 )
177
319# 178#
320# No Perl scripts right now: 179# No Perl scripts right now:
321# 180#
322 181
323# SCRIPT_PERL += perf-add--interactive.perl 182SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH))
324
325SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \
326 $(patsubst %.perl,%,$(SCRIPT_PERL))
327
328# Empty...
329EXTRA_PROGRAMS =
330
331# ... and all the rest that could be moved out of bindir to perfexecdir
332PROGRAMS += $(EXTRA_PROGRAMS)
333 183
334# 184#
335# Single 'perf' binary right now: 185# Single 'perf' binary right now:
336# 186#
337PROGRAMS += $(OUTPUT)perf 187PROGRAMS += $(OUTPUT)perf
338 188
339# List built-in command $C whose implementation cmd_$C() is not in 189LANG_BINDINGS =
340# builtin-$C.o but is linked in as part of some other command.
341#
342 190
343# what 'all' will build and 'install' will install, in perfexecdir 191# what 'all' will build and 'install' will install, in perfexecdir
344ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS) 192ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
345 193
346# what 'all' will build but not install in perfexecdir 194# what 'all' will build but not install in perfexecdir
347OTHER_PROGRAMS = $(OUTPUT)perf$X 195OTHER_PROGRAMS = $(OUTPUT)perf
348 196
349# Set paths to tools early so that they can be used for version tests. 197# Set paths to tools early so that they can be used for version tests.
350ifndef SHELL_PATH 198ifndef SHELL_PATH
@@ -375,6 +223,7 @@ LIB_H += util/include/linux/prefetch.h
375LIB_H += util/include/linux/rbtree.h 223LIB_H += util/include/linux/rbtree.h
376LIB_H += util/include/linux/string.h 224LIB_H += util/include/linux/string.h
377LIB_H += util/include/linux/types.h 225LIB_H += util/include/linux/types.h
226LIB_H += util/include/linux/linkage.h
378LIB_H += util/include/asm/asm-offsets.h 227LIB_H += util/include/asm/asm-offsets.h
379LIB_H += util/include/asm/bug.h 228LIB_H += util/include/asm/bug.h
380LIB_H += util/include/asm/byteorder.h 229LIB_H += util/include/asm/byteorder.h
@@ -383,13 +232,18 @@ LIB_H += util/include/asm/swab.h
383LIB_H += util/include/asm/system.h 232LIB_H += util/include/asm/system.h
384LIB_H += util/include/asm/uaccess.h 233LIB_H += util/include/asm/uaccess.h
385LIB_H += util/include/dwarf-regs.h 234LIB_H += util/include/dwarf-regs.h
235LIB_H += util/include/asm/dwarf2.h
236LIB_H += util/include/asm/cpufeature.h
386LIB_H += perf.h 237LIB_H += perf.h
238LIB_H += util/annotate.h
387LIB_H += util/cache.h 239LIB_H += util/cache.h
388LIB_H += util/callchain.h 240LIB_H += util/callchain.h
389LIB_H += util/build-id.h 241LIB_H += util/build-id.h
390LIB_H += util/debug.h 242LIB_H += util/debug.h
391LIB_H += util/debugfs.h 243LIB_H += util/debugfs.h
392LIB_H += util/event.h 244LIB_H += util/event.h
245LIB_H += util/evsel.h
246LIB_H += util/evlist.h
393LIB_H += util/exec_cmd.h 247LIB_H += util/exec_cmd.h
394LIB_H += util/types.h 248LIB_H += util/types.h
395LIB_H += util/levenshtein.h 249LIB_H += util/levenshtein.h
@@ -398,11 +252,13 @@ LIB_H += util/parse-options.h
398LIB_H += util/parse-events.h 252LIB_H += util/parse-events.h
399LIB_H += util/quote.h 253LIB_H += util/quote.h
400LIB_H += util/util.h 254LIB_H += util/util.h
255LIB_H += util/xyarray.h
401LIB_H += util/header.h 256LIB_H += util/header.h
402LIB_H += util/help.h 257LIB_H += util/help.h
403LIB_H += util/session.h 258LIB_H += util/session.h
404LIB_H += util/strbuf.h 259LIB_H += util/strbuf.h
405LIB_H += util/strlist.h 260LIB_H += util/strlist.h
261LIB_H += util/strfilter.h
406LIB_H += util/svghelper.h 262LIB_H += util/svghelper.h
407LIB_H += util/run-command.h 263LIB_H += util/run-command.h
408LIB_H += util/sigchain.h 264LIB_H += util/sigchain.h
@@ -412,20 +268,27 @@ LIB_H += util/values.h
412LIB_H += util/sort.h 268LIB_H += util/sort.h
413LIB_H += util/hist.h 269LIB_H += util/hist.h
414LIB_H += util/thread.h 270LIB_H += util/thread.h
271LIB_H += util/thread_map.h
415LIB_H += util/trace-event.h 272LIB_H += util/trace-event.h
416LIB_H += util/probe-finder.h 273LIB_H += util/probe-finder.h
417LIB_H += util/probe-event.h 274LIB_H += util/probe-event.h
418LIB_H += util/pstack.h 275LIB_H += util/pstack.h
419LIB_H += util/cpumap.h 276LIB_H += util/cpumap.h
277LIB_H += util/top.h
278LIB_H += $(ARCH_INCLUDE)
279LIB_H += util/cgroup.h
420 280
421LIB_OBJS += $(OUTPUT)util/abspath.o 281LIB_OBJS += $(OUTPUT)util/abspath.o
422LIB_OBJS += $(OUTPUT)util/alias.o 282LIB_OBJS += $(OUTPUT)util/alias.o
283LIB_OBJS += $(OUTPUT)util/annotate.o
423LIB_OBJS += $(OUTPUT)util/build-id.o 284LIB_OBJS += $(OUTPUT)util/build-id.o
424LIB_OBJS += $(OUTPUT)util/config.o 285LIB_OBJS += $(OUTPUT)util/config.o
425LIB_OBJS += $(OUTPUT)util/ctype.o 286LIB_OBJS += $(OUTPUT)util/ctype.o
426LIB_OBJS += $(OUTPUT)util/debugfs.o 287LIB_OBJS += $(OUTPUT)util/debugfs.o
427LIB_OBJS += $(OUTPUT)util/environment.o 288LIB_OBJS += $(OUTPUT)util/environment.o
428LIB_OBJS += $(OUTPUT)util/event.o 289LIB_OBJS += $(OUTPUT)util/event.o
290LIB_OBJS += $(OUTPUT)util/evlist.o
291LIB_OBJS += $(OUTPUT)util/evsel.o
429LIB_OBJS += $(OUTPUT)util/exec_cmd.o 292LIB_OBJS += $(OUTPUT)util/exec_cmd.o
430LIB_OBJS += $(OUTPUT)util/help.o 293LIB_OBJS += $(OUTPUT)util/help.o
431LIB_OBJS += $(OUTPUT)util/levenshtein.o 294LIB_OBJS += $(OUTPUT)util/levenshtein.o
@@ -440,6 +303,8 @@ LIB_OBJS += $(OUTPUT)util/quote.o
440LIB_OBJS += $(OUTPUT)util/strbuf.o 303LIB_OBJS += $(OUTPUT)util/strbuf.o
441LIB_OBJS += $(OUTPUT)util/string.o 304LIB_OBJS += $(OUTPUT)util/string.o
442LIB_OBJS += $(OUTPUT)util/strlist.o 305LIB_OBJS += $(OUTPUT)util/strlist.o
306LIB_OBJS += $(OUTPUT)util/strfilter.o
307LIB_OBJS += $(OUTPUT)util/top.o
443LIB_OBJS += $(OUTPUT)util/usage.o 308LIB_OBJS += $(OUTPUT)util/usage.o
444LIB_OBJS += $(OUTPUT)util/wrapper.o 309LIB_OBJS += $(OUTPUT)util/wrapper.o
445LIB_OBJS += $(OUTPUT)util/sigchain.o 310LIB_OBJS += $(OUTPUT)util/sigchain.o
@@ -454,6 +319,7 @@ LIB_OBJS += $(OUTPUT)util/map.o
454LIB_OBJS += $(OUTPUT)util/pstack.o 319LIB_OBJS += $(OUTPUT)util/pstack.o
455LIB_OBJS += $(OUTPUT)util/session.o 320LIB_OBJS += $(OUTPUT)util/session.o
456LIB_OBJS += $(OUTPUT)util/thread.o 321LIB_OBJS += $(OUTPUT)util/thread.o
322LIB_OBJS += $(OUTPUT)util/thread_map.o
457LIB_OBJS += $(OUTPUT)util/trace-event-parse.o 323LIB_OBJS += $(OUTPUT)util/trace-event-parse.o
458LIB_OBJS += $(OUTPUT)util/trace-event-read.o 324LIB_OBJS += $(OUTPUT)util/trace-event-read.o
459LIB_OBJS += $(OUTPUT)util/trace-event-info.o 325LIB_OBJS += $(OUTPUT)util/trace-event-info.o
@@ -463,7 +329,9 @@ LIB_OBJS += $(OUTPUT)util/sort.o
463LIB_OBJS += $(OUTPUT)util/hist.o 329LIB_OBJS += $(OUTPUT)util/hist.o
464LIB_OBJS += $(OUTPUT)util/probe-event.o 330LIB_OBJS += $(OUTPUT)util/probe-event.o
465LIB_OBJS += $(OUTPUT)util/util.o 331LIB_OBJS += $(OUTPUT)util/util.o
332LIB_OBJS += $(OUTPUT)util/xyarray.o
466LIB_OBJS += $(OUTPUT)util/cpumap.o 333LIB_OBJS += $(OUTPUT)util/cpumap.o
334LIB_OBJS += $(OUTPUT)util/cgroup.o
467 335
468BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o 336BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
469 337
@@ -472,9 +340,13 @@ BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
472# Benchmark modules 340# Benchmark modules
473BUILTIN_OBJS += $(OUTPUT)bench/sched-messaging.o 341BUILTIN_OBJS += $(OUTPUT)bench/sched-messaging.o
474BUILTIN_OBJS += $(OUTPUT)bench/sched-pipe.o 342BUILTIN_OBJS += $(OUTPUT)bench/sched-pipe.o
343ifeq ($(RAW_ARCH),x86_64)
344BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy-x86-64-asm.o
345endif
475BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o 346BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o
476 347
477BUILTIN_OBJS += $(OUTPUT)builtin-diff.o 348BUILTIN_OBJS += $(OUTPUT)builtin-diff.o
349BUILTIN_OBJS += $(OUTPUT)builtin-evlist.o
478BUILTIN_OBJS += $(OUTPUT)builtin-help.o 350BUILTIN_OBJS += $(OUTPUT)builtin-help.o
479BUILTIN_OBJS += $(OUTPUT)builtin-sched.o 351BUILTIN_OBJS += $(OUTPUT)builtin-sched.o
480BUILTIN_OBJS += $(OUTPUT)builtin-buildid-list.o 352BUILTIN_OBJS += $(OUTPUT)builtin-buildid-list.o
@@ -485,7 +357,7 @@ BUILTIN_OBJS += $(OUTPUT)builtin-report.o
485BUILTIN_OBJS += $(OUTPUT)builtin-stat.o 357BUILTIN_OBJS += $(OUTPUT)builtin-stat.o
486BUILTIN_OBJS += $(OUTPUT)builtin-timechart.o 358BUILTIN_OBJS += $(OUTPUT)builtin-timechart.o
487BUILTIN_OBJS += $(OUTPUT)builtin-top.o 359BUILTIN_OBJS += $(OUTPUT)builtin-top.o
488BUILTIN_OBJS += $(OUTPUT)builtin-trace.o 360BUILTIN_OBJS += $(OUTPUT)builtin-script.o
489BUILTIN_OBJS += $(OUTPUT)builtin-probe.o 361BUILTIN_OBJS += $(OUTPUT)builtin-probe.o
490BUILTIN_OBJS += $(OUTPUT)builtin-kmem.o 362BUILTIN_OBJS += $(OUTPUT)builtin-kmem.o
491BUILTIN_OBJS += $(OUTPUT)builtin-lock.o 363BUILTIN_OBJS += $(OUTPUT)builtin-lock.o
@@ -495,6 +367,20 @@ BUILTIN_OBJS += $(OUTPUT)builtin-inject.o
495 367
496PERFLIBS = $(LIB_FILE) 368PERFLIBS = $(LIB_FILE)
497 369
370# Files needed for the python binding, perf.so
371# pyrf is just an internal name needed for all those wrappers.
372# This has to be in sync with what is in the 'sources' variable in
373# tools/perf/util/setup.py
374
375PYRF_OBJS += $(OUTPUT)util/cpumap.o
376PYRF_OBJS += $(OUTPUT)util/ctype.o
377PYRF_OBJS += $(OUTPUT)util/evlist.o
378PYRF_OBJS += $(OUTPUT)util/evsel.o
379PYRF_OBJS += $(OUTPUT)util/python.o
380PYRF_OBJS += $(OUTPUT)util/thread_map.o
381PYRF_OBJS += $(OUTPUT)util/util.o
382PYRF_OBJS += $(OUTPUT)util/xyarray.o
383
498# 384#
499# Platform specific tweaks 385# Platform specific tweaks
500# 386#
@@ -507,7 +393,7 @@ PERFLIBS = $(LIB_FILE)
507-include config.mak 393-include config.mak
508 394
509ifndef NO_DWARF 395ifndef NO_DWARF
510FLAGS_DWARF=$(ALL_CFLAGS) -I/usr/include/elfutils -ldw -lelf $(ALL_LDFLAGS) $(EXTLIBS) 396FLAGS_DWARF=$(ALL_CFLAGS) -ldw -lelf $(ALL_LDFLAGS) $(EXTLIBS)
511ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF)),y) 397ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF)),y)
512 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); 398 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);
513 NO_DWARF := 1 399 NO_DWARF := 1
@@ -516,22 +402,6 @@ endif # NO_DWARF
516 402
517-include arch/$(ARCH)/Makefile 403-include arch/$(ARCH)/Makefile
518 404
519ifeq ($(uname_S),Darwin)
520 ifndef NO_FINK
521 ifeq ($(shell test -d /sw/lib && echo y),y)
522 BASIC_CFLAGS += -I/sw/include
523 BASIC_LDFLAGS += -L/sw/lib
524 endif
525 endif
526 ifndef NO_DARWIN_PORTS
527 ifeq ($(shell test -d /opt/local/lib && echo y),y)
528 BASIC_CFLAGS += -I/opt/local/include
529 BASIC_LDFLAGS += -L/opt/local/lib
530 endif
531 endif
532 PTHREAD_LIBS =
533endif
534
535ifneq ($(OUTPUT),) 405ifneq ($(OUTPUT),)
536 BASIC_CFLAGS += -I$(OUTPUT) 406 BASIC_CFLAGS += -I$(OUTPUT)
537endif 407endif
@@ -554,7 +424,7 @@ ifndef NO_DWARF
554ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined) 424ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined)
555 msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled); 425 msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled);
556else 426else
557 BASIC_CFLAGS += -I/usr/include/elfutils -DDWARF_SUPPORT 427 BASIC_CFLAGS += -DDWARF_SUPPORT
558 EXTLIBS += -lelf -ldw 428 EXTLIBS += -lelf -ldw
559 LIB_OBJS += $(OUTPUT)util/probe-finder.o 429 LIB_OBJS += $(OUTPUT)util/probe-finder.o
560endif # PERF_HAVE_DWARF_REGS 430endif # PERF_HAVE_DWARF_REGS
@@ -576,6 +446,7 @@ else
576 LIB_OBJS += $(OUTPUT)util/ui/browsers/annotate.o 446 LIB_OBJS += $(OUTPUT)util/ui/browsers/annotate.o
577 LIB_OBJS += $(OUTPUT)util/ui/browsers/hists.o 447 LIB_OBJS += $(OUTPUT)util/ui/browsers/hists.o
578 LIB_OBJS += $(OUTPUT)util/ui/browsers/map.o 448 LIB_OBJS += $(OUTPUT)util/ui/browsers/map.o
449 LIB_OBJS += $(OUTPUT)util/ui/browsers/top.o
579 LIB_OBJS += $(OUTPUT)util/ui/helpline.o 450 LIB_OBJS += $(OUTPUT)util/ui/helpline.o
580 LIB_OBJS += $(OUTPUT)util/ui/progress.o 451 LIB_OBJS += $(OUTPUT)util/ui/progress.o
581 LIB_OBJS += $(OUTPUT)util/ui/util.o 452 LIB_OBJS += $(OUTPUT)util/ui/util.o
@@ -585,6 +456,7 @@ else
585 LIB_H += util/ui/libslang.h 456 LIB_H += util/ui/libslang.h
586 LIB_H += util/ui/progress.h 457 LIB_H += util/ui/progress.h
587 LIB_H += util/ui/util.h 458 LIB_H += util/ui/util.h
459 LIB_H += util/ui/ui.h
588 endif 460 endif
589endif 461endif
590 462
@@ -616,12 +488,14 @@ else
616 PYTHON_EMBED_CCOPTS = `python-config --cflags 2>/dev/null` 488 PYTHON_EMBED_CCOPTS = `python-config --cflags 2>/dev/null`
617 FLAGS_PYTHON_EMBED=$(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS) 489 FLAGS_PYTHON_EMBED=$(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
618 ifneq ($(call try-cc,$(SOURCE_PYTHON_EMBED),$(FLAGS_PYTHON_EMBED)),y) 490 ifneq ($(call try-cc,$(SOURCE_PYTHON_EMBED),$(FLAGS_PYTHON_EMBED)),y)
491 msg := $(warning No Python.h found, install python-dev[el] to have python support in 'perf script' and to build the python bindings)
619 BASIC_CFLAGS += -DNO_LIBPYTHON 492 BASIC_CFLAGS += -DNO_LIBPYTHON
620 else 493 else
621 ALL_LDFLAGS += $(PYTHON_EMBED_LDFLAGS) 494 ALL_LDFLAGS += $(PYTHON_EMBED_LDFLAGS)
622 EXTLIBS += $(PYTHON_EMBED_LIBADD) 495 EXTLIBS += $(PYTHON_EMBED_LIBADD)
623 LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-python.o 496 LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-python.o
624 LIB_OBJS += $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o 497 LIB_OBJS += $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o
498 LANG_BINDINGS += $(OUTPUT)python/perf.so
625 endif 499 endif
626endif 500endif
627 501
@@ -671,201 +545,13 @@ else
671 endif 545 endif
672endif 546endif
673 547
674ifndef CC_LD_DYNPATH
675 ifdef NO_R_TO_GCC_LINKER
676 # Some gcc does not accept and pass -R to the linker to specify
677 # the runtime dynamic library path.
678 CC_LD_DYNPATH = -Wl,-rpath,
679 else
680 CC_LD_DYNPATH = -R
681 endif
682endif
683
684ifdef NEEDS_SOCKET
685 EXTLIBS += -lsocket
686endif
687ifdef NEEDS_NSL
688 EXTLIBS += -lnsl
689endif
690ifdef NO_D_TYPE_IN_DIRENT
691 BASIC_CFLAGS += -DNO_D_TYPE_IN_DIRENT
692endif
693ifdef NO_D_INO_IN_DIRENT
694 BASIC_CFLAGS += -DNO_D_INO_IN_DIRENT
695endif
696ifdef NO_ST_BLOCKS_IN_STRUCT_STAT
697 BASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT
698endif
699ifdef USE_NSEC
700 BASIC_CFLAGS += -DUSE_NSEC
701endif
702ifdef USE_ST_TIMESPEC
703 BASIC_CFLAGS += -DUSE_ST_TIMESPEC
704endif
705ifdef NO_NSEC
706 BASIC_CFLAGS += -DNO_NSEC
707endif
708ifdef NO_C99_FORMAT
709 BASIC_CFLAGS += -DNO_C99_FORMAT
710endif
711ifdef SNPRINTF_RETURNS_BOGUS
712 COMPAT_CFLAGS += -DSNPRINTF_RETURNS_BOGUS
713 COMPAT_OBJS += $(OUTPUT)compat/snprintf.o
714endif
715ifdef FREAD_READS_DIRECTORIES
716 COMPAT_CFLAGS += -DFREAD_READS_DIRECTORIES
717 COMPAT_OBJS += $(OUTPUT)compat/fopen.o
718endif
719ifdef NO_SYMLINK_HEAD
720 BASIC_CFLAGS += -DNO_SYMLINK_HEAD
721endif
722ifdef NO_STRCASESTR
723 COMPAT_CFLAGS += -DNO_STRCASESTR
724 COMPAT_OBJS += $(OUTPUT)compat/strcasestr.o
725endif
726ifdef NO_STRTOUMAX
727 COMPAT_CFLAGS += -DNO_STRTOUMAX
728 COMPAT_OBJS += $(OUTPUT)compat/strtoumax.o
729endif
730ifdef NO_STRTOULL
731 COMPAT_CFLAGS += -DNO_STRTOULL
732endif
733ifdef NO_SETENV
734 COMPAT_CFLAGS += -DNO_SETENV
735 COMPAT_OBJS += $(OUTPUT)compat/setenv.o
736endif
737ifdef NO_MKDTEMP
738 COMPAT_CFLAGS += -DNO_MKDTEMP
739 COMPAT_OBJS += $(OUTPUT)compat/mkdtemp.o
740endif
741ifdef NO_UNSETENV
742 COMPAT_CFLAGS += -DNO_UNSETENV
743 COMPAT_OBJS += $(OUTPUT)compat/unsetenv.o
744endif
745ifdef NO_SYS_SELECT_H
746 BASIC_CFLAGS += -DNO_SYS_SELECT_H
747endif
748ifdef NO_MMAP
749 COMPAT_CFLAGS += -DNO_MMAP
750 COMPAT_OBJS += $(OUTPUT)compat/mmap.o
751else
752 ifdef USE_WIN32_MMAP
753 COMPAT_CFLAGS += -DUSE_WIN32_MMAP
754 COMPAT_OBJS += $(OUTPUT)compat/win32mmap.o
755 endif
756endif
757ifdef NO_PREAD
758 COMPAT_CFLAGS += -DNO_PREAD
759 COMPAT_OBJS += $(OUTPUT)compat/pread.o
760endif
761ifdef NO_FAST_WORKING_DIRECTORY
762 BASIC_CFLAGS += -DNO_FAST_WORKING_DIRECTORY
763endif
764ifdef NO_TRUSTABLE_FILEMODE
765 BASIC_CFLAGS += -DNO_TRUSTABLE_FILEMODE
766endif
767ifdef NO_IPV6
768 BASIC_CFLAGS += -DNO_IPV6
769endif
770ifdef NO_UINTMAX_T
771 BASIC_CFLAGS += -Duintmax_t=uint32_t
772endif
773ifdef NO_SOCKADDR_STORAGE
774ifdef NO_IPV6
775 BASIC_CFLAGS += -Dsockaddr_storage=sockaddr_in
776else
777 BASIC_CFLAGS += -Dsockaddr_storage=sockaddr_in6
778endif
779endif
780ifdef NO_INET_NTOP
781 LIB_OBJS += $(OUTPUT)compat/inet_ntop.o
782endif
783ifdef NO_INET_PTON
784 LIB_OBJS += $(OUTPUT)compat/inet_pton.o
785endif
786
787ifdef NO_ICONV
788 BASIC_CFLAGS += -DNO_ICONV
789endif
790
791ifdef OLD_ICONV
792 BASIC_CFLAGS += -DOLD_ICONV
793endif
794
795ifdef NO_DEFLATE_BOUND
796 BASIC_CFLAGS += -DNO_DEFLATE_BOUND
797endif
798
799ifdef PPC_SHA1
800 SHA1_HEADER = "ppc/sha1.h"
801 LIB_OBJS += $(OUTPUT)ppc/sha1.o ppc/sha1ppc.o
802else
803ifdef ARM_SHA1
804 SHA1_HEADER = "arm/sha1.h"
805 LIB_OBJS += $(OUTPUT)arm/sha1.o $(OUTPUT)arm/sha1_arm.o
806else
807ifdef MOZILLA_SHA1
808 SHA1_HEADER = "mozilla-sha1/sha1.h"
809 LIB_OBJS += $(OUTPUT)mozilla-sha1/sha1.o
810else
811 SHA1_HEADER = <openssl/sha.h>
812 EXTLIBS += $(LIB_4_CRYPTO)
813endif
814endif
815endif
816ifdef NO_PERL_MAKEMAKER
817 export NO_PERL_MAKEMAKER
818endif
819ifdef NO_HSTRERROR
820 COMPAT_CFLAGS += -DNO_HSTRERROR
821 COMPAT_OBJS += $(OUTPUT)compat/hstrerror.o
822endif
823ifdef NO_MEMMEM
824 COMPAT_CFLAGS += -DNO_MEMMEM
825 COMPAT_OBJS += $(OUTPUT)compat/memmem.o
826endif
827ifdef INTERNAL_QSORT
828 COMPAT_CFLAGS += -DINTERNAL_QSORT
829 COMPAT_OBJS += $(OUTPUT)compat/qsort.o
830endif
831ifdef RUNTIME_PREFIX
832 COMPAT_CFLAGS += -DRUNTIME_PREFIX
833endif
834
835ifdef DIR_HAS_BSD_GROUP_SEMANTICS
836 COMPAT_CFLAGS += -DDIR_HAS_BSD_GROUP_SEMANTICS
837endif
838ifdef NO_EXTERNAL_GREP
839 BASIC_CFLAGS += -DNO_EXTERNAL_GREP
840endif
841
842ifeq ($(PERL_PATH),)
843NO_PERL=NoThanks
844endif
845
846QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir
847QUIET_SUBDIR1 =
848
849ifneq ($(findstring $(MAKEFLAGS),w),w)
850PRINT_DIR = --no-print-directory
851else # "make -w"
852NO_SUBDIR = :
853endif
854
855ifneq ($(findstring $(MAKEFLAGS),s),s) 548ifneq ($(findstring $(MAKEFLAGS),s),s)
856ifndef V 549ifndef V
857 QUIET_CC = @echo ' ' CC $@; 550 QUIET_CC = @echo ' ' CC $@;
858 QUIET_AR = @echo ' ' AR $@; 551 QUIET_AR = @echo ' ' AR $@;
859 QUIET_LINK = @echo ' ' LINK $@; 552 QUIET_LINK = @echo ' ' LINK $@;
860 QUIET_MKDIR = @echo ' ' MKDIR $@; 553 QUIET_MKDIR = @echo ' ' MKDIR $@;
861 QUIET_BUILT_IN = @echo ' ' BUILTIN $@;
862 QUIET_GEN = @echo ' ' GEN $@; 554 QUIET_GEN = @echo ' ' GEN $@;
863 QUIET_SUBDIR0 = +@subdir=
864 QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \
865 $(MAKE) $(PRINT_DIR) -C $$subdir
866 export V
867 export QUIET_GEN
868 export QUIET_BUILT_IN
869endif 555endif
870endif 556endif
871 557
@@ -875,7 +561,6 @@ endif
875 561
876# Shell quote (do not use $(call) to accommodate ancient setups); 562# Shell quote (do not use $(call) to accommodate ancient setups);
877 563
878SHA1_HEADER_SQ = $(subst ','\'',$(SHA1_HEADER))
879ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG)) 564ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG))
880 565
881DESTDIR_SQ = $(subst ','\'',$(DESTDIR)) 566DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
@@ -889,45 +574,36 @@ htmldir_SQ = $(subst ','\'',$(htmldir))
889prefix_SQ = $(subst ','\'',$(prefix)) 574prefix_SQ = $(subst ','\'',$(prefix))
890 575
891SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) 576SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
892PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH))
893
894LIBS = $(PERFLIBS) $(EXTLIBS)
895 577
896BASIC_CFLAGS += -DSHA1_HEADER='$(SHA1_HEADER_SQ)' \ 578LIBS = -Wl,--whole-archive $(PERFLIBS) -Wl,--no-whole-archive $(EXTLIBS)
897 $(COMPAT_CFLAGS)
898LIB_OBJS += $(COMPAT_OBJS)
899 579
900ALL_CFLAGS += $(BASIC_CFLAGS) 580ALL_CFLAGS += $(BASIC_CFLAGS)
581ALL_CFLAGS += $(ARCH_CFLAGS)
901ALL_LDFLAGS += $(BASIC_LDFLAGS) 582ALL_LDFLAGS += $(BASIC_LDFLAGS)
902 583
903export TAR INSTALL DESTDIR SHELL_PATH 584export INSTALL SHELL_PATH
904 585
905 586
906### Build rules 587### Build rules
907 588
908SHELL = $(SHELL_PATH) 589SHELL = $(SHELL_PATH)
909 590
910all:: shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) $(OUTPUT)PERF-BUILD-OPTIONS 591all: shell_compatibility_test $(ALL_PROGRAMS) $(LANG_BINDINGS) $(OTHER_PROGRAMS)
911ifneq (,$X)
912 $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) perf$X)), test '$p' -ef '$p$X' || $(RM) '$p';)
913endif
914
915all::
916 592
917please_set_SHELL_PATH_to_a_more_modern_shell: 593please_set_SHELL_PATH_to_a_more_modern_shell:
918 @$$(:) 594 @$$(:)
919 595
920shell_compatibility_test: please_set_SHELL_PATH_to_a_more_modern_shell 596shell_compatibility_test: please_set_SHELL_PATH_to_a_more_modern_shell
921 597
922strip: $(PROGRAMS) $(OUTPUT)perf$X 598strip: $(PROGRAMS) $(OUTPUT)perf
923 $(STRIP) $(STRIP_OPTS) $(PROGRAMS) $(OUTPUT)perf$X 599 $(STRIP) $(STRIP_OPTS) $(PROGRAMS) $(OUTPUT)perf
924 600
925$(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS 601$(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
926 $(QUIET_CC)$(CC) -DPERF_VERSION='"$(PERF_VERSION)"' \ 602 $(QUIET_CC)$(CC) -DPERF_VERSION='"$(PERF_VERSION)"' \
927 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ 603 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
928 $(ALL_CFLAGS) -c $(filter %.c,$^) -o $@ 604 $(ALL_CFLAGS) -c $(filter %.c,$^) -o $@
929 605
930$(OUTPUT)perf$X: $(OUTPUT)perf.o $(BUILTIN_OBJS) $(PERFLIBS) 606$(OUTPUT)perf: $(OUTPUT)perf.o $(BUILTIN_OBJS) $(PERFLIBS)
931 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) $(OUTPUT)perf.o \ 607 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) $(OUTPUT)perf.o \
932 $(BUILTIN_OBJS) $(LIBS) -o $@ 608 $(BUILTIN_OBJS) $(LIBS) -o $@
933 609
@@ -943,39 +619,17 @@ $(OUTPUT)builtin-timechart.o: builtin-timechart.c $(OUTPUT)common-cmds.h $(OUTPU
943 '-DPERF_MAN_PATH="$(mandir_SQ)"' \ 619 '-DPERF_MAN_PATH="$(mandir_SQ)"' \
944 '-DPERF_INFO_PATH="$(infodir_SQ)"' $< 620 '-DPERF_INFO_PATH="$(infodir_SQ)"' $<
945 621
946$(BUILT_INS): $(OUTPUT)perf$X
947 $(QUIET_BUILT_IN)$(RM) $@ && \
948 ln perf$X $@ 2>/dev/null || \
949 ln -s perf$X $@ 2>/dev/null || \
950 cp perf$X $@
951
952$(OUTPUT)common-cmds.h: util/generate-cmdlist.sh command-list.txt 622$(OUTPUT)common-cmds.h: util/generate-cmdlist.sh command-list.txt
953 623
954$(OUTPUT)common-cmds.h: $(wildcard Documentation/perf-*.txt) 624$(OUTPUT)common-cmds.h: $(wildcard Documentation/perf-*.txt)
955 $(QUIET_GEN). util/generate-cmdlist.sh > $@+ && mv $@+ $@ 625 $(QUIET_GEN). util/generate-cmdlist.sh > $@+ && mv $@+ $@
956 626
957$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh 627$(SCRIPTS) : % : %.sh
958 $(QUIET_GEN)$(RM) $(OUTPUT)$@ $(OUTPUT)$@+ && \ 628 $(QUIET_GEN)$(INSTALL) '$@.sh' '$(OUTPUT)$@'
959 sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
960 -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \
961 -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \
962 -e 's/@@PERF_VERSION@@/$(PERF_VERSION)/g' \
963 -e 's/@@NO_CURL@@/$(NO_CURL)/g' \
964 $@.sh > $(OUTPUT)$@+ && \
965 chmod +x $(OUTPUT)$@+ && \
966 mv $(OUTPUT)$@+ $(OUTPUT)$@
967
968configure: configure.ac
969 $(QUIET_GEN)$(RM) $@ $<+ && \
970 sed -e 's/@@PERF_VERSION@@/$(PERF_VERSION)/g' \
971 $< > $<+ && \
972 autoconf -o $@ $<+ && \
973 $(RM) $<+
974 629
975# These can record PERF_VERSION 630# These can record PERF_VERSION
976$(OUTPUT)perf.o perf.spec \ 631$(OUTPUT)perf.o perf.spec \
977 $(patsubst %.sh,%,$(SCRIPT_SH)) \ 632 $(SCRIPTS) \
978 $(patsubst %.perl,%,$(SCRIPT_PERL)) \
979 : $(OUTPUT)PERF-VERSION-FILE 633 : $(OUTPUT)PERF-VERSION-FILE
980 634
981$(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS 635$(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS
@@ -992,9 +646,6 @@ $(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS
992 '-DPREFIX="$(prefix_SQ)"' \ 646 '-DPREFIX="$(prefix_SQ)"' \
993 $< 647 $<
994 648
995$(OUTPUT)builtin-init-db.o: builtin-init-db.c $(OUTPUT)PERF-CFLAGS
996 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DDEFAULT_PERF_TEMPLATE_DIR='"$(template_dir_SQ)"' $<
997
998$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS 649$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS
999 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< 650 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
1000 651
@@ -1004,6 +655,9 @@ $(OUTPUT)util/ui/browser.o: util/ui/browser.c $(OUTPUT)PERF-CFLAGS
1004$(OUTPUT)util/ui/browsers/annotate.o: util/ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS 655$(OUTPUT)util/ui/browsers/annotate.o: util/ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS
1005 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 656 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
1006 657
658$(OUTPUT)util/ui/browsers/top.o: util/ui/browsers/top.c $(OUTPUT)PERF-CFLAGS
659 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
660
1007$(OUTPUT)util/ui/browsers/hists.o: util/ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS 661$(OUTPUT)util/ui/browsers/hists.o: util/ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS
1008 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 662 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
1009 663
@@ -1025,12 +679,11 @@ $(OUTPUT)util/scripting-engines/trace-event-python.o: util/scripting-engines/tra
1025$(OUTPUT)scripts/python/Perf-Trace-Util/Context.o: scripts/python/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS 679$(OUTPUT)scripts/python/Perf-Trace-Util/Context.o: scripts/python/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS
1026 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $< 680 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $<
1027 681
1028$(OUTPUT)perf-%$X: %.o $(PERFLIBS) 682$(OUTPUT)perf-%: %.o $(PERFLIBS)
1029 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) 683 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
1030 684
1031$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H) 685$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
1032$(patsubst perf-%$X,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h) 686$(patsubst perf-%,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
1033builtin-revert.o wt-status.o: wt-status.h
1034 687
1035# we compile into subdirectories. if the target directory is not the source directory, they might not exists. So 688# we compile into subdirectories. if the target directory is not the source directory, they might not exists. So
1036# we depend the various files onto their directories. 689# we depend the various files onto their directories.
@@ -1043,6 +696,36 @@ $(sort $(dir $(DIRECTORY_DEPS))):
1043$(LIB_FILE): $(LIB_OBJS) 696$(LIB_FILE): $(LIB_OBJS)
1044 $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS) 697 $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS)
1045 698
699help:
700 @echo 'Perf make targets:'
701 @echo ' doc - make *all* documentation (see below)'
702 @echo ' man - make manpage documentation (access with man <foo>)'
703 @echo ' html - make html documentation'
704 @echo ' info - make GNU info documentation (access with info <foo>)'
705 @echo ' pdf - make pdf documentation'
706 @echo ' TAGS - use etags to make tag information for source browsing'
707 @echo ' tags - use ctags to make tag information for source browsing'
708 @echo ' cscope - use cscope to make interactive browsing database'
709 @echo ''
710 @echo 'Perf install targets:'
711 @echo ' NOTE: documentation build requires asciidoc, xmlto packages to be installed'
712 @echo ' HINT: use "make prefix=<path> <install target>" to install to a particular'
713 @echo ' path like make prefix=/usr/local install install-doc'
714 @echo ' install - install compiled binaries'
715 @echo ' install-doc - install *all* documentation'
716 @echo ' install-man - install manpage documentation'
717 @echo ' install-html - install html documentation'
718 @echo ' install-info - install GNU info documentation'
719 @echo ' install-pdf - install pdf documentation'
720 @echo ''
721 @echo ' quick-install-doc - alias for quick-install-man'
722 @echo ' quick-install-man - install the documentation quickly'
723 @echo ' quick-install-html - install the html documentation quickly'
724 @echo ''
725 @echo 'Perf maintainer targets:'
726 @echo ' distclean - alias to clean'
727 @echo ' clean - clean all binary objects and build output'
728
1046doc: 729doc:
1047 $(MAKE) -C Documentation all 730 $(MAKE) -C Documentation all
1048 731
@@ -1081,30 +764,12 @@ $(OUTPUT)PERF-CFLAGS: .FORCE-PERF-CFLAGS
1081 echo "$$FLAGS" >$(OUTPUT)PERF-CFLAGS; \ 764 echo "$$FLAGS" >$(OUTPUT)PERF-CFLAGS; \
1082 fi 765 fi
1083 766
1084# We need to apply sq twice, once to protect from the shell
1085# that runs $(OUTPUT)PERF-BUILD-OPTIONS, and then again to protect it
1086# and the first level quoting from the shell that runs "echo".
1087$(OUTPUT)PERF-BUILD-OPTIONS: .FORCE-PERF-BUILD-OPTIONS
1088 @echo SHELL_PATH=\''$(subst ','\'',$(SHELL_PATH_SQ))'\' >$@
1089 @echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@
1090 @echo NO_CURL=\''$(subst ','\'',$(subst ','\'',$(NO_CURL)))'\' >>$@
1091 @echo NO_PERL=\''$(subst ','\'',$(subst ','\'',$(NO_PERL)))'\' >>$@
1092
1093### Testing rules 767### Testing rules
1094 768
1095#
1096# None right now:
1097#
1098# TEST_PROGRAMS += test-something$X
1099
1100all:: $(TEST_PROGRAMS)
1101
1102# GNU make supports exporting all variables by "export" without parameters. 769# GNU make supports exporting all variables by "export" without parameters.
1103# However, the environment gets quite big, and some programs have problems 770# However, the environment gets quite big, and some programs have problems
1104# with that. 771# with that.
1105 772
1106export NO_SVN_TESTS
1107
1108check: $(OUTPUT)common-cmds.h 773check: $(OUTPUT)common-cmds.h
1109 if sparse; \ 774 if sparse; \
1110 then \ 775 then \
@@ -1113,33 +778,21 @@ check: $(OUTPUT)common-cmds.h
1113 sparse $(ALL_CFLAGS) $(SPARSE_FLAGS) $$i || exit; \ 778 sparse $(ALL_CFLAGS) $(SPARSE_FLAGS) $$i || exit; \
1114 done; \ 779 done; \
1115 else \ 780 else \
1116 echo 2>&1 "Did you mean 'make test'?"; \
1117 exit 1; \ 781 exit 1; \
1118 fi 782 fi
1119 783
1120remove-dashes:
1121 ./fixup-builtins $(BUILT_INS) $(PROGRAMS) $(SCRIPTS)
1122
1123### Installation rules 784### Installation rules
1124 785
1125ifneq ($(filter /%,$(firstword $(template_dir))),)
1126template_instdir = $(template_dir)
1127else
1128template_instdir = $(prefix)/$(template_dir)
1129endif
1130export template_instdir
1131
1132ifneq ($(filter /%,$(firstword $(perfexecdir))),) 786ifneq ($(filter /%,$(firstword $(perfexecdir))),)
1133perfexec_instdir = $(perfexecdir) 787perfexec_instdir = $(perfexecdir)
1134else 788else
1135perfexec_instdir = $(prefix)/$(perfexecdir) 789perfexec_instdir = $(prefix)/$(perfexecdir)
1136endif 790endif
1137perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir)) 791perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir))
1138export perfexec_instdir
1139 792
1140install: all 793install: all
1141 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' 794 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
1142 $(INSTALL) $(OUTPUT)perf$X '$(DESTDIR_SQ)$(bindir_SQ)' 795 $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)'
1143 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace' 796 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
1144 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin' 797 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
1145 $(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' 798 $(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
@@ -1152,14 +805,6 @@ install: all
1152 $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python' 805 $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python'
1153 $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin' 806 $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
1154 807
1155ifdef BUILT_INS
1156 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
1157 $(INSTALL) $(BUILT_INS) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
1158ifneq (,$X)
1159 $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) $(OUTPUT)perf$X)), $(RM) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/$p';)
1160endif
1161endif
1162
1163install-doc: 808install-doc:
1164 $(MAKE) -C Documentation install 809 $(MAKE) -C Documentation install
1165 810
@@ -1184,104 +829,17 @@ quick-install-man:
1184quick-install-html: 829quick-install-html:
1185 $(MAKE) -C Documentation quick-install-html 830 $(MAKE) -C Documentation quick-install-html
1186 831
1187
1188### Maintainer's dist rules
1189#
1190# None right now
1191#
1192#
1193# perf.spec: perf.spec.in
1194# sed -e 's/@@VERSION@@/$(PERF_VERSION)/g' < $< > $@+
1195# mv $@+ $@
1196#
1197# PERF_TARNAME=perf-$(PERF_VERSION)
1198# dist: perf.spec perf-archive$(X) configure
1199# ./perf-archive --format=tar \
1200# --prefix=$(PERF_TARNAME)/ HEAD^{tree} > $(PERF_TARNAME).tar
1201# @mkdir -p $(PERF_TARNAME)
1202# @cp perf.spec configure $(PERF_TARNAME)
1203# @echo $(PERF_VERSION) > $(PERF_TARNAME)/version
1204# $(TAR) rf $(PERF_TARNAME).tar \
1205# $(PERF_TARNAME)/perf.spec \
1206# $(PERF_TARNAME)/configure \
1207# $(PERF_TARNAME)/version
1208# @$(RM) -r $(PERF_TARNAME)
1209# gzip -f -9 $(PERF_TARNAME).tar
1210#
1211# htmldocs = perf-htmldocs-$(PERF_VERSION)
1212# manpages = perf-manpages-$(PERF_VERSION)
1213# dist-doc:
1214# $(RM) -r .doc-tmp-dir
1215# mkdir .doc-tmp-dir
1216# $(MAKE) -C Documentation WEBDOC_DEST=../.doc-tmp-dir install-webdoc
1217# cd .doc-tmp-dir && $(TAR) cf ../$(htmldocs).tar .
1218# gzip -n -9 -f $(htmldocs).tar
1219# :
1220# $(RM) -r .doc-tmp-dir
1221# mkdir -p .doc-tmp-dir/man1 .doc-tmp-dir/man5 .doc-tmp-dir/man7
1222# $(MAKE) -C Documentation DESTDIR=./ \
1223# man1dir=../.doc-tmp-dir/man1 \
1224# man5dir=../.doc-tmp-dir/man5 \
1225# man7dir=../.doc-tmp-dir/man7 \
1226# install
1227# cd .doc-tmp-dir && $(TAR) cf ../$(manpages).tar .
1228# gzip -n -9 -f $(manpages).tar
1229# $(RM) -r .doc-tmp-dir
1230#
1231# rpm: dist
1232# $(RPMBUILD) -ta $(PERF_TARNAME).tar.gz
1233
1234### Cleaning rules 832### Cleaning rules
1235 833
1236distclean: clean
1237# $(RM) configure
1238
1239clean: 834clean:
1240 $(RM) *.o */*.o */*/*.o */*/*/*.o $(LIB_FILE) 835 $(RM) $(OUTPUT){*.o,*/*.o,*/*/*.o,*/*/*/*.o,$(LIB_FILE),perf-archive}
1241 $(RM) $(ALL_PROGRAMS) $(BUILT_INS) perf$X 836 $(RM) $(ALL_PROGRAMS) perf
1242 $(RM) $(TEST_PROGRAMS)
1243 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* 837 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope*
1244 $(RM) -r autom4te.cache
1245 $(RM) config.log config.mak.autogen config.mak.append config.status config.cache
1246 $(RM) -r $(PERF_TARNAME) .doc-tmp-dir
1247 $(RM) $(PERF_TARNAME).tar.gz perf-core_$(PERF_VERSION)-*.tar.gz
1248 $(RM) $(htmldocs).tar.gz $(manpages).tar.gz
1249 $(MAKE) -C Documentation/ clean 838 $(MAKE) -C Documentation/ clean
1250 $(RM) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS $(OUTPUT)PERF-BUILD-OPTIONS 839 $(RM) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS
840 @python util/setup.py clean --build-lib='$(OUTPUT)python' \
841 --build-temp='$(OUTPUT)python/temp'
1251 842
1252.PHONY: all install clean strip 843.PHONY: all install clean strip
1253.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell 844.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
1254.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS 845.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS
1255.PHONY: .FORCE-PERF-BUILD-OPTIONS
1256
1257### Make sure built-ins do not have dups and listed in perf.c
1258#
1259check-builtins::
1260 ./check-builtins.sh
1261
1262### Test suite coverage testing
1263#
1264# None right now
1265#
1266# .PHONY: coverage coverage-clean coverage-build coverage-report
1267#
1268# coverage:
1269# $(MAKE) coverage-build
1270# $(MAKE) coverage-report
1271#
1272# coverage-clean:
1273# rm -f *.gcda *.gcno
1274#
1275# COVERAGE_CFLAGS = $(CFLAGS) -O0 -ftest-coverage -fprofile-arcs
1276# COVERAGE_LDFLAGS = $(CFLAGS) -O0 -lgcov
1277#
1278# coverage-build: coverage-clean
1279# $(MAKE) CFLAGS="$(COVERAGE_CFLAGS)" LDFLAGS="$(COVERAGE_LDFLAGS)" all
1280# $(MAKE) CFLAGS="$(COVERAGE_CFLAGS)" LDFLAGS="$(COVERAGE_LDFLAGS)" \
1281# -j1 test
1282#
1283# coverage-report:
1284# gcov -b *.c */*.c
1285# grep '^function.*called 0 ' *.c.gcov */*.c.gcov \
1286# | sed -e 's/\([^:]*\)\.gcov: *function \([^ ]*\) called.*/\1: \2/' \
1287# | 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 6d5604d8df95..e18eb7ed30ae 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -9,6 +9,7 @@
9 9
10#include "util/util.h" 10#include "util/util.h"
11 11
12#include "util/util.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"
@@ -18,6 +19,9 @@
18#include "perf.h" 19#include "perf.h"
19#include "util/debug.h" 20#include "util/debug.h"
20 21
22#include "util/evlist.h"
23#include "util/evsel.h"
24#include "util/annotate.h"
21#include "util/event.h" 25#include "util/event.h"
22#include "util/parse-options.h" 26#include "util/parse-options.h"
23#include "util/parse-events.h" 27#include "util/parse-events.h"
@@ -36,9 +40,13 @@ static bool print_line;
36 40
37static const char *sym_hist_filter; 41static const char *sym_hist_filter;
38 42
39static int hists__add_entry(struct hists *self, struct addr_location *al) 43static int perf_evlist__add_sample(struct perf_evlist *evlist,
44 struct perf_sample *sample,
45 struct perf_evsel *evsel,
46 struct addr_location *al)
40{ 47{
41 struct hist_entry *he; 48 struct hist_entry *he;
49 int ret;
42 50
43 if (sym_hist_filter != NULL && 51 if (sym_hist_filter != NULL &&
44 (al->sym == NULL || strcmp(sym_hist_filter, al->sym->name) != 0)) { 52 (al->sym == NULL || strcmp(sym_hist_filter, al->sym->name) != 0)) {
@@ -51,25 +59,41 @@ static int hists__add_entry(struct hists *self, struct addr_location *al)
51 return 0; 59 return 0;
52 } 60 }
53 61
54 he = __hists__add_entry(self, al, NULL, 1); 62 he = __hists__add_entry(&evsel->hists, al, NULL, 1);
55 if (he == NULL) 63 if (he == NULL)
56 return -ENOMEM; 64 return -ENOMEM;
57 65
58 return hist_entry__inc_addr_samples(he, al->addr); 66 ret = 0;
67 if (he->ms.sym != NULL) {
68 struct annotation *notes = symbol__annotation(he->ms.sym);
69 if (notes->src == NULL &&
70 symbol__alloc_hist(he->ms.sym, evlist->nr_entries) < 0)
71 return -ENOMEM;
72
73 ret = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
74 }
75
76 evsel->hists.stats.total_period += sample->period;
77 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
78 return ret;
59} 79}
60 80
61static int process_sample_event(event_t *event, struct perf_session *session) 81static int process_sample_event(union perf_event *event,
82 struct perf_sample *sample,
83 struct perf_evsel *evsel,
84 struct perf_session *session)
62{ 85{
63 struct addr_location al; 86 struct addr_location al;
64 struct sample_data data;
65 87
66 if (event__preprocess_sample(event, session, &al, &data, NULL) < 0) { 88 if (perf_event__preprocess_sample(event, session, &al, sample,
89 symbol__annotate_init) < 0) {
67 pr_warning("problem processing %d event, skipping it.\n", 90 pr_warning("problem processing %d event, skipping it.\n",
68 event->header.type); 91 event->header.type);
69 return -1; 92 return -1;
70 } 93 }
71 94
72 if (!al.filtered && hists__add_entry(&session->hists, &al)) { 95 if (!al.filtered &&
96 perf_evlist__add_sample(session->evlist, sample, evsel, &al)) {
73 pr_warning("problem incrementing symbol count, " 97 pr_warning("problem incrementing symbol count, "
74 "skipping event\n"); 98 "skipping event\n");
75 return -1; 99 return -1;
@@ -78,261 +102,26 @@ static int process_sample_event(event_t *event, struct perf_session *session)
78 return 0; 102 return 0;
79} 103}
80 104
81static int objdump_line__print(struct objdump_line *self, 105static 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{
148 struct sym_ext *iter;
149 struct rb_node **p = &root_sym_ext.rb_node;
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}
165
166static void free_source_line(struct hist_entry *he, int len)
167{
168 struct sym_priv *priv = symbol__priv(he->ms.sym);
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{ 106{
280 struct map *map = he->ms.map; 107 return symbol__tty_annotate(he->ms.sym, he->ms.map, evidx,
281 struct dso *dso = map->dso; 108 print_line, full_paths, 0, 0);
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} 109}
321 110
322static void hists__find_annotations(struct hists *self) 111static void hists__find_annotations(struct hists *self, int evidx)
323{ 112{
324 struct rb_node *nd = rb_first(&self->entries), *next; 113 struct rb_node *nd = rb_first(&self->entries), *next;
325 int key = KEY_RIGHT; 114 int key = KEY_RIGHT;
326 115
327 while (nd) { 116 while (nd) {
328 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); 117 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
329 struct sym_priv *priv; 118 struct annotation *notes;
330 119
331 if (he->ms.sym == NULL || he->ms.map->dso->annotate_warned) 120 if (he->ms.sym == NULL || he->ms.map->dso->annotate_warned)
332 goto find_next; 121 goto find_next;
333 122
334 priv = symbol__priv(he->ms.sym); 123 notes = symbol__annotation(he->ms.sym);
335 if (priv->hist == NULL) { 124 if (notes->src == NULL) {
336find_next: 125find_next:
337 if (key == KEY_LEFT) 126 if (key == KEY_LEFT)
338 nd = rb_prev(nd); 127 nd = rb_prev(nd);
@@ -342,7 +131,7 @@ find_next:
342 } 131 }
343 132
344 if (use_browser > 0) { 133 if (use_browser > 0) {
345 key = hist_entry__tui_annotate(he); 134 key = hist_entry__tui_annotate(he, evidx);
346 switch (key) { 135 switch (key) {
347 case KEY_RIGHT: 136 case KEY_RIGHT:
348 next = rb_next(nd); 137 next = rb_next(nd);
@@ -357,32 +146,36 @@ find_next:
357 if (next != NULL) 146 if (next != NULL)
358 nd = next; 147 nd = next;
359 } else { 148 } else {
360 hist_entry__tty_annotate(he); 149 hist_entry__tty_annotate(he, evidx);
361 nd = rb_next(nd); 150 nd = rb_next(nd);
362 /* 151 /*
363 * Since we have a hist_entry per IP for the same 152 * Since we have a hist_entry per IP for the same
364 * symbol, free he->ms.sym->hist to signal we already 153 * symbol, free he->ms.sym->src to signal we already
365 * processed this symbol. 154 * processed this symbol.
366 */ 155 */
367 free(priv->hist); 156 free(notes->src);
368 priv->hist = NULL; 157 notes->src = NULL;
369 } 158 }
370 } 159 }
371} 160}
372 161
373static struct perf_event_ops event_ops = { 162static struct perf_event_ops event_ops = {
374 .sample = process_sample_event, 163 .sample = process_sample_event,
375 .mmap = event__process_mmap, 164 .mmap = perf_event__process_mmap,
376 .comm = event__process_comm, 165 .comm = perf_event__process_comm,
377 .fork = event__process_task, 166 .fork = perf_event__process_task,
167 .ordered_samples = true,
168 .ordering_requires_timestamps = true,
378}; 169};
379 170
380static int __cmd_annotate(void) 171static int __cmd_annotate(void)
381{ 172{
382 int ret; 173 int ret;
383 struct perf_session *session; 174 struct perf_session *session;
175 struct perf_evsel *pos;
176 u64 total_nr_samples;
384 177
385 session = perf_session__new(input_name, O_RDONLY, force, false); 178 session = perf_session__new(input_name, O_RDONLY, force, false, &event_ops);
386 if (session == NULL) 179 if (session == NULL)
387 return -ENOMEM; 180 return -ENOMEM;
388 181
@@ -401,12 +194,36 @@ static int __cmd_annotate(void)
401 if (verbose > 2) 194 if (verbose > 2)
402 perf_session__fprintf_dsos(session, stdout); 195 perf_session__fprintf_dsos(session, stdout);
403 196
404 hists__collapse_resort(&session->hists); 197 total_nr_samples = 0;
405 hists__output_resort(&session->hists); 198 list_for_each_entry(pos, &session->evlist->entries, node) {
406 hists__find_annotations(&session->hists); 199 struct hists *hists = &pos->hists;
407out_delete: 200 u32 nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
408 perf_session__delete(session);
409 201
202 if (nr_samples > 0) {
203 total_nr_samples += nr_samples;
204 hists__collapse_resort(hists);
205 hists__output_resort(hists);
206 hists__find_annotations(hists, pos->idx);
207 }
208 }
209
210 if (total_nr_samples == 0) {
211 ui__warning("The %s file has no samples!\n", input_name);
212 goto out_delete;
213 }
214out_delete:
215 /*
216 * Speed up the exit process, for large files this can
217 * take quite a while.
218 *
219 * XXX Enable this when using valgrind or if we ever
220 * librarize this command.
221 *
222 * Also experiment with obstacks to see how much speed
223 * up we'll get here.
224 *
225 * perf_session__delete(session);
226 */
410 return ret; 227 return ret;
411} 228}
412 229
@@ -449,9 +266,9 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used)
449 else if (use_tui) 266 else if (use_tui)
450 use_browser = 1; 267 use_browser = 1;
451 268
452 setup_browser(); 269 setup_browser(true);
453 270
454 symbol_conf.priv_size = sizeof(struct sym_priv); 271 symbol_conf.priv_size = sizeof(struct annotation);
455 symbol_conf.try_vmlinux_path = true; 272 symbol_conf.try_vmlinux_path = true;
456 273
457 if (symbol__init() < 0) 274 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 2e000c068cc5..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 */
@@ -52,6 +55,7 @@ static struct {
52 bool show_lines; 55 bool show_lines;
53 bool show_vars; 56 bool show_vars;
54 bool show_ext_vars; 57 bool show_ext_vars;
58 bool show_funcs;
55 bool mod_events; 59 bool mod_events;
56 int nevents; 60 int nevents;
57 struct perf_probe_event events[MAX_PROBES]; 61 struct perf_probe_event events[MAX_PROBES];
@@ -59,6 +63,7 @@ static struct {
59 struct line_range line_range; 63 struct line_range line_range;
60 const char *target_module; 64 const char *target_module;
61 int max_probe_points; 65 int max_probe_points;
66 struct strfilter *filter;
62} params; 67} params;
63 68
64/* Parse an event definition. Note that any error must die. */ 69/* Parse an event definition. Note that any error must die. */
@@ -157,6 +162,27 @@ static int opt_show_vars(const struct option *opt __used,
157} 162}
158#endif 163#endif
159 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
160static const char * const probe_usage[] = { 186static const char * const probe_usage[] = {
161 "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]", 187 "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]",
162 "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]", 188 "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]",
@@ -221,6 +247,13 @@ static const struct option options[] = {
221 OPT__DRY_RUN(&probe_event_dry_run), 247 OPT__DRY_RUN(&probe_event_dry_run),
222 OPT_INTEGER('\0', "max-probes", &params.max_probe_points, 248 OPT_INTEGER('\0', "max-probes", &params.max_probe_points,
223 "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),
224 OPT_END() 257 OPT_END()
225}; 258};
226 259
@@ -246,9 +279,14 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
246 params.max_probe_points = MAX_PROBES; 279 params.max_probe_points = MAX_PROBES;
247 280
248 if ((!params.nevents && !params.dellist && !params.list_events && 281 if ((!params.nevents && !params.dellist && !params.list_events &&
249 !params.show_lines)) 282 !params.show_lines && !params.show_funcs))
250 usage_with_options(probe_usage, options); 283 usage_with_options(probe_usage, options);
251 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
252 if (params.list_events) { 290 if (params.list_events) {
253 if (params.mod_events) { 291 if (params.mod_events) {
254 pr_err(" Error: Don't use --list with --add/--del.\n"); 292 pr_err(" Error: Don't use --list with --add/--del.\n");
@@ -262,12 +300,41 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
262 pr_err(" Error: Don't use --list with --vars.\n"); 300 pr_err(" Error: Don't use --list with --vars.\n");
263 usage_with_options(probe_usage, options); 301 usage_with_options(probe_usage, options);
264 } 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 }
265 ret = show_perf_probe_events(); 307 ret = show_perf_probe_events();
266 if (ret < 0) 308 if (ret < 0)
267 pr_err(" Error: Failed to show event list. (%d)\n", 309 pr_err(" Error: Failed to show event list. (%d)\n",
268 ret); 310 ret);
269 return ret; 311 return ret;
270 } 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 }
271 338
272#ifdef DWARF_SUPPORT 339#ifdef DWARF_SUPPORT
273 if (params.show_lines) { 340 if (params.show_lines) {
@@ -292,10 +359,16 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
292 " --add/--del.\n"); 359 " --add/--del.\n");
293 usage_with_options(probe_usage, options); 360 usage_with_options(probe_usage, options);
294 } 361 }
362 if (!params.filter)
363 params.filter = strfilter__new(DEFAULT_VAR_FILTER,
364 NULL);
365
295 ret = show_available_vars(params.events, params.nevents, 366 ret = show_available_vars(params.events, params.nevents,
296 params.max_probe_points, 367 params.max_probe_points,
297 params.target_module, 368 params.target_module,
369 params.filter,
298 params.show_ext_vars); 370 params.show_ext_vars);
371 strfilter__delete(params.filter);
299 if (ret < 0) 372 if (ret < 0)
300 pr_err(" Error: Failed to show vars. (%d)\n", ret); 373 pr_err(" Error: Failed to show vars. (%d)\n", ret);
301 return ret; 374 return ret;
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index e2c2de201eec..416538248a4b 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;
301 239
302 if (fd[nr_cpu][counter][thread_index] < 0) { 240 pair = list_entry(other->entries.next, struct perf_evsel, node);
241
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));
339 exit(-1);
340 }
347 341
348 if (!file_new) { 342 if (perf_evlist__mmap(evlist, mmap_pages, false) < 0)
349 if (memcmp(&h_attr->attr, attr, sizeof(*attr))) { 343 die("failed to mmap with %d (%s)\n", errno, strerror(errno));
350 fprintf(stderr, "incompatible append\n");
351 exit(-1);
352 }
353 }
354 344
355 if (read(fd[nr_cpu][counter][thread_index], &read_data, sizeof(read_data)) == -1) { 345 if (file_new)
356 perror("Unable to read perf file descriptor"); 346 session->evlist = evlist;
347 else {
348 if (!perf_evlist__equal(session->evlist, evlist)) {
349 fprintf(stderr, "incompatible append\n");
357 exit(-1); 350 exit(-1);
358 } 351 }
352 }
359 353
360 if (perf_header_attr__add_id(h_attr, read_data.id) < 0) { 354 perf_session__update_sample_type(session);
361 pr_warning("Not enough memory to add id\n");
362 exit(-1);
363 }
364
365 assert(fd[nr_cpu][counter][thread_index] >= 0);
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->cpus->nr; 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");
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,31 +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 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" 645 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
703 "Check /proc/kallsyms permission or run as root.\n"); 646 "Check /proc/kallsyms permission or run as root.\n");
704 647
705 err = event__synthesize_modules(process_synthesized_event, 648 err = perf_event__synthesize_modules(process_synthesized_event,
706 session, machine); 649 session, machine);
707 if (err < 0) 650 if (err < 0)
708 pr_err("Couldn't record kernel module information.\n" 651 pr_err("Couldn't record kernel module information.\n"
709 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" 652 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
710 "Check /proc/modules permission or run as root.\n"); 653 "Check /proc/modules permission or run as root.\n");
711 654
712 if (perf_guest) 655 if (perf_guest)
713 perf_session__process_machines(session, event__synthesize_guest_os); 656 perf_session__process_machines(session,
657 perf_event__synthesize_guest_os);
714 658
715 if (!system_wide) 659 if (!system_wide)
716 event__synthesize_thread(target_tid, process_synthesized_event, 660 perf_event__synthesize_thread_map(evsel_list->threads,
717 session); 661 process_synthesized_event,
662 session);
718 else 663 else
719 event__synthesize_threads(process_synthesized_event, session); 664 perf_event__synthesize_threads(process_synthesized_event,
665 session);
720 666
721 if (realtime_prio) { 667 if (realtime_prio) {
722 struct sched_param param; 668 struct sched_param param;
@@ -743,26 +689,26 @@ static int __cmd_record(int argc, const char **argv)
743 if (hits == samples) { 689 if (hits == samples) {
744 if (done) 690 if (done)
745 break; 691 break;
746 err = poll(event_array, nr_poll, -1); 692 err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
747 waking++; 693 waking++;
748 } 694 }
749 695
750 if (done) { 696 if (done) {
751 for (i = 0; i < nr_cpu; i++) { 697 for (i = 0; i < evsel_list->cpus->nr; i++) {
752 for (counter = 0; 698 struct perf_evsel *pos;
753 counter < nr_counters; 699
754 counter++) { 700 list_for_each_entry(pos, &evsel_list->entries, node) {
755 for (thread = 0; 701 for (thread = 0;
756 thread < thread_num; 702 thread < evsel_list->threads->nr;
757 thread++) 703 thread++)
758 ioctl(fd[i][counter][thread], 704 ioctl(FD(pos, i, thread),
759 PERF_EVENT_IOC_DISABLE); 705 PERF_EVENT_IOC_DISABLE);
760 } 706 }
761 } 707 }
762 } 708 }
763 } 709 }
764 710
765 if (quiet) 711 if (quiet || signr == SIGUSR1)
766 return 0; 712 return 0;
767 713
768 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);
@@ -771,7 +717,7 @@ static int __cmd_record(int argc, const char **argv)
771 * Approximate RIP event size: 24 bytes. 717 * Approximate RIP event size: 24 bytes.
772 */ 718 */
773 fprintf(stderr, 719 fprintf(stderr,
774 "[ perf record: Captured and wrote %.3f MB %s (~%lld samples) ]\n", 720 "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
775 (double)bytes_written / 1024.0 / 1024.0, 721 (double)bytes_written / 1024.0 / 1024.0,
776 output_name, 722 output_name,
777 bytes_written / 24); 723 bytes_written / 24);
@@ -792,10 +738,10 @@ static const char * const record_usage[] = {
792static bool force, append_file; 738static bool force, append_file;
793 739
794const struct option record_options[] = { 740const struct option record_options[] = {
795 OPT_CALLBACK('e', "event", NULL, "event", 741 OPT_CALLBACK('e', "event", &evsel_list, "event",
796 "event selector. use 'perf list' to list available events", 742 "event selector. use 'perf list' to list available events",
797 parse_events), 743 parse_events),
798 OPT_CALLBACK(0, "filter", NULL, "filter", 744 OPT_CALLBACK(0, "filter", &evsel_list, "filter",
799 "event filter", parse_filter), 745 "event filter", parse_filter),
800 OPT_INTEGER('p', "pid", &target_pid, 746 OPT_INTEGER('p', "pid", &target_pid,
801 "record events on existing process id"), 747 "record events on existing process id"),
@@ -803,6 +749,8 @@ const struct option record_options[] = {
803 "record events on existing thread id"), 749 "record events on existing thread id"),
804 OPT_INTEGER('r', "realtime", &realtime_prio, 750 OPT_INTEGER('r', "realtime", &realtime_prio,
805 "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"),
806 OPT_BOOLEAN('R', "raw-samples", &raw_samples, 754 OPT_BOOLEAN('R', "raw-samples", &raw_samples,
807 "collect raw sample records from all opened counters"), 755 "collect raw sample records from all opened counters"),
808 OPT_BOOLEAN('a', "all-cpus", &system_wide, 756 OPT_BOOLEAN('a', "all-cpus", &system_wide,
@@ -829,16 +777,27 @@ const struct option record_options[] = {
829 "per thread counts"), 777 "per thread counts"),
830 OPT_BOOLEAN('d', "data", &sample_address, 778 OPT_BOOLEAN('d', "data", &sample_address,
831 "Sample addresses"), 779 "Sample addresses"),
780 OPT_BOOLEAN('T', "timestamp", &sample_time, "Sample timestamps"),
832 OPT_BOOLEAN('n', "no-samples", &no_samples, 781 OPT_BOOLEAN('n', "no-samples", &no_samples,
833 "don't sample"), 782 "don't sample"),
834 OPT_BOOLEAN('N', "no-buildid-cache", &no_buildid, 783 OPT_BOOLEAN('N', "no-buildid-cache", &no_buildid_cache,
835 "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),
836 OPT_END() 790 OPT_END()
837}; 791};
838 792
839int cmd_record(int argc, const char **argv, const char *prefix __used) 793int cmd_record(int argc, const char **argv, const char *prefix __used)
840{ 794{
841 int i, j, err = -ENOMEM; 795 int err = -ENOMEM;
796 struct perf_evsel *pos;
797
798 evsel_list = perf_evlist__new(NULL, NULL);
799 if (evsel_list == NULL)
800 return -ENOMEM;
842 801
843 argc = parse_options(argc, argv, record_options, record_usage, 802 argc = parse_options(argc, argv, record_options, record_usage,
844 PARSE_OPT_STOP_AT_NON_OPTION); 803 PARSE_OPT_STOP_AT_NON_OPTION);
@@ -856,43 +815,39 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
856 write_mode = WRITE_FORCE; 815 write_mode = WRITE_FORCE;
857 } 816 }
858 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
859 symbol__init(); 824 symbol__init();
860 if (no_buildid) 825
826 if (no_buildid_cache || no_buildid)
861 disable_buildid_cache(); 827 disable_buildid_cache();
862 828
863 if (!nr_counters) { 829 if (evsel_list->nr_entries == 0 &&
864 nr_counters = 1; 830 perf_evlist__add_default(evsel_list) < 0) {
865 attrs[0].type = PERF_TYPE_HARDWARE; 831 pr_err("Not enough memory for event selector list\n");
866 attrs[0].config = PERF_COUNT_HW_CPU_CYCLES; 832 goto out_symbol_exit;
867 } 833 }
868 834
869 if (target_pid != -1) { 835 if (target_pid != -1)
870 target_tid = target_pid; 836 target_tid = target_pid;
871 thread_num = find_all_tid(target_pid, &all_tids);
872 if (thread_num <= 0) {
873 fprintf(stderr, "Can't find all threads of pid %d\n",
874 target_pid);
875 usage_with_options(record_usage, record_options);
876 }
877 } else {
878 all_tids=malloc(sizeof(pid_t));
879 if (!all_tids)
880 goto out_symbol_exit;
881 837
882 all_tids[0] = target_tid; 838 if (perf_evlist__create_maps(evsel_list, target_pid,
883 thread_num = 1; 839 target_tid, cpu_list) < 0)
884 } 840 usage_with_options(record_usage, record_options);
885 841
886 for (i = 0; i < MAX_NR_CPUS; i++) { 842 list_for_each_entry(pos, &evsel_list->entries, node) {
887 for (j = 0; j < MAX_COUNTERS; j++) { 843 if (perf_evsel__alloc_fd(pos, evsel_list->cpus->nr,
888 fd[i][j] = malloc(sizeof(int)*thread_num); 844 evsel_list->threads->nr) < 0)
889 if (!fd[i][j]) 845 goto out_free_fd;
890 goto out_free_fd; 846 if (perf_header__push_event(pos->attr.config, event_name(pos)))
891 } 847 goto out_free_fd;
892 } 848 }
893 event_array = malloc( 849
894 sizeof(struct pollfd)*MAX_NR_CPUS*MAX_COUNTERS*thread_num); 850 if (perf_evlist__alloc_pollfd(evsel_list) < 0)
895 if (!event_array)
896 goto out_free_fd; 851 goto out_free_fd;
897 852
898 if (user_interval != ULLONG_MAX) 853 if (user_interval != ULLONG_MAX)
@@ -910,20 +865,12 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
910 } else { 865 } else {
911 fprintf(stderr, "frequency and count are zero, aborting\n"); 866 fprintf(stderr, "frequency and count are zero, aborting\n");
912 err = -EINVAL; 867 err = -EINVAL;
913 goto out_free_event_array; 868 goto out_free_fd;
914 } 869 }
915 870
916 err = __cmd_record(argc, argv); 871 err = __cmd_record(argc, argv);
917
918out_free_event_array:
919 free(event_array);
920out_free_fd: 872out_free_fd:
921 for (i = 0; i < MAX_NR_CPUS; i++) { 873 perf_evlist__delete_maps(evsel_list);
922 for (j = 0; j < MAX_COUNTERS; j++)
923 free(fd[i][j]);
924 }
925 free(all_tids);
926 all_tids = NULL;
927out_symbol_exit: 874out_symbol_exit:
928 symbol__exit(); 875 symbol__exit();
929 return err; 876 return err;
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 5de405d45230..498c6f70a747 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
@@ -43,120 +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 = callchain_append(he->callchain, data->callchain, syms, 72 err = callchain_append(he->callchain, &session->callchain_cursor,
111 data->period); 73 sample->period);
112 if (err) 74 if (err)
113 goto out_free_syms; 75 return err;
114 } 76 }
115 /* 77 /*
116 * Only in the newt browser we are doing integrated annotation, 78 * Only in the newt browser we are doing integrated annotation,
117 * 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
118 * code will not use it. 80 * code will not use it.
119 */ 81 */
120 if (use_browser > 0) 82 if (al->sym != NULL && use_browser > 0) {
121 err = hist_entry__inc_addr_samples(he, al->addr); 83 struct annotation *notes = symbol__annotation(he->ms.sym);
122out_free_syms:
123 free(syms);
124 return err;
125}
126 84
127static int add_event_total(struct perf_session *session, 85 assert(evsel != NULL);
128 struct sample_data *data,
129 struct perf_event_attr *attr)
130{
131 struct hists *hists;
132 86
133 if (attr) 87 err = -ENOMEM;
134 hists = perf_session__hists_findnew(session, data->id, 88 if (notes->src == NULL &&
135 attr->type, attr->config); 89 symbol__alloc_hist(he->ms.sym, session->evlist->nr_entries) < 0)
136 else 90 goto out;
137 hists = perf_session__hists_findnew(session, data->id, 0, 0);
138 91
139 if (!hists) 92 err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
140 return -ENOMEM; 93 }
141 94
142 hists->stats.total_period += data->period; 95 evsel->hists.stats.total_period += sample->period;
143 /* 96 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
144 * FIXME: add_event_total should be moved from here to 97out:
145 * perf_session__process_event so that the proper hist is passed to 98 return err;
146 * the event_op methods.
147 */
148 hists__inc_nr_events(hists, PERF_RECORD_SAMPLE);
149 session->hists.stats.total_period += data->period;
150 return 0;
151} 99}
152 100
153static 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)
154{ 106{
155 struct sample_data data = { .period = 1, };
156 struct addr_location al; 107 struct addr_location al;
157 struct perf_event_attr *attr;
158 108
159 if (event__preprocess_sample(event, session, &al, &data, NULL) < 0) { 109 if (perf_event__preprocess_sample(event, session, &al, sample,
110 annotate_init) < 0) {
160 fprintf(stderr, "problem processing %d event, skipping it.\n", 111 fprintf(stderr, "problem processing %d event, skipping it.\n",
161 event->header.type); 112 event->header.type);
162 return -1; 113 return -1;
@@ -165,30 +116,22 @@ static int process_sample_event(event_t *event, struct perf_session *session)
165 if (al.filtered || (hide_unresolved && al.sym == NULL)) 116 if (al.filtered || (hide_unresolved && al.sym == NULL))
166 return 0; 117 return 0;
167 118
168 if (perf_session__add_hist_entry(session, &al, &data)) { 119 if (perf_session__add_hist_entry(session, &al, sample, evsel)) {
169 pr_debug("problem incrementing symbol period, skipping event\n"); 120 pr_debug("problem incrementing symbol period, skipping event\n");
170 return -1; 121 return -1;
171 } 122 }
172 123
173 attr = perf_header__find_attr(data.id, &session->header);
174
175 if (add_event_total(session, &data, attr)) {
176 pr_debug("problem adding event period\n");
177 return -1;
178 }
179
180 return 0; 124 return 0;
181} 125}
182 126
183static int process_read_event(event_t *event, struct perf_session *session __used) 127static int process_read_event(union perf_event *event,
128 struct perf_sample *sample __used,
129 struct perf_session *session)
184{ 130{
185 struct perf_event_attr *attr; 131 struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist,
186 132 event->read.id);
187 attr = perf_header__find_attr(event->read.id, &session->header);
188
189 if (show_threads) { 133 if (show_threads) {
190 const char *name = attr ? __event_name(attr->type, attr->config) 134 const char *name = evsel ? event_name(evsel) : "unknown";
191 : "unknown";
192 perf_read_values_add_value(&show_threads_values, 135 perf_read_values_add_value(&show_threads_values,
193 event->read.pid, event->read.tid, 136 event->read.pid, event->read.tid,
194 event->read.id, 137 event->read.id,
@@ -196,8 +139,8 @@ static int process_read_event(event_t *event, struct perf_session *session __use
196 event->read.value); 139 event->read.value);
197 } 140 }
198 141
199 dump_printf(": %d %d %s %Lu\n", event->read.pid, event->read.tid, 142 dump_printf(": %d %d %s %" PRIu64 "\n", event->read.pid, event->read.tid,
200 attr ? __event_name(attr->type, attr->config) : "FAIL", 143 evsel ? event_name(evsel) : "FAIL",
201 event->read.value); 144 event->read.value);
202 145
203 return 0; 146 return 0;
@@ -221,7 +164,7 @@ static int perf_session__setup_sample_type(struct perf_session *self)
221 } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE && 164 } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE &&
222 !symbol_conf.use_callchain) { 165 !symbol_conf.use_callchain) {
223 symbol_conf.use_callchain = true; 166 symbol_conf.use_callchain = true;
224 if (register_callchain_param(&callchain_param) < 0) { 167 if (callchain_register_param(&callchain_param) < 0) {
225 fprintf(stderr, "Can't register callchain" 168 fprintf(stderr, "Can't register callchain"
226 " params\n"); 169 " params\n");
227 return -EINVAL; 170 return -EINVAL;
@@ -232,17 +175,19 @@ static int perf_session__setup_sample_type(struct perf_session *self)
232} 175}
233 176
234static struct perf_event_ops event_ops = { 177static struct perf_event_ops event_ops = {
235 .sample = process_sample_event, 178 .sample = process_sample_event,
236 .mmap = event__process_mmap, 179 .mmap = perf_event__process_mmap,
237 .comm = event__process_comm, 180 .comm = perf_event__process_comm,
238 .exit = event__process_task, 181 .exit = perf_event__process_task,
239 .fork = event__process_task, 182 .fork = perf_event__process_task,
240 .lost = event__process_lost, 183 .lost = perf_event__process_lost,
241 .read = process_read_event, 184 .read = process_read_event,
242 .attr = event__process_attr, 185 .attr = perf_event__process_attr,
243 .event_type = event__process_event_type, 186 .event_type = perf_event__process_event_type,
244 .tracing_data = event__process_tracing_data, 187 .tracing_data = perf_event__process_tracing_data,
245 .build_id = event__process_build_id, 188 .build_id = perf_event__process_build_id,
189 .ordered_samples = true,
190 .ordering_requires_timestamps = true,
246}; 191};
247 192
248extern volatile int session_done; 193extern volatile int session_done;
@@ -266,21 +211,21 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self,
266 return ret + fprintf(fp, "\n#\n"); 211 return ret + fprintf(fp, "\n#\n");
267} 212}
268 213
269static int hists__tty_browse_tree(struct rb_root *tree, const char *help) 214static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
215 const char *help)
270{ 216{
271 struct rb_node *next = rb_first(tree); 217 struct perf_evsel *pos;
272 218
273 while (next) { 219 list_for_each_entry(pos, &evlist->entries, node) {
274 struct hists *hists = rb_entry(next, struct hists, rb_node); 220 struct hists *hists = &pos->hists;
275 const char *evname = NULL; 221 const char *evname = NULL;
276 222
277 if (rb_first(&hists->entries) != rb_last(&hists->entries)) 223 if (rb_first(&hists->entries) != rb_last(&hists->entries))
278 evname = __event_name(hists->type, hists->config); 224 evname = event_name(pos);
279 225
280 hists__fprintf_nr_sample_events(hists, evname, stdout); 226 hists__fprintf_nr_sample_events(hists, evname, stdout);
281 hists__fprintf(hists, NULL, false, stdout); 227 hists__fprintf(hists, NULL, false, stdout);
282 fprintf(stdout, "\n\n"); 228 fprintf(stdout, "\n\n");
283 next = rb_next(&hists->rb_node);
284 } 229 }
285 230
286 if (sort_order == default_sort_order && 231 if (sort_order == default_sort_order &&
@@ -301,13 +246,14 @@ static int hists__tty_browse_tree(struct rb_root *tree, const char *help)
301static int __cmd_report(void) 246static int __cmd_report(void)
302{ 247{
303 int ret = -EINVAL; 248 int ret = -EINVAL;
249 u64 nr_samples;
304 struct perf_session *session; 250 struct perf_session *session;
305 struct rb_node *next; 251 struct perf_evsel *pos;
306 const char *help = "For a higher level overview, try: perf report --sort comm,dso"; 252 const char *help = "For a higher level overview, try: perf report --sort comm,dso";
307 253
308 signal(SIGINT, sig_handler); 254 signal(SIGINT, sig_handler);
309 255
310 session = perf_session__new(input_name, O_RDONLY, force, false); 256 session = perf_session__new(input_name, O_RDONLY, force, false, &event_ops);
311 if (session == NULL) 257 if (session == NULL)
312 return -ENOMEM; 258 return -ENOMEM;
313 259
@@ -333,20 +279,24 @@ static int __cmd_report(void)
333 if (verbose > 2) 279 if (verbose > 2)
334 perf_session__fprintf_dsos(session, stdout); 280 perf_session__fprintf_dsos(session, stdout);
335 281
336 next = rb_first(&session->hists_tree); 282 nr_samples = 0;
337 while (next) { 283 list_for_each_entry(pos, &session->evlist->entries, node) {
338 struct hists *hists; 284 struct hists *hists = &pos->hists;
339 285
340 hists = rb_entry(next, struct hists, rb_node);
341 hists__collapse_resort(hists); 286 hists__collapse_resort(hists);
342 hists__output_resort(hists); 287 hists__output_resort(hists);
343 next = rb_next(&hists->rb_node); 288 nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE];
289 }
290
291 if (nr_samples == 0) {
292 ui__warning("The %s file has no samples!\n", input_name);
293 goto out_delete;
344 } 294 }
345 295
346 if (use_browser > 0) 296 if (use_browser > 0)
347 hists__tui_browse_tree(&session->hists_tree, help); 297 perf_evlist__tui_browse_hists(session->evlist, help);
348 else 298 else
349 hists__tty_browse_tree(&session->hists_tree, help); 299 perf_evlist__tty_browse_hists(session->evlist, help);
350 300
351out_delete: 301out_delete:
352 /* 302 /*
@@ -421,7 +371,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
421 if (tok2) 371 if (tok2)
422 callchain_param.print_limit = strtod(tok2, &endptr); 372 callchain_param.print_limit = strtod(tok2, &endptr);
423setup: 373setup:
424 if (register_callchain_param(&callchain_param) < 0) { 374 if (callchain_register_param(&callchain_param) < 0) {
425 fprintf(stderr, "Can't register callchain params\n"); 375 fprintf(stderr, "Can't register callchain params\n");
426 return -1; 376 return -1;
427 } 377 }
@@ -442,6 +392,8 @@ static const struct option options[] = {
442 "dump raw trace in ASCII"), 392 "dump raw trace in ASCII"),
443 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 393 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
444 "file", "vmlinux pathname"), 394 "file", "vmlinux pathname"),
395 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
396 "file", "kallsyms pathname"),
445 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), 397 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
446 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, 398 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
447 "load module symbols - WARNING: use only with -k and LIVE kernel"), 399 "load module symbols - WARNING: use only with -k and LIVE kernel"),
@@ -478,6 +430,8 @@ static const struct option options[] = {
478 "columns '.' is reserved."), 430 "columns '.' is reserved."),
479 OPT_BOOLEAN('U', "hide-unresolved", &hide_unresolved, 431 OPT_BOOLEAN('U', "hide-unresolved", &hide_unresolved,
480 "Only display entries resolved to a symbol"), 432 "Only display entries resolved to a symbol"),
433 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
434 "Look for files with symbols relative to this directory"),
481 OPT_END() 435 OPT_END()
482}; 436};
483 437
@@ -491,7 +445,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
491 use_browser = 1; 445 use_browser = 1;
492 446
493 if (strcmp(input_name, "-") != 0) 447 if (strcmp(input_name, "-") != 0)
494 setup_browser(); 448 setup_browser(true);
495 else 449 else
496 use_browser = 0; 450 use_browser = 0;
497 /* 451 /*
@@ -500,7 +454,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
500 * implementation. 454 * implementation.
501 */ 455 */
502 if (use_browser > 0) { 456 if (use_browser > 0) {
503 symbol_conf.priv_size = sizeof(struct sym_priv); 457 symbol_conf.priv_size = sizeof(struct annotation);
458 annotate_init = symbol__annotate_init;
504 /* 459 /*
505 * For searching by name on the "Browse map details". 460 * For searching by name on the "Browse map details".
506 * providing it only in verbose mode not to bloat too 461 * 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-trace.c b/tools/perf/builtin-script.c
index 86cfe3800e6b..ac574ea23917 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-script.c
@@ -12,6 +12,8 @@
12#include "util/trace-event.h" 12#include "util/trace-event.h"
13#include "util/parse-options.h" 13#include "util/parse-options.h"
14#include "util/util.h" 14#include "util/util.h"
15#include "util/evlist.h"
16#include "util/evsel.h"
15 17
16static char const *script_name; 18static char const *script_name;
17static char const *generate_script_lang; 19static char const *generate_script_lang;
@@ -19,6 +21,175 @@ static bool debug_mode;
19static u64 last_timestamp; 21static u64 last_timestamp;
20static u64 nr_unordered; 22static u64 nr_unordered;
21extern const struct option record_options[]; 23extern const struct option record_options[];
24static bool no_callchain;
25
26enum perf_output_field {
27 PERF_OUTPUT_COMM = 1U << 0,
28 PERF_OUTPUT_TID = 1U << 1,
29 PERF_OUTPUT_PID = 1U << 2,
30 PERF_OUTPUT_TIME = 1U << 3,
31 PERF_OUTPUT_CPU = 1U << 4,
32 PERF_OUTPUT_EVNAME = 1U << 5,
33 PERF_OUTPUT_TRACE = 1U << 6,
34 PERF_OUTPUT_SYM = 1U << 7,
35};
36
37struct output_option {
38 const char *str;
39 enum perf_output_field field;
40} all_output_options[] = {
41 {.str = "comm", .field = PERF_OUTPUT_COMM},
42 {.str = "tid", .field = PERF_OUTPUT_TID},
43 {.str = "pid", .field = PERF_OUTPUT_PID},
44 {.str = "time", .field = PERF_OUTPUT_TIME},
45 {.str = "cpu", .field = PERF_OUTPUT_CPU},
46 {.str = "event", .field = PERF_OUTPUT_EVNAME},
47 {.str = "trace", .field = PERF_OUTPUT_TRACE},
48 {.str = "sym", .field = PERF_OUTPUT_SYM},
49};
50
51/* default set to maintain compatibility with current format */
52static u64 output_fields[PERF_TYPE_MAX] = {
53 [PERF_TYPE_HARDWARE] = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | \
54 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | \
55 PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM,
56
57 [PERF_TYPE_SOFTWARE] = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | \
58 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | \
59 PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM,
60
61 [PERF_TYPE_TRACEPOINT] = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | \
62 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | \
63 PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE,
64};
65
66static bool output_set_by_user;
67
68#define PRINT_FIELD(x) (output_fields[attr->type] & PERF_OUTPUT_##x)
69
70static int perf_session__check_attr(struct perf_session *session,
71 struct perf_event_attr *attr)
72{
73 if (PRINT_FIELD(TRACE) &&
74 !perf_session__has_traces(session, "record -R"))
75 return -EINVAL;
76
77 if (PRINT_FIELD(SYM)) {
78 if (!(session->sample_type & PERF_SAMPLE_IP)) {
79 pr_err("Samples do not contain IP data.\n");
80 return -EINVAL;
81 }
82 if (!no_callchain &&
83 !(session->sample_type & PERF_SAMPLE_CALLCHAIN))
84 symbol_conf.use_callchain = false;
85 }
86
87 if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) &&
88 !(session->sample_type & PERF_SAMPLE_TID)) {
89 pr_err("Samples do not contain TID/PID data.\n");
90 return -EINVAL;
91 }
92
93 if (PRINT_FIELD(TIME) &&
94 !(session->sample_type & PERF_SAMPLE_TIME)) {
95 pr_err("Samples do not contain timestamps.\n");
96 return -EINVAL;
97 }
98
99 if (PRINT_FIELD(CPU) &&
100 !(session->sample_type & PERF_SAMPLE_CPU)) {
101 pr_err("Samples do not contain cpu.\n");
102 return -EINVAL;
103 }
104
105 return 0;
106}
107
108static void print_sample_start(struct perf_sample *sample,
109 struct thread *thread,
110 struct perf_event_attr *attr)
111{
112 int type;
113 struct event *event;
114 const char *evname = NULL;
115 unsigned long secs;
116 unsigned long usecs;
117 unsigned long long nsecs;
118
119 if (PRINT_FIELD(COMM)) {
120 if (latency_format)
121 printf("%8.8s ", thread->comm);
122 else if (PRINT_FIELD(SYM) && symbol_conf.use_callchain)
123 printf("%s ", thread->comm);
124 else
125 printf("%16s ", thread->comm);
126 }
127
128 if (PRINT_FIELD(PID) && PRINT_FIELD(TID))
129 printf("%5d/%-5d ", sample->pid, sample->tid);
130 else if (PRINT_FIELD(PID))
131 printf("%5d ", sample->pid);
132 else if (PRINT_FIELD(TID))
133 printf("%5d ", sample->tid);
134
135 if (PRINT_FIELD(CPU)) {
136 if (latency_format)
137 printf("%3d ", sample->cpu);
138 else
139 printf("[%03d] ", sample->cpu);
140 }
141
142 if (PRINT_FIELD(TIME)) {
143 nsecs = sample->time;
144 secs = nsecs / NSECS_PER_SEC;
145 nsecs -= secs * NSECS_PER_SEC;
146 usecs = nsecs / NSECS_PER_USEC;
147 printf("%5lu.%06lu: ", secs, usecs);
148 }
149
150 if (PRINT_FIELD(EVNAME)) {
151 if (attr->type == PERF_TYPE_TRACEPOINT) {
152 type = trace_parse_common_type(sample->raw_data);
153 event = trace_find_event(type);
154 if (event)
155 evname = event->name;
156 } else
157 evname = __event_name(attr->type, attr->config);
158
159 printf("%s: ", evname ? evname : "(unknown)");
160 }
161}
162
163static void process_event(union perf_event *event __unused,
164 struct perf_sample *sample,
165 struct perf_evsel *evsel,
166 struct perf_session *session,
167 struct thread *thread)
168{
169 struct perf_event_attr *attr = &evsel->attr;
170
171 if (output_fields[attr->type] == 0)
172 return;
173
174 if (perf_session__check_attr(session, attr) < 0)
175 return;
176
177 print_sample_start(sample, thread, attr);
178
179 if (PRINT_FIELD(TRACE))
180 print_trace_event(sample->cpu, sample->raw_data,
181 sample->raw_size);
182
183 if (PRINT_FIELD(SYM)) {
184 if (!symbol_conf.use_callchain)
185 printf(" ");
186 else
187 printf("\n");
188 perf_session__print_symbols(event, sample, session);
189 }
190
191 printf("\n");
192}
22 193
23static int default_start_script(const char *script __unused, 194static int default_start_script(const char *script __unused,
24 int argc __unused, 195 int argc __unused,
@@ -40,7 +211,7 @@ static int default_generate_script(const char *outfile __unused)
40static struct scripting_ops default_scripting_ops = { 211static struct scripting_ops default_scripting_ops = {
41 .start_script = default_start_script, 212 .start_script = default_start_script,
42 .stop_script = default_stop_script, 213 .stop_script = default_stop_script,
43 .process_event = print_event, 214 .process_event = process_event,
44 .generate_script = default_generate_script, 215 .generate_script = default_generate_script,
45}; 216};
46 217
@@ -56,78 +227,54 @@ static void setup_scripting(void)
56 227
57static int cleanup_scripting(void) 228static int cleanup_scripting(void)
58{ 229{
59 pr_debug("\nperf trace script stopped\n"); 230 pr_debug("\nperf script stopped\n");
60 231
61 return scripting_ops->stop_script(); 232 return scripting_ops->stop_script();
62} 233}
63 234
64static char const *input_name = "perf.data"; 235static char const *input_name = "perf.data";
65 236
66static int process_sample_event(event_t *event, struct perf_session *session) 237static int process_sample_event(union perf_event *event,
238 struct perf_sample *sample,
239 struct perf_evsel *evsel,
240 struct perf_session *session)
67{ 241{
68 struct sample_data data; 242 struct thread *thread = perf_session__findnew(session, event->ip.pid);
69 struct thread *thread;
70
71 memset(&data, 0, sizeof(data));
72 data.time = -1;
73 data.cpu = -1;
74 data.period = 1;
75 243
76 event__parse_sample(event, session->sample_type, &data);
77
78 dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc,
79 data.pid, data.tid, data.ip, data.period);
80
81 thread = perf_session__findnew(session, event->ip.pid);
82 if (thread == NULL) { 244 if (thread == NULL) {
83 pr_debug("problem processing %d event, skipping it.\n", 245 pr_debug("problem processing %d event, skipping it.\n",
84 event->header.type); 246 event->header.type);
85 return -1; 247 return -1;
86 } 248 }
87 249
88 if (session->sample_type & PERF_SAMPLE_RAW) { 250 if (debug_mode) {
89 if (debug_mode) { 251 if (sample->time < last_timestamp) {
90 if (data.time < last_timestamp) { 252 pr_err("Samples misordered, previous: %" PRIu64
91 pr_err("Samples misordered, previous: %llu " 253 " this: %" PRIu64 "\n", last_timestamp,
92 "this: %llu\n", last_timestamp, 254 sample->time);
93 data.time); 255 nr_unordered++;
94 nr_unordered++;
95 }
96 last_timestamp = data.time;
97 return 0;
98 } 256 }
99 /* 257 last_timestamp = sample->time;
100 * FIXME: better resolve from pid from the struct trace_entry 258 return 0;
101 * field, although it should be the same than this perf
102 * event pid
103 */
104 scripting_ops->process_event(data.cpu, data.raw_data,
105 data.raw_size,
106 data.time, thread->comm);
107 } 259 }
260 scripting_ops->process_event(event, sample, evsel, session, thread);
108 261
109 session->hists.stats.total_period += data.period; 262 session->hists.stats.total_period += sample->period;
110 return 0;
111}
112
113static u64 nr_lost;
114
115static int process_lost_event(event_t *event, struct perf_session *session __used)
116{
117 nr_lost += event->lost.lost;
118
119 return 0; 263 return 0;
120} 264}
121 265
122static struct perf_event_ops event_ops = { 266static struct perf_event_ops event_ops = {
123 .sample = process_sample_event, 267 .sample = process_sample_event,
124 .comm = event__process_comm, 268 .mmap = perf_event__process_mmap,
125 .attr = event__process_attr, 269 .comm = perf_event__process_comm,
126 .event_type = event__process_event_type, 270 .exit = perf_event__process_task,
127 .tracing_data = event__process_tracing_data, 271 .fork = perf_event__process_task,
128 .build_id = event__process_build_id, 272 .attr = perf_event__process_attr,
129 .lost = process_lost_event, 273 .event_type = perf_event__process_event_type,
274 .tracing_data = perf_event__process_tracing_data,
275 .build_id = perf_event__process_build_id,
130 .ordered_samples = true, 276 .ordered_samples = true,
277 .ordering_requires_timestamps = true,
131}; 278};
132 279
133extern volatile int session_done; 280extern volatile int session_done;
@@ -137,7 +284,7 @@ static void sig_handler(int sig __unused)
137 session_done = 1; 284 session_done = 1;
138} 285}
139 286
140static int __cmd_trace(struct perf_session *session) 287static int __cmd_script(struct perf_session *session)
141{ 288{
142 int ret; 289 int ret;
143 290
@@ -145,10 +292,8 @@ static int __cmd_trace(struct perf_session *session)
145 292
146 ret = perf_session__process_events(session, &event_ops); 293 ret = perf_session__process_events(session, &event_ops);
147 294
148 if (debug_mode) { 295 if (debug_mode)
149 pr_err("Misordered timestamps: %llu\n", nr_unordered); 296 pr_err("Misordered timestamps: %" PRIu64 "\n", nr_unordered);
150 pr_err("Lost events: %llu\n", nr_lost);
151 }
152 297
153 return ret; 298 return ret;
154} 299}
@@ -159,7 +304,7 @@ struct script_spec {
159 char spec[0]; 304 char spec[0];
160}; 305};
161 306
162LIST_HEAD(script_specs); 307static LIST_HEAD(script_specs);
163 308
164static struct script_spec *script_spec__new(const char *spec, 309static struct script_spec *script_spec__new(const char *spec,
165 struct scripting_ops *ops) 310 struct scripting_ops *ops)
@@ -247,7 +392,7 @@ static void list_available_languages(void)
247 392
248 fprintf(stderr, "\n"); 393 fprintf(stderr, "\n");
249 fprintf(stderr, "Scripting language extensions (used in " 394 fprintf(stderr, "Scripting language extensions (used in "
250 "perf trace -s [spec:]script.[spec]):\n\n"); 395 "perf script -s [spec:]script.[spec]):\n\n");
251 396
252 list_for_each_entry(s, &script_specs, node) 397 list_for_each_entry(s, &script_specs, node)
253 fprintf(stderr, " %-42s [%s]\n", s->spec, s->ops->name); 398 fprintf(stderr, " %-42s [%s]\n", s->spec, s->ops->name);
@@ -301,17 +446,96 @@ static int parse_scriptname(const struct option *opt __used,
301 return 0; 446 return 0;
302} 447}
303 448
304#define for_each_lang(scripts_dir, lang_dirent, lang_next) \ 449static int parse_output_fields(const struct option *opt __used,
450 const char *arg, int unset __used)
451{
452 char *tok;
453 int i, imax = sizeof(all_output_options) / sizeof(struct output_option);
454 int rc = 0;
455 char *str = strdup(arg);
456 int type = -1;
457
458 if (!str)
459 return -ENOMEM;
460
461 tok = strtok(str, ":");
462 if (!tok) {
463 fprintf(stderr,
464 "Invalid field string - not prepended with type.");
465 return -EINVAL;
466 }
467
468 /* first word should state which event type user
469 * is specifying the fields
470 */
471 if (!strcmp(tok, "hw"))
472 type = PERF_TYPE_HARDWARE;
473 else if (!strcmp(tok, "sw"))
474 type = PERF_TYPE_SOFTWARE;
475 else if (!strcmp(tok, "trace"))
476 type = PERF_TYPE_TRACEPOINT;
477 else {
478 fprintf(stderr, "Invalid event type in field string.");
479 return -EINVAL;
480 }
481
482 output_fields[type] = 0;
483 while (1) {
484 tok = strtok(NULL, ",");
485 if (!tok)
486 break;
487 for (i = 0; i < imax; ++i) {
488 if (strcmp(tok, all_output_options[i].str) == 0) {
489 output_fields[type] |= all_output_options[i].field;
490 break;
491 }
492 }
493 if (i == imax) {
494 fprintf(stderr, "Invalid field requested.");
495 rc = -EINVAL;
496 break;
497 }
498 }
499
500 if (output_fields[type] == 0) {
501 pr_debug("No fields requested for %s type. "
502 "Events will not be displayed\n", event_type(type));
503 }
504
505 output_set_by_user = true;
506
507 free(str);
508 return rc;
509}
510
511/* Helper function for filesystems that return a dent->d_type DT_UNKNOWN */
512static int is_directory(const char *base_path, const struct dirent *dent)
513{
514 char path[PATH_MAX];
515 struct stat st;
516
517 sprintf(path, "%s/%s", base_path, dent->d_name);
518 if (stat(path, &st))
519 return 0;
520
521 return S_ISDIR(st.st_mode);
522}
523
524#define for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next)\
305 while (!readdir_r(scripts_dir, &lang_dirent, &lang_next) && \ 525 while (!readdir_r(scripts_dir, &lang_dirent, &lang_next) && \
306 lang_next) \ 526 lang_next) \
307 if (lang_dirent.d_type == DT_DIR && \ 527 if ((lang_dirent.d_type == DT_DIR || \
528 (lang_dirent.d_type == DT_UNKNOWN && \
529 is_directory(scripts_path, &lang_dirent))) && \
308 (strcmp(lang_dirent.d_name, ".")) && \ 530 (strcmp(lang_dirent.d_name, ".")) && \
309 (strcmp(lang_dirent.d_name, ".."))) 531 (strcmp(lang_dirent.d_name, "..")))
310 532
311#define for_each_script(lang_dir, script_dirent, script_next) \ 533#define for_each_script(lang_path, lang_dir, script_dirent, script_next)\
312 while (!readdir_r(lang_dir, &script_dirent, &script_next) && \ 534 while (!readdir_r(lang_dir, &script_dirent, &script_next) && \
313 script_next) \ 535 script_next) \
314 if (script_dirent.d_type != DT_DIR) 536 if (script_dirent.d_type != DT_DIR && \
537 (script_dirent.d_type != DT_UNKNOWN || \
538 !is_directory(lang_path, &script_dirent)))
315 539
316 540
317#define RECORD_SUFFIX "-record" 541#define RECORD_SUFFIX "-record"
@@ -324,7 +548,7 @@ struct script_desc {
324 char *args; 548 char *args;
325}; 549};
326 550
327LIST_HEAD(script_descs); 551static LIST_HEAD(script_descs);
328 552
329static struct script_desc *script_desc__new(const char *name) 553static struct script_desc *script_desc__new(const char *name)
330{ 554{
@@ -380,10 +604,10 @@ out_delete_desc:
380 return NULL; 604 return NULL;
381} 605}
382 606
383static char *ends_with(char *str, const char *suffix) 607static const char *ends_with(const char *str, const char *suffix)
384{ 608{
385 size_t suffix_len = strlen(suffix); 609 size_t suffix_len = strlen(suffix);
386 char *p = str; 610 const char *p = str;
387 611
388 if (strlen(str) > suffix_len) { 612 if (strlen(str) > suffix_len) {
389 p = str + strlen(str) - suffix_len; 613 p = str + strlen(str) - suffix_len;
@@ -466,16 +690,16 @@ static int list_available_scripts(const struct option *opt __used,
466 if (!scripts_dir) 690 if (!scripts_dir)
467 return -1; 691 return -1;
468 692
469 for_each_lang(scripts_dir, lang_dirent, lang_next) { 693 for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next) {
470 snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path, 694 snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path,
471 lang_dirent.d_name); 695 lang_dirent.d_name);
472 lang_dir = opendir(lang_path); 696 lang_dir = opendir(lang_path);
473 if (!lang_dir) 697 if (!lang_dir)
474 continue; 698 continue;
475 699
476 for_each_script(lang_dir, script_dirent, script_next) { 700 for_each_script(lang_path, lang_dir, script_dirent, script_next) {
477 script_root = strdup(script_dirent.d_name); 701 script_root = strdup(script_dirent.d_name);
478 str = ends_with(script_root, REPORT_SUFFIX); 702 str = (char *)ends_with(script_root, REPORT_SUFFIX);
479 if (str) { 703 if (str) {
480 *str = '\0'; 704 *str = '\0';
481 desc = script_desc__findnew(script_root); 705 desc = script_desc__findnew(script_root);
@@ -514,16 +738,16 @@ static char *get_script_path(const char *script_root, const char *suffix)
514 if (!scripts_dir) 738 if (!scripts_dir)
515 return NULL; 739 return NULL;
516 740
517 for_each_lang(scripts_dir, lang_dirent, lang_next) { 741 for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next) {
518 snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path, 742 snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path,
519 lang_dirent.d_name); 743 lang_dirent.d_name);
520 lang_dir = opendir(lang_path); 744 lang_dir = opendir(lang_path);
521 if (!lang_dir) 745 if (!lang_dir)
522 continue; 746 continue;
523 747
524 for_each_script(lang_dir, script_dirent, script_next) { 748 for_each_script(lang_path, lang_dir, script_dirent, script_next) {
525 __script_root = strdup(script_dirent.d_name); 749 __script_root = strdup(script_dirent.d_name);
526 str = ends_with(__script_root, suffix); 750 str = (char *)ends_with(__script_root, suffix);
527 if (str) { 751 if (str) {
528 *str = '\0'; 752 *str = '\0';
529 if (strcmp(__script_root, script_root)) 753 if (strcmp(__script_root, script_root))
@@ -543,7 +767,7 @@ static char *get_script_path(const char *script_root, const char *suffix)
543 767
544static bool is_top_script(const char *script_path) 768static bool is_top_script(const char *script_path)
545{ 769{
546 return ends_with((char *)script_path, "top") == NULL ? false : true; 770 return ends_with(script_path, "top") == NULL ? false : true;
547} 771}
548 772
549static int has_required_arg(char *script_path) 773static int has_required_arg(char *script_path)
@@ -569,12 +793,12 @@ out:
569 return n_args; 793 return n_args;
570} 794}
571 795
572static const char * const trace_usage[] = { 796static const char * const script_usage[] = {
573 "perf trace [<options>]", 797 "perf script [<options>]",
574 "perf trace [<options>] record <script> [<record-options>] <command>", 798 "perf script [<options>] record <script> [<record-options>] <command>",
575 "perf trace [<options>] report <script> [script-args]", 799 "perf script [<options>] report <script> [script-args]",
576 "perf trace [<options>] <script> [<record-options>] <command>", 800 "perf script [<options>] <script> [<record-options>] <command>",
577 "perf trace [<options>] <top-script> [script-args]", 801 "perf script [<options>] <top-script> [script-args]",
578 NULL 802 NULL
579}; 803};
580 804
@@ -591,11 +815,22 @@ static const struct option options[] = {
591 "script file name (lang:script name, script name, or *)", 815 "script file name (lang:script name, script name, or *)",
592 parse_scriptname), 816 parse_scriptname),
593 OPT_STRING('g', "gen-script", &generate_script_lang, "lang", 817 OPT_STRING('g', "gen-script", &generate_script_lang, "lang",
594 "generate perf-trace.xx script in specified language"), 818 "generate perf-script.xx script in specified language"),
595 OPT_STRING('i', "input", &input_name, "file", 819 OPT_STRING('i', "input", &input_name, "file",
596 "input file name"), 820 "input file name"),
597 OPT_BOOLEAN('d', "debug-mode", &debug_mode, 821 OPT_BOOLEAN('d', "debug-mode", &debug_mode,
598 "do various checks like samples ordering and lost events"), 822 "do various checks like samples ordering and lost events"),
823 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
824 "file", "vmlinux pathname"),
825 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
826 "file", "kallsyms pathname"),
827 OPT_BOOLEAN('G', "hide-call-graph", &no_callchain,
828 "When printing symbols do not display call chain"),
829 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
830 "Look for files with symbols relative to this directory"),
831 OPT_CALLBACK('f', "fields", NULL, "str",
832 "comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace. Fields: comm,tid,pid,time,cpu,event,trace,sym",
833 parse_output_fields),
599 834
600 OPT_END() 835 OPT_END()
601}; 836};
@@ -614,7 +849,7 @@ static bool have_cmd(int argc, const char **argv)
614 return argc != 0; 849 return argc != 0;
615} 850}
616 851
617int cmd_trace(int argc, const char **argv, const char *prefix __used) 852int cmd_script(int argc, const char **argv, const char *prefix __used)
618{ 853{
619 char *rec_script_path = NULL; 854 char *rec_script_path = NULL;
620 char *rep_script_path = NULL; 855 char *rep_script_path = NULL;
@@ -626,7 +861,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
626 861
627 setup_scripting(); 862 setup_scripting();
628 863
629 argc = parse_options(argc, argv, options, trace_usage, 864 argc = parse_options(argc, argv, options, script_usage,
630 PARSE_OPT_STOP_AT_NON_OPTION); 865 PARSE_OPT_STOP_AT_NON_OPTION);
631 866
632 if (argc > 1 && !strncmp(argv[0], "rec", strlen("rec"))) { 867 if (argc > 1 && !strncmp(argv[0], "rec", strlen("rec"))) {
@@ -640,7 +875,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
640 if (!rep_script_path) { 875 if (!rep_script_path) {
641 fprintf(stderr, 876 fprintf(stderr,
642 "Please specify a valid report script" 877 "Please specify a valid report script"
643 "(see 'perf trace -l' for listing)\n"); 878 "(see 'perf script -l' for listing)\n");
644 return -1; 879 return -1;
645 } 880 }
646 } 881 }
@@ -658,8 +893,8 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
658 893
659 if (!rec_script_path && !rep_script_path) { 894 if (!rec_script_path && !rep_script_path) {
660 fprintf(stderr, " Couldn't find script %s\n\n See perf" 895 fprintf(stderr, " Couldn't find script %s\n\n See perf"
661 " trace -l for available scripts.\n", argv[0]); 896 " script -l for available scripts.\n", argv[0]);
662 usage_with_options(trace_usage, options); 897 usage_with_options(script_usage, options);
663 } 898 }
664 899
665 if (is_top_script(argv[0])) { 900 if (is_top_script(argv[0])) {
@@ -671,9 +906,9 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
671 rec_args = (argc - 1) - rep_args; 906 rec_args = (argc - 1) - rep_args;
672 if (rec_args < 0) { 907 if (rec_args < 0) {
673 fprintf(stderr, " %s script requires options." 908 fprintf(stderr, " %s script requires options."
674 "\n\n See perf trace -l for available " 909 "\n\n See perf script -l for available "
675 "scripts and options.\n", argv[0]); 910 "scripts and options.\n", argv[0]);
676 usage_with_options(trace_usage, options); 911 usage_with_options(script_usage, options);
677 } 912 }
678 } 913 }
679 914
@@ -772,18 +1007,26 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
772 if (!script_name) 1007 if (!script_name)
773 setup_pager(); 1008 setup_pager();
774 1009
775 session = perf_session__new(input_name, O_RDONLY, 0, false); 1010 session = perf_session__new(input_name, O_RDONLY, 0, false, &event_ops);
776 if (session == NULL) 1011 if (session == NULL)
777 return -ENOMEM; 1012 return -ENOMEM;
778 1013
779 if (strcmp(input_name, "-") && 1014 if (!no_callchain)
780 !perf_session__has_traces(session, "record -R")) 1015 symbol_conf.use_callchain = true;
781 return -EINVAL; 1016 else
1017 symbol_conf.use_callchain = false;
782 1018
783 if (generate_script_lang) { 1019 if (generate_script_lang) {
784 struct stat perf_stat; 1020 struct stat perf_stat;
1021 int input;
1022
1023 if (output_set_by_user) {
1024 fprintf(stderr,
1025 "custom fields not supported for generated scripts");
1026 return -1;
1027 }
785 1028
786 int input = open(input_name, O_RDONLY); 1029 input = open(input_name, O_RDONLY);
787 if (input < 0) { 1030 if (input < 0) {
788 perror("failed to open file"); 1031 perror("failed to open file");
789 exit(-1); 1032 exit(-1);
@@ -806,7 +1049,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
806 return -1; 1049 return -1;
807 } 1050 }
808 1051
809 err = scripting_ops->generate_script("perf-trace"); 1052 err = scripting_ops->generate_script("perf-script");
810 goto out; 1053 goto out;
811 } 1054 }
812 1055
@@ -814,10 +1057,10 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
814 err = scripting_ops->start_script(script_name, argc, argv); 1057 err = scripting_ops->start_script(script_name, argc, argv);
815 if (err) 1058 if (err)
816 goto out; 1059 goto out;
817 pr_debug("perf trace started with script %s\n\n", script_name); 1060 pr_debug("perf script started with script %s\n\n", script_name);
818 } 1061 }
819 1062
820 err = __cmd_trace(session); 1063 err = __cmd_script(session);
821 1064
822 perf_session__delete(session); 1065 perf_session__delete(session);
823 cleanup_scripting(); 1066 cleanup_scripting();
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index a6b4d44f9502..03f0e45f1479 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -43,15 +43,20 @@
43#include "util/parse-options.h" 43#include "util/parse-options.h"
44#include "util/parse-events.h" 44#include "util/parse-events.h"
45#include "util/event.h" 45#include "util/event.h"
46#include "util/evlist.h"
47#include "util/evsel.h"
46#include "util/debug.h" 48#include "util/debug.h"
47#include "util/header.h" 49#include "util/header.h"
48#include "util/cpumap.h" 50#include "util/cpumap.h"
49#include "util/thread.h" 51#include "util/thread.h"
52#include "util/thread_map.h"
50 53
51#include <sys/prctl.h> 54#include <sys/prctl.h>
52#include <math.h> 55#include <math.h>
53#include <locale.h> 56#include <locale.h>
54 57
58#define DEFAULT_SEPARATOR " "
59
55static struct perf_event_attr default_attrs[] = { 60static struct perf_event_attr default_attrs[] = {
56 61
57 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK }, 62 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK },
@@ -68,26 +73,24 @@ static struct perf_event_attr default_attrs[] = {
68 73
69}; 74};
70 75
76struct perf_evlist *evsel_list;
77
71static bool system_wide = false; 78static bool system_wide = false;
72static int nr_cpus = 0;
73static int run_idx = 0; 79static int run_idx = 0;
74 80
75static int run_count = 1; 81static int run_count = 1;
76static bool no_inherit = false; 82static bool no_inherit = false;
77static bool scale = true; 83static bool scale = true;
84static bool no_aggr = false;
78static pid_t target_pid = -1; 85static pid_t target_pid = -1;
79static pid_t target_tid = -1; 86static pid_t target_tid = -1;
80static pid_t *all_tids = NULL;
81static int thread_num = 0;
82static pid_t child_pid = -1; 87static pid_t child_pid = -1;
83static bool null_run = false; 88static bool null_run = false;
84static bool big_num = false; 89static bool big_num = true;
90static int big_num_opt = -1;
85static const char *cpu_list; 91static const char *cpu_list;
86 92static const char *csv_sep = NULL;
87 93static bool csv_output = false;
88static int *fd[MAX_NR_CPUS][MAX_COUNTERS];
89
90static int event_scaled[MAX_COUNTERS];
91 94
92static volatile int done = 0; 95static volatile int done = 0;
93 96
@@ -96,6 +99,22 @@ struct stats
96 double n, mean, M2; 99 double n, mean, M2;
97}; 100};
98 101
102struct perf_stat {
103 struct stats res_stats[3];
104};
105
106static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel)
107{
108 evsel->priv = zalloc(sizeof(struct perf_stat));
109 return evsel->priv == NULL ? -ENOMEM : 0;
110}
111
112static void perf_evsel__free_stat_priv(struct perf_evsel *evsel)
113{
114 free(evsel->priv);
115 evsel->priv = NULL;
116}
117
99static void update_stats(struct stats *stats, u64 val) 118static void update_stats(struct stats *stats, u64 val)
100{ 119{
101 double delta; 120 double delta;
@@ -135,69 +154,39 @@ static double stddev_stats(struct stats *stats)
135 return sqrt(variance_mean); 154 return sqrt(variance_mean);
136} 155}
137 156
138struct stats event_res_stats[MAX_COUNTERS][3]; 157struct stats runtime_nsecs_stats[MAX_NR_CPUS];
139struct stats runtime_nsecs_stats; 158struct stats runtime_cycles_stats[MAX_NR_CPUS];
159struct stats runtime_branches_stats[MAX_NR_CPUS];
140struct stats walltime_nsecs_stats; 160struct stats walltime_nsecs_stats;
141struct stats runtime_cycles_stats;
142struct stats runtime_branches_stats;
143 161
144#define MATCH_EVENT(t, c, counter) \ 162static int create_perf_stat_counter(struct perf_evsel *evsel)
145 (attrs[counter].type == PERF_TYPE_##t && \
146 attrs[counter].config == PERF_COUNT_##c)
147
148#define ERR_PERF_OPEN \
149"Error: counter %d, sys_perf_event_open() syscall returned with %d (%s)\n"
150
151static int create_perf_stat_counter(int counter)
152{ 163{
153 struct perf_event_attr *attr = attrs + counter; 164 struct perf_event_attr *attr = &evsel->attr;
154 int thread;
155 int ncreated = 0;
156 165
157 if (scale) 166 if (scale)
158 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | 167 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
159 PERF_FORMAT_TOTAL_TIME_RUNNING; 168 PERF_FORMAT_TOTAL_TIME_RUNNING;
160 169
161 if (system_wide) { 170 attr->inherit = !no_inherit;
162 int cpu; 171
163 172 if (system_wide)
164 for (cpu = 0; cpu < nr_cpus; cpu++) { 173 return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, false);
165 fd[cpu][counter][0] = sys_perf_event_open(attr, 174
166 -1, cpumap[cpu], -1, 0); 175 if (target_pid == -1 && target_tid == -1) {
167 if (fd[cpu][counter][0] < 0) 176 attr->disabled = 1;
168 pr_debug(ERR_PERF_OPEN, counter, 177 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 } 178 }
190 179
191 return ncreated; 180 return perf_evsel__open_per_thread(evsel, evsel_list->threads, false);
192} 181}
193 182
194/* 183/*
195 * Does the counter have nsecs as a unit? 184 * Does the counter have nsecs as a unit?
196 */ 185 */
197static inline int nsec_counter(int counter) 186static inline int nsec_counter(struct perf_evsel *evsel)
198{ 187{
199 if (MATCH_EVENT(SOFTWARE, SW_CPU_CLOCK, counter) || 188 if (perf_evsel__match(evsel, SOFTWARE, SW_CPU_CLOCK) ||
200 MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) 189 perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK))
201 return 1; 190 return 1;
202 191
203 return 0; 192 return 0;
@@ -205,84 +194,74 @@ static inline int nsec_counter(int counter)
205 194
206/* 195/*
207 * Read out the results of a single counter: 196 * Read out the results of a single counter:
197 * aggregate counts across CPUs in system-wide mode
208 */ 198 */
209static void read_counter(int counter) 199static int read_counter_aggr(struct perf_evsel *counter)
210{ 200{
211 u64 count[3], single_count[3]; 201 struct perf_stat *ps = counter->priv;
212 int cpu; 202 u64 *count = counter->counts->aggr.values;
213 size_t res, nv; 203 int i;
214 int scaled;
215 int i, thread;
216 204
217 count[0] = count[1] = count[2] = 0; 205 if (__perf_evsel__read(counter, evsel_list->cpus->nr,
206 evsel_list->threads->nr, scale) < 0)
207 return -1;
218 208
219 nv = scale ? 3 : 1; 209 for (i = 0; i < 3; i++)
220 for (cpu = 0; cpu < nr_cpus; cpu++) { 210 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 211
225 res = read(fd[cpu][counter][thread], 212 if (verbose) {
226 single_count, nv * sizeof(u64)); 213 fprintf(stderr, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
227 assert(res == nv * sizeof(u64)); 214 event_name(counter), count[0], count[1], count[2]);
215 }
228 216
229 close(fd[cpu][counter][thread]); 217 /*
230 fd[cpu][counter][thread] = -1; 218 * Save the full runtime - to allow normalization during printout:
219 */
220 if (perf_evsel__match(counter, SOFTWARE, SW_TASK_CLOCK))
221 update_stats(&runtime_nsecs_stats[0], count[0]);
222 if (perf_evsel__match(counter, HARDWARE, HW_CPU_CYCLES))
223 update_stats(&runtime_cycles_stats[0], count[0]);
224 if (perf_evsel__match(counter, HARDWARE, HW_BRANCH_INSTRUCTIONS))
225 update_stats(&runtime_branches_stats[0], count[0]);
231 226
232 count[0] += single_count[0]; 227 return 0;
233 if (scale) { 228}
234 count[1] += single_count[1];
235 count[2] += single_count[2];
236 }
237 }
238 }
239 229
240 scaled = 0; 230/*
241 if (scale) { 231 * Read out the results of a single counter:
242 if (count[2] == 0) { 232 * do not aggregate counts across CPUs in system-wide mode
243 event_scaled[counter] = -1; 233 */
244 count[0] = 0; 234static int read_counter(struct perf_evsel *counter)
245 return; 235{
246 } 236 u64 *count;
237 int cpu;
247 238
248 if (count[2] < count[1]) { 239 for (cpu = 0; cpu < evsel_list->cpus->nr; cpu++) {
249 event_scaled[counter] = 1; 240 if (__perf_evsel__read_on_cpu(counter, cpu, 0, scale) < 0)
250 count[0] = (unsigned long long) 241 return -1;
251 ((double)count[0] * count[1] / count[2] + 0.5);
252 }
253 }
254 242
255 for (i = 0; i < 3; i++) 243 count = counter->counts->cpu[cpu].values;
256 update_stats(&event_res_stats[counter][i], count[i]);
257 244
258 if (verbose) { 245 if (perf_evsel__match(counter, SOFTWARE, SW_TASK_CLOCK))
259 fprintf(stderr, "%s: %Ld %Ld %Ld\n", event_name(counter), 246 update_stats(&runtime_nsecs_stats[cpu], count[0]);
260 count[0], count[1], count[2]); 247 if (perf_evsel__match(counter, HARDWARE, HW_CPU_CYCLES))
248 update_stats(&runtime_cycles_stats[cpu], count[0]);
249 if (perf_evsel__match(counter, HARDWARE, HW_BRANCH_INSTRUCTIONS))
250 update_stats(&runtime_branches_stats[cpu], count[0]);
261 } 251 }
262 252
263 /* 253 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} 254}
273 255
274static int run_perf_stat(int argc __used, const char **argv) 256static int run_perf_stat(int argc __used, const char **argv)
275{ 257{
276 unsigned long long t0, t1; 258 unsigned long long t0, t1;
259 struct perf_evsel *counter;
277 int status = 0; 260 int status = 0;
278 int counter, ncreated = 0;
279 int child_ready_pipe[2], go_pipe[2]; 261 int child_ready_pipe[2], go_pipe[2];
280 const bool forks = (argc > 0); 262 const bool forks = (argc > 0);
281 char buf; 263 char buf;
282 264
283 if (!system_wide)
284 nr_cpus = 1;
285
286 if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) { 265 if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) {
287 perror("failed to create pipes"); 266 perror("failed to create pipes");
288 exit(1); 267 exit(1);
@@ -322,7 +301,7 @@ static int run_perf_stat(int argc __used, const char **argv)
322 } 301 }
323 302
324 if (target_tid == -1 && target_pid == -1 && !system_wide) 303 if (target_tid == -1 && target_pid == -1 && !system_wide)
325 all_tids[0] = child_pid; 304 evsel_list->threads->map[0] = child_pid;
326 305
327 /* 306 /*
328 * Wait for the child to be ready to exec. 307 * Wait for the child to be ready to exec.
@@ -334,15 +313,30 @@ static int run_perf_stat(int argc __used, const char **argv)
334 close(child_ready_pipe[0]); 313 close(child_ready_pipe[0]);
335 } 314 }
336 315
337 for (counter = 0; counter < nr_counters; counter++) 316 list_for_each_entry(counter, &evsel_list->entries, node) {
338 ncreated += create_perf_stat_counter(counter); 317 if (create_perf_stat_counter(counter) < 0) {
318 if (errno == -EPERM || errno == -EACCES) {
319 error("You may not have permission to collect %sstats.\n"
320 "\t Consider tweaking"
321 " /proc/sys/kernel/perf_event_paranoid or running as root.",
322 system_wide ? "system-wide " : "");
323 } else if (errno == ENOENT) {
324 error("%s event is not supported. ", event_name(counter));
325 } else {
326 error("open_counter returned with %d (%s). "
327 "/bin/dmesg may provide additional information.\n",
328 errno, strerror(errno));
329 }
330 if (child_pid != -1)
331 kill(child_pid, SIGTERM);
332 die("Not all events could be opened.\n");
333 return -1;
334 }
335 }
339 336
340 if (ncreated == 0) { 337 if (perf_evlist__set_filters(evsel_list)) {
341 pr_err("No permission to collect %sstats.\n" 338 error("failed to set filter with %d (%s)\n", errno,
342 "Consider tweaking /proc/sys/kernel/perf_event_paranoid.\n", 339 strerror(errno));
343 system_wide ? "system-wide " : "");
344 if (child_pid != -1)
345 kill(child_pid, SIGTERM);
346 return -1; 340 return -1;
347 } 341 }
348 342
@@ -362,60 +356,104 @@ static int run_perf_stat(int argc __used, const char **argv)
362 356
363 update_stats(&walltime_nsecs_stats, t1 - t0); 357 update_stats(&walltime_nsecs_stats, t1 - t0);
364 358
365 for (counter = 0; counter < nr_counters; counter++) 359 if (no_aggr) {
366 read_counter(counter); 360 list_for_each_entry(counter, &evsel_list->entries, node) {
361 read_counter(counter);
362 perf_evsel__close_fd(counter, evsel_list->cpus->nr, 1);
363 }
364 } else {
365 list_for_each_entry(counter, &evsel_list->entries, node) {
366 read_counter_aggr(counter);
367 perf_evsel__close_fd(counter, evsel_list->cpus->nr,
368 evsel_list->threads->nr);
369 }
370 }
367 371
368 return WEXITSTATUS(status); 372 return WEXITSTATUS(status);
369} 373}
370 374
371static void print_noise(int counter, double avg) 375static void print_noise(struct perf_evsel *evsel, double avg)
372{ 376{
377 struct perf_stat *ps;
378
373 if (run_count == 1) 379 if (run_count == 1)
374 return; 380 return;
375 381
382 ps = evsel->priv;
376 fprintf(stderr, " ( +- %7.3f%% )", 383 fprintf(stderr, " ( +- %7.3f%% )",
377 100 * stddev_stats(&event_res_stats[counter][0]) / avg); 384 100 * stddev_stats(&ps->res_stats[0]) / avg);
378} 385}
379 386
380static void nsec_printout(int counter, double avg) 387static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg)
381{ 388{
382 double msecs = avg / 1e6; 389 double msecs = avg / 1e6;
390 char cpustr[16] = { '\0', };
391 const char *fmt = csv_output ? "%s%.6f%s%s" : "%s%18.6f%s%-24s";
392
393 if (no_aggr)
394 sprintf(cpustr, "CPU%*d%s",
395 csv_output ? 0 : -4,
396 evsel_list->cpus->map[cpu], csv_sep);
397
398 fprintf(stderr, fmt, cpustr, msecs, csv_sep, event_name(evsel));
399
400 if (evsel->cgrp)
401 fprintf(stderr, "%s%s", csv_sep, evsel->cgrp->name);
383 402
384 fprintf(stderr, " %18.6f %-24s", msecs, event_name(counter)); 403 if (csv_output)
404 return;
385 405
386 if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) { 406 if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK))
387 fprintf(stderr, " # %10.3f CPUs ", 407 fprintf(stderr, " # %10.3f CPUs ",
388 avg / avg_stats(&walltime_nsecs_stats)); 408 avg / avg_stats(&walltime_nsecs_stats));
389 }
390} 409}
391 410
392static void abs_printout(int counter, double avg) 411static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
393{ 412{
394 double total, ratio = 0.0; 413 double total, ratio = 0.0;
414 char cpustr[16] = { '\0', };
415 const char *fmt;
416
417 if (csv_output)
418 fmt = "%s%.0f%s%s";
419 else if (big_num)
420 fmt = "%s%'18.0f%s%-24s";
421 else
422 fmt = "%s%18.0f%s%-24s";
395 423
396 if (big_num) 424 if (no_aggr)
397 fprintf(stderr, " %'18.0f %-24s", avg, event_name(counter)); 425 sprintf(cpustr, "CPU%*d%s",
426 csv_output ? 0 : -4,
427 evsel_list->cpus->map[cpu], csv_sep);
398 else 428 else
399 fprintf(stderr, " %18.0f %-24s", avg, event_name(counter)); 429 cpu = 0;
400 430
401 if (MATCH_EVENT(HARDWARE, HW_INSTRUCTIONS, counter)) { 431 fprintf(stderr, fmt, cpustr, avg, csv_sep, event_name(evsel));
402 total = avg_stats(&runtime_cycles_stats); 432
433 if (evsel->cgrp)
434 fprintf(stderr, "%s%s", csv_sep, evsel->cgrp->name);
435
436 if (csv_output)
437 return;
438
439 if (perf_evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS)) {
440 total = avg_stats(&runtime_cycles_stats[cpu]);
403 441
404 if (total) 442 if (total)
405 ratio = avg / total; 443 ratio = avg / total;
406 444
407 fprintf(stderr, " # %10.3f IPC ", ratio); 445 fprintf(stderr, " # %10.3f IPC ", ratio);
408 } else if (MATCH_EVENT(HARDWARE, HW_BRANCH_MISSES, counter) && 446 } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) &&
409 runtime_branches_stats.n != 0) { 447 runtime_branches_stats[cpu].n != 0) {
410 total = avg_stats(&runtime_branches_stats); 448 total = avg_stats(&runtime_branches_stats[cpu]);
411 449
412 if (total) 450 if (total)
413 ratio = avg * 100 / total; 451 ratio = avg * 100 / total;
414 452
415 fprintf(stderr, " # %10.3f %% ", ratio); 453 fprintf(stderr, " # %10.3f %% ", ratio);
416 454
417 } else if (runtime_nsecs_stats.n != 0) { 455 } else if (runtime_nsecs_stats[cpu].n != 0) {
418 total = avg_stats(&runtime_nsecs_stats); 456 total = avg_stats(&runtime_nsecs_stats[cpu]);
419 457
420 if (total) 458 if (total)
421 ratio = 1000.0 * avg / total; 459 ratio = 1000.0 * avg / total;
@@ -426,72 +464,143 @@ static void abs_printout(int counter, double avg)
426 464
427/* 465/*
428 * Print out the results of a single counter: 466 * Print out the results of a single counter:
467 * aggregated counts in system-wide mode
429 */ 468 */
430static void print_counter(int counter) 469static void print_counter_aggr(struct perf_evsel *counter)
431{ 470{
432 double avg = avg_stats(&event_res_stats[counter][0]); 471 struct perf_stat *ps = counter->priv;
433 int scaled = event_scaled[counter]; 472 double avg = avg_stats(&ps->res_stats[0]);
473 int scaled = counter->counts->scaled;
434 474
435 if (scaled == -1) { 475 if (scaled == -1) {
436 fprintf(stderr, " %18s %-24s\n", 476 fprintf(stderr, "%*s%s%*s",
437 "<not counted>", event_name(counter)); 477 csv_output ? 0 : 18,
478 "<not counted>",
479 csv_sep,
480 csv_output ? 0 : -24,
481 event_name(counter));
482
483 if (counter->cgrp)
484 fprintf(stderr, "%s%s", csv_sep, counter->cgrp->name);
485
486 fputc('\n', stderr);
438 return; 487 return;
439 } 488 }
440 489
441 if (nsec_counter(counter)) 490 if (nsec_counter(counter))
442 nsec_printout(counter, avg); 491 nsec_printout(-1, counter, avg);
443 else 492 else
444 abs_printout(counter, avg); 493 abs_printout(-1, counter, avg);
494
495 if (csv_output) {
496 fputc('\n', stderr);
497 return;
498 }
445 499
446 print_noise(counter, avg); 500 print_noise(counter, avg);
447 501
448 if (scaled) { 502 if (scaled) {
449 double avg_enabled, avg_running; 503 double avg_enabled, avg_running;
450 504
451 avg_enabled = avg_stats(&event_res_stats[counter][1]); 505 avg_enabled = avg_stats(&ps->res_stats[1]);
452 avg_running = avg_stats(&event_res_stats[counter][2]); 506 avg_running = avg_stats(&ps->res_stats[2]);
453 507
454 fprintf(stderr, " (scaled from %.2f%%)", 508 fprintf(stderr, " (scaled from %.2f%%)",
455 100 * avg_running / avg_enabled); 509 100 * avg_running / avg_enabled);
456 } 510 }
457
458 fprintf(stderr, "\n"); 511 fprintf(stderr, "\n");
459} 512}
460 513
514/*
515 * Print out the results of a single counter:
516 * does not use aggregated count in system-wide
517 */
518static void print_counter(struct perf_evsel *counter)
519{
520 u64 ena, run, val;
521 int cpu;
522
523 for (cpu = 0; cpu < evsel_list->cpus->nr; cpu++) {
524 val = counter->counts->cpu[cpu].val;
525 ena = counter->counts->cpu[cpu].ena;
526 run = counter->counts->cpu[cpu].run;
527 if (run == 0 || ena == 0) {
528 fprintf(stderr, "CPU%*d%s%*s%s%*s",
529 csv_output ? 0 : -4,
530 evsel_list->cpus->map[cpu], csv_sep,
531 csv_output ? 0 : 18,
532 "<not counted>", csv_sep,
533 csv_output ? 0 : -24,
534 event_name(counter));
535
536 if (counter->cgrp)
537 fprintf(stderr, "%s%s", csv_sep, counter->cgrp->name);
538
539 fputc('\n', stderr);
540 continue;
541 }
542
543 if (nsec_counter(counter))
544 nsec_printout(cpu, counter, val);
545 else
546 abs_printout(cpu, counter, val);
547
548 if (!csv_output) {
549 print_noise(counter, 1.0);
550
551 if (run != ena) {
552 fprintf(stderr, " (scaled from %.2f%%)",
553 100.0 * run / ena);
554 }
555 }
556 fputc('\n', stderr);
557 }
558}
559
461static void print_stat(int argc, const char **argv) 560static void print_stat(int argc, const char **argv)
462{ 561{
463 int i, counter; 562 struct perf_evsel *counter;
563 int i;
464 564
465 fflush(stdout); 565 fflush(stdout);
466 566
467 fprintf(stderr, "\n"); 567 if (!csv_output) {
468 fprintf(stderr, " Performance counter stats for "); 568 fprintf(stderr, "\n");
469 if(target_pid == -1 && target_tid == -1) { 569 fprintf(stderr, " Performance counter stats for ");
470 fprintf(stderr, "\'%s", argv[0]); 570 if(target_pid == -1 && target_tid == -1) {
471 for (i = 1; i < argc; i++) 571 fprintf(stderr, "\'%s", argv[0]);
472 fprintf(stderr, " %s", argv[i]); 572 for (i = 1; i < argc; i++)
473 } else if (target_pid != -1) 573 fprintf(stderr, " %s", argv[i]);
474 fprintf(stderr, "process id \'%d", target_pid); 574 } else if (target_pid != -1)
475 else 575 fprintf(stderr, "process id \'%d", target_pid);
476 fprintf(stderr, "thread id \'%d", target_tid); 576 else
477 577 fprintf(stderr, "thread id \'%d", target_tid);
478 fprintf(stderr, "\'"); 578
479 if (run_count > 1) 579 fprintf(stderr, "\'");
480 fprintf(stderr, " (%d runs)", run_count); 580 if (run_count > 1)
481 fprintf(stderr, ":\n\n"); 581 fprintf(stderr, " (%d runs)", run_count);
582 fprintf(stderr, ":\n\n");
583 }
482 584
483 for (counter = 0; counter < nr_counters; counter++) 585 if (no_aggr) {
484 print_counter(counter); 586 list_for_each_entry(counter, &evsel_list->entries, node)
587 print_counter(counter);
588 } else {
589 list_for_each_entry(counter, &evsel_list->entries, node)
590 print_counter_aggr(counter);
591 }
485 592
486 fprintf(stderr, "\n"); 593 if (!csv_output) {
487 fprintf(stderr, " %18.9f seconds time elapsed", 594 fprintf(stderr, "\n");
488 avg_stats(&walltime_nsecs_stats)/1e9); 595 fprintf(stderr, " %18.9f seconds time elapsed",
489 if (run_count > 1) { 596 avg_stats(&walltime_nsecs_stats)/1e9);
490 fprintf(stderr, " ( +- %7.3f%% )", 597 if (run_count > 1) {
598 fprintf(stderr, " ( +- %7.3f%% )",
491 100*stddev_stats(&walltime_nsecs_stats) / 599 100*stddev_stats(&walltime_nsecs_stats) /
492 avg_stats(&walltime_nsecs_stats)); 600 avg_stats(&walltime_nsecs_stats));
601 }
602 fprintf(stderr, "\n\n");
493 } 603 }
494 fprintf(stderr, "\n\n");
495} 604}
496 605
497static volatile int signr = -1; 606static volatile int signr = -1;
@@ -521,10 +630,19 @@ static const char * const stat_usage[] = {
521 NULL 630 NULL
522}; 631};
523 632
633static int stat__set_big_num(const struct option *opt __used,
634 const char *s __used, int unset)
635{
636 big_num_opt = unset ? 0 : 1;
637 return 0;
638}
639
524static const struct option options[] = { 640static const struct option options[] = {
525 OPT_CALLBACK('e', "event", NULL, "event", 641 OPT_CALLBACK('e', "event", &evsel_list, "event",
526 "event selector. use 'perf list' to list available events", 642 "event selector. use 'perf list' to list available events",
527 parse_events), 643 parse_events),
644 OPT_CALLBACK(0, "filter", &evsel_list, "filter",
645 "event filter", parse_filter),
528 OPT_BOOLEAN('i', "no-inherit", &no_inherit, 646 OPT_BOOLEAN('i', "no-inherit", &no_inherit,
529 "child tasks do not inherit counters"), 647 "child tasks do not inherit counters"),
530 OPT_INTEGER('p', "pid", &target_pid, 648 OPT_INTEGER('p', "pid", &target_pid,
@@ -541,64 +659,103 @@ static const struct option options[] = {
541 "repeat command and print average + stddev (max: 100)"), 659 "repeat command and print average + stddev (max: 100)"),
542 OPT_BOOLEAN('n', "null", &null_run, 660 OPT_BOOLEAN('n', "null", &null_run,
543 "null run - dont start any counters"), 661 "null run - dont start any counters"),
544 OPT_BOOLEAN('B', "big-num", &big_num, 662 OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL,
545 "print large numbers with thousands\' separators"), 663 "print large numbers with thousands\' separators",
664 stat__set_big_num),
546 OPT_STRING('C', "cpu", &cpu_list, "cpu", 665 OPT_STRING('C', "cpu", &cpu_list, "cpu",
547 "list of cpus to monitor in system-wide"), 666 "list of cpus to monitor in system-wide"),
667 OPT_BOOLEAN('A', "no-aggr", &no_aggr,
668 "disable CPU count aggregation"),
669 OPT_STRING('x', "field-separator", &csv_sep, "separator",
670 "print counts with custom separator"),
671 OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
672 "monitor event in cgroup name only",
673 parse_cgroups),
548 OPT_END() 674 OPT_END()
549}; 675};
550 676
551int cmd_stat(int argc, const char **argv, const char *prefix __used) 677int cmd_stat(int argc, const char **argv, const char *prefix __used)
552{ 678{
553 int status; 679 struct perf_evsel *pos;
554 int i,j; 680 int status = -ENOMEM;
555 681
556 setlocale(LC_ALL, ""); 682 setlocale(LC_ALL, "");
557 683
684 evsel_list = perf_evlist__new(NULL, NULL);
685 if (evsel_list == NULL)
686 return -ENOMEM;
687
558 argc = parse_options(argc, argv, options, stat_usage, 688 argc = parse_options(argc, argv, options, stat_usage,
559 PARSE_OPT_STOP_AT_NON_OPTION); 689 PARSE_OPT_STOP_AT_NON_OPTION);
690
691 if (csv_sep)
692 csv_output = true;
693 else
694 csv_sep = DEFAULT_SEPARATOR;
695
696 /*
697 * let the spreadsheet do the pretty-printing
698 */
699 if (csv_output) {
700 /* User explicitely passed -B? */
701 if (big_num_opt == 1) {
702 fprintf(stderr, "-B option not supported with -x\n");
703 usage_with_options(stat_usage, options);
704 } else /* Nope, so disable big number formatting */
705 big_num = false;
706 } else if (big_num_opt == 0) /* User passed --no-big-num */
707 big_num = false;
708
560 if (!argc && target_pid == -1 && target_tid == -1) 709 if (!argc && target_pid == -1 && target_tid == -1)
561 usage_with_options(stat_usage, options); 710 usage_with_options(stat_usage, options);
562 if (run_count <= 0) 711 if (run_count <= 0)
563 usage_with_options(stat_usage, options); 712 usage_with_options(stat_usage, options);
564 713
714 /* no_aggr, cgroup are for system-wide only */
715 if ((no_aggr || nr_cgroups) && !system_wide) {
716 fprintf(stderr, "both cgroup and no-aggregation "
717 "modes only available in system-wide mode\n");
718
719 usage_with_options(stat_usage, options);
720 }
721
565 /* Set attrs and nr_counters if no event is selected and !null_run */ 722 /* Set attrs and nr_counters if no event is selected and !null_run */
566 if (!null_run && !nr_counters) { 723 if (!null_run && !evsel_list->nr_entries) {
567 memcpy(attrs, default_attrs, sizeof(default_attrs)); 724 size_t c;
568 nr_counters = ARRAY_SIZE(default_attrs); 725
726 for (c = 0; c < ARRAY_SIZE(default_attrs); ++c) {
727 pos = perf_evsel__new(&default_attrs[c], c);
728 if (pos == NULL)
729 goto out;
730 perf_evlist__add(evsel_list, pos);
731 }
569 } 732 }
570 733
571 if (system_wide) 734 if (target_pid != -1)
572 nr_cpus = read_cpu_map(cpu_list); 735 target_tid = target_pid;
573 else
574 nr_cpus = 1;
575 736
576 if (nr_cpus < 1) 737 evsel_list->threads = thread_map__new(target_pid, target_tid);
738 if (evsel_list->threads == NULL) {
739 pr_err("Problems finding threads of monitor\n");
577 usage_with_options(stat_usage, options); 740 usage_with_options(stat_usage, options);
741 }
578 742
579 if (target_pid != -1) { 743 if (system_wide)
580 target_tid = target_pid; 744 evsel_list->cpus = cpu_map__new(cpu_list);
581 thread_num = find_all_tid(target_pid, &all_tids); 745 else
582 if (thread_num <= 0) { 746 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 747
592 all_tids[0] = target_tid; 748 if (evsel_list->cpus == NULL) {
593 thread_num = 1; 749 perror("failed to parse CPUs map");
750 usage_with_options(stat_usage, options);
751 return -1;
594 } 752 }
595 753
596 for (i = 0; i < MAX_NR_CPUS; i++) { 754 list_for_each_entry(pos, &evsel_list->entries, node) {
597 for (j = 0; j < MAX_COUNTERS; j++) { 755 if (perf_evsel__alloc_stat_priv(pos) < 0 ||
598 fd[i][j] = malloc(sizeof(int)*thread_num); 756 perf_evsel__alloc_counts(pos, evsel_list->cpus->nr) < 0 ||
599 if (!fd[i][j]) 757 perf_evsel__alloc_fd(pos, evsel_list->cpus->nr, evsel_list->threads->nr) < 0)
600 return -ENOMEM; 758 goto out_free_fd;
601 }
602 } 759 }
603 760
604 /* 761 /*
@@ -621,6 +778,11 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
621 778
622 if (status != -1) 779 if (status != -1)
623 print_stat(argc, argv); 780 print_stat(argc, argv);
624 781out_free_fd:
782 list_for_each_entry(pos, &evsel_list->entries, node)
783 perf_evsel__free_stat_priv(pos);
784 perf_evlist__delete_maps(evsel_list);
785out:
786 perf_evlist__delete(evsel_list);
625 return status; 787 return status;
626} 788}
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 035b9fa063a9..11e3c8458362 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,364 @@ 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
478 for (i = 0; i < nsyscalls; ++i) {
479 char name[64];
480
481 snprintf(name, sizeof(name), "sys_enter_%s", syscall_names[i]);
482 ids[i] = trace_event__id(name);
483 if (ids[i] < 0) {
484 pr_debug("Is debugfs mounted on /sys/kernel/debug?\n");
485 return -1;
486 }
487 nr_events[i] = 0;
488 expected_nr_events[i] = random() % 257;
489 }
490
491 threads = thread_map__new(-1, getpid());
492 if (threads == NULL) {
493 pr_debug("thread_map__new\n");
494 return -1;
495 }
496
497 cpus = cpu_map__new(NULL);
498 if (cpus == NULL) {
499 pr_debug("cpu_map__new\n");
500 goto out_free_threads;
501 }
502
503 CPU_ZERO(&cpu_set);
504 CPU_SET(cpus->map[0], &cpu_set);
505 sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
506 if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) {
507 pr_debug("sched_setaffinity() failed on CPU %d: %s ",
508 cpus->map[0], strerror(errno));
509 goto out_free_cpus;
510 }
511
512 evlist = perf_evlist__new(cpus, threads);
513 if (evlist == NULL) {
514 pr_debug("perf_evlist__new\n");
515 goto out_free_cpus;
516 }
517
518 /* anonymous union fields, can't be initialized above */
519 attr.wakeup_events = 1;
520 attr.sample_period = 1;
521
522 for (i = 0; i < nsyscalls; ++i) {
523 attr.config = ids[i];
524 evsels[i] = perf_evsel__new(&attr, i);
525 if (evsels[i] == NULL) {
526 pr_debug("perf_evsel__new\n");
527 goto out_free_evlist;
528 }
529
530 perf_evlist__add(evlist, evsels[i]);
531
532 if (perf_evsel__open(evsels[i], cpus, threads, false) < 0) {
533 pr_debug("failed to open counter: %s, "
534 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
535 strerror(errno));
536 goto out_close_fd;
537 }
538 }
539
540 if (perf_evlist__mmap(evlist, 128, true) < 0) {
541 pr_debug("failed to mmap events: %d (%s)\n", errno,
542 strerror(errno));
543 goto out_close_fd;
544 }
545
546 for (i = 0; i < nsyscalls; ++i)
547 for (j = 0; j < expected_nr_events[i]; ++j) {
548 int foo = syscalls[i]();
549 ++foo;
550 }
551
552 while ((event = perf_evlist__read_on_cpu(evlist, 0)) != NULL) {
553 struct perf_sample sample;
554
555 if (event->header.type != PERF_RECORD_SAMPLE) {
556 pr_debug("unexpected %s event\n",
557 perf_event__name(event->header.type));
558 goto out_munmap;
559 }
560
561 perf_event__parse_sample(event, attr.sample_type, false, &sample);
562 evsel = perf_evlist__id2evsel(evlist, sample.id);
563 if (evsel == NULL) {
564 pr_debug("event with id %" PRIu64
565 " doesn't map to an evsel\n", sample.id);
566 goto out_munmap;
567 }
568 nr_events[evsel->idx]++;
569 }
570
571 list_for_each_entry(evsel, &evlist->entries, node) {
572 if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) {
573 pr_debug("expected %d %s events, got %d\n",
574 expected_nr_events[evsel->idx],
575 event_name(evsel), nr_events[evsel->idx]);
576 goto out_munmap;
577 }
578 }
579
580 err = 0;
581out_munmap:
582 perf_evlist__munmap(evlist);
583out_close_fd:
584 for (i = 0; i < nsyscalls; ++i)
585 perf_evsel__close_fd(evsels[i], 1, threads->nr);
586out_free_evlist:
587 perf_evlist__delete(evlist);
588out_free_cpus:
589 cpu_map__delete(cpus);
590out_free_threads:
591 thread_map__delete(threads);
592 return err;
593#undef nsyscalls
594}
595
222static struct test { 596static struct test {
223 const char *desc; 597 const char *desc;
224 int (*func)(void); 598 int (*func)(void);
@@ -228,6 +602,18 @@ static struct test {
228 .func = test__vmlinux_matches_kallsyms, 602 .func = test__vmlinux_matches_kallsyms,
229 }, 603 },
230 { 604 {
605 .desc = "detect open syscall event",
606 .func = test__open_syscall_event,
607 },
608 {
609 .desc = "detect open syscall event on all cpus",
610 .func = test__open_syscall_event_on_all_cpus,
611 },
612 {
613 .desc = "read samples using the mmap interface",
614 .func = test__basic_mmap,
615 },
616 {
231 .func = NULL, 617 .func = NULL,
232 }, 618 },
233}; 619};
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 dd625808c2a5..7e3d6e310bf8 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,87 +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]; 65#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
66
67static struct perf_top top = {
68 .count_filter = 5,
69 .delay_secs = 2,
70 .display_weighted = -1,
71 .target_pid = -1,
72 .target_tid = -1,
73 .active_symbols = LIST_HEAD_INIT(top.active_symbols),
74 .active_symbols_lock = PTHREAD_MUTEX_INITIALIZER,
75 .active_symbols_cond = PTHREAD_COND_INITIALIZER,
76 .freq = 1000, /* 1 KHz */
77};
59 78
60static bool system_wide = false; 79static bool system_wide = false;
61 80
62static int default_interval = 0; 81static bool use_tui, use_stdio;
63 82
64static int count_filter = 5; 83static int default_interval = 0;
65static int print_entries;
66 84
67static int target_pid = -1;
68static int target_tid = -1;
69static pid_t *all_tids = NULL;
70static int thread_num = 0;
71static bool inherit = false; 85static bool inherit = false;
72static int nr_cpus = 0;
73static int realtime_prio = 0; 86static int realtime_prio = 0;
74static bool group = false; 87static bool group = false;
75static unsigned int page_size; 88static unsigned int page_size;
76static unsigned int mmap_pages = 16; 89static unsigned int mmap_pages = 128;
77static int freq = 1000; /* 1 KHz */
78 90
79static int delay_secs = 2;
80static bool zero = false;
81static bool dump_symtab = false; 91static bool dump_symtab = false;
82 92
83static bool hide_kernel_symbols = false;
84static bool hide_user_symbols = false;
85static struct winsize winsize; 93static struct winsize winsize;
86 94
87/*
88 * Source
89 */
90
91struct source_line {
92 u64 eip;
93 unsigned long count[MAX_COUNTERS];
94 char *line;
95 struct source_line *next;
96};
97
98static const char *sym_filter = NULL; 95static const char *sym_filter = NULL;
99struct sym_entry *sym_filter_entry = NULL;
100struct sym_entry *sym_filter_entry_sched = NULL; 96struct sym_entry *sym_filter_entry_sched = NULL;
101static int sym_pcnt_filter = 5; 97static int sym_pcnt_filter = 5;
102static int sym_counter = 0;
103static int display_weighted = -1;
104static const char *cpu_list;
105
106/*
107 * Symbols
108 */
109
110struct sym_entry_source {
111 struct source_line *source;
112 struct source_line *lines;
113 struct source_line **lines_tail;
114 pthread_mutex_t lock;
115};
116
117struct sym_entry {
118 struct rb_node rb_node;
119 struct list_head node;
120 unsigned long snap_count;
121 double weight;
122 int skip;
123 u16 name_len;
124 u8 origin;
125 struct map *map;
126 struct sym_entry_source *src;
127 unsigned long count[0];
128};
129 98
130/* 99/*
131 * Source functions 100 * Source functions
132 */ 101 */
133 102
134static inline struct symbol *sym_entry__symbol(struct sym_entry *self)
135{
136 return ((void *)self) + symbol_conf.priv_size;
137}
138
139void get_term_dimensions(struct winsize *ws) 103void get_term_dimensions(struct winsize *ws)
140{ 104{
141 char *s = getenv("LINES"); 105 char *s = getenv("LINES");
@@ -160,10 +124,10 @@ void get_term_dimensions(struct winsize *ws)
160 124
161static void update_print_entries(struct winsize *ws) 125static void update_print_entries(struct winsize *ws)
162{ 126{
163 print_entries = ws->ws_row; 127 top.print_entries = ws->ws_row;
164 128
165 if (print_entries > 9) 129 if (top.print_entries > 9)
166 print_entries -= 9; 130 top.print_entries -= 9;
167} 131}
168 132
169static void sig_winch_handler(int sig __used) 133static void sig_winch_handler(int sig __used)
@@ -175,12 +139,9 @@ static void sig_winch_handler(int sig __used)
175static int parse_source(struct sym_entry *syme) 139static int parse_source(struct sym_entry *syme)
176{ 140{
177 struct symbol *sym; 141 struct symbol *sym;
178 struct sym_entry_source *source; 142 struct annotation *notes;
179 struct map *map; 143 struct map *map;
180 FILE *file; 144 int err = -1;
181 char command[PATH_MAX*2];
182 const char *path;
183 u64 len;
184 145
185 if (!syme) 146 if (!syme)
186 return -1; 147 return -1;
@@ -191,408 +152,137 @@ static int parse_source(struct sym_entry *syme)
191 /* 152 /*
192 * We can't annotate with just /proc/kallsyms 153 * We can't annotate with just /proc/kallsyms
193 */ 154 */
194 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);
195 return -1; 159 return -1;
196
197 if (syme->src == NULL) {
198 syme->src = zalloc(sizeof(*source));
199 if (syme->src == NULL)
200 return -1;
201 pthread_mutex_init(&syme->src->lock, NULL);
202 } 160 }
203 161
204 source = syme->src; 162 notes = symbol__annotation(sym);
205 163 if (notes->src != NULL) {
206 if (source->lines) { 164 pthread_mutex_lock(&notes->lock);
207 pthread_mutex_lock(&source->lock);
208 goto out_assign; 165 goto out_assign;
209 } 166 }
210 path = map->dso->long_name;
211
212 len = sym->end - sym->start;
213
214 sprintf(command,
215 "objdump --start-address=%#0*Lx --stop-address=%#0*Lx -dS %s",
216 BITS_PER_LONG / 4, map__rip_2objdump(map, sym->start),
217 BITS_PER_LONG / 4, map__rip_2objdump(map, sym->end), path);
218
219 file = popen(command, "r");
220 if (!file)
221 return -1;
222
223 pthread_mutex_lock(&source->lock);
224 source->lines_tail = &source->lines;
225 while (!feof(file)) {
226 struct source_line *src;
227 size_t dummy = 0;
228 char *c, *sep;
229
230 src = malloc(sizeof(struct source_line));
231 assert(src != NULL);
232 memset(src, 0, sizeof(struct source_line));
233 167
234 if (getline(&src->line, &dummy, file) < 0) 168 pthread_mutex_lock(&notes->lock);
235 break;
236 if (!src->line)
237 break;
238
239 c = strchr(src->line, '\n');
240 if (c)
241 *c = 0;
242
243 src->next = NULL;
244 *source->lines_tail = src;
245 source->lines_tail = &src->next;
246 169
247 src->eip = strtoull(src->line, &sep, 16); 170 if (symbol__alloc_hist(sym, top.evlist->nr_entries) < 0) {
248 if (*sep == ':') 171 pthread_mutex_unlock(&notes->lock);
249 src->eip = map__objdump_2ip(map, src->eip); 172 pr_err("Not enough memory for annotating '%s' symbol!\n",
250 else /* this line has no ip info (e.g. source line) */ 173 sym->name);
251 src->eip = 0; 174 sleep(1);
175 return err;
252 } 176 }
253 pclose(file); 177
178 err = symbol__annotate(sym, syme->map, 0);
179 if (err == 0) {
254out_assign: 180out_assign:
255 sym_filter_entry = syme; 181 top.sym_filter_entry = syme;
256 pthread_mutex_unlock(&source->lock); 182 }
257 return 0; 183
184 pthread_mutex_unlock(&notes->lock);
185 return err;
258} 186}
259 187
260static void __zero_source_counters(struct sym_entry *syme) 188static void __zero_source_counters(struct sym_entry *syme)
261{ 189{
262 int i; 190 struct symbol *sym = sym_entry__symbol(syme);
263 struct source_line *line; 191 symbol__annotate_zero_histograms(sym);
264
265 line = syme->src->lines;
266 while (line) {
267 for (i = 0; i < nr_counters; i++)
268 line->count[i] = 0;
269 line = line->next;
270 }
271} 192}
272 193
273static 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)
274{ 195{
275 struct source_line *line; 196 struct annotation *notes;
276 197 struct symbol *sym;
277 if (syme != sym_filter_entry)
278 return;
279 198
280 if (pthread_mutex_trylock(&syme->src->lock)) 199 if (syme != top.sym_filter_entry)
281 return; 200 return;
282 201
283 if (syme->src == NULL || syme->src->source == NULL) 202 sym = sym_entry__symbol(syme);
284 goto out_unlock; 203 notes = symbol__annotation(sym);
285
286 for (line = syme->src->lines; line; line = line->next) {
287 /* skip lines without IP info */
288 if (line->eip == 0)
289 continue;
290 if (line->eip == ip) {
291 line->count[counter]++;
292 break;
293 }
294 if (line->eip > ip)
295 break;
296 }
297out_unlock:
298 pthread_mutex_unlock(&syme->src->lock);
299}
300
301#define PATTERN_LEN (BITS_PER_LONG / 4 + 2)
302
303static void lookup_sym_source(struct sym_entry *syme)
304{
305 struct symbol *symbol = sym_entry__symbol(syme);
306 struct source_line *line;
307 char pattern[PATTERN_LEN + 1];
308
309 sprintf(pattern, "%0*Lx <", BITS_PER_LONG / 4,
310 map__rip_2objdump(syme->map, symbol->start));
311
312 pthread_mutex_lock(&syme->src->lock);
313 for (line = syme->src->lines; line; line = line->next) {
314 if (memcmp(line->line, pattern, PATTERN_LEN) == 0) {
315 syme->src->source = line;
316 break;
317 }
318 }
319 pthread_mutex_unlock(&syme->src->lock);
320}
321 204
322static void show_lines(struct source_line *queue, int count, int total) 205 if (pthread_mutex_trylock(&notes->lock))
323{ 206 return;
324 int i;
325 struct source_line *line;
326 207
327 line = queue; 208 ip = syme->map->map_ip(syme->map, ip);
328 for (i = 0; i < count; i++) { 209 symbol__inc_addr_samples(sym, syme->map, counter, ip);
329 float pcnt = 100.0*(float)line->count[sym_counter]/(float)total;
330 210
331 printf("%8li %4.1f%%\t%s\n", line->count[sym_counter], pcnt, line->line); 211 pthread_mutex_unlock(&notes->lock);
332 line = line->next;
333 }
334} 212}
335 213
336#define TRACE_COUNT 3
337
338static void show_details(struct sym_entry *syme) 214static void show_details(struct sym_entry *syme)
339{ 215{
216 struct annotation *notes;
340 struct symbol *symbol; 217 struct symbol *symbol;
341 struct source_line *line; 218 int more;
342 struct source_line *line_queue = NULL;
343 int displayed = 0;
344 int line_queue_count = 0, total = 0, more = 0;
345 219
346 if (!syme) 220 if (!syme)
347 return; 221 return;
348 222
349 if (!syme->src->source)
350 lookup_sym_source(syme);
351
352 if (!syme->src->source)
353 return;
354
355 symbol = sym_entry__symbol(syme); 223 symbol = sym_entry__symbol(syme);
356 printf("Showing %s for %s\n", event_name(sym_counter), symbol->name); 224 notes = symbol__annotation(symbol);
357 printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter);
358
359 pthread_mutex_lock(&syme->src->lock);
360 line = syme->src->source;
361 while (line) {
362 total += line->count[sym_counter];
363 line = line->next;
364 }
365
366 line = syme->src->source;
367 while (line) {
368 float pcnt = 0.0;
369
370 if (!line_queue_count)
371 line_queue = line;
372 line_queue_count++;
373
374 if (line->count[sym_counter])
375 pcnt = 100.0 * line->count[sym_counter] / (float)total;
376 if (pcnt >= (float)sym_pcnt_filter) {
377 if (displayed <= print_entries)
378 show_lines(line_queue, line_queue_count, total);
379 else more++;
380 displayed += line_queue_count;
381 line_queue_count = 0;
382 line_queue = NULL;
383 } else if (line_queue_count > TRACE_COUNT) {
384 line_queue = line_queue->next;
385 line_queue_count--;
386 }
387
388 line->count[sym_counter] = zero ? 0 : line->count[sym_counter] * 7 / 8;
389 line = line->next;
390 }
391 pthread_mutex_unlock(&syme->src->lock);
392 if (more)
393 printf("%d lines not displayed, maybe increase display entries [e]\n", more);
394}
395
396/*
397 * Symbols will be added here in event__process_sample and will get out
398 * after decayed.
399 */
400static LIST_HEAD(active_symbols);
401static pthread_mutex_t active_symbols_lock = PTHREAD_MUTEX_INITIALIZER;
402 225
403/* 226 pthread_mutex_lock(&notes->lock);
404 * Ordering weight: count-1 * count-2 * ... / count-n
405 */
406static double sym_weight(const struct sym_entry *sym)
407{
408 double weight = sym->snap_count;
409 int counter;
410
411 if (!display_weighted)
412 return weight;
413 227
414 for (counter = 1; counter < nr_counters-1; counter++) 228 if (notes->src == NULL)
415 weight *= sym->count[counter]; 229 goto out_unlock;
416 230
417 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);
418 233
419 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);
420} 244}
421 245
422static long samples;
423static long kernel_samples, us_samples;
424static long exact_samples;
425static long guest_us_samples, guest_kernel_samples;
426static const char CONSOLE_CLEAR[] = ""; 246static const char CONSOLE_CLEAR[] = "";
427 247
428static void __list_insert_active_sym(struct sym_entry *syme) 248static void __list_insert_active_sym(struct sym_entry *syme)
429{ 249{
430 list_add(&syme->node, &active_symbols); 250 list_add(&syme->node, &top.active_symbols);
431} 251}
432 252
433static void list_remove_active_sym(struct sym_entry *syme) 253static void print_sym_table(struct perf_session *session)
434{ 254{
435 pthread_mutex_lock(&active_symbols_lock); 255 char bf[160];
436 list_del_init(&syme->node); 256 int printed = 0;
437 pthread_mutex_unlock(&active_symbols_lock);
438}
439
440static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se)
441{
442 struct rb_node **p = &tree->rb_node;
443 struct rb_node *parent = NULL;
444 struct sym_entry *iter;
445
446 while (*p != NULL) {
447 parent = *p;
448 iter = rb_entry(parent, struct sym_entry, rb_node);
449
450 if (se->weight > iter->weight)
451 p = &(*p)->rb_left;
452 else
453 p = &(*p)->rb_right;
454 }
455
456 rb_link_node(&se->rb_node, parent, p);
457 rb_insert_color(&se->rb_node, tree);
458}
459
460static void print_sym_table(void)
461{
462 int printed = 0, j;
463 int counter, snap = !display_weighted ? sym_counter : 0;
464 float samples_per_sec = samples/delay_secs;
465 float ksamples_per_sec = kernel_samples/delay_secs;
466 float us_samples_per_sec = (us_samples)/delay_secs;
467 float guest_kernel_samples_per_sec = (guest_kernel_samples)/delay_secs;
468 float guest_us_samples_per_sec = (guest_us_samples)/delay_secs;
469 float esamples_percent = (100.0*exact_samples)/samples;
470 float sum_ksamples = 0.0;
471 struct sym_entry *syme, *n;
472 struct rb_root tmp = RB_ROOT;
473 struct rb_node *nd; 257 struct rb_node *nd;
474 int sym_width = 0, dso_width = 0, dso_short_width = 0; 258 struct sym_entry *syme;
259 struct rb_root tmp = RB_ROOT;
475 const int win_width = winsize.ws_col - 1; 260 const int win_width = winsize.ws_col - 1;
476 261 int sym_width, dso_width, dso_short_width;
477 samples = us_samples = kernel_samples = exact_samples = 0; 262 float sum_ksamples = perf_top__decay_samples(&top, &tmp);
478 guest_kernel_samples = guest_us_samples = 0;
479
480 /* Sort the active symbols */
481 pthread_mutex_lock(&active_symbols_lock);
482 syme = list_entry(active_symbols.next, struct sym_entry, node);
483 pthread_mutex_unlock(&active_symbols_lock);
484
485 list_for_each_entry_safe_from(syme, n, &active_symbols, node) {
486 syme->snap_count = syme->count[snap];
487 if (syme->snap_count != 0) {
488
489 if ((hide_user_symbols &&
490 syme->origin == PERF_RECORD_MISC_USER) ||
491 (hide_kernel_symbols &&
492 syme->origin == PERF_RECORD_MISC_KERNEL)) {
493 list_remove_active_sym(syme);
494 continue;
495 }
496 syme->weight = sym_weight(syme);
497 rb_insert_active_sym(&tmp, syme);
498 sum_ksamples += syme->snap_count;
499
500 for (j = 0; j < nr_counters; j++)
501 syme->count[j] = zero ? 0 : syme->count[j] * 7 / 8;
502 } else
503 list_remove_active_sym(syme);
504 }
505 263
506 puts(CONSOLE_CLEAR); 264 puts(CONSOLE_CLEAR);
507 265
508 printf("%-*.*s\n", win_width, win_width, graph_dotted_line); 266 perf_top__header_snprintf(&top, bf, sizeof(bf));
509 if (!perf_guest) { 267 printf("%s\n", bf);
510 printf(" PerfTop:%8.0f irqs/sec kernel:%4.1f%%"
511 " exact: %4.1f%% [",
512 samples_per_sec,
513 100.0 - (100.0 * ((samples_per_sec - ksamples_per_sec) /
514 samples_per_sec)),
515 esamples_percent);
516 } else {
517 printf(" PerfTop:%8.0f irqs/sec kernel:%4.1f%% us:%4.1f%%"
518 " guest kernel:%4.1f%% guest us:%4.1f%%"
519 " exact: %4.1f%% [",
520 samples_per_sec,
521 100.0 - (100.0 * ((samples_per_sec-ksamples_per_sec) /
522 samples_per_sec)),
523 100.0 - (100.0 * ((samples_per_sec-us_samples_per_sec) /
524 samples_per_sec)),
525 100.0 - (100.0 * ((samples_per_sec -
526 guest_kernel_samples_per_sec) /
527 samples_per_sec)),
528 100.0 - (100.0 * ((samples_per_sec -
529 guest_us_samples_per_sec) /
530 samples_per_sec)),
531 esamples_percent);
532 }
533
534 if (nr_counters == 1 || !display_weighted) {
535 printf("%Ld", (u64)attrs[0].sample_period);
536 if (freq)
537 printf("Hz ");
538 else
539 printf(" ");
540 }
541
542 if (!display_weighted)
543 printf("%s", event_name(sym_counter));
544 else for (counter = 0; counter < nr_counters; counter++) {
545 if (counter)
546 printf("/");
547
548 printf("%s", event_name(counter));
549 }
550 268
551 printf( "], "); 269 perf_top__reset_sample_counters(&top);
552
553 if (target_pid != -1)
554 printf(" (target_pid: %d", target_pid);
555 else if (target_tid != -1)
556 printf(" (target_tid: %d", target_tid);
557 else
558 printf(" (all");
559
560 if (cpu_list)
561 printf(", CPU%s: %s)\n", nr_cpus > 1 ? "s" : "", cpu_list);
562 else {
563 if (target_tid != -1)
564 printf(")\n");
565 else
566 printf(", %d CPU%s)\n", nr_cpus, nr_cpus > 1 ? "s" : "");
567 }
568 270
569 printf("%-*.*s\n", win_width, win_width, graph_dotted_line); 271 printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
570 272
571 if (sym_filter_entry) { 273 if (session->hists.stats.total_lost != 0) {
572 show_details(sym_filter_entry); 274 color_fprintf(stdout, PERF_COLOR_RED, "WARNING:");
573 return; 275 printf(" LOST %" PRIu64 " events, Check IO/CPU overload\n",
276 session->hists.stats.total_lost);
574 } 277 }
575 278
576 /* 279 if (top.sym_filter_entry) {
577 * Find the longest symbol name that will be displayed 280 show_details(top.sym_filter_entry);
578 */ 281 return;
579 for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
580 syme = rb_entry(nd, struct sym_entry, rb_node);
581 if (++printed > print_entries ||
582 (int)syme->snap_count < count_filter)
583 continue;
584
585 if (syme->map->dso->long_name_len > dso_width)
586 dso_width = syme->map->dso->long_name_len;
587
588 if (syme->map->dso->short_name_len > dso_short_width)
589 dso_short_width = syme->map->dso->short_name_len;
590
591 if (syme->name_len > sym_width)
592 sym_width = syme->name_len;
593 } 282 }
594 283
595 printed = 0; 284 perf_top__find_widths(&top, &tmp, &dso_width, &dso_short_width,
285 &sym_width);
596 286
597 if (sym_width + dso_width > winsize.ws_col - 29) { 287 if (sym_width + dso_width > winsize.ws_col - 29) {
598 dso_width = dso_short_width; 288 dso_width = dso_short_width;
@@ -600,7 +290,7 @@ static void print_sym_table(void)
600 sym_width = winsize.ws_col - dso_width - 29; 290 sym_width = winsize.ws_col - dso_width - 29;
601 } 291 }
602 putchar('\n'); 292 putchar('\n');
603 if (nr_counters == 1) 293 if (top.evlist->nr_entries == 1)
604 printf(" samples pcnt"); 294 printf(" samples pcnt");
605 else 295 else
606 printf(" weight samples pcnt"); 296 printf(" weight samples pcnt");
@@ -609,7 +299,7 @@ static void print_sym_table(void)
609 printf(" RIP "); 299 printf(" RIP ");
610 printf(" %-*.*s DSO\n", sym_width, sym_width, "function"); 300 printf(" %-*.*s DSO\n", sym_width, sym_width, "function");
611 printf(" %s _______ _____", 301 printf(" %s _______ _____",
612 nr_counters == 1 ? " " : "______"); 302 top.evlist->nr_entries == 1 ? " " : "______");
613 if (verbose) 303 if (verbose)
614 printf(" ________________"); 304 printf(" ________________");
615 printf(" %-*.*s", sym_width, sym_width, graph_line); 305 printf(" %-*.*s", sym_width, sym_width, graph_line);
@@ -622,20 +312,21 @@ static void print_sym_table(void)
622 312
623 syme = rb_entry(nd, struct sym_entry, rb_node); 313 syme = rb_entry(nd, struct sym_entry, rb_node);
624 sym = sym_entry__symbol(syme); 314 sym = sym_entry__symbol(syme);
625 if (++printed > print_entries || (int)syme->snap_count < count_filter) 315 if (++printed > top.print_entries ||
316 (int)syme->snap_count < top.count_filter)
626 continue; 317 continue;
627 318
628 pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) / 319 pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) /
629 sum_ksamples)); 320 sum_ksamples));
630 321
631 if (nr_counters == 1 || !display_weighted) 322 if (top.evlist->nr_entries == 1 || !top.display_weighted)
632 printf("%20.2f ", syme->weight); 323 printf("%20.2f ", syme->weight);
633 else 324 else
634 printf("%9.1f %10ld ", syme->weight, syme->snap_count); 325 printf("%9.1f %10ld ", syme->weight, syme->snap_count);
635 326
636 percent_color_fprintf(stdout, "%4.1f%%", pcnt); 327 percent_color_fprintf(stdout, "%4.1f%%", pcnt);
637 if (verbose) 328 if (verbose)
638 printf(" %016llx", sym->start); 329 printf(" %016" PRIx64, sym->start);
639 printf(" %-*.*s", sym_width, sym_width, sym->name); 330 printf(" %-*.*s", sym_width, sym_width, sym->name);
640 printf(" %-*.*s\n", dso_width, dso_width, 331 printf(" %-*.*s\n", dso_width, dso_width,
641 dso_width >= syme->map->dso->long_name_len ? 332 dso_width >= syme->map->dso->long_name_len ?
@@ -687,10 +378,8 @@ static void prompt_symbol(struct sym_entry **target, const char *msg)
687 378
688 /* zero counters of active symbol */ 379 /* zero counters of active symbol */
689 if (syme) { 380 if (syme) {
690 pthread_mutex_lock(&syme->src->lock);
691 __zero_source_counters(syme); 381 __zero_source_counters(syme);
692 *target = NULL; 382 *target = NULL;
693 pthread_mutex_unlock(&syme->src->lock);
694 } 383 }
695 384
696 fprintf(stdout, "\n%s: ", msg); 385 fprintf(stdout, "\n%s: ", msg);
@@ -701,11 +390,11 @@ static void prompt_symbol(struct sym_entry **target, const char *msg)
701 if (p) 390 if (p)
702 *p = 0; 391 *p = 0;
703 392
704 pthread_mutex_lock(&active_symbols_lock); 393 pthread_mutex_lock(&top.active_symbols_lock);
705 syme = list_entry(active_symbols.next, struct sym_entry, node); 394 syme = list_entry(top.active_symbols.next, struct sym_entry, node);
706 pthread_mutex_unlock(&active_symbols_lock); 395 pthread_mutex_unlock(&top.active_symbols_lock);
707 396
708 list_for_each_entry_safe_from(syme, n, &active_symbols, node) { 397 list_for_each_entry_safe_from(syme, n, &top.active_symbols, node) {
709 struct symbol *sym = sym_entry__symbol(syme); 398 struct symbol *sym = sym_entry__symbol(syme);
710 399
711 if (!strcmp(buf, sym->name)) { 400 if (!strcmp(buf, sym->name)) {
@@ -729,34 +418,34 @@ static void print_mapped_keys(void)
729{ 418{
730 char *name = NULL; 419 char *name = NULL;
731 420
732 if (sym_filter_entry) { 421 if (top.sym_filter_entry) {
733 struct symbol *sym = sym_entry__symbol(sym_filter_entry); 422 struct symbol *sym = sym_entry__symbol(top.sym_filter_entry);
734 name = sym->name; 423 name = sym->name;
735 } 424 }
736 425
737 fprintf(stdout, "\nMapped keys:\n"); 426 fprintf(stdout, "\nMapped keys:\n");
738 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);
739 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);
740 429
741 if (nr_counters > 1) 430 if (top.evlist->nr_entries > 1)
742 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));
743 432
744 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);
745 434
746 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);
747 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); 436 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL");
748 fprintf(stdout, "\t[S] stop annotation.\n"); 437 fprintf(stdout, "\t[S] stop annotation.\n");
749 438
750 if (nr_counters > 1) 439 if (top.evlist->nr_entries > 1)
751 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);
752 441
753 fprintf(stdout, 442 fprintf(stdout,
754 "\t[K] hide kernel_symbols symbols. \t(%s)\n", 443 "\t[K] hide kernel_symbols symbols. \t(%s)\n",
755 hide_kernel_symbols ? "yes" : "no"); 444 top.hide_kernel_symbols ? "yes" : "no");
756 fprintf(stdout, 445 fprintf(stdout,
757 "\t[U] hide user symbols. \t(%s)\n", 446 "\t[U] hide user symbols. \t(%s)\n",
758 hide_user_symbols ? "yes" : "no"); 447 top.hide_user_symbols ? "yes" : "no");
759 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);
760 fprintf(stdout, "\t[qQ] quit.\n"); 449 fprintf(stdout, "\t[qQ] quit.\n");
761} 450}
762 451
@@ -777,7 +466,7 @@ static int key_mapped(int c)
777 return 1; 466 return 1;
778 case 'E': 467 case 'E':
779 case 'w': 468 case 'w':
780 return nr_counters > 1 ? 1 : 0; 469 return top.evlist->nr_entries > 1 ? 1 : 0;
781 default: 470 default:
782 break; 471 break;
783 } 472 }
@@ -812,43 +501,50 @@ static void handle_keypress(struct perf_session *session, int c)
812 501
813 switch (c) { 502 switch (c) {
814 case 'd': 503 case 'd':
815 prompt_integer(&delay_secs, "Enter display delay"); 504 prompt_integer(&top.delay_secs, "Enter display delay");
816 if (delay_secs < 1) 505 if (top.delay_secs < 1)
817 delay_secs = 1; 506 top.delay_secs = 1;
818 break; 507 break;
819 case 'e': 508 case 'e':
820 prompt_integer(&print_entries, "Enter display entries (lines)"); 509 prompt_integer(&top.print_entries, "Enter display entries (lines)");
821 if (print_entries == 0) { 510 if (top.print_entries == 0) {
822 sig_winch_handler(SIGWINCH); 511 sig_winch_handler(SIGWINCH);
823 signal(SIGWINCH, sig_winch_handler); 512 signal(SIGWINCH, sig_winch_handler);
824 } else 513 } else
825 signal(SIGWINCH, SIG_DFL); 514 signal(SIGWINCH, SIG_DFL);
826 break; 515 break;
827 case 'E': 516 case 'E':
828 if (nr_counters > 1) { 517 if (top.evlist->nr_entries > 1) {
829 int i; 518 /* Select 0 as the default event: */
519 int counter = 0;
830 520
831 fprintf(stderr, "\nAvailable events:"); 521 fprintf(stderr, "\nAvailable events:");
832 for (i = 0; i < nr_counters; i++)
833 fprintf(stderr, "\n\t%d %s", i, event_name(i));
834 522
835 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");
836 527
837 if (sym_counter >= nr_counters) { 528 if (counter >= top.evlist->nr_entries) {
838 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);
839 sym_counter = 0; 530 fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(top.sym_evsel));
840 sleep(1); 531 sleep(1);
532 break;
841 } 533 }
842 } 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);
843 break; 539 break;
844 case 'f': 540 case 'f':
845 prompt_integer(&count_filter, "Enter display event count filter"); 541 prompt_integer(&top.count_filter, "Enter display event count filter");
846 break; 542 break;
847 case 'F': 543 case 'F':
848 prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)"); 544 prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)");
849 break; 545 break;
850 case 'K': 546 case 'K':
851 hide_kernel_symbols = !hide_kernel_symbols; 547 top.hide_kernel_symbols = !top.hide_kernel_symbols;
852 break; 548 break;
853 case 'q': 549 case 'q':
854 case 'Q': 550 case 'Q':
@@ -857,34 +553,50 @@ static void handle_keypress(struct perf_session *session, int c)
857 perf_session__fprintf_dsos(session, stderr); 553 perf_session__fprintf_dsos(session, stderr);
858 exit(0); 554 exit(0);
859 case 's': 555 case 's':
860 prompt_symbol(&sym_filter_entry, "Enter details symbol"); 556 prompt_symbol(&top.sym_filter_entry, "Enter details symbol");
861 break; 557 break;
862 case 'S': 558 case 'S':
863 if (!sym_filter_entry) 559 if (!top.sym_filter_entry)
864 break; 560 break;
865 else { 561 else {
866 struct sym_entry *syme = sym_filter_entry; 562 struct sym_entry *syme = top.sym_filter_entry;
867 563
868 pthread_mutex_lock(&syme->src->lock); 564 top.sym_filter_entry = NULL;
869 sym_filter_entry = NULL;
870 __zero_source_counters(syme); 565 __zero_source_counters(syme);
871 pthread_mutex_unlock(&syme->src->lock);
872 } 566 }
873 break; 567 break;
874 case 'U': 568 case 'U':
875 hide_user_symbols = !hide_user_symbols; 569 top.hide_user_symbols = !top.hide_user_symbols;
876 break; 570 break;
877 case 'w': 571 case 'w':
878 display_weighted = ~display_weighted; 572 top.display_weighted = ~top.display_weighted;
879 break; 573 break;
880 case 'z': 574 case 'z':
881 zero = !zero; 575 top.zero = !top.zero;
882 break; 576 break;
883 default: 577 default:
884 break; 578 break;
885 } 579 }
886} 580}
887 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
888static void *display_thread(void *arg __used) 600static void *display_thread(void *arg __used)
889{ 601{
890 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; 602 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
@@ -899,13 +611,13 @@ static void *display_thread(void *arg __used)
899 tc.c_cc[VTIME] = 0; 611 tc.c_cc[VTIME] = 0;
900 612
901repeat: 613repeat:
902 delay_msecs = delay_secs * 1000; 614 delay_msecs = top.delay_secs * 1000;
903 tcsetattr(0, TCSANOW, &tc); 615 tcsetattr(0, TCSANOW, &tc);
904 /* trash return*/ 616 /* trash return*/
905 getc(stdin); 617 getc(stdin);
906 618
907 do { 619 do {
908 print_sym_table(); 620 print_sym_table(session);
909 } while (!poll(&stdin_poll, 1, delay_msecs) == 1); 621 } while (!poll(&stdin_poll, 1, delay_msecs) == 1);
910 622
911 c = getc(stdin); 623 c = getc(stdin);
@@ -920,6 +632,7 @@ repeat:
920/* Tag samples to be skipped. */ 632/* Tag samples to be skipped. */
921static const char *skip_symbols[] = { 633static const char *skip_symbols[] = {
922 "default_idle", 634 "default_idle",
635 "native_safe_halt",
923 "cpu_idle", 636 "cpu_idle",
924 "enter_idle", 637 "enter_idle",
925 "exit_idle", 638 "exit_idle",
@@ -955,9 +668,9 @@ static int symbol_filter(struct map *map, struct symbol *sym)
955 668
956 syme = symbol__priv(sym); 669 syme = symbol__priv(sym);
957 syme->map = map; 670 syme->map = map;
958 syme->src = NULL; 671 symbol__annotate_init(map, sym);
959 672
960 if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) { 673 if (!top.sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) {
961 /* schedule initial sym_filter_entry setup */ 674 /* schedule initial sym_filter_entry setup */
962 sym_filter_entry_sched = syme; 675 sym_filter_entry_sched = syme;
963 sym_filter = NULL; 676 sym_filter = NULL;
@@ -965,48 +678,45 @@ static int symbol_filter(struct map *map, struct symbol *sym)
965 678
966 for (i = 0; skip_symbols[i]; i++) { 679 for (i = 0; skip_symbols[i]; i++) {
967 if (!strcmp(skip_symbols[i], name)) { 680 if (!strcmp(skip_symbols[i], name)) {
968 syme->skip = 1; 681 sym->ignore = true;
969 break; 682 break;
970 } 683 }
971 } 684 }
972 685
973 if (!syme->skip)
974 syme->name_len = strlen(sym->name);
975
976 return 0; 686 return 0;
977} 687}
978 688
979static void event__process_sample(const event_t *self, 689static void perf_event__process_sample(const union perf_event *event,
980 struct perf_session *session, int counter) 690 struct perf_sample *sample,
691 struct perf_session *session)
981{ 692{
982 u64 ip = self->ip.ip; 693 u64 ip = event->ip.ip;
983 struct sym_entry *syme; 694 struct sym_entry *syme;
984 struct addr_location al; 695 struct addr_location al;
985 struct sample_data data;
986 struct machine *machine; 696 struct machine *machine;
987 u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 697 u8 origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
988 698
989 ++samples; 699 ++top.samples;
990 700
991 switch (origin) { 701 switch (origin) {
992 case PERF_RECORD_MISC_USER: 702 case PERF_RECORD_MISC_USER:
993 ++us_samples; 703 ++top.us_samples;
994 if (hide_user_symbols) 704 if (top.hide_user_symbols)
995 return; 705 return;
996 machine = perf_session__find_host_machine(session); 706 machine = perf_session__find_host_machine(session);
997 break; 707 break;
998 case PERF_RECORD_MISC_KERNEL: 708 case PERF_RECORD_MISC_KERNEL:
999 ++kernel_samples; 709 ++top.kernel_samples;
1000 if (hide_kernel_symbols) 710 if (top.hide_kernel_symbols)
1001 return; 711 return;
1002 machine = perf_session__find_host_machine(session); 712 machine = perf_session__find_host_machine(session);
1003 break; 713 break;
1004 case PERF_RECORD_MISC_GUEST_KERNEL: 714 case PERF_RECORD_MISC_GUEST_KERNEL:
1005 ++guest_kernel_samples; 715 ++top.guest_kernel_samples;
1006 machine = perf_session__find_machine(session, self->ip.pid); 716 machine = perf_session__find_machine(session, event->ip.pid);
1007 break; 717 break;
1008 case PERF_RECORD_MISC_GUEST_USER: 718 case PERF_RECORD_MISC_GUEST_USER:
1009 ++guest_us_samples; 719 ++top.guest_us_samples;
1010 /* 720 /*
1011 * TODO: we don't process guest user from host side 721 * TODO: we don't process guest user from host side
1012 * except simple counting. 722 * except simple counting.
@@ -1018,15 +728,15 @@ static void event__process_sample(const event_t *self,
1018 728
1019 if (!machine && perf_guest) { 729 if (!machine && perf_guest) {
1020 pr_err("Can't find guest [%d]'s kernel information\n", 730 pr_err("Can't find guest [%d]'s kernel information\n",
1021 self->ip.pid); 731 event->ip.pid);
1022 return; 732 return;
1023 } 733 }
1024 734
1025 if (self->header.misc & PERF_RECORD_MISC_EXACT_IP) 735 if (event->header.misc & PERF_RECORD_MISC_EXACT_IP)
1026 exact_samples++; 736 top.exact_samples++;
1027 737
1028 if (event__preprocess_sample(self, session, &al, &data, 738 if (perf_event__preprocess_sample(event, session, &al, sample,
1029 symbol_filter) < 0 || 739 symbol_filter) < 0 ||
1030 al.filtered) 740 al.filtered)
1031 return; 741 return;
1032 742
@@ -1044,8 +754,9 @@ static void event__process_sample(const event_t *self,
1044 */ 754 */
1045 if (al.map == machine->vmlinux_maps[MAP__FUNCTION] && 755 if (al.map == machine->vmlinux_maps[MAP__FUNCTION] &&
1046 RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) { 756 RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) {
1047 pr_err("The %s file can't be used\n", 757 ui__warning("The %s file can't be used\n",
1048 symbol_conf.vmlinux_name); 758 symbol_conf.vmlinux_name);
759 exit_browser(0);
1049 exit(1); 760 exit(1);
1050 } 761 }
1051 762
@@ -1054,13 +765,13 @@ static void event__process_sample(const event_t *self,
1054 765
1055 /* let's see, whether we need to install initial sym_filter_entry */ 766 /* let's see, whether we need to install initial sym_filter_entry */
1056 if (sym_filter_entry_sched) { 767 if (sym_filter_entry_sched) {
1057 sym_filter_entry = sym_filter_entry_sched; 768 top.sym_filter_entry = sym_filter_entry_sched;
1058 sym_filter_entry_sched = NULL; 769 sym_filter_entry_sched = NULL;
1059 if (parse_source(sym_filter_entry) < 0) { 770 if (parse_source(top.sym_filter_entry) < 0) {
1060 struct symbol *sym = sym_entry__symbol(sym_filter_entry); 771 struct symbol *sym = sym_entry__symbol(top.sym_filter_entry);
1061 772
1062 pr_err("Can't annotate %s", sym->name); 773 pr_err("Can't annotate %s", sym->name);
1063 if (sym_filter_entry->map->dso->origin == DSO__ORIG_KERNEL) { 774 if (top.sym_filter_entry->map->dso->symtab_type == SYMTAB__KALLSYMS) {
1064 pr_err(": No vmlinux file was found in the path:\n"); 775 pr_err(": No vmlinux file was found in the path:\n");
1065 machine__fprintf_vmlinux_path(machine, stderr); 776 machine__fprintf_vmlinux_path(machine, stderr);
1066 } else 777 } else
@@ -1070,225 +781,153 @@ static void event__process_sample(const event_t *self,
1070 } 781 }
1071 782
1072 syme = symbol__priv(al.sym); 783 syme = symbol__priv(al.sym);
1073 if (!syme->skip) { 784 if (!al.sym->ignore) {
1074 syme->count[counter]++; 785 struct perf_evsel *evsel;
1075 syme->origin = origin; 786
1076 record_precise_ip(syme, counter, ip); 787 evsel = perf_evlist__id2evsel(top.evlist, sample->id);
1077 pthread_mutex_lock(&active_symbols_lock); 788 assert(evsel != NULL);
1078 if (list_empty(&syme->node) || !syme->node.next) 789 syme->count[evsel->idx]++;
790 record_precise_ip(syme, evsel->idx, ip);
791 pthread_mutex_lock(&top.active_symbols_lock);
792 if (list_empty(&syme->node) || !syme->node.next) {
793 static bool first = true;
1079 __list_insert_active_sym(syme); 794 __list_insert_active_sym(syme);
1080 pthread_mutex_unlock(&active_symbols_lock); 795 if (first) {
796 pthread_cond_broadcast(&top.active_symbols_cond);
797 first = false;
798 }
799 }
800 pthread_mutex_unlock(&top.active_symbols_lock);
1081 } 801 }
1082} 802}
1083 803
1084struct mmap_data { 804static void perf_session__mmap_read_cpu(struct perf_session *self, int cpu)
1085 int counter;
1086 void *base;
1087 int mask;
1088 unsigned int prev;
1089};
1090
1091static unsigned int mmap_read_head(struct mmap_data *md)
1092{ 805{
1093 struct perf_event_mmap_page *pc = md->base; 806 struct perf_sample sample;
1094 int head; 807 union perf_event *event;
1095
1096 head = pc->data_head;
1097 rmb();
1098
1099 return head;
1100}
1101
1102static void perf_session__mmap_read_counter(struct perf_session *self,
1103 struct mmap_data *md)
1104{
1105 unsigned int head = mmap_read_head(md);
1106 unsigned int old = md->prev;
1107 unsigned char *data = md->base + page_size;
1108 int diff;
1109
1110 /*
1111 * If we're further behind than half the buffer, there's a chance
1112 * the writer will bite our tail and mess up the samples under us.
1113 *
1114 * If we somehow ended up ahead of the head, we got messed up.
1115 *
1116 * In either case, truncate and restart at head.
1117 */
1118 diff = head - old;
1119 if (diff > md->mask / 2 || diff < 0) {
1120 fprintf(stderr, "WARNING: failed to keep up with mmap data.\n");
1121
1122 /*
1123 * head points to a known good entry, start there.
1124 */
1125 old = head;
1126 }
1127
1128 for (; old != head;) {
1129 event_t *event = (event_t *)&data[old & md->mask];
1130
1131 event_t event_copy;
1132
1133 size_t size = event->header.size;
1134 808
1135 /* 809 while ((event = perf_evlist__read_on_cpu(top.evlist, cpu)) != NULL) {
1136 * Event straddles the mmap boundary -- header should always 810 perf_session__parse_sample(self, event, &sample);
1137 * be inside due to u64 alignment of output.
1138 */
1139 if ((old & md->mask) + size != ((old + size) & md->mask)) {
1140 unsigned int offset = old;
1141 unsigned int len = min(sizeof(*event), size), cpy;
1142 void *dst = &event_copy;
1143
1144 do {
1145 cpy = min(md->mask + 1 - (offset & md->mask), len);
1146 memcpy(dst, &data[offset & md->mask], cpy);
1147 offset += cpy;
1148 dst += cpy;
1149 len -= cpy;
1150 } while (len);
1151
1152 event = &event_copy;
1153 }
1154 811
1155 if (event->header.type == PERF_RECORD_SAMPLE) 812 if (event->header.type == PERF_RECORD_SAMPLE)
1156 event__process_sample(event, self, md->counter); 813 perf_event__process_sample(event, &sample, self);
1157 else 814 else
1158 event__process(event, self); 815 perf_event__process(event, &sample, self);
1159 old += size;
1160 } 816 }
1161
1162 md->prev = old;
1163} 817}
1164 818
1165static struct pollfd *event_array;
1166static struct mmap_data *mmap_array[MAX_NR_CPUS][MAX_COUNTERS];
1167
1168static void perf_session__mmap_read(struct perf_session *self) 819static void perf_session__mmap_read(struct perf_session *self)
1169{ 820{
1170 int i, counter, thread_index; 821 int i;
1171
1172 for (i = 0; i < nr_cpus; i++) {
1173 for (counter = 0; counter < nr_counters; counter++)
1174 for (thread_index = 0;
1175 thread_index < thread_num;
1176 thread_index++) {
1177 perf_session__mmap_read_counter(self,
1178 &mmap_array[i][counter][thread_index]);
1179 }
1180 }
1181}
1182 822
1183int nr_poll; 823 for (i = 0; i < top.evlist->cpus->nr; i++)
1184int group_fd; 824 perf_session__mmap_read_cpu(self, i);
825}
1185 826
1186static void start_counter(int i, int counter) 827static void start_counters(struct perf_evlist *evlist)
1187{ 828{
1188 struct perf_event_attr *attr; 829 struct perf_evsel *counter;
1189 int cpu = -1;
1190 int thread_index;
1191
1192 if (target_tid == -1)
1193 cpu = cpumap[i];
1194 830
1195 attr = attrs + counter; 831 list_for_each_entry(counter, &evlist->entries, node) {
832 struct perf_event_attr *attr = &counter->attr;
1196 833
1197 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; 834 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
1198 835
1199 if (freq) { 836 if (top.freq) {
1200 attr->sample_type |= PERF_SAMPLE_PERIOD; 837 attr->sample_type |= PERF_SAMPLE_PERIOD;
1201 attr->freq = 1; 838 attr->freq = 1;
1202 attr->sample_freq = freq; 839 attr->sample_freq = top.freq;
1203 } 840 }
1204 841
1205 attr->inherit = (cpu < 0) && inherit; 842 if (evlist->nr_entries > 1) {
1206 attr->mmap = 1; 843 attr->sample_type |= PERF_SAMPLE_ID;
844 attr->read_format |= PERF_FORMAT_ID;
845 }
1207 846
1208 for (thread_index = 0; thread_index < thread_num; thread_index++) { 847 attr->mmap = 1;
848 attr->inherit = inherit;
1209try_again: 849try_again:
1210 fd[i][counter][thread_index] = sys_perf_event_open(attr, 850 if (perf_evsel__open(counter, top.evlist->cpus,
1211 all_tids[thread_index], cpu, group_fd, 0); 851 top.evlist->threads, group) < 0) {
1212
1213 if (fd[i][counter][thread_index] < 0) {
1214 int err = errno; 852 int err = errno;
1215 853
1216 if (err == EPERM || err == EACCES) 854 if (err == EPERM || err == EACCES) {
1217 die("No permission - are you root?\n"); 855 ui__warning_paranoid();
856 goto out_err;
857 }
1218 /* 858 /*
1219 * If it's cycles then fall back to hrtimer 859 * If it's cycles then fall back to hrtimer
1220 * based cpu-clock-tick sw counter, which 860 * based cpu-clock-tick sw counter, which
1221 * is always available even if no PMU support: 861 * is always available even if no PMU support:
1222 */ 862 */
1223 if (attr->type == PERF_TYPE_HARDWARE 863 if (attr->type == PERF_TYPE_HARDWARE &&
1224 && attr->config == PERF_COUNT_HW_CPU_CYCLES) { 864 attr->config == PERF_COUNT_HW_CPU_CYCLES) {
1225
1226 if (verbose) 865 if (verbose)
1227 warning(" ... trying to fall back to cpu-clock-ticks\n"); 866 ui__warning("Cycles event not supported,\n"
867 "trying to fall back to cpu-clock-ticks\n");
1228 868
1229 attr->type = PERF_TYPE_SOFTWARE; 869 attr->type = PERF_TYPE_SOFTWARE;
1230 attr->config = PERF_COUNT_SW_CPU_CLOCK; 870 attr->config = PERF_COUNT_SW_CPU_CLOCK;
1231 goto try_again; 871 goto try_again;
1232 } 872 }
1233 printf("\n"); 873
1234 error("perfcounter syscall returned with %d (%s)\n", 874 if (err == ENOENT) {
1235 fd[i][counter][thread_index], strerror(err)); 875 ui__warning("The %s event is not supported.\n",
1236 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); 876 event_name(counter));
1237 exit(-1); 877 goto out_err;
878 }
879
880 ui__warning("The sys_perf_event_open() syscall "
881 "returned with %d (%s). /bin/dmesg "
882 "may provide additional information.\n"
883 "No CONFIG_PERF_EVENTS=y kernel support "
884 "configured?\n", err, strerror(err));
885 goto out_err;
1238 } 886 }
1239 assert(fd[i][counter][thread_index] >= 0); 887 }
1240 fcntl(fd[i][counter][thread_index], F_SETFL, O_NONBLOCK);
1241 888
1242 /* 889 if (perf_evlist__mmap(evlist, mmap_pages, false) < 0) {
1243 * First counter acts as the group leader: 890 ui__warning("Failed to mmap with %d (%s)\n",
1244 */ 891 errno, strerror(errno));
1245 if (group && group_fd == -1) 892 goto out_err;
1246 group_fd = fd[i][counter][thread_index];
1247
1248 event_array[nr_poll].fd = fd[i][counter][thread_index];
1249 event_array[nr_poll].events = POLLIN;
1250 nr_poll++;
1251
1252 mmap_array[i][counter][thread_index].counter = counter;
1253 mmap_array[i][counter][thread_index].prev = 0;
1254 mmap_array[i][counter][thread_index].mask = mmap_pages*page_size - 1;
1255 mmap_array[i][counter][thread_index].base = mmap(NULL, (mmap_pages+1)*page_size,
1256 PROT_READ, MAP_SHARED, fd[i][counter][thread_index], 0);
1257 if (mmap_array[i][counter][thread_index].base == MAP_FAILED)
1258 die("failed to mmap with %d (%s)\n", errno, strerror(errno));
1259 } 893 }
894
895 return;
896
897out_err:
898 exit_browser(0);
899 exit(0);
1260} 900}
1261 901
1262static int __cmd_top(void) 902static int __cmd_top(void)
1263{ 903{
1264 pthread_t thread; 904 pthread_t thread;
1265 int i, counter; 905 int ret __used;
1266 int ret;
1267 /* 906 /*
1268 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this 907 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this
1269 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now. 908 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now.
1270 */ 909 */
1271 struct perf_session *session = perf_session__new(NULL, O_WRONLY, false, false); 910 struct perf_session *session = perf_session__new(NULL, O_WRONLY, false, false, NULL);
1272 if (session == NULL) 911 if (session == NULL)
1273 return -ENOMEM; 912 return -ENOMEM;
1274 913
1275 if (target_tid != -1) 914 if (top.target_tid != -1)
1276 event__synthesize_thread(target_tid, event__process, session); 915 perf_event__synthesize_thread_map(top.evlist->threads,
916 perf_event__process, session);
1277 else 917 else
1278 event__synthesize_threads(event__process, session); 918 perf_event__synthesize_threads(perf_event__process, session);
1279 919
1280 for (i = 0; i < nr_cpus; i++) { 920 start_counters(top.evlist);
1281 group_fd = -1; 921 session->evlist = top.evlist;
1282 for (counter = 0; counter < nr_counters; counter++) 922 perf_session__update_sample_type(session);
1283 start_counter(i, counter);
1284 }
1285 923
1286 /* Wait for a minimal set of events before starting the snapshot */ 924 /* Wait for a minimal set of events before starting the snapshot */
1287 poll(&event_array[0], nr_poll, 100); 925 poll(top.evlist->pollfd, top.evlist->nr_fds, 100);
1288 926
1289 perf_session__mmap_read(session); 927 perf_session__mmap_read(session);
1290 928
1291 if (pthread_create(&thread, NULL, display_thread, session)) { 929 if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui :
930 display_thread), session)) {
1292 printf("Could not create display thread.\n"); 931 printf("Could not create display thread.\n");
1293 exit(-1); 932 exit(-1);
1294 } 933 }
@@ -1304,12 +943,12 @@ static int __cmd_top(void)
1304 } 943 }
1305 944
1306 while (1) { 945 while (1) {
1307 int hits = samples; 946 u64 hits = top.samples;
1308 947
1309 perf_session__mmap_read(session); 948 perf_session__mmap_read(session);
1310 949
1311 if (hits == samples) 950 if (hits == top.samples)
1312 ret = poll(event_array, nr_poll, 100); 951 ret = poll(top.evlist->pollfd, top.evlist->nr_fds, 100);
1313 } 952 }
1314 953
1315 return 0; 954 return 0;
@@ -1321,31 +960,31 @@ static const char * const top_usage[] = {
1321}; 960};
1322 961
1323static const struct option options[] = { 962static const struct option options[] = {
1324 OPT_CALLBACK('e', "event", NULL, "event", 963 OPT_CALLBACK('e', "event", &top.evlist, "event",
1325 "event selector. use 'perf list' to list available events", 964 "event selector. use 'perf list' to list available events",
1326 parse_events), 965 parse_events),
1327 OPT_INTEGER('c', "count", &default_interval, 966 OPT_INTEGER('c', "count", &default_interval,
1328 "event period to sample"), 967 "event period to sample"),
1329 OPT_INTEGER('p', "pid", &target_pid, 968 OPT_INTEGER('p', "pid", &top.target_pid,
1330 "profile events on existing process id"), 969 "profile events on existing process id"),
1331 OPT_INTEGER('t', "tid", &target_tid, 970 OPT_INTEGER('t', "tid", &top.target_tid,
1332 "profile events on existing thread id"), 971 "profile events on existing thread id"),
1333 OPT_BOOLEAN('a', "all-cpus", &system_wide, 972 OPT_BOOLEAN('a', "all-cpus", &system_wide,
1334 "system-wide collection from all CPUs"), 973 "system-wide collection from all CPUs"),
1335 OPT_STRING('C', "cpu", &cpu_list, "cpu", 974 OPT_STRING('C', "cpu", &top.cpu_list, "cpu",
1336 "list of cpus to monitor"), 975 "list of cpus to monitor"),
1337 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 976 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
1338 "file", "vmlinux pathname"), 977 "file", "vmlinux pathname"),
1339 OPT_BOOLEAN('K', "hide_kernel_symbols", &hide_kernel_symbols, 978 OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols,
1340 "hide kernel symbols"), 979 "hide kernel symbols"),
1341 OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"), 980 OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"),
1342 OPT_INTEGER('r', "realtime", &realtime_prio, 981 OPT_INTEGER('r', "realtime", &realtime_prio,
1343 "collect data with this RT SCHED_FIFO priority"), 982 "collect data with this RT SCHED_FIFO priority"),
1344 OPT_INTEGER('d', "delay", &delay_secs, 983 OPT_INTEGER('d', "delay", &top.delay_secs,
1345 "number of seconds to delay between refreshes"), 984 "number of seconds to delay between refreshes"),
1346 OPT_BOOLEAN('D', "dump-symtab", &dump_symtab, 985 OPT_BOOLEAN('D', "dump-symtab", &dump_symtab,
1347 "dump the symbol table used for profiling"), 986 "dump the symbol table used for profiling"),
1348 OPT_INTEGER('f', "count-filter", &count_filter, 987 OPT_INTEGER('f', "count-filter", &top.count_filter,
1349 "only display functions with more events than this"), 988 "only display functions with more events than this"),
1350 OPT_BOOLEAN('g', "group", &group, 989 OPT_BOOLEAN('g', "group", &group,
1351 "put the counters into a counter group"), 990 "put the counters into a counter group"),
@@ -1353,14 +992,16 @@ static const struct option options[] = {
1353 "child tasks inherit counters"), 992 "child tasks inherit counters"),
1354 OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name", 993 OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name",
1355 "symbol to annotate"), 994 "symbol to annotate"),
1356 OPT_BOOLEAN('z', "zero", &zero, 995 OPT_BOOLEAN('z', "zero", &top.zero,
1357 "zero history across updates"), 996 "zero history across updates"),
1358 OPT_INTEGER('F', "freq", &freq, 997 OPT_INTEGER('F', "freq", &top.freq,
1359 "profile at this frequency"), 998 "profile at this frequency"),
1360 OPT_INTEGER('E', "entries", &print_entries, 999 OPT_INTEGER('E', "entries", &top.print_entries,
1361 "display this many functions"), 1000 "display this many functions"),
1362 OPT_BOOLEAN('U', "hide_user_symbols", &hide_user_symbols, 1001 OPT_BOOLEAN('U', "hide_user_symbols", &top.hide_user_symbols,
1363 "hide user symbols"), 1002 "hide user symbols"),
1003 OPT_BOOLEAN(0, "tui", &use_tui, "Use the TUI interface"),
1004 OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"),
1364 OPT_INCR('v', "verbose", &verbose, 1005 OPT_INCR('v', "verbose", &verbose,
1365 "be more verbose (show counter open errors, etc)"), 1006 "be more verbose (show counter open errors, etc)"),
1366 OPT_END() 1007 OPT_END()
@@ -1368,8 +1009,12 @@ static const struct option options[] = {
1368 1009
1369int cmd_top(int argc, const char **argv, const char *prefix __used) 1010int cmd_top(int argc, const char **argv, const char *prefix __used)
1370{ 1011{
1371 int counter; 1012 struct perf_evsel *pos;
1372 int i,j; 1013 int status = -ENOMEM;
1014
1015 top.evlist = perf_evlist__new(NULL, NULL);
1016 if (top.evlist == NULL)
1017 return -ENOMEM;
1373 1018
1374 page_size = sysconf(_SC_PAGE_SIZE); 1019 page_size = sysconf(_SC_PAGE_SIZE);
1375 1020
@@ -1377,92 +1022,90 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1377 if (argc) 1022 if (argc)
1378 usage_with_options(top_usage, options); 1023 usage_with_options(top_usage, options);
1379 1024
1380 if (target_pid != -1) { 1025 /*
1381 target_tid = target_pid; 1026 * XXX For now start disabled, only using TUI if explicitely asked for.
1382 thread_num = find_all_tid(target_pid, &all_tids); 1027 * Change that when handle_keys equivalent gets written, live annotation
1383 if (thread_num <= 0) { 1028 * done, etc.
1384 fprintf(stderr, "Can't find all threads of pid %d\n", 1029 */
1385 target_pid); 1030 use_browser = 0;
1386 usage_with_options(top_usage, options);
1387 }
1388 } else {
1389 all_tids=malloc(sizeof(pid_t));
1390 if (!all_tids)
1391 return -ENOMEM;
1392 1031
1393 all_tids[0] = target_tid; 1032 if (use_stdio)
1394 thread_num = 1; 1033 use_browser = 0;
1395 } 1034 else if (use_tui)
1035 use_browser = 1;
1396 1036
1397 for (i = 0; i < MAX_NR_CPUS; i++) { 1037 setup_browser(false);
1398 for (j = 0; j < MAX_COUNTERS; j++) {
1399 fd[i][j] = malloc(sizeof(int)*thread_num);
1400 mmap_array[i][j] = zalloc(
1401 sizeof(struct mmap_data)*thread_num);
1402 if (!fd[i][j] || !mmap_array[i][j])
1403 return -ENOMEM;
1404 }
1405 }
1406 event_array = malloc(
1407 sizeof(struct pollfd)*MAX_NR_CPUS*MAX_COUNTERS*thread_num);
1408 if (!event_array)
1409 return -ENOMEM;
1410 1038
1411 /* CPU and PID are mutually exclusive */ 1039 /* CPU and PID are mutually exclusive */
1412 if (target_tid > 0 && cpu_list) { 1040 if (top.target_tid > 0 && top.cpu_list) {
1413 printf("WARNING: PID switch overriding CPU\n"); 1041 printf("WARNING: PID switch overriding CPU\n");
1414 sleep(1); 1042 sleep(1);
1415 cpu_list = NULL; 1043 top.cpu_list = NULL;
1416 } 1044 }
1417 1045
1418 if (!nr_counters) 1046 if (top.target_pid != -1)
1419 nr_counters = 1; 1047 top.target_tid = top.target_pid;
1420 1048
1421 symbol_conf.priv_size = (sizeof(struct sym_entry) + 1049 if (perf_evlist__create_maps(top.evlist, top.target_pid,
1422 (nr_counters + 1) * sizeof(unsigned long)); 1050 top.target_tid, top.cpu_list) < 0)
1051 usage_with_options(top_usage, options);
1423 1052
1424 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); 1053 if (!top.evlist->nr_entries &&
1425 if (symbol__init() < 0) 1054 perf_evlist__add_default(top.evlist) < 0) {
1426 return -1; 1055 pr_err("Not enough memory for event selector list\n");
1056 return -ENOMEM;
1057 }
1427 1058
1428 if (delay_secs < 1) 1059 if (top.delay_secs < 1)
1429 delay_secs = 1; 1060 top.delay_secs = 1;
1430 1061
1431 /* 1062 /*
1432 * User specified count overrides default frequency. 1063 * User specified count overrides default frequency.
1433 */ 1064 */
1434 if (default_interval) 1065 if (default_interval)
1435 freq = 0; 1066 top.freq = 0;
1436 else if (freq) { 1067 else if (top.freq) {
1437 default_interval = freq; 1068 default_interval = top.freq;
1438 } else { 1069 } else {
1439 fprintf(stderr, "frequency and count are zero, aborting\n"); 1070 fprintf(stderr, "frequency and count are zero, aborting\n");
1440 exit(EXIT_FAILURE); 1071 exit(EXIT_FAILURE);
1441 } 1072 }
1442 1073
1443 /* 1074 list_for_each_entry(pos, &top.evlist->entries, node) {
1444 * Fill in the ones not specifically initialized via -c: 1075 if (perf_evsel__alloc_fd(pos, top.evlist->cpus->nr,
1445 */ 1076 top.evlist->threads->nr) < 0)
1446 for (counter = 0; counter < nr_counters; counter++) { 1077 goto out_free_fd;
1447 if (attrs[counter].sample_period) 1078 /*
1079 * Fill in the ones not specifically initialized via -c:
1080 */
1081 if (pos->attr.sample_period)
1448 continue; 1082 continue;
1449 1083
1450 attrs[counter].sample_period = default_interval; 1084 pos->attr.sample_period = default_interval;
1451 } 1085 }
1452 1086
1453 if (target_tid != -1) 1087 if (perf_evlist__alloc_pollfd(top.evlist) < 0 ||
1454 nr_cpus = 1; 1088 perf_evlist__alloc_mmap(top.evlist) < 0)
1455 else 1089 goto out_free_fd;
1456 nr_cpus = read_cpu_map(cpu_list);
1457 1090
1458 if (nr_cpus < 1) 1091 top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node);
1459 usage_with_options(top_usage, options); 1092
1093 symbol_conf.priv_size = (sizeof(struct sym_entry) + sizeof(struct annotation) +
1094 (top.evlist->nr_entries + 1) * sizeof(unsigned long));
1095
1096 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
1097 if (symbol__init() < 0)
1098 return -1;
1460 1099
1461 get_term_dimensions(&winsize); 1100 get_term_dimensions(&winsize);
1462 if (print_entries == 0) { 1101 if (top.print_entries == 0) {
1463 update_print_entries(&winsize); 1102 update_print_entries(&winsize);
1464 signal(SIGWINCH, sig_winch_handler); 1103 signal(SIGWINCH, sig_winch_handler);
1465 } 1104 }
1466 1105
1467 return __cmd_top(); 1106 status = __cmd_top();
1107out_free_fd:
1108 perf_evlist__delete(top.evlist);
1109
1110 return status;
1468} 1111}
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/feature-tests.mak
index b253db634f04..b041ca67a2cb 100644
--- a/tools/perf/feature-tests.mak
+++ b/tools/perf/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
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-report b/tools/perf/scripts/perl/bin/failed-syscalls-report
index 4028d92dc4ae..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 "$PERF_EXEC_PATH"/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-report b/tools/perf/scripts/perl/bin/rw-by-file-report
index ba25f4d41fb0..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 "$PERF_EXEC_PATH"/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-report b/tools/perf/scripts/perl/bin/rw-by-pid-report
index 641a3f5d085c..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 "$PERF_EXEC_PATH"/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-report b/tools/perf/scripts/perl/bin/rwtop-report
index 4918dba77021..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 "$PERF_EXEC_PATH"/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-report b/tools/perf/scripts/perl/bin/wakeup-latency-report
index 49052ebcb632..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 "$PERF_EXEC_PATH"/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-report b/tools/perf/scripts/perl/bin/workqueue-stats-report
index df0c65f4ca93..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 "$PERF_EXEC_PATH"/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 13cc02b5893a..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#
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 03587021463d..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 "$PERF_EXEC_PATH"/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-report b/tools/perf/scripts/python/bin/futex-contention-report
index c8268138fb7e..6c44271091ab 100644
--- a/tools/perf/scripts/python/bin/futex-contention-report
+++ b/tools/perf/scripts/python/bin/futex-contention-report
@@ -1,4 +1,4 @@
1#!/bin/bash 1#!/bin/bash
2# description: futext contention measurement 2# description: futext contention measurement
3 3
4perf trace $@ -s "$PERF_EXEC_PATH"/scripts/python/futex-contention.py 4perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/futex-contention.py
diff --git a/tools/perf/scripts/python/bin/netdev-times-report b/tools/perf/scripts/python/bin/netdev-times-report
index 4ad361b31249..8f759291da86 100644
--- a/tools/perf/scripts/python/bin/netdev-times-report
+++ b/tools/perf/scripts/python/bin/netdev-times-report
@@ -2,4 +2,4 @@
2# description: display a process of packet and processing time 2# description: display a process of packet and processing time
3# args: [tx] [rx] [dev=] [debug] 3# args: [tx] [rx] [dev=] [debug]
4 4
5perf trace -s "$PERF_EXEC_PATH"/scripts/python/netdev-times.py $@ 5perf script -s "$PERF_EXEC_PATH"/scripts/python/netdev-times.py $@
diff --git a/tools/perf/scripts/python/bin/sched-migration-report b/tools/perf/scripts/python/bin/sched-migration-report
index df1791f07c24..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 "$PERF_EXEC_PATH"/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-report b/tools/perf/scripts/python/bin/sctop-report
index 36b409c05e50..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 "$PERF_EXEC_PATH"/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-report b/tools/perf/scripts/python/bin/syscall-counts-by-pid-report
index 4eb88c9fc83c..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 "$PERF_EXEC_PATH"/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-report b/tools/perf/scripts/python/bin/syscall-counts-report
index cb2f9c5cf17e..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 "$PERF_EXEC_PATH"/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 acd7848717b3..85805fac4116 100644
--- a/tools/perf/scripts/python/failed-syscalls-by-pid.py
+++ b/tools/perf/scripts/python/failed-syscalls-by-pid.py
@@ -15,7 +15,7 @@ from perf_trace_context import *
15from Core import * 15from Core import *
16from Util import * 16from Util import *
17 17
18usage = "perf trace -s syscall-counts-by-pid.py [comm|pid]\n"; 18usage = "perf script -s syscall-counts-by-pid.py [comm|pid]\n";
19 19
20for_comm = None 20for_comm = None
21for_pid = None 21for_pid = None
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 7a6ec2c7d8ab..42c267e292fa 100644
--- a/tools/perf/scripts/python/sctop.py
+++ b/tools/perf/scripts/python/sctop.py
@@ -17,7 +17,7 @@ from perf_trace_context import *
17from Core import * 17from Core import *
18from Util import * 18from Util import *
19 19
20usage = "perf trace -s sctop.py [comm] [interval]\n"; 20usage = "perf script -s sctop.py [comm] [interval]\n";
21 21
22for_comm = None 22for_comm = None
23default_interval = 3 23default_interval = 3
diff --git a/tools/perf/scripts/python/syscall-counts-by-pid.py b/tools/perf/scripts/python/syscall-counts-by-pid.py
index d1ee3ec10cf2..c64d1c55d745 100644
--- a/tools/perf/scripts/python/syscall-counts-by-pid.py
+++ b/tools/perf/scripts/python/syscall-counts-by-pid.py
@@ -14,7 +14,7 @@ from perf_trace_context import *
14from Core import * 14from Core import *
15from Util import syscall_name 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 20for_pid = None
diff --git a/tools/perf/scripts/python/syscall-counts.py b/tools/perf/scripts/python/syscall-counts.py
index ea183dc82d29..b435d3f188e8 100644
--- a/tools/perf/scripts/python/syscall-counts.py
+++ b/tools/perf/scripts/python/syscall-counts.py
@@ -15,7 +15,7 @@ from perf_trace_context import *
15from Core import * 15from Core import *
16from Util import syscall_name 16from Util import syscall_name
17 17
18usage = "perf trace -s syscall-counts.py [comm]\n"; 18usage = "perf script -s syscall-counts.py [comm]\n";
19 19
20for_comm = None 20for_comm = None
21 21
diff --git a/tools/perf/util/PERF-VERSION-GEN b/tools/perf/util/PERF-VERSION-GEN
index 97d76562a1a0..26d4d3fd6deb 100755
--- a/tools/perf/util/PERF-VERSION-GEN
+++ b/tools/perf/util/PERF-VERSION-GEN
@@ -23,10 +23,10 @@ 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 eval $(grep '^VERSION[[:space:]]*=' ../../Makefile|tr -d ' ')
27 eval `grep '^PATCHLEVEL\s*=' ../../Makefile|tr -d ' '` 27 eval $(grep '^PATCHLEVEL[[:space:]]*=' ../../Makefile|tr -d ' ')
28 eval `grep '^SUBLEVEL\s*=' ../../Makefile|tr -d ' '` 28 eval $(grep '^SUBLEVEL[[:space:]]*=' ../../Makefile|tr -d ' ')
29 eval `grep '^EXTRAVERSION\s*=' ../../Makefile|tr -d ' '` 29 eval $(grep '^EXTRAVERSION[[:space:]]*=' ../../Makefile|tr -d ' ')
30 30
31 VN="${VERSION}.${PATCHLEVEL}.${SUBLEVEL}${EXTRAVERSION}" 31 VN="${VERSION}.${PATCHLEVEL}.${SUBLEVEL}${EXTRAVERSION}"
32fi 32fi
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 a7729797fd96..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
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index e12d539417b2..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,10 +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)
30 31
31#define chain_for_each_child_safe(child, next, parent) \ 32#define chain_for_each_child_safe(child, next, parent) \
32 list_for_each_entry_safe(child, next, &parent->children, brothers) 33 list_for_each_entry_safe(child, next, &parent->children, siblings)
33 34
34static void 35static void
35rb_insert_callchain(struct rb_root *root, struct callchain_node *chain, 36rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
@@ -38,14 +39,14 @@ rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
38 struct rb_node **p = &root->rb_node; 39 struct rb_node **p = &root->rb_node;
39 struct rb_node *parent = NULL; 40 struct rb_node *parent = NULL;
40 struct callchain_node *rnode; 41 struct callchain_node *rnode;
41 u64 chain_cumul = cumul_hits(chain); 42 u64 chain_cumul = callchain_cumul_hits(chain);
42 43
43 while (*p) { 44 while (*p) {
44 u64 rnode_cumul; 45 u64 rnode_cumul;
45 46
46 parent = *p; 47 parent = *p;
47 rnode = rb_entry(parent, struct callchain_node, rb_node); 48 rnode = rb_entry(parent, struct callchain_node, rb_node);
48 rnode_cumul = cumul_hits(rnode); 49 rnode_cumul = callchain_cumul_hits(rnode);
49 50
50 switch (mode) { 51 switch (mode) {
51 case CHAIN_FLAT: 52 case CHAIN_FLAT:
@@ -104,7 +105,7 @@ static void __sort_chain_graph_abs(struct callchain_node *node,
104 105
105 chain_for_each_child(child, node) { 106 chain_for_each_child(child, node) {
106 __sort_chain_graph_abs(child, min_hit); 107 __sort_chain_graph_abs(child, min_hit);
107 if (cumul_hits(child) >= min_hit) 108 if (callchain_cumul_hits(child) >= min_hit)
108 rb_insert_callchain(&node->rb_root, child, 109 rb_insert_callchain(&node->rb_root, child,
109 CHAIN_GRAPH_ABS); 110 CHAIN_GRAPH_ABS);
110 } 111 }
@@ -129,7 +130,7 @@ static void __sort_chain_graph_rel(struct callchain_node *node,
129 130
130 chain_for_each_child(child, node) { 131 chain_for_each_child(child, node) {
131 __sort_chain_graph_rel(child, min_percent); 132 __sort_chain_graph_rel(child, min_percent);
132 if (cumul_hits(child) >= min_hit) 133 if (callchain_cumul_hits(child) >= min_hit)
133 rb_insert_callchain(&node->rb_root, child, 134 rb_insert_callchain(&node->rb_root, child,
134 CHAIN_GRAPH_REL); 135 CHAIN_GRAPH_REL);
135 } 136 }
@@ -143,7 +144,7 @@ sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_root *chain_root,
143 rb_root->rb_node = chain_root->node.rb_root.rb_node; 144 rb_root->rb_node = chain_root->node.rb_root.rb_node;
144} 145}
145 146
146int register_callchain_param(struct callchain_param *param) 147int callchain_register_param(struct callchain_param *param)
147{ 148{
148 switch (param->mode) { 149 switch (param->mode) {
149 case CHAIN_GRAPH_ABS: 150 case CHAIN_GRAPH_ABS:
@@ -189,32 +190,27 @@ create_child(struct callchain_node *parent, bool inherit_children)
189 chain_for_each_child(next, new) 190 chain_for_each_child(next, new)
190 next->parent = new; 191 next->parent = new;
191 } 192 }
192 list_add_tail(&new->brothers, &parent->children); 193 list_add_tail(&new->siblings, &parent->children);
193 194
194 return new; 195 return new;
195} 196}
196 197
197 198
198struct resolved_ip {
199 u64 ip;
200 struct map_symbol ms;
201};
202
203struct resolved_chain {
204 u64 nr;
205 struct resolved_ip ips[0];
206};
207
208
209/* 199/*
210 * Fill the node with callchain values 200 * Fill the node with callchain values
211 */ 201 */
212static void 202static void
213fill_node(struct callchain_node *node, struct resolved_chain *chain, int start) 203fill_node(struct callchain_node *node, struct callchain_cursor *cursor)
214{ 204{
215 unsigned int i; 205 struct callchain_cursor_node *cursor_node;
206
207 node->val_nr = cursor->nr - cursor->pos;
208 if (!node->val_nr)
209 pr_warning("Warning: empty node in callchain tree\n");
216 210
217 for (i = start; i < chain->nr; i++) { 211 cursor_node = callchain_cursor_current(cursor);
212
213 while (cursor_node) {
218 struct callchain_list *call; 214 struct callchain_list *call;
219 215
220 call = zalloc(sizeof(*call)); 216 call = zalloc(sizeof(*call));
@@ -222,23 +218,25 @@ fill_node(struct callchain_node *node, struct resolved_chain *chain, int start)
222 perror("not enough memory for the code path tree"); 218 perror("not enough memory for the code path tree");
223 return; 219 return;
224 } 220 }
225 call->ip = chain->ips[i].ip; 221 call->ip = cursor_node->ip;
226 call->ms = chain->ips[i].ms; 222 call->ms.sym = cursor_node->sym;
223 call->ms.map = cursor_node->map;
227 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);
228 } 228 }
229 node->val_nr = chain->nr - start;
230 if (!node->val_nr)
231 pr_warning("Warning: empty node in callchain tree\n");
232} 229}
233 230
234static void 231static void
235add_child(struct callchain_node *parent, struct resolved_chain *chain, 232add_child(struct callchain_node *parent,
236 int start, u64 period) 233 struct callchain_cursor *cursor,
234 u64 period)
237{ 235{
238 struct callchain_node *new; 236 struct callchain_node *new;
239 237
240 new = create_child(parent, false); 238 new = create_child(parent, false);
241 fill_node(new, chain, start); 239 fill_node(new, cursor);
242 240
243 new->children_hit = 0; 241 new->children_hit = 0;
244 new->hit = period; 242 new->hit = period;
@@ -250,9 +248,10 @@ add_child(struct callchain_node *parent, struct resolved_chain *chain,
250 * 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
251 */ 249 */
252static void 250static void
253split_add_child(struct callchain_node *parent, struct resolved_chain *chain, 251split_add_child(struct callchain_node *parent,
254 struct callchain_list *to_split, int idx_parents, int idx_local, 252 struct callchain_cursor *cursor,
255 u64 period) 253 struct callchain_list *to_split,
254 u64 idx_parents, u64 idx_local, u64 period)
256{ 255{
257 struct callchain_node *new; 256 struct callchain_node *new;
258 struct list_head *old_tail; 257 struct list_head *old_tail;
@@ -272,14 +271,14 @@ split_add_child(struct callchain_node *parent, struct resolved_chain *chain,
272 /* split the hits */ 271 /* split the hits */
273 new->hit = parent->hit; 272 new->hit = parent->hit;
274 new->children_hit = parent->children_hit; 273 new->children_hit = parent->children_hit;
275 parent->children_hit = cumul_hits(new); 274 parent->children_hit = callchain_cumul_hits(new);
276 new->val_nr = parent->val_nr - idx_local; 275 new->val_nr = parent->val_nr - idx_local;
277 parent->val_nr = idx_local; 276 parent->val_nr = idx_local;
278 277
279 /* create a new child for the new branch if any */ 278 /* create a new child for the new branch if any */
280 if (idx_total < chain->nr) { 279 if (idx_total < cursor->nr) {
281 parent->hit = 0; 280 parent->hit = 0;
282 add_child(parent, chain, idx_total, period); 281 add_child(parent, cursor, period);
283 parent->children_hit += period; 282 parent->children_hit += period;
284 } else { 283 } else {
285 parent->hit = period; 284 parent->hit = period;
@@ -287,36 +286,41 @@ split_add_child(struct callchain_node *parent, struct resolved_chain *chain,
287} 286}
288 287
289static int 288static int
290append_chain(struct callchain_node *root, struct resolved_chain *chain, 289append_chain(struct callchain_node *root,
291 unsigned int start, u64 period); 290 struct callchain_cursor *cursor,
291 u64 period);
292 292
293static void 293static void
294append_chain_children(struct callchain_node *root, struct resolved_chain *chain, 294append_chain_children(struct callchain_node *root,
295 unsigned int start, u64 period) 295 struct callchain_cursor *cursor,
296 u64 period)
296{ 297{
297 struct callchain_node *rnode; 298 struct callchain_node *rnode;
298 299
299 /* lookup in childrens */ 300 /* lookup in childrens */
300 chain_for_each_child(rnode, root) { 301 chain_for_each_child(rnode, root) {
301 unsigned int ret = append_chain(rnode, chain, start, period); 302 unsigned int ret = append_chain(rnode, cursor, period);
302 303
303 if (!ret) 304 if (!ret)
304 goto inc_children_hit; 305 goto inc_children_hit;
305 } 306 }
306 /* nothing in children, add to the current node */ 307 /* nothing in children, add to the current node */
307 add_child(root, chain, start, period); 308 add_child(root, cursor, period);
308 309
309inc_children_hit: 310inc_children_hit:
310 root->children_hit += period; 311 root->children_hit += period;
311} 312}
312 313
313static int 314static int
314append_chain(struct callchain_node *root, struct resolved_chain *chain, 315append_chain(struct callchain_node *root,
315 unsigned int start, u64 period) 316 struct callchain_cursor *cursor,
317 u64 period)
316{ 318{
319 struct callchain_cursor_node *curr_snap = cursor->curr;
317 struct callchain_list *cnode; 320 struct callchain_list *cnode;
318 unsigned int i = start; 321 u64 start = cursor->pos;
319 bool found = false; 322 bool found = false;
323 u64 matches;
320 324
321 /* 325 /*
322 * Lookup in the current node 326 * Lookup in the current node
@@ -324,141 +328,134 @@ append_chain(struct callchain_node *root, struct resolved_chain *chain,
324 * anywhere inside a function. 328 * anywhere inside a function.
325 */ 329 */
326 list_for_each_entry(cnode, &root->val, list) { 330 list_for_each_entry(cnode, &root->val, list) {
331 struct callchain_cursor_node *node;
327 struct symbol *sym; 332 struct symbol *sym;
328 333
329 if (i == chain->nr) 334 node = callchain_cursor_current(cursor);
335 if (!node)
330 break; 336 break;
331 337
332 sym = chain->ips[i].ms.sym; 338 sym = node->sym;
333 339
334 if (cnode->ms.sym && sym) { 340 if (cnode->ms.sym && sym) {
335 if (cnode->ms.sym->start != sym->start) 341 if (cnode->ms.sym->start != sym->start)
336 break; 342 break;
337 } else if (cnode->ip != chain->ips[i].ip) 343 } else if (cnode->ip != node->ip)
338 break; 344 break;
339 345
340 if (!found) 346 if (!found)
341 found = true; 347 found = true;
342 i++; 348
349 callchain_cursor_advance(cursor);
343 } 350 }
344 351
345 /* matches not, relay on the parent */ 352 /* matches not, relay on the parent */
346 if (!found) 353 if (!found) {
354 cursor->curr = curr_snap;
355 cursor->pos = start;
347 return -1; 356 return -1;
357 }
358
359 matches = cursor->pos - start;
348 360
349 /* 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 */
350 if (i - start < root->val_nr) { 362 if (matches < root->val_nr) {
351 split_add_child(root, chain, cnode, start, i - start, period); 363 split_add_child(root, cursor, cnode, start, matches, period);
352 return 0; 364 return 0;
353 } 365 }
354 366
355 /* we match 100% of the path, increment the hit */ 367 /* we match 100% of the path, increment the hit */
356 if (i - start == root->val_nr && i == chain->nr) { 368 if (matches == root->val_nr && cursor->pos == cursor->nr) {
357 root->hit += period; 369 root->hit += period;
358 return 0; 370 return 0;
359 } 371 }
360 372
361 /* We match the node and still have a part remaining */ 373 /* We match the node and still have a part remaining */
362 append_chain_children(root, chain, i, period); 374 append_chain_children(root, cursor, period);
363 375
364 return 0; 376 return 0;
365} 377}
366 378
367static void filter_context(struct ip_callchain *old, struct resolved_chain *new, 379int callchain_append(struct callchain_root *root,
368 struct map_symbol *syms) 380 struct callchain_cursor *cursor,
369{ 381 u64 period)
370 int i, j = 0;
371
372 for (i = 0; i < (int)old->nr; i++) {
373 if (old->ips[i] >= PERF_CONTEXT_MAX)
374 continue;
375
376 new->ips[j].ip = old->ips[i];
377 new->ips[j].ms = syms[i];
378 j++;
379 }
380
381 new->nr = j;
382}
383
384
385int callchain_append(struct callchain_root *root, struct ip_callchain *chain,
386 struct map_symbol *syms, u64 period)
387{ 382{
388 struct resolved_chain *filtered; 383 if (!cursor->nr)
389
390 if (!chain->nr)
391 return 0; 384 return 0;
392 385
393 filtered = zalloc(sizeof(*filtered) + 386 callchain_cursor_commit(cursor);
394 chain->nr * sizeof(struct resolved_ip));
395 if (!filtered)
396 return -ENOMEM;
397
398 filter_context(chain, filtered, syms);
399
400 if (!filtered->nr)
401 goto end;
402 387
403 append_chain_children(&root->node, filtered, 0, period); 388 append_chain_children(&root->node, cursor, period);
404 389
405 if (filtered->nr > root->max_depth) 390 if (cursor->nr > root->max_depth)
406 root->max_depth = filtered->nr; 391 root->max_depth = cursor->nr;
407end:
408 free(filtered);
409 392
410 return 0; 393 return 0;
411} 394}
412 395
413static int 396static int
414merge_chain_branch(struct callchain_node *dst, struct callchain_node *src, 397merge_chain_branch(struct callchain_cursor *cursor,
415 struct resolved_chain *chain) 398 struct callchain_node *dst, struct callchain_node *src)
416{ 399{
400 struct callchain_cursor_node **old_last = cursor->last;
417 struct callchain_node *child, *next_child; 401 struct callchain_node *child, *next_child;
418 struct callchain_list *list, *next_list; 402 struct callchain_list *list, *next_list;
419 int old_pos = chain->nr; 403 int old_pos = cursor->nr;
420 int err = 0; 404 int err = 0;
421 405
422 list_for_each_entry_safe(list, next_list, &src->val, list) { 406 list_for_each_entry_safe(list, next_list, &src->val, list) {
423 chain->ips[chain->nr].ip = list->ip; 407 callchain_cursor_append(cursor, list->ip,
424 chain->ips[chain->nr].ms = list->ms; 408 list->ms.map, list->ms.sym);
425 chain->nr++;
426 list_del(&list->list); 409 list_del(&list->list);
427 free(list); 410 free(list);
428 } 411 }
429 412
430 if (src->hit) 413 if (src->hit) {
431 append_chain_children(dst, chain, 0, src->hit); 414 callchain_cursor_commit(cursor);
415 append_chain_children(dst, cursor, src->hit);
416 }
432 417
433 chain_for_each_child_safe(child, next_child, src) { 418 chain_for_each_child_safe(child, next_child, src) {
434 err = merge_chain_branch(dst, child, chain); 419 err = merge_chain_branch(cursor, dst, child);
435 if (err) 420 if (err)
436 break; 421 break;
437 422
438 list_del(&child->brothers); 423 list_del(&child->siblings);
439 free(child); 424 free(child);
440 } 425 }
441 426
442 chain->nr = old_pos; 427 cursor->nr = old_pos;
428 cursor->last = old_last;
443 429
444 return err; 430 return err;
445} 431}
446 432
447int callchain_merge(struct callchain_root *dst, struct callchain_root *src) 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}
438
439int callchain_cursor_append(struct callchain_cursor *cursor,
440 u64 ip, struct map *map, struct symbol *sym)
448{ 441{
449 struct resolved_chain *chain; 442 struct callchain_cursor_node *node = *cursor->last;
450 int err;
451 443
452 chain = malloc(sizeof(*chain) + 444 if (!node) {
453 src->max_depth * sizeof(struct resolved_ip)); 445 node = calloc(sizeof(*node), 1);
454 if (!chain) 446 if (!node)
455 return -ENOMEM; 447 return -ENOMEM;
456 448
457 chain->nr = 0; 449 *cursor->last = node;
450 }
458 451
459 err = merge_chain_branch(&dst->node, &src->node, chain); 452 node->ip = ip;
453 node->map = map;
454 node->sym = sym;
460 455
461 free(chain); 456 cursor->nr++;
462 457
463 return err; 458 cursor->last = &node->next;
459
460 return 0;
464} 461}
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index c15fb8c24ad2..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 */
@@ -49,9 +49,30 @@ struct callchain_list {
49 struct list_head list; 49 struct list_head list;
50}; 50};
51 51
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
52static inline void callchain_init(struct callchain_root *root) 73static inline void callchain_init(struct callchain_root *root)
53{ 74{
54 INIT_LIST_HEAD(&root->node.brothers); 75 INIT_LIST_HEAD(&root->node.siblings);
55 INIT_LIST_HEAD(&root->node.children); 76 INIT_LIST_HEAD(&root->node.children);
56 INIT_LIST_HEAD(&root->node.val); 77 INIT_LIST_HEAD(&root->node.val);
57 78
@@ -61,15 +82,54 @@ static inline void callchain_init(struct callchain_root *root)
61 root->max_depth = 0; 82 root->max_depth = 0;
62} 83}
63 84
64static inline u64 cumul_hits(struct callchain_node *node) 85static inline u64 callchain_cumul_hits(struct callchain_node *node)
65{ 86{
66 return node->hit + node->children_hit; 87 return node->hit + node->children_hit;
67} 88}
68 89
69int register_callchain_param(struct callchain_param *param); 90int callchain_register_param(struct callchain_param *param);
70int callchain_append(struct callchain_root *root, struct ip_callchain *chain, 91int callchain_append(struct callchain_root *root,
71 struct map_symbol *syms, u64 period); 92 struct callchain_cursor *cursor,
72int callchain_merge(struct callchain_root *dst, struct callchain_root *src); 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);
73 112
74bool ip_callchain__valid(struct ip_callchain *chain, const event_t *event); 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}
129
130static inline void callchain_cursor_advance(struct callchain_cursor *cursor)
131{
132 cursor->curr = cursor->curr->next;
133 cursor->pos++;
134}
75#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 c8d81b00089d..155749d74350 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -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 7b514082bbaf..fd53db47e3de 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -9,7 +9,7 @@ extern int verbose;
9extern bool quiet, 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..1023f67633a4 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -6,8 +6,9 @@
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"
9 10
10const char *event__name[] = { 11static const char *perf_event__names[] = {
11 [0] = "TOTAL", 12 [0] = "TOTAL",
12 [PERF_RECORD_MMAP] = "MMAP", 13 [PERF_RECORD_MMAP] = "MMAP",
13 [PERF_RECORD_LOST] = "LOST", 14 [PERF_RECORD_LOST] = "LOST",
@@ -22,13 +23,31 @@ const char *event__name[] = {
22 [PERF_RECORD_HEADER_EVENT_TYPE] = "EVENT_TYPE", 23 [PERF_RECORD_HEADER_EVENT_TYPE] = "EVENT_TYPE",
23 [PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA", 24 [PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA",
24 [PERF_RECORD_HEADER_BUILD_ID] = "BUILD_ID", 25 [PERF_RECORD_HEADER_BUILD_ID] = "BUILD_ID",
26 [PERF_RECORD_FINISHED_ROUND] = "FINISHED_ROUND",
25}; 27};
26 28
27static pid_t event__synthesize_comm(pid_t pid, int full, 29const char *perf_event__name(unsigned int id)
28 event__handler_t process, 30{
29 struct perf_session *session) 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}
37
38static struct perf_sample synth_sample = {
39 .pid = -1,
40 .tid = -1,
41 .time = -1,
42 .stream_id = -1,
43 .cpu = -1,
44 .period = 1,
45};
46
47static pid_t perf_event__synthesize_comm(union perf_event *event, pid_t pid,
48 int full, perf_event__handler_t process,
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,10 @@ 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 perf_session__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps,
473 symbol_name, 541 symbol_name,
474 self->mmap.pgoff); 542 event->mmap.pgoff);
475 if (machine__is_default_guest(machine)) { 543 if (machine__is_default_guest(machine)) {
476 /* 544 /*
477 * preload dso of guest kernel and modules 545 * preload dso of guest kernel and modules
@@ -485,21 +553,23 @@ out_problem:
485 return -1; 553 return -1;
486} 554}
487 555
488int event__process_mmap(event_t *self, struct perf_session *session) 556int perf_event__process_mmap(union perf_event *event,
557 struct perf_sample *sample __used,
558 struct perf_session *session)
489{ 559{
490 struct machine *machine; 560 struct machine *machine;
491 struct thread *thread; 561 struct thread *thread;
492 struct map *map; 562 struct map *map;
493 u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 563 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
494 int ret = 0; 564 int ret = 0;
495 565
496 dump_printf(" %d/%d: [%#Lx(%#Lx) @ %#Lx]: %s\n", 566 dump_printf(" %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %s\n",
497 self->mmap.pid, self->mmap.tid, self->mmap.start, 567 event->mmap.pid, event->mmap.tid, event->mmap.start,
498 self->mmap.len, self->mmap.pgoff, self->mmap.filename); 568 event->mmap.len, event->mmap.pgoff, event->mmap.filename);
499 569
500 if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL || 570 if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
501 cpumode == PERF_RECORD_MISC_KERNEL) { 571 cpumode == PERF_RECORD_MISC_KERNEL) {
502 ret = event__process_kernel_mmap(self, session); 572 ret = perf_event__process_kernel_mmap(event, session);
503 if (ret < 0) 573 if (ret < 0)
504 goto out_problem; 574 goto out_problem;
505 return 0; 575 return 0;
@@ -508,12 +578,12 @@ int event__process_mmap(event_t *self, struct perf_session *session)
508 machine = perf_session__find_host_machine(session); 578 machine = perf_session__find_host_machine(session);
509 if (machine == NULL) 579 if (machine == NULL)
510 goto out_problem; 580 goto out_problem;
511 thread = perf_session__findnew(session, self->mmap.pid); 581 thread = perf_session__findnew(session, event->mmap.pid);
512 if (thread == NULL) 582 if (thread == NULL)
513 goto out_problem; 583 goto out_problem;
514 map = map__new(&machine->user_dsos, self->mmap.start, 584 map = map__new(&machine->user_dsos, event->mmap.start,
515 self->mmap.len, self->mmap.pgoff, 585 event->mmap.len, event->mmap.pgoff,
516 self->mmap.pid, self->mmap.filename, 586 event->mmap.pid, event->mmap.filename,
517 MAP__FUNCTION); 587 MAP__FUNCTION);
518 if (map == NULL) 588 if (map == NULL)
519 goto out_problem; 589 goto out_problem;
@@ -526,15 +596,17 @@ out_problem:
526 return 0; 596 return 0;
527} 597}
528 598
529int event__process_task(event_t *self, struct perf_session *session) 599int perf_event__process_task(union perf_event *event,
600 struct perf_sample *sample __used,
601 struct perf_session *session)
530{ 602{
531 struct thread *thread = perf_session__findnew(session, self->fork.tid); 603 struct thread *thread = perf_session__findnew(session, event->fork.tid);
532 struct thread *parent = perf_session__findnew(session, self->fork.ptid); 604 struct thread *parent = perf_session__findnew(session, event->fork.ptid);
533 605
534 dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid, 606 dump_printf("(%d:%d):(%d:%d)\n", event->fork.pid, event->fork.tid,
535 self->fork.ppid, self->fork.ptid); 607 event->fork.ppid, event->fork.ptid);
536 608
537 if (self->header.type == PERF_RECORD_EXIT) { 609 if (event->header.type == PERF_RECORD_EXIT) {
538 perf_session__remove_thread(session, thread); 610 perf_session__remove_thread(session, thread);
539 return 0; 611 return 0;
540 } 612 }
@@ -548,19 +620,22 @@ int event__process_task(event_t *self, struct perf_session *session)
548 return 0; 620 return 0;
549} 621}
550 622
551int event__process(event_t *event, struct perf_session *session) 623int perf_event__process(union perf_event *event, struct perf_sample *sample,
624 struct perf_session *session)
552{ 625{
553 switch (event->header.type) { 626 switch (event->header.type) {
554 case PERF_RECORD_COMM: 627 case PERF_RECORD_COMM:
555 event__process_comm(event, session); 628 perf_event__process_comm(event, sample, session);
556 break; 629 break;
557 case PERF_RECORD_MMAP: 630 case PERF_RECORD_MMAP:
558 event__process_mmap(event, session); 631 perf_event__process_mmap(event, sample, session);
559 break; 632 break;
560 case PERF_RECORD_FORK: 633 case PERF_RECORD_FORK:
561 case PERF_RECORD_EXIT: 634 case PERF_RECORD_EXIT:
562 event__process_task(event, session); 635 perf_event__process_task(event, sample, session);
563 break; 636 break;
637 case PERF_RECORD_LOST:
638 perf_event__process_lost(event, sample, session);
564 default: 639 default:
565 break; 640 break;
566 } 641 }
@@ -635,7 +710,7 @@ try_again:
635 * in the whole kernel symbol list. 710 * in the whole kernel symbol list.
636 */ 711 */
637 if ((long long)al->addr < 0 && 712 if ((long long)al->addr < 0 &&
638 cpumode == PERF_RECORD_MISC_KERNEL && 713 cpumode == PERF_RECORD_MISC_USER &&
639 machine && mg != &machine->kmaps) { 714 machine && mg != &machine->kmaps) {
640 mg = &machine->kmaps; 715 mg = &machine->kmaps;
641 goto try_again; 716 goto try_again;
@@ -657,49 +732,15 @@ void thread__find_addr_location(struct thread *self,
657 al->sym = NULL; 732 al->sym = NULL;
658} 733}
659 734
660static void dso__calc_col_width(struct dso *self, struct hists *hists) 735int perf_event__preprocess_sample(const union perf_event *event,
661{ 736 struct perf_session *session,
662 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep && 737 struct addr_location *al,
663 (!symbol_conf.dso_list || 738 struct perf_sample *sample,
664 strlist__has_entry(symbol_conf.dso_list, self->name))) { 739 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{ 740{
676 u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 741 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
677 struct thread *thread; 742 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
685 if (session->sample_type & PERF_SAMPLE_CALLCHAIN) {
686 unsigned int i;
687 743
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) 744 if (thread == NULL)
704 return -1; 745 return -1;
705 746
@@ -720,12 +761,12 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session,
720 machine__create_kernel_maps(&session->host_machine); 761 machine__create_kernel_maps(&session->host_machine);
721 762
722 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION, 763 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION,
723 self->ip.pid, self->ip.ip, al); 764 event->ip.pid, event->ip.ip, al);
724 dump_printf(" ...... dso: %s\n", 765 dump_printf(" ...... dso: %s\n",
725 al->map ? al->map->dso->long_name : 766 al->map ? al->map->dso->long_name :
726 al->level == 'H' ? "[hypervisor]" : "<not found>"); 767 al->level == 'H' ? "[hypervisor]" : "<not found>");
727 al->sym = NULL; 768 al->sym = NULL;
728 al->cpu = data->cpu; 769 al->cpu = sample->cpu;
729 770
730 if (al->map) { 771 if (al->map) {
731 if (symbol_conf.dso_list && 772 if (symbol_conf.dso_list &&
@@ -736,23 +777,8 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session,
736 strlist__has_entry(symbol_conf.dso_list, 777 strlist__has_entry(symbol_conf.dso_list,
737 al->map->dso->long_name))))) 778 al->map->dso->long_name)))))
738 goto out_filtered; 779 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 780
747 al->sym = map__find_symbol(al->map, al->addr, filter); 781 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 } 782 }
757 783
758 if (symbol_conf.sym_list && al->sym && 784 if (symbol_conf.sym_list && al->sym &&
@@ -765,72 +791,3 @@ out_filtered:
765 al->filtered = true; 791 al->filtered = true;
766 return 0; 792 return 0;
767} 793}
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..9c35170fb379 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -61,7 +61,7 @@ struct sample_event {
61 u64 array[]; 61 u64 array[];
62}; 62};
63 63
64struct sample_data { 64struct perf_sample {
65 u64 ip; 65 u64 ip;
66 u32 pid, tid; 66 u32 pid, tid;
67 u64 time; 67 u64 time;
@@ -85,6 +85,7 @@ struct build_id_event {
85}; 85};
86 86
87enum perf_user_event_type { /* above any possible kernel type */ 87enum perf_user_event_type { /* above any possible kernel type */
88 PERF_RECORD_USER_TYPE_START = 64,
88 PERF_RECORD_HEADER_ATTR = 64, 89 PERF_RECORD_HEADER_ATTR = 64,
89 PERF_RECORD_HEADER_EVENT_TYPE = 65, 90 PERF_RECORD_HEADER_EVENT_TYPE = 65,
90 PERF_RECORD_HEADER_TRACING_DATA = 66, 91 PERF_RECORD_HEADER_TRACING_DATA = 66,
@@ -116,7 +117,7 @@ struct tracing_data_event {
116 u32 size; 117 u32 size;
117}; 118};
118 119
119typedef union event_union { 120union perf_event {
120 struct perf_event_header header; 121 struct perf_event_header header;
121 struct ip_event ip; 122 struct ip_event ip;
122 struct mmap_event mmap; 123 struct mmap_event mmap;
@@ -129,39 +130,54 @@ typedef union event_union {
129 struct event_type_event event_type; 130 struct event_type_event event_type;
130 struct tracing_data_event tracing_data; 131 struct tracing_data_event tracing_data;
131 struct build_id_event build_id; 132 struct build_id_event build_id;
132} event_t; 133};
133 134
134void event__print_totals(void); 135void perf_event__print_totals(void);
135 136
136struct perf_session; 137struct perf_session;
137 138struct thread_map;
138typedef int (*event__handler_t)(event_t *event, struct perf_session *session); 139
139 140typedef int (*perf_event__handler_synth_t)(union perf_event *event,
140int event__synthesize_thread(pid_t pid, event__handler_t process, 141 struct perf_session *session);
142typedef int (*perf_event__handler_t)(union perf_event *event,
143 struct perf_sample *sample,
144 struct perf_session *session);
145
146int perf_event__synthesize_thread_map(struct thread_map *threads,
147 perf_event__handler_t process,
148 struct perf_session *session);
149int perf_event__synthesize_threads(perf_event__handler_t process,
150 struct perf_session *session);
151int perf_event__synthesize_kernel_mmap(perf_event__handler_t process,
152 struct perf_session *session,
153 struct machine *machine,
154 const char *symbol_name);
155
156int perf_event__synthesize_modules(perf_event__handler_t process,
157 struct perf_session *session,
158 struct machine *machine);
159
160int perf_event__process_comm(union perf_event *event, struct perf_sample *sample,
161 struct perf_session *session);
162int perf_event__process_lost(union perf_event *event, struct perf_sample *sample,
141 struct perf_session *session); 163 struct perf_session *session);
142void event__synthesize_threads(event__handler_t process, 164int perf_event__process_mmap(union perf_event *event, struct perf_sample *sample,
143 struct perf_session *session); 165 struct perf_session *session);
144int event__synthesize_kernel_mmap(event__handler_t process, 166int perf_event__process_task(union perf_event *event, struct perf_sample *sample,
145 struct perf_session *session, 167 struct perf_session *session);
146 struct machine *machine, 168int perf_event__process(union perf_event *event, struct perf_sample *sample,
147 const char *symbol_name); 169 struct perf_session *session);
148
149int event__synthesize_modules(event__handler_t process,
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 170
159struct addr_location; 171struct addr_location;
160int event__preprocess_sample(const event_t *self, struct perf_session *session, 172int perf_event__preprocess_sample(const union perf_event *self,
161 struct addr_location *al, struct sample_data *data, 173 struct perf_session *session,
162 symbol_filter_t filter); 174 struct addr_location *al,
163int event__parse_sample(const event_t *event, u64 type, struct sample_data *data); 175 struct perf_sample *sample,
176 symbol_filter_t filter);
177
178const char *perf_event__name(unsigned int id);
164 179
165extern const char *event__name[]; 180int perf_event__parse_sample(const union perf_event *event, u64 type,
181 bool sample_id_all, struct perf_sample *sample);
166 182
167#endif /* __PERF_RECORD_H */ 183#endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
new file mode 100644
index 000000000000..45da8d186b49
--- /dev/null
+++ b/tools/perf/util/evlist.c
@@ -0,0 +1,400 @@
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#include "debug.h"
16
17#include <sys/mman.h>
18
19#include <linux/bitops.h>
20#include <linux/hash.h>
21
22#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
23#define SID(e, x, y) xyarray__entry(e->sample_id, x, y)
24
25void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
26 struct thread_map *threads)
27{
28 int i;
29
30 for (i = 0; i < PERF_EVLIST__HLIST_SIZE; ++i)
31 INIT_HLIST_HEAD(&evlist->heads[i]);
32 INIT_LIST_HEAD(&evlist->entries);
33 perf_evlist__set_maps(evlist, cpus, threads);
34}
35
36struct perf_evlist *perf_evlist__new(struct cpu_map *cpus,
37 struct thread_map *threads)
38{
39 struct perf_evlist *evlist = zalloc(sizeof(*evlist));
40
41 if (evlist != NULL)
42 perf_evlist__init(evlist, cpus, threads);
43
44 return evlist;
45}
46
47static void perf_evlist__purge(struct perf_evlist *evlist)
48{
49 struct perf_evsel *pos, *n;
50
51 list_for_each_entry_safe(pos, n, &evlist->entries, node) {
52 list_del_init(&pos->node);
53 perf_evsel__delete(pos);
54 }
55
56 evlist->nr_entries = 0;
57}
58
59void perf_evlist__exit(struct perf_evlist *evlist)
60{
61 free(evlist->mmap);
62 free(evlist->pollfd);
63 evlist->mmap = NULL;
64 evlist->pollfd = NULL;
65}
66
67void perf_evlist__delete(struct perf_evlist *evlist)
68{
69 perf_evlist__purge(evlist);
70 perf_evlist__exit(evlist);
71 free(evlist);
72}
73
74void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry)
75{
76 list_add_tail(&entry->node, &evlist->entries);
77 ++evlist->nr_entries;
78}
79
80int perf_evlist__add_default(struct perf_evlist *evlist)
81{
82 struct perf_event_attr attr = {
83 .type = PERF_TYPE_HARDWARE,
84 .config = PERF_COUNT_HW_CPU_CYCLES,
85 };
86 struct perf_evsel *evsel = perf_evsel__new(&attr, 0);
87
88 if (evsel == NULL)
89 return -ENOMEM;
90
91 perf_evlist__add(evlist, evsel);
92 return 0;
93}
94
95int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
96{
97 int nfds = evlist->cpus->nr * evlist->threads->nr * evlist->nr_entries;
98 evlist->pollfd = malloc(sizeof(struct pollfd) * nfds);
99 return evlist->pollfd != NULL ? 0 : -ENOMEM;
100}
101
102void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd)
103{
104 fcntl(fd, F_SETFL, O_NONBLOCK);
105 evlist->pollfd[evlist->nr_fds].fd = fd;
106 evlist->pollfd[evlist->nr_fds].events = POLLIN;
107 evlist->nr_fds++;
108}
109
110static void perf_evlist__id_hash(struct perf_evlist *evlist,
111 struct perf_evsel *evsel,
112 int cpu, int thread, u64 id)
113{
114 int hash;
115 struct perf_sample_id *sid = SID(evsel, cpu, thread);
116
117 sid->id = id;
118 sid->evsel = evsel;
119 hash = hash_64(sid->id, PERF_EVLIST__HLIST_BITS);
120 hlist_add_head(&sid->node, &evlist->heads[hash]);
121}
122
123void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel,
124 int cpu, int thread, u64 id)
125{
126 perf_evlist__id_hash(evlist, evsel, cpu, thread, id);
127 evsel->id[evsel->ids++] = id;
128}
129
130static int perf_evlist__id_add_fd(struct perf_evlist *evlist,
131 struct perf_evsel *evsel,
132 int cpu, int thread, int fd)
133{
134 u64 read_data[4] = { 0, };
135 int id_idx = 1; /* The first entry is the counter value */
136
137 if (!(evsel->attr.read_format & PERF_FORMAT_ID) ||
138 read(fd, &read_data, sizeof(read_data)) == -1)
139 return -1;
140
141 if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
142 ++id_idx;
143 if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
144 ++id_idx;
145
146 perf_evlist__id_add(evlist, evsel, cpu, thread, read_data[id_idx]);
147 return 0;
148}
149
150struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id)
151{
152 struct hlist_head *head;
153 struct hlist_node *pos;
154 struct perf_sample_id *sid;
155 int hash;
156
157 if (evlist->nr_entries == 1)
158 return list_entry(evlist->entries.next, struct perf_evsel, node);
159
160 hash = hash_64(id, PERF_EVLIST__HLIST_BITS);
161 head = &evlist->heads[hash];
162
163 hlist_for_each_entry(sid, pos, head, node)
164 if (sid->id == id)
165 return sid->evsel;
166 return NULL;
167}
168
169union perf_event *perf_evlist__read_on_cpu(struct perf_evlist *evlist, int cpu)
170{
171 /* XXX Move this to perf.c, making it generally available */
172 unsigned int page_size = sysconf(_SC_PAGE_SIZE);
173 struct perf_mmap *md = &evlist->mmap[cpu];
174 unsigned int head = perf_mmap__read_head(md);
175 unsigned int old = md->prev;
176 unsigned char *data = md->base + page_size;
177 union perf_event *event = NULL;
178
179 if (evlist->overwrite) {
180 /*
181 * If we're further behind than half the buffer, there's a chance
182 * the writer will bite our tail and mess up the samples under us.
183 *
184 * If we somehow ended up ahead of the head, we got messed up.
185 *
186 * In either case, truncate and restart at head.
187 */
188 int diff = head - old;
189 if (diff > md->mask / 2 || diff < 0) {
190 fprintf(stderr, "WARNING: failed to keep up with mmap data.\n");
191
192 /*
193 * head points to a known good entry, start there.
194 */
195 old = head;
196 }
197 }
198
199 if (old != head) {
200 size_t size;
201
202 event = (union perf_event *)&data[old & md->mask];
203 size = event->header.size;
204
205 /*
206 * Event straddles the mmap boundary -- header should always
207 * be inside due to u64 alignment of output.
208 */
209 if ((old & md->mask) + size != ((old + size) & md->mask)) {
210 unsigned int offset = old;
211 unsigned int len = min(sizeof(*event), size), cpy;
212 void *dst = &evlist->event_copy;
213
214 do {
215 cpy = min(md->mask + 1 - (offset & md->mask), len);
216 memcpy(dst, &data[offset & md->mask], cpy);
217 offset += cpy;
218 dst += cpy;
219 len -= cpy;
220 } while (len);
221
222 event = &evlist->event_copy;
223 }
224
225 old += size;
226 }
227
228 md->prev = old;
229
230 if (!evlist->overwrite)
231 perf_mmap__write_tail(md, old);
232
233 return event;
234}
235
236void perf_evlist__munmap(struct perf_evlist *evlist)
237{
238 int cpu;
239
240 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
241 if (evlist->mmap[cpu].base != NULL) {
242 munmap(evlist->mmap[cpu].base, evlist->mmap_len);
243 evlist->mmap[cpu].base = NULL;
244 }
245 }
246}
247
248int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
249{
250 evlist->mmap = zalloc(evlist->cpus->nr * sizeof(struct perf_mmap));
251 return evlist->mmap != NULL ? 0 : -ENOMEM;
252}
253
254static int __perf_evlist__mmap(struct perf_evlist *evlist, struct perf_evsel *evsel,
255 int cpu, int prot, int mask, int fd)
256{
257 evlist->mmap[cpu].prev = 0;
258 evlist->mmap[cpu].mask = mask;
259 evlist->mmap[cpu].base = mmap(NULL, evlist->mmap_len, prot,
260 MAP_SHARED, fd, 0);
261 if (evlist->mmap[cpu].base == MAP_FAILED) {
262 if (evlist->cpus->map[cpu] == -1 && evsel->attr.inherit)
263 ui__warning("Inherit is not allowed on per-task "
264 "events using mmap.\n");
265 return -1;
266 }
267
268 perf_evlist__add_pollfd(evlist, fd);
269 return 0;
270}
271
272/** perf_evlist__mmap - Create per cpu maps to receive events
273 *
274 * @evlist - list of events
275 * @pages - map length in pages
276 * @overwrite - overwrite older events?
277 *
278 * If overwrite is false the user needs to signal event consuption using:
279 *
280 * struct perf_mmap *m = &evlist->mmap[cpu];
281 * unsigned int head = perf_mmap__read_head(m);
282 *
283 * perf_mmap__write_tail(m, head)
284 *
285 * Using perf_evlist__read_on_cpu does this automatically.
286 */
287int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite)
288{
289 unsigned int page_size = sysconf(_SC_PAGE_SIZE);
290 int mask = pages * page_size - 1, cpu;
291 struct perf_evsel *first_evsel, *evsel;
292 const struct cpu_map *cpus = evlist->cpus;
293 const struct thread_map *threads = evlist->threads;
294 int thread, prot = PROT_READ | (overwrite ? 0 : PROT_WRITE);
295
296 if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0)
297 return -ENOMEM;
298
299 if (evlist->pollfd == NULL && perf_evlist__alloc_pollfd(evlist) < 0)
300 return -ENOMEM;
301
302 evlist->overwrite = overwrite;
303 evlist->mmap_len = (pages + 1) * page_size;
304 first_evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
305
306 list_for_each_entry(evsel, &evlist->entries, node) {
307 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
308 evsel->sample_id == NULL &&
309 perf_evsel__alloc_id(evsel, cpus->nr, threads->nr) < 0)
310 return -ENOMEM;
311
312 for (cpu = 0; cpu < cpus->nr; cpu++) {
313 for (thread = 0; thread < threads->nr; thread++) {
314 int fd = FD(evsel, cpu, thread);
315
316 if (evsel->idx || thread) {
317 if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT,
318 FD(first_evsel, cpu, 0)) != 0)
319 goto out_unmap;
320 } else if (__perf_evlist__mmap(evlist, evsel, cpu,
321 prot, mask, fd) < 0)
322 goto out_unmap;
323
324 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
325 perf_evlist__id_add_fd(evlist, evsel, cpu, thread, fd) < 0)
326 goto out_unmap;
327 }
328 }
329 }
330
331 return 0;
332
333out_unmap:
334 for (cpu = 0; cpu < cpus->nr; cpu++) {
335 if (evlist->mmap[cpu].base != NULL) {
336 munmap(evlist->mmap[cpu].base, evlist->mmap_len);
337 evlist->mmap[cpu].base = NULL;
338 }
339 }
340 return -1;
341}
342
343int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid,
344 pid_t target_tid, const char *cpu_list)
345{
346 evlist->threads = thread_map__new(target_pid, target_tid);
347
348 if (evlist->threads == NULL)
349 return -1;
350
351 if (target_tid != -1)
352 evlist->cpus = cpu_map__dummy_new();
353 else
354 evlist->cpus = cpu_map__new(cpu_list);
355
356 if (evlist->cpus == NULL)
357 goto out_delete_threads;
358
359 return 0;
360
361out_delete_threads:
362 thread_map__delete(evlist->threads);
363 return -1;
364}
365
366void perf_evlist__delete_maps(struct perf_evlist *evlist)
367{
368 cpu_map__delete(evlist->cpus);
369 thread_map__delete(evlist->threads);
370 evlist->cpus = NULL;
371 evlist->threads = NULL;
372}
373
374int perf_evlist__set_filters(struct perf_evlist *evlist)
375{
376 const struct thread_map *threads = evlist->threads;
377 const struct cpu_map *cpus = evlist->cpus;
378 struct perf_evsel *evsel;
379 char *filter;
380 int thread;
381 int cpu;
382 int err;
383 int fd;
384
385 list_for_each_entry(evsel, &evlist->entries, node) {
386 filter = evsel->filter;
387 if (!filter)
388 continue;
389 for (cpu = 0; cpu < cpus->nr; cpu++) {
390 for (thread = 0; thread < threads->nr; thread++) {
391 fd = FD(evsel, cpu, thread);
392 err = ioctl(fd, PERF_EVENT_IOC_SET_FILTER, filter);
393 if (err)
394 return err;
395 }
396 }
397 }
398
399 return 0;
400}
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
new file mode 100644
index 000000000000..8b1cb7a4c5f1
--- /dev/null
+++ b/tools/perf/util/evlist.h
@@ -0,0 +1,68 @@
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 mmap_len;
21 bool overwrite;
22 union perf_event event_copy;
23 struct perf_mmap *mmap;
24 struct pollfd *pollfd;
25 struct thread_map *threads;
26 struct cpu_map *cpus;
27};
28
29struct perf_evsel;
30
31struct perf_evlist *perf_evlist__new(struct cpu_map *cpus,
32 struct thread_map *threads);
33void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
34 struct thread_map *threads);
35void perf_evlist__exit(struct perf_evlist *evlist);
36void perf_evlist__delete(struct perf_evlist *evlist);
37
38void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry);
39int perf_evlist__add_default(struct perf_evlist *evlist);
40
41void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel,
42 int cpu, int thread, u64 id);
43
44int perf_evlist__alloc_pollfd(struct perf_evlist *evlist);
45void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd);
46
47struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id);
48
49union perf_event *perf_evlist__read_on_cpu(struct perf_evlist *self, int cpu);
50
51int perf_evlist__alloc_mmap(struct perf_evlist *evlist);
52int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite);
53void perf_evlist__munmap(struct perf_evlist *evlist);
54
55static inline void perf_evlist__set_maps(struct perf_evlist *evlist,
56 struct cpu_map *cpus,
57 struct thread_map *threads)
58{
59 evlist->cpus = cpus;
60 evlist->threads = threads;
61}
62
63int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid,
64 pid_t target_tid, const char *cpu_list);
65void perf_evlist__delete_maps(struct perf_evlist *evlist);
66int perf_evlist__set_filters(struct perf_evlist *evlist);
67
68#endif /* __PERF_EVLIST_H */
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
new file mode 100644
index 000000000000..d6fd59beb860
--- /dev/null
+++ b/tools/perf/util/evsel.c
@@ -0,0 +1,384 @@
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
18void perf_evsel__init(struct perf_evsel *evsel,
19 struct perf_event_attr *attr, int idx)
20{
21 evsel->idx = idx;
22 evsel->attr = *attr;
23 INIT_LIST_HEAD(&evsel->node);
24}
25
26struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
27{
28 struct perf_evsel *evsel = zalloc(sizeof(*evsel));
29
30 if (evsel != NULL)
31 perf_evsel__init(evsel, attr, idx);
32
33 return evsel;
34}
35
36int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
37{
38 evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int));
39 return evsel->fd != NULL ? 0 : -ENOMEM;
40}
41
42int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
43{
44 evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id));
45 if (evsel->sample_id == NULL)
46 return -ENOMEM;
47
48 evsel->id = zalloc(ncpus * nthreads * sizeof(u64));
49 if (evsel->id == NULL) {
50 xyarray__delete(evsel->sample_id);
51 evsel->sample_id = NULL;
52 return -ENOMEM;
53 }
54
55 return 0;
56}
57
58int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus)
59{
60 evsel->counts = zalloc((sizeof(*evsel->counts) +
61 (ncpus * sizeof(struct perf_counts_values))));
62 return evsel->counts != NULL ? 0 : -ENOMEM;
63}
64
65void perf_evsel__free_fd(struct perf_evsel *evsel)
66{
67 xyarray__delete(evsel->fd);
68 evsel->fd = NULL;
69}
70
71void perf_evsel__free_id(struct perf_evsel *evsel)
72{
73 xyarray__delete(evsel->sample_id);
74 evsel->sample_id = NULL;
75 free(evsel->id);
76 evsel->id = NULL;
77}
78
79void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
80{
81 int cpu, thread;
82
83 for (cpu = 0; cpu < ncpus; cpu++)
84 for (thread = 0; thread < nthreads; ++thread) {
85 close(FD(evsel, cpu, thread));
86 FD(evsel, cpu, thread) = -1;
87 }
88}
89
90void perf_evsel__exit(struct perf_evsel *evsel)
91{
92 assert(list_empty(&evsel->node));
93 xyarray__delete(evsel->fd);
94 xyarray__delete(evsel->sample_id);
95 free(evsel->id);
96}
97
98void perf_evsel__delete(struct perf_evsel *evsel)
99{
100 perf_evsel__exit(evsel);
101 close_cgroup(evsel->cgrp);
102 free(evsel->name);
103 free(evsel);
104}
105
106int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
107 int cpu, int thread, bool scale)
108{
109 struct perf_counts_values count;
110 size_t nv = scale ? 3 : 1;
111
112 if (FD(evsel, cpu, thread) < 0)
113 return -EINVAL;
114
115 if (evsel->counts == NULL && perf_evsel__alloc_counts(evsel, cpu + 1) < 0)
116 return -ENOMEM;
117
118 if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0)
119 return -errno;
120
121 if (scale) {
122 if (count.run == 0)
123 count.val = 0;
124 else if (count.run < count.ena)
125 count.val = (u64)((double)count.val * count.ena / count.run + 0.5);
126 } else
127 count.ena = count.run = 0;
128
129 evsel->counts->cpu[cpu] = count;
130 return 0;
131}
132
133int __perf_evsel__read(struct perf_evsel *evsel,
134 int ncpus, int nthreads, bool scale)
135{
136 size_t nv = scale ? 3 : 1;
137 int cpu, thread;
138 struct perf_counts_values *aggr = &evsel->counts->aggr, count;
139
140 aggr->val = aggr->ena = aggr->run = 0;
141
142 for (cpu = 0; cpu < ncpus; cpu++) {
143 for (thread = 0; thread < nthreads; thread++) {
144 if (FD(evsel, cpu, thread) < 0)
145 continue;
146
147 if (readn(FD(evsel, cpu, thread),
148 &count, nv * sizeof(u64)) < 0)
149 return -errno;
150
151 aggr->val += count.val;
152 if (scale) {
153 aggr->ena += count.ena;
154 aggr->run += count.run;
155 }
156 }
157 }
158
159 evsel->counts->scaled = 0;
160 if (scale) {
161 if (aggr->run == 0) {
162 evsel->counts->scaled = -1;
163 aggr->val = 0;
164 return 0;
165 }
166
167 if (aggr->run < aggr->ena) {
168 evsel->counts->scaled = 1;
169 aggr->val = (u64)((double)aggr->val * aggr->ena / aggr->run + 0.5);
170 }
171 } else
172 aggr->ena = aggr->run = 0;
173
174 return 0;
175}
176
177static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
178 struct thread_map *threads, bool group)
179{
180 int cpu, thread;
181 unsigned long flags = 0;
182 int pid = -1;
183
184 if (evsel->fd == NULL &&
185 perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0)
186 return -1;
187
188 if (evsel->cgrp) {
189 flags = PERF_FLAG_PID_CGROUP;
190 pid = evsel->cgrp->fd;
191 }
192
193 for (cpu = 0; cpu < cpus->nr; cpu++) {
194 int group_fd = -1;
195
196 for (thread = 0; thread < threads->nr; thread++) {
197
198 if (!evsel->cgrp)
199 pid = threads->map[thread];
200
201 FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr,
202 pid,
203 cpus->map[cpu],
204 group_fd, flags);
205 if (FD(evsel, cpu, thread) < 0)
206 goto out_close;
207
208 if (group && group_fd == -1)
209 group_fd = FD(evsel, cpu, thread);
210 }
211 }
212
213 return 0;
214
215out_close:
216 do {
217 while (--thread >= 0) {
218 close(FD(evsel, cpu, thread));
219 FD(evsel, cpu, thread) = -1;
220 }
221 thread = threads->nr;
222 } while (--cpu >= 0);
223 return -1;
224}
225
226static struct {
227 struct cpu_map map;
228 int cpus[1];
229} empty_cpu_map = {
230 .map.nr = 1,
231 .cpus = { -1, },
232};
233
234static struct {
235 struct thread_map map;
236 int threads[1];
237} empty_thread_map = {
238 .map.nr = 1,
239 .threads = { -1, },
240};
241
242int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
243 struct thread_map *threads, bool group)
244{
245 if (cpus == NULL) {
246 /* Work around old compiler warnings about strict aliasing */
247 cpus = &empty_cpu_map.map;
248 }
249
250 if (threads == NULL)
251 threads = &empty_thread_map.map;
252
253 return __perf_evsel__open(evsel, cpus, threads, group);
254}
255
256int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
257 struct cpu_map *cpus, bool group)
258{
259 return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group);
260}
261
262int perf_evsel__open_per_thread(struct perf_evsel *evsel,
263 struct thread_map *threads, bool group)
264{
265 return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group);
266}
267
268static int perf_event__parse_id_sample(const union perf_event *event, u64 type,
269 struct perf_sample *sample)
270{
271 const u64 *array = event->sample.array;
272
273 array += ((event->header.size -
274 sizeof(event->header)) / sizeof(u64)) - 1;
275
276 if (type & PERF_SAMPLE_CPU) {
277 u32 *p = (u32 *)array;
278 sample->cpu = *p;
279 array--;
280 }
281
282 if (type & PERF_SAMPLE_STREAM_ID) {
283 sample->stream_id = *array;
284 array--;
285 }
286
287 if (type & PERF_SAMPLE_ID) {
288 sample->id = *array;
289 array--;
290 }
291
292 if (type & PERF_SAMPLE_TIME) {
293 sample->time = *array;
294 array--;
295 }
296
297 if (type & PERF_SAMPLE_TID) {
298 u32 *p = (u32 *)array;
299 sample->pid = p[0];
300 sample->tid = p[1];
301 }
302
303 return 0;
304}
305
306int perf_event__parse_sample(const union perf_event *event, u64 type,
307 bool sample_id_all, struct perf_sample *data)
308{
309 const u64 *array;
310
311 data->cpu = data->pid = data->tid = -1;
312 data->stream_id = data->id = data->time = -1ULL;
313
314 if (event->header.type != PERF_RECORD_SAMPLE) {
315 if (!sample_id_all)
316 return 0;
317 return perf_event__parse_id_sample(event, type, data);
318 }
319
320 array = event->sample.array;
321
322 if (type & PERF_SAMPLE_IP) {
323 data->ip = event->ip.ip;
324 array++;
325 }
326
327 if (type & PERF_SAMPLE_TID) {
328 u32 *p = (u32 *)array;
329 data->pid = p[0];
330 data->tid = p[1];
331 array++;
332 }
333
334 if (type & PERF_SAMPLE_TIME) {
335 data->time = *array;
336 array++;
337 }
338
339 if (type & PERF_SAMPLE_ADDR) {
340 data->addr = *array;
341 array++;
342 }
343
344 data->id = -1ULL;
345 if (type & PERF_SAMPLE_ID) {
346 data->id = *array;
347 array++;
348 }
349
350 if (type & PERF_SAMPLE_STREAM_ID) {
351 data->stream_id = *array;
352 array++;
353 }
354
355 if (type & PERF_SAMPLE_CPU) {
356 u32 *p = (u32 *)array;
357 data->cpu = *p;
358 array++;
359 }
360
361 if (type & PERF_SAMPLE_PERIOD) {
362 data->period = *array;
363 array++;
364 }
365
366 if (type & PERF_SAMPLE_READ) {
367 fprintf(stderr, "PERF_SAMPLE_READ is unsuported for now\n");
368 return -1;
369 }
370
371 if (type & PERF_SAMPLE_CALLCHAIN) {
372 data->callchain = (struct ip_callchain *)array;
373 array += 1 + data->callchain->nr;
374 }
375
376 if (type & PERF_SAMPLE_RAW) {
377 u32 *p = (u32 *)array;
378 data->raw_size = *p;
379 p++;
380 data->raw_data = p;
381 }
382
383 return 0;
384}
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
new file mode 100644
index 000000000000..f79bb2c09a6c
--- /dev/null
+++ b/tools/perf/util/evsel.h
@@ -0,0 +1,152 @@
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
152#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..93862a8027ea 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)
151{ 70{
152 set_bit(feat, self->adds_features); 71 set_bit(feat, header->adds_features);
153} 72}
154 73
155bool perf_header__has_feat(const struct perf_header *self, int feat) 74void perf_header__clear_feat(struct perf_header *header, int feat)
156{ 75{
157 return test_bit(feat, self->adds_features); 76 clear_bit(feat, header->adds_features);
77}
78
79bool perf_header__has_feat(const struct perf_header *header, int feat)
80{
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,20 @@ 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 realname = (char *)name;
198 else
199 realname = realpath(name, NULL);
200
201 if (realname == NULL || filename == NULL || linkname == NULL)
273 goto out_free; 202 goto out_free;
274 203
275 len = snprintf(filename, size, "%s%s%s", 204 len = snprintf(filename, size, "%s%s%s",
276 debugdir, is_kallsyms ? "/" : "", name); 205 debugdir, is_kallsyms ? "/" : "", realname);
277 if (mkdir_p(filename, 0755)) 206 if (mkdir_p(filename, 0755))
278 goto out_free; 207 goto out_free;
279 208
@@ -283,7 +212,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
283 if (is_kallsyms) { 212 if (is_kallsyms) {
284 if (copyfile("/proc/kallsyms", filename)) 213 if (copyfile("/proc/kallsyms", filename))
285 goto out_free; 214 goto out_free;
286 } else if (link(name, filename) && copyfile(name, filename)) 215 } else if (link(realname, filename) && copyfile(name, filename))
287 goto out_free; 216 goto out_free;
288 } 217 }
289 218
@@ -300,6 +229,8 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
300 if (symlink(targetname, linkname) == 0) 229 if (symlink(targetname, linkname) == 0)
301 err = 0; 230 err = 0;
302out_free: 231out_free:
232 if (!is_kallsyms)
233 free(realname);
303 free(filename); 234 free(filename);
304 free(linkname); 235 free(linkname);
305 return err; 236 return err;
@@ -354,12 +285,12 @@ out_free:
354 return err; 285 return err;
355} 286}
356 287
357static int dso__cache_build_id(struct dso *self, const char *debugdir) 288static int dso__cache_build_id(struct dso *dso, const char *debugdir)
358{ 289{
359 bool is_kallsyms = self->kernel && self->long_name[0] != '/'; 290 bool is_kallsyms = dso->kernel && dso->long_name[0] != '/';
360 291
361 return build_id_cache__add_b(self->build_id, sizeof(self->build_id), 292 return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id),
362 self->long_name, debugdir, is_kallsyms); 293 dso->long_name, debugdir, is_kallsyms);
363} 294}
364 295
365static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir) 296static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir)
@@ -374,14 +305,14 @@ static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir)
374 return err; 305 return err;
375} 306}
376 307
377static int machine__cache_build_ids(struct machine *self, const char *debugdir) 308static int machine__cache_build_ids(struct machine *machine, const char *debugdir)
378{ 309{
379 int ret = __dsos__cache_build_ids(&self->kernel_dsos, debugdir); 310 int ret = __dsos__cache_build_ids(&machine->kernel_dsos, debugdir);
380 ret |= __dsos__cache_build_ids(&self->user_dsos, debugdir); 311 ret |= __dsos__cache_build_ids(&machine->user_dsos, debugdir);
381 return ret; 312 return ret;
382} 313}
383 314
384static int perf_session__cache_build_ids(struct perf_session *self) 315static int perf_session__cache_build_ids(struct perf_session *session)
385{ 316{
386 struct rb_node *nd; 317 struct rb_node *nd;
387 int ret; 318 int ret;
@@ -392,28 +323,28 @@ static int perf_session__cache_build_ids(struct perf_session *self)
392 if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) 323 if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
393 return -1; 324 return -1;
394 325
395 ret = machine__cache_build_ids(&self->host_machine, debugdir); 326 ret = machine__cache_build_ids(&session->host_machine, debugdir);
396 327
397 for (nd = rb_first(&self->machines); nd; nd = rb_next(nd)) { 328 for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) {
398 struct machine *pos = rb_entry(nd, struct machine, rb_node); 329 struct machine *pos = rb_entry(nd, struct machine, rb_node);
399 ret |= machine__cache_build_ids(pos, debugdir); 330 ret |= machine__cache_build_ids(pos, debugdir);
400 } 331 }
401 return ret ? -1 : 0; 332 return ret ? -1 : 0;
402} 333}
403 334
404static bool machine__read_build_ids(struct machine *self, bool with_hits) 335static bool machine__read_build_ids(struct machine *machine, bool with_hits)
405{ 336{
406 bool ret = __dsos__read_build_ids(&self->kernel_dsos, with_hits); 337 bool ret = __dsos__read_build_ids(&machine->kernel_dsos, with_hits);
407 ret |= __dsos__read_build_ids(&self->user_dsos, with_hits); 338 ret |= __dsos__read_build_ids(&machine->user_dsos, with_hits);
408 return ret; 339 return ret;
409} 340}
410 341
411static bool perf_session__read_build_ids(struct perf_session *self, bool with_hits) 342static bool perf_session__read_build_ids(struct perf_session *session, bool with_hits)
412{ 343{
413 struct rb_node *nd; 344 struct rb_node *nd;
414 bool ret = machine__read_build_ids(&self->host_machine, with_hits); 345 bool ret = machine__read_build_ids(&session->host_machine, with_hits);
415 346
416 for (nd = rb_first(&self->machines); nd; nd = rb_next(nd)) { 347 for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) {
417 struct machine *pos = rb_entry(nd, struct machine, rb_node); 348 struct machine *pos = rb_entry(nd, struct machine, rb_node);
418 ret |= machine__read_build_ids(pos, with_hits); 349 ret |= machine__read_build_ids(pos, with_hits);
419 } 350 }
@@ -421,7 +352,8 @@ static bool perf_session__read_build_ids(struct perf_session *self, bool with_hi
421 return ret; 352 return ret;
422} 353}
423 354
424static int perf_header__adds_write(struct perf_header *self, int fd) 355static int perf_header__adds_write(struct perf_header *header,
356 struct perf_evlist *evlist, int fd)
425{ 357{
426 int nr_sections; 358 int nr_sections;
427 struct perf_session *session; 359 struct perf_session *session;
@@ -430,11 +362,13 @@ static int perf_header__adds_write(struct perf_header *self, int fd)
430 u64 sec_start; 362 u64 sec_start;
431 int idx = 0, err; 363 int idx = 0, err;
432 364
433 session = container_of(self, struct perf_session, header); 365 session = container_of(header, struct perf_session, header);
434 if (perf_session__read_build_ids(session, true)) 366
435 perf_header__set_feat(self, HEADER_BUILD_ID); 367 if (perf_header__has_feat(header, HEADER_BUILD_ID &&
368 !perf_session__read_build_ids(session, true)))
369 perf_header__clear_feat(header, HEADER_BUILD_ID);
436 370
437 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); 371 nr_sections = bitmap_weight(header->adds_features, HEADER_FEAT_BITS);
438 if (!nr_sections) 372 if (!nr_sections)
439 return 0; 373 return 0;
440 374
@@ -444,28 +378,28 @@ static int perf_header__adds_write(struct perf_header *self, int fd)
444 378
445 sec_size = sizeof(*feat_sec) * nr_sections; 379 sec_size = sizeof(*feat_sec) * nr_sections;
446 380
447 sec_start = self->data_offset + self->data_size; 381 sec_start = header->data_offset + header->data_size;
448 lseek(fd, sec_start + sec_size, SEEK_SET); 382 lseek(fd, sec_start + sec_size, SEEK_SET);
449 383
450 if (perf_header__has_feat(self, HEADER_TRACE_INFO)) { 384 if (perf_header__has_feat(header, HEADER_TRACE_INFO)) {
451 struct perf_file_section *trace_sec; 385 struct perf_file_section *trace_sec;
452 386
453 trace_sec = &feat_sec[idx++]; 387 trace_sec = &feat_sec[idx++];
454 388
455 /* Write trace info */ 389 /* Write trace info */
456 trace_sec->offset = lseek(fd, 0, SEEK_CUR); 390 trace_sec->offset = lseek(fd, 0, SEEK_CUR);
457 read_tracing_data(fd, attrs, nr_counters); 391 read_tracing_data(fd, &evlist->entries);
458 trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset; 392 trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset;
459 } 393 }
460 394
461 if (perf_header__has_feat(self, HEADER_BUILD_ID)) { 395 if (perf_header__has_feat(header, HEADER_BUILD_ID)) {
462 struct perf_file_section *buildid_sec; 396 struct perf_file_section *buildid_sec;
463 397
464 buildid_sec = &feat_sec[idx++]; 398 buildid_sec = &feat_sec[idx++];
465 399
466 /* Write build-ids */ 400 /* Write build-ids */
467 buildid_sec->offset = lseek(fd, 0, SEEK_CUR); 401 buildid_sec->offset = lseek(fd, 0, SEEK_CUR);
468 err = dsos__write_buildid_table(self, fd); 402 err = dsos__write_buildid_table(header, fd);
469 if (err < 0) { 403 if (err < 0) {
470 pr_debug("failed to write buildid table\n"); 404 pr_debug("failed to write buildid table\n");
471 goto out_free; 405 goto out_free;
@@ -504,32 +438,41 @@ int perf_header__write_pipe(int fd)
504 return 0; 438 return 0;
505} 439}
506 440
507int perf_header__write(struct perf_header *self, int fd, bool at_exit) 441int perf_session__write_header(struct perf_session *session,
442 struct perf_evlist *evlist,
443 int fd, bool at_exit)
508{ 444{
509 struct perf_file_header f_header; 445 struct perf_file_header f_header;
510 struct perf_file_attr f_attr; 446 struct perf_file_attr f_attr;
511 struct perf_header_attr *attr; 447 struct perf_header *header = &session->header;
512 int i, err; 448 struct perf_evsel *attr, *pair = NULL;
449 int err;
513 450
514 lseek(fd, sizeof(f_header), SEEK_SET); 451 lseek(fd, sizeof(f_header), SEEK_SET);
515 452
516 for (i = 0; i < self->attrs; i++) { 453 if (session->evlist != evlist)
517 attr = self->attr[i]; 454 pair = list_entry(session->evlist->entries.next, struct perf_evsel, node);
518 455
456 list_for_each_entry(attr, &evlist->entries, node) {
519 attr->id_offset = lseek(fd, 0, SEEK_CUR); 457 attr->id_offset = lseek(fd, 0, SEEK_CUR);
520 err = do_write(fd, attr->id, attr->ids * sizeof(u64)); 458 err = do_write(fd, attr->id, attr->ids * sizeof(u64));
521 if (err < 0) { 459 if (err < 0) {
460out_err_write:
522 pr_debug("failed to write perf header\n"); 461 pr_debug("failed to write perf header\n");
523 return err; 462 return err;
524 } 463 }
464 if (session->evlist != evlist) {
465 err = do_write(fd, pair->id, pair->ids * sizeof(u64));
466 if (err < 0)
467 goto out_err_write;
468 attr->ids += pair->ids;
469 pair = list_entry(pair->node.next, struct perf_evsel, node);
470 }
525 } 471 }
526 472
473 header->attr_offset = lseek(fd, 0, SEEK_CUR);
527 474
528 self->attr_offset = lseek(fd, 0, SEEK_CUR); 475 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){ 476 f_attr = (struct perf_file_attr){
534 .attr = attr->attr, 477 .attr = attr->attr,
535 .ids = { 478 .ids = {
@@ -544,20 +487,20 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit)
544 } 487 }
545 } 488 }
546 489
547 self->event_offset = lseek(fd, 0, SEEK_CUR); 490 header->event_offset = lseek(fd, 0, SEEK_CUR);
548 self->event_size = event_count * sizeof(struct perf_trace_event_type); 491 header->event_size = event_count * sizeof(struct perf_trace_event_type);
549 if (events) { 492 if (events) {
550 err = do_write(fd, events, self->event_size); 493 err = do_write(fd, events, header->event_size);
551 if (err < 0) { 494 if (err < 0) {
552 pr_debug("failed to write perf header events\n"); 495 pr_debug("failed to write perf header events\n");
553 return err; 496 return err;
554 } 497 }
555 } 498 }
556 499
557 self->data_offset = lseek(fd, 0, SEEK_CUR); 500 header->data_offset = lseek(fd, 0, SEEK_CUR);
558 501
559 if (at_exit) { 502 if (at_exit) {
560 err = perf_header__adds_write(self, fd); 503 err = perf_header__adds_write(header, evlist, fd);
561 if (err < 0) 504 if (err < 0)
562 return err; 505 return err;
563 } 506 }
@@ -567,20 +510,20 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit)
567 .size = sizeof(f_header), 510 .size = sizeof(f_header),
568 .attr_size = sizeof(f_attr), 511 .attr_size = sizeof(f_attr),
569 .attrs = { 512 .attrs = {
570 .offset = self->attr_offset, 513 .offset = header->attr_offset,
571 .size = self->attrs * sizeof(f_attr), 514 .size = evlist->nr_entries * sizeof(f_attr),
572 }, 515 },
573 .data = { 516 .data = {
574 .offset = self->data_offset, 517 .offset = header->data_offset,
575 .size = self->data_size, 518 .size = header->data_size,
576 }, 519 },
577 .event_types = { 520 .event_types = {
578 .offset = self->event_offset, 521 .offset = header->event_offset,
579 .size = self->event_size, 522 .size = header->event_size,
580 }, 523 },
581 }; 524 };
582 525
583 memcpy(&f_header.adds_features, &self->adds_features, sizeof(self->adds_features)); 526 memcpy(&f_header.adds_features, &header->adds_features, sizeof(header->adds_features));
584 527
585 lseek(fd, 0, SEEK_SET); 528 lseek(fd, 0, SEEK_SET);
586 err = do_write(fd, &f_header, sizeof(f_header)); 529 err = do_write(fd, &f_header, sizeof(f_header));
@@ -588,26 +531,26 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit)
588 pr_debug("failed to write perf header\n"); 531 pr_debug("failed to write perf header\n");
589 return err; 532 return err;
590 } 533 }
591 lseek(fd, self->data_offset + self->data_size, SEEK_SET); 534 lseek(fd, header->data_offset + header->data_size, SEEK_SET);
592 535
593 self->frozen = 1; 536 header->frozen = 1;
594 return 0; 537 return 0;
595} 538}
596 539
597static int perf_header__getbuffer64(struct perf_header *self, 540static int perf_header__getbuffer64(struct perf_header *header,
598 int fd, void *buf, size_t size) 541 int fd, void *buf, size_t size)
599{ 542{
600 if (do_read(fd, buf, size) <= 0) 543 if (readn(fd, buf, size) <= 0)
601 return -1; 544 return -1;
602 545
603 if (self->needs_swap) 546 if (header->needs_swap)
604 mem_bswap_64(buf, size); 547 mem_bswap_64(buf, size);
605 548
606 return 0; 549 return 0;
607} 550}
608 551
609int perf_header__process_sections(struct perf_header *self, int fd, 552int perf_header__process_sections(struct perf_header *header, int fd,
610 int (*process)(struct perf_file_section *self, 553 int (*process)(struct perf_file_section *section,
611 struct perf_header *ph, 554 struct perf_header *ph,
612 int feat, int fd)) 555 int feat, int fd))
613{ 556{
@@ -617,7 +560,7 @@ int perf_header__process_sections(struct perf_header *self, int fd,
617 int idx = 0; 560 int idx = 0;
618 int err = -1, feat = 1; 561 int err = -1, feat = 1;
619 562
620 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); 563 nr_sections = bitmap_weight(header->adds_features, HEADER_FEAT_BITS);
621 if (!nr_sections) 564 if (!nr_sections)
622 return 0; 565 return 0;
623 566
@@ -627,17 +570,17 @@ int perf_header__process_sections(struct perf_header *self, int fd,
627 570
628 sec_size = sizeof(*feat_sec) * nr_sections; 571 sec_size = sizeof(*feat_sec) * nr_sections;
629 572
630 lseek(fd, self->data_offset + self->data_size, SEEK_SET); 573 lseek(fd, header->data_offset + header->data_size, SEEK_SET);
631 574
632 if (perf_header__getbuffer64(self, fd, feat_sec, sec_size)) 575 if (perf_header__getbuffer64(header, fd, feat_sec, sec_size))
633 goto out_free; 576 goto out_free;
634 577
635 err = 0; 578 err = 0;
636 while (idx < nr_sections && feat < HEADER_LAST_FEATURE) { 579 while (idx < nr_sections && feat < HEADER_LAST_FEATURE) {
637 if (perf_header__has_feat(self, feat)) { 580 if (perf_header__has_feat(header, feat)) {
638 struct perf_file_section *sec = &feat_sec[idx++]; 581 struct perf_file_section *sec = &feat_sec[idx++];
639 582
640 err = process(sec, self, feat, fd); 583 err = process(sec, header, feat, fd);
641 if (err < 0) 584 if (err < 0)
642 break; 585 break;
643 } 586 }
@@ -648,35 +591,35 @@ out_free:
648 return err; 591 return err;
649} 592}
650 593
651int perf_file_header__read(struct perf_file_header *self, 594int perf_file_header__read(struct perf_file_header *header,
652 struct perf_header *ph, int fd) 595 struct perf_header *ph, int fd)
653{ 596{
654 lseek(fd, 0, SEEK_SET); 597 lseek(fd, 0, SEEK_SET);
655 598
656 if (do_read(fd, self, sizeof(*self)) <= 0 || 599 if (readn(fd, header, sizeof(*header)) <= 0 ||
657 memcmp(&self->magic, __perf_magic, sizeof(self->magic))) 600 memcmp(&header->magic, __perf_magic, sizeof(header->magic)))
658 return -1; 601 return -1;
659 602
660 if (self->attr_size != sizeof(struct perf_file_attr)) { 603 if (header->attr_size != sizeof(struct perf_file_attr)) {
661 u64 attr_size = bswap_64(self->attr_size); 604 u64 attr_size = bswap_64(header->attr_size);
662 605
663 if (attr_size != sizeof(struct perf_file_attr)) 606 if (attr_size != sizeof(struct perf_file_attr))
664 return -1; 607 return -1;
665 608
666 mem_bswap_64(self, offsetof(struct perf_file_header, 609 mem_bswap_64(header, offsetof(struct perf_file_header,
667 adds_features)); 610 adds_features));
668 ph->needs_swap = true; 611 ph->needs_swap = true;
669 } 612 }
670 613
671 if (self->size != sizeof(*self)) { 614 if (header->size != sizeof(*header)) {
672 /* Support the previous format */ 615 /* Support the previous format */
673 if (self->size == offsetof(typeof(*self), adds_features)) 616 if (header->size == offsetof(typeof(*header), adds_features))
674 bitmap_zero(self->adds_features, HEADER_FEAT_BITS); 617 bitmap_zero(header->adds_features, HEADER_FEAT_BITS);
675 else 618 else
676 return -1; 619 return -1;
677 } 620 }
678 621
679 memcpy(&ph->adds_features, &self->adds_features, 622 memcpy(&ph->adds_features, &header->adds_features,
680 sizeof(ph->adds_features)); 623 sizeof(ph->adds_features));
681 /* 624 /*
682 * FIXME: hack that assumes that if we need swap the perf.data file 625 * FIXME: hack that assumes that if we need swap the perf.data file
@@ -690,10 +633,10 @@ int perf_file_header__read(struct perf_file_header *self,
690 perf_header__set_feat(ph, HEADER_BUILD_ID); 633 perf_header__set_feat(ph, HEADER_BUILD_ID);
691 } 634 }
692 635
693 ph->event_offset = self->event_types.offset; 636 ph->event_offset = header->event_types.offset;
694 ph->event_size = self->event_types.size; 637 ph->event_size = header->event_types.size;
695 ph->data_offset = self->data.offset; 638 ph->data_offset = header->data.offset;
696 ph->data_size = self->data.size; 639 ph->data_size = header->data.size;
697 return 0; 640 return 0;
698} 641}
699 642
@@ -752,14 +695,50 @@ out:
752 return err; 695 return err;
753} 696}
754 697
755static int perf_header__read_build_ids(struct perf_header *self, 698static int perf_header__read_build_ids_abi_quirk(struct perf_header *header,
756 int input, u64 offset, u64 size) 699 int input, u64 offset, u64 size)
757{ 700{
758 struct perf_session *session = container_of(self, 701 struct perf_session *session = container_of(header, struct perf_session, header);
759 struct perf_session, header); 702 struct {
703 struct perf_event_header header;
704 u8 build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))];
705 char filename[0];
706 } old_bev;
760 struct build_id_event bev; 707 struct build_id_event bev;
761 char filename[PATH_MAX]; 708 char filename[PATH_MAX];
762 u64 limit = offset + size; 709 u64 limit = offset + size;
710
711 while (offset < limit) {
712 ssize_t len;
713
714 if (read(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev))
715 return -1;
716
717 if (header->needs_swap)
718 perf_event_header__bswap(&old_bev.header);
719
720 len = old_bev.header.size - sizeof(old_bev);
721 if (read(input, filename, len) != len)
722 return -1;
723
724 bev.header = old_bev.header;
725 bev.pid = 0;
726 memcpy(bev.build_id, old_bev.build_id, sizeof(bev.build_id));
727 __event_process_build_id(&bev, filename, session);
728
729 offset += bev.header.size;
730 }
731
732 return 0;
733}
734
735static int perf_header__read_build_ids(struct perf_header *header,
736 int input, u64 offset, u64 size)
737{
738 struct perf_session *session = container_of(header, struct perf_session, header);
739 struct build_id_event bev;
740 char filename[PATH_MAX];
741 u64 limit = offset + size, orig_offset = offset;
763 int err = -1; 742 int err = -1;
764 743
765 while (offset < limit) { 744 while (offset < limit) {
@@ -768,12 +747,30 @@ static int perf_header__read_build_ids(struct perf_header *self,
768 if (read(input, &bev, sizeof(bev)) != sizeof(bev)) 747 if (read(input, &bev, sizeof(bev)) != sizeof(bev))
769 goto out; 748 goto out;
770 749
771 if (self->needs_swap) 750 if (header->needs_swap)
772 perf_event_header__bswap(&bev.header); 751 perf_event_header__bswap(&bev.header);
773 752
774 len = bev.header.size - sizeof(bev); 753 len = bev.header.size - sizeof(bev);
775 if (read(input, filename, len) != len) 754 if (read(input, filename, len) != len)
776 goto out; 755 goto out;
756 /*
757 * The a1645ce1 changeset:
758 *
759 * "perf: 'perf kvm' tool for monitoring guest performance from host"
760 *
761 * Added a field to struct build_id_event that broke the file
762 * format.
763 *
764 * Since the kernel build-id is the first entry, process the
765 * table using the old format if the well known
766 * '[kernel.kallsyms]' string for the kernel build-id has the
767 * first 4 characters chopped off (where the pid_t sits).
768 */
769 if (memcmp(filename, "nel.kallsyms]", 13) == 0) {
770 if (lseek(input, orig_offset, SEEK_SET) == (off_t)-1)
771 return -1;
772 return perf_header__read_build_ids_abi_quirk(header, input, offset, size);
773 }
777 774
778 __event_process_build_id(&bev, filename, session); 775 __event_process_build_id(&bev, filename, session);
779 776
@@ -784,13 +781,13 @@ out:
784 return err; 781 return err;
785} 782}
786 783
787static int perf_file_section__process(struct perf_file_section *self, 784static int perf_file_section__process(struct perf_file_section *section,
788 struct perf_header *ph, 785 struct perf_header *ph,
789 int feat, int fd) 786 int feat, int fd)
790{ 787{
791 if (lseek(fd, self->offset, SEEK_SET) == (off_t)-1) { 788 if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) {
792 pr_debug("Failed to lseek to %Ld offset for feature %d, " 789 pr_debug("Failed to lseek to %" PRIu64 " offset for feature "
793 "continuing...\n", self->offset, feat); 790 "%d, continuing...\n", section->offset, feat);
794 return 0; 791 return 0;
795 } 792 }
796 793
@@ -800,7 +797,7 @@ static int perf_file_section__process(struct perf_file_section *self,
800 break; 797 break;
801 798
802 case HEADER_BUILD_ID: 799 case HEADER_BUILD_ID:
803 if (perf_header__read_build_ids(ph, fd, self->offset, self->size)) 800 if (perf_header__read_build_ids(ph, fd, section->offset, section->size))
804 pr_debug("Failed to read buildids, continuing...\n"); 801 pr_debug("Failed to read buildids, continuing...\n");
805 break; 802 break;
806 default: 803 default:
@@ -810,21 +807,21 @@ static int perf_file_section__process(struct perf_file_section *self,
810 return 0; 807 return 0;
811} 808}
812 809
813static int perf_file_header__read_pipe(struct perf_pipe_file_header *self, 810static int perf_file_header__read_pipe(struct perf_pipe_file_header *header,
814 struct perf_header *ph, int fd, 811 struct perf_header *ph, int fd,
815 bool repipe) 812 bool repipe)
816{ 813{
817 if (do_read(fd, self, sizeof(*self)) <= 0 || 814 if (readn(fd, header, sizeof(*header)) <= 0 ||
818 memcmp(&self->magic, __perf_magic, sizeof(self->magic))) 815 memcmp(&header->magic, __perf_magic, sizeof(header->magic)))
819 return -1; 816 return -1;
820 817
821 if (repipe && do_write(STDOUT_FILENO, self, sizeof(*self)) < 0) 818 if (repipe && do_write(STDOUT_FILENO, header, sizeof(*header)) < 0)
822 return -1; 819 return -1;
823 820
824 if (self->size != sizeof(*self)) { 821 if (header->size != sizeof(*header)) {
825 u64 size = bswap_64(self->size); 822 u64 size = bswap_64(header->size);
826 823
827 if (size != sizeof(*self)) 824 if (size != sizeof(*header))
828 return -1; 825 return -1;
829 826
830 ph->needs_swap = true; 827 ph->needs_swap = true;
@@ -835,10 +832,10 @@ static int perf_file_header__read_pipe(struct perf_pipe_file_header *self,
835 832
836static int perf_header__read_pipe(struct perf_session *session, int fd) 833static int perf_header__read_pipe(struct perf_session *session, int fd)
837{ 834{
838 struct perf_header *self = &session->header; 835 struct perf_header *header = &session->header;
839 struct perf_pipe_file_header f_header; 836 struct perf_pipe_file_header f_header;
840 837
841 if (perf_file_header__read_pipe(&f_header, self, fd, 838 if (perf_file_header__read_pipe(&f_header, header, fd,
842 session->repipe) < 0) { 839 session->repipe) < 0) {
843 pr_debug("incompatible file format\n"); 840 pr_debug("incompatible file format\n");
844 return -EINVAL; 841 return -EINVAL;
@@ -849,18 +846,22 @@ static int perf_header__read_pipe(struct perf_session *session, int fd)
849 return 0; 846 return 0;
850} 847}
851 848
852int perf_header__read(struct perf_session *session, int fd) 849int perf_session__read_header(struct perf_session *session, int fd)
853{ 850{
854 struct perf_header *self = &session->header; 851 struct perf_header *header = &session->header;
855 struct perf_file_header f_header; 852 struct perf_file_header f_header;
856 struct perf_file_attr f_attr; 853 struct perf_file_attr f_attr;
857 u64 f_id; 854 u64 f_id;
858 int nr_attrs, nr_ids, i, j; 855 int nr_attrs, nr_ids, i, j;
859 856
857 session->evlist = perf_evlist__new(NULL, NULL);
858 if (session->evlist == NULL)
859 return -ENOMEM;
860
860 if (session->fd_pipe) 861 if (session->fd_pipe)
861 return perf_header__read_pipe(session, fd); 862 return perf_header__read_pipe(session, fd);
862 863
863 if (perf_file_header__read(&f_header, self, fd) < 0) { 864 if (perf_file_header__read(&f_header, header, fd) < 0) {
864 pr_debug("incompatible file format\n"); 865 pr_debug("incompatible file format\n");
865 return -EINVAL; 866 return -EINVAL;
866 } 867 }
@@ -869,33 +870,39 @@ int perf_header__read(struct perf_session *session, int fd)
869 lseek(fd, f_header.attrs.offset, SEEK_SET); 870 lseek(fd, f_header.attrs.offset, SEEK_SET);
870 871
871 for (i = 0; i < nr_attrs; i++) { 872 for (i = 0; i < nr_attrs; i++) {
872 struct perf_header_attr *attr; 873 struct perf_evsel *evsel;
873 off_t tmp; 874 off_t tmp;
874 875
875 if (perf_header__getbuffer64(self, fd, &f_attr, sizeof(f_attr))) 876 if (perf_header__getbuffer64(header, fd, &f_attr, sizeof(f_attr)))
876 goto out_errno; 877 goto out_errno;
877 878
878 tmp = lseek(fd, 0, SEEK_CUR); 879 tmp = lseek(fd, 0, SEEK_CUR);
880 evsel = perf_evsel__new(&f_attr.attr, i);
879 881
880 attr = perf_header_attr__new(&f_attr.attr); 882 if (evsel == NULL)
881 if (attr == NULL) 883 goto out_delete_evlist;
882 return -ENOMEM; 884 /*
885 * Do it before so that if perf_evsel__alloc_id fails, this
886 * entry gets purged too at perf_evlist__delete().
887 */
888 perf_evlist__add(session->evlist, evsel);
883 889
884 nr_ids = f_attr.ids.size / sizeof(u64); 890 nr_ids = f_attr.ids.size / sizeof(u64);
891 /*
892 * We don't have the cpu and thread maps on the header, so
893 * for allocating the perf_sample_id table we fake 1 cpu and
894 * hattr->ids threads.
895 */
896 if (perf_evsel__alloc_id(evsel, 1, nr_ids))
897 goto out_delete_evlist;
898
885 lseek(fd, f_attr.ids.offset, SEEK_SET); 899 lseek(fd, f_attr.ids.offset, SEEK_SET);
886 900
887 for (j = 0; j < nr_ids; j++) { 901 for (j = 0; j < nr_ids; j++) {
888 if (perf_header__getbuffer64(self, fd, &f_id, sizeof(f_id))) 902 if (perf_header__getbuffer64(header, fd, &f_id, sizeof(f_id)))
889 goto out_errno; 903 goto out_errno;
890 904
891 if (perf_header_attr__add_id(attr, f_id) < 0) { 905 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 } 906 }
900 907
901 lseek(fd, tmp, SEEK_SET); 908 lseek(fd, tmp, SEEK_SET);
@@ -906,70 +913,63 @@ int perf_header__read(struct perf_session *session, int fd)
906 events = malloc(f_header.event_types.size); 913 events = malloc(f_header.event_types.size);
907 if (events == NULL) 914 if (events == NULL)
908 return -ENOMEM; 915 return -ENOMEM;
909 if (perf_header__getbuffer64(self, fd, events, 916 if (perf_header__getbuffer64(header, fd, events,
910 f_header.event_types.size)) 917 f_header.event_types.size))
911 goto out_errno; 918 goto out_errno;
912 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); 919 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
913 } 920 }
914 921
915 perf_header__process_sections(self, fd, perf_file_section__process); 922 perf_header__process_sections(header, fd, perf_file_section__process);
916 923
917 lseek(fd, self->data_offset, SEEK_SET); 924 lseek(fd, header->data_offset, SEEK_SET);
918 925
919 self->frozen = 1; 926 header->frozen = 1;
920 return 0; 927 return 0;
921out_errno: 928out_errno:
922 return -errno; 929 return -errno;
930
931out_delete_evlist:
932 perf_evlist__delete(session->evlist);
933 session->evlist = NULL;
934 return -ENOMEM;
923} 935}
924 936
925u64 perf_header__sample_type(struct perf_header *header) 937u64 perf_evlist__sample_type(struct perf_evlist *evlist)
926{ 938{
939 struct perf_evsel *pos;
927 u64 type = 0; 940 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 941
942 list_for_each_entry(pos, &evlist->entries, node) {
933 if (!type) 943 if (!type)
934 type = attr->attr.sample_type; 944 type = pos->attr.sample_type;
935 else if (type != attr->attr.sample_type) 945 else if (type != pos->attr.sample_type)
936 die("non matching sample_type"); 946 die("non matching sample_type");
937 } 947 }
938 948
939 return type; 949 return type;
940} 950}
941 951
942struct perf_event_attr * 952bool perf_evlist__sample_id_all(const struct perf_evlist *evlist)
943perf_header__find_attr(u64 id, struct perf_header *header)
944{ 953{
945 int i; 954 bool value = false, first = true;
946 955 struct perf_evsel *pos;
947 /* 956
948 * We set id to -1 if the data file doesn't contain sample 957 list_for_each_entry(pos, &evlist->entries, node) {
949 * ids. Check for this and avoid walking through the entire 958 if (first) {
950 * list of ids which may be large. 959 value = pos->attr.sample_id_all;
951 */ 960 first = false;
952 if (id == -1ULL) 961 } else if (value != pos->attr.sample_id_all)
953 return NULL; 962 die("non matching sample_id_all");
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 } 963 }
964 964
965 return NULL; 965 return value;
966} 966}
967 967
968int event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, 968int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id,
969 event__handler_t process, 969 perf_event__handler_t process,
970 struct perf_session *session) 970 struct perf_session *session)
971{ 971{
972 event_t *ev; 972 union perf_event *ev;
973 size_t size; 973 size_t size;
974 int err; 974 int err;
975 975
@@ -980,31 +980,31 @@ int event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id,
980 980
981 ev = malloc(size); 981 ev = malloc(size);
982 982
983 if (ev == NULL)
984 return -ENOMEM;
985
983 ev->attr.attr = *attr; 986 ev->attr.attr = *attr;
984 memcpy(ev->attr.id, id, ids * sizeof(u64)); 987 memcpy(ev->attr.id, id, ids * sizeof(u64));
985 988
986 ev->attr.header.type = PERF_RECORD_HEADER_ATTR; 989 ev->attr.header.type = PERF_RECORD_HEADER_ATTR;
987 ev->attr.header.size = size; 990 ev->attr.header.size = size;
988 991
989 err = process(ev, session); 992 err = process(ev, NULL, session);
990 993
991 free(ev); 994 free(ev);
992 995
993 return err; 996 return err;
994} 997}
995 998
996int event__synthesize_attrs(struct perf_header *self, 999int perf_session__synthesize_attrs(struct perf_session *session,
997 event__handler_t process, 1000 perf_event__handler_t process)
998 struct perf_session *session)
999{ 1001{
1000 struct perf_header_attr *attr; 1002 struct perf_evsel *attr;
1001 int i, err = 0; 1003 int err = 0;
1002
1003 for (i = 0; i < self->attrs; i++) {
1004 attr = self->attr[i];
1005 1004
1006 err = event__synthesize_attr(&attr->attr, attr->ids, attr->id, 1005 list_for_each_entry(attr, &session->evlist->entries, node) {
1007 process, session); 1006 err = perf_event__synthesize_attr(&attr->attr, attr->ids,
1007 attr->id, process, session);
1008 if (err) { 1008 if (err) {
1009 pr_debug("failed to create perf header attribute\n"); 1009 pr_debug("failed to create perf header attribute\n");
1010 return err; 1010 return err;
@@ -1014,29 +1014,39 @@ int event__synthesize_attrs(struct perf_header *self,
1014 return err; 1014 return err;
1015} 1015}
1016 1016
1017int event__process_attr(event_t *self, struct perf_session *session) 1017int perf_event__process_attr(union perf_event *event,
1018 struct perf_session *session)
1018{ 1019{
1019 struct perf_header_attr *attr;
1020 unsigned int i, ids, n_ids; 1020 unsigned int i, ids, n_ids;
1021 struct perf_evsel *evsel;
1021 1022
1022 attr = perf_header_attr__new(&self->attr.attr); 1023 if (session->evlist == NULL) {
1023 if (attr == NULL) 1024 session->evlist = perf_evlist__new(NULL, NULL);
1025 if (session->evlist == NULL)
1026 return -ENOMEM;
1027 }
1028
1029 evsel = perf_evsel__new(&event->attr.attr,
1030 session->evlist->nr_entries);
1031 if (evsel == NULL)
1024 return -ENOMEM; 1032 return -ENOMEM;
1025 1033
1026 ids = self->header.size; 1034 perf_evlist__add(session->evlist, evsel);
1027 ids -= (void *)&self->attr.id - (void *)self; 1035
1036 ids = event->header.size;
1037 ids -= (void *)&event->attr.id - (void *)event;
1028 n_ids = ids / sizeof(u64); 1038 n_ids = ids / sizeof(u64);
1039 /*
1040 * We don't have the cpu and thread maps on the header, so
1041 * for allocating the perf_sample_id table we fake 1 cpu and
1042 * hattr->ids threads.
1043 */
1044 if (perf_evsel__alloc_id(evsel, 1, n_ids))
1045 return -ENOMEM;
1029 1046
1030 for (i = 0; i < n_ids; i++) { 1047 for (i = 0; i < n_ids; i++) {
1031 if (perf_header_attr__add_id(attr, self->attr.id[i]) < 0) { 1048 perf_evlist__id_add(session->evlist, evsel, 0, i,
1032 perf_header_attr__delete(attr); 1049 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 } 1050 }
1041 1051
1042 perf_session__update_sample_type(session); 1052 perf_session__update_sample_type(session);
@@ -1044,11 +1054,11 @@ int event__process_attr(event_t *self, struct perf_session *session)
1044 return 0; 1054 return 0;
1045} 1055}
1046 1056
1047int event__synthesize_event_type(u64 event_id, char *name, 1057int perf_event__synthesize_event_type(u64 event_id, char *name,
1048 event__handler_t process, 1058 perf_event__handler_t process,
1049 struct perf_session *session) 1059 struct perf_session *session)
1050{ 1060{
1051 event_t ev; 1061 union perf_event ev;
1052 size_t size = 0; 1062 size_t size = 0;
1053 int err = 0; 1063 int err = 0;
1054 1064
@@ -1064,13 +1074,13 @@ int event__synthesize_event_type(u64 event_id, char *name,
1064 ev.event_type.header.size = sizeof(ev.event_type) - 1074 ev.event_type.header.size = sizeof(ev.event_type) -
1065 (sizeof(ev.event_type.event_type.name) - size); 1075 (sizeof(ev.event_type.event_type.name) - size);
1066 1076
1067 err = process(&ev, session); 1077 err = process(&ev, NULL, session);
1068 1078
1069 return err; 1079 return err;
1070} 1080}
1071 1081
1072int event__synthesize_event_types(event__handler_t process, 1082int perf_event__synthesize_event_types(perf_event__handler_t process,
1073 struct perf_session *session) 1083 struct perf_session *session)
1074{ 1084{
1075 struct perf_trace_event_type *type; 1085 struct perf_trace_event_type *type;
1076 int i, err = 0; 1086 int i, err = 0;
@@ -1078,8 +1088,9 @@ int event__synthesize_event_types(event__handler_t process,
1078 for (i = 0; i < event_count; i++) { 1088 for (i = 0; i < event_count; i++) {
1079 type = &events[i]; 1089 type = &events[i];
1080 1090
1081 err = event__synthesize_event_type(type->event_id, type->name, 1091 err = perf_event__synthesize_event_type(type->event_id,
1082 process, session); 1092 type->name, process,
1093 session);
1083 if (err) { 1094 if (err) {
1084 pr_debug("failed to create perf header event type\n"); 1095 pr_debug("failed to create perf header event type\n");
1085 return err; 1096 return err;
@@ -1089,29 +1100,28 @@ int event__synthesize_event_types(event__handler_t process,
1089 return err; 1100 return err;
1090} 1101}
1091 1102
1092int event__process_event_type(event_t *self, 1103int perf_event__process_event_type(union perf_event *event,
1093 struct perf_session *session __unused) 1104 struct perf_session *session __unused)
1094{ 1105{
1095 if (perf_header__push_event(self->event_type.event_type.event_id, 1106 if (perf_header__push_event(event->event_type.event_type.event_id,
1096 self->event_type.event_type.name) < 0) 1107 event->event_type.event_type.name) < 0)
1097 return -ENOMEM; 1108 return -ENOMEM;
1098 1109
1099 return 0; 1110 return 0;
1100} 1111}
1101 1112
1102int event__synthesize_tracing_data(int fd, struct perf_event_attr *pattrs, 1113int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist,
1103 int nb_events, 1114 perf_event__handler_t process,
1104 event__handler_t process,
1105 struct perf_session *session __unused) 1115 struct perf_session *session __unused)
1106{ 1116{
1107 event_t ev; 1117 union perf_event ev;
1108 ssize_t size = 0, aligned_size = 0, padding; 1118 ssize_t size = 0, aligned_size = 0, padding;
1109 int err = 0; 1119 int err __used = 0;
1110 1120
1111 memset(&ev, 0, sizeof(ev)); 1121 memset(&ev, 0, sizeof(ev));
1112 1122
1113 ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA; 1123 ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA;
1114 size = read_tracing_data_size(fd, pattrs, nb_events); 1124 size = read_tracing_data_size(fd, &evlist->entries);
1115 if (size <= 0) 1125 if (size <= 0)
1116 return size; 1126 return size;
1117 aligned_size = ALIGN(size, sizeof(u64)); 1127 aligned_size = ALIGN(size, sizeof(u64));
@@ -1119,18 +1129,18 @@ int event__synthesize_tracing_data(int fd, struct perf_event_attr *pattrs,
1119 ev.tracing_data.header.size = sizeof(ev.tracing_data); 1129 ev.tracing_data.header.size = sizeof(ev.tracing_data);
1120 ev.tracing_data.size = aligned_size; 1130 ev.tracing_data.size = aligned_size;
1121 1131
1122 process(&ev, session); 1132 process(&ev, NULL, session);
1123 1133
1124 err = read_tracing_data(fd, pattrs, nb_events); 1134 err = read_tracing_data(fd, &evlist->entries);
1125 write_padded(fd, NULL, 0, padding); 1135 write_padded(fd, NULL, 0, padding);
1126 1136
1127 return aligned_size; 1137 return aligned_size;
1128} 1138}
1129 1139
1130int event__process_tracing_data(event_t *self, 1140int perf_event__process_tracing_data(union perf_event *event,
1131 struct perf_session *session) 1141 struct perf_session *session)
1132{ 1142{
1133 ssize_t size_read, padding, size = self->tracing_data.size; 1143 ssize_t size_read, padding, size = event->tracing_data.size;
1134 off_t offset = lseek(session->fd, 0, SEEK_CUR); 1144 off_t offset = lseek(session->fd, 0, SEEK_CUR);
1135 char buf[BUFSIZ]; 1145 char buf[BUFSIZ];
1136 1146
@@ -1156,12 +1166,12 @@ int event__process_tracing_data(event_t *self,
1156 return size_read + padding; 1166 return size_read + padding;
1157} 1167}
1158 1168
1159int event__synthesize_build_id(struct dso *pos, u16 misc, 1169int perf_event__synthesize_build_id(struct dso *pos, u16 misc,
1160 event__handler_t process, 1170 perf_event__handler_t process,
1161 struct machine *machine, 1171 struct machine *machine,
1162 struct perf_session *session) 1172 struct perf_session *session)
1163{ 1173{
1164 event_t ev; 1174 union perf_event ev;
1165 size_t len; 1175 size_t len;
1166 int err = 0; 1176 int err = 0;
1167 1177
@@ -1179,16 +1189,16 @@ int event__synthesize_build_id(struct dso *pos, u16 misc,
1179 ev.build_id.header.size = sizeof(ev.build_id) + len; 1189 ev.build_id.header.size = sizeof(ev.build_id) + len;
1180 memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len); 1190 memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len);
1181 1191
1182 err = process(&ev, session); 1192 err = process(&ev, NULL, session);
1183 1193
1184 return err; 1194 return err;
1185} 1195}
1186 1196
1187int event__process_build_id(event_t *self, 1197int perf_event__process_build_id(union perf_event *event,
1188 struct perf_session *session) 1198 struct perf_session *session)
1189{ 1199{
1190 __event_process_build_id(&self->build_id, 1200 __event_process_build_id(&event->build_id,
1191 self->build_id.filename, 1201 event->build_id.filename,
1192 session); 1202 session);
1193 return 0; 1203 return 0;
1194} 1204}
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 402ac2454cf8..456661d7f10e 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,25 @@ 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); 67u64 perf_evlist__sample_type(struct perf_evlist *evlist);
79void perf_header_attr__delete(struct perf_header_attr *self); 68bool perf_evlist__sample_id_all(const struct perf_evlist *evlist);
69void perf_header__set_feat(struct perf_header *header, int feat);
70void perf_header__clear_feat(struct perf_header *header, int feat);
71bool perf_header__has_feat(const struct perf_header *header, int feat);
80 72
81int perf_header_attr__add_id(struct perf_header_attr *self, u64 id); 73int perf_header__process_sections(struct perf_header *header, int fd,
82 74 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, 75 struct perf_header *ph,
92 int feat, int fd)); 76 int feat, int fd));
93 77
@@ -95,33 +79,31 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
95 const char *name, bool is_kallsyms); 79 const char *name, bool is_kallsyms);
96int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir); 80int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir);
97 81
98int event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, 82int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id,
99 event__handler_t process, 83 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); 84 struct perf_session *session);
85int perf_session__synthesize_attrs(struct perf_session *session,
86 perf_event__handler_t process);
87int perf_event__process_attr(union perf_event *event, struct perf_session *session);
88
89int perf_event__synthesize_event_type(u64 event_id, char *name,
90 perf_event__handler_t process,
91 struct perf_session *session);
92int perf_event__synthesize_event_types(perf_event__handler_t process,
93 struct perf_session *session);
94int perf_event__process_event_type(union perf_event *event,
95 struct perf_session *session);
120 96
121int event__synthesize_build_id(struct dso *pos, u16 misc, 97int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist,
122 event__handler_t process, 98 perf_event__handler_t process,
123 struct machine *machine, 99 struct perf_session *session);
124 struct perf_session *session); 100int perf_event__process_tracing_data(union perf_event *event,
125int event__process_build_id(event_t *self, struct perf_session *session); 101 struct perf_session *session);
126 102
103int perf_event__synthesize_build_id(struct dso *pos, u16 misc,
104 perf_event__handler_t process,
105 struct machine *machine,
106 struct perf_session *session);
107int perf_event__process_build_id(union perf_event *event,
108 struct perf_session *session);
127#endif /* __PERF_HEADER_H */ 109#endif /* __PERF_HEADER_H */
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 2022e8740994..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))
@@ -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,8 +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;
229 if (symbol_conf.use_callchain) 241 if (symbol_conf.use_callchain) {
230 callchain_merge(iter->callchain, he->callchain); 242 callchain_cursor_reset(&self->callchain_cursor);
243 callchain_merge(&self->callchain_cursor, iter->callchain,
244 he->callchain);
245 }
231 hist_entry__free(he); 246 hist_entry__free(he);
232 return false; 247 return false;
233 } 248 }
@@ -262,7 +277,7 @@ void hists__collapse_resort(struct hists *self)
262 next = rb_next(&n->rb_node); 277 next = rb_next(&n->rb_node);
263 278
264 rb_erase(&n->rb_node, &self->entries); 279 rb_erase(&n->rb_node, &self->entries);
265 if (collapse__insert_entry(&tmp, n)) 280 if (hists__collapse_insert_entry(self, &tmp, n))
266 hists__inc_nr_entries(self, n); 281 hists__inc_nr_entries(self, n);
267 } 282 }
268 283
@@ -356,7 +371,7 @@ static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
356 371
357static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, 372static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
358 int depth, int depth_mask, int period, 373 int depth, int depth_mask, int period,
359 u64 total_samples, int hits, 374 u64 total_samples, u64 hits,
360 int left_margin) 375 int left_margin)
361{ 376{
362 int i; 377 int i;
@@ -425,7 +440,7 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
425 u64 cumul; 440 u64 cumul;
426 441
427 child = rb_entry(node, struct callchain_node, rb_node); 442 child = rb_entry(node, struct callchain_node, rb_node);
428 cumul = cumul_hits(child); 443 cumul = callchain_cumul_hits(child);
429 remaining -= cumul; 444 remaining -= cumul;
430 445
431 /* 446 /*
@@ -585,6 +600,7 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
585{ 600{
586 struct sort_entry *se; 601 struct sort_entry *se;
587 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;
588 const char *sep = symbol_conf.field_sep; 604 const char *sep = symbol_conf.field_sep;
589 int ret; 605 int ret;
590 606
@@ -593,6 +609,7 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
593 609
594 if (pair_hists) { 610 if (pair_hists) {
595 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;
596 total = pair_hists->stats.total_period; 613 total = pair_hists->stats.total_period;
597 period_sys = self->pair ? self->pair->period_sys : 0; 614 period_sys = self->pair ? self->pair->period_sys : 0;
598 period_us = self->pair ? self->pair->period_us : 0; 615 period_us = self->pair ? self->pair->period_us : 0;
@@ -600,6 +617,7 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
600 period_guest_us = self->pair ? self->pair->period_guest_us : 0; 617 period_guest_us = self->pair ? self->pair->period_guest_us : 0;
601 } else { 618 } else {
602 period = self->period; 619 period = self->period;
620 nr_events = self->nr_events;
603 total = session_total; 621 total = session_total;
604 period_sys = self->period_sys; 622 period_sys = self->period_sys;
605 period_us = self->period_us; 623 period_us = self->period_us;
@@ -636,13 +654,13 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
636 } 654 }
637 } 655 }
638 } else 656 } else
639 ret = snprintf(s, size, sep ? "%lld" : "%12lld ", period); 657 ret = snprintf(s, size, sep ? "%" PRIu64 : "%12" PRIu64 " ", period);
640 658
641 if (symbol_conf.show_nr_samples) { 659 if (symbol_conf.show_nr_samples) {
642 if (sep) 660 if (sep)
643 ret += snprintf(s + ret, size - ret, "%c%lld", *sep, period); 661 ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, nr_events);
644 else 662 else
645 ret += snprintf(s + ret, size - ret, "%11lld", period); 663 ret += snprintf(s + ret, size - ret, "%11" PRIu64, nr_events);
646 } 664 }
647 665
648 if (pair_hists) { 666 if (pair_hists) {
@@ -944,216 +962,14 @@ void hists__filter_by_thread(struct hists *self, const struct thread *thread)
944 } 962 }
945} 963}
946 964
947static int symbol__alloc_hist(struct symbol *self) 965int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip)
948{
949 struct sym_priv *priv = symbol__priv(self);
950 const int size = (sizeof(*priv->hist) +
951 (self->end - self->start) * sizeof(u64));
952
953 priv->hist = zalloc(size);
954 return priv->hist == NULL ? -1 : 0;
955}
956
957int hist_entry__inc_addr_samples(struct hist_entry *self, u64 ip)
958{
959 unsigned int sym_size, offset;
960 struct symbol *sym = self->ms.sym;
961 struct sym_priv *priv;
962 struct sym_hist *h;
963
964 if (!sym || !self->ms.map)
965 return 0;
966
967 priv = symbol__priv(sym);
968 if (priv->hist == NULL && symbol__alloc_hist(sym) < 0)
969 return -ENOMEM;
970
971 sym_size = sym->end - sym->start;
972 offset = ip - sym->start;
973
974 pr_debug3("%s: ip=%#Lx\n", __func__, self->ms.map->unmap_ip(self->ms.map, ip));
975
976 if (offset >= sym_size)
977 return 0;
978
979 h = priv->hist;
980 h->sum++;
981 h->ip[offset]++;
982
983 pr_debug3("%#Lx %s: period++ [ip: %#Lx, %#Lx] => %Ld\n", self->ms.sym->start,
984 self->ms.sym->name, ip, ip - self->ms.sym->start, h->ip[offset]);
985 return 0;
986}
987
988static struct objdump_line *objdump_line__new(s64 offset, char *line, size_t privsize)
989{
990 struct objdump_line *self = malloc(sizeof(*self) + privsize);
991
992 if (self != NULL) {
993 self->offset = offset;
994 self->line = line;
995 }
996
997 return self;
998}
999
1000void objdump_line__free(struct objdump_line *self)
1001{
1002 free(self->line);
1003 free(self);
1004}
1005
1006static void objdump__add_line(struct list_head *head, struct objdump_line *line)
1007{
1008 list_add_tail(&line->node, head);
1009}
1010
1011struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
1012 struct objdump_line *pos)
1013{
1014 list_for_each_entry_continue(pos, head, node)
1015 if (pos->offset >= 0)
1016 return pos;
1017
1018 return NULL;
1019}
1020
1021static int hist_entry__parse_objdump_line(struct hist_entry *self, FILE *file,
1022 struct list_head *head, size_t privsize)
1023{ 966{
1024 struct symbol *sym = self->ms.sym; 967 return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip);
1025 struct objdump_line *objdump_line;
1026 char *line = NULL, *tmp, *tmp2, *c;
1027 size_t line_len;
1028 s64 line_ip, offset = -1;
1029
1030 if (getline(&line, &line_len, file) < 0)
1031 return -1;
1032
1033 if (!line)
1034 return -1;
1035
1036 while (line_len != 0 && isspace(line[line_len - 1]))
1037 line[--line_len] = '\0';
1038
1039 c = strchr(line, '\n');
1040 if (c)
1041 *c = 0;
1042
1043 line_ip = -1;
1044
1045 /*
1046 * Strip leading spaces:
1047 */
1048 tmp = line;
1049 while (*tmp) {
1050 if (*tmp != ' ')
1051 break;
1052 tmp++;
1053 }
1054
1055 if (*tmp) {
1056 /*
1057 * Parse hexa addresses followed by ':'
1058 */
1059 line_ip = strtoull(tmp, &tmp2, 16);
1060 if (*tmp2 != ':' || tmp == tmp2 || tmp2[1] == '\0')
1061 line_ip = -1;
1062 }
1063
1064 if (line_ip != -1) {
1065 u64 start = map__rip_2objdump(self->ms.map, sym->start),
1066 end = map__rip_2objdump(self->ms.map, sym->end);
1067
1068 offset = line_ip - start;
1069 if (offset < 0 || (u64)line_ip > end)
1070 offset = -1;
1071 }
1072
1073 objdump_line = objdump_line__new(offset, line, privsize);
1074 if (objdump_line == NULL) {
1075 free(line);
1076 return -1;
1077 }
1078 objdump__add_line(head, objdump_line);
1079
1080 return 0;
1081} 968}
1082 969
1083int hist_entry__annotate(struct hist_entry *self, struct list_head *head, 970int hist_entry__annotate(struct hist_entry *he, size_t privsize)
1084 size_t privsize)
1085{ 971{
1086 struct symbol *sym = self->ms.sym; 972 return symbol__annotate(he->ms.sym, he->ms.map, privsize);
1087 struct map *map = self->ms.map;
1088 struct dso *dso = map->dso;
1089 char *filename = dso__build_id_filename(dso, NULL, 0);
1090 bool free_filename = true;
1091 char command[PATH_MAX * 2];
1092 FILE *file;
1093 int err = 0;
1094 u64 len;
1095
1096 if (filename == NULL) {
1097 if (dso->has_build_id) {
1098 pr_err("Can't annotate %s: not enough memory\n",
1099 sym->name);
1100 return -ENOMEM;
1101 }
1102 goto fallback;
1103 } else if (readlink(filename, command, sizeof(command)) < 0 ||
1104 strstr(command, "[kernel.kallsyms]") ||
1105 access(filename, R_OK)) {
1106 free(filename);
1107fallback:
1108 /*
1109 * If we don't have build-ids or the build-id file isn't in the
1110 * cache, or is just a kallsyms file, well, lets hope that this
1111 * DSO is the same as when 'perf record' ran.
1112 */
1113 filename = dso->long_name;
1114 free_filename = false;
1115 }
1116
1117 if (dso->origin == DSO__ORIG_KERNEL) {
1118 if (dso->annotate_warned)
1119 goto out_free_filename;
1120 err = -ENOENT;
1121 dso->annotate_warned = 1;
1122 pr_err("Can't annotate %s: No vmlinux file was found in the "
1123 "path\n", sym->name);
1124 goto out_free_filename;
1125 }
1126
1127 pr_debug("%s: filename=%s, sym=%s, start=%#Lx, end=%#Lx\n", __func__,
1128 filename, sym->name, map->unmap_ip(map, sym->start),
1129 map->unmap_ip(map, sym->end));
1130
1131 len = sym->end - sym->start;
1132
1133 pr_debug("annotating [%p] %30s : [%p] %30s\n",
1134 dso, dso->long_name, sym, sym->name);
1135
1136 snprintf(command, sizeof(command),
1137 "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS -C %s|grep -v %s|expand",
1138 map__rip_2objdump(map, sym->start),
1139 map__rip_2objdump(map, sym->end),
1140 filename, filename);
1141
1142 pr_debug("Executing: %s\n", command);
1143
1144 file = popen(command, "r");
1145 if (!file)
1146 goto out_free_filename;
1147
1148 while (!feof(file))
1149 if (hist_entry__parse_objdump_line(self, file, head, privsize) < 0)
1150 break;
1151
1152 pclose(file);
1153out_free_filename:
1154 if (free_filename)
1155 free(filename);
1156 return err;
1157} 973}
1158 974
1159void hists__inc_nr_events(struct hists *self, u32 type) 975void hists__inc_nr_events(struct hists *self, u32 type)
@@ -1168,10 +984,17 @@ size_t hists__fprintf_nr_events(struct hists *self, FILE *fp)
1168 size_t ret = 0; 984 size_t ret = 0;
1169 985
1170 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) { 986 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
1171 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"))
1172 continue; 994 continue;
1173 ret += fprintf(fp, "%10s events: %10d\n", 995
1174 event__name[i], self->stats.nr_events[i]); 996 ret += fprintf(fp, "%16s events: %10d\n", name,
997 self->stats.nr_events[i]);
1175 } 998 }
1176 999
1177 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/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/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..356c7e467b83 100644
--- a/tools/perf/util/include/linux/list.h
+++ b/tools/perf/util/include/linux/list.h
@@ -1,3 +1,4 @@
1#include <linux/kernel.h>
1#include "../../../../include/linux/list.h" 2#include "../../../../include/linux/list.h"
2 3
3#ifndef PERF_LIST_H 4#ifndef PERF_LIST_H
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/parse-events.c b/tools/perf/util/parse-events.c
index 4af5bd59cfd1..952b4ae3d954 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;
@@ -266,10 +263,35 @@ static char *event_cache_name(u8 cache_type, u8 cache_op, u8 cache_result)
266 return name; 263 return name;
267} 264}
268 265
269const char *event_name(int counter) 266const char *event_type(int type)
270{ 267{
271 u64 config = attrs[counter].config; 268 switch (type) {
272 int type = attrs[counter].type; 269 case PERF_TYPE_HARDWARE:
270 return "hardware";
271
272 case PERF_TYPE_SOFTWARE:
273 return "software";
274
275 case PERF_TYPE_TRACEPOINT:
276 return "tracepoint";
277
278 case PERF_TYPE_HW_CACHE:
279 return "hardware-cache";
280
281 default:
282 break;
283 }
284
285 return "unknown";
286}
287
288const char *event_name(struct perf_evsel *evsel)
289{
290 u64 config = evsel->attr.config;
291 int type = evsel->attr.type;
292
293 if (evsel->name)
294 return evsel->name;
273 295
274 return __event_name(type, config); 296 return __event_name(type, config);
275} 297}
@@ -279,7 +301,7 @@ const char *__event_name(int type, u64 config)
279 static char buf[32]; 301 static char buf[32];
280 302
281 if (type == PERF_TYPE_RAW) { 303 if (type == PERF_TYPE_RAW) {
282 sprintf(buf, "raw 0x%llx", config); 304 sprintf(buf, "raw 0x%" PRIx64, config);
283 return buf; 305 return buf;
284 } 306 }
285 307
@@ -434,7 +456,7 @@ parse_single_tracepoint_event(char *sys_name,
434 id = atoll(id_buf); 456 id = atoll(id_buf);
435 attr->config = id; 457 attr->config = id;
436 attr->type = PERF_TYPE_TRACEPOINT; 458 attr->type = PERF_TYPE_TRACEPOINT;
437 *strp = evt_name + evt_length; 459 *strp += strlen(sys_name) + evt_length + 1; /* + 1 for the ':' */
438 460
439 attr->sample_type |= PERF_SAMPLE_RAW; 461 attr->sample_type |= PERF_SAMPLE_RAW;
440 attr->sample_type |= PERF_SAMPLE_TIME; 462 attr->sample_type |= PERF_SAMPLE_TIME;
@@ -449,8 +471,8 @@ parse_single_tracepoint_event(char *sys_name,
449/* sys + ':' + event + ':' + flags*/ 471/* sys + ':' + event + ':' + flags*/
450#define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128) 472#define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128)
451static enum event_result 473static enum event_result
452parse_multiple_tracepoint_event(char *sys_name, const char *evt_exp, 474parse_multiple_tracepoint_event(const struct option *opt, char *sys_name,
453 char *flags) 475 const char *evt_exp, char *flags)
454{ 476{
455 char evt_path[MAXPATHLEN]; 477 char evt_path[MAXPATHLEN];
456 struct dirent *evt_ent; 478 struct dirent *evt_ent;
@@ -483,19 +505,19 @@ parse_multiple_tracepoint_event(char *sys_name, const char *evt_exp,
483 if (len < 0) 505 if (len < 0)
484 return EVT_FAILED; 506 return EVT_FAILED;
485 507
486 if (parse_events(NULL, event_opt, 0)) 508 if (parse_events(opt, event_opt, 0))
487 return EVT_FAILED; 509 return EVT_FAILED;
488 } 510 }
489 511
490 return EVT_HANDLED_ALL; 512 return EVT_HANDLED_ALL;
491} 513}
492 514
493 515static enum event_result
494static enum event_result parse_tracepoint_event(const char **strp, 516parse_tracepoint_event(const struct option *opt, const char **strp,
495 struct perf_event_attr *attr) 517 struct perf_event_attr *attr)
496{ 518{
497 const char *evt_name; 519 const char *evt_name;
498 char *flags; 520 char *flags = NULL, *comma_loc;
499 char sys_name[MAX_EVENT_LENGTH]; 521 char sys_name[MAX_EVENT_LENGTH];
500 unsigned int sys_length, evt_length; 522 unsigned int sys_length, evt_length;
501 523
@@ -514,6 +536,11 @@ static enum event_result parse_tracepoint_event(const char **strp,
514 sys_name[sys_length] = '\0'; 536 sys_name[sys_length] = '\0';
515 evt_name = evt_name + 1; 537 evt_name = evt_name + 1;
516 538
539 comma_loc = strchr(evt_name, ',');
540 if (comma_loc) {
541 /* take the event name up to the comma */
542 evt_name = strndup(evt_name, comma_loc - evt_name);
543 }
517 flags = strchr(evt_name, ':'); 544 flags = strchr(evt_name, ':');
518 if (flags) { 545 if (flags) {
519 /* split it out: */ 546 /* split it out: */
@@ -524,14 +551,14 @@ static enum event_result parse_tracepoint_event(const char **strp,
524 evt_length = strlen(evt_name); 551 evt_length = strlen(evt_name);
525 if (evt_length >= MAX_EVENT_LENGTH) 552 if (evt_length >= MAX_EVENT_LENGTH)
526 return EVT_FAILED; 553 return EVT_FAILED;
527
528 if (strpbrk(evt_name, "*?")) { 554 if (strpbrk(evt_name, "*?")) {
529 *strp = evt_name + evt_length; 555 *strp += strlen(sys_name) + evt_length + 1; /* 1 == the ':' */
530 return parse_multiple_tracepoint_event(sys_name, evt_name, 556 return parse_multiple_tracepoint_event(opt, sys_name, evt_name,
531 flags); 557 flags);
532 } else 558 } else {
533 return parse_single_tracepoint_event(sys_name, evt_name, 559 return parse_single_tracepoint_event(sys_name, evt_name,
534 evt_length, attr, strp); 560 evt_length, attr, strp);
561 }
535} 562}
536 563
537static enum event_result 564static enum event_result
@@ -736,11 +763,12 @@ parse_event_modifier(const char **strp, struct perf_event_attr *attr)
736 * Symbolic names are (almost) exactly matched. 763 * Symbolic names are (almost) exactly matched.
737 */ 764 */
738static enum event_result 765static enum event_result
739parse_event_symbols(const char **str, struct perf_event_attr *attr) 766parse_event_symbols(const struct option *opt, const char **str,
767 struct perf_event_attr *attr)
740{ 768{
741 enum event_result ret; 769 enum event_result ret;
742 770
743 ret = parse_tracepoint_event(str, attr); 771 ret = parse_tracepoint_event(opt, str, attr);
744 if (ret != EVT_FAILED) 772 if (ret != EVT_FAILED)
745 goto modifier; 773 goto modifier;
746 774
@@ -774,47 +802,17 @@ modifier:
774 return ret; 802 return ret;
775} 803}
776 804
777static int store_event_type(const char *orgname) 805int parse_events(const struct option *opt, const char *str, int unset __used)
778{
779 char filename[PATH_MAX], *c;
780 FILE *file;
781 int id, n;
782
783 sprintf(filename, "%s/", debugfs_path);
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 }
800 return perf_header__push_event(id, orgname);
801}
802
803int parse_events(const struct option *opt __used, const char *str, int unset __used)
804{ 806{
807 struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
805 struct perf_event_attr attr; 808 struct perf_event_attr attr;
806 enum event_result ret; 809 enum event_result ret;
807 810 const char *ostr;
808 if (strchr(str, ':'))
809 if (store_event_type(str) < 0)
810 return -1;
811 811
812 for (;;) { 812 for (;;) {
813 if (nr_counters == MAX_COUNTERS) 813 ostr = str;
814 return -1;
815
816 memset(&attr, 0, sizeof(attr)); 814 memset(&attr, 0, sizeof(attr));
817 ret = parse_event_symbols(&str, &attr); 815 ret = parse_event_symbols(opt, &str, &attr);
818 if (ret == EVT_FAILED) 816 if (ret == EVT_FAILED)
819 return -1; 817 return -1;
820 818
@@ -822,8 +820,16 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u
822 return -1; 820 return -1;
823 821
824 if (ret != EVT_HANDLED_ALL) { 822 if (ret != EVT_HANDLED_ALL) {
825 attrs[nr_counters] = attr; 823 struct perf_evsel *evsel;
826 nr_counters++; 824 evsel = perf_evsel__new(&attr, evlist->nr_entries);
825 if (evsel == NULL)
826 return -1;
827 perf_evlist__add(evlist, evsel);
828
829 evsel->name = calloc(str - ostr + 1, 1);
830 if (!evsel->name)
831 return -1;
832 strncpy(evsel->name, ostr, str - ostr);
827 } 833 }
828 834
829 if (*str == 0) 835 if (*str == 0)
@@ -837,24 +843,26 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u
837 return 0; 843 return 0;
838} 844}
839 845
840int parse_filter(const struct option *opt __used, const char *str, 846int parse_filter(const struct option *opt, const char *str,
841 int unset __used) 847 int unset __used)
842{ 848{
843 int i = nr_counters - 1; 849 struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
844 int len = strlen(str); 850 struct perf_evsel *last = NULL;
845 851
846 if (i < 0 || attrs[i].type != PERF_TYPE_TRACEPOINT) { 852 if (evlist->nr_entries > 0)
853 last = list_entry(evlist->entries.prev, struct perf_evsel, node);
854
855 if (last == NULL || last->attr.type != PERF_TYPE_TRACEPOINT) {
847 fprintf(stderr, 856 fprintf(stderr,
848 "-F option should follow a -e tracepoint option\n"); 857 "-F option should follow a -e tracepoint option\n");
849 return -1; 858 return -1;
850 } 859 }
851 860
852 filters[i] = malloc(len + 1); 861 last->filter = strdup(str);
853 if (!filters[i]) { 862 if (last->filter == NULL) {
854 fprintf(stderr, "not enough memory to hold filter string\n"); 863 fprintf(stderr, "not enough memory to hold filter string\n");
855 return -1; 864 return -1;
856 } 865 }
857 strcpy(filters[i], str);
858 866
859 return 0; 867 return 0;
860} 868}
@@ -872,7 +880,7 @@ static const char * const event_type_descriptors[] = {
872 * Print the events from <debugfs_mount_point>/tracing/events 880 * Print the events from <debugfs_mount_point>/tracing/events
873 */ 881 */
874 882
875static void print_tracepoint_events(void) 883void print_tracepoint_events(const char *subsys_glob, const char *event_glob)
876{ 884{
877 DIR *sys_dir, *evt_dir; 885 DIR *sys_dir, *evt_dir;
878 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; 886 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
@@ -887,6 +895,9 @@ static void print_tracepoint_events(void)
887 return; 895 return;
888 896
889 for_each_subsystem(sys_dir, sys_dirent, sys_next) { 897 for_each_subsystem(sys_dir, sys_dirent, sys_next) {
898 if (subsys_glob != NULL &&
899 !strglobmatch(sys_dirent.d_name, subsys_glob))
900 continue;
890 901
891 snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path, 902 snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path,
892 sys_dirent.d_name); 903 sys_dirent.d_name);
@@ -895,6 +906,10 @@ static void print_tracepoint_events(void)
895 continue; 906 continue;
896 907
897 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { 908 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) {
909 if (event_glob != NULL &&
910 !strglobmatch(evt_dirent.d_name, event_glob))
911 continue;
912
898 snprintf(evt_path, MAXPATHLEN, "%s:%s", 913 snprintf(evt_path, MAXPATHLEN, "%s:%s",
899 sys_dirent.d_name, evt_dirent.d_name); 914 sys_dirent.d_name, evt_dirent.d_name);
900 printf(" %-42s [%s]\n", evt_path, 915 printf(" %-42s [%s]\n", evt_path,
@@ -906,12 +921,101 @@ static void print_tracepoint_events(void)
906} 921}
907 922
908/* 923/*
924 * Check whether event is in <debugfs_mount_point>/tracing/events
925 */
926
927int is_valid_tracepoint(const char *event_string)
928{
929 DIR *sys_dir, *evt_dir;
930 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
931 char evt_path[MAXPATHLEN];
932 char dir_path[MAXPATHLEN];
933
934 if (debugfs_valid_mountpoint(debugfs_path))
935 return 0;
936
937 sys_dir = opendir(debugfs_path);
938 if (!sys_dir)
939 return 0;
940
941 for_each_subsystem(sys_dir, sys_dirent, sys_next) {
942
943 snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path,
944 sys_dirent.d_name);
945 evt_dir = opendir(dir_path);
946 if (!evt_dir)
947 continue;
948
949 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) {
950 snprintf(evt_path, MAXPATHLEN, "%s:%s",
951 sys_dirent.d_name, evt_dirent.d_name);
952 if (!strcmp(evt_path, event_string)) {
953 closedir(evt_dir);
954 closedir(sys_dir);
955 return 1;
956 }
957 }
958 closedir(evt_dir);
959 }
960 closedir(sys_dir);
961 return 0;
962}
963
964void print_events_type(u8 type)
965{
966 struct event_symbol *syms = event_symbols;
967 unsigned int i;
968 char name[64];
969
970 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
971 if (type != syms->type)
972 continue;
973
974 if (strlen(syms->alias))
975 snprintf(name, sizeof(name), "%s OR %s",
976 syms->symbol, syms->alias);
977 else
978 snprintf(name, sizeof(name), "%s", syms->symbol);
979
980 printf(" %-42s [%s]\n", name,
981 event_type_descriptors[type]);
982 }
983}
984
985int print_hwcache_events(const char *event_glob)
986{
987 unsigned int type, op, i, printed = 0;
988
989 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
990 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
991 /* skip invalid cache type */
992 if (!is_cache_op_valid(type, op))
993 continue;
994
995 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
996 char *name = event_cache_name(type, op, i);
997
998 if (event_glob != NULL &&
999 !strglobmatch(name, event_glob))
1000 continue;
1001
1002 printf(" %-42s [%s]\n", name,
1003 event_type_descriptors[PERF_TYPE_HW_CACHE]);
1004 ++printed;
1005 }
1006 }
1007 }
1008
1009 return printed;
1010}
1011
1012/*
909 * Print the help text for the event symbols: 1013 * Print the help text for the event symbols:
910 */ 1014 */
911void print_events(void) 1015void print_events(const char *event_glob)
912{ 1016{
913 struct event_symbol *syms = event_symbols; 1017 struct event_symbol *syms = event_symbols;
914 unsigned int i, type, op, prev_type = -1; 1018 unsigned int i, type, prev_type = -1, printed = 0, ntypes_printed = 0;
915 char name[40]; 1019 char name[40];
916 1020
917 printf("\n"); 1021 printf("\n");
@@ -920,8 +1024,16 @@ void print_events(void)
920 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { 1024 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
921 type = syms->type; 1025 type = syms->type;
922 1026
923 if (type != prev_type) 1027 if (type != prev_type && printed) {
924 printf("\n"); 1028 printf("\n");
1029 printed = 0;
1030 ntypes_printed++;
1031 }
1032
1033 if (event_glob != NULL &&
1034 !(strglobmatch(syms->symbol, event_glob) ||
1035 (syms->alias && strglobmatch(syms->alias, event_glob))))
1036 continue;
925 1037
926 if (strlen(syms->alias)) 1038 if (strlen(syms->alias))
927 sprintf(name, "%s OR %s", syms->symbol, syms->alias); 1039 sprintf(name, "%s OR %s", syms->symbol, syms->alias);
@@ -931,22 +1043,17 @@ void print_events(void)
931 event_type_descriptors[type]); 1043 event_type_descriptors[type]);
932 1044
933 prev_type = type; 1045 prev_type = type;
1046 ++printed;
934 } 1047 }
935 1048
936 printf("\n"); 1049 if (ntypes_printed) {
937 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { 1050 printed = 0;
938 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { 1051 printf("\n");
939 /* skip invalid cache type */
940 if (!is_cache_op_valid(type, op))
941 continue;
942
943 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
944 printf(" %-42s [%s]\n",
945 event_cache_name(type, op, i),
946 event_type_descriptors[PERF_TYPE_HW_CACHE]);
947 }
948 }
949 } 1052 }
1053 print_hwcache_events(event_glob);
1054
1055 if (event_glob != NULL)
1056 return;
950 1057
951 printf("\n"); 1058 printf("\n");
952 printf(" %-42s [%s]\n", 1059 printf(" %-42s [%s]\n",
@@ -959,7 +1066,7 @@ void print_events(void)
959 event_type_descriptors[PERF_TYPE_BREAKPOINT]); 1066 event_type_descriptors[PERF_TYPE_BREAKPOINT]);
960 printf("\n"); 1067 printf("\n");
961 1068
962 print_tracepoint_events(); 1069 print_tracepoint_events(NULL, NULL);
963 1070
964 exit(129); 1071 exit(129);
965} 1072}
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/probe-event.c b/tools/perf/util/probe-event.c
index 3b6a5297bf16..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"
@@ -95,7 +96,7 @@ static int init_vmlinux(void)
95 goto out; 96 goto out;
96 97
97 if (machine__create_kernel_maps(&machine) < 0) { 98 if (machine__create_kernel_maps(&machine) < 0) {
98 pr_debug("machine__create_kernel_maps "); 99 pr_debug("machine__create_kernel_maps() failed.\n");
99 goto out; 100 goto out;
100 } 101 }
101out: 102out:
@@ -111,9 +112,29 @@ static struct symbol *__find_kernel_function_by_name(const char *name,
111 NULL); 112 NULL);
112} 113}
113 114
114const char *kernel_get_module_path(const char *module) 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)
115{ 134{
116 struct dso *dso; 135 struct dso *dso;
136 struct map *map;
137 const char *vmlinux_name;
117 138
118 if (module) { 139 if (module) {
119 list_for_each_entry(dso, &machine.kernel_dsos, node) { 140 list_for_each_entry(dso, &machine.kernel_dsos, node) {
@@ -123,16 +144,29 @@ const char *kernel_get_module_path(const char *module)
123 } 144 }
124 pr_debug("Failed to find module %s.\n", module); 145 pr_debug("Failed to find module %s.\n", module);
125 return NULL; 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;
126 } else { 156 } else {
127 dso = machine.vmlinux_maps[MAP__FUNCTION]->dso; 157 if (dso__load_vmlinux_path(dso, map, NULL) <= 0) {
128 if (dso__load_vmlinux_path(dso,
129 machine.vmlinux_maps[MAP__FUNCTION], NULL) < 0) {
130 pr_debug("Failed to load kernel map.\n"); 158 pr_debug("Failed to load kernel map.\n");
131 return NULL; 159 return NULL;
132 } 160 }
133 } 161 }
134found: 162found:
135 return dso->long_name; 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;
136} 170}
137 171
138#ifdef DWARF_SUPPORT 172#ifdef DWARF_SUPPORT
@@ -140,7 +174,8 @@ static int open_vmlinux(const char *module)
140{ 174{
141 const char *path = kernel_get_module_path(module); 175 const char *path = kernel_get_module_path(module);
142 if (!path) { 176 if (!path) {
143 pr_err("Failed to find path of %s module", module ?: "kernel"); 177 pr_err("Failed to find path of %s module.\n",
178 module ?: "kernel");
144 return -ENOENT; 179 return -ENOENT;
145 } 180 }
146 pr_debug("Try to open %s\n", path); 181 pr_debug("Try to open %s\n", path);
@@ -162,7 +197,7 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
162 sym = __find_kernel_function_by_name(tp->symbol, &map); 197 sym = __find_kernel_function_by_name(tp->symbol, &map);
163 if (sym) { 198 if (sym) {
164 addr = map->unmap_ip(map, sym->start + tp->offset); 199 addr = map->unmap_ip(map, sym->start + tp->offset);
165 pr_debug("try to find %s+%ld@%llx\n", tp->symbol, 200 pr_debug("try to find %s+%ld@%" PRIx64 "\n", tp->symbol,
166 tp->offset, addr); 201 tp->offset, addr);
167 ret = find_perf_probe_point((unsigned long)addr, pp); 202 ret = find_perf_probe_point((unsigned long)addr, pp);
168 } 203 }
@@ -199,7 +234,6 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
199 234
200 /* Searching trace events corresponding to probe event */ 235 /* Searching trace events corresponding to probe event */
201 ntevs = find_probe_trace_events(fd, pev, tevs, max_tevs); 236 ntevs = find_probe_trace_events(fd, pev, tevs, max_tevs);
202 close(fd);
203 237
204 if (ntevs > 0) { /* Succeeded to find trace events */ 238 if (ntevs > 0) { /* Succeeded to find trace events */
205 pr_debug("find %d probe_trace_events.\n", ntevs); 239 pr_debug("find %d probe_trace_events.\n", ntevs);
@@ -217,7 +251,7 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
217 pr_warning("Warning: No dwarf info found in the vmlinux - " 251 pr_warning("Warning: No dwarf info found in the vmlinux - "
218 "please rebuild kernel with CONFIG_DEBUG_INFO=y.\n"); 252 "please rebuild kernel with CONFIG_DEBUG_INFO=y.\n");
219 if (!need_dwarf) { 253 if (!need_dwarf) {
220 pr_debug("Trying to use symbols.\nn"); 254 pr_debug("Trying to use symbols.\n");
221 return 0; 255 return 0;
222 } 256 }
223 } 257 }
@@ -286,42 +320,49 @@ static int get_real_path(const char *raw_path, const char *comp_dir,
286#define LINEBUF_SIZE 256 320#define LINEBUF_SIZE 256
287#define NR_ADDITIONAL_LINES 2 321#define NR_ADDITIONAL_LINES 2
288 322
289static 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)
290{ 324{
291 char buf[LINEBUF_SIZE]; 325 char buf[LINEBUF_SIZE];
292 const char *color = PERF_COLOR_BLUE; 326 const char *color = show_num ? "" : PERF_COLOR_BLUE;
327 const char *prefix = NULL;
293 328
294 if (fgets(buf, LINEBUF_SIZE, fp) == NULL) 329 do {
295 goto error;
296 if (!skip) {
297 if (show_num)
298 fprintf(stdout, "%7d %s", l, buf);
299 else
300 color_fprintf(stdout, color, " %s", buf);
301 }
302
303 while (strlen(buf) == LINEBUF_SIZE - 1 &&
304 buf[LINEBUF_SIZE - 2] != '\n') {
305 if (fgets(buf, LINEBUF_SIZE, fp) == NULL) 330 if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
306 goto error; 331 goto error;
307 if (!skip) { 332 if (skip)
308 if (show_num) 333 continue;
309 fprintf(stdout, "%s", buf); 334 if (!prefix) {
310 else 335 prefix = show_num ? "%7d " : " ";
311 color_fprintf(stdout, color, "%s", buf); 336 color_fprintf(stdout, color, prefix, l);
312 } 337 }
313 } 338 color_fprintf(stdout, color, "%s", buf);
314 339
315 return 0; 340 } while (strchr(buf, '\n') == NULL);
341
342 return 1;
316error: 343error:
317 if (feof(fp)) 344 if (ferror(fp)) {
318 pr_warning("Source file is shorter than expected.\n");
319 else
320 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}
321 350
322 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;
323} 359}
324 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
325/* 366/*
326 * Show line-range always requires debuginfo to find source file and 367 * Show line-range always requires debuginfo to find source file and
327 * line number. 368 * line number.
@@ -346,7 +387,6 @@ int show_line_range(struct line_range *lr, const char *module)
346 } 387 }
347 388
348 ret = find_line_range(fd, lr); 389 ret = find_line_range(fd, lr);
349 close(fd);
350 if (ret == 0) { 390 if (ret == 0) {
351 pr_warning("Specified source line is not found.\n"); 391 pr_warning("Specified source line is not found.\n");
352 return -ENOENT; 392 return -ENOENT;
@@ -367,10 +407,10 @@ int show_line_range(struct line_range *lr, const char *module)
367 setup_pager(); 407 setup_pager();
368 408
369 if (lr->function) 409 if (lr->function)
370 fprintf(stdout, "<%s:%d>\n", lr->function, 410 fprintf(stdout, "<%s@%s:%d>\n", lr->function, lr->path,
371 lr->start - lr->offset); 411 lr->start - lr->offset);
372 else 412 else
373 fprintf(stdout, "<%s:%d>\n", lr->file, lr->start); 413 fprintf(stdout, "<%s:%d>\n", lr->path, lr->start);
374 414
375 fp = fopen(lr->path, "r"); 415 fp = fopen(lr->path, "r");
376 if (fp == NULL) { 416 if (fp == NULL) {
@@ -379,38 +419,44 @@ int show_line_range(struct line_range *lr, const char *module)
379 return -errno; 419 return -errno;
380 } 420 }
381 /* Skip to starting line number */ 421 /* Skip to starting line number */
382 while (l < lr->start && ret >= 0) 422 while (l < lr->start) {
383 ret = show_one_line(fp, l++, true, false); 423 ret = skip_one_line(fp, l++);
384 if (ret < 0) 424 if (ret < 0)
385 goto end; 425 goto end;
426 }
386 427
387 list_for_each_entry(ln, &lr->line_list, list) { 428 list_for_each_entry(ln, &lr->line_list, list) {
388 while (ln->line > l && ret >= 0) 429 for (; ln->line > l; l++) {
389 ret = show_one_line(fp, (l++) - lr->offset, 430 ret = show_one_line(fp, l - lr->offset);
390 false, false); 431 if (ret < 0)
391 if (ret >= 0) 432 goto end;
392 ret = show_one_line(fp, (l++) - lr->offset, 433 }
393 false, true); 434 ret = show_one_line_with_num(fp, l++ - lr->offset);
394 if (ret < 0) 435 if (ret < 0)
395 goto end; 436 goto end;
396 } 437 }
397 438
398 if (lr->end == INT_MAX) 439 if (lr->end == INT_MAX)
399 lr->end = l + NR_ADDITIONAL_LINES; 440 lr->end = l + NR_ADDITIONAL_LINES;
400 while (l <= lr->end && !feof(fp) && ret >= 0) 441 while (l <= lr->end) {
401 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 }
402end: 446end:
403 fclose(fp); 447 fclose(fp);
404 return ret; 448 return ret;
405} 449}
406 450
407static int show_available_vars_at(int fd, struct perf_probe_event *pev, 451static int show_available_vars_at(int fd, struct perf_probe_event *pev,
408 int max_vls, bool externs) 452 int max_vls, struct strfilter *_filter,
453 bool externs)
409{ 454{
410 char *buf; 455 char *buf;
411 int ret, i; 456 int ret, i, nvars;
412 struct str_node *node; 457 struct str_node *node;
413 struct variable_list *vls = NULL, *vl; 458 struct variable_list *vls = NULL, *vl;
459 const char *var;
414 460
415 buf = synthesize_perf_probe_point(&pev->point); 461 buf = synthesize_perf_probe_point(&pev->point);
416 if (!buf) 462 if (!buf)
@@ -418,36 +464,45 @@ static int show_available_vars_at(int fd, struct perf_probe_event *pev,
418 pr_debug("Searching variables at %s\n", buf); 464 pr_debug("Searching variables at %s\n", buf);
419 465
420 ret = find_available_vars_at(fd, pev, &vls, max_vls, externs); 466 ret = find_available_vars_at(fd, pev, &vls, max_vls, externs);
421 if (ret > 0) { 467 if (ret <= 0) {
422 /* Some variables were found */ 468 pr_err("Failed to find variables at %s (%d)\n", buf, ret);
423 fprintf(stdout, "Available variables at %s\n", buf); 469 goto end;
424 for (i = 0; i < ret; i++) { 470 }
425 vl = &vls[i]; 471 /* Some variables are found */
426 /* 472 fprintf(stdout, "Available variables at %s\n", buf);
427 * A probe point might be converted to 473 for (i = 0; i < ret; i++) {
428 * several trace points. 474 vl = &vls[i];
429 */ 475 /*
430 fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol, 476 * A probe point might be converted to
431 vl->point.offset); 477 * several trace points.
432 free(vl->point.symbol); 478 */
433 if (vl->vars) { 479 fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol,
434 strlist__for_each(node, vl->vars) 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)) {
435 fprintf(stdout, "\t\t%s\n", node->s); 487 fprintf(stdout, "\t\t%s\n", node->s);
436 strlist__delete(vl->vars); 488 nvars++;
437 } else 489 }
438 fprintf(stdout, "(No variables)\n"); 490 }
491 strlist__delete(vl->vars);
439 } 492 }
440 free(vls); 493 if (nvars == 0)
441 } else 494 fprintf(stdout, "\t\t(No matched variables)\n");
442 pr_err("Failed to find variables at %s (%d)\n", buf, ret); 495 }
443 496 free(vls);
497end:
444 free(buf); 498 free(buf);
445 return ret; 499 return ret;
446} 500}
447 501
448/* Show available variables on given probe point */ 502/* Show available variables on given probe point */
449int show_available_vars(struct perf_probe_event *pevs, int npevs, 503int show_available_vars(struct perf_probe_event *pevs, int npevs,
450 int max_vls, const char *module, bool externs) 504 int max_vls, const char *module,
505 struct strfilter *_filter, bool externs)
451{ 506{
452 int i, fd, ret = 0; 507 int i, fd, ret = 0;
453 508
@@ -455,18 +510,18 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
455 if (ret < 0) 510 if (ret < 0)
456 return ret; 511 return ret;
457 512
458 fd = open_vmlinux(module);
459 if (fd < 0) {
460 pr_warning("Failed to open debuginfo file.\n");
461 return fd;
462 }
463
464 setup_pager(); 513 setup_pager();
465 514
466 for (i = 0; i < npevs && ret >= 0; i++) 515 for (i = 0; i < npevs && ret >= 0; i++) {
467 ret = show_available_vars_at(fd, &pevs[i], max_vls, externs); 516 fd = open_vmlinux(module);
468 517 if (fd < 0) {
469 close(fd); 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 }
470 return ret; 525 return ret;
471} 526}
472 527
@@ -510,63 +565,105 @@ int show_line_range(struct line_range *lr __unused, const char *module __unused)
510 565
511int show_available_vars(struct perf_probe_event *pevs __unused, 566int show_available_vars(struct perf_probe_event *pevs __unused,
512 int npevs __unused, int max_vls __unused, 567 int npevs __unused, int max_vls __unused,
513 const char *module __unused, bool externs __unused) 568 const char *module __unused,
569 struct strfilter *filter __unused,
570 bool externs __unused)
514{ 571{
515 pr_warning("Debuginfo-analysis is not supported.\n"); 572 pr_warning("Debuginfo-analysis is not supported.\n");
516 return -ENOSYS; 573 return -ENOSYS;
517} 574}
518#endif 575#endif
519 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 */
520int parse_line_range_desc(const char *arg, struct line_range *lr) 597int parse_line_range_desc(const char *arg, struct line_range *lr)
521{ 598{
522 const char *ptr; 599 char *range, *file, *name = strdup(arg);
523 char *tmp; 600 int err;
524 /* 601
525 * <Syntax> 602 if (!name)
526 * SRC:SLN[+NUM|-ELN] 603 return -ENOMEM;
527 * FUNC[:SLN[+NUM|-ELN]] 604
528 */ 605 lr->start = 0;
529 ptr = strchr(arg, ':'); 606 lr->end = INT_MAX;
530 if (ptr) { 607
531 lr->start = (int)strtoul(ptr + 1, &tmp, 0); 608 range = strchr(name, ':');
532 if (*tmp == '+') { 609 if (range) {
533 lr->end = lr->start + (int)strtoul(tmp + 1, &tmp, 0); 610 *range++ = '\0';
534 lr->end--; /* 611
535 * Adjust the number of lines here. 612 err = parse_line_num(&range, &lr->start, "start line");
536 * If the number of lines == 1, the 613 if (err)
537 * the end of line should be equal to 614 goto err;
538 * the start of line. 615
539 */ 616 if (*range == '+' || *range == '-') {
540 } else if (*tmp == '-') 617 const char c = *range++;
541 lr->end = (int)strtoul(tmp + 1, &tmp, 0); 618
542 else 619 err = parse_line_num(&range, &lr->end, "end line");
543 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
544 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;
545 if (lr->start > lr->end) { 638 if (lr->start > lr->end) {
546 semantic_error("Start line must be smaller" 639 semantic_error("Start line must be smaller"
547 " than end line.\n"); 640 " than end line.\n");
548 return -EINVAL; 641 goto err;
549 } 642 }
550 if (*tmp != '\0') { 643 if (*range != '\0') {
551 semantic_error("Tailing with invalid character '%d'.\n", 644 semantic_error("Tailing with invalid str '%s'.\n", range);
552 *tmp); 645 goto err;
553 return -EINVAL;
554 } 646 }
555 tmp = strndup(arg, (ptr - arg));
556 } else {
557 tmp = strdup(arg);
558 lr->end = INT_MAX;
559 } 647 }
560 648
561 if (tmp == NULL) 649 file = strchr(name, '@');
562 return -ENOMEM; 650 if (file) {
563 651 *file = '\0';
564 if (strchr(tmp, '.')) 652 lr->file = strdup(++file);
565 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;
566 else 660 else
567 lr->function = tmp; 661 lr->function = name;
568 662
569 return 0; 663 return 0;
664err:
665 free(name);
666 return err;
570} 667}
571 668
572/* Check the name is good for event/group */ 669/* Check the name is good for event/group */
@@ -690,39 +787,40 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
690 787
691 /* Exclusion check */ 788 /* Exclusion check */
692 if (pp->lazy_line && pp->line) { 789 if (pp->lazy_line && pp->line) {
693 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");
694 return -EINVAL; 792 return -EINVAL;
695 } 793 }
696 794
697 if (pp->lazy_line && pp->offset) { 795 if (pp->lazy_line && pp->offset) {
698 semantic_error("Lazy pattern can't be used with offset."); 796 semantic_error("Lazy pattern can't be used with offset.\n");
699 return -EINVAL; 797 return -EINVAL;
700 } 798 }
701 799
702 if (pp->line && pp->offset) { 800 if (pp->line && pp->offset) {
703 semantic_error("Offset can't be used with line number."); 801 semantic_error("Offset can't be used with line number.\n");
704 return -EINVAL; 802 return -EINVAL;
705 } 803 }
706 804
707 if (!pp->line && !pp->lazy_line && pp->file && !pp->function) { 805 if (!pp->line && !pp->lazy_line && pp->file && !pp->function) {
708 semantic_error("File always requires line number or " 806 semantic_error("File always requires line number or "
709 "lazy pattern."); 807 "lazy pattern.\n");
710 return -EINVAL; 808 return -EINVAL;
711 } 809 }
712 810
713 if (pp->offset && !pp->function) { 811 if (pp->offset && !pp->function) {
714 semantic_error("Offset requires an entry function."); 812 semantic_error("Offset requires an entry function.\n");
715 return -EINVAL; 813 return -EINVAL;
716 } 814 }
717 815
718 if (pp->retprobe && !pp->function) { 816 if (pp->retprobe && !pp->function) {
719 semantic_error("Return probe requires an entry function."); 817 semantic_error("Return probe requires an entry function.\n");
720 return -EINVAL; 818 return -EINVAL;
721 } 819 }
722 820
723 if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe) { 821 if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe) {
724 semantic_error("Offset/Line/Lazy pattern can't be used with " 822 semantic_error("Offset/Line/Lazy pattern can't be used with "
725 "return probe."); 823 "return probe.\n");
726 return -EINVAL; 824 return -EINVAL;
727 } 825 }
728 826
@@ -996,7 +1094,7 @@ int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len)
996 1094
997 return tmp - buf; 1095 return tmp - buf;
998error: 1096error:
999 pr_debug("Failed to synthesize perf probe argument: %s", 1097 pr_debug("Failed to synthesize perf probe argument: %s\n",
1000 strerror(-ret)); 1098 strerror(-ret));
1001 return ret; 1099 return ret;
1002} 1100}
@@ -1024,13 +1122,13 @@ static char *synthesize_perf_probe_point(struct perf_probe_point *pp)
1024 goto error; 1122 goto error;
1025 } 1123 }
1026 if (pp->file) { 1124 if (pp->file) {
1027 len = strlen(pp->file) - 31; 1125 tmp = pp->file;
1028 if (len < 0) 1126 len = strlen(tmp);
1029 len = 0; 1127 if (len > 30) {
1030 tmp = strchr(pp->file + len, '/'); 1128 tmp = strchr(pp->file + len - 30, '/');
1031 if (!tmp) 1129 tmp = tmp ? tmp + 1 : pp->file + len - 30;
1032 tmp = pp->file + len; 1130 }
1033 ret = e_snprintf(file, 32, "@%s", tmp + 1); 1131 ret = e_snprintf(file, 32, "@%s", tmp);
1034 if (ret <= 0) 1132 if (ret <= 0)
1035 goto error; 1133 goto error;
1036 } 1134 }
@@ -1046,7 +1144,7 @@ static char *synthesize_perf_probe_point(struct perf_probe_point *pp)
1046 1144
1047 return buf; 1145 return buf;
1048error: 1146error:
1049 pr_debug("Failed to synthesize perf probe point: %s", 1147 pr_debug("Failed to synthesize perf probe point: %s\n",
1050 strerror(-ret)); 1148 strerror(-ret));
1051 if (buf) 1149 if (buf)
1052 free(buf); 1150 free(buf);
@@ -1731,9 +1829,12 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
1731 } 1829 }
1732 1830
1733 /* Loop 2: add all events */ 1831 /* Loop 2: add all events */
1734 for (i = 0; i < npevs && ret >= 0; i++) 1832 for (i = 0; i < npevs; i++) {
1735 ret = __add_probe_trace_events(pkgs[i].pev, pkgs[i].tevs, 1833 ret = __add_probe_trace_events(pkgs[i].pev, pkgs[i].tevs,
1736 pkgs[i].ntevs, force_add); 1834 pkgs[i].ntevs, force_add);
1835 if (ret < 0)
1836 break;
1837 }
1737end: 1838end:
1738 /* Loop 3: cleanup and free trace events */ 1839 /* Loop 3: cleanup and free trace events */
1739 for (i = 0; i < npevs; i++) { 1840 for (i = 0; i < npevs; i++) {
@@ -1787,7 +1888,7 @@ static int del_trace_probe_event(int fd, const char *group,
1787 1888
1788 ret = e_snprintf(buf, 128, "%s:%s", group, event); 1889 ret = e_snprintf(buf, 128, "%s:%s", group, event);
1789 if (ret < 0) { 1890 if (ret < 0) {
1790 pr_err("Failed to copy event."); 1891 pr_err("Failed to copy event.\n");
1791 return ret; 1892 return ret;
1792 } 1893 }
1793 1894
@@ -1859,4 +1960,46 @@ int del_perf_probe_events(struct strlist *dellist)
1859 1960
1860 return ret; 1961 return ret;
1861} 1962}
1963/* TODO: don't use a global variable for filter ... */
1964static struct strfilter *available_func_filter;
1862 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}
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 5accbedfea37..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
@@ -126,7 +127,8 @@ extern int show_perf_probe_events(void);
126extern int show_line_range(struct line_range *lr, const char *module); 127extern int show_line_range(struct line_range *lr, const char *module);
127extern int show_available_vars(struct perf_probe_event *pevs, int npevs, 128extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
128 int max_probe_points, const char *module, 129 int max_probe_points, const char *module,
129 bool externs); 130 struct strfilter *filter, bool externs);
131extern int show_available_funcs(const char *module, struct strfilter *filter);
130 132
131 133
132/* 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 3991d73d1cff..b7c85ce466a1 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"
@@ -117,28 +118,6 @@ static void line_list__free(struct list_head *head)
117} 118}
118 119
119/* Dwarf FL wrappers */ 120/* Dwarf FL wrappers */
120
121static int __linux_kernel_find_elf(Dwfl_Module *mod,
122 void **userdata,
123 const char *module_name,
124 Dwarf_Addr base,
125 char **file_name, Elf **elfp)
126{
127 int fd;
128 const char *path = kernel_get_module_path(module_name);
129
130 if (path) {
131 fd = open(path, O_RDONLY);
132 if (fd >= 0) {
133 *file_name = strdup(path);
134 return fd;
135 }
136 }
137 /* If failed, try to call standard method */
138 return dwfl_linux_kernel_find_elf(mod, userdata, module_name, base,
139 file_name, elfp);
140}
141
142static char *debuginfo_path; /* Currently dummy */ 121static char *debuginfo_path; /* Currently dummy */
143 122
144static const Dwfl_Callbacks offline_callbacks = { 123static const Dwfl_Callbacks offline_callbacks = {
@@ -151,14 +130,6 @@ static const Dwfl_Callbacks offline_callbacks = {
151 .find_elf = dwfl_build_id_find_elf, 130 .find_elf = dwfl_build_id_find_elf,
152}; 131};
153 132
154static const Dwfl_Callbacks kernel_callbacks = {
155 .find_debuginfo = dwfl_standard_find_debuginfo,
156 .debuginfo_path = &debuginfo_path,
157
158 .find_elf = __linux_kernel_find_elf,
159 .section_address = dwfl_linux_kernel_module_section_address,
160};
161
162/* Get a Dwarf from offline image */ 133/* Get a Dwarf from offline image */
163static Dwarf *dwfl_init_offline_dwarf(int fd, Dwfl **dwflp, Dwarf_Addr *bias) 134static Dwarf *dwfl_init_offline_dwarf(int fd, Dwfl **dwflp, Dwarf_Addr *bias)
164{ 135{
@@ -185,6 +156,38 @@ error:
185 return dbg; 156 return dbg;
186} 157}
187 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
188/* Get a Dwarf from live kernel image */ 191/* Get a Dwarf from live kernel image */
189static Dwarf *dwfl_init_live_kernel_dwarf(Dwarf_Addr addr, Dwfl **dwflp, 192static Dwarf *dwfl_init_live_kernel_dwarf(Dwarf_Addr addr, Dwfl **dwflp,
190 Dwarf_Addr *bias) 193 Dwarf_Addr *bias)
@@ -205,11 +208,34 @@ static Dwarf *dwfl_init_live_kernel_dwarf(Dwarf_Addr addr, Dwfl **dwflp,
205 dbg = dwfl_addrdwarf(*dwflp, addr, bias); 208 dbg = dwfl_addrdwarf(*dwflp, addr, bias);
206 /* Here, check whether we could get a real dwarf */ 209 /* Here, check whether we could get a real dwarf */
207 if (!dbg) { 210 if (!dbg) {
211 pr_debug("Failed to find kernel dwarf at %lx\n",
212 (unsigned long)addr);
208 dwfl_end(*dwflp); 213 dwfl_end(*dwflp);
209 *dwflp = NULL; 214 *dwflp = NULL;
210 } 215 }
211 return dbg; 216 return dbg;
212} 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
213 239
214/* Dwarf wrappers */ 240/* Dwarf wrappers */
215 241
@@ -247,6 +273,25 @@ static const char *cu_get_comp_dir(Dwarf_Die *cu_die)
247 return dwarf_formstring(&attr); 273 return dwarf_formstring(&attr);
248} 274}
249 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
250/* Compare diename and tname */ 295/* Compare diename and tname */
251static bool die_compare_name(Dwarf_Die *dw_die, const char *tname) 296static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
252{ 297{
@@ -255,6 +300,19 @@ static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
255 return name ? (strcmp(tname, name) == 0) : false; 300 return name ? (strcmp(tname, name) == 0) : false;
256} 301}
257 302
303/* Get callsite line number of inline-function instance */
304static int die_get_call_lineno(Dwarf_Die *in_die)
305{
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
258/* Get type die */ 316/* Get type die */
259static Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) 317static Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
260{ 318{
@@ -295,13 +353,23 @@ static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
295 return vr_die; 353 return vr_die;
296} 354}
297 355
298static bool die_is_signed_type(Dwarf_Die *tp_die) 356static int die_get_attr_udata(Dwarf_Die *tp_die, unsigned int attr_name,
357 Dwarf_Word *result)
299{ 358{
300 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{
301 Dwarf_Word ret; 370 Dwarf_Word ret;
302 371
303 if (dwarf_attr(tp_die, DW_AT_encoding, &attr) == NULL || 372 if (die_get_attr_udata(tp_die, DW_AT_encoding, &ret))
304 dwarf_formudata(&attr, &ret) != 0)
305 return false; 373 return false;
306 374
307 return (ret == DW_ATE_signed_char || ret == DW_ATE_signed || 375 return (ret == DW_ATE_signed_char || ret == DW_ATE_signed ||
@@ -310,11 +378,29 @@ static bool die_is_signed_type(Dwarf_Die *tp_die)
310 378
311static int die_get_byte_size(Dwarf_Die *tp_die) 379static int die_get_byte_size(Dwarf_Die *tp_die)
312{ 380{
313 Dwarf_Attribute attr;
314 Dwarf_Word ret; 381 Dwarf_Word ret;
315 382
316 if (dwarf_attr(tp_die, DW_AT_byte_size, &attr) == NULL || 383 if (die_get_attr_udata(tp_die, DW_AT_byte_size, &ret))
317 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))
318 return 0; 404 return 0;
319 405
320 return (int)ret; 406 return (int)ret;
@@ -430,7 +516,165 @@ static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data)
430static 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,
431 Dwarf_Die *die_mem) 517 Dwarf_Die *die_mem)
432{ 518{
433 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;
599}
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;
434} 678}
435 679
436struct __find_variable_param { 680struct __find_variable_param {
@@ -627,8 +871,8 @@ static_var:
627 regs = get_arch_regstr(regn); 871 regs = get_arch_regstr(regn);
628 if (!regs) { 872 if (!regs) {
629 /* This should be a bug in DWARF or this tool */ 873 /* This should be a bug in DWARF or this tool */
630 pr_warning("Mapping for DWARF register number %u " 874 pr_warning("Mapping for the register number %u "
631 "missing on this architecture.", regn); 875 "missing on this architecture.\n", regn);
632 return -ERANGE; 876 return -ERANGE;
633 } 877 }
634 878
@@ -644,6 +888,8 @@ static_var:
644 return 0; 888 return 0;
645} 889}
646 890
891#define BYTES_TO_BITS(nb) ((nb) * BITS_PER_LONG / sizeof(long))
892
647static int convert_variable_type(Dwarf_Die *vr_die, 893static int convert_variable_type(Dwarf_Die *vr_die,
648 struct probe_trace_arg *tvar, 894 struct probe_trace_arg *tvar,
649 const char *cast) 895 const char *cast)
@@ -660,6 +906,14 @@ static int convert_variable_type(Dwarf_Die *vr_die,
660 return (tvar->type == NULL) ? -ENOMEM : 0; 906 return (tvar->type == NULL) ? -ENOMEM : 0;
661 } 907 }
662 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
663 if (die_get_real_type(vr_die, &type) == NULL) { 917 if (die_get_real_type(vr_die, &type) == NULL) {
664 pr_warning("Failed to get a type information of %s.\n", 918 pr_warning("Failed to get a type information of %s.\n",
665 dwarf_diename(vr_die)); 919 dwarf_diename(vr_die));
@@ -674,13 +928,14 @@ static int convert_variable_type(Dwarf_Die *vr_die,
674 if (ret != DW_TAG_pointer_type && 928 if (ret != DW_TAG_pointer_type &&
675 ret != DW_TAG_array_type) { 929 ret != DW_TAG_array_type) {
676 pr_warning("Failed to cast into string: " 930 pr_warning("Failed to cast into string: "
677 "%s(%s) is not a pointer nor array.", 931 "%s(%s) is not a pointer nor array.\n",
678 dwarf_diename(vr_die), dwarf_diename(&type)); 932 dwarf_diename(vr_die), dwarf_diename(&type));
679 return -EINVAL; 933 return -EINVAL;
680 } 934 }
681 if (ret == DW_TAG_pointer_type) { 935 if (ret == DW_TAG_pointer_type) {
682 if (die_get_real_type(&type, &type) == NULL) { 936 if (die_get_real_type(&type, &type) == NULL) {
683 pr_warning("Failed to get a type information."); 937 pr_warning("Failed to get a type"
938 " information.\n");
684 return -ENOENT; 939 return -ENOENT;
685 } 940 }
686 while (*ref_ptr) 941 while (*ref_ptr)
@@ -695,7 +950,7 @@ static int convert_variable_type(Dwarf_Die *vr_die,
695 if (!die_compare_name(&type, "char") && 950 if (!die_compare_name(&type, "char") &&
696 !die_compare_name(&type, "unsigned char")) { 951 !die_compare_name(&type, "unsigned char")) {
697 pr_warning("Failed to cast into string: " 952 pr_warning("Failed to cast into string: "
698 "%s is not (unsigned) char *.", 953 "%s is not (unsigned) char *.\n",
699 dwarf_diename(vr_die)); 954 dwarf_diename(vr_die));
700 return -EINVAL; 955 return -EINVAL;
701 } 956 }
@@ -703,29 +958,31 @@ static int convert_variable_type(Dwarf_Die *vr_die,
703 return (tvar->type == NULL) ? -ENOMEM : 0; 958 return (tvar->type == NULL) ? -ENOMEM : 0;
704 } 959 }
705 960
706 ret = die_get_byte_size(&type) * 8; 961 ret = BYTES_TO_BITS(die_get_byte_size(&type));
707 if (ret) { 962 if (!ret)
708 /* Check the bitwidth */ 963 /* No size ... try to use default type */
709 if (ret > MAX_BASIC_TYPE_BITS) { 964 return 0;
710 pr_info("%s exceeds max-bitwidth."
711 " Cut down to %d bits.\n",
712 dwarf_diename(&type), MAX_BASIC_TYPE_BITS);
713 ret = MAX_BASIC_TYPE_BITS;
714 }
715 965
716 ret = snprintf(buf, 16, "%c%d", 966 /* Check the bitwidth */
717 die_is_signed_type(&type) ? 's' : 'u', ret); 967 if (ret > MAX_BASIC_TYPE_BITS) {
718 if (ret < 0 || ret >= 16) { 968 pr_info("%s exceeds max-bitwidth. Cut down to %d bits.\n",
719 if (ret >= 16) 969 dwarf_diename(&type), MAX_BASIC_TYPE_BITS);
720 ret = -E2BIG; 970 ret = MAX_BASIC_TYPE_BITS;
721 pr_warning("Failed to convert variable type: %s\n", 971 }
722 strerror(-ret)); 972 ret = snprintf(buf, 16, "%c%d",
723 return ret; 973 die_is_signed_type(&type) ? 's' : 'u', ret);
724 } 974
725 tvar->type = strdup(buf); 975formatted:
726 if (tvar->type == NULL) 976 if (ret < 0 || ret >= 16) {
727 return -ENOMEM; 977 if (ret >= 16)
978 ret = -E2BIG;
979 pr_warning("Failed to convert variable type: %s\n",
980 strerror(-ret));
981 return ret;
728 } 982 }
983 tvar->type = strdup(buf);
984 if (tvar->type == NULL)
985 return -ENOMEM;
729 return 0; 986 return 0;
730} 987}
731 988
@@ -805,8 +1062,8 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
805 return -EINVAL; 1062 return -EINVAL;
806 } 1063 }
807 if (field->name[0] == '[') { 1064 if (field->name[0] == '[') {
808 pr_err("Semantic error: %s is not a pointor nor array.", 1065 pr_err("Semantic error: %s is not a pointor"
809 varname); 1066 " nor array.\n", varname);
810 return -EINVAL; 1067 return -EINVAL;
811 } 1068 }
812 if (field->ref) { 1069 if (field->ref) {
@@ -953,7 +1210,7 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr,
953 name = dwarf_diename(sp_die); 1210 name = dwarf_diename(sp_die);
954 if (name) { 1211 if (name) {
955 if (dwarf_entrypc(sp_die, &eaddr) != 0) { 1212 if (dwarf_entrypc(sp_die, &eaddr) != 0) {
956 pr_warning("Failed to get entry pc of %s\n", 1213 pr_warning("Failed to get entry address of %s\n",
957 dwarf_diename(sp_die)); 1214 dwarf_diename(sp_die));
958 return -ENOENT; 1215 return -ENOENT;
959 } 1216 }
@@ -969,7 +1226,7 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr,
969 if (retprobe) { 1226 if (retprobe) {
970 if (eaddr != paddr) { 1227 if (eaddr != paddr) {
971 pr_warning("Return probe must be on the head of" 1228 pr_warning("Return probe must be on the head of"
972 " a real function\n"); 1229 " a real function.\n");
973 return -EINVAL; 1230 return -EINVAL;
974 } 1231 }
975 tp->retprobe = true; 1232 tp->retprobe = true;
@@ -1008,7 +1265,7 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf)
1008 Dwarf_Frame *frame; 1265 Dwarf_Frame *frame;
1009 if (dwarf_cfi_addrframe(pf->cfi, pf->addr, &frame) != 0 || 1266 if (dwarf_cfi_addrframe(pf->cfi, pf->addr, &frame) != 0 ||
1010 dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) { 1267 dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) {
1011 pr_warning("Failed to get CFA on 0x%jx\n", 1268 pr_warning("Failed to get call frame on 0x%jx\n",
1012 (uintmax_t)pf->addr); 1269 (uintmax_t)pf->addr);
1013 return -ENOENT; 1270 return -ENOENT;
1014 } 1271 }
@@ -1024,157 +1281,102 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf)
1024 return ret; 1281 return ret;
1025} 1282}
1026 1283
1027/* Find probe point from its line number */ 1284static int probe_point_line_walker(const char *fname, int lineno,
1028static int find_probe_point_by_line(struct probe_finder *pf) 1285 Dwarf_Addr addr, void *data)
1029{ 1286{
1030 Dwarf_Lines *lines; 1287 struct probe_finder *pf = data;
1031 Dwarf_Line *line; 1288 int ret;
1032 size_t nlines, i;
1033 Dwarf_Addr addr;
1034 int lineno;
1035 int ret = 0;
1036
1037 if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) {
1038 pr_warning("No source lines found in this CU.\n");
1039 return -ENOENT;
1040 }
1041 1289
1042 for (i = 0; i < nlines && ret == 0; i++) { 1290 if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0)
1043 line = dwarf_onesrcline(lines, i); 1291 return 0;
1044 if (dwarf_lineno(line, &lineno) != 0 ||
1045 lineno != pf->lno)
1046 continue;
1047 1292
1048 /* TODO: Get fileno from line, but how? */ 1293 pf->addr = addr;
1049 if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0) 1294 ret = call_probe_finder(NULL, pf);
1050 continue;
1051 1295
1052 if (dwarf_lineaddr(line, &addr) != 0) { 1296 /* Continue if no error, because the line will be in inline function */
1053 pr_warning("Failed to get the address of the line.\n"); 1297 return ret < 0 ? ret : 0;
1054 return -ENOENT; 1298}
1055 }
1056 pr_debug("Probe line found: line[%d]:%d addr:0x%jx\n",
1057 (int)i, lineno, (uintmax_t)addr);
1058 pf->addr = addr;
1059 1299
1060 ret = call_probe_finder(NULL, pf); 1300/* Find probe point from its line number */
1061 /* Continuing, because target line might be inlined. */ 1301static int find_probe_point_by_line(struct probe_finder *pf)
1062 } 1302{
1063 return ret; 1303 return die_walk_lines(&pf->cu_die, probe_point_line_walker, pf);
1064} 1304}
1065 1305
1066/* Find lines which match lazy pattern */ 1306/* Find lines which match lazy pattern */
1067static int find_lazy_match_lines(struct list_head *head, 1307static int find_lazy_match_lines(struct list_head *head,
1068 const char *fname, const char *pat) 1308 const char *fname, const char *pat)
1069{ 1309{
1070 char *fbuf, *p1, *p2; 1310 FILE *fp;
1071 int fd, line, nlines = -1; 1311 char *line = NULL;
1072 struct stat st; 1312 size_t line_len;
1073 1313 ssize_t len;
1074 fd = open(fname, O_RDONLY); 1314 int count = 0, linenum = 1;
1075 if (fd < 0) { 1315
1076 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));
1077 return -errno; 1319 return -errno;
1078 } 1320 }
1079 1321
1080 if (fstat(fd, &st) < 0) { 1322 while ((len = getline(&line, &line_len, fp)) > 0) {
1081 pr_warning("Failed to get the size of %s: %s\n", 1323
1082 fname, strerror(errno)); 1324 if (line[len - 1] == '\n')
1083 nlines = -errno; 1325 line[len - 1] = '\0';
1084 goto out_close; 1326
1085 } 1327 if (strlazymatch(line, pat)) {
1086 1328 line_list__add_line(head, linenum);
1087 nlines = -ENOMEM; 1329 count++;
1088 fbuf = malloc(st.st_size + 2);
1089 if (fbuf == NULL)
1090 goto out_close;
1091 if (read(fd, fbuf, st.st_size) < 0) {
1092 pr_warning("Failed to read %s: %s\n", fname, strerror(errno));
1093 nlines = -errno;
1094 goto out_free_fbuf;
1095 }
1096 fbuf[st.st_size] = '\n'; /* Dummy line */
1097 fbuf[st.st_size + 1] = '\0';
1098 p1 = fbuf;
1099 line = 1;
1100 nlines = 0;
1101 while ((p2 = strchr(p1, '\n')) != NULL) {
1102 *p2 = '\0';
1103 if (strlazymatch(p1, pat)) {
1104 line_list__add_line(head, line);
1105 nlines++;
1106 } 1330 }
1107 line++; 1331 linenum++;
1108 p1 = p2 + 1;
1109 } 1332 }
1110out_free_fbuf: 1333
1111 free(fbuf); 1334 if (ferror(fp))
1112out_close: 1335 count = -errno;
1113 close(fd); 1336 free(line);
1114 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;
1115} 1364}
1116 1365
1117/* Find probe points from lazy pattern */ 1366/* Find probe points from lazy pattern */
1118static 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)
1119{ 1368{
1120 Dwarf_Lines *lines;
1121 Dwarf_Line *line;
1122 size_t nlines, i;
1123 Dwarf_Addr addr;
1124 Dwarf_Die die_mem;
1125 int lineno;
1126 int ret = 0; 1369 int ret = 0;
1127 1370
1128 if (list_empty(&pf->lcache)) { 1371 if (list_empty(&pf->lcache)) {
1129 /* Matching lazy line pattern */ 1372 /* Matching lazy line pattern */
1130 ret = find_lazy_match_lines(&pf->lcache, pf->fname, 1373 ret = find_lazy_match_lines(&pf->lcache, pf->fname,
1131 pf->pev->point.lazy_line); 1374 pf->pev->point.lazy_line);
1132 if (ret == 0) { 1375 if (ret <= 0)
1133 pr_debug("No matched lines found in %s.\n", pf->fname);
1134 return 0;
1135 } else if (ret < 0)
1136 return ret; 1376 return ret;
1137 } 1377 }
1138 1378
1139 if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) { 1379 return die_walk_lines(sp_die, probe_point_lazy_walker, pf);
1140 pr_warning("No source lines found in this CU.\n");
1141 return -ENOENT;
1142 }
1143
1144 for (i = 0; i < nlines && ret >= 0; i++) {
1145 line = dwarf_onesrcline(lines, i);
1146
1147 if (dwarf_lineno(line, &lineno) != 0 ||
1148 !line_list__has_line(&pf->lcache, lineno))
1149 continue;
1150
1151 /* TODO: Get fileno from line, but how? */
1152 if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
1153 continue;
1154
1155 if (dwarf_lineaddr(line, &addr) != 0) {
1156 pr_debug("Failed to get the address of line %d.\n",
1157 lineno);
1158 continue;
1159 }
1160 if (sp_die) {
1161 /* Address filtering 1: does sp_die include addr? */
1162 if (!dwarf_haspc(sp_die, addr))
1163 continue;
1164 /* Address filtering 2: No child include addr? */
1165 if (die_find_inlinefunc(sp_die, addr, &die_mem))
1166 continue;
1167 }
1168
1169 pr_debug("Probe line found: line[%d]:%d addr:0x%llx\n",
1170 (int)i, lineno, (unsigned long long)addr);
1171 pf->addr = addr;
1172
1173 ret = call_probe_finder(sp_die, pf);
1174 /* Continuing, because target line might be inlined. */
1175 }
1176 /* TODO: deallocate lines, but how? */
1177 return ret;
1178} 1380}
1179 1381
1180/* Callback parameter with return value */ 1382/* Callback parameter with return value */
@@ -1195,7 +1397,7 @@ static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
1195 else { 1397 else {
1196 /* Get probe address */ 1398 /* Get probe address */
1197 if (dwarf_entrypc(in_die, &addr) != 0) { 1399 if (dwarf_entrypc(in_die, &addr) != 0) {
1198 pr_warning("Failed to get entry pc of %s.\n", 1400 pr_warning("Failed to get entry address of %s.\n",
1199 dwarf_diename(in_die)); 1401 dwarf_diename(in_die));
1200 param->retval = -ENOENT; 1402 param->retval = -ENOENT;
1201 return DWARF_CB_ABORT; 1403 return DWARF_CB_ABORT;
@@ -1225,6 +1427,10 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
1225 !die_compare_name(sp_die, pp->function)) 1427 !die_compare_name(sp_die, pp->function))
1226 return DWARF_CB_OK; 1428 return DWARF_CB_OK;
1227 1429
1430 /* Check declared file */
1431 if (pp->file && strtailcmp(pp->file, dwarf_decl_file(sp_die)))
1432 return DWARF_CB_OK;
1433
1228 pf->fname = dwarf_decl_file(sp_die); 1434 pf->fname = dwarf_decl_file(sp_die);
1229 if (pp->line) { /* Function relative line */ 1435 if (pp->line) { /* Function relative line */
1230 dwarf_decl_line(sp_die, &pf->lno); 1436 dwarf_decl_line(sp_die, &pf->lno);
@@ -1236,8 +1442,8 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
1236 param->retval = find_probe_point_lazy(sp_die, pf); 1442 param->retval = find_probe_point_lazy(sp_die, pf);
1237 else { 1443 else {
1238 if (dwarf_entrypc(sp_die, &pf->addr) != 0) { 1444 if (dwarf_entrypc(sp_die, &pf->addr) != 0) {
1239 pr_warning("Failed to get entry pc of %s.\n", 1445 pr_warning("Failed to get entry address of "
1240 dwarf_diename(sp_die)); 1446 "%s.\n", dwarf_diename(sp_die));
1241 param->retval = -ENOENT; 1447 param->retval = -ENOENT;
1242 return DWARF_CB_ABORT; 1448 return DWARF_CB_ABORT;
1243 } 1449 }
@@ -1279,8 +1485,9 @@ static int find_probes(int fd, struct probe_finder *pf)
1279 1485
1280 dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias); 1486 dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias);
1281 if (!dbg) { 1487 if (!dbg) {
1282 pr_warning("No dwarf info found in the vmlinux - " 1488 pr_warning("No debug information found in the vmlinux - "
1283 "please rebuild with CONFIG_DEBUG_INFO=y.\n"); 1489 "please rebuild with CONFIG_DEBUG_INFO=y.\n");
1490 close(fd); /* Without dwfl_end(), fd isn't closed. */
1284 return -EBADF; 1491 return -EBADF;
1285 } 1492 }
1286 1493
@@ -1292,8 +1499,7 @@ static int find_probes(int fd, struct probe_finder *pf)
1292 off = 0; 1499 off = 0;
1293 line_list__init(&pf->lcache); 1500 line_list__init(&pf->lcache);
1294 /* Loop on CUs (Compilation Unit) */ 1501 /* Loop on CUs (Compilation Unit) */
1295 while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) && 1502 while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL)) {
1296 ret >= 0) {
1297 /* Get the DIE(Debugging Information Entry) of this CU */ 1503 /* Get the DIE(Debugging Information Entry) of this CU */
1298 diep = dwarf_offdie(dbg, off + cuhl, &pf->cu_die); 1504 diep = dwarf_offdie(dbg, off + cuhl, &pf->cu_die);
1299 if (!diep) 1505 if (!diep)
@@ -1314,6 +1520,8 @@ static int find_probes(int fd, struct probe_finder *pf)
1314 pf->lno = pp->line; 1520 pf->lno = pp->line;
1315 ret = find_probe_point_by_line(pf); 1521 ret = find_probe_point_by_line(pf);
1316 } 1522 }
1523 if (ret < 0)
1524 break;
1317 } 1525 }
1318 off = noff; 1526 off = noff;
1319 } 1527 }
@@ -1515,16 +1723,14 @@ int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt)
1515 Dwarf_Die cudie, spdie, indie; 1723 Dwarf_Die cudie, spdie, indie;
1516 Dwarf *dbg = NULL; 1724 Dwarf *dbg = NULL;
1517 Dwfl *dwfl = NULL; 1725 Dwfl *dwfl = NULL;
1518 Dwarf_Line *line; 1726 Dwarf_Addr _addr, baseaddr, bias = 0;
1519 Dwarf_Addr laddr, eaddr, bias = 0; 1727 const char *fname = NULL, *func = NULL, *tmp;
1520 const char *tmp; 1728 int baseline = 0, lineno = 0, ret = 0;
1521 int lineno, ret = 0;
1522 bool found = false;
1523 1729
1524 /* Open the live linux kernel */ 1730 /* Open the live linux kernel */
1525 dbg = dwfl_init_live_kernel_dwarf(addr, &dwfl, &bias); 1731 dbg = dwfl_init_live_kernel_dwarf(addr, &dwfl, &bias);
1526 if (!dbg) { 1732 if (!dbg) {
1527 pr_warning("No dwarf info found in the vmlinux - " 1733 pr_warning("No debug information found in the vmlinux - "
1528 "please rebuild with CONFIG_DEBUG_INFO=y.\n"); 1734 "please rebuild with CONFIG_DEBUG_INFO=y.\n");
1529 ret = -EINVAL; 1735 ret = -EINVAL;
1530 goto end; 1736 goto end;
@@ -1534,73 +1740,85 @@ int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt)
1534 addr += bias; 1740 addr += bias;
1535 /* Find cu die */ 1741 /* Find cu die */
1536 if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr - bias, &cudie)) { 1742 if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr - bias, &cudie)) {
1537 pr_warning("No CU DIE is found at %lx\n", addr); 1743 pr_warning("Failed to find debug information for address %lx\n",
1744 addr);
1538 ret = -EINVAL; 1745 ret = -EINVAL;
1539 goto end; 1746 goto end;
1540 } 1747 }
1541 1748
1542 /* Find a corresponding line */ 1749 /* Find a corresponding line (filename and lineno) */
1543 line = dwarf_getsrc_die(&cudie, (Dwarf_Addr)addr); 1750 cu_find_lineinfo(&cudie, addr, &fname, &lineno);
1544 if (line) { 1751 /* Don't care whether it failed or not */
1545 if (dwarf_lineaddr(line, &laddr) == 0 &&
1546 (Dwarf_Addr)addr == laddr &&
1547 dwarf_lineno(line, &lineno) == 0) {
1548 tmp = dwarf_linesrc(line, NULL, NULL);
1549 if (tmp) {
1550 ppt->line = lineno;
1551 ppt->file = strdup(tmp);
1552 if (ppt->file == NULL) {
1553 ret = -ENOMEM;
1554 goto end;
1555 }
1556 found = true;
1557 }
1558 }
1559 }
1560 1752
1561 /* Find a corresponding function */ 1753 /* Find a corresponding function (name, baseline and baseaddr) */
1562 if (die_find_real_subprogram(&cudie, (Dwarf_Addr)addr, &spdie)) { 1754 if (die_find_real_subprogram(&cudie, (Dwarf_Addr)addr, &spdie)) {
1755 /* Get function entry information */
1563 tmp = dwarf_diename(&spdie); 1756 tmp = dwarf_diename(&spdie);
1564 if (!tmp || dwarf_entrypc(&spdie, &eaddr) != 0) 1757 if (!tmp ||
1565 goto end; 1758 dwarf_entrypc(&spdie, &baseaddr) != 0 ||
1566 1759 dwarf_decl_line(&spdie, &baseline) != 0)
1567 if (ppt->line) { 1760 goto post;
1568 if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr, 1761 func = tmp;
1569 &indie)) { 1762
1570 /* addr in an inline function */ 1763 if (addr == (unsigned long)baseaddr)
1764 /* Function entry - Relative line number is 0 */
1765 lineno = baseline;
1766 else if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr,
1767 &indie)) {
1768 if (dwarf_entrypc(&indie, &_addr) == 0 &&
1769 _addr == addr)
1770 /*
1771 * addr is at an inline function entry.
1772 * In this case, lineno should be the call-site
1773 * line number.
1774 */
1775 lineno = die_get_call_lineno(&indie);
1776 else {
1777 /*
1778 * addr is in an inline function body.
1779 * Since lineno points one of the lines
1780 * of the inline function, baseline should
1781 * be the entry line of the inline function.
1782 */
1571 tmp = dwarf_diename(&indie); 1783 tmp = dwarf_diename(&indie);
1572 if (!tmp) 1784 if (tmp &&
1573 goto end; 1785 dwarf_decl_line(&spdie, &baseline) == 0)
1574 ret = dwarf_decl_line(&indie, &lineno); 1786 func = tmp;
1575 } else {
1576 if (eaddr == addr) { /* Function entry */
1577 lineno = ppt->line;
1578 ret = 0;
1579 } else
1580 ret = dwarf_decl_line(&spdie, &lineno);
1581 }
1582 if (ret == 0) {
1583 /* Make a relative line number */
1584 ppt->line -= lineno;
1585 goto found;
1586 } 1787 }
1587 } 1788 }
1588 /* We don't have a line number, let's use offset */ 1789 }
1589 ppt->offset = addr - (unsigned long)eaddr; 1790
1590found: 1791post:
1591 ppt->function = strdup(tmp); 1792 /* Make a relative line number or an offset */
1793 if (lineno)
1794 ppt->line = lineno - baseline;
1795 else if (func)
1796 ppt->offset = addr - (unsigned long)baseaddr;
1797
1798 /* Duplicate strings */
1799 if (func) {
1800 ppt->function = strdup(func);
1592 if (ppt->function == NULL) { 1801 if (ppt->function == NULL) {
1593 ret = -ENOMEM; 1802 ret = -ENOMEM;
1594 goto end; 1803 goto end;
1595 } 1804 }
1596 found = true;
1597 } 1805 }
1598 1806 if (fname) {
1807 ppt->file = strdup(fname);
1808 if (ppt->file == NULL) {
1809 if (ppt->function) {
1810 free(ppt->function);
1811 ppt->function = NULL;
1812 }
1813 ret = -ENOMEM;
1814 goto end;
1815 }
1816 }
1599end: 1817end:
1600 if (dwfl) 1818 if (dwfl)
1601 dwfl_end(dwfl); 1819 dwfl_end(dwfl);
1602 if (ret >= 0) 1820 if (ret == 0 && (fname || func))
1603 ret = found ? 1 : 0; 1821 ret = 1; /* Found a point */
1604 return ret; 1822 return ret;
1605} 1823}
1606 1824
@@ -1617,91 +1835,28 @@ static int line_range_add_line(const char *src, unsigned int lineno,
1617 return line_list__add_line(&lr->line_list, lineno); 1835 return line_list__add_line(&lr->line_list, lineno);
1618} 1836}
1619 1837
1620/* Search function declaration lines */ 1838static int line_range_walk_cb(const char *fname, int lineno,
1621static int line_range_funcdecl_cb(Dwarf_Die *sp_die, void *data) 1839 Dwarf_Addr addr __used,
1840 void *data)
1622{ 1841{
1623 struct dwarf_callback_param *param = data; 1842 struct line_finder *lf = data;
1624 struct line_finder *lf = param->data;
1625 const char *src;
1626 int lineno;
1627
1628 src = dwarf_decl_file(sp_die);
1629 if (src && strtailcmp(src, lf->fname) != 0)
1630 return DWARF_CB_OK;
1631 1843
1632 if (dwarf_decl_line(sp_die, &lineno) != 0 || 1844 if ((strtailcmp(fname, lf->fname) != 0) ||
1633 (lf->lno_s > lineno || lf->lno_e < lineno)) 1845 (lf->lno_s > lineno || lf->lno_e < lineno))
1634 return DWARF_CB_OK; 1846 return 0;
1635 1847
1636 param->retval = line_range_add_line(src, lineno, lf->lr); 1848 if (line_range_add_line(fname, lineno, lf->lr) < 0)
1637 if (param->retval < 0) 1849 return -EINVAL;
1638 return DWARF_CB_ABORT;
1639 return DWARF_CB_OK;
1640}
1641 1850
1642static int find_line_range_func_decl_lines(struct line_finder *lf) 1851 return 0;
1643{
1644 struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0};
1645 dwarf_getfuncs(&lf->cu_die, line_range_funcdecl_cb, &param, 0);
1646 return param.retval;
1647} 1852}
1648 1853
1649/* Find line range from its line number */ 1854/* Find line range from its line number */
1650static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) 1855static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
1651{ 1856{
1652 Dwarf_Lines *lines; 1857 int ret;
1653 Dwarf_Line *line;
1654 size_t nlines, i;
1655 Dwarf_Addr addr;
1656 int lineno, ret = 0;
1657 const char *src;
1658 Dwarf_Die die_mem;
1659
1660 line_list__init(&lf->lr->line_list);
1661 if (dwarf_getsrclines(&lf->cu_die, &lines, &nlines) != 0) {
1662 pr_warning("No source lines found in this CU.\n");
1663 return -ENOENT;
1664 }
1665
1666 /* Search probable lines on lines list */
1667 for (i = 0; i < nlines; i++) {
1668 line = dwarf_onesrcline(lines, i);
1669 if (dwarf_lineno(line, &lineno) != 0 ||
1670 (lf->lno_s > lineno || lf->lno_e < lineno))
1671 continue;
1672
1673 if (sp_die) {
1674 /* Address filtering 1: does sp_die include addr? */
1675 if (dwarf_lineaddr(line, &addr) != 0 ||
1676 !dwarf_haspc(sp_die, addr))
1677 continue;
1678
1679 /* Address filtering 2: No child include addr? */
1680 if (die_find_inlinefunc(sp_die, addr, &die_mem))
1681 continue;
1682 }
1683
1684 /* TODO: Get fileno from line, but how? */
1685 src = dwarf_linesrc(line, NULL, NULL);
1686 if (strtailcmp(src, lf->fname) != 0)
1687 continue;
1688
1689 ret = line_range_add_line(src, lineno, lf->lr);
1690 if (ret < 0)
1691 return ret;
1692 }
1693 1858
1694 /* 1859 ret = die_walk_lines(sp_die ?: &lf->cu_die, line_range_walk_cb, lf);
1695 * Dwarf lines doesn't include function declarations. We have to
1696 * check functions list or given function.
1697 */
1698 if (sp_die) {
1699 src = dwarf_decl_file(sp_die);
1700 if (src && dwarf_decl_line(sp_die, &lineno) == 0 &&
1701 (lf->lno_s <= lineno && lf->lno_e >= lineno))
1702 ret = line_range_add_line(src, lineno, lf->lr);
1703 } else
1704 ret = find_line_range_func_decl_lines(lf);
1705 1860
1706 /* Update status */ 1861 /* Update status */
1707 if (ret >= 0) 1862 if (ret >= 0)
@@ -1731,9 +1886,10 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
1731 struct line_finder *lf = param->data; 1886 struct line_finder *lf = param->data;
1732 struct line_range *lr = lf->lr; 1887 struct line_range *lr = lf->lr;
1733 1888
1734 pr_debug("find (%llx) %s\n", 1889 /* Check declared file */
1735 (unsigned long long)dwarf_dieoffset(sp_die), 1890 if (lr->file && strtailcmp(lr->file, dwarf_decl_file(sp_die)))
1736 dwarf_diename(sp_die)); 1891 return DWARF_CB_OK;
1892
1737 if (dwarf_tag(sp_die) == DW_TAG_subprogram && 1893 if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
1738 die_compare_name(sp_die, lr->function)) { 1894 die_compare_name(sp_die, lr->function)) {
1739 lf->fname = dwarf_decl_file(sp_die); 1895 lf->fname = dwarf_decl_file(sp_die);
@@ -1784,8 +1940,9 @@ int find_line_range(int fd, struct line_range *lr)
1784 1940
1785 dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias); 1941 dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias);
1786 if (!dbg) { 1942 if (!dbg) {
1787 pr_warning("No dwarf info found in the vmlinux - " 1943 pr_warning("No debug information found in the vmlinux - "
1788 "please rebuild with CONFIG_DEBUG_INFO=y.\n"); 1944 "please rebuild with CONFIG_DEBUG_INFO=y.\n");
1945 close(fd); /* Without dwfl_end(), fd isn't closed. */
1789 return -EBADF; 1946 return -EBADF;
1790 } 1947 }
1791 1948
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index bba69d455699..beaefc3c1223 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -34,9 +34,9 @@ extern int find_available_vars_at(int fd, struct perf_probe_event *pev,
34 bool externs); 34 bool externs);
35 35
36#include <dwarf.h> 36#include <dwarf.h>
37#include <libdw.h> 37#include <elfutils/libdw.h>
38#include <libdwfl.h> 38#include <elfutils/libdwfl.h>
39#include <version.h> 39#include <elfutils/version.h>
40 40
41struct probe_finder { 41struct probe_finder {
42 struct perf_probe_event *pev; /* Target probe event */ 42 struct perf_probe_event *pev; /* Target probe event */
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
new file mode 100644
index 000000000000..f5e38451fdc5
--- /dev/null
+++ b/tools/perf/util/python.c
@@ -0,0 +1,897 @@
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[] = {"sample_id_all", NULL, NULL};
678
679 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|i", kwlist,
680 &cpu, &sample_id_all))
681 return NULL;
682
683 event = perf_evlist__read_on_cpu(evlist, cpu);
684 if (event != NULL) {
685 struct perf_evsel *first;
686 PyObject *pyevent = pyrf_event__new(event);
687 struct pyrf_event *pevent = (struct pyrf_event *)pyevent;
688
689 if (pyevent == NULL)
690 return PyErr_NoMemory();
691
692 first = list_entry(evlist->entries.next, struct perf_evsel, node);
693 perf_event__parse_sample(event, first->attr.sample_type, sample_id_all,
694 &pevent->sample);
695 return pyevent;
696 }
697
698 Py_INCREF(Py_None);
699 return Py_None;
700}
701
702static PyMethodDef pyrf_evlist__methods[] = {
703 {
704 .ml_name = "mmap",
705 .ml_meth = (PyCFunction)pyrf_evlist__mmap,
706 .ml_flags = METH_VARARGS | METH_KEYWORDS,
707 .ml_doc = PyDoc_STR("mmap the file descriptor table.")
708 },
709 {
710 .ml_name = "poll",
711 .ml_meth = (PyCFunction)pyrf_evlist__poll,
712 .ml_flags = METH_VARARGS | METH_KEYWORDS,
713 .ml_doc = PyDoc_STR("poll the file descriptor table.")
714 },
715 {
716 .ml_name = "get_pollfd",
717 .ml_meth = (PyCFunction)pyrf_evlist__get_pollfd,
718 .ml_flags = METH_VARARGS | METH_KEYWORDS,
719 .ml_doc = PyDoc_STR("get the poll file descriptor table.")
720 },
721 {
722 .ml_name = "add",
723 .ml_meth = (PyCFunction)pyrf_evlist__add,
724 .ml_flags = METH_VARARGS | METH_KEYWORDS,
725 .ml_doc = PyDoc_STR("adds an event selector to the list.")
726 },
727 {
728 .ml_name = "read_on_cpu",
729 .ml_meth = (PyCFunction)pyrf_evlist__read_on_cpu,
730 .ml_flags = METH_VARARGS | METH_KEYWORDS,
731 .ml_doc = PyDoc_STR("reads an event.")
732 },
733 { .ml_name = NULL, }
734};
735
736static Py_ssize_t pyrf_evlist__length(PyObject *obj)
737{
738 struct pyrf_evlist *pevlist = (void *)obj;
739
740 return pevlist->evlist.nr_entries;
741}
742
743static PyObject *pyrf_evlist__item(PyObject *obj, Py_ssize_t i)
744{
745 struct pyrf_evlist *pevlist = (void *)obj;
746 struct perf_evsel *pos;
747
748 if (i >= pevlist->evlist.nr_entries)
749 return NULL;
750
751 list_for_each_entry(pos, &pevlist->evlist.entries, node)
752 if (i-- == 0)
753 break;
754
755 return Py_BuildValue("O", container_of(pos, struct pyrf_evsel, evsel));
756}
757
758static PySequenceMethods pyrf_evlist__sequence_methods = {
759 .sq_length = pyrf_evlist__length,
760 .sq_item = pyrf_evlist__item,
761};
762
763static char pyrf_evlist__doc[] = PyDoc_STR("perf event selector list object.");
764
765static PyTypeObject pyrf_evlist__type = {
766 PyVarObject_HEAD_INIT(NULL, 0)
767 .tp_name = "perf.evlist",
768 .tp_basicsize = sizeof(struct pyrf_evlist),
769 .tp_dealloc = (destructor)pyrf_evlist__delete,
770 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
771 .tp_as_sequence = &pyrf_evlist__sequence_methods,
772 .tp_doc = pyrf_evlist__doc,
773 .tp_methods = pyrf_evlist__methods,
774 .tp_init = (initproc)pyrf_evlist__init,
775};
776
777static int pyrf_evlist__setup_types(void)
778{
779 pyrf_evlist__type.tp_new = PyType_GenericNew;
780 return PyType_Ready(&pyrf_evlist__type);
781}
782
783static struct {
784 const char *name;
785 int value;
786} perf__constants[] = {
787 { "TYPE_HARDWARE", PERF_TYPE_HARDWARE },
788 { "TYPE_SOFTWARE", PERF_TYPE_SOFTWARE },
789 { "TYPE_TRACEPOINT", PERF_TYPE_TRACEPOINT },
790 { "TYPE_HW_CACHE", PERF_TYPE_HW_CACHE },
791 { "TYPE_RAW", PERF_TYPE_RAW },
792 { "TYPE_BREAKPOINT", PERF_TYPE_BREAKPOINT },
793
794 { "COUNT_HW_CPU_CYCLES", PERF_COUNT_HW_CPU_CYCLES },
795 { "COUNT_HW_INSTRUCTIONS", PERF_COUNT_HW_INSTRUCTIONS },
796 { "COUNT_HW_CACHE_REFERENCES", PERF_COUNT_HW_CACHE_REFERENCES },
797 { "COUNT_HW_CACHE_MISSES", PERF_COUNT_HW_CACHE_MISSES },
798 { "COUNT_HW_BRANCH_INSTRUCTIONS", PERF_COUNT_HW_BRANCH_INSTRUCTIONS },
799 { "COUNT_HW_BRANCH_MISSES", PERF_COUNT_HW_BRANCH_MISSES },
800 { "COUNT_HW_BUS_CYCLES", PERF_COUNT_HW_BUS_CYCLES },
801 { "COUNT_HW_CACHE_L1D", PERF_COUNT_HW_CACHE_L1D },
802 { "COUNT_HW_CACHE_L1I", PERF_COUNT_HW_CACHE_L1I },
803 { "COUNT_HW_CACHE_LL", PERF_COUNT_HW_CACHE_LL },
804 { "COUNT_HW_CACHE_DTLB", PERF_COUNT_HW_CACHE_DTLB },
805 { "COUNT_HW_CACHE_ITLB", PERF_COUNT_HW_CACHE_ITLB },
806 { "COUNT_HW_CACHE_BPU", PERF_COUNT_HW_CACHE_BPU },
807 { "COUNT_HW_CACHE_OP_READ", PERF_COUNT_HW_CACHE_OP_READ },
808 { "COUNT_HW_CACHE_OP_WRITE", PERF_COUNT_HW_CACHE_OP_WRITE },
809 { "COUNT_HW_CACHE_OP_PREFETCH", PERF_COUNT_HW_CACHE_OP_PREFETCH },
810 { "COUNT_HW_CACHE_RESULT_ACCESS", PERF_COUNT_HW_CACHE_RESULT_ACCESS },
811 { "COUNT_HW_CACHE_RESULT_MISS", PERF_COUNT_HW_CACHE_RESULT_MISS },
812
813 { "COUNT_SW_CPU_CLOCK", PERF_COUNT_SW_CPU_CLOCK },
814 { "COUNT_SW_TASK_CLOCK", PERF_COUNT_SW_TASK_CLOCK },
815 { "COUNT_SW_PAGE_FAULTS", PERF_COUNT_SW_PAGE_FAULTS },
816 { "COUNT_SW_CONTEXT_SWITCHES", PERF_COUNT_SW_CONTEXT_SWITCHES },
817 { "COUNT_SW_CPU_MIGRATIONS", PERF_COUNT_SW_CPU_MIGRATIONS },
818 { "COUNT_SW_PAGE_FAULTS_MIN", PERF_COUNT_SW_PAGE_FAULTS_MIN },
819 { "COUNT_SW_PAGE_FAULTS_MAJ", PERF_COUNT_SW_PAGE_FAULTS_MAJ },
820 { "COUNT_SW_ALIGNMENT_FAULTS", PERF_COUNT_SW_ALIGNMENT_FAULTS },
821 { "COUNT_SW_EMULATION_FAULTS", PERF_COUNT_SW_EMULATION_FAULTS },
822
823 { "SAMPLE_IP", PERF_SAMPLE_IP },
824 { "SAMPLE_TID", PERF_SAMPLE_TID },
825 { "SAMPLE_TIME", PERF_SAMPLE_TIME },
826 { "SAMPLE_ADDR", PERF_SAMPLE_ADDR },
827 { "SAMPLE_READ", PERF_SAMPLE_READ },
828 { "SAMPLE_CALLCHAIN", PERF_SAMPLE_CALLCHAIN },
829 { "SAMPLE_ID", PERF_SAMPLE_ID },
830 { "SAMPLE_CPU", PERF_SAMPLE_CPU },
831 { "SAMPLE_PERIOD", PERF_SAMPLE_PERIOD },
832 { "SAMPLE_STREAM_ID", PERF_SAMPLE_STREAM_ID },
833 { "SAMPLE_RAW", PERF_SAMPLE_RAW },
834
835 { "FORMAT_TOTAL_TIME_ENABLED", PERF_FORMAT_TOTAL_TIME_ENABLED },
836 { "FORMAT_TOTAL_TIME_RUNNING", PERF_FORMAT_TOTAL_TIME_RUNNING },
837 { "FORMAT_ID", PERF_FORMAT_ID },
838 { "FORMAT_GROUP", PERF_FORMAT_GROUP },
839
840 { "RECORD_MMAP", PERF_RECORD_MMAP },
841 { "RECORD_LOST", PERF_RECORD_LOST },
842 { "RECORD_COMM", PERF_RECORD_COMM },
843 { "RECORD_EXIT", PERF_RECORD_EXIT },
844 { "RECORD_THROTTLE", PERF_RECORD_THROTTLE },
845 { "RECORD_UNTHROTTLE", PERF_RECORD_UNTHROTTLE },
846 { "RECORD_FORK", PERF_RECORD_FORK },
847 { "RECORD_READ", PERF_RECORD_READ },
848 { "RECORD_SAMPLE", PERF_RECORD_SAMPLE },
849 { .name = NULL, },
850};
851
852static PyMethodDef perf__methods[] = {
853 { .ml_name = NULL, }
854};
855
856PyMODINIT_FUNC initperf(void)
857{
858 PyObject *obj;
859 int i;
860 PyObject *dict, *module = Py_InitModule("perf", perf__methods);
861
862 if (module == NULL ||
863 pyrf_event__setup_types() < 0 ||
864 pyrf_evlist__setup_types() < 0 ||
865 pyrf_evsel__setup_types() < 0 ||
866 pyrf_thread_map__setup_types() < 0 ||
867 pyrf_cpu_map__setup_types() < 0)
868 return;
869
870 Py_INCREF(&pyrf_evlist__type);
871 PyModule_AddObject(module, "evlist", (PyObject*)&pyrf_evlist__type);
872
873 Py_INCREF(&pyrf_evsel__type);
874 PyModule_AddObject(module, "evsel", (PyObject*)&pyrf_evsel__type);
875
876 Py_INCREF(&pyrf_thread_map__type);
877 PyModule_AddObject(module, "thread_map", (PyObject*)&pyrf_thread_map__type);
878
879 Py_INCREF(&pyrf_cpu_map__type);
880 PyModule_AddObject(module, "cpu_map", (PyObject*)&pyrf_cpu_map__type);
881
882 dict = PyModule_GetDict(module);
883 if (dict == NULL)
884 goto error;
885
886 for (i = 0; perf__constants[i].name != NULL; i++) {
887 obj = PyInt_FromLong(perf__constants[i].value);
888 if (obj == NULL)
889 goto error;
890 PyDict_SetItemString(dict, perf__constants[i].name, obj);
891 Py_DECREF(obj);
892 }
893
894error:
895 if (PyErr_Occurred())
896 PyErr_SetString(PyExc_ImportError, "perf: Init failed!");
897}
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..caa224522fea 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,7 +53,7 @@ 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 }
@@ -65,9 +67,38 @@ out_close:
65 return -1; 67 return -1;
66} 68}
67 69
70static void perf_session__id_header_size(struct perf_session *session)
71{
72 struct perf_sample *data;
73 u64 sample_type = session->sample_type;
74 u16 size = 0;
75
76 if (!session->sample_id_all)
77 goto out;
78
79 if (sample_type & PERF_SAMPLE_TID)
80 size += sizeof(data->tid) * 2;
81
82 if (sample_type & PERF_SAMPLE_TIME)
83 size += sizeof(data->time);
84
85 if (sample_type & PERF_SAMPLE_ID)
86 size += sizeof(data->id);
87
88 if (sample_type & PERF_SAMPLE_STREAM_ID)
89 size += sizeof(data->stream_id);
90
91 if (sample_type & PERF_SAMPLE_CPU)
92 size += sizeof(data->cpu) * 2;
93out:
94 session->id_hdr_size = size;
95}
96
68void perf_session__update_sample_type(struct perf_session *self) 97void perf_session__update_sample_type(struct perf_session *self)
69{ 98{
70 self->sample_type = perf_header__sample_type(&self->header); 99 self->sample_type = perf_evlist__sample_type(self->evlist);
100 self->sample_id_all = perf_evlist__sample_id_all(self->evlist);
101 perf_session__id_header_size(self);
71} 102}
72 103
73int perf_session__create_kernel_maps(struct perf_session *self) 104int perf_session__create_kernel_maps(struct perf_session *self)
@@ -85,7 +116,9 @@ static void perf_session__destroy_kernel_maps(struct perf_session *self)
85 machines__destroy_guest_kernel_maps(&self->machines); 116 machines__destroy_guest_kernel_maps(&self->machines);
86} 117}
87 118
88struct perf_session *perf_session__new(const char *filename, int mode, bool force, bool repipe) 119struct perf_session *perf_session__new(const char *filename, int mode,
120 bool force, bool repipe,
121 struct perf_event_ops *ops)
89{ 122{
90 size_t len = filename ? strlen(filename) + 1 : 0; 123 size_t len = filename ? strlen(filename) + 1 : 0;
91 struct perf_session *self = zalloc(sizeof(*self) + len); 124 struct perf_session *self = zalloc(sizeof(*self) + len);
@@ -93,38 +126,47 @@ struct perf_session *perf_session__new(const char *filename, int mode, bool forc
93 if (self == NULL) 126 if (self == NULL)
94 goto out; 127 goto out;
95 128
96 if (perf_header__init(&self->header) < 0)
97 goto out_free;
98
99 memcpy(self->filename, filename, len); 129 memcpy(self->filename, filename, len);
100 self->threads = RB_ROOT; 130 self->threads = RB_ROOT;
101 INIT_LIST_HEAD(&self->dead_threads); 131 INIT_LIST_HEAD(&self->dead_threads);
102 self->hists_tree = RB_ROOT;
103 self->last_match = NULL; 132 self->last_match = NULL;
104 self->mmap_window = 32; 133 /*
134 * On 64bit we can mmap the data file in one go. No need for tiny mmap
135 * slices. On 32bit we use 32MB.
136 */
137#if BITS_PER_LONG == 64
138 self->mmap_window = ULLONG_MAX;
139#else
140 self->mmap_window = 32 * 1024 * 1024ULL;
141#endif
105 self->machines = RB_ROOT; 142 self->machines = RB_ROOT;
106 self->repipe = repipe; 143 self->repipe = repipe;
107 INIT_LIST_HEAD(&self->ordered_samples.samples_head); 144 INIT_LIST_HEAD(&self->ordered_samples.samples);
145 INIT_LIST_HEAD(&self->ordered_samples.sample_cache);
146 INIT_LIST_HEAD(&self->ordered_samples.to_free);
108 machine__init(&self->host_machine, "", HOST_KERNEL_ID); 147 machine__init(&self->host_machine, "", HOST_KERNEL_ID);
109 148
110 if (mode == O_RDONLY) { 149 if (mode == O_RDONLY) {
111 if (perf_session__open(self, force) < 0) 150 if (perf_session__open(self, force) < 0)
112 goto out_delete; 151 goto out_delete;
152 perf_session__update_sample_type(self);
113 } else if (mode == O_WRONLY) { 153 } else if (mode == O_WRONLY) {
114 /* 154 /*
115 * In O_RDONLY mode this will be performed when reading the 155 * In O_RDONLY mode this will be performed when reading the
116 * kernel MMAP event, in event__process_mmap(). 156 * kernel MMAP event, in perf_event__process_mmap().
117 */ 157 */
118 if (perf_session__create_kernel_maps(self) < 0) 158 if (perf_session__create_kernel_maps(self) < 0)
119 goto out_delete; 159 goto out_delete;
120 } 160 }
121 161
122 perf_session__update_sample_type(self); 162 if (ops && ops->ordering_requires_timestamps &&
163 ops->ordered_samples && !self->sample_id_all) {
164 dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n");
165 ops->ordered_samples = false;
166 }
167
123out: 168out:
124 return self; 169 return self;
125out_free:
126 free(self);
127 return NULL;
128out_delete: 170out_delete:
129 perf_session__delete(self); 171 perf_session__delete(self);
130 return NULL; 172 return NULL;
@@ -155,7 +197,6 @@ static void perf_session__delete_threads(struct perf_session *self)
155 197
156void perf_session__delete(struct perf_session *self) 198void perf_session__delete(struct perf_session *self)
157{ 199{
158 perf_header__exit(&self->header);
159 perf_session__destroy_kernel_maps(self); 200 perf_session__destroy_kernel_maps(self);
160 perf_session__delete_dead_threads(self); 201 perf_session__delete_dead_threads(self);
161 perf_session__delete_threads(self); 202 perf_session__delete_threads(self);
@@ -183,17 +224,16 @@ static bool symbol__match_parent_regex(struct symbol *sym)
183 return 0; 224 return 0;
184} 225}
185 226
186struct map_symbol *perf_session__resolve_callchain(struct perf_session *self, 227int perf_session__resolve_callchain(struct perf_session *self,
187 struct thread *thread, 228 struct thread *thread,
188 struct ip_callchain *chain, 229 struct ip_callchain *chain,
189 struct symbol **parent) 230 struct symbol **parent)
190{ 231{
191 u8 cpumode = PERF_RECORD_MISC_USER; 232 u8 cpumode = PERF_RECORD_MISC_USER;
192 unsigned int i; 233 unsigned int i;
193 struct map_symbol *syms = calloc(chain->nr, sizeof(*syms)); 234 int err;
194 235
195 if (!syms) 236 callchain_cursor_reset(&self->callchain_cursor);
196 return NULL;
197 237
198 for (i = 0; i < chain->nr; i++) { 238 for (i = 0; i < chain->nr; i++) {
199 u64 ip = chain->ips[i]; 239 u64 ip = chain->ips[i];
@@ -222,22 +262,42 @@ struct map_symbol *perf_session__resolve_callchain(struct perf_session *self,
222 *parent = al.sym; 262 *parent = al.sym;
223 if (!symbol_conf.use_callchain) 263 if (!symbol_conf.use_callchain)
224 break; 264 break;
225 syms[i].map = al.map;
226 syms[i].sym = al.sym;
227 } 265 }
266
267 err = callchain_cursor_append(&self->callchain_cursor,
268 ip, al.map, al.sym);
269 if (err)
270 return err;
228 } 271 }
229 272
230 return syms; 273 return 0;
231} 274}
232 275
233static int process_event_stub(event_t *event __used, 276static int process_event_synth_stub(union perf_event *event __used,
277 struct perf_session *session __used)
278{
279 dump_printf(": unhandled!\n");
280 return 0;
281}
282
283static int process_event_sample_stub(union perf_event *event __used,
284 struct perf_sample *sample __used,
285 struct perf_evsel *evsel __used,
286 struct perf_session *session __used)
287{
288 dump_printf(": unhandled!\n");
289 return 0;
290}
291
292static int process_event_stub(union perf_event *event __used,
293 struct perf_sample *sample __used,
234 struct perf_session *session __used) 294 struct perf_session *session __used)
235{ 295{
236 dump_printf(": unhandled!\n"); 296 dump_printf(": unhandled!\n");
237 return 0; 297 return 0;
238} 298}
239 299
240static int process_finished_round_stub(event_t *event __used, 300static int process_finished_round_stub(union perf_event *event __used,
241 struct perf_session *session __used, 301 struct perf_session *session __used,
242 struct perf_event_ops *ops __used) 302 struct perf_event_ops *ops __used)
243{ 303{
@@ -245,14 +305,14 @@ static int process_finished_round_stub(event_t *event __used,
245 return 0; 305 return 0;
246} 306}
247 307
248static int process_finished_round(event_t *event, 308static int process_finished_round(union perf_event *event,
249 struct perf_session *session, 309 struct perf_session *session,
250 struct perf_event_ops *ops); 310 struct perf_event_ops *ops);
251 311
252static void perf_event_ops__fill_defaults(struct perf_event_ops *handler) 312static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
253{ 313{
254 if (handler->sample == NULL) 314 if (handler->sample == NULL)
255 handler->sample = process_event_stub; 315 handler->sample = process_event_sample_stub;
256 if (handler->mmap == NULL) 316 if (handler->mmap == NULL)
257 handler->mmap = process_event_stub; 317 handler->mmap = process_event_stub;
258 if (handler->comm == NULL) 318 if (handler->comm == NULL)
@@ -262,7 +322,7 @@ static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
262 if (handler->exit == NULL) 322 if (handler->exit == NULL)
263 handler->exit = process_event_stub; 323 handler->exit = process_event_stub;
264 if (handler->lost == NULL) 324 if (handler->lost == NULL)
265 handler->lost = process_event_stub; 325 handler->lost = perf_event__process_lost;
266 if (handler->read == NULL) 326 if (handler->read == NULL)
267 handler->read = process_event_stub; 327 handler->read = process_event_stub;
268 if (handler->throttle == NULL) 328 if (handler->throttle == NULL)
@@ -270,13 +330,13 @@ static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
270 if (handler->unthrottle == NULL) 330 if (handler->unthrottle == NULL)
271 handler->unthrottle = process_event_stub; 331 handler->unthrottle = process_event_stub;
272 if (handler->attr == NULL) 332 if (handler->attr == NULL)
273 handler->attr = process_event_stub; 333 handler->attr = process_event_synth_stub;
274 if (handler->event_type == NULL) 334 if (handler->event_type == NULL)
275 handler->event_type = process_event_stub; 335 handler->event_type = process_event_synth_stub;
276 if (handler->tracing_data == NULL) 336 if (handler->tracing_data == NULL)
277 handler->tracing_data = process_event_stub; 337 handler->tracing_data = process_event_synth_stub;
278 if (handler->build_id == NULL) 338 if (handler->build_id == NULL)
279 handler->build_id = process_event_stub; 339 handler->build_id = process_event_synth_stub;
280 if (handler->finished_round == NULL) { 340 if (handler->finished_round == NULL) {
281 if (handler->ordered_samples) 341 if (handler->ordered_samples)
282 handler->finished_round = process_finished_round; 342 handler->finished_round = process_finished_round;
@@ -296,123 +356,151 @@ void mem_bswap_64(void *src, int byte_size)
296 } 356 }
297} 357}
298 358
299static void event__all64_swap(event_t *self) 359static void perf_event__all64_swap(union perf_event *event)
300{ 360{
301 struct perf_event_header *hdr = &self->header; 361 struct perf_event_header *hdr = &event->header;
302 mem_bswap_64(hdr + 1, self->header.size - sizeof(*hdr)); 362 mem_bswap_64(hdr + 1, event->header.size - sizeof(*hdr));
303} 363}
304 364
305static void event__comm_swap(event_t *self) 365static void perf_event__comm_swap(union perf_event *event)
306{ 366{
307 self->comm.pid = bswap_32(self->comm.pid); 367 event->comm.pid = bswap_32(event->comm.pid);
308 self->comm.tid = bswap_32(self->comm.tid); 368 event->comm.tid = bswap_32(event->comm.tid);
309} 369}
310 370
311static void event__mmap_swap(event_t *self) 371static void perf_event__mmap_swap(union perf_event *event)
312{ 372{
313 self->mmap.pid = bswap_32(self->mmap.pid); 373 event->mmap.pid = bswap_32(event->mmap.pid);
314 self->mmap.tid = bswap_32(self->mmap.tid); 374 event->mmap.tid = bswap_32(event->mmap.tid);
315 self->mmap.start = bswap_64(self->mmap.start); 375 event->mmap.start = bswap_64(event->mmap.start);
316 self->mmap.len = bswap_64(self->mmap.len); 376 event->mmap.len = bswap_64(event->mmap.len);
317 self->mmap.pgoff = bswap_64(self->mmap.pgoff); 377 event->mmap.pgoff = bswap_64(event->mmap.pgoff);
318} 378}
319 379
320static void event__task_swap(event_t *self) 380static void perf_event__task_swap(union perf_event *event)
321{ 381{
322 self->fork.pid = bswap_32(self->fork.pid); 382 event->fork.pid = bswap_32(event->fork.pid);
323 self->fork.tid = bswap_32(self->fork.tid); 383 event->fork.tid = bswap_32(event->fork.tid);
324 self->fork.ppid = bswap_32(self->fork.ppid); 384 event->fork.ppid = bswap_32(event->fork.ppid);
325 self->fork.ptid = bswap_32(self->fork.ptid); 385 event->fork.ptid = bswap_32(event->fork.ptid);
326 self->fork.time = bswap_64(self->fork.time); 386 event->fork.time = bswap_64(event->fork.time);
327} 387}
328 388
329static void event__read_swap(event_t *self) 389static void perf_event__read_swap(union perf_event *event)
330{ 390{
331 self->read.pid = bswap_32(self->read.pid); 391 event->read.pid = bswap_32(event->read.pid);
332 self->read.tid = bswap_32(self->read.tid); 392 event->read.tid = bswap_32(event->read.tid);
333 self->read.value = bswap_64(self->read.value); 393 event->read.value = bswap_64(event->read.value);
334 self->read.time_enabled = bswap_64(self->read.time_enabled); 394 event->read.time_enabled = bswap_64(event->read.time_enabled);
335 self->read.time_running = bswap_64(self->read.time_running); 395 event->read.time_running = bswap_64(event->read.time_running);
336 self->read.id = bswap_64(self->read.id); 396 event->read.id = bswap_64(event->read.id);
337} 397}
338 398
339static void event__attr_swap(event_t *self) 399static void perf_event__attr_swap(union perf_event *event)
340{ 400{
341 size_t size; 401 size_t size;
342 402
343 self->attr.attr.type = bswap_32(self->attr.attr.type); 403 event->attr.attr.type = bswap_32(event->attr.attr.type);
344 self->attr.attr.size = bswap_32(self->attr.attr.size); 404 event->attr.attr.size = bswap_32(event->attr.attr.size);
345 self->attr.attr.config = bswap_64(self->attr.attr.config); 405 event->attr.attr.config = bswap_64(event->attr.attr.config);
346 self->attr.attr.sample_period = bswap_64(self->attr.attr.sample_period); 406 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); 407 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); 408 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); 409 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); 410 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); 411 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); 412 event->attr.attr.bp_len = bswap_64(event->attr.attr.bp_len);
353 413
354 size = self->header.size; 414 size = event->header.size;
355 size -= (void *)&self->attr.id - (void *)self; 415 size -= (void *)&event->attr.id - (void *)event;
356 mem_bswap_64(self->attr.id, size); 416 mem_bswap_64(event->attr.id, size);
357} 417}
358 418
359static void event__event_type_swap(event_t *self) 419static void perf_event__event_type_swap(union perf_event *event)
360{ 420{
361 self->event_type.event_type.event_id = 421 event->event_type.event_type.event_id =
362 bswap_64(self->event_type.event_type.event_id); 422 bswap_64(event->event_type.event_type.event_id);
363} 423}
364 424
365static void event__tracing_data_swap(event_t *self) 425static void perf_event__tracing_data_swap(union perf_event *event)
366{ 426{
367 self->tracing_data.size = bswap_32(self->tracing_data.size); 427 event->tracing_data.size = bswap_32(event->tracing_data.size);
368} 428}
369 429
370typedef void (*event__swap_op)(event_t *self); 430typedef void (*perf_event__swap_op)(union perf_event *event);
371 431
372static event__swap_op event__swap_ops[] = { 432static perf_event__swap_op perf_event__swap_ops[] = {
373 [PERF_RECORD_MMAP] = event__mmap_swap, 433 [PERF_RECORD_MMAP] = perf_event__mmap_swap,
374 [PERF_RECORD_COMM] = event__comm_swap, 434 [PERF_RECORD_COMM] = perf_event__comm_swap,
375 [PERF_RECORD_FORK] = event__task_swap, 435 [PERF_RECORD_FORK] = perf_event__task_swap,
376 [PERF_RECORD_EXIT] = event__task_swap, 436 [PERF_RECORD_EXIT] = perf_event__task_swap,
377 [PERF_RECORD_LOST] = event__all64_swap, 437 [PERF_RECORD_LOST] = perf_event__all64_swap,
378 [PERF_RECORD_READ] = event__read_swap, 438 [PERF_RECORD_READ] = perf_event__read_swap,
379 [PERF_RECORD_SAMPLE] = event__all64_swap, 439 [PERF_RECORD_SAMPLE] = perf_event__all64_swap,
380 [PERF_RECORD_HEADER_ATTR] = event__attr_swap, 440 [PERF_RECORD_HEADER_ATTR] = perf_event__attr_swap,
381 [PERF_RECORD_HEADER_EVENT_TYPE] = event__event_type_swap, 441 [PERF_RECORD_HEADER_EVENT_TYPE] = perf_event__event_type_swap,
382 [PERF_RECORD_HEADER_TRACING_DATA] = event__tracing_data_swap, 442 [PERF_RECORD_HEADER_TRACING_DATA] = perf_event__tracing_data_swap,
383 [PERF_RECORD_HEADER_BUILD_ID] = NULL, 443 [PERF_RECORD_HEADER_BUILD_ID] = NULL,
384 [PERF_RECORD_HEADER_MAX] = NULL, 444 [PERF_RECORD_HEADER_MAX] = NULL,
385}; 445};
386 446
387struct sample_queue { 447struct sample_queue {
388 u64 timestamp; 448 u64 timestamp;
389 struct sample_event *event; 449 u64 file_offset;
450 union perf_event *event;
390 struct list_head list; 451 struct list_head list;
391}; 452};
392 453
454static void perf_session_free_sample_buffers(struct perf_session *session)
455{
456 struct ordered_samples *os = &session->ordered_samples;
457
458 while (!list_empty(&os->to_free)) {
459 struct sample_queue *sq;
460
461 sq = list_entry(os->to_free.next, struct sample_queue, list);
462 list_del(&sq->list);
463 free(sq);
464 }
465}
466
467static int perf_session_deliver_event(struct perf_session *session,
468 union perf_event *event,
469 struct perf_sample *sample,
470 struct perf_event_ops *ops,
471 u64 file_offset);
472
393static void flush_sample_queue(struct perf_session *s, 473static void flush_sample_queue(struct perf_session *s,
394 struct perf_event_ops *ops) 474 struct perf_event_ops *ops)
395{ 475{
396 struct list_head *head = &s->ordered_samples.samples_head; 476 struct ordered_samples *os = &s->ordered_samples;
397 u64 limit = s->ordered_samples.next_flush; 477 struct list_head *head = &os->samples;
398 struct sample_queue *tmp, *iter; 478 struct sample_queue *tmp, *iter;
479 struct perf_sample sample;
480 u64 limit = os->next_flush;
481 u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL;
399 482
400 if (!ops->ordered_samples || !limit) 483 if (!ops->ordered_samples || !limit)
401 return; 484 return;
402 485
403 list_for_each_entry_safe(iter, tmp, head, list) { 486 list_for_each_entry_safe(iter, tmp, head, list) {
404 if (iter->timestamp > limit) 487 if (iter->timestamp > limit)
405 return; 488 break;
406
407 if (iter == s->ordered_samples.last_inserted)
408 s->ordered_samples.last_inserted = NULL;
409 489
410 ops->sample((event_t *)iter->event, s); 490 perf_session__parse_sample(s, iter->event, &sample);
491 perf_session_deliver_event(s, iter->event, &sample, ops,
492 iter->file_offset);
411 493
412 s->ordered_samples.last_flush = iter->timestamp; 494 os->last_flush = iter->timestamp;
413 list_del(&iter->list); 495 list_del(&iter->list);
414 free(iter->event); 496 list_add(&iter->list, &os->sample_cache);
415 free(iter); 497 }
498
499 if (list_empty(head)) {
500 os->last_sample = NULL;
501 } else if (last_ts <= limit) {
502 os->last_sample =
503 list_entry(head->prev, struct sample_queue, list);
416 } 504 }
417} 505}
418 506
@@ -455,7 +543,7 @@ static void flush_sample_queue(struct perf_session *s,
455 * Flush every events below timestamp 7 543 * Flush every events below timestamp 7
456 * etc... 544 * etc...
457 */ 545 */
458static int process_finished_round(event_t *event __used, 546static int process_finished_round(union perf_event *event __used,
459 struct perf_session *session, 547 struct perf_session *session,
460 struct perf_event_ops *ops) 548 struct perf_event_ops *ops)
461{ 549{
@@ -465,178 +553,275 @@ static int process_finished_round(event_t *event __used,
465 return 0; 553 return 0;
466} 554}
467 555
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 */ 556/* The queue is ordered by time */
510static void __queue_sample_event(struct sample_queue *new, 557static void __queue_event(struct sample_queue *new, struct perf_session *s)
511 struct perf_session *s)
512{ 558{
513 struct sample_queue *last_inserted = s->ordered_samples.last_inserted; 559 struct ordered_samples *os = &s->ordered_samples;
514 struct list_head *head = &s->ordered_samples.samples_head; 560 struct sample_queue *sample = os->last_sample;
561 u64 timestamp = new->timestamp;
562 struct list_head *p;
515 563
564 os->last_sample = new;
516 565
517 if (!last_inserted) { 566 if (!sample) {
518 __queue_sample_end(new, head); 567 list_add(&new->list, &os->samples);
568 os->max_timestamp = timestamp;
519 return; 569 return;
520 } 570 }
521 571
522 /* 572 /*
523 * Most of the time the current event has a timestamp 573 * 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 574 * 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 575 * 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 */ 576 */
529 if (last_inserted->timestamp >= new->timestamp) 577 if (sample->timestamp <= timestamp) {
530 __queue_sample_before(new, last_inserted, head); 578 while (sample->timestamp <= timestamp) {
531 else 579 p = sample->list.next;
532 __queue_sample_after(new, last_inserted, head); 580 if (p == &os->samples) {
581 list_add_tail(&new->list, &os->samples);
582 os->max_timestamp = timestamp;
583 return;
584 }
585 sample = list_entry(p, struct sample_queue, list);
586 }
587 list_add_tail(&new->list, &sample->list);
588 } else {
589 while (sample->timestamp > timestamp) {
590 p = sample->list.prev;
591 if (p == &os->samples) {
592 list_add(&new->list, &os->samples);
593 return;
594 }
595 sample = list_entry(p, struct sample_queue, list);
596 }
597 list_add(&new->list, &sample->list);
598 }
533} 599}
534 600
535static int queue_sample_event(event_t *event, struct sample_data *data, 601#define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct sample_queue))
536 struct perf_session *s) 602
603static int perf_session_queue_event(struct perf_session *s, union perf_event *event,
604 struct perf_sample *sample, u64 file_offset)
537{ 605{
538 u64 timestamp = data->time; 606 struct ordered_samples *os = &s->ordered_samples;
607 struct list_head *sc = &os->sample_cache;
608 u64 timestamp = sample->time;
539 struct sample_queue *new; 609 struct sample_queue *new;
540 610
611 if (!timestamp || timestamp == ~0ULL)
612 return -ETIME;
541 613
542 if (timestamp < s->ordered_samples.last_flush) { 614 if (timestamp < s->ordered_samples.last_flush) {
543 printf("Warning: Timestamp below last timeslice flush\n"); 615 printf("Warning: Timestamp below last timeslice flush\n");
544 return -EINVAL; 616 return -EINVAL;
545 } 617 }
546 618
547 new = malloc(sizeof(*new)); 619 if (!list_empty(sc)) {
548 if (!new) 620 new = list_entry(sc->next, struct sample_queue, list);
549 return -ENOMEM; 621 list_del(&new->list);
622 } else if (os->sample_buffer) {
623 new = os->sample_buffer + os->sample_buffer_idx;
624 if (++os->sample_buffer_idx == MAX_SAMPLE_BUFFER)
625 os->sample_buffer = NULL;
626 } else {
627 os->sample_buffer = malloc(MAX_SAMPLE_BUFFER * sizeof(*new));
628 if (!os->sample_buffer)
629 return -ENOMEM;
630 list_add(&os->sample_buffer->list, &os->to_free);
631 os->sample_buffer_idx = 2;
632 new = os->sample_buffer + 1;
633 }
550 634
551 new->timestamp = timestamp; 635 new->timestamp = timestamp;
636 new->file_offset = file_offset;
637 new->event = event;
552 638
553 new->event = malloc(event->header.size); 639 __queue_event(new, s);
554 if (!new->event) {
555 free(new);
556 return -ENOMEM;
557 }
558 640
559 memcpy(new->event, event, event->header.size); 641 return 0;
642}
560 643
561 __queue_sample_event(new, s); 644static void callchain__printf(struct perf_sample *sample)
562 s->ordered_samples.last_inserted = new; 645{
646 unsigned int i;
563 647
564 if (new->timestamp > s->ordered_samples.max_timestamp) 648 printf("... chain: nr:%" PRIu64 "\n", sample->callchain->nr);
565 s->ordered_samples.max_timestamp = new->timestamp;
566 649
567 return 0; 650 for (i = 0; i < sample->callchain->nr; i++)
651 printf("..... %2d: %016" PRIx64 "\n",
652 i, sample->callchain->ips[i]);
568} 653}
569 654
570static int perf_session__process_sample(event_t *event, struct perf_session *s, 655static void perf_session__print_tstamp(struct perf_session *session,
571 struct perf_event_ops *ops) 656 union perf_event *event,
657 struct perf_sample *sample)
572{ 658{
573 struct sample_data data; 659 if (event->header.type != PERF_RECORD_SAMPLE &&
660 !session->sample_id_all) {
661 fputs("-1 -1 ", stdout);
662 return;
663 }
574 664
575 if (!ops->ordered_samples) 665 if ((session->sample_type & PERF_SAMPLE_CPU))
576 return ops->sample(event, s); 666 printf("%u ", sample->cpu);
577 667
578 bzero(&data, sizeof(struct sample_data)); 668 if (session->sample_type & PERF_SAMPLE_TIME)
579 event__parse_sample(event, s->sample_type, &data); 669 printf("%" PRIu64 " ", sample->time);
670}
671
672static void dump_event(struct perf_session *session, union perf_event *event,
673 u64 file_offset, struct perf_sample *sample)
674{
675 if (!dump_trace)
676 return;
580 677
581 queue_sample_event(event, &data, s); 678 printf("\n%#" PRIx64 " [%#x]: event: %d\n",
679 file_offset, event->header.size, event->header.type);
582 680
583 return 0; 681 trace_event(event);
682
683 if (sample)
684 perf_session__print_tstamp(session, event, sample);
685
686 printf("%#" PRIx64 " [%#x]: PERF_RECORD_%s", file_offset,
687 event->header.size, perf_event__name(event->header.type));
584} 688}
585 689
586static int perf_session__process_event(struct perf_session *self, 690static void dump_sample(struct perf_session *session, union perf_event *event,
587 event_t *event, 691 struct perf_sample *sample)
588 struct perf_event_ops *ops,
589 u64 offset, u64 head)
590{ 692{
591 trace_event(event); 693 if (!dump_trace)
694 return;
592 695
593 if (event->header.type < PERF_RECORD_HEADER_MAX) { 696 printf("(IP, %d): %d/%d: %#" PRIx64 " period: %" PRIu64 "\n",
594 dump_printf("%#Lx [%#x]: PERF_RECORD_%s", 697 event->header.misc, sample->pid, sample->tid, sample->ip,
595 offset + head, event->header.size, 698 sample->period);
596 event__name[event->header.type]); 699
597 hists__inc_nr_events(&self->hists, event->header.type); 700 if (session->sample_type & PERF_SAMPLE_CALLCHAIN)
598 } 701 callchain__printf(sample);
702}
599 703
600 if (self->header.needs_swap && event__swap_ops[event->header.type]) 704static int perf_session_deliver_event(struct perf_session *session,
601 event__swap_ops[event->header.type](event); 705 union perf_event *event,
706 struct perf_sample *sample,
707 struct perf_event_ops *ops,
708 u64 file_offset)
709{
710 struct perf_evsel *evsel;
711
712 dump_event(session, event, file_offset, sample);
602 713
603 switch (event->header.type) { 714 switch (event->header.type) {
604 case PERF_RECORD_SAMPLE: 715 case PERF_RECORD_SAMPLE:
605 return perf_session__process_sample(event, self, ops); 716 dump_sample(session, event, sample);
717 evsel = perf_evlist__id2evsel(session->evlist, sample->id);
718 if (evsel == NULL) {
719 ++session->hists.stats.nr_unknown_id;
720 return -1;
721 }
722 return ops->sample(event, sample, evsel, session);
606 case PERF_RECORD_MMAP: 723 case PERF_RECORD_MMAP:
607 return ops->mmap(event, self); 724 return ops->mmap(event, sample, session);
608 case PERF_RECORD_COMM: 725 case PERF_RECORD_COMM:
609 return ops->comm(event, self); 726 return ops->comm(event, sample, session);
610 case PERF_RECORD_FORK: 727 case PERF_RECORD_FORK:
611 return ops->fork(event, self); 728 return ops->fork(event, sample, session);
612 case PERF_RECORD_EXIT: 729 case PERF_RECORD_EXIT:
613 return ops->exit(event, self); 730 return ops->exit(event, sample, session);
614 case PERF_RECORD_LOST: 731 case PERF_RECORD_LOST:
615 return ops->lost(event, self); 732 return ops->lost(event, sample, session);
616 case PERF_RECORD_READ: 733 case PERF_RECORD_READ:
617 return ops->read(event, self); 734 return ops->read(event, sample, session);
618 case PERF_RECORD_THROTTLE: 735 case PERF_RECORD_THROTTLE:
619 return ops->throttle(event, self); 736 return ops->throttle(event, sample, session);
620 case PERF_RECORD_UNTHROTTLE: 737 case PERF_RECORD_UNTHROTTLE:
621 return ops->unthrottle(event, self); 738 return ops->unthrottle(event, sample, session);
739 default:
740 ++session->hists.stats.nr_unknown_events;
741 return -1;
742 }
743}
744
745static int perf_session__preprocess_sample(struct perf_session *session,
746 union perf_event *event, struct perf_sample *sample)
747{
748 if (event->header.type != PERF_RECORD_SAMPLE ||
749 !(session->sample_type & PERF_SAMPLE_CALLCHAIN))
750 return 0;
751
752 if (!ip_callchain__valid(sample->callchain, event)) {
753 pr_debug("call-chain problem with event, skipping it.\n");
754 ++session->hists.stats.nr_invalid_chains;
755 session->hists.stats.total_invalid_chains += sample->period;
756 return -EINVAL;
757 }
758 return 0;
759}
760
761static int perf_session__process_user_event(struct perf_session *session, union perf_event *event,
762 struct perf_event_ops *ops, u64 file_offset)
763{
764 dump_event(session, event, file_offset, NULL);
765
766 /* These events are processed right away */
767 switch (event->header.type) {
622 case PERF_RECORD_HEADER_ATTR: 768 case PERF_RECORD_HEADER_ATTR:
623 return ops->attr(event, self); 769 return ops->attr(event, session);
624 case PERF_RECORD_HEADER_EVENT_TYPE: 770 case PERF_RECORD_HEADER_EVENT_TYPE:
625 return ops->event_type(event, self); 771 return ops->event_type(event, session);
626 case PERF_RECORD_HEADER_TRACING_DATA: 772 case PERF_RECORD_HEADER_TRACING_DATA:
627 /* setup for reading amidst mmap */ 773 /* setup for reading amidst mmap */
628 lseek(self->fd, offset + head, SEEK_SET); 774 lseek(session->fd, file_offset, SEEK_SET);
629 return ops->tracing_data(event, self); 775 return ops->tracing_data(event, session);
630 case PERF_RECORD_HEADER_BUILD_ID: 776 case PERF_RECORD_HEADER_BUILD_ID:
631 return ops->build_id(event, self); 777 return ops->build_id(event, session);
632 case PERF_RECORD_FINISHED_ROUND: 778 case PERF_RECORD_FINISHED_ROUND:
633 return ops->finished_round(event, self, ops); 779 return ops->finished_round(event, session, ops);
634 default: 780 default:
635 ++self->hists.stats.nr_unknown_events; 781 return -EINVAL;
636 return -1;
637 } 782 }
638} 783}
639 784
785static int perf_session__process_event(struct perf_session *session,
786 union perf_event *event,
787 struct perf_event_ops *ops,
788 u64 file_offset)
789{
790 struct perf_sample sample;
791 int ret;
792
793 if (session->header.needs_swap &&
794 perf_event__swap_ops[event->header.type])
795 perf_event__swap_ops[event->header.type](event);
796
797 if (event->header.type >= PERF_RECORD_HEADER_MAX)
798 return -EINVAL;
799
800 hists__inc_nr_events(&session->hists, event->header.type);
801
802 if (event->header.type >= PERF_RECORD_USER_TYPE_START)
803 return perf_session__process_user_event(session, event, ops, file_offset);
804
805 /*
806 * For all kernel events we get the sample data
807 */
808 perf_session__parse_sample(session, event, &sample);
809
810 /* Preprocess sample records - precheck callchains */
811 if (perf_session__preprocess_sample(session, event, &sample))
812 return 0;
813
814 if (ops->ordered_samples) {
815 ret = perf_session_queue_event(session, event, &sample,
816 file_offset);
817 if (ret != -ETIME)
818 return ret;
819 }
820
821 return perf_session_deliver_event(session, event, &sample, ops,
822 file_offset);
823}
824
640void perf_event_header__bswap(struct perf_event_header *self) 825void perf_event_header__bswap(struct perf_event_header *self)
641{ 826{
642 self->type = bswap_32(self->type); 827 self->type = bswap_32(self->type);
@@ -656,21 +841,38 @@ static struct thread *perf_session__register_idle_thread(struct perf_session *se
656 return thread; 841 return thread;
657} 842}
658 843
659int do_read(int fd, void *buf, size_t size) 844static void perf_session__warn_about_errors(const struct perf_session *session,
845 const struct perf_event_ops *ops)
660{ 846{
661 void *buf_start = buf; 847 if (ops->lost == perf_event__process_lost &&
662 848 session->hists.stats.total_lost != 0) {
663 while (size) { 849 ui__warning("Processed %" PRIu64 " events and LOST %" PRIu64
664 int ret = read(fd, buf, size); 850 "!\n\nCheck IO/CPU overload!\n\n",
851 session->hists.stats.total_period,
852 session->hists.stats.total_lost);
853 }
665 854
666 if (ret <= 0) 855 if (session->hists.stats.nr_unknown_events != 0) {
667 return ret; 856 ui__warning("Found %u unknown events!\n\n"
857 "Is this an older tool processing a perf.data "
858 "file generated by a more recent tool?\n\n"
859 "If that is not the case, consider "
860 "reporting to linux-kernel@vger.kernel.org.\n\n",
861 session->hists.stats.nr_unknown_events);
862 }
668 863
669 size -= ret; 864 if (session->hists.stats.nr_unknown_id != 0) {
670 buf += ret; 865 ui__warning("%u samples with id not present in the header\n",
866 session->hists.stats.nr_unknown_id);
671 } 867 }
672 868
673 return buf - buf_start; 869 if (session->hists.stats.nr_invalid_chains != 0) {
870 ui__warning("Found invalid callchains!\n\n"
871 "%u out of %u events were discarded for this reason.\n\n"
872 "Consider reporting to linux-kernel@vger.kernel.org.\n\n",
873 session->hists.stats.nr_invalid_chains,
874 session->hists.stats.nr_events[PERF_RECORD_SAMPLE]);
875 }
674} 876}
675 877
676#define session_done() (*(volatile int *)(&session_done)) 878#define session_done() (*(volatile int *)(&session_done))
@@ -679,7 +881,7 @@ volatile int session_done;
679static int __perf_session__process_pipe_events(struct perf_session *self, 881static int __perf_session__process_pipe_events(struct perf_session *self,
680 struct perf_event_ops *ops) 882 struct perf_event_ops *ops)
681{ 883{
682 event_t event; 884 union perf_event event;
683 uint32_t size; 885 uint32_t size;
684 int skip = 0; 886 int skip = 0;
685 u64 head; 887 u64 head;
@@ -690,7 +892,7 @@ static int __perf_session__process_pipe_events(struct perf_session *self,
690 892
691 head = 0; 893 head = 0;
692more: 894more:
693 err = do_read(self->fd, &event, sizeof(struct perf_event_header)); 895 err = readn(self->fd, &event, sizeof(struct perf_event_header));
694 if (err <= 0) { 896 if (err <= 0) {
695 if (err == 0) 897 if (err == 0)
696 goto done; 898 goto done;
@@ -710,8 +912,7 @@ more:
710 p += sizeof(struct perf_event_header); 912 p += sizeof(struct perf_event_header);
711 913
712 if (size - sizeof(struct perf_event_header)) { 914 if (size - sizeof(struct perf_event_header)) {
713 err = do_read(self->fd, p, 915 err = readn(self->fd, p, size - sizeof(struct perf_event_header));
714 size - sizeof(struct perf_event_header));
715 if (err <= 0) { 916 if (err <= 0) {
716 if (err == 0) { 917 if (err == 0) {
717 pr_err("unexpected end of event stream\n"); 918 pr_err("unexpected end of event stream\n");
@@ -724,9 +925,8 @@ more:
724 } 925 }
725 926
726 if (size == 0 || 927 if (size == 0 ||
727 (skip = perf_session__process_event(self, &event, ops, 928 (skip = perf_session__process_event(self, &event, ops, head)) < 0) {
728 0, head)) < 0) { 929 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); 930 head, event.header.size, event.header.type);
731 /* 931 /*
732 * assume we lost track of the stream, check alignment, and 932 * assume we lost track of the stream, check alignment, and
@@ -740,9 +940,6 @@ more:
740 940
741 head += size; 941 head += size;
742 942
743 dump_printf("\n%#Lx [%#x]: event: %d\n",
744 head, event.header.size, event.header.type);
745
746 if (skip > 0) 943 if (skip > 0)
747 head += skip; 944 head += skip;
748 945
@@ -751,82 +948,91 @@ more:
751done: 948done:
752 err = 0; 949 err = 0;
753out_err: 950out_err:
951 perf_session__warn_about_errors(self, ops);
952 perf_session_free_sample_buffers(self);
754 return err; 953 return err;
755} 954}
756 955
757int __perf_session__process_events(struct perf_session *self, 956int __perf_session__process_events(struct perf_session *session,
758 u64 data_offset, u64 data_size, 957 u64 data_offset, u64 data_size,
759 u64 file_size, struct perf_event_ops *ops) 958 u64 file_size, struct perf_event_ops *ops)
760{ 959{
761 int err, mmap_prot, mmap_flags; 960 u64 head, page_offset, file_offset, file_pos, progress_next;
762 u64 head, shift; 961 int err, mmap_prot, mmap_flags, map_idx = 0;
763 u64 offset = 0; 962 struct ui_progress *progress;
764 size_t page_size; 963 size_t page_size, mmap_size;
765 event_t *event; 964 char *buf, *mmaps[8];
965 union perf_event *event;
766 uint32_t size; 966 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 967
773 perf_event_ops__fill_defaults(ops); 968 perf_event_ops__fill_defaults(ops);
774 969
775 page_size = sysconf(_SC_PAGESIZE); 970 page_size = sysconf(_SC_PAGESIZE);
776 971
777 head = data_offset; 972 page_offset = page_size * (data_offset / page_size);
778 shift = page_size * (head / page_size); 973 file_offset = page_offset;
779 offset += shift; 974 head = data_offset - page_offset;
780 head -= shift; 975
976 if (data_offset + data_size < file_size)
977 file_size = data_offset + data_size;
978
979 progress_next = file_size / 16;
980 progress = ui_progress__new("Processing events...", file_size);
981 if (progress == NULL)
982 return -1;
983
984 mmap_size = session->mmap_window;
985 if (mmap_size > file_size)
986 mmap_size = file_size;
987
988 memset(mmaps, 0, sizeof(mmaps));
781 989
782 mmap_prot = PROT_READ; 990 mmap_prot = PROT_READ;
783 mmap_flags = MAP_SHARED; 991 mmap_flags = MAP_SHARED;
784 992
785 if (self->header.needs_swap) { 993 if (session->header.needs_swap) {
786 mmap_prot |= PROT_WRITE; 994 mmap_prot |= PROT_WRITE;
787 mmap_flags = MAP_PRIVATE; 995 mmap_flags = MAP_PRIVATE;
788 } 996 }
789remap: 997remap:
790 buf = mmap(NULL, page_size * self->mmap_window, mmap_prot, 998 buf = mmap(NULL, mmap_size, mmap_prot, mmap_flags, session->fd,
791 mmap_flags, self->fd, offset); 999 file_offset);
792 if (buf == MAP_FAILED) { 1000 if (buf == MAP_FAILED) {
793 pr_err("failed to mmap file\n"); 1001 pr_err("failed to mmap file\n");
794 err = -errno; 1002 err = -errno;
795 goto out_err; 1003 goto out_err;
796 } 1004 }
1005 mmaps[map_idx] = buf;
1006 map_idx = (map_idx + 1) & (ARRAY_SIZE(mmaps) - 1);
1007 file_pos = file_offset + head;
797 1008
798more: 1009more:
799 event = (event_t *)(buf + head); 1010 event = (union perf_event *)(buf + head);
800 ui_progress__update(progress, offset);
801 1011
802 if (self->header.needs_swap) 1012 if (session->header.needs_swap)
803 perf_event_header__bswap(&event->header); 1013 perf_event_header__bswap(&event->header);
804 size = event->header.size; 1014 size = event->header.size;
805 if (size == 0) 1015 if (size == 0)
806 size = 8; 1016 size = 8;
807 1017
808 if (head + event->header.size >= page_size * self->mmap_window) { 1018 if (head + event->header.size > mmap_size) {
809 int munmap_ret; 1019 if (mmaps[map_idx]) {
810 1020 munmap(mmaps[map_idx], mmap_size);
811 shift = page_size * (head / page_size); 1021 mmaps[map_idx] = NULL;
812 1022 }
813 munmap_ret = munmap(buf, page_size * self->mmap_window);
814 assert(munmap_ret == 0);
815 1023
816 offset += shift; 1024 page_offset = page_size * (head / page_size);
817 head -= shift; 1025 file_offset += page_offset;
1026 head -= page_offset;
818 goto remap; 1027 goto remap;
819 } 1028 }
820 1029
821 size = event->header.size; 1030 size = event->header.size;
822 1031
823 dump_printf("\n%#Lx [%#x]: event: %d\n",
824 offset + head, event->header.size, event->header.type);
825
826 if (size == 0 || 1032 if (size == 0 ||
827 perf_session__process_event(self, event, ops, offset, head) < 0) { 1033 perf_session__process_event(session, event, ops, file_pos) < 0) {
828 dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n", 1034 dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n",
829 offset + head, event->header.size, 1035 file_offset + head, event->header.size,
830 event->header.type); 1036 event->header.type);
831 /* 1037 /*
832 * assume we lost track of the stream, check alignment, and 1038 * assume we lost track of the stream, check alignment, and
@@ -839,19 +1045,24 @@ more:
839 } 1045 }
840 1046
841 head += size; 1047 head += size;
1048 file_pos += size;
842 1049
843 if (offset + head >= data_offset + data_size) 1050 if (file_pos >= progress_next) {
844 goto done; 1051 progress_next += file_size / 16;
1052 ui_progress__update(progress, file_pos);
1053 }
845 1054
846 if (offset + head < file_size) 1055 if (file_pos < file_size)
847 goto more; 1056 goto more;
848done: 1057
849 err = 0; 1058 err = 0;
850 /* do the final flush for ordered samples */ 1059 /* do the final flush for ordered samples */
851 self->ordered_samples.next_flush = ULLONG_MAX; 1060 session->ordered_samples.next_flush = ULLONG_MAX;
852 flush_sample_queue(self, ops); 1061 flush_sample_queue(session, ops);
853out_err: 1062out_err:
854 ui_progress__delete(progress); 1063 ui_progress__delete(progress);
1064 perf_session__warn_about_errors(session, ops);
1065 perf_session_free_sample_buffers(session);
855 return err; 1066 return err;
856} 1067}
857 1068
@@ -929,3 +1140,79 @@ 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); 1140 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); 1141 return ret + machines__fprintf_dsos_buildid(&self->machines, fp, with_hits);
931} 1142}
1143
1144size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
1145{
1146 struct perf_evsel *pos;
1147 size_t ret = fprintf(fp, "Aggregated stats:\n");
1148
1149 ret += hists__fprintf_nr_events(&session->hists, fp);
1150
1151 list_for_each_entry(pos, &session->evlist->entries, node) {
1152 ret += fprintf(fp, "%s stats:\n", event_name(pos));
1153 ret += hists__fprintf_nr_events(&pos->hists, fp);
1154 }
1155
1156 return ret;
1157}
1158
1159void perf_session__print_symbols(union perf_event *event,
1160 struct perf_sample *sample,
1161 struct perf_session *session)
1162{
1163 struct addr_location al;
1164 const char *symname, *dsoname;
1165 struct callchain_cursor *cursor = &session->callchain_cursor;
1166 struct callchain_cursor_node *node;
1167
1168 if (perf_event__preprocess_sample(event, session, &al, sample,
1169 NULL) < 0) {
1170 error("problem processing %d event, skipping it.\n",
1171 event->header.type);
1172 return;
1173 }
1174
1175 if (symbol_conf.use_callchain && sample->callchain) {
1176
1177 if (perf_session__resolve_callchain(session, al.thread,
1178 sample->callchain, NULL) != 0) {
1179 if (verbose)
1180 error("Failed to resolve callchain. Skipping\n");
1181 return;
1182 }
1183 callchain_cursor_commit(cursor);
1184
1185 while (1) {
1186 node = callchain_cursor_current(cursor);
1187 if (!node)
1188 break;
1189
1190 if (node->sym && node->sym->name)
1191 symname = node->sym->name;
1192 else
1193 symname = "";
1194
1195 if (node->map && node->map->dso && node->map->dso->name)
1196 dsoname = node->map->dso->name;
1197 else
1198 dsoname = "";
1199
1200 printf("\t%16" PRIx64 " %s (%s)\n", node->ip, symname, dsoname);
1201
1202 callchain_cursor_advance(cursor);
1203 }
1204
1205 } else {
1206 if (al.sym && al.sym->name)
1207 symname = al.sym->name;
1208 else
1209 symname = "";
1210
1211 if (al.map && al.map->dso && al.map->dso->name)
1212 dsoname = al.map->dso->name;
1213 else
1214 dsoname = "";
1215
1216 printf("%16" PRIx64 " %s (%s)", al.addr, symname, dsoname);
1217 }
1218}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 9fa0fc2a863f..1ac481fc1100 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,61 @@ 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;
42 int fd; 46 int fd;
43 bool fd_pipe; 47 bool fd_pipe;
44 bool repipe; 48 bool repipe;
49 bool sample_id_all;
50 u16 id_hdr_size;
45 int cwdlen; 51 int cwdlen;
46 char *cwd; 52 char *cwd;
47 struct ordered_samples ordered_samples; 53 struct ordered_samples ordered_samples;
48 char filename[0]; 54 struct callchain_cursor callchain_cursor;
55 char filename[0];
49}; 56};
50 57
58struct perf_evsel;
51struct perf_event_ops; 59struct perf_event_ops;
52 60
53typedef int (*event_op)(event_t *self, struct perf_session *session); 61typedef int (*event_sample)(union perf_event *event, struct perf_sample *sample,
54typedef int (*event_op2)(event_t *self, struct perf_session *session, 62 struct perf_evsel *evsel, struct perf_session *session);
63typedef int (*event_op)(union perf_event *self, struct perf_sample *sample,
64 struct perf_session *session);
65typedef int (*event_synth_op)(union perf_event *self,
66 struct perf_session *session);
67typedef int (*event_op2)(union perf_event *self, struct perf_session *session,
55 struct perf_event_ops *ops); 68 struct perf_event_ops *ops);
56 69
57struct perf_event_ops { 70struct perf_event_ops {
58 event_op sample, 71 event_sample sample;
59 mmap, 72 event_op mmap,
60 comm, 73 comm,
61 fork, 74 fork,
62 exit, 75 exit,
63 lost, 76 lost,
64 read, 77 read,
65 throttle, 78 throttle,
66 unthrottle, 79 unthrottle;
67 attr, 80 event_synth_op attr,
68 event_type, 81 event_type,
69 tracing_data, 82 tracing_data,
70 build_id; 83 build_id;
71 event_op2 finished_round; 84 event_op2 finished_round;
72 bool ordered_samples; 85 bool ordered_samples;
86 bool ordering_requires_timestamps;
73}; 87};
74 88
75struct perf_session *perf_session__new(const char *filename, int mode, bool force, bool repipe); 89struct perf_session *perf_session__new(const char *filename, int mode,
90 bool force, bool repipe,
91 struct perf_event_ops *ops);
76void perf_session__delete(struct perf_session *self); 92void perf_session__delete(struct perf_session *self);
77 93
78void perf_event_header__bswap(struct perf_event_header *self); 94void perf_event_header__bswap(struct perf_event_header *self);
@@ -83,10 +99,10 @@ int __perf_session__process_events(struct perf_session *self,
83int perf_session__process_events(struct perf_session *self, 99int perf_session__process_events(struct perf_session *self,
84 struct perf_event_ops *event_ops); 100 struct perf_event_ops *event_ops);
85 101
86struct map_symbol *perf_session__resolve_callchain(struct perf_session *self, 102int perf_session__resolve_callchain(struct perf_session *self,
87 struct thread *thread, 103 struct thread *thread,
88 struct ip_callchain *chain, 104 struct ip_callchain *chain,
89 struct symbol **parent); 105 struct symbol **parent);
90 106
91bool perf_session__has_traces(struct perf_session *self, const char *msg); 107bool perf_session__has_traces(struct perf_session *self, const char *msg);
92 108
@@ -98,7 +114,6 @@ void mem_bswap_64(void *src, int byte_size);
98 114
99int perf_session__create_kernel_maps(struct perf_session *self); 115int perf_session__create_kernel_maps(struct perf_session *self);
100 116
101int do_read(int fd, void *buf, size_t size);
102void perf_session__update_sample_type(struct perf_session *self); 117void perf_session__update_sample_type(struct perf_session *self);
103void perf_session__remove_thread(struct perf_session *self, struct thread *th); 118void perf_session__remove_thread(struct perf_session *self, struct thread *th);
104 119
@@ -137,9 +152,18 @@ size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp);
137size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, 152size_t perf_session__fprintf_dsos_buildid(struct perf_session *self,
138 FILE *fp, bool with_hits); 153 FILE *fp, bool with_hits);
139 154
140static inline 155size_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) 156
157static inline int perf_session__parse_sample(struct perf_session *session,
158 const union perf_event *event,
159 struct perf_sample *sample)
142{ 160{
143 return hists__fprintf_nr_events(&self->hists, fp); 161 return perf_event__parse_sample(event, session->sample_type,
162 session->sample_id_all, sample);
144} 163}
164
165void perf_session__print_symbols(union perf_event *event,
166 struct perf_sample *sample,
167 struct perf_session *session);
168
145#endif /* __PERF_SESSION_H */ 169#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/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 0500895a45af..f06c10f092ba 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,6 +23,10 @@
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
@@ -41,6 +46,7 @@ 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 *self)
@@ -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
@@ -121,7 +127,7 @@ 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 *self)
@@ -148,7 +154,7 @@ static struct symbol *symbol__new(u64 start, u64 len, u8 binding,
148 self->binding = binding; 154 self->binding = binding;
149 self->namelen = namelen - 1; 155 self->namelen = namelen - 1;
150 156
151 pr_debug4("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end); 157 pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n", __func__, name, start, self->end);
152 158
153 memcpy(self->name, name, namelen); 159 memcpy(self->name, name, namelen);
154 160
@@ -162,7 +168,7 @@ void symbol__delete(struct symbol *self)
162 168
163static size_t symbol__fprintf(struct symbol *self, FILE *fp) 169static size_t symbol__fprintf(struct symbol *self, 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 self->start, self->end,
167 self->binding == STB_GLOBAL ? 'g' : 173 self->binding == STB_GLOBAL ? 'g' :
168 self->binding == STB_LOCAL ? 'l' : 'w', 174 self->binding == STB_LOCAL ? 'l' : 'w',
@@ -201,8 +207,7 @@ struct dso *dso__new(const char *name)
201 dso__set_short_name(self, self->name); 207 dso__set_short_name(self, self->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 self->symbols[i] = self->symbol_names[i] = RB_ROOT;
204 self->slen_calculated = 0; 210 self->symtab_type = SYMTAB__NOT_FOUND;
205 self->origin = DSO__ORIG_NOT_FOUND;
206 self->loaded = 0; 211 self->loaded = 0;
207 self->sorted_by_name = 0; 212 self->sorted_by_name = 0;
208 self->has_build_id = 0; 213 self->has_build_id = 0;
@@ -425,16 +430,25 @@ size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
425 430
426int kallsyms__parse(const char *filename, void *arg, 431int kallsyms__parse(const char *filename, void *arg,
427 int (*process_symbol)(void *arg, const char *name, 432 int (*process_symbol)(void *arg, const char *name,
428 char type, u64 start)) 433 char type, u64 start, u64 end))
429{ 434{
430 char *line = NULL; 435 char *line = NULL;
431 size_t n; 436 size_t n;
432 int err = 0; 437 int err = -1;
438 u64 prev_start = 0;
439 char prev_symbol_type = 0;
440 char *prev_symbol_name;
433 FILE *file = fopen(filename, "r"); 441 FILE *file = fopen(filename, "r");
434 442
435 if (file == NULL) 443 if (file == NULL)
436 goto out_failure; 444 goto out_failure;
437 445
446 prev_symbol_name = malloc(KSYM_NAME_LEN);
447 if (prev_symbol_name == NULL)
448 goto out_close;
449
450 err = 0;
451
438 while (!feof(file)) { 452 while (!feof(file)) {
439 u64 start; 453 u64 start;
440 int line_len, len; 454 int line_len, len;
@@ -454,14 +468,33 @@ int kallsyms__parse(const char *filename, void *arg,
454 continue; 468 continue;
455 469
456 symbol_type = toupper(line[len]); 470 symbol_type = toupper(line[len]);
457 symbol_name = line + len + 2; 471 len += 2;
472 symbol_name = line + len;
473 len = line_len - len;
458 474
459 err = process_symbol(arg, symbol_name, symbol_type, start); 475 if (len >= KSYM_NAME_LEN) {
460 if (err) 476 err = -1;
461 break; 477 break;
478 }
479
480 if (prev_symbol_type) {
481 u64 end = start;
482 if (end != prev_start)
483 --end;
484 err = process_symbol(arg, prev_symbol_name,
485 prev_symbol_type, prev_start, end);
486 if (err)
487 break;
488 }
489
490 memcpy(prev_symbol_name, symbol_name, len + 1);
491 prev_symbol_type = symbol_type;
492 prev_start = start;
462 } 493 }
463 494
495 free(prev_symbol_name);
464 free(line); 496 free(line);
497out_close:
465 fclose(file); 498 fclose(file);
466 return err; 499 return err;
467 500
@@ -483,7 +516,7 @@ static u8 kallsyms2elf_type(char type)
483} 516}
484 517
485static int map__process_kallsym_symbol(void *arg, const char *name, 518static int map__process_kallsym_symbol(void *arg, const char *name,
486 char type, u64 start) 519 char type, u64 start, u64 end)
487{ 520{
488 struct symbol *sym; 521 struct symbol *sym;
489 struct process_kallsyms_args *a = arg; 522 struct process_kallsyms_args *a = arg;
@@ -492,11 +525,8 @@ static int map__process_kallsym_symbol(void *arg, const char *name,
492 if (!symbol_type__is_a(type, a->map->type)) 525 if (!symbol_type__is_a(type, a->map->type))
493 return 0; 526 return 0;
494 527
495 /* 528 sym = symbol__new(start, end - start + 1,
496 * Will fix up the end later, when we have all symbols sorted. 529 kallsyms2elf_type(type), name);
497 */
498 sym = symbol__new(start, 0, kallsyms2elf_type(type), name);
499
500 if (sym == NULL) 530 if (sym == NULL)
501 return -ENOMEM; 531 return -ENOMEM;
502 /* 532 /*
@@ -532,7 +562,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
532 struct machine *machine = kmaps->machine; 562 struct machine *machine = kmaps->machine;
533 struct map *curr_map = map; 563 struct map *curr_map = map;
534 struct symbol *pos; 564 struct symbol *pos;
535 int count = 0; 565 int count = 0, moved = 0;
536 struct rb_root *root = &self->symbols[map->type]; 566 struct rb_root *root = &self->symbols[map->type];
537 struct rb_node *next = rb_first(root); 567 struct rb_node *next = rb_first(root);
538 int kernel_range = 0; 568 int kernel_range = 0;
@@ -590,6 +620,11 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
590 char dso_name[PATH_MAX]; 620 char dso_name[PATH_MAX];
591 struct dso *dso; 621 struct dso *dso;
592 622
623 if (count == 0) {
624 curr_map = map;
625 goto filter_symbol;
626 }
627
593 if (self->kernel == DSO_TYPE_GUEST_KERNEL) 628 if (self->kernel == DSO_TYPE_GUEST_KERNEL)
594 snprintf(dso_name, sizeof(dso_name), 629 snprintf(dso_name, sizeof(dso_name),
595 "[guest.kernel].%d", 630 "[guest.kernel].%d",
@@ -615,7 +650,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
615 map_groups__insert(kmaps, curr_map); 650 map_groups__insert(kmaps, curr_map);
616 ++kernel_range; 651 ++kernel_range;
617 } 652 }
618 653filter_symbol:
619 if (filter && filter(curr_map, pos)) { 654 if (filter && filter(curr_map, pos)) {
620discard_symbol: rb_erase(&pos->rb_node, root); 655discard_symbol: rb_erase(&pos->rb_node, root);
621 symbol__delete(pos); 656 symbol__delete(pos);
@@ -623,8 +658,9 @@ discard_symbol: rb_erase(&pos->rb_node, root);
623 if (curr_map != map) { 658 if (curr_map != map) {
624 rb_erase(&pos->rb_node, root); 659 rb_erase(&pos->rb_node, root);
625 symbols__insert(&curr_map->dso->symbols[curr_map->type], pos); 660 symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
626 } 661 ++moved;
627 count++; 662 } else
663 ++count;
628 } 664 }
629 } 665 }
630 666
@@ -634,7 +670,7 @@ discard_symbol: rb_erase(&pos->rb_node, root);
634 dso__set_loaded(curr_map->dso, curr_map->type); 670 dso__set_loaded(curr_map->dso, curr_map->type);
635 } 671 }
636 672
637 return count; 673 return count + moved;
638} 674}
639 675
640int dso__load_kallsyms(struct dso *self, const char *filename, 676int dso__load_kallsyms(struct dso *self, const char *filename,
@@ -643,11 +679,10 @@ int dso__load_kallsyms(struct dso *self, const char *filename,
643 if (dso__load_all_kallsyms(self, filename, map) < 0) 679 if (dso__load_all_kallsyms(self, filename, map) < 0)
644 return -1; 680 return -1;
645 681
646 symbols__fixup_end(&self->symbols[map->type]);
647 if (self->kernel == DSO_TYPE_GUEST_KERNEL) 682 if (self->kernel == DSO_TYPE_GUEST_KERNEL)
648 self->origin = DSO__ORIG_GUEST_KERNEL; 683 self->symtab_type = SYMTAB__GUEST_KALLSYMS;
649 else 684 else
650 self->origin = DSO__ORIG_KERNEL; 685 self->symtab_type = SYMTAB__KALLSYMS;
651 686
652 return dso__split_kallsyms(self, map, filter); 687 return dso__split_kallsyms(self, map, filter);
653} 688}
@@ -833,8 +868,11 @@ static int dso__synthesize_plt_symbols(struct dso *self, struct map *map,
833 char sympltname[1024]; 868 char sympltname[1024];
834 Elf *elf; 869 Elf *elf;
835 int nr = 0, symidx, fd, err = 0; 870 int nr = 0, symidx, fd, err = 0;
871 char name[PATH_MAX];
836 872
837 fd = open(self->long_name, O_RDONLY); 873 snprintf(name, sizeof(name), "%s%s",
874 symbol_conf.symfs, self->long_name);
875 fd = open(name, O_RDONLY);
838 if (fd < 0) 876 if (fd < 0)
839 goto out; 877 goto out;
840 878
@@ -1123,6 +1161,13 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
1123 1161
1124 section_name = elf_sec__name(&shdr, secstrs); 1162 section_name = elf_sec__name(&shdr, secstrs);
1125 1163
1164 /* On ARM, symbols for thumb functions have 1 added to
1165 * the symbol address as a flag - remove it */
1166 if ((ehdr.e_machine == EM_ARM) &&
1167 (map->type == MAP__FUNCTION) &&
1168 (sym.st_value & 1))
1169 --sym.st_value;
1170
1126 if (self->kernel != DSO_TYPE_USER || kmodule) { 1171 if (self->kernel != DSO_TYPE_USER || kmodule) {
1127 char dso_name[PATH_MAX]; 1172 char dso_name[PATH_MAX];
1128 1173
@@ -1151,6 +1196,8 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
1151 if (curr_dso == NULL) 1196 if (curr_dso == NULL)
1152 goto out_elf_end; 1197 goto out_elf_end;
1153 curr_dso->kernel = self->kernel; 1198 curr_dso->kernel = self->kernel;
1199 curr_dso->long_name = self->long_name;
1200 curr_dso->long_name_len = self->long_name_len;
1154 curr_map = map__new2(start, curr_dso, 1201 curr_map = map__new2(start, curr_dso,
1155 map->type); 1202 map->type);
1156 if (curr_map == NULL) { 1203 if (curr_map == NULL) {
@@ -1159,7 +1206,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
1159 } 1206 }
1160 curr_map->map_ip = identity__map_ip; 1207 curr_map->map_ip = identity__map_ip;
1161 curr_map->unmap_ip = identity__map_ip; 1208 curr_map->unmap_ip = identity__map_ip;
1162 curr_dso->origin = self->origin; 1209 curr_dso->symtab_type = self->symtab_type;
1163 map_groups__insert(kmap->kmaps, curr_map); 1210 map_groups__insert(kmap->kmaps, curr_map);
1164 dsos__add(&self->node, curr_dso); 1211 dsos__add(&self->node, curr_dso);
1165 dso__set_loaded(curr_dso, map->type); 1212 dso__set_loaded(curr_dso, map->type);
@@ -1170,8 +1217,8 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
1170 } 1217 }
1171 1218
1172 if (curr_dso->adjust_symbols) { 1219 if (curr_dso->adjust_symbols) {
1173 pr_debug4("%s: adjusting symbol: st_value: %#Lx " 1220 pr_debug4("%s: adjusting symbol: st_value: %#" PRIx64 " "
1174 "sh_addr: %#Lx sh_offset: %#Lx\n", __func__, 1221 "sh_addr: %#" PRIx64 " sh_offset: %#" PRIx64 "\n", __func__,
1175 (u64)sym.st_value, (u64)shdr.sh_addr, 1222 (u64)sym.st_value, (u64)shdr.sh_addr,
1176 (u64)shdr.sh_offset); 1223 (u64)shdr.sh_offset);
1177 sym.st_value -= shdr.sh_addr - shdr.sh_offset; 1224 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
@@ -1385,21 +1432,21 @@ out:
1385char dso__symtab_origin(const struct dso *self) 1432char dso__symtab_origin(const struct dso *self)
1386{ 1433{
1387 static const char origin[] = { 1434 static const char origin[] = {
1388 [DSO__ORIG_KERNEL] = 'k', 1435 [SYMTAB__KALLSYMS] = 'k',
1389 [DSO__ORIG_JAVA_JIT] = 'j', 1436 [SYMTAB__JAVA_JIT] = 'j',
1390 [DSO__ORIG_BUILD_ID_CACHE] = 'B', 1437 [SYMTAB__BUILD_ID_CACHE] = 'B',
1391 [DSO__ORIG_FEDORA] = 'f', 1438 [SYMTAB__FEDORA_DEBUGINFO] = 'f',
1392 [DSO__ORIG_UBUNTU] = 'u', 1439 [SYMTAB__UBUNTU_DEBUGINFO] = 'u',
1393 [DSO__ORIG_BUILDID] = 'b', 1440 [SYMTAB__BUILDID_DEBUGINFO] = 'b',
1394 [DSO__ORIG_DSO] = 'd', 1441 [SYMTAB__SYSTEM_PATH_DSO] = 'd',
1395 [DSO__ORIG_KMODULE] = 'K', 1442 [SYMTAB__SYSTEM_PATH_KMODULE] = 'K',
1396 [DSO__ORIG_GUEST_KERNEL] = 'g', 1443 [SYMTAB__GUEST_KALLSYMS] = 'g',
1397 [DSO__ORIG_GUEST_KMODULE] = 'G', 1444 [SYMTAB__GUEST_KMODULE] = 'G',
1398 }; 1445 };
1399 1446
1400 if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) 1447 if (self == NULL || self->symtab_type == SYMTAB__NOT_FOUND)
1401 return '!'; 1448 return '!';
1402 return origin[self->origin]; 1449 return origin[self->symtab_type];
1403} 1450}
1404 1451
1405int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) 1452int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
@@ -1432,8 +1479,8 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
1432 1479
1433 if (strncmp(self->name, "/tmp/perf-", 10) == 0) { 1480 if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
1434 ret = dso__load_perf_map(self, map, filter); 1481 ret = dso__load_perf_map(self, map, filter);
1435 self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : 1482 self->symtab_type = ret > 0 ? SYMTAB__JAVA_JIT :
1436 DSO__ORIG_NOT_FOUND; 1483 SYMTAB__NOT_FOUND;
1437 return ret; 1484 return ret;
1438 } 1485 }
1439 1486
@@ -1441,23 +1488,28 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
1441 * On the first pass, only load images if they have a full symtab. 1488 * On the first pass, only load images if they have a full symtab.
1442 * Failing that, do a second pass where we accept .dynsym also 1489 * Failing that, do a second pass where we accept .dynsym also
1443 */ 1490 */
1444 for (self->origin = DSO__ORIG_BUILD_ID_CACHE, want_symtab = 1; 1491 want_symtab = 1;
1445 self->origin != DSO__ORIG_NOT_FOUND; 1492restart:
1446 self->origin++) { 1493 for (self->symtab_type = SYMTAB__BUILD_ID_CACHE;
1447 switch (self->origin) { 1494 self->symtab_type != SYMTAB__NOT_FOUND;
1448 case DSO__ORIG_BUILD_ID_CACHE: 1495 self->symtab_type++) {
1449 if (dso__build_id_filename(self, name, size) == NULL) 1496 switch (self->symtab_type) {
1497 case SYMTAB__BUILD_ID_CACHE:
1498 /* skip the locally configured cache if a symfs is given */
1499 if (symbol_conf.symfs[0] ||
1500 (dso__build_id_filename(self, name, size) == NULL)) {
1450 continue; 1501 continue;
1502 }
1451 break; 1503 break;
1452 case DSO__ORIG_FEDORA: 1504 case SYMTAB__FEDORA_DEBUGINFO:
1453 snprintf(name, size, "/usr/lib/debug%s.debug", 1505 snprintf(name, size, "%s/usr/lib/debug%s.debug",
1454 self->long_name); 1506 symbol_conf.symfs, self->long_name);
1455 break; 1507 break;
1456 case DSO__ORIG_UBUNTU: 1508 case SYMTAB__UBUNTU_DEBUGINFO:
1457 snprintf(name, size, "/usr/lib/debug%s", 1509 snprintf(name, size, "%s/usr/lib/debug%s",
1458 self->long_name); 1510 symbol_conf.symfs, self->long_name);
1459 break; 1511 break;
1460 case DSO__ORIG_BUILDID: { 1512 case SYMTAB__BUILDID_DEBUGINFO: {
1461 char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 1513 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
1462 1514
1463 if (!self->has_build_id) 1515 if (!self->has_build_id)
@@ -1467,31 +1519,28 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
1467 sizeof(self->build_id), 1519 sizeof(self->build_id),
1468 build_id_hex); 1520 build_id_hex);
1469 snprintf(name, size, 1521 snprintf(name, size,
1470 "/usr/lib/debug/.build-id/%.2s/%s.debug", 1522 "%s/usr/lib/debug/.build-id/%.2s/%s.debug",
1471 build_id_hex, build_id_hex + 2); 1523 symbol_conf.symfs, build_id_hex, build_id_hex + 2);
1472 } 1524 }
1473 break; 1525 break;
1474 case DSO__ORIG_DSO: 1526 case SYMTAB__SYSTEM_PATH_DSO:
1475 snprintf(name, size, "%s", self->long_name); 1527 snprintf(name, size, "%s%s",
1528 symbol_conf.symfs, self->long_name);
1476 break; 1529 break;
1477 case DSO__ORIG_GUEST_KMODULE: 1530 case SYMTAB__GUEST_KMODULE:
1478 if (map->groups && map->groups->machine) 1531 if (map->groups && machine)
1479 root_dir = map->groups->machine->root_dir; 1532 root_dir = machine->root_dir;
1480 else 1533 else
1481 root_dir = ""; 1534 root_dir = "";
1482 snprintf(name, size, "%s%s", root_dir, self->long_name); 1535 snprintf(name, size, "%s%s%s", symbol_conf.symfs,
1536 root_dir, self->long_name);
1483 break; 1537 break;
1484 1538
1485 default: 1539 case SYMTAB__SYSTEM_PATH_KMODULE:
1486 /* 1540 snprintf(name, size, "%s%s", symbol_conf.symfs,
1487 * If we wanted a full symtab but no image had one, 1541 self->long_name);
1488 * relax our requirements and repeat the search. 1542 break;
1489 */ 1543 default:;
1490 if (want_symtab) {
1491 want_symtab = 0;
1492 self->origin = DSO__ORIG_BUILD_ID_CACHE;
1493 } else
1494 continue;
1495 } 1544 }
1496 1545
1497 /* Name is now the name of the next image to try */ 1546 /* Name is now the name of the next image to try */
@@ -1518,6 +1567,15 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
1518 } 1567 }
1519 } 1568 }
1520 1569
1570 /*
1571 * If we wanted a full symtab but no image had one,
1572 * relax our requirements and repeat the search.
1573 */
1574 if (ret <= 0 && want_symtab) {
1575 want_symtab = 0;
1576 goto restart;
1577 }
1578
1521 free(name); 1579 free(name);
1522 if (ret < 0 && strstr(self->name, " (deleted)") != NULL) 1580 if (ret < 0 && strstr(self->name, " (deleted)") != NULL)
1523 return 0; 1581 return 0;
@@ -1702,9 +1760,9 @@ struct map *machine__new_module(struct machine *self, u64 start,
1702 return NULL; 1760 return NULL;
1703 1761
1704 if (machine__is_host(self)) 1762 if (machine__is_host(self))
1705 dso->origin = DSO__ORIG_KMODULE; 1763 dso->symtab_type = SYMTAB__SYSTEM_PATH_KMODULE;
1706 else 1764 else
1707 dso->origin = DSO__ORIG_GUEST_KMODULE; 1765 dso->symtab_type = SYMTAB__GUEST_KMODULE;
1708 map_groups__insert(&self->kmaps, map); 1766 map_groups__insert(&self->kmaps, map);
1709 return map; 1767 return map;
1710} 1768}
@@ -1774,21 +1832,25 @@ out_failure:
1774 return -1; 1832 return -1;
1775} 1833}
1776 1834
1777static int dso__load_vmlinux(struct dso *self, struct map *map, 1835int dso__load_vmlinux(struct dso *self, struct map *map,
1778 const char *vmlinux, symbol_filter_t filter) 1836 const char *vmlinux, symbol_filter_t filter)
1779{ 1837{
1780 int err = -1, fd; 1838 int err = -1, fd;
1839 char symfs_vmlinux[PATH_MAX];
1781 1840
1782 fd = open(vmlinux, O_RDONLY); 1841 snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s",
1842 symbol_conf.symfs, vmlinux);
1843 fd = open(symfs_vmlinux, O_RDONLY);
1783 if (fd < 0) 1844 if (fd < 0)
1784 return -1; 1845 return -1;
1785 1846
1847 dso__set_long_name(self, (char *)vmlinux);
1786 dso__set_loaded(self, map->type); 1848 dso__set_loaded(self, map->type);
1787 err = dso__load_sym(self, map, vmlinux, fd, filter, 0, 0); 1849 err = dso__load_sym(self, map, symfs_vmlinux, fd, filter, 0, 0);
1788 close(fd); 1850 close(fd);
1789 1851
1790 if (err > 0) 1852 if (err > 0)
1791 pr_debug("Using %s for symbols\n", vmlinux); 1853 pr_debug("Using %s for symbols\n", symfs_vmlinux);
1792 1854
1793 return err; 1855 return err;
1794} 1856}
@@ -1830,8 +1892,8 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
1830 const char *kallsyms_filename = NULL; 1892 const char *kallsyms_filename = NULL;
1831 char *kallsyms_allocated_filename = NULL; 1893 char *kallsyms_allocated_filename = NULL;
1832 /* 1894 /*
1833 * Step 1: if the user specified a vmlinux filename, use it and only 1895 * Step 1: if the user specified a kallsyms or vmlinux filename, use
1834 * it, reporting errors to the user if it cannot be used. 1896 * it and only it, reporting errors to the user if it cannot be used.
1835 * 1897 *
1836 * For instance, try to analyse an ARM perf.data file _without_ a 1898 * For instance, try to analyse an ARM perf.data file _without_ a
1837 * build-id, or if the user specifies the wrong path to the right 1899 * build-id, or if the user specifies the wrong path to the right
@@ -1844,6 +1906,11 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
1844 * validation in dso__load_vmlinux and will bail out if they don't 1906 * validation in dso__load_vmlinux and will bail out if they don't
1845 * match. 1907 * match.
1846 */ 1908 */
1909 if (symbol_conf.kallsyms_name != NULL) {
1910 kallsyms_filename = symbol_conf.kallsyms_name;
1911 goto do_kallsyms;
1912 }
1913
1847 if (symbol_conf.vmlinux_name != NULL) { 1914 if (symbol_conf.vmlinux_name != NULL) {
1848 err = dso__load_vmlinux(self, map, 1915 err = dso__load_vmlinux(self, map,
1849 symbol_conf.vmlinux_name, filter); 1916 symbol_conf.vmlinux_name, filter);
@@ -1861,6 +1928,10 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
1861 goto out_fixup; 1928 goto out_fixup;
1862 } 1929 }
1863 1930
1931 /* do not try local files if a symfs was given */
1932 if (symbol_conf.symfs[0] != 0)
1933 return -1;
1934
1864 /* 1935 /*
1865 * Say the kernel DSO was created when processing the build-id header table, 1936 * Say the kernel DSO was created when processing the build-id header table,
1866 * we have a build-id, so check if it is the same as the running kernel, 1937 * we have a build-id, so check if it is the same as the running kernel,
@@ -2125,14 +2196,55 @@ static struct dso *machine__create_kernel(struct machine *self)
2125 return kernel; 2196 return kernel;
2126} 2197}
2127 2198
2199struct process_args {
2200 u64 start;
2201};
2202
2203static int symbol__in_kernel(void *arg, const char *name,
2204 char type __used, u64 start, u64 end __used)
2205{
2206 struct process_args *args = arg;
2207
2208 if (strchr(name, '['))
2209 return 0;
2210
2211 args->start = start;
2212 return 1;
2213}
2214
2215/* Figure out the start address of kernel map from /proc/kallsyms */
2216static u64 machine__get_kernel_start_addr(struct machine *machine)
2217{
2218 const char *filename;
2219 char path[PATH_MAX];
2220 struct process_args args;
2221
2222 if (machine__is_host(machine)) {
2223 filename = "/proc/kallsyms";
2224 } else {
2225 if (machine__is_default_guest(machine))
2226 filename = (char *)symbol_conf.default_guest_kallsyms;
2227 else {
2228 sprintf(path, "%s/proc/kallsyms", machine->root_dir);
2229 filename = path;
2230 }
2231 }
2232
2233 if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0)
2234 return 0;
2235
2236 return args.start;
2237}
2238
2128int __machine__create_kernel_maps(struct machine *self, struct dso *kernel) 2239int __machine__create_kernel_maps(struct machine *self, struct dso *kernel)
2129{ 2240{
2130 enum map_type type; 2241 enum map_type type;
2242 u64 start = machine__get_kernel_start_addr(self);
2131 2243
2132 for (type = 0; type < MAP__NR_TYPES; ++type) { 2244 for (type = 0; type < MAP__NR_TYPES; ++type) {
2133 struct kmap *kmap; 2245 struct kmap *kmap;
2134 2246
2135 self->vmlinux_maps[type] = map__new2(0, kernel, type); 2247 self->vmlinux_maps[type] = map__new2(start, kernel, type);
2136 if (self->vmlinux_maps[type] == NULL) 2248 if (self->vmlinux_maps[type] == NULL)
2137 return -1; 2249 return -1;
2138 2250
@@ -2210,9 +2322,6 @@ static int vmlinux_path__init(void)
2210 struct utsname uts; 2322 struct utsname uts;
2211 char bf[PATH_MAX]; 2323 char bf[PATH_MAX];
2212 2324
2213 if (uname(&uts) < 0)
2214 return -1;
2215
2216 vmlinux_path = malloc(sizeof(char *) * 5); 2325 vmlinux_path = malloc(sizeof(char *) * 5);
2217 if (vmlinux_path == NULL) 2326 if (vmlinux_path == NULL)
2218 return -1; 2327 return -1;
@@ -2225,6 +2334,14 @@ static int vmlinux_path__init(void)
2225 if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2334 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2226 goto out_fail; 2335 goto out_fail;
2227 ++vmlinux_path__nr_entries; 2336 ++vmlinux_path__nr_entries;
2337
2338 /* only try running kernel version if no symfs was given */
2339 if (symbol_conf.symfs[0] != 0)
2340 return 0;
2341
2342 if (uname(&uts) < 0)
2343 return -1;
2344
2228 snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release); 2345 snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
2229 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 2346 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
2230 if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2347 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
@@ -2284,9 +2401,13 @@ static int setup_list(struct strlist **list, const char *list_str,
2284 2401
2285int symbol__init(void) 2402int symbol__init(void)
2286{ 2403{
2404 const char *symfs;
2405
2287 if (symbol_conf.initialized) 2406 if (symbol_conf.initialized)
2288 return 0; 2407 return 0;
2289 2408
2409 symbol_conf.priv_size = ALIGN(symbol_conf.priv_size, sizeof(u64));
2410
2290 elf_version(EV_CURRENT); 2411 elf_version(EV_CURRENT);
2291 if (symbol_conf.sort_by_name) 2412 if (symbol_conf.sort_by_name)
2292 symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - 2413 symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
@@ -2312,6 +2433,18 @@ int symbol__init(void)
2312 symbol_conf.sym_list_str, "symbol") < 0) 2433 symbol_conf.sym_list_str, "symbol") < 0)
2313 goto out_free_comm_list; 2434 goto out_free_comm_list;
2314 2435
2436 /*
2437 * A path to symbols of "/" is identical to ""
2438 * reset here for simplicity.
2439 */
2440 symfs = realpath(symbol_conf.symfs, NULL);
2441 if (symfs == NULL)
2442 symfs = symbol_conf.symfs;
2443 if (strcmp(symfs, "/") == 0)
2444 symbol_conf.symfs = "";
2445 if (symfs != symbol_conf.symfs)
2446 free((void *)symfs);
2447
2315 symbol_conf.initialized = true; 2448 symbol_conf.initialized = true;
2316 return 0; 2449 return 0;
2317 2450
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 038f2201ee09..713b0b40cc4a 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -48,12 +48,17 @@ 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
@@ -72,6 +77,7 @@ struct symbol_conf {
72 show_cpu_utilization, 77 show_cpu_utilization,
73 initialized; 78 initialized;
74 const char *vmlinux_name, 79 const char *vmlinux_name,
80 *kallsyms_name,
75 *source_prefix, 81 *source_prefix,
76 *field_sep; 82 *field_sep;
77 const char *default_guest_vmlinux_name, 83 const char *default_guest_vmlinux_name,
@@ -85,6 +91,7 @@ struct symbol_conf {
85 struct strlist *dso_list, 91 struct strlist *dso_list,
86 *comm_list, 92 *comm_list,
87 *sym_list; 93 *sym_list;
94 const char *symfs;
88}; 95};
89 96
90extern struct symbol_conf symbol_conf; 97extern struct symbol_conf symbol_conf;
@@ -130,13 +137,12 @@ struct dso {
130 struct rb_root symbol_names[MAP__NR_TYPES]; 137 struct rb_root symbol_names[MAP__NR_TYPES];
131 enum dso_kernel_type kernel; 138 enum dso_kernel_type kernel;
132 u8 adjust_symbols:1; 139 u8 adjust_symbols:1;
133 u8 slen_calculated:1;
134 u8 has_build_id:1; 140 u8 has_build_id:1;
135 u8 hit:1; 141 u8 hit:1;
136 u8 annotate_warned:1; 142 u8 annotate_warned:1;
137 u8 sname_alloc:1; 143 u8 sname_alloc:1;
138 u8 lname_alloc:1; 144 u8 lname_alloc:1;
139 unsigned char origin; 145 unsigned char symtab_type;
140 u8 sorted_by_name; 146 u8 sorted_by_name;
141 u8 loaded; 147 u8 loaded;
142 u8 build_id[BUILD_ID_SIZE]; 148 u8 build_id[BUILD_ID_SIZE];
@@ -166,6 +172,8 @@ void dso__sort_by_name(struct dso *self, enum map_type type);
166struct dso *__dsos__findnew(struct list_head *head, const char *name); 172struct dso *__dsos__findnew(struct list_head *head, const char *name);
167 173
168int dso__load(struct dso *self, struct map *map, symbol_filter_t filter); 174int dso__load(struct dso *self, struct map *map, symbol_filter_t filter);
175int dso__load_vmlinux(struct dso *self, struct map *map,
176 const char *vmlinux, symbol_filter_t filter);
169int dso__load_vmlinux_path(struct dso *self, struct map *map, 177int dso__load_vmlinux_path(struct dso *self, struct map *map,
170 symbol_filter_t filter); 178 symbol_filter_t filter);
171int dso__load_kallsyms(struct dso *self, const char *filename, struct map *map, 179int dso__load_kallsyms(struct dso *self, const char *filename, struct map *map,
@@ -185,18 +193,18 @@ size_t dso__fprintf_buildid(struct dso *self, FILE *fp);
185size_t dso__fprintf_symbols_by_name(struct dso *self, enum map_type type, FILE *fp); 193size_t dso__fprintf_symbols_by_name(struct dso *self, enum map_type type, FILE *fp);
186size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp); 194size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp);
187 195
188enum dso_origin { 196enum symtab_type {
189 DSO__ORIG_KERNEL = 0, 197 SYMTAB__KALLSYMS = 0,
190 DSO__ORIG_GUEST_KERNEL, 198 SYMTAB__GUEST_KALLSYMS,
191 DSO__ORIG_JAVA_JIT, 199 SYMTAB__JAVA_JIT,
192 DSO__ORIG_BUILD_ID_CACHE, 200 SYMTAB__BUILD_ID_CACHE,
193 DSO__ORIG_FEDORA, 201 SYMTAB__FEDORA_DEBUGINFO,
194 DSO__ORIG_UBUNTU, 202 SYMTAB__UBUNTU_DEBUGINFO,
195 DSO__ORIG_BUILDID, 203 SYMTAB__BUILDID_DEBUGINFO,
196 DSO__ORIG_DSO, 204 SYMTAB__SYSTEM_PATH_DSO,
197 DSO__ORIG_GUEST_KMODULE, 205 SYMTAB__GUEST_KMODULE,
198 DSO__ORIG_KMODULE, 206 SYMTAB__SYSTEM_PATH_KMODULE,
199 DSO__ORIG_NOT_FOUND, 207 SYMTAB__NOT_FOUND,
200}; 208};
201 209
202char dso__symtab_origin(const struct dso *self); 210char dso__symtab_origin(const struct dso *self);
@@ -213,7 +221,7 @@ bool __dsos__read_build_ids(struct list_head *head, bool with_hits);
213int build_id__sprintf(const u8 *self, int len, char *bf); 221int build_id__sprintf(const u8 *self, int len, char *bf);
214int kallsyms__parse(const char *filename, void *arg, 222int kallsyms__parse(const char *filename, void *arg,
215 int (*process_symbol)(void *arg, const char *name, 223 int (*process_symbol)(void *arg, const char *name,
216 char type, u64 start)); 224 char type, u64 start, u64 end));
217 225
218void machine__destroy_kernel_maps(struct machine *self); 226void machine__destroy_kernel_maps(struct machine *self);
219int __machine__create_kernel_maps(struct machine *self, struct dso *kernel); 227int __machine__create_kernel_maps(struct machine *self, struct dso *kernel);
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 8bc010edca25..611219f80680 100644
--- a/tools/perf/util/ui/browser.c
+++ b/tools/perf/util/ui/browser.c
@@ -1,4 +1,5 @@
1#include "libslang.h" 1#include "libslang.h"
2#include "ui.h"
2#include <linux/compiler.h> 3#include <linux/compiler.h>
3#include <linux/list.h> 4#include <linux/list.h>
4#include <linux/rbtree.h> 5#include <linux/rbtree.h>
@@ -156,6 +157,20 @@ void ui_browser__add_exit_keys(struct ui_browser *self, int keys[])
156 } 157 }
157} 158}
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
159int ui_browser__show(struct ui_browser *self, const char *title, 174int ui_browser__show(struct ui_browser *self, const char *title,
160 const char *helpline, ...) 175 const char *helpline, ...)
161{ 176{
@@ -178,9 +193,8 @@ int ui_browser__show(struct ui_browser *self, const char *title,
178 if (self->sb == NULL) 193 if (self->sb == NULL)
179 return -1; 194 return -1;
180 195
181 SLsmg_gotorc(0, 0); 196 pthread_mutex_lock(&ui__lock);
182 ui_browser__set_color(self, NEWT_COLORSET_ROOT); 197 __ui_browser__show_title(self, title);
183 slsmg_write_nstring(title, self->width);
184 198
185 ui_browser__add_exit_keys(self, keys); 199 ui_browser__add_exit_keys(self, keys);
186 newtFormAddComponent(self->form, self->sb); 200 newtFormAddComponent(self->form, self->sb);
@@ -188,25 +202,30 @@ int ui_browser__show(struct ui_browser *self, const char *title,
188 va_start(ap, helpline); 202 va_start(ap, helpline);
189 ui_helpline__vpush(helpline, ap); 203 ui_helpline__vpush(helpline, ap);
190 va_end(ap); 204 va_end(ap);
205 pthread_mutex_unlock(&ui__lock);
191 return 0; 206 return 0;
192} 207}
193 208
194void ui_browser__hide(struct ui_browser *self) 209void ui_browser__hide(struct ui_browser *self)
195{ 210{
211 pthread_mutex_lock(&ui__lock);
196 newtFormDestroy(self->form); 212 newtFormDestroy(self->form);
197 self->form = NULL; 213 self->form = NULL;
198 ui_helpline__pop(); 214 ui_helpline__pop();
215 pthread_mutex_unlock(&ui__lock);
199} 216}
200 217
201int ui_browser__refresh(struct ui_browser *self) 218int ui_browser__refresh(struct ui_browser *self)
202{ 219{
203 int row; 220 int row;
204 221
222 pthread_mutex_lock(&ui__lock);
205 newtScrollbarSet(self->sb, self->index, self->nr_entries - 1); 223 newtScrollbarSet(self->sb, self->index, self->nr_entries - 1);
206 row = self->refresh(self); 224 row = self->refresh(self);
207 ui_browser__set_color(self, HE_COLORSET_NORMAL); 225 ui_browser__set_color(self, HE_COLORSET_NORMAL);
208 SLsmg_fill_region(self->y + row, self->x, 226 SLsmg_fill_region(self->y + row, self->x,
209 self->height - row, self->width, ' '); 227 self->height - row, self->width, ' ');
228 pthread_mutex_unlock(&ui__lock);
210 229
211 return 0; 230 return 0;
212} 231}
diff --git a/tools/perf/util/ui/browser.h b/tools/perf/util/ui/browser.h
index 0dc7e4da36f5..fc63dda10910 100644
--- a/tools/perf/util/ui/browser.h
+++ b/tools/perf/util/ui/browser.h
@@ -24,7 +24,6 @@ struct ui_browser {
24 u32 nr_entries; 24 u32 nr_entries;
25}; 25};
26 26
27
28void ui_browser__set_color(struct ui_browser *self, int color); 27void ui_browser__set_color(struct ui_browser *self, int color);
29void ui_browser__set_percent_color(struct ui_browser *self, 28void ui_browser__set_percent_color(struct ui_browser *self,
30 double percent, bool current); 29 double percent, bool current);
@@ -35,6 +34,8 @@ void ui_browser__reset_index(struct ui_browser *self);
35void ui_browser__gotorc(struct ui_browser *self, int y, int x); 34void ui_browser__gotorc(struct ui_browser *self, int y, int x);
36void ui_browser__add_exit_key(struct ui_browser *self, int key); 35void ui_browser__add_exit_key(struct ui_browser *self, int key);
37void ui_browser__add_exit_keys(struct ui_browser *self, int keys[]); 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);
38int ui_browser__show(struct ui_browser *self, const char *title, 39int ui_browser__show(struct ui_browser *self, const char *title,
39 const char *helpline, ...); 40 const char *helpline, ...);
40void ui_browser__hide(struct ui_browser *self); 41void ui_browser__hide(struct ui_browser *self);
diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c
index 82b78f99251b..15633d608133 100644
--- a/tools/perf/util/ui/browsers/annotate.c
+++ b/tools/perf/util/ui/browsers/annotate.c
@@ -1,9 +1,12 @@
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 "../../annotate.h"
9#include <pthread.h>
7 10
8static void ui__error_window(const char *fmt, ...) 11static void ui__error_window(const char *fmt, ...)
9{ 12{
@@ -42,8 +45,6 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro
42 struct objdump_line_rb_node *olrb = objdump_line__rb(ol); 45 struct objdump_line_rb_node *olrb = objdump_line__rb(ol);
43 ui_browser__set_percent_color(self, olrb->percent, current_entry); 46 ui_browser__set_percent_color(self, olrb->percent, current_entry);
44 slsmg_printf(" %7.2f ", olrb->percent); 47 slsmg_printf(" %7.2f ", olrb->percent);
45 if (!current_entry)
46 ui_browser__set_color(self, HE_COLORSET_CODE);
47 } else { 48 } else {
48 ui_browser__set_percent_color(self, 0, current_entry); 49 ui_browser__set_percent_color(self, 0, current_entry);
49 slsmg_write_nstring(" ", 9); 50 slsmg_write_nstring(" ", 9);
@@ -55,35 +56,40 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro
55 slsmg_write_nstring(" ", width - 18); 56 slsmg_write_nstring(" ", width - 18);
56 else 57 else
57 slsmg_write_nstring(ol->line, width - 18); 58 slsmg_write_nstring(ol->line, width - 18);
59
60 if (!current_entry)
61 ui_browser__set_color(self, HE_COLORSET_CODE);
58} 62}
59 63
60static double objdump_line__calc_percent(struct objdump_line *self, 64static double objdump_line__calc_percent(struct objdump_line *self,
61 struct list_head *head, 65 struct symbol *sym, int evidx)
62 struct symbol *sym)
63{ 66{
64 double percent = 0.0; 67 double percent = 0.0;
65 68
66 if (self->offset != -1) { 69 if (self->offset != -1) {
67 int len = sym->end - sym->start; 70 int len = sym->end - sym->start;
68 unsigned int hits = 0; 71 unsigned int hits = 0;
69 struct sym_priv *priv = symbol__priv(sym); 72 struct annotation *notes = symbol__annotation(sym);
70 struct sym_ext *sym_ext = priv->ext; 73 struct source_line *src_line = notes->src->lines;
71 struct sym_hist *h = priv->hist; 74 struct sym_hist *h = annotation__histogram(notes, evidx);
72 s64 offset = self->offset; 75 s64 offset = self->offset;
73 struct objdump_line *next = objdump__get_next_ip_line(head, self); 76 struct objdump_line *next;
74
75 77
78 next = objdump__get_next_ip_line(&notes->src->source, self);
76 while (offset < (s64)len && 79 while (offset < (s64)len &&
77 (next == NULL || offset < next->offset)) { 80 (next == NULL || offset < next->offset)) {
78 if (sym_ext) { 81 if (src_line) {
79 percent += sym_ext[offset].percent; 82 percent += src_line[offset].percent;
80 } else 83 } else
81 hits += h->ip[offset]; 84 hits += h->addr[offset];
82 85
83 ++offset; 86 ++offset;
84 } 87 }
85 88 /*
86 if (sym_ext == NULL && h->sum) 89 * If the percentage wasn't already calculated in
90 * symbol__get_source_line, do it now:
91 */
92 if (src_line == NULL && h->sum)
87 percent = 100.0 * hits / h->sum; 93 percent = 100.0 * hits / h->sum;
88 } 94 }
89 95
@@ -133,103 +139,163 @@ static void annotate_browser__set_top(struct annotate_browser *self,
133 self->curr_hot = nd; 139 self->curr_hot = nd;
134} 140}
135 141
136static int annotate_browser__run(struct annotate_browser *self) 142static void annotate_browser__calc_percent(struct annotate_browser *browser,
143 int evidx)
137{ 144{
138 struct rb_node *nd; 145 struct symbol *sym = browser->b.priv;
139 struct hist_entry *he = self->b.priv; 146 struct annotation *notes = symbol__annotation(sym);
140 int key; 147 struct objdump_line *pos;
141 148
142 if (ui_browser__show(&self->b, he->ms.sym->name, 149 browser->entries = RB_ROOT;
143 "<-, -> or ESC: exit, TAB/shift+TAB: cycle thru samples") < 0) 150
144 return -1; 151 pthread_mutex_lock(&notes->lock);
152
153 list_for_each_entry(pos, &notes->src->source, node) {
154 struct objdump_line_rb_node *rbpos = objdump_line__rb(pos);
155 rbpos->percent = objdump_line__calc_percent(pos, sym, evidx);
156 if (rbpos->percent < 0.01) {
157 RB_CLEAR_NODE(&rbpos->rb_node);
158 continue;
159 }
160 objdump__insert_line(&browser->entries, rbpos);
161 }
162 pthread_mutex_unlock(&notes->lock);
163
164 browser->curr_hot = rb_last(&browser->entries);
165}
166
167static int annotate_browser__run(struct annotate_browser *self, int evidx,
168 int refresh)
169{
170 struct rb_node *nd = NULL;
171 struct symbol *sym = self->b.priv;
145 /* 172 /*
146 * To allow builtin-annotate to cycle thru multiple symbols by 173 * RIGHT To allow builtin-annotate to cycle thru multiple symbols by
147 * examining the exit key for this function. 174 * examining the exit key for this function.
148 */ 175 */
149 ui_browser__add_exit_key(&self->b, NEWT_KEY_RIGHT); 176 int exit_keys[] = { 'H', NEWT_KEY_TAB, NEWT_KEY_UNTAB,
177 NEWT_KEY_RIGHT, 0 };
178 int key;
179
180 if (ui_browser__show(&self->b, sym->name,
181 "<-, -> or ESC: exit, TAB/shift+TAB: "
182 "cycle hottest lines, H: Hottest") < 0)
183 return -1;
184
185 ui_browser__add_exit_keys(&self->b, exit_keys);
186 annotate_browser__calc_percent(self, evidx);
187
188 if (self->curr_hot)
189 annotate_browser__set_top(self, self->curr_hot);
150 190
151 nd = self->curr_hot; 191 nd = self->curr_hot;
152 if (nd) { 192
153 int tabs[] = { NEWT_KEY_TAB, NEWT_KEY_UNTAB, 0 }; 193 if (refresh != 0)
154 ui_browser__add_exit_keys(&self->b, tabs); 194 newtFormSetTimer(self->b.form, refresh);
155 }
156 195
157 while (1) { 196 while (1) {
158 key = ui_browser__run(&self->b); 197 key = ui_browser__run(&self->b);
159 198
199 if (refresh != 0) {
200 annotate_browser__calc_percent(self, evidx);
201 /*
202 * Current line focus got out of the list of most active
203 * lines, NULL it so that if TAB|UNTAB is pressed, we
204 * move to curr_hot (current hottest line).
205 */
206 if (nd != NULL && RB_EMPTY_NODE(nd))
207 nd = NULL;
208 }
209
160 switch (key) { 210 switch (key) {
211 case -1:
212 /*
213 * FIXME we need to check if it was
214 * es.reason == NEWT_EXIT_TIMER
215 */
216 if (refresh != 0)
217 symbol__annotate_decay_histogram(sym, evidx);
218 continue;
161 case NEWT_KEY_TAB: 219 case NEWT_KEY_TAB:
162 nd = rb_prev(nd); 220 if (nd != NULL) {
163 if (nd == NULL) 221 nd = rb_prev(nd);
164 nd = rb_last(&self->entries); 222 if (nd == NULL)
165 annotate_browser__set_top(self, nd); 223 nd = rb_last(&self->entries);
224 } else
225 nd = self->curr_hot;
166 break; 226 break;
167 case NEWT_KEY_UNTAB: 227 case NEWT_KEY_UNTAB:
168 nd = rb_next(nd); 228 if (nd != NULL)
169 if (nd == NULL) 229 nd = rb_next(nd);
170 nd = rb_first(&self->entries); 230 if (nd == NULL)
171 annotate_browser__set_top(self, nd); 231 nd = rb_first(&self->entries);
232 else
233 nd = self->curr_hot;
234 break;
235 case 'H':
236 nd = self->curr_hot;
172 break; 237 break;
173 default: 238 default:
174 goto out; 239 goto out;
175 } 240 }
241
242 if (nd != NULL)
243 annotate_browser__set_top(self, nd);
176 } 244 }
177out: 245out:
178 ui_browser__hide(&self->b); 246 ui_browser__hide(&self->b);
179 return key; 247 return key;
180} 248}
181 249
182int hist_entry__tui_annotate(struct hist_entry *self) 250int hist_entry__tui_annotate(struct hist_entry *he, int evidx)
251{
252 return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, 0);
253}
254
255int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
256 int refresh)
183{ 257{
184 struct objdump_line *pos, *n; 258 struct objdump_line *pos, *n;
185 struct objdump_line_rb_node *rbpos; 259 struct annotation *notes;
186 LIST_HEAD(head);
187 struct annotate_browser browser = { 260 struct annotate_browser browser = {
188 .b = { 261 .b = {
189 .entries = &head,
190 .refresh = ui_browser__list_head_refresh, 262 .refresh = ui_browser__list_head_refresh,
191 .seek = ui_browser__list_head_seek, 263 .seek = ui_browser__list_head_seek,
192 .write = annotate_browser__write, 264 .write = annotate_browser__write,
193 .priv = self, 265 .priv = sym,
194 }, 266 },
195 }; 267 };
196 int ret; 268 int ret;
197 269
198 if (self->ms.sym == NULL) 270 if (sym == NULL)
199 return -1; 271 return -1;
200 272
201 if (self->ms.map->dso->annotate_warned) 273 if (map->dso->annotate_warned)
202 return -1; 274 return -1;
203 275
204 if (hist_entry__annotate(self, &head, sizeof(*rbpos)) < 0) { 276 if (symbol__annotate(sym, map, sizeof(struct objdump_line_rb_node)) < 0) {
205 ui__error_window(ui_helpline__last_msg); 277 ui__error_window(ui_helpline__last_msg);
206 return -1; 278 return -1;
207 } 279 }
208 280
209 ui_helpline__push("Press <- or ESC to exit"); 281 ui_helpline__push("Press <- or ESC to exit");
210 282
211 list_for_each_entry(pos, &head, node) { 283 notes = symbol__annotation(sym);
284
285 list_for_each_entry(pos, &notes->src->source, node) {
286 struct objdump_line_rb_node *rbpos;
212 size_t line_len = strlen(pos->line); 287 size_t line_len = strlen(pos->line);
288
213 if (browser.b.width < line_len) 289 if (browser.b.width < line_len)
214 browser.b.width = line_len; 290 browser.b.width = line_len;
215 rbpos = objdump_line__rb(pos); 291 rbpos = objdump_line__rb(pos);
216 rbpos->idx = browser.b.nr_entries++; 292 rbpos->idx = browser.b.nr_entries++;
217 rbpos->percent = objdump_line__calc_percent(pos, &head, self->ms.sym);
218 if (rbpos->percent < 0.01)
219 continue;
220 objdump__insert_line(&browser.entries, rbpos);
221 } 293 }
222 294
223 /* 295 browser.b.entries = &notes->src->source,
224 * Position the browser at the hottest line.
225 */
226 browser.curr_hot = rb_last(&browser.entries);
227 if (browser.curr_hot)
228 annotate_browser__set_top(&browser, browser.curr_hot);
229
230 browser.b.width += 18; /* Percentage */ 296 browser.b.width += 18; /* Percentage */
231 ret = annotate_browser__run(&browser); 297 ret = annotate_browser__run(&browser, evidx, refresh);
232 list_for_each_entry_safe(pos, n, &head, node) { 298 list_for_each_entry_safe(pos, n, &notes->src->source, node) {
233 list_del(&pos->node); 299 list_del(&pos->node);
234 objdump_line__free(pos); 300 objdump_line__free(pos);
235 } 301 }
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c
index ebda8c3fde9e..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"
@@ -292,7 +294,8 @@ static int hist_browser__run(struct hist_browser *self, const char *title)
292{ 294{
293 int key; 295 int key;
294 int exit_keys[] = { 'a', '?', 'h', 'C', 'd', 'D', 'E', 't', 296 int exit_keys[] = { 'a', '?', 'h', 'C', 'd', 'D', 'E', 't',
295 NEWT_KEY_ENTER, NEWT_KEY_RIGHT, NEWT_KEY_LEFT, 0, }; 297 NEWT_KEY_ENTER, NEWT_KEY_RIGHT, NEWT_KEY_LEFT,
298 NEWT_KEY_TAB, NEWT_KEY_UNTAB, 0, };
296 299
297 self->b.entries = &self->hists->entries; 300 self->b.entries = &self->hists->entries;
298 self->b.nr_entries = self->hists->nr_entries; 301 self->b.nr_entries = self->hists->nr_entries;
@@ -350,7 +353,7 @@ static char *callchain_list__sym_name(struct callchain_list *self,
350 if (self->ms.sym) 353 if (self->ms.sym)
351 return self->ms.sym->name; 354 return self->ms.sym->name;
352 355
353 snprintf(bf, bfsize, "%#Lx", self->ip); 356 snprintf(bf, bfsize, "%#" PRIx64, self->ip);
354 return bf; 357 return bf;
355} 358}
356 359
@@ -377,7 +380,7 @@ static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *self,
377 while (node) { 380 while (node) {
378 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);
379 struct rb_node *next = rb_next(node); 382 struct rb_node *next = rb_next(node);
380 u64 cumul = cumul_hits(child); 383 u64 cumul = callchain_cumul_hits(child);
381 struct callchain_list *chain; 384 struct callchain_list *chain;
382 char folded_sign = ' '; 385 char folded_sign = ' ';
383 int first = true; 386 int first = true;
@@ -638,6 +641,9 @@ static void ui_browser__hists_seek(struct ui_browser *self,
638 struct rb_node *nd; 641 struct rb_node *nd;
639 bool first = true; 642 bool first = true;
640 643
644 if (self->nr_entries == 0)
645 return;
646
641 switch (whence) { 647 switch (whence) {
642 case SEEK_SET: 648 case SEEK_SET:
643 nd = hists__filter_entries(rb_first(self->entries)); 649 nd = hists__filter_entries(rb_first(self->entries));
@@ -797,8 +803,11 @@ static int hists__browser_title(struct hists *self, char *bf, size_t size,
797 return printed; 803 return printed;
798} 804}
799 805
800int 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)
801{ 809{
810 struct hists *self = &evsel->hists;
802 struct hist_browser *browser = hist_browser__new(self); 811 struct hist_browser *browser = hist_browser__new(self);
803 struct pstack *fstack; 812 struct pstack *fstack;
804 const struct thread *thread_filter = NULL; 813 const struct thread *thread_filter = NULL;
@@ -818,8 +827,8 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
818 hists__browser_title(self, msg, sizeof(msg), ev_name, 827 hists__browser_title(self, msg, sizeof(msg), ev_name,
819 dso_filter, thread_filter); 828 dso_filter, thread_filter);
820 while (1) { 829 while (1) {
821 const struct thread *thread; 830 const struct thread *thread = NULL;
822 const struct dso *dso; 831 const struct dso *dso = NULL;
823 char *options[16]; 832 char *options[16];
824 int nr_options = 0, choice = 0, i, 833 int nr_options = 0, choice = 0, i,
825 annotate = -2, zoom_dso = -2, zoom_thread = -2, 834 annotate = -2, zoom_dso = -2, zoom_thread = -2,
@@ -827,8 +836,10 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
827 836
828 key = hist_browser__run(browser, msg); 837 key = hist_browser__run(browser, msg);
829 838
830 thread = hist_browser__selected_thread(browser); 839 if (browser->he_selection != NULL) {
831 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 }
832 843
833 switch (key) { 844 switch (key) {
834 case NEWT_KEY_TAB: 845 case NEWT_KEY_TAB:
@@ -839,7 +850,8 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
839 */ 850 */
840 goto out_free_stack; 851 goto out_free_stack;
841 case 'a': 852 case 'a':
842 if (browser->selection->map == NULL && 853 if (browser->selection == NULL ||
854 browser->selection->sym == NULL ||
843 browser->selection->map->dso->annotate_warned) 855 browser->selection->map->dso->annotate_warned)
844 continue; 856 continue;
845 goto do_annotate; 857 goto do_annotate;
@@ -858,6 +870,7 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
858 "E Expand all callchains\n" 870 "E Expand all callchains\n"
859 "d Zoom into current DSO\n" 871 "d Zoom into current DSO\n"
860 "t Zoom into current Thread\n" 872 "t Zoom into current Thread\n"
873 "TAB/UNTAB Switch events\n"
861 "q/CTRL+C Exit browser"); 874 "q/CTRL+C Exit browser");
862 continue; 875 continue;
863 case NEWT_KEY_ENTER: 876 case NEWT_KEY_ENTER:
@@ -867,8 +880,14 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
867 case NEWT_KEY_LEFT: { 880 case NEWT_KEY_LEFT: {
868 const void *top; 881 const void *top;
869 882
870 if (pstack__empty(fstack)) 883 if (pstack__empty(fstack)) {
884 /*
885 * Go back to the perf_evsel_menu__run or other user
886 */
887 if (left_exits)
888 goto out_free_stack;
871 continue; 889 continue;
890 }
872 top = pstack__pop(fstack); 891 top = pstack__pop(fstack);
873 if (top == &dso_filter) 892 if (top == &dso_filter)
874 goto zoom_out_dso; 893 goto zoom_out_dso;
@@ -877,14 +896,16 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
877 continue; 896 continue;
878 } 897 }
879 case NEWT_KEY_ESCAPE: 898 case NEWT_KEY_ESCAPE:
880 if (!ui__dialog_yesno("Do you really want to exit?")) 899 if (!left_exits &&
900 !ui__dialog_yesno("Do you really want to exit?"))
881 continue; 901 continue;
882 /* Fall thru */ 902 /* Fall thru */
883 default: 903 default:
884 goto out_free_stack; 904 goto out_free_stack;
885 } 905 }
886 906
887 if (browser->selection->sym != NULL && 907 if (browser->selection != NULL &&
908 browser->selection->sym != NULL &&
888 !browser->selection->map->dso->annotate_warned && 909 !browser->selection->map->dso->annotate_warned &&
889 asprintf(&options[nr_options], "Annotate %s", 910 asprintf(&options[nr_options], "Annotate %s",
890 browser->selection->sym->name) > 0) 911 browser->selection->sym->name) > 0)
@@ -903,7 +924,8 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
903 (dso->kernel ? "the Kernel" : dso->short_name)) > 0) 924 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
904 zoom_dso = nr_options++; 925 zoom_dso = nr_options++;
905 926
906 if (browser->selection->map != NULL && 927 if (browser->selection != NULL &&
928 browser->selection->map != NULL &&
907 asprintf(&options[nr_options], "Browse map details") > 0) 929 asprintf(&options[nr_options], "Browse map details") > 0)
908 browse_map = nr_options++; 930 browse_map = nr_options++;
909 931
@@ -923,19 +945,11 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
923 if (choice == annotate) { 945 if (choice == annotate) {
924 struct hist_entry *he; 946 struct hist_entry *he;
925do_annotate: 947do_annotate:
926 if (browser->selection->map->dso->origin == DSO__ORIG_KERNEL) {
927 browser->selection->map->dso->annotate_warned = 1;
928 ui_helpline__puts("No vmlinux file found, can't "
929 "annotate with just a "
930 "kallsyms file");
931 continue;
932 }
933
934 he = hist_browser__selected_entry(browser); 948 he = hist_browser__selected_entry(browser);
935 if (he == NULL) 949 if (he == NULL)
936 continue; 950 continue;
937 951
938 hist_entry__tui_annotate(he); 952 hist_entry__tui_annotate(he, evsel->idx);
939 } else if (choice == browse_map) 953 } else if (choice == browse_map)
940 map__browse(browser->selection->map); 954 map__browse(browser->selection->map);
941 else if (choice == zoom_dso) { 955 else if (choice == zoom_dso) {
@@ -984,30 +998,141 @@ out:
984 return key; 998 return key;
985} 999}
986 1000
987int 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)
1008{
1009 struct perf_evsel_menu *menu = container_of(browser,
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);
1024
1025 if (current_entry)
1026 menu->selection = evsel;
1027}
1028
1029static int perf_evsel_menu__run(struct perf_evsel_menu *menu, const char *help)
988{ 1030{
989 struct rb_node *first = rb_first(self), *nd = first, *next; 1031 int exit_keys[] = { NEWT_KEY_ENTER, NEWT_KEY_RIGHT, 0, };
990 int key = 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;
1040
1041 ui_browser__add_exit_keys(&menu->b, exit_keys);
991 1042
992 while (nd) { 1043 while (1) {
993 struct hists *hists = rb_entry(nd, struct hists, rb_node); 1044 key = ui_browser__run(&menu->b);
994 const char *ev_name = __event_name(hists->type, hists->config);
995 1045
996 key = hists__browse(hists, help, ev_name);
997 switch (key) { 1046 switch (key) {
998 case NEWT_KEY_TAB: 1047 case NEWT_KEY_RIGHT:
999 next = rb_next(nd); 1048 case NEWT_KEY_ENTER:
1000 if (next) 1049 if (!menu->selection)
1001 nd = next; 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);
1002 break; 1056 break;
1003 case NEWT_KEY_UNTAB: 1057 case NEWT_KEY_LEFT:
1004 if (nd == first) 1058 continue;
1059 case NEWT_KEY_ESCAPE:
1060 if (!ui__dialog_yesno("Do you really want to exit?"))
1005 continue; 1061 continue;
1006 nd = rb_prev(nd); 1062 /* Fall thru */
1063 default:
1064 goto out;
1065 }
1066
1067 switch (key) {
1068 case NEWT_KEY_TAB:
1069 if (pos->node.next == &evlist->entries)
1070 pos = list_entry(evlist->entries.next, struct perf_evsel, node);
1071 else
1072 pos = list_entry(pos->node.next, struct perf_evsel, node);
1073 goto browse_hists;
1074 case NEWT_KEY_UNTAB:
1075 if (pos->node.prev == &evlist->entries)
1076 pos = list_entry(evlist->entries.prev, struct perf_evsel, node);
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;
1007 default: 1083 default:
1008 return key; 1084 break;
1009 } 1085 }
1010 } 1086 }
1011 1087
1088out:
1089 ui_browser__hide(&menu->b);
1012 return key; 1090 return key;
1013} 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 e35437dfa5b4..8462bffe20bc 100644
--- a/tools/perf/util/ui/browsers/map.c
+++ b/tools/perf/util/ui/browsers/map.c
@@ -1,5 +1,6 @@
1#include "../libslang.h" 1#include "../libslang.h"
2#include <elf.h> 2#include <elf.h>
3#include <inttypes.h>
3#include <sys/ttydefaults.h> 4#include <sys/ttydefaults.h>
4#include <ctype.h> 5#include <ctype.h>
5#include <string.h> 6#include <string.h>
@@ -40,7 +41,7 @@ static int ui_entry__read(const char *title, char *bf, size_t size, int width)
40out_free_form: 41out_free_form:
41 newtPopWindow(); 42 newtPopWindow();
42 newtFormDestroy(form); 43 newtFormDestroy(form);
43 return 0; 44 return err;
44} 45}
45 46
46struct map_browser { 47struct map_browser {
@@ -57,7 +58,7 @@ static void map_browser__write(struct ui_browser *self, void *nd, int row)
57 int width; 58 int width;
58 59
59 ui_browser__set_percent_color(self, 0, current_entry); 60 ui_browser__set_percent_color(self, 0, current_entry);
60 slsmg_printf("%*llx %*llx %c ", 61 slsmg_printf("%*" PRIx64 " %*" PRIx64 " %c ",
61 mb->addrlen, sym->start, mb->addrlen, sym->end, 62 mb->addrlen, sym->start, mb->addrlen, sym->end,
62 sym->binding == STB_GLOBAL ? 'g' : 63 sym->binding == STB_GLOBAL ? 'g' :
63 sym->binding == STB_LOCAL ? 'l' : 'w'); 64 sym->binding == STB_LOCAL ? 'l' : 'w');
@@ -150,6 +151,6 @@ int map__browse(struct map *self)
150 ++mb.b.nr_entries; 151 ++mb.b.nr_entries;
151 } 152 }
152 153
153 mb.addrlen = snprintf(tmp, sizeof(tmp), "%llx", maxaddr); 154 mb.addrlen = snprintf(tmp, sizeof(tmp), "%" PRIx64, maxaddr);
154 return map_browser__run(&mb); 155 return map_browser__run(&mb);
155} 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 056c69521a38..fdf1fc8f08bc 100644
--- a/tools/perf/util/ui/util.c
+++ b/tools/perf/util/ui/util.c
@@ -9,6 +9,7 @@
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
14static void newt_form__set_exit_keys(newtComponent self) 15static void newt_form__set_exit_keys(newtComponent self)
@@ -104,10 +105,26 @@ out_destroy_form:
104 return rc; 105 return rc;
105} 106}
106 107
107static const char yes[] = "Yes", no[] = "No"; 108static const char yes[] = "Yes", no[] = "No",
109 warning_str[] = "Warning!", ok[] = "Ok";
108 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 return newtWinChoice(NULL, (char *)yes, (char *)no, (char *)msg) == 1; 114 return newtWinChoice(NULL, (char *)yes, (char *)no, (char *)msg) == 1;
113} 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);
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 7562707ddd1c..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,6 +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);
242int readn(int fd, void *buf, size_t size);
268 243
269#define _STR(x) #x 244#define _STR(x) #x
270#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..362a0cb448db
--- /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..8ce792ea08e9
--- /dev/null
+++ b/tools/testing/ktest/ktest.pl
@@ -0,0 +1,2122 @@
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{"CLEAR_LOG"} = 0;
40$default{"BISECT_MANUAL"} = 0;
41$default{"BISECT_SKIP"} = 1;
42$default{"SUCCESS_LINE"} = "login:";
43$default{"BOOTED_TIMEOUT"} = 1;
44$default{"DIE_ON_FAILURE"} = 1;
45$default{"SSH_EXEC"} = "ssh \$SSH_USER\@\$MACHINE \$SSH_COMMAND";
46$default{"SCP_TO_TARGET"} = "scp \$SRC_FILE \$SSH_USER\@\$MACHINE:\$DST_FILE";
47$default{"REBOOT"} = "ssh \$SSH_USER\@\$MACHINE reboot";
48$default{"STOP_AFTER_SUCCESS"} = 10;
49$default{"STOP_AFTER_FAILURE"} = 60;
50$default{"STOP_TEST_AFTER"} = 600;
51$default{"LOCALVERSION"} = "-test";
52
53my $ktest_config;
54my $version;
55my $machine;
56my $ssh_user;
57my $tmpdir;
58my $builddir;
59my $outputdir;
60my $output_config;
61my $test_type;
62my $build_type;
63my $build_options;
64my $reboot_type;
65my $reboot_script;
66my $power_cycle;
67my $reboot;
68my $reboot_on_error;
69my $poweroff_on_error;
70my $die_on_failure;
71my $powercycle_after_reboot;
72my $poweroff_after_halt;
73my $ssh_exec;
74my $scp_to_target;
75my $power_off;
76my $grub_menu;
77my $grub_number;
78my $target;
79my $make;
80my $post_install;
81my $noclean;
82my $minconfig;
83my $addconfig;
84my $in_bisect = 0;
85my $bisect_bad = "";
86my $reverse_bisect;
87my $bisect_manual;
88my $bisect_skip;
89my $in_patchcheck = 0;
90my $run_test;
91my $redirect;
92my $buildlog;
93my $dmesg;
94my $monitor_fp;
95my $monitor_pid;
96my $monitor_cnt = 0;
97my $sleep_time;
98my $bisect_sleep_time;
99my $store_failures;
100my $timeout;
101my $booted_timeout;
102my $console;
103my $success_line;
104my $stop_after_success;
105my $stop_after_failure;
106my $stop_test_after;
107my $build_target;
108my $target_image;
109my $localversion;
110my $iteration = 0;
111my $successes = 0;
112
113my %entered_configs;
114my %config_help;
115
116$config_help{"MACHINE"} = << "EOF"
117 The machine hostname that you will test.
118EOF
119 ;
120$config_help{"SSH_USER"} = << "EOF"
121 The box is expected to have ssh on normal bootup, provide the user
122 (most likely root, since you need privileged operations)
123EOF
124 ;
125$config_help{"BUILD_DIR"} = << "EOF"
126 The directory that contains the Linux source code (full path).
127EOF
128 ;
129$config_help{"OUTPUT_DIR"} = << "EOF"
130 The directory that the objects will be built (full path).
131 (can not be same as BUILD_DIR)
132EOF
133 ;
134$config_help{"BUILD_TARGET"} = << "EOF"
135 The location of the compiled file to copy to the target.
136 (relative to OUTPUT_DIR)
137EOF
138 ;
139$config_help{"TARGET_IMAGE"} = << "EOF"
140 The place to put your image on the test machine.
141EOF
142 ;
143$config_help{"POWER_CYCLE"} = << "EOF"
144 A script or command to reboot the box.
145
146 Here is a digital loggers power switch example
147 POWER_CYCLE = wget --no-proxy -O /dev/null -q --auth-no-challenge 'http://admin:admin\@power/outlet?5=CCL'
148
149 Here is an example to reboot a virtual box on the current host
150 with the name "Guest".
151 POWER_CYCLE = virsh destroy Guest; sleep 5; virsh start Guest
152EOF
153 ;
154$config_help{"CONSOLE"} = << "EOF"
155 The script or command that reads the console
156
157 If you use ttywatch server, something like the following would work.
158CONSOLE = nc -d localhost 3001
159
160 For a virtual machine with guest name "Guest".
161CONSOLE = virsh console Guest
162EOF
163 ;
164$config_help{"LOCALVERSION"} = << "EOF"
165 Required version ending to differentiate the test
166 from other linux builds on the system.
167EOF
168 ;
169$config_help{"REBOOT_TYPE"} = << "EOF"
170 Way to reboot the box to the test kernel.
171 Only valid options so far are "grub" and "script".
172
173 If you specify grub, it will assume grub version 1
174 and will search in /boot/grub/menu.lst for the title \$GRUB_MENU
175 and select that target to reboot to the kernel. If this is not
176 your setup, then specify "script" and have a command or script
177 specified in REBOOT_SCRIPT to boot to the target.
178
179 The entry in /boot/grub/menu.lst must be entered in manually.
180 The test will not modify that file.
181EOF
182 ;
183$config_help{"GRUB_MENU"} = << "EOF"
184 The grub title name for the test kernel to boot
185 (Only mandatory if REBOOT_TYPE = grub)
186
187 Note, ktest.pl will not update the grub menu.lst, you need to
188 manually add an option for the test. ktest.pl will search
189 the grub menu.lst for this option to find what kernel to
190 reboot into.
191
192 For example, if in the /boot/grub/menu.lst the test kernel title has:
193 title Test Kernel
194 kernel vmlinuz-test
195 GRUB_MENU = Test Kernel
196EOF
197 ;
198$config_help{"REBOOT_SCRIPT"} = << "EOF"
199 A script to reboot the target into the test kernel
200 (Only mandatory if REBOOT_TYPE = script)
201EOF
202 ;
203
204
205sub get_ktest_config {
206 my ($config) = @_;
207
208 return if (defined($opt{$config}));
209
210 if (defined($config_help{$config})) {
211 print "\n";
212 print $config_help{$config};
213 }
214
215 for (;;) {
216 print "$config = ";
217 if (defined($default{$config})) {
218 print "\[$default{$config}\] ";
219 }
220 $entered_configs{$config} = <STDIN>;
221 $entered_configs{$config} =~ s/^\s*(.*\S)\s*$/$1/;
222 if ($entered_configs{$config} =~ /^\s*$/) {
223 if ($default{$config}) {
224 $entered_configs{$config} = $default{$config};
225 } else {
226 print "Your answer can not be blank\n";
227 next;
228 }
229 }
230 last;
231 }
232}
233
234sub get_ktest_configs {
235 get_ktest_config("MACHINE");
236 get_ktest_config("SSH_USER");
237 get_ktest_config("BUILD_DIR");
238 get_ktest_config("OUTPUT_DIR");
239 get_ktest_config("BUILD_TARGET");
240 get_ktest_config("TARGET_IMAGE");
241 get_ktest_config("POWER_CYCLE");
242 get_ktest_config("CONSOLE");
243 get_ktest_config("LOCALVERSION");
244
245 my $rtype = $opt{"REBOOT_TYPE"};
246
247 if (!defined($rtype)) {
248 if (!defined($opt{"GRUB_MENU"})) {
249 get_ktest_config("REBOOT_TYPE");
250 $rtype = $entered_configs{"REBOOT_TYPE"};
251 } else {
252 $rtype = "grub";
253 }
254 }
255
256 if ($rtype eq "grub") {
257 get_ktest_config("GRUB_MENU");
258 } else {
259 get_ktest_config("REBOOT_SCRIPT");
260 }
261}
262
263sub set_value {
264 my ($lvalue, $rvalue) = @_;
265
266 if (defined($opt{$lvalue})) {
267 die "Error: Option $lvalue defined more than once!\n";
268 }
269 if ($rvalue =~ /^\s*$/) {
270 delete $opt{$lvalue};
271 } else {
272 $opt{$lvalue} = $rvalue;
273 }
274}
275
276sub read_config {
277 my ($config) = @_;
278
279 open(IN, $config) || die "can't read file $config";
280
281 my $name = $config;
282 $name =~ s,.*/(.*),$1,;
283
284 my $test_num = 0;
285 my $default = 1;
286 my $repeat = 1;
287 my $num_tests_set = 0;
288 my $skip = 0;
289 my $rest;
290
291 while (<IN>) {
292
293 # ignore blank lines and comments
294 next if (/^\s*$/ || /\s*\#/);
295
296 if (/^\s*TEST_START(.*)/) {
297
298 $rest = $1;
299
300 if ($num_tests_set) {
301 die "$name: $.: Can not specify both NUM_TESTS and TEST_START\n";
302 }
303
304 my $old_test_num = $test_num;
305 my $old_repeat = $repeat;
306
307 $test_num += $repeat;
308 $default = 0;
309 $repeat = 1;
310
311 if ($rest =~ /\s+SKIP(.*)/) {
312 $rest = $1;
313 $skip = 1;
314 } else {
315 $skip = 0;
316 }
317
318 if ($rest =~ /\s+ITERATE\s+(\d+)(.*)$/) {
319 $repeat = $1;
320 $rest = $2;
321 $repeat_tests{"$test_num"} = $repeat;
322 }
323
324 if ($rest =~ /\s+SKIP(.*)/) {
325 $rest = $1;
326 $skip = 1;
327 }
328
329 if ($rest !~ /^\s*$/) {
330 die "$name: $.: Gargbage found after TEST_START\n$_";
331 }
332
333 if ($skip) {
334 $test_num = $old_test_num;
335 $repeat = $old_repeat;
336 }
337
338 } elsif (/^\s*DEFAULTS(.*)$/) {
339 $default = 1;
340
341 $rest = $1;
342
343 if ($rest =~ /\s+SKIP(.*)/) {
344 $rest = $1;
345 $skip = 1;
346 } else {
347 $skip = 0;
348 }
349
350 if ($rest !~ /^\s*$/) {
351 die "$name: $.: Gargbage found after DEFAULTS\n$_";
352 }
353
354 } elsif (/^\s*([A-Z_\[\]\d]+)\s*=\s*(.*?)\s*$/) {
355
356 next if ($skip);
357
358 my $lvalue = $1;
359 my $rvalue = $2;
360
361 if (!$default &&
362 ($lvalue eq "NUM_TESTS" ||
363 $lvalue eq "LOG_FILE" ||
364 $lvalue eq "CLEAR_LOG")) {
365 die "$name: $.: $lvalue must be set in DEFAULTS section\n";
366 }
367
368 if ($lvalue eq "NUM_TESTS") {
369 if ($test_num) {
370 die "$name: $.: Can not specify both NUM_TESTS and TEST_START\n";
371 }
372 if (!$default) {
373 die "$name: $.: NUM_TESTS must be set in default section\n";
374 }
375 $num_tests_set = 1;
376 }
377
378 if ($default || $lvalue =~ /\[\d+\]$/) {
379 set_value($lvalue, $rvalue);
380 } else {
381 my $val = "$lvalue\[$test_num\]";
382 set_value($val, $rvalue);
383
384 if ($repeat > 1) {
385 $repeats{$val} = $repeat;
386 }
387 }
388 } else {
389 die "$name: $.: Garbage found in config\n$_";
390 }
391 }
392
393 close(IN);
394
395 if ($test_num) {
396 $test_num += $repeat - 1;
397 $opt{"NUM_TESTS"} = $test_num;
398 }
399
400 # make sure we have all mandatory configs
401 get_ktest_configs;
402
403 # set any defaults
404
405 foreach my $default (keys %default) {
406 if (!defined($opt{$default})) {
407 $opt{$default} = $default{$default};
408 }
409 }
410}
411
412sub _logit {
413 if (defined($opt{"LOG_FILE"})) {
414 open(OUT, ">> $opt{LOG_FILE}") or die "Can't write to $opt{LOG_FILE}";
415 print OUT @_;
416 close(OUT);
417 }
418}
419
420sub logit {
421 if (defined($opt{"LOG_FILE"})) {
422 _logit @_;
423 } else {
424 print @_;
425 }
426}
427
428sub doprint {
429 print @_;
430 _logit @_;
431}
432
433sub run_command;
434
435sub reboot {
436 # try to reboot normally
437 if (run_command $reboot) {
438 if (defined($powercycle_after_reboot)) {
439 sleep $powercycle_after_reboot;
440 run_command "$power_cycle";
441 }
442 } else {
443 # nope? power cycle it.
444 run_command "$power_cycle";
445 }
446}
447
448sub do_not_reboot {
449 my $i = $iteration;
450
451 return $test_type eq "build" ||
452 ($test_type eq "patchcheck" && $opt{"PATCHCHECK_TYPE[$i]"} eq "build") ||
453 ($test_type eq "bisect" && $opt{"BISECT_TYPE[$i]"} eq "build");
454}
455
456sub dodie {
457 doprint "CRITICAL FAILURE... ", @_, "\n";
458
459 my $i = $iteration;
460
461 if ($reboot_on_error && !do_not_reboot) {
462
463 doprint "REBOOTING\n";
464 reboot;
465
466 } elsif ($poweroff_on_error && defined($power_off)) {
467 doprint "POWERING OFF\n";
468 `$power_off`;
469 }
470
471 if (defined($opt{"LOG_FILE"})) {
472 print " See $opt{LOG_FILE} for more info.\n";
473 }
474
475 die @_, "\n";
476}
477
478sub open_console {
479 my ($fp) = @_;
480
481 my $flags;
482
483 my $pid = open($fp, "$console|") or
484 dodie "Can't open console $console";
485
486 $flags = fcntl($fp, F_GETFL, 0) or
487 dodie "Can't get flags for the socket: $!";
488 $flags = fcntl($fp, F_SETFL, $flags | O_NONBLOCK) or
489 dodie "Can't set flags for the socket: $!";
490
491 return $pid;
492}
493
494sub close_console {
495 my ($fp, $pid) = @_;
496
497 doprint "kill child process $pid\n";
498 kill 2, $pid;
499
500 print "closing!\n";
501 close($fp);
502}
503
504sub start_monitor {
505 if ($monitor_cnt++) {
506 return;
507 }
508 $monitor_fp = \*MONFD;
509 $monitor_pid = open_console $monitor_fp;
510
511 return;
512
513 open(MONFD, "Stop perl from warning about single use of MONFD");
514}
515
516sub end_monitor {
517 if (--$monitor_cnt) {
518 return;
519 }
520 close_console($monitor_fp, $monitor_pid);
521}
522
523sub wait_for_monitor {
524 my ($time) = @_;
525 my $line;
526
527 doprint "** Wait for monitor to settle down **\n";
528
529 # read the monitor and wait for the system to calm down
530 do {
531 $line = wait_for_input($monitor_fp, $time);
532 print "$line" if (defined($line));
533 } while (defined($line));
534 print "** Monitor flushed **\n";
535}
536
537sub fail {
538
539 if ($die_on_failure) {
540 dodie @_;
541 }
542
543 doprint "FAILED\n";
544
545 my $i = $iteration;
546
547 # no need to reboot for just building.
548 if (!do_not_reboot) {
549 doprint "REBOOTING\n";
550 reboot;
551 start_monitor;
552 wait_for_monitor $sleep_time;
553 end_monitor;
554 }
555
556 doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
557 doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
558 doprint "KTEST RESULT: TEST $i Failed: ", @_, "\n";
559 doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
560 doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
561
562 return 1 if (!defined($store_failures));
563
564 my @t = localtime;
565 my $date = sprintf "%04d%02d%02d%02d%02d%02d",
566 1900+$t[5],$t[4],$t[3],$t[2],$t[1],$t[0];
567
568 my $type = $build_type;
569 if ($type =~ /useconfig/) {
570 $type = "useconfig";
571 }
572
573 my $dir = "$machine-$test_type-$type-fail-$date";
574 my $faildir = "$store_failures/$dir";
575
576 if (!-d $faildir) {
577 mkpath($faildir) or
578 die "can't create $faildir";
579 }
580 if (-f "$output_config") {
581 cp "$output_config", "$faildir/config" or
582 die "failed to copy .config";
583 }
584 if (-f $buildlog) {
585 cp $buildlog, "$faildir/buildlog" or
586 die "failed to move $buildlog";
587 }
588 if (-f $dmesg) {
589 cp $dmesg, "$faildir/dmesg" or
590 die "failed to move $dmesg";
591 }
592
593 doprint "*** Saved info to $faildir ***\n";
594
595 return 1;
596}
597
598sub run_command {
599 my ($command) = @_;
600 my $dolog = 0;
601 my $dord = 0;
602 my $pid;
603
604 $command =~ s/\$SSH_USER/$ssh_user/g;
605 $command =~ s/\$MACHINE/$machine/g;
606
607 doprint("$command ... ");
608
609 $pid = open(CMD, "$command 2>&1 |") or
610 (fail "unable to exec $command" and return 0);
611
612 if (defined($opt{"LOG_FILE"})) {
613 open(LOG, ">>$opt{LOG_FILE}") or
614 dodie "failed to write to log";
615 $dolog = 1;
616 }
617
618 if (defined($redirect)) {
619 open (RD, ">$redirect") or
620 dodie "failed to write to redirect $redirect";
621 $dord = 1;
622 }
623
624 while (<CMD>) {
625 print LOG if ($dolog);
626 print RD if ($dord);
627 }
628
629 waitpid($pid, 0);
630 my $failed = $?;
631
632 close(CMD);
633 close(LOG) if ($dolog);
634 close(RD) if ($dord);
635
636 if ($failed) {
637 doprint "FAILED!\n";
638 } else {
639 doprint "SUCCESS\n";
640 }
641
642 return !$failed;
643}
644
645sub run_ssh {
646 my ($cmd) = @_;
647 my $cp_exec = $ssh_exec;
648
649 $cp_exec =~ s/\$SSH_COMMAND/$cmd/g;
650 return run_command "$cp_exec";
651}
652
653sub run_scp {
654 my ($src, $dst) = @_;
655 my $cp_scp = $scp_to_target;
656
657 $cp_scp =~ s/\$SRC_FILE/$src/g;
658 $cp_scp =~ s/\$DST_FILE/$dst/g;
659
660 return run_command "$cp_scp";
661}
662
663sub get_grub_index {
664
665 if ($reboot_type ne "grub") {
666 return;
667 }
668 return if (defined($grub_number));
669
670 doprint "Find grub menu ... ";
671 $grub_number = -1;
672
673 my $ssh_grub = $ssh_exec;
674 $ssh_grub =~ s,\$SSH_COMMAND,cat /boot/grub/menu.lst,g;
675
676 open(IN, "$ssh_grub |")
677 or die "unable to get menu.lst";
678
679 while (<IN>) {
680 if (/^\s*title\s+$grub_menu\s*$/) {
681 $grub_number++;
682 last;
683 } elsif (/^\s*title\s/) {
684 $grub_number++;
685 }
686 }
687 close(IN);
688
689 die "Could not find '$grub_menu' in /boot/grub/menu on $machine"
690 if ($grub_number < 0);
691 doprint "$grub_number\n";
692}
693
694sub wait_for_input
695{
696 my ($fp, $time) = @_;
697 my $rin;
698 my $ready;
699 my $line;
700 my $ch;
701
702 if (!defined($time)) {
703 $time = $timeout;
704 }
705
706 $rin = '';
707 vec($rin, fileno($fp), 1) = 1;
708 $ready = select($rin, undef, undef, $time);
709
710 $line = "";
711
712 # try to read one char at a time
713 while (sysread $fp, $ch, 1) {
714 $line .= $ch;
715 last if ($ch eq "\n");
716 }
717
718 if (!length($line)) {
719 return undef;
720 }
721
722 return $line;
723}
724
725sub reboot_to {
726 if ($reboot_type eq "grub") {
727 run_ssh "'(echo \"savedefault --default=$grub_number --once\" | grub --batch; reboot)'";
728 return;
729 }
730
731 run_command "$reboot_script";
732}
733
734sub get_sha1 {
735 my ($commit) = @_;
736
737 doprint "git rev-list --max-count=1 $commit ... ";
738 my $sha1 = `git rev-list --max-count=1 $commit`;
739 my $ret = $?;
740
741 logit $sha1;
742
743 if ($ret) {
744 doprint "FAILED\n";
745 dodie "Failed to get git $commit";
746 }
747
748 print "SUCCESS\n";
749
750 chomp $sha1;
751
752 return $sha1;
753}
754
755sub monitor {
756 my $booted = 0;
757 my $bug = 0;
758 my $skip_call_trace = 0;
759 my $loops;
760
761 wait_for_monitor 5;
762
763 my $line;
764 my $full_line = "";
765
766 open(DMESG, "> $dmesg") or
767 die "unable to write to $dmesg";
768
769 reboot_to;
770
771 my $success_start;
772 my $failure_start;
773 my $monitor_start = time;
774 my $done = 0;
775
776 while (!$done) {
777
778 if ($booted) {
779 $line = wait_for_input($monitor_fp, $booted_timeout);
780 } else {
781 $line = wait_for_input($monitor_fp);
782 }
783
784 last if (!defined($line));
785
786 doprint $line;
787 print DMESG $line;
788
789 # we are not guaranteed to get a full line
790 $full_line .= $line;
791
792 if ($full_line =~ /$success_line/) {
793 $booted = 1;
794 $success_start = time;
795 }
796
797 if ($booted && defined($stop_after_success) &&
798 $stop_after_success >= 0) {
799 my $now = time;
800 if ($now - $success_start >= $stop_after_success) {
801 doprint "Test forced to stop after $stop_after_success seconds after success\n";
802 last;
803 }
804 }
805
806 if ($full_line =~ /\[ backtrace testing \]/) {
807 $skip_call_trace = 1;
808 }
809
810 if ($full_line =~ /call trace:/i) {
811 if (!$bug && !$skip_call_trace) {
812 $bug = 1;
813 $failure_start = time;
814 }
815 }
816
817 if ($bug && defined($stop_after_failure) &&
818 $stop_after_failure >= 0) {
819 my $now = time;
820 if ($now - $failure_start >= $stop_after_failure) {
821 doprint "Test forced to stop after $stop_after_failure seconds after failure\n";
822 last;
823 }
824 }
825
826 if ($full_line =~ /\[ end of backtrace testing \]/) {
827 $skip_call_trace = 0;
828 }
829
830 if ($full_line =~ /Kernel panic -/) {
831 $failure_start = time;
832 $bug = 1;
833 }
834
835 if ($line =~ /\n/) {
836 $full_line = "";
837 }
838
839 if ($stop_test_after > 0 && !$booted && !$bug) {
840 if (time - $monitor_start > $stop_test_after) {
841 $done = 1;
842 }
843 }
844 }
845
846 close(DMESG);
847
848 if ($bug) {
849 return 0 if ($in_bisect);
850 fail "failed - got a bug report" and return 0;
851 }
852
853 if (!$booted) {
854 return 0 if ($in_bisect);
855 fail "failed - never got a boot prompt." and return 0;
856 }
857
858 return 1;
859}
860
861sub install {
862
863 run_scp "$outputdir/$build_target", "$target_image" or
864 dodie "failed to copy image";
865
866 my $install_mods = 0;
867
868 # should we process modules?
869 $install_mods = 0;
870 open(IN, "$output_config") or dodie("Can't read config file");
871 while (<IN>) {
872 if (/CONFIG_MODULES(=y)?/) {
873 $install_mods = 1 if (defined($1));
874 last;
875 }
876 }
877 close(IN);
878
879 if (!$install_mods) {
880 doprint "No modules needed\n";
881 return;
882 }
883
884 run_command "$make INSTALL_MOD_PATH=$tmpdir modules_install" or
885 dodie "Failed to install modules";
886
887 my $modlib = "/lib/modules/$version";
888 my $modtar = "ktest-mods.tar.bz2";
889
890 run_ssh "rm -rf $modlib" or
891 dodie "failed to remove old mods: $modlib";
892
893 # would be nice if scp -r did not follow symbolic links
894 run_command "cd $tmpdir && tar -cjf $modtar lib/modules/$version" or
895 dodie "making tarball";
896
897 run_scp "$tmpdir/$modtar", "/tmp" or
898 dodie "failed to copy modules";
899
900 unlink "$tmpdir/$modtar";
901
902 run_ssh "'(cd / && tar xf /tmp/$modtar)'" or
903 dodie "failed to tar modules";
904
905 run_ssh "rm -f /tmp/$modtar";
906
907 return if (!defined($post_install));
908
909 my $cp_post_install = $post_install;
910 $cp_post_install = s/\$KERNEL_VERSION/$version/g;
911 run_command "$cp_post_install" or
912 dodie "Failed to run post install";
913}
914
915sub check_buildlog {
916 my ($patch) = @_;
917
918 my @files = `git show $patch | diffstat -l`;
919
920 open(IN, "git show $patch |") or
921 dodie "failed to show $patch";
922 while (<IN>) {
923 if (m,^--- a/(.*),) {
924 chomp $1;
925 $files[$#files] = $1;
926 }
927 }
928 close(IN);
929
930 open(IN, $buildlog) or dodie "Can't open $buildlog";
931 while (<IN>) {
932 if (/^\s*(.*?):.*(warning|error)/) {
933 my $err = $1;
934 foreach my $file (@files) {
935 my $fullpath = "$builddir/$file";
936 if ($file eq $err || $fullpath eq $err) {
937 fail "$file built with warnings" and return 0;
938 }
939 }
940 }
941 }
942 close(IN);
943
944 return 1;
945}
946
947sub make_oldconfig {
948 my ($defconfig) = @_;
949
950 if (!run_command "$defconfig $make oldnoconfig") {
951 # Perhaps oldnoconfig doesn't exist in this version of the kernel
952 # try a yes '' | oldconfig
953 doprint "oldnoconfig failed, trying yes '' | make oldconfig\n";
954 run_command "yes '' | $defconfig $make oldconfig" or
955 dodie "failed make config oldconfig";
956 }
957}
958
959sub build {
960 my ($type) = @_;
961 my $defconfig = "";
962
963 unlink $buildlog;
964
965 if ($type =~ /^useconfig:(.*)/) {
966 run_command "cp $1 $output_config" or
967 dodie "could not copy $1 to .config";
968
969 $type = "oldconfig";
970 }
971
972 # old config can ask questions
973 if ($type eq "oldconfig") {
974 $type = "oldnoconfig";
975
976 # allow for empty configs
977 run_command "touch $output_config";
978
979 run_command "mv $output_config $outputdir/config_temp" or
980 dodie "moving .config";
981
982 if (!$noclean && !run_command "$make mrproper") {
983 dodie "make mrproper";
984 }
985
986 run_command "mv $outputdir/config_temp $output_config" or
987 dodie "moving config_temp";
988
989 } elsif (!$noclean) {
990 unlink "$output_config";
991 run_command "$make mrproper" or
992 dodie "make mrproper";
993 }
994
995 # add something to distinguish this build
996 open(OUT, "> $outputdir/localversion") or dodie("Can't make localversion file");
997 print OUT "$localversion\n";
998 close(OUT);
999
1000 if (defined($minconfig)) {
1001 $defconfig = "KCONFIG_ALLCONFIG=$minconfig";
1002 }
1003
1004 if ($type eq "oldnoconfig") {
1005 make_oldconfig $defconfig;
1006 } else {
1007 run_command "$defconfig $make $type" or
1008 dodie "failed make config";
1009 }
1010
1011 $redirect = "$buildlog";
1012 if (!run_command "$make $build_options") {
1013 undef $redirect;
1014 # bisect may need this to pass
1015 return 0 if ($in_bisect);
1016 fail "failed build" and return 0;
1017 }
1018 undef $redirect;
1019
1020 return 1;
1021}
1022
1023sub halt {
1024 if (!run_ssh "halt" or defined($power_off)) {
1025 if (defined($poweroff_after_halt)) {
1026 sleep $poweroff_after_halt;
1027 run_command "$power_off";
1028 }
1029 } else {
1030 # nope? the zap it!
1031 run_command "$power_off";
1032 }
1033}
1034
1035sub success {
1036 my ($i) = @_;
1037
1038 $successes++;
1039
1040 doprint "\n\n*******************************************\n";
1041 doprint "*******************************************\n";
1042 doprint "KTEST RESULT: TEST $i SUCCESS!!!! **\n";
1043 doprint "*******************************************\n";
1044 doprint "*******************************************\n";
1045
1046 if ($i != $opt{"NUM_TESTS"} && !do_not_reboot) {
1047 doprint "Reboot and wait $sleep_time seconds\n";
1048 reboot;
1049 start_monitor;
1050 wait_for_monitor $sleep_time;
1051 end_monitor;
1052 }
1053}
1054
1055sub get_version {
1056 # get the release name
1057 doprint "$make kernelrelease ... ";
1058 $version = `$make kernelrelease | tail -1`;
1059 chomp($version);
1060 doprint "$version\n";
1061}
1062
1063sub answer_bisect {
1064 for (;;) {
1065 doprint "Pass or fail? [p/f]";
1066 my $ans = <STDIN>;
1067 chomp $ans;
1068 if ($ans eq "p" || $ans eq "P") {
1069 return 1;
1070 } elsif ($ans eq "f" || $ans eq "F") {
1071 return 0;
1072 } else {
1073 print "Please answer 'P' or 'F'\n";
1074 }
1075 }
1076}
1077
1078sub child_run_test {
1079 my $failed = 0;
1080
1081 # child should have no power
1082 $reboot_on_error = 0;
1083 $poweroff_on_error = 0;
1084 $die_on_failure = 1;
1085
1086 run_command $run_test or $failed = 1;
1087 exit $failed;
1088}
1089
1090my $child_done;
1091
1092sub child_finished {
1093 $child_done = 1;
1094}
1095
1096sub do_run_test {
1097 my $child_pid;
1098 my $child_exit;
1099 my $line;
1100 my $full_line;
1101 my $bug = 0;
1102
1103 wait_for_monitor 1;
1104
1105 doprint "run test $run_test\n";
1106
1107 $child_done = 0;
1108
1109 $SIG{CHLD} = qw(child_finished);
1110
1111 $child_pid = fork;
1112
1113 child_run_test if (!$child_pid);
1114
1115 $full_line = "";
1116
1117 do {
1118 $line = wait_for_input($monitor_fp, 1);
1119 if (defined($line)) {
1120
1121 # we are not guaranteed to get a full line
1122 $full_line .= $line;
1123 doprint $line;
1124
1125 if ($full_line =~ /call trace:/i) {
1126 $bug = 1;
1127 }
1128
1129 if ($full_line =~ /Kernel panic -/) {
1130 $bug = 1;
1131 }
1132
1133 if ($line =~ /\n/) {
1134 $full_line = "";
1135 }
1136 }
1137 } while (!$child_done && !$bug);
1138
1139 if ($bug) {
1140 my $failure_start = time;
1141 my $now;
1142 do {
1143 $line = wait_for_input($monitor_fp, 1);
1144 if (defined($line)) {
1145 doprint $line;
1146 }
1147 $now = time;
1148 if ($now - $failure_start >= $stop_after_failure) {
1149 last;
1150 }
1151 } while (defined($line));
1152
1153 doprint "Detected kernel crash!\n";
1154 # kill the child with extreme prejudice
1155 kill 9, $child_pid;
1156 }
1157
1158 waitpid $child_pid, 0;
1159 $child_exit = $?;
1160
1161 if ($bug || $child_exit) {
1162 return 0 if $in_bisect;
1163 fail "test failed" and return 0;
1164 }
1165 return 1;
1166}
1167
1168sub run_git_bisect {
1169 my ($command) = @_;
1170
1171 doprint "$command ... ";
1172
1173 my $output = `$command 2>&1`;
1174 my $ret = $?;
1175
1176 logit $output;
1177
1178 if ($ret) {
1179 doprint "FAILED\n";
1180 dodie "Failed to git bisect";
1181 }
1182
1183 doprint "SUCCESS\n";
1184 if ($output =~ m/^(Bisecting: .*\(roughly \d+ steps?\))\s+\[([[:xdigit:]]+)\]/) {
1185 doprint "$1 [$2]\n";
1186 } elsif ($output =~ m/^([[:xdigit:]]+) is the first bad commit/) {
1187 $bisect_bad = $1;
1188 doprint "Found bad commit... $1\n";
1189 return 0;
1190 } else {
1191 # we already logged it, just print it now.
1192 print $output;
1193 }
1194
1195 return 1;
1196}
1197
1198sub bisect_reboot {
1199 doprint "Reboot and sleep $bisect_sleep_time seconds\n";
1200 reboot;
1201 start_monitor;
1202 wait_for_monitor $bisect_sleep_time;
1203 end_monitor;
1204}
1205
1206# returns 1 on success, 0 on failure, -1 on skip
1207sub run_bisect_test {
1208 my ($type, $buildtype) = @_;
1209
1210 my $failed = 0;
1211 my $result;
1212 my $output;
1213 my $ret;
1214
1215 $in_bisect = 1;
1216
1217 build $buildtype or $failed = 1;
1218
1219 if ($type ne "build") {
1220 if ($failed && $bisect_skip) {
1221 $in_bisect = 0;
1222 return -1;
1223 }
1224 dodie "Failed on build" if $failed;
1225
1226 # Now boot the box
1227 get_grub_index;
1228 get_version;
1229 install;
1230
1231 start_monitor;
1232 monitor or $failed = 1;
1233
1234 if ($type ne "boot") {
1235 if ($failed && $bisect_skip) {
1236 end_monitor;
1237 bisect_reboot;
1238 $in_bisect = 0;
1239 return -1;
1240 }
1241 dodie "Failed on boot" if $failed;
1242
1243 do_run_test or $failed = 1;
1244 }
1245 end_monitor;
1246 }
1247
1248 if ($failed) {
1249 $result = 0;
1250
1251 # reboot the box to a good kernel
1252 if ($type ne "build") {
1253 bisect_reboot;
1254 }
1255 } else {
1256 $result = 1;
1257 }
1258 $in_bisect = 0;
1259
1260 return $result;
1261}
1262
1263sub run_bisect {
1264 my ($type) = @_;
1265 my $buildtype = "oldconfig";
1266
1267 # We should have a minconfig to use?
1268 if (defined($minconfig)) {
1269 $buildtype = "useconfig:$minconfig";
1270 }
1271
1272 my $ret = run_bisect_test $type, $buildtype;
1273
1274 if ($bisect_manual) {
1275 $ret = answer_bisect;
1276 }
1277
1278 # Are we looking for where it worked, not failed?
1279 if ($reverse_bisect) {
1280 $ret = !$ret;
1281 }
1282
1283 if ($ret > 0) {
1284 return "good";
1285 } elsif ($ret == 0) {
1286 return "bad";
1287 } elsif ($bisect_skip) {
1288 doprint "HIT A BAD COMMIT ... SKIPPING\n";
1289 return "skip";
1290 }
1291}
1292
1293sub bisect {
1294 my ($i) = @_;
1295
1296 my $result;
1297
1298 die "BISECT_GOOD[$i] not defined\n" if (!defined($opt{"BISECT_GOOD[$i]"}));
1299 die "BISECT_BAD[$i] not defined\n" if (!defined($opt{"BISECT_BAD[$i]"}));
1300 die "BISECT_TYPE[$i] not defined\n" if (!defined($opt{"BISECT_TYPE[$i]"}));
1301
1302 my $good = $opt{"BISECT_GOOD[$i]"};
1303 my $bad = $opt{"BISECT_BAD[$i]"};
1304 my $type = $opt{"BISECT_TYPE[$i]"};
1305 my $start = $opt{"BISECT_START[$i]"};
1306 my $replay = $opt{"BISECT_REPLAY[$i]"};
1307 my $start_files = $opt{"BISECT_FILES[$i]"};
1308
1309 if (defined($start_files)) {
1310 $start_files = " -- " . $start_files;
1311 } else {
1312 $start_files = "";
1313 }
1314
1315 # convert to true sha1's
1316 $good = get_sha1($good);
1317 $bad = get_sha1($bad);
1318
1319 if (defined($opt{"BISECT_REVERSE[$i]"}) &&
1320 $opt{"BISECT_REVERSE[$i]"} == 1) {
1321 doprint "Performing a reverse bisect (bad is good, good is bad!)\n";
1322 $reverse_bisect = 1;
1323 } else {
1324 $reverse_bisect = 0;
1325 }
1326
1327 # Can't have a test without having a test to run
1328 if ($type eq "test" && !defined($run_test)) {
1329 $type = "boot";
1330 }
1331
1332 my $check = $opt{"BISECT_CHECK[$i]"};
1333 if (defined($check) && $check ne "0") {
1334
1335 # get current HEAD
1336 my $head = get_sha1("HEAD");
1337
1338 if ($check ne "good") {
1339 doprint "TESTING BISECT BAD [$bad]\n";
1340 run_command "git checkout $bad" or
1341 die "Failed to checkout $bad";
1342
1343 $result = run_bisect $type;
1344
1345 if ($result ne "bad") {
1346 fail "Tested BISECT_BAD [$bad] and it succeeded" and return 0;
1347 }
1348 }
1349
1350 if ($check ne "bad") {
1351 doprint "TESTING BISECT GOOD [$good]\n";
1352 run_command "git checkout $good" or
1353 die "Failed to checkout $good";
1354
1355 $result = run_bisect $type;
1356
1357 if ($result ne "good") {
1358 fail "Tested BISECT_GOOD [$good] and it failed" and return 0;
1359 }
1360 }
1361
1362 # checkout where we started
1363 run_command "git checkout $head" or
1364 die "Failed to checkout $head";
1365 }
1366
1367 run_command "git bisect start$start_files" or
1368 dodie "could not start bisect";
1369
1370 run_command "git bisect good $good" or
1371 dodie "could not set bisect good to $good";
1372
1373 run_git_bisect "git bisect bad $bad" or
1374 dodie "could not set bisect bad to $bad";
1375
1376 if (defined($replay)) {
1377 run_command "git bisect replay $replay" or
1378 dodie "failed to run replay";
1379 }
1380
1381 if (defined($start)) {
1382 run_command "git checkout $start" or
1383 dodie "failed to checkout $start";
1384 }
1385
1386 my $test;
1387 do {
1388 $result = run_bisect $type;
1389 $test = run_git_bisect "git bisect $result";
1390 } while ($test);
1391
1392 run_command "git bisect log" or
1393 dodie "could not capture git bisect log";
1394
1395 run_command "git bisect reset" or
1396 dodie "could not reset git bisect";
1397
1398 doprint "Bad commit was [$bisect_bad]\n";
1399
1400 success $i;
1401}
1402
1403my %config_ignore;
1404my %config_set;
1405
1406my %config_list;
1407my %null_config;
1408
1409my %dependency;
1410
1411sub process_config_ignore {
1412 my ($config) = @_;
1413
1414 open (IN, $config)
1415 or dodie "Failed to read $config";
1416
1417 while (<IN>) {
1418 if (/^(.*?(CONFIG\S*)(=.*| is not set))/) {
1419 $config_ignore{$2} = $1;
1420 }
1421 }
1422
1423 close(IN);
1424}
1425
1426sub read_current_config {
1427 my ($config_ref) = @_;
1428
1429 %{$config_ref} = ();
1430 undef %{$config_ref};
1431
1432 my @key = keys %{$config_ref};
1433 if ($#key >= 0) {
1434 print "did not delete!\n";
1435 exit;
1436 }
1437 open (IN, "$output_config");
1438
1439 while (<IN>) {
1440 if (/^(CONFIG\S+)=(.*)/) {
1441 ${$config_ref}{$1} = $2;
1442 }
1443 }
1444 close(IN);
1445}
1446
1447sub get_dependencies {
1448 my ($config) = @_;
1449
1450 my $arr = $dependency{$config};
1451 if (!defined($arr)) {
1452 return ();
1453 }
1454
1455 my @deps = @{$arr};
1456
1457 foreach my $dep (@{$arr}) {
1458 print "ADD DEP $dep\n";
1459 @deps = (@deps, get_dependencies $dep);
1460 }
1461
1462 return @deps;
1463}
1464
1465sub create_config {
1466 my @configs = @_;
1467
1468 open(OUT, ">$output_config") or dodie "Can not write to $output_config";
1469
1470 foreach my $config (@configs) {
1471 print OUT "$config_set{$config}\n";
1472 my @deps = get_dependencies $config;
1473 foreach my $dep (@deps) {
1474 print OUT "$config_set{$dep}\n";
1475 }
1476 }
1477
1478 foreach my $config (keys %config_ignore) {
1479 print OUT "$config_ignore{$config}\n";
1480 }
1481 close(OUT);
1482
1483# exit;
1484 make_oldconfig "";
1485}
1486
1487sub compare_configs {
1488 my (%a, %b) = @_;
1489
1490 foreach my $item (keys %a) {
1491 if (!defined($b{$item})) {
1492 print "diff $item\n";
1493 return 1;
1494 }
1495 delete $b{$item};
1496 }
1497
1498 my @keys = keys %b;
1499 if ($#keys) {
1500 print "diff2 $keys[0]\n";
1501 }
1502 return -1 if ($#keys >= 0);
1503
1504 return 0;
1505}
1506
1507sub run_config_bisect_test {
1508 my ($type) = @_;
1509
1510 return run_bisect_test $type, "oldconfig";
1511}
1512
1513sub process_passed {
1514 my (%configs) = @_;
1515
1516 doprint "These configs had no failure: (Enabling them for further compiles)\n";
1517 # Passed! All these configs are part of a good compile.
1518 # Add them to the min options.
1519 foreach my $config (keys %configs) {
1520 if (defined($config_list{$config})) {
1521 doprint " removing $config\n";
1522 $config_ignore{$config} = $config_list{$config};
1523 delete $config_list{$config};
1524 }
1525 }
1526 doprint "config copied to $outputdir/config_good\n";
1527 run_command "cp -f $output_config $outputdir/config_good";
1528}
1529
1530sub process_failed {
1531 my ($config) = @_;
1532
1533 doprint "\n\n***************************************\n";
1534 doprint "Found bad config: $config\n";
1535 doprint "***************************************\n\n";
1536}
1537
1538sub run_config_bisect {
1539
1540 my @start_list = keys %config_list;
1541
1542 if ($#start_list < 0) {
1543 doprint "No more configs to test!!!\n";
1544 return -1;
1545 }
1546
1547 doprint "***** RUN TEST ***\n";
1548 my $type = $opt{"CONFIG_BISECT_TYPE[$iteration]"};
1549 my $ret;
1550 my %current_config;
1551
1552 my $count = $#start_list + 1;
1553 doprint " $count configs to test\n";
1554
1555 my $half = int($#start_list / 2);
1556
1557 do {
1558 my @tophalf = @start_list[0 .. $half];
1559
1560 create_config @tophalf;
1561 read_current_config \%current_config;
1562
1563 $count = $#tophalf + 1;
1564 doprint "Testing $count configs\n";
1565 my $found = 0;
1566 # make sure we test something
1567 foreach my $config (@tophalf) {
1568 if (defined($current_config{$config})) {
1569 logit " $config\n";
1570 $found = 1;
1571 }
1572 }
1573 if (!$found) {
1574 # try the other half
1575 doprint "Top half produced no set configs, trying bottom half\n";
1576 @tophalf = @start_list[$half .. $#start_list];
1577 create_config @tophalf;
1578 read_current_config \%current_config;
1579 foreach my $config (@tophalf) {
1580 if (defined($current_config{$config})) {
1581 logit " $config\n";
1582 $found = 1;
1583 }
1584 }
1585 if (!$found) {
1586 doprint "Failed: Can't make new config with current configs\n";
1587 foreach my $config (@start_list) {
1588 doprint " CONFIG: $config\n";
1589 }
1590 return -1;
1591 }
1592 $count = $#tophalf + 1;
1593 doprint "Testing $count configs\n";
1594 }
1595
1596 $ret = run_config_bisect_test $type;
1597 if ($bisect_manual) {
1598 $ret = answer_bisect;
1599 }
1600 if ($ret) {
1601 process_passed %current_config;
1602 return 0;
1603 }
1604
1605 doprint "This config had a failure.\n";
1606 doprint "Removing these configs that were not set in this config:\n";
1607 doprint "config copied to $outputdir/config_bad\n";
1608 run_command "cp -f $output_config $outputdir/config_bad";
1609
1610 # A config exists in this group that was bad.
1611 foreach my $config (keys %config_list) {
1612 if (!defined($current_config{$config})) {
1613 doprint " removing $config\n";
1614 delete $config_list{$config};
1615 }
1616 }
1617
1618 @start_list = @tophalf;
1619
1620 if ($#start_list == 0) {
1621 process_failed $start_list[0];
1622 return 1;
1623 }
1624
1625 # remove half the configs we are looking at and see if
1626 # they are good.
1627 $half = int($#start_list / 2);
1628 } while ($half > 0);
1629
1630 # we found a single config, try it again unless we are running manually
1631
1632 if ($bisect_manual) {
1633 process_failed $start_list[0];
1634 return 1;
1635 }
1636
1637 my @tophalf = @start_list[0 .. 0];
1638
1639 $ret = run_config_bisect_test $type;
1640 if ($ret) {
1641 process_passed %current_config;
1642 return 0;
1643 }
1644
1645 process_failed $start_list[0];
1646 return 1;
1647}
1648
1649sub config_bisect {
1650 my ($i) = @_;
1651
1652 my $start_config = $opt{"CONFIG_BISECT[$i]"};
1653
1654 my $tmpconfig = "$tmpdir/use_config";
1655
1656 # Make the file with the bad config and the min config
1657 if (defined($minconfig)) {
1658 # read the min config for things to ignore
1659 run_command "cp $minconfig $tmpconfig" or
1660 dodie "failed to copy $minconfig to $tmpconfig";
1661 } else {
1662 unlink $tmpconfig;
1663 }
1664
1665 # Add other configs
1666 if (defined($addconfig)) {
1667 run_command "cat $addconfig >> $tmpconfig" or
1668 dodie "failed to append $addconfig";
1669 }
1670
1671 my $defconfig = "";
1672 if (-f $tmpconfig) {
1673 $defconfig = "KCONFIG_ALLCONFIG=$tmpconfig";
1674 process_config_ignore $tmpconfig;
1675 }
1676
1677 # now process the start config
1678 run_command "cp $start_config $output_config" or
1679 dodie "failed to copy $start_config to $output_config";
1680
1681 # read directly what we want to check
1682 my %config_check;
1683 open (IN, $output_config)
1684 or dodie "faied to open $output_config";
1685
1686 while (<IN>) {
1687 if (/^((CONFIG\S*)=.*)/) {
1688 $config_check{$2} = $1;
1689 }
1690 }
1691 close(IN);
1692
1693 # Now run oldconfig with the minconfig (and addconfigs)
1694 make_oldconfig $defconfig;
1695
1696 # check to see what we lost (or gained)
1697 open (IN, $output_config)
1698 or dodie "Failed to read $start_config";
1699
1700 my %removed_configs;
1701 my %added_configs;
1702
1703 while (<IN>) {
1704 if (/^((CONFIG\S*)=.*)/) {
1705 # save off all options
1706 $config_set{$2} = $1;
1707 if (defined($config_check{$2})) {
1708 if (defined($config_ignore{$2})) {
1709 $removed_configs{$2} = $1;
1710 } else {
1711 $config_list{$2} = $1;
1712 }
1713 } elsif (!defined($config_ignore{$2})) {
1714 $added_configs{$2} = $1;
1715 $config_list{$2} = $1;
1716 }
1717 }
1718 }
1719 close(IN);
1720
1721 my @confs = keys %removed_configs;
1722 if ($#confs >= 0) {
1723 doprint "Configs overridden by default configs and removed from check:\n";
1724 foreach my $config (@confs) {
1725 doprint " $config\n";
1726 }
1727 }
1728 @confs = keys %added_configs;
1729 if ($#confs >= 0) {
1730 doprint "Configs appearing in make oldconfig and added:\n";
1731 foreach my $config (@confs) {
1732 doprint " $config\n";
1733 }
1734 }
1735
1736 my %config_test;
1737 my $once = 0;
1738
1739 # Sometimes kconfig does weird things. We must make sure
1740 # that the config we autocreate has everything we need
1741 # to test, otherwise we may miss testing configs, or
1742 # may not be able to create a new config.
1743 # Here we create a config with everything set.
1744 create_config (keys %config_list);
1745 read_current_config \%config_test;
1746 foreach my $config (keys %config_list) {
1747 if (!defined($config_test{$config})) {
1748 if (!$once) {
1749 $once = 1;
1750 doprint "Configs not produced by kconfig (will not be checked):\n";
1751 }
1752 doprint " $config\n";
1753 delete $config_list{$config};
1754 }
1755 }
1756 my $ret;
1757 do {
1758 $ret = run_config_bisect;
1759 } while (!$ret);
1760
1761 return $ret if ($ret < 0);
1762
1763 success $i;
1764}
1765
1766sub patchcheck {
1767 my ($i) = @_;
1768
1769 die "PATCHCHECK_START[$i] not defined\n"
1770 if (!defined($opt{"PATCHCHECK_START[$i]"}));
1771 die "PATCHCHECK_TYPE[$i] not defined\n"
1772 if (!defined($opt{"PATCHCHECK_TYPE[$i]"}));
1773
1774 my $start = $opt{"PATCHCHECK_START[$i]"};
1775
1776 my $end = "HEAD";
1777 if (defined($opt{"PATCHCHECK_END[$i]"})) {
1778 $end = $opt{"PATCHCHECK_END[$i]"};
1779 }
1780
1781 # Get the true sha1's since we can use things like HEAD~3
1782 $start = get_sha1($start);
1783 $end = get_sha1($end);
1784
1785 my $type = $opt{"PATCHCHECK_TYPE[$i]"};
1786
1787 # Can't have a test without having a test to run
1788 if ($type eq "test" && !defined($run_test)) {
1789 $type = "boot";
1790 }
1791
1792 open (IN, "git log --pretty=oneline $end|") or
1793 dodie "could not get git list";
1794
1795 my @list;
1796
1797 while (<IN>) {
1798 chomp;
1799 $list[$#list+1] = $_;
1800 last if (/^$start/);
1801 }
1802 close(IN);
1803
1804 if ($list[$#list] !~ /^$start/) {
1805 fail "SHA1 $start not found";
1806 }
1807
1808 # go backwards in the list
1809 @list = reverse @list;
1810
1811 my $save_clean = $noclean;
1812
1813 $in_patchcheck = 1;
1814 foreach my $item (@list) {
1815 my $sha1 = $item;
1816 $sha1 =~ s/^([[:xdigit:]]+).*/$1/;
1817
1818 doprint "\nProcessing commit $item\n\n";
1819
1820 run_command "git checkout $sha1" or
1821 die "Failed to checkout $sha1";
1822
1823 # only clean on the first and last patch
1824 if ($item eq $list[0] ||
1825 $item eq $list[$#list]) {
1826 $noclean = $save_clean;
1827 } else {
1828 $noclean = 1;
1829 }
1830
1831 if (defined($minconfig)) {
1832 build "useconfig:$minconfig" or return 0;
1833 } else {
1834 # ?? no config to use?
1835 build "oldconfig" or return 0;
1836 }
1837
1838 check_buildlog $sha1 or return 0;
1839
1840 next if ($type eq "build");
1841
1842 get_grub_index;
1843 get_version;
1844 install;
1845
1846 my $failed = 0;
1847
1848 start_monitor;
1849 monitor or $failed = 1;
1850
1851 if (!$failed && $type ne "boot"){
1852 do_run_test or $failed = 1;
1853 }
1854 end_monitor;
1855 return 0 if ($failed);
1856
1857 }
1858 $in_patchcheck = 0;
1859 success $i;
1860
1861 return 1;
1862}
1863
1864$#ARGV < 1 or die "ktest.pl version: $VERSION\n usage: ktest.pl config-file\n";
1865
1866if ($#ARGV == 0) {
1867 $ktest_config = $ARGV[0];
1868 if (! -f $ktest_config) {
1869 print "$ktest_config does not exist.\n";
1870 my $ans;
1871 for (;;) {
1872 print "Create it? [Y/n] ";
1873 $ans = <STDIN>;
1874 chomp $ans;
1875 if ($ans =~ /^\s*$/) {
1876 $ans = "y";
1877 }
1878 last if ($ans =~ /^y$/i || $ans =~ /^n$/i);
1879 print "Please answer either 'y' or 'n'.\n";
1880 }
1881 if ($ans !~ /^y$/i) {
1882 exit 0;
1883 }
1884 }
1885} else {
1886 $ktest_config = "ktest.conf";
1887}
1888
1889if (! -f $ktest_config) {
1890 open(OUT, ">$ktest_config") or die "Can not create $ktest_config";
1891 print OUT << "EOF"
1892# Generated by ktest.pl
1893#
1894# Define each test with TEST_START
1895# The config options below it will override the defaults
1896TEST_START
1897
1898DEFAULTS
1899EOF
1900;
1901 close(OUT);
1902}
1903read_config $ktest_config;
1904
1905# Append any configs entered in manually to the config file.
1906my @new_configs = keys %entered_configs;
1907if ($#new_configs >= 0) {
1908 print "\nAppending entered in configs to $ktest_config\n";
1909 open(OUT, ">>$ktest_config") or die "Can not append to $ktest_config";
1910 foreach my $config (@new_configs) {
1911 print OUT "$config = $entered_configs{$config}\n";
1912 $opt{$config} = $entered_configs{$config};
1913 }
1914}
1915
1916if ($opt{"CLEAR_LOG"} && defined($opt{"LOG_FILE"})) {
1917 unlink $opt{"LOG_FILE"};
1918}
1919
1920doprint "\n\nSTARTING AUTOMATED TESTS\n\n";
1921
1922for (my $i = 0, my $repeat = 1; $i <= $opt{"NUM_TESTS"}; $i += $repeat) {
1923
1924 if (!$i) {
1925 doprint "DEFAULT OPTIONS:\n";
1926 } else {
1927 doprint "\nTEST $i OPTIONS";
1928 if (defined($repeat_tests{$i})) {
1929 $repeat = $repeat_tests{$i};
1930 doprint " ITERATE $repeat";
1931 }
1932 doprint "\n";
1933 }
1934
1935 foreach my $option (sort keys %opt) {
1936
1937 if ($option =~ /\[(\d+)\]$/) {
1938 next if ($i != $1);
1939 } else {
1940 next if ($i);
1941 }
1942
1943 doprint "$option = $opt{$option}\n";
1944 }
1945}
1946
1947sub set_test_option {
1948 my ($name, $i) = @_;
1949
1950 my $option = "$name\[$i\]";
1951
1952 if (defined($opt{$option})) {
1953 return $opt{$option};
1954 }
1955
1956 foreach my $test (keys %repeat_tests) {
1957 if ($i >= $test &&
1958 $i < $test + $repeat_tests{$test}) {
1959 $option = "$name\[$test\]";
1960 if (defined($opt{$option})) {
1961 return $opt{$option};
1962 }
1963 }
1964 }
1965
1966 if (defined($opt{$name})) {
1967 return $opt{$name};
1968 }
1969
1970 return undef;
1971}
1972
1973# First we need to do is the builds
1974for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
1975
1976 $iteration = $i;
1977
1978 my $makecmd = set_test_option("MAKE_CMD", $i);
1979
1980 $machine = set_test_option("MACHINE", $i);
1981 $ssh_user = set_test_option("SSH_USER", $i);
1982 $tmpdir = set_test_option("TMP_DIR", $i);
1983 $outputdir = set_test_option("OUTPUT_DIR", $i);
1984 $builddir = set_test_option("BUILD_DIR", $i);
1985 $test_type = set_test_option("TEST_TYPE", $i);
1986 $build_type = set_test_option("BUILD_TYPE", $i);
1987 $build_options = set_test_option("BUILD_OPTIONS", $i);
1988 $power_cycle = set_test_option("POWER_CYCLE", $i);
1989 $reboot = set_test_option("REBOOT", $i);
1990 $noclean = set_test_option("BUILD_NOCLEAN", $i);
1991 $minconfig = set_test_option("MIN_CONFIG", $i);
1992 $run_test = set_test_option("TEST", $i);
1993 $addconfig = set_test_option("ADD_CONFIG", $i);
1994 $reboot_type = set_test_option("REBOOT_TYPE", $i);
1995 $grub_menu = set_test_option("GRUB_MENU", $i);
1996 $post_install = set_test_option("POST_INSTALL", $i);
1997 $reboot_script = set_test_option("REBOOT_SCRIPT", $i);
1998 $reboot_on_error = set_test_option("REBOOT_ON_ERROR", $i);
1999 $poweroff_on_error = set_test_option("POWEROFF_ON_ERROR", $i);
2000 $die_on_failure = set_test_option("DIE_ON_FAILURE", $i);
2001 $power_off = set_test_option("POWER_OFF", $i);
2002 $powercycle_after_reboot = set_test_option("POWERCYCLE_AFTER_REBOOT", $i);
2003 $poweroff_after_halt = set_test_option("POWEROFF_AFTER_HALT", $i);
2004 $sleep_time = set_test_option("SLEEP_TIME", $i);
2005 $bisect_sleep_time = set_test_option("BISECT_SLEEP_TIME", $i);
2006 $bisect_manual = set_test_option("BISECT_MANUAL", $i);
2007 $bisect_skip = set_test_option("BISECT_SKIP", $i);
2008 $store_failures = set_test_option("STORE_FAILURES", $i);
2009 $timeout = set_test_option("TIMEOUT", $i);
2010 $booted_timeout = set_test_option("BOOTED_TIMEOUT", $i);
2011 $console = set_test_option("CONSOLE", $i);
2012 $success_line = set_test_option("SUCCESS_LINE", $i);
2013 $stop_after_success = set_test_option("STOP_AFTER_SUCCESS", $i);
2014 $stop_after_failure = set_test_option("STOP_AFTER_FAILURE", $i);
2015 $stop_test_after = set_test_option("STOP_TEST_AFTER", $i);
2016 $build_target = set_test_option("BUILD_TARGET", $i);
2017 $ssh_exec = set_test_option("SSH_EXEC", $i);
2018 $scp_to_target = set_test_option("SCP_TO_TARGET", $i);
2019 $target_image = set_test_option("TARGET_IMAGE", $i);
2020 $localversion = set_test_option("LOCALVERSION", $i);
2021
2022 chdir $builddir || die "can't change directory to $builddir";
2023
2024 if (!-d $tmpdir) {
2025 mkpath($tmpdir) or
2026 die "can't create $tmpdir";
2027 }
2028
2029 $ENV{"SSH_USER"} = $ssh_user;
2030 $ENV{"MACHINE"} = $machine;
2031
2032 $target = "$ssh_user\@$machine";
2033
2034 $buildlog = "$tmpdir/buildlog-$machine";
2035 $dmesg = "$tmpdir/dmesg-$machine";
2036 $make = "$makecmd O=$outputdir";
2037 $output_config = "$outputdir/.config";
2038
2039 if ($reboot_type eq "grub") {
2040 dodie "GRUB_MENU not defined" if (!defined($grub_menu));
2041 } elsif (!defined($reboot_script)) {
2042 dodie "REBOOT_SCRIPT not defined"
2043 }
2044
2045 my $run_type = $build_type;
2046 if ($test_type eq "patchcheck") {
2047 $run_type = $opt{"PATCHCHECK_TYPE[$i]"};
2048 } elsif ($test_type eq "bisect") {
2049 $run_type = $opt{"BISECT_TYPE[$i]"};
2050 } elsif ($test_type eq "config_bisect") {
2051 $run_type = $opt{"CONFIG_BISECT_TYPE[$i]"};
2052 }
2053
2054 # mistake in config file?
2055 if (!defined($run_type)) {
2056 $run_type = "ERROR";
2057 }
2058
2059 doprint "\n\n";
2060 doprint "RUNNING TEST $i of $opt{NUM_TESTS} with option $test_type $run_type\n\n";
2061
2062 unlink $dmesg;
2063 unlink $buildlog;
2064
2065 if (!defined($minconfig)) {
2066 $minconfig = $addconfig;
2067
2068 } elsif (defined($addconfig)) {
2069 run_command "cat $addconfig $minconfig > $tmpdir/add_config" or
2070 dodie "Failed to create temp config";
2071 $minconfig = "$tmpdir/add_config";
2072 }
2073
2074 my $checkout = $opt{"CHECKOUT[$i]"};
2075 if (defined($checkout)) {
2076 run_command "git checkout $checkout" or
2077 die "failed to checkout $checkout";
2078 }
2079
2080 if ($test_type eq "bisect") {
2081 bisect $i;
2082 next;
2083 } elsif ($test_type eq "config_bisect") {
2084 config_bisect $i;
2085 next;
2086 } elsif ($test_type eq "patchcheck") {
2087 patchcheck $i;
2088 next;
2089 }
2090
2091 if ($build_type ne "nobuild") {
2092 build $build_type or next;
2093 }
2094
2095 if ($test_type ne "build") {
2096 get_grub_index;
2097 get_version;
2098 install;
2099
2100 my $failed = 0;
2101 start_monitor;
2102 monitor or $failed = 1;;
2103
2104 if (!$failed && $test_type ne "boot" && defined($run_test)) {
2105 do_run_test or $failed = 1;
2106 }
2107 end_monitor;
2108 next if ($failed);
2109 }
2110
2111 success $i;
2112}
2113
2114if ($opt{"POWEROFF_ON_SUCCESS"}) {
2115 halt;
2116} elsif ($opt{"REBOOT_ON_SUCCESS"} && !do_not_reboot) {
2117 reboot;
2118}
2119
2120doprint "\n $successes of $opt{NUM_TESTS} tests were successful\n\n";
2121
2122exit 0;
diff --git a/tools/testing/ktest/sample.conf b/tools/testing/ktest/sample.conf
new file mode 100644
index 000000000000..4c5d6bd74a02
--- /dev/null
+++ b/tools/testing/ktest/sample.conf
@@ -0,0 +1,664 @@
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
77#### Mandatory Default Options ####
78
79# These options must be in the default section, although most
80# may be overridden by test options.
81
82# The machine hostname that you will test
83#MACHINE = target
84
85# The box is expected to have ssh on normal bootup, provide the user
86# (most likely root, since you need privileged operations)
87#SSH_USER = root
88
89# The directory that contains the Linux source code
90#BUILD_DIR = /home/test/linux.git
91
92# The directory that the objects will be built
93# (can not be same as BUILD_DIR)
94#OUTPUT_DIR = /home/test/build/target
95
96# The location of the compiled file to copy to the target
97# (relative to OUTPUT_DIR)
98#BUILD_TARGET = arch/x86/boot/bzImage
99
100# The place to put your image on the test machine
101#TARGET_IMAGE = /boot/vmlinuz-test
102
103# A script or command to reboot the box
104#
105# Here is a digital loggers power switch example
106#POWER_CYCLE = wget --no-proxy -O /dev/null -q --auth-no-challenge 'http://admin:admin@power/outlet?5=CCL'
107#
108# Here is an example to reboot a virtual box on the current host
109# with the name "Guest".
110#POWER_CYCLE = virsh destroy Guest; sleep 5; virsh start Guest
111
112# The script or command that reads the console
113#
114# If you use ttywatch server, something like the following would work.
115#CONSOLE = nc -d localhost 3001
116#
117# For a virtual machine with guest name "Guest".
118#CONSOLE = virsh console Guest
119
120# Required version ending to differentiate the test
121# from other linux builds on the system.
122#LOCALVERSION = -test
123
124# The grub title name for the test kernel to boot
125# (Only mandatory if REBOOT_TYPE = grub)
126#
127# Note, ktest.pl will not update the grub menu.lst, you need to
128# manually add an option for the test. ktest.pl will search
129# the grub menu.lst for this option to find what kernel to
130# reboot into.
131#
132# For example, if in the /boot/grub/menu.lst the test kernel title has:
133# title Test Kernel
134# kernel vmlinuz-test
135#GRUB_MENU = Test Kernel
136
137# A script to reboot the target into the test kernel
138# (Only mandatory if REBOOT_TYPE = script)
139#REBOOT_SCRIPT =
140
141#### Optional Config Options (all have defaults) ####
142
143# Start a test setup. If you leave this off, all options
144# will be default and the test will run once.
145# This is a label and not really an option (it takes no value).
146# You can append ITERATE and a number after it to iterate the
147# test a number of times, or SKIP to ignore this test.
148#
149#TEST_START
150#TEST_START ITERATE 5
151#TEST_START SKIP
152
153# Have the following options as default again. Used after tests
154# have already been defined by TEST_START. Optionally, you can
155# just define all default options before the first TEST_START
156# and you do not need this option.
157#
158# This is a label and not really an option (it takes no value).
159# You can append SKIP to this label and the options within this
160# section will be ignored.
161#
162# DEFAULTS
163# DEFAULTS SKIP
164
165# The default test type (default test)
166# The test types may be:
167# build - only build the kernel, do nothing else
168# boot - build and boot the kernel
169# test - build, boot and if TEST is set, run the test script
170# (If TEST is not set, it defaults back to boot)
171# bisect - Perform a bisect on the kernel (see BISECT_TYPE below)
172# patchcheck - Do a test on a series of commits in git (see PATCHCHECK below)
173#TEST_TYPE = test
174
175# Test to run if there is a successful boot and TEST_TYPE is test.
176# Must exit with 0 on success and non zero on error
177# default (undefined)
178#TEST = ssh user@machine /root/run_test
179
180# The build type is any make config type or special command
181# (default randconfig)
182# nobuild - skip the clean and build step
183# useconfig:/path/to/config - use the given config and run
184# oldconfig on it.
185# This option is ignored if TEST_TYPE is patchcheck or bisect
186#BUILD_TYPE = randconfig
187
188# The make command (default make)
189# If you are building a 32bit x86 on a 64 bit host
190#MAKE_CMD = CC=i386-gcc AS=i386-as make ARCH=i386
191
192# Any build options for the make of the kernel (not for other makes, like configs)
193# (default "")
194#BUILD_OPTIONS = -j20
195
196# If you need an initrd, you can add a script or code here to install
197# it. The environment variable KERNEL_VERSION will be set to the
198# kernel version that is used. Remember to add the initrd line
199# to your grub menu.lst file.
200#
201# Here's a couple of examples to use:
202#POST_INSTALL = ssh user@target /sbin/mkinitrd --allow-missing -f /boot/initramfs-test.img $KERNEL_VERSION
203#
204# or on some systems:
205#POST_INSTALL = ssh user@target /sbin/dracut -f /boot/initramfs-test.img $KERNEL_VERSION
206
207# Way to reboot the box to the test kernel.
208# Only valid options so far are "grub" and "script"
209# (default grub)
210# If you specify grub, it will assume grub version 1
211# and will search in /boot/grub/menu.lst for the title $GRUB_MENU
212# and select that target to reboot to the kernel. If this is not
213# your setup, then specify "script" and have a command or script
214# specified in REBOOT_SCRIPT to boot to the target.
215#
216# The entry in /boot/grub/menu.lst must be entered in manually.
217# The test will not modify that file.
218#REBOOT_TYPE = grub
219
220# The min config that is needed to build for the machine
221# A nice way to create this is with the following:
222#
223# $ ssh target
224# $ lsmod > mymods
225# $ scp mymods host:/tmp
226# $ exit
227# $ cd linux.git
228# $ rm .config
229# $ make LSMOD=mymods localyesconfig
230# $ grep '^CONFIG' .config > /home/test/config-min
231#
232# If you want even less configs:
233#
234# log in directly to target (do not ssh)
235#
236# $ su
237# # lsmod | cut -d' ' -f1 | xargs rmmod
238#
239# repeat the above several times
240#
241# # lsmod > mymods
242# # reboot
243#
244# May need to reboot to get your network back to copy the mymods
245# to the host, and then remove the previous .config and run the
246# localyesconfig again. The CONFIG_MIN generated like this will
247# not guarantee network activity to the box so the TEST_TYPE of
248# test may fail.
249#
250# You might also want to set:
251# CONFIG_CMDLINE="<your options here>"
252# randconfig may set the above and override your real command
253# line options.
254# (default undefined)
255#MIN_CONFIG = /home/test/config-min
256
257# Sometimes there's options that just break the boot and
258# you do not care about. Here are a few:
259# # CONFIG_STAGING is not set
260# Staging drivers are horrible, and can break the build.
261# # CONFIG_SCSI_DEBUG is not set
262# SCSI_DEBUG may change your root partition
263# # CONFIG_KGDB_SERIAL_CONSOLE is not set
264# KGDB may cause oops waiting for a connection that's not there.
265# This option points to the file containing config options that will be prepended
266# to the MIN_CONFIG (or be the MIN_CONFIG if it is not set)
267#
268# Note, config options in MIN_CONFIG will override these options.
269#
270# (default undefined)
271#ADD_CONFIG = /home/test/config-broken
272
273# The location on the host where to write temp files
274# (default /tmp/ktest)
275#TMP_DIR = /tmp/ktest
276
277# Optional log file to write the status (recommended)
278# Note, this is a DEFAULT section only option.
279# (default undefined)
280#LOG_FILE = /home/test/logfiles/target.log
281
282# Remove old logfile if it exists before starting all tests.
283# Note, this is a DEFAULT section only option.
284# (default 0)
285#CLEAR_LOG = 0
286
287# Line to define a successful boot up in console output.
288# This is what the line contains, not the entire line. If you need
289# the entire line to match, then use regural expression syntax like:
290# (do not add any quotes around it)
291#
292# SUCCESS_LINE = ^MyBox Login:$
293#
294# (default "login:")
295#SUCCESS_LINE = login:
296
297# In case the console constantly fills the screen, having
298# a specified time to stop the test after success is recommended.
299# (in seconds)
300# (default 10)
301#STOP_AFTER_SUCCESS = 10
302
303# In case the console constantly fills the screen, having
304# a specified time to stop the test after failure is recommended.
305# (in seconds)
306# (default 60)
307#STOP_AFTER_FAILURE = 60
308
309# In case the console constantly fills the screen, having
310# a specified time to stop the test if it never succeeds nor fails
311# is recommended.
312# Note: this is ignored if a success or failure is detected.
313# (in seconds)
314# (default 600, -1 is to never stop)
315#STOP_TEST_AFTER = 600
316
317# Stop testing if a build fails. If set, the script will end if
318# a failure is detected, otherwise it will save off the .config,
319# dmesg and bootlog in a directory called
320# MACHINE-TEST_TYPE_BUILD_TYPE-fail-yyyymmddhhmmss
321# if the STORE_FAILURES directory is set.
322# (default 1)
323# Note, even if this is set to zero, there are some errors that still
324# stop the tests.
325#DIE_ON_FAILURE = 1
326
327# Directory to store failure directories on failure. If this is not
328# set, DIE_ON_FAILURE=0 will not save off the .config, dmesg and
329# bootlog. This option is ignored if DIE_ON_FAILURE is not set.
330# (default undefined)
331#STORE_FAILURES = /home/test/failures
332
333# Build without doing a make mrproper, or removing .config
334# (default 0)
335#BUILD_NOCLEAN = 0
336
337# As the test reads the console, after it hits the SUCCESS_LINE
338# the time it waits for the monitor to settle down between reads
339# can usually be lowered.
340# (in seconds) (default 1)
341#BOOTED_TIMEOUT = 1
342
343# The timeout in seconds when we consider the box hung after
344# the console stop producing output. Be sure to leave enough
345# time here to get pass a reboot. Some machines may not produce
346# any console output for a long time during a reboot. You do
347# not want the test to fail just because the system was in
348# the process of rebooting to the test kernel.
349# (default 120)
350#TIMEOUT = 120
351
352# In between tests, a reboot of the box may occur, and this
353# is the time to wait for the console after it stops producing
354# output. Some machines may not produce a large lag on reboot
355# so this should accommodate it.
356# The difference between this and TIMEOUT, is that TIMEOUT happens
357# when rebooting to the test kernel. This sleep time happens
358# after a test has completed and we are about to start running
359# another test. If a reboot to the reliable kernel happens,
360# we wait SLEEP_TIME for the console to stop producing output
361# before starting the next test.
362# (default 60)
363#SLEEP_TIME = 60
364
365# The time in between bisects to sleep (in seconds)
366# (default 60)
367#BISECT_SLEEP_TIME = 60
368
369# Reboot the target box on error (default 0)
370#REBOOT_ON_ERROR = 0
371
372# Power off the target on error (ignored if REBOOT_ON_ERROR is set)
373# Note, this is a DEFAULT section only option.
374# (default 0)
375#POWEROFF_ON_ERROR = 0
376
377# Power off the target after all tests have completed successfully
378# Note, this is a DEFAULT section only option.
379# (default 0)
380#POWEROFF_ON_SUCCESS = 0
381
382# Reboot the target after all test completed successfully (default 1)
383# (ignored if POWEROFF_ON_SUCCESS is set)
384#REBOOT_ON_SUCCESS = 1
385
386# In case there are isses with rebooting, you can specify this
387# to always powercycle after this amount of time after calling
388# reboot.
389# Note, POWERCYCLE_AFTER_REBOOT = 0 does NOT disable it. It just
390# makes it powercycle immediately after rebooting. Do not define
391# it if you do not want it.
392# (default undefined)
393#POWERCYCLE_AFTER_REBOOT = 5
394
395# In case there's isses with halting, you can specify this
396# to always poweroff after this amount of time after calling
397# halt.
398# Note, POWEROFF_AFTER_HALT = 0 does NOT disable it. It just
399# makes it poweroff immediately after halting. Do not define
400# it if you do not want it.
401# (default undefined)
402#POWEROFF_AFTER_HALT = 20
403
404# A script or command to power off the box (default undefined)
405# Needed for POWEROFF_ON_ERROR and SUCCESS
406#
407# Example for digital loggers power switch:
408#POWER_OFF = wget --no-proxy -O /dev/null -q --auth-no-challenge 'http://admin:admin@power/outlet?5=OFF'
409#
410# Example for a virtual guest call "Guest".
411#POWER_OFF = virsh destroy Guest
412
413# The way to execute a command on the target
414# (default ssh $SSH_USER@$MACHINE $SSH_COMMAND";)
415# The variables SSH_USER, MACHINE and SSH_COMMAND are defined
416#SSH_EXEC = ssh $SSH_USER@$MACHINE $SSH_COMMAND";
417
418# The way to copy a file to the target
419# (default scp $SRC_FILE $SSH_USER@$MACHINE:$DST_FILE)
420# The variables SSH_USER, MACHINE, SRC_FILE and DST_FILE are defined.
421#SCP_TO_TARGET = scp $SRC_FILE $SSH_USER@$MACHINE:$DST_FILE
422
423# The nice way to reboot the target
424# (default ssh $SSH_USER@$MACHINE reboot)
425# The variables SSH_USER and MACHINE are defined.
426#REBOOT = ssh $SSH_USER@$MACHINE reboot
427
428#### Per test run options ####
429# The following options are only allowed in TEST_START sections.
430# They are ignored in the DEFAULTS sections.
431#
432# All of these are optional and undefined by default, although
433# some of these options are required for TEST_TYPE of patchcheck
434# and bisect.
435#
436#
437# CHECKOUT = branch
438#
439# If the BUILD_DIR is a git repository, then you can set this option
440# to checkout the given branch before running the TEST. If you
441# specify this for the first run, that branch will be used for
442# all preceding tests until a new CHECKOUT is set.
443#
444#
445#
446# For TEST_TYPE = patchcheck
447#
448# This expects the BUILD_DIR to be a git repository, and
449# will checkout the PATCHCHECK_START commit.
450#
451# The option BUILD_TYPE will be ignored.
452#
453# The MIN_CONFIG will be used for all builds of the patchcheck. The build type
454# used for patchcheck is oldconfig.
455#
456# PATCHCHECK_START is required and is the first patch to
457# test (the SHA1 of the commit). You may also specify anything
458# that git checkout allows (branch name, tage, HEAD~3).
459#
460# PATCHCHECK_END is the last patch to check (default HEAD)
461#
462# PATCHCHECK_TYPE is required and is the type of test to run:
463# build, boot, test.
464#
465# Note, the build test will look for warnings, if a warning occurred
466# in a file that a commit touches, the build will fail.
467#
468# If BUILD_NOCLEAN is set, then make mrproper will not be run on
469# any of the builds, just like all other TEST_TYPE tests. But
470# what makes patchcheck different from the other tests, is if
471# BUILD_NOCLEAN is not set, only the first and last patch run
472# make mrproper. This helps speed up the test.
473#
474# Example:
475# TEST_START
476# TEST_TYPE = patchcheck
477# CHECKOUT = mybranch
478# PATCHCHECK_TYPE = boot
479# PATCHCHECK_START = 747e94ae3d1b4c9bf5380e569f614eb9040b79e7
480# PATCHCHECK_END = HEAD~2
481#
482#
483#
484# For TEST_TYPE = bisect
485#
486# You can specify a git bisect if the BUILD_DIR is a git repository.
487# The MIN_CONFIG will be used for all builds of the bisect. The build type
488# used for bisecting is oldconfig.
489#
490# The option BUILD_TYPE will be ignored.
491#
492# BISECT_TYPE is the type of test to perform:
493# build - bad fails to build
494# boot - bad builds but fails to boot
495# test - bad boots but fails a test
496#
497# BISECT_GOOD is the commit (SHA1) to label as good (accepts all git good commit types)
498# BISECT_BAD is the commit to label as bad (accepts all git bad commit types)
499#
500# The above three options are required for a bisect operation.
501#
502# BISECT_REPLAY = /path/to/replay/file (optional, default undefined)
503#
504# If an operation failed in the bisect that was not expected to
505# fail. Then the test ends. The state of the BUILD_DIR will be
506# left off at where the failure occurred. You can examine the
507# reason for the failure, and perhaps even find a git commit
508# that would work to continue with. You can run:
509#
510# git bisect log > /path/to/replay/file
511#
512# The adding:
513#
514# BISECT_REPLAY= /path/to/replay/file
515#
516# And running the test again. The test will perform the initial
517# git bisect start, git bisect good, and git bisect bad, and
518# then it will run git bisect replay on this file, before
519# continuing with the bisect.
520#
521# BISECT_START = commit (optional, default undefined)
522#
523# As with BISECT_REPLAY, if the test failed on a commit that
524# just happen to have a bad commit in the middle of the bisect,
525# and you need to skip it. If BISECT_START is defined, it
526# will checkout that commit after doing the initial git bisect start,
527# git bisect good, git bisect bad, and running the git bisect replay
528# if the BISECT_REPLAY is set.
529#
530# BISECT_SKIP = 1 (optional, default 0)
531#
532# If BISECT_TYPE is set to test but the build fails, ktest will
533# simply fail the test and end their. You could use BISECT_REPLAY
534# and BISECT_START to resume after you found a new starting point,
535# or you could set BISECT_SKIP to 1. If BISECT_SKIP is set to 1,
536# when something other than the BISECT_TYPE fails, ktest.pl will
537# run "git bisect skip" and try again.
538#
539# BISECT_FILES = <path> (optional, default undefined)
540#
541# To just run the git bisect on a specific path, set BISECT_FILES.
542# For example:
543#
544# BISECT_FILES = arch/x86 kernel/time
545#
546# Will run the bisect with "git bisect start -- arch/x86 kernel/time"
547#
548# BISECT_REVERSE = 1 (optional, default 0)
549#
550# In those strange instances where it was broken forever
551# and you are trying to find where it started to work!
552# Set BISECT_GOOD to the commit that was last known to fail
553# Set BISECT_BAD to the commit that is known to start working.
554# With BISECT_REVERSE = 1, The test will consider failures as
555# good, and success as bad.
556#
557# BISECT_MANUAL = 1 (optional, default 0)
558#
559# In case there's a problem with automating the bisect for
560# whatever reason. (Can't reboot, want to inspect each iteration)
561# Doing a BISECT_MANUAL will have the test wait for you to
562# tell it if the test passed or failed after each iteration.
563# This is basicall the same as running git bisect yourself
564# but ktest will rebuild and install the kernel for you.
565#
566# BISECT_CHECK = 1 (optional, default 0)
567#
568# Just to be sure the good is good and bad is bad, setting
569# BISECT_CHECK to 1 will start the bisect by first checking
570# out BISECT_BAD and makes sure it fails, then it will check
571# out BISECT_GOOD and makes sure it succeeds before starting
572# the bisect (it works for BISECT_REVERSE too).
573#
574# You can limit the test to just check BISECT_GOOD or
575# BISECT_BAD with BISECT_CHECK = good or
576# BISECT_CHECK = bad, respectively.
577#
578# Example:
579# TEST_START
580# TEST_TYPE = bisect
581# BISECT_GOOD = v2.6.36
582# BISECT_BAD = b5153163ed580e00c67bdfecb02b2e3843817b3e
583# BISECT_TYPE = build
584# MIN_CONFIG = /home/test/config-bisect
585#
586#
587#
588# For TEST_TYPE = config_bisect
589#
590# In those cases that you have two different configs. One of them
591# work, the other does not, and you do not know what config causes
592# the problem.
593# The TEST_TYPE config_bisect will bisect the bad config looking for
594# what config causes the failure.
595#
596# The way it works is this:
597#
598# First it finds a config to work with. Since a different version, or
599# MIN_CONFIG may cause different dependecies, it must run through this
600# preparation.
601#
602# Overwrites any config set in the bad config with a config set in
603# either the MIN_CONFIG or ADD_CONFIG. Thus, make sure these configs
604# are minimal and do not disable configs you want to test:
605# (ie. # CONFIG_FOO is not set).
606#
607# An oldconfig is run on the bad config and any new config that
608# appears will be added to the configs to test.
609#
610# Finally, it generates a config with the above result and runs it
611# again through make oldconfig to produce a config that should be
612# satisfied by kconfig.
613#
614# Then it starts the bisect.
615#
616# The configs to test are cut in half. If all the configs in this
617# half depend on a config in the other half, then the other half
618# is tested instead. If no configs are enabled by either half, then
619# this means a circular dependency exists and the test fails.
620#
621# A config is created with the test half, and the bisect test is run.
622#
623# If the bisect succeeds, then all configs in the generated config
624# are removed from the configs to test and added to the configs that
625# will be enabled for all builds (they will be enabled, but not be part
626# of the configs to examine).
627#
628# If the bisect fails, then all test configs that were not enabled by
629# the config file are removed from the test. These configs will not
630# be enabled in future tests. Since current config failed, we consider
631# this to be a subset of the config that we started with.
632#
633# When we are down to one config, it is considered the bad config.
634#
635# Note, the config chosen may not be the true bad config. Due to
636# dependencies and selections of the kbuild system, mulitple
637# configs may be needed to cause a failure. If you disable the
638# config that was found and restart the test, if the test fails
639# again, it is recommended to rerun the config_bisect with a new
640# bad config without the found config enabled.
641#
642# The option BUILD_TYPE will be ignored.
643#
644# CONFIG_BISECT_TYPE is the type of test to perform:
645# build - bad fails to build
646# boot - bad builds but fails to boot
647# test - bad boots but fails a test
648#
649# CONFIG_BISECT is the config that failed to boot
650#
651# If BISECT_MANUAL is set, it will pause between iterations.
652# This is useful to use just ktest.pl just for the config bisect.
653# If you set it to build, it will run the bisect and you can
654# control what happens in between iterations. It will ask you if
655# the test succeeded or not and continue the config bisect.
656#
657# Example:
658# TEST_START
659# TEST_TYPE = config_bisect
660# CONFIG_BISECT_TYPE = build
661# CONFIG_BISECT = /home/test/¢onfig-bad
662# MIN_CONFIG = /home/test/config-min
663# BISECT_MANUAL = 1
664#
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..df0c6d2c3860
--- /dev/null
+++ b/tools/virtio/virtio_test.c
@@ -0,0 +1,248 @@
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 = "indirect",
202 .val = 'I',
203 },
204 {
205 .name = "no-indirect",
206 .val = 'i',
207 },
208 {
209 }
210};
211
212static void help()
213{
214 fprintf(stderr, "Usage: virtio_test [--help] [--no-indirect]\n");
215}
216
217int main(int argc, char **argv)
218{
219 struct vdev_info dev;
220 unsigned long long features = 1ULL << VIRTIO_RING_F_INDIRECT_DESC;
221 int o;
222
223 for (;;) {
224 o = getopt_long(argc, argv, optstring, longopts, NULL);
225 switch (o) {
226 case -1:
227 goto done;
228 case '?':
229 help();
230 exit(2);
231 case 'h':
232 help();
233 goto done;
234 case 'i':
235 features &= ~(1ULL << VIRTIO_RING_F_INDIRECT_DESC);
236 break;
237 default:
238 assert(0);
239 break;
240 }
241 }
242
243done:
244 vdev_info_init(&dev, features);
245 vq_info_add(&dev, 256);
246 run_test(&dev, &dev.vqs[0], 0x100000);
247 return 0;
248}