aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/.gitignore1
-rw-r--r--tools/perf/Documentation/Makefile19
-rw-r--r--tools/perf/Documentation/perf-evlist.txt26
-rw-r--r--tools/perf/Documentation/perf-list.txt23
-rw-r--r--tools/perf/Documentation/perf-lock.txt12
-rw-r--r--tools/perf/Documentation/perf-probe.txt26
-rw-r--r--tools/perf/Documentation/perf-record.txt11
-rw-r--r--tools/perf/Documentation/perf-script.txt22
-rw-r--r--tools/perf/Documentation/perf-stat.txt11
-rw-r--r--tools/perf/Makefile654
-rw-r--r--tools/perf/bench/sched-pipe.c2
-rw-r--r--tools/perf/builtin-annotate.c341
-rw-r--r--tools/perf/builtin-diff.c17
-rw-r--r--tools/perf/builtin-evlist.c54
-rw-r--r--tools/perf/builtin-inject.c89
-rw-r--r--tools/perf/builtin-kmem.c11
-rw-r--r--tools/perf/builtin-list.c43
-rw-r--r--tools/perf/builtin-lock.c23
-rw-r--r--tools/perf/builtin-probe.c70
-rw-r--r--tools/perf/builtin-record.c473
-rw-r--r--tools/perf/builtin-report.c216
-rw-r--r--tools/perf/builtin-sched.c28
-rw-r--r--tools/perf/builtin-script.c310
-rw-r--r--tools/perf/builtin-stat.c126
-rw-r--r--tools/perf/builtin-test.c184
-rw-r--r--tools/perf/builtin-timechart.c30
-rw-r--r--tools/perf/builtin-top.c1067
-rw-r--r--tools/perf/builtin.h1
-rw-r--r--tools/perf/command-list.txt1
-rw-r--r--tools/perf/perf.c1
-rw-r--r--tools/perf/perf.h26
-rwxr-xr-xtools/perf/python/twatch.py41
-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.c22
-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.c5
-rw-r--r--tools/perf/util/cpumap.h2
-rw-r--r--tools/perf/util/debug.c12
-rw-r--r--tools/perf/util/debug.h3
-rw-r--r--tools/perf/util/event.c388
-rw-r--r--tools/perf/util/event.h74
-rw-r--r--tools/perf/util/evlist.c394
-rw-r--r--tools/perf/util/evlist.h68
-rw-r--r--tools/perf/util/evsel.c236
-rw-r--r--tools/perf/util/evsel.h47
-rw-r--r--tools/perf/util/exec_cmd.c19
-rw-r--r--tools/perf/util/header.c601
-rw-r--r--tools/perf/util/header.h95
-rw-r--r--tools/perf/util/hist.c257
-rw-r--r--tools/perf/util/hist.h61
-rw-r--r--tools/perf/util/include/linux/list.h1
-rw-r--r--tools/perf/util/parse-events.c197
-rw-r--r--tools/perf/util/parse-events.h13
-rw-r--r--tools/perf/util/probe-event.c178
-rw-r--r--tools/perf/util/probe-event.h4
-rw-r--r--tools/perf/util/probe-finder.c692
-rw-r--r--tools/perf/util/python.c896
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c12
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c15
-rw-r--r--tools/perf/util/session.c352
-rw-r--r--tools/perf/util/session.h52
-rw-r--r--tools/perf/util/setup.py24
-rw-r--r--tools/perf/util/strfilter.c199
-rw-r--r--tools/perf/util/strfilter.h48
-rw-r--r--tools/perf/util/string.c2
-rw-r--r--tools/perf/util/svghelper.c6
-rw-r--r--tools/perf/util/symbol.c97
-rw-r--r--tools/perf/util/symbol.h32
-rw-r--r--tools/perf/util/thread.c55
-rw-r--r--tools/perf/util/thread.h14
-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-parse.c112
-rw-r--r--tools/perf/util/trace-event-scripting.c10
-rw-r--r--tools/perf/util/trace-event.h11
-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.c178
-rw-r--r--tools/perf/util/ui/browsers/hists.c197
-rw-r--r--tools/perf/util/ui/browsers/map.c2
-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.c7
-rw-r--r--tools/perf/util/util.h26
-rw-r--r--tools/power/x86/turbostat/turbostat.c200
-rw-r--r--tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c2
-rwxr-xr-xtools/testing/ktest/ktest.pl141
-rw-r--r--tools/testing/ktest/sample.conf42
-rw-r--r--tools/usb/Makefile13
-rw-r--r--tools/usb/ffs-test.c4
-rw-r--r--tools/usb/hcd-tests.sh275
102 files changed, 7861 insertions, 4361 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-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-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 921de259ea10..4a26a2f3a6a3 100644
--- a/tools/perf/Documentation/perf-lock.txt
+++ b/tools/perf/Documentation/perf-lock.txt
@@ -24,8 +24,8 @@ 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
27OPTIONS 27COMMON OPTIONS
28------- 28--------------
29 29
30-i:: 30-i::
31--input=<file>:: 31--input=<file>::
@@ -39,6 +39,14 @@ OPTIONS
39--dump-raw-trace:: 39--dump-raw-trace::
40 Dump raw trace in ASCII. 40 Dump raw trace in ASCII.
41 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
42SEE ALSO 50SEE ALSO
43-------- 51--------
44linkperf:perf[1] 52linkperf:perf[1]
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 86b797a35aa6..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.
@@ -117,13 +128,14 @@ LINE SYNTAX
117----------- 128-----------
118Line range is described 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 e032716c839b..5a520f825295 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -137,6 +137,17 @@ Do not update the builid cache. This saves some overhead in situations
137where the information in the perf.data file (which includes buildids) 137where the information in the perf.data file (which includes buildids)
138is sufficient. 138is sufficient.
139 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
140SEE ALSO 151SEE ALSO
141-------- 152--------
142linkperf:perf-stat[1], linkperf:perf-list[1] 153linkperf:perf-stat[1], linkperf:perf-list[1]
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt
index 29ad94293cd2..66f040b30729 100644
--- a/tools/perf/Documentation/perf-script.txt
+++ b/tools/perf/Documentation/perf-script.txt
@@ -112,6 +112,28 @@ OPTIONS
112--debug-mode:: 112--debug-mode::
113 Do various checks like samples ordering and lost events. 113 Do various checks like samples ordering and lost events.
114 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.
136
115SEE ALSO 137SEE ALSO
116-------- 138--------
117linkperf:perf-record[1], linkperf:perf-script-perl[1], 139linkperf:perf-record[1], linkperf:perf-script-perl[1],
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index b6da7affbbee..918cc38ee6d1 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -83,6 +83,17 @@ This option is only valid in system-wide mode.
83print counts using a CSV-style output to make it easy to import directly into 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. 84spreadsheets. Columns are separated by the string specified in SEP.
85 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
86EXAMPLES 97EXAMPLES
87-------- 98--------
88 99
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 7141c42e1469..207dee5c5b16 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/ \
@@ -191,8 +46,6 @@ ifeq ($(ARCH),x86_64)
191 ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S 46 ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S
192endif 47endif
193 48
194# CFLAGS and LDFLAGS are for the users to override from the command line.
195
196# 49#
197# Include saner warnings here, which can catch bugs: 50# Include saner warnings here, which can catch bugs:
198# 51#
@@ -270,22 +123,13 @@ CC = $(CROSS_COMPILE)gcc
270AR = $(CROSS_COMPILE)ar 123AR = $(CROSS_COMPILE)ar
271RM = rm -f 124RM = rm -f
272MKDIR = mkdir 125MKDIR = mkdir
273TAR = tar
274FIND = find 126FIND = find
275INSTALL = install 127INSTALL = install
276RPMBUILD = rpmbuild
277PTHREAD_LIBS = -lpthread
278 128
279# sparse is architecture-neutral, which means that we need to tell it 129# sparse is architecture-neutral, which means that we need to tell it
280# explicitly what architecture to check for. Fix this up for yours.. 130# explicitly what architecture to check for. Fix this up for yours..
281SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__ 131SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
282 132
283ifeq ($(V), 2)
284 QUIET_STDERR = ">/dev/null"
285else
286 QUIET_STDERR = ">/dev/null 2>&1"
287endif
288
289-include feature-tests.mak 133-include feature-tests.mak
290 134
291ifeq ($(call try-cc,$(SOURCE_HELLO),-Werror -fstack-protector-all),y) 135ifeq ($(call try-cc,$(SOURCE_HELLO),-Werror -fstack-protector-all),y)
@@ -310,49 +154,41 @@ BASIC_LDFLAGS =
310 154
311# Guard against environment variables 155# Guard against environment variables
312BUILTIN_OBJS = 156BUILTIN_OBJS =
313BUILT_INS =
314COMPAT_CFLAGS =
315COMPAT_OBJS =
316LIB_H = 157LIB_H =
317LIB_OBJS = 158LIB_OBJS =
318SCRIPT_PERL = 159PYRF_OBJS =
319SCRIPT_SH = 160SCRIPT_SH =
320TEST_PROGRAMS =
321 161
322SCRIPT_SH += perf-archive.sh 162SCRIPT_SH += perf-archive.sh
323 163
324grep-libs = $(filter -l%,$(1)) 164grep-libs = $(filter -l%,$(1))
325strip-libs = $(filter-out -l%,$(1)) 165strip-libs = $(filter-out -l%,$(1))
326 166
167$(OUTPUT)python/perf.so: $(PYRF_OBJS)
168 $(QUIET_GEN)( \
169 export CFLAGS="$(BASIC_CFLAGS)"; \
170 python util/setup.py --quiet build_ext --build-lib='$(OUTPUT)python' \
171 --build-temp='$(OUTPUT)python/temp' \
172 )
173
327# 174#
328# No Perl scripts right now: 175# No Perl scripts right now:
329# 176#
330 177
331# SCRIPT_PERL += perf-add--interactive.perl 178SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH))
332
333SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \
334 $(patsubst %.perl,%,$(SCRIPT_PERL))
335
336# Empty...
337EXTRA_PROGRAMS =
338
339# ... and all the rest that could be moved out of bindir to perfexecdir
340PROGRAMS += $(EXTRA_PROGRAMS)
341 179
342# 180#
343# Single 'perf' binary right now: 181# Single 'perf' binary right now:
344# 182#
345PROGRAMS += $(OUTPUT)perf 183PROGRAMS += $(OUTPUT)perf
346 184
347# List built-in command $C whose implementation cmd_$C() is not in 185LANG_BINDINGS =
348# builtin-$C.o but is linked in as part of some other command.
349#
350 186
351# what 'all' will build and 'install' will install, in perfexecdir 187# what 'all' will build and 'install' will install, in perfexecdir
352ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS) 188ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
353 189
354# what 'all' will build but not install in perfexecdir 190# what 'all' will build but not install in perfexecdir
355OTHER_PROGRAMS = $(OUTPUT)perf$X 191OTHER_PROGRAMS = $(OUTPUT)perf
356 192
357# Set paths to tools early so that they can be used for version tests. 193# Set paths to tools early so that they can be used for version tests.
358ifndef SHELL_PATH 194ifndef SHELL_PATH
@@ -395,6 +231,7 @@ LIB_H += util/include/dwarf-regs.h
395LIB_H += util/include/asm/dwarf2.h 231LIB_H += util/include/asm/dwarf2.h
396LIB_H += util/include/asm/cpufeature.h 232LIB_H += util/include/asm/cpufeature.h
397LIB_H += perf.h 233LIB_H += perf.h
234LIB_H += util/annotate.h
398LIB_H += util/cache.h 235LIB_H += util/cache.h
399LIB_H += util/callchain.h 236LIB_H += util/callchain.h
400LIB_H += util/build-id.h 237LIB_H += util/build-id.h
@@ -402,6 +239,7 @@ LIB_H += util/debug.h
402LIB_H += util/debugfs.h 239LIB_H += util/debugfs.h
403LIB_H += util/event.h 240LIB_H += util/event.h
404LIB_H += util/evsel.h 241LIB_H += util/evsel.h
242LIB_H += util/evlist.h
405LIB_H += util/exec_cmd.h 243LIB_H += util/exec_cmd.h
406LIB_H += util/types.h 244LIB_H += util/types.h
407LIB_H += util/levenshtein.h 245LIB_H += util/levenshtein.h
@@ -416,6 +254,7 @@ LIB_H += util/help.h
416LIB_H += util/session.h 254LIB_H += util/session.h
417LIB_H += util/strbuf.h 255LIB_H += util/strbuf.h
418LIB_H += util/strlist.h 256LIB_H += util/strlist.h
257LIB_H += util/strfilter.h
419LIB_H += util/svghelper.h 258LIB_H += util/svghelper.h
420LIB_H += util/run-command.h 259LIB_H += util/run-command.h
421LIB_H += util/sigchain.h 260LIB_H += util/sigchain.h
@@ -425,21 +264,26 @@ LIB_H += util/values.h
425LIB_H += util/sort.h 264LIB_H += util/sort.h
426LIB_H += util/hist.h 265LIB_H += util/hist.h
427LIB_H += util/thread.h 266LIB_H += util/thread.h
267LIB_H += util/thread_map.h
428LIB_H += util/trace-event.h 268LIB_H += util/trace-event.h
429LIB_H += util/probe-finder.h 269LIB_H += util/probe-finder.h
430LIB_H += util/probe-event.h 270LIB_H += util/probe-event.h
431LIB_H += util/pstack.h 271LIB_H += util/pstack.h
432LIB_H += util/cpumap.h 272LIB_H += util/cpumap.h
273LIB_H += util/top.h
433LIB_H += $(ARCH_INCLUDE) 274LIB_H += $(ARCH_INCLUDE)
275LIB_H += util/cgroup.h
434 276
435LIB_OBJS += $(OUTPUT)util/abspath.o 277LIB_OBJS += $(OUTPUT)util/abspath.o
436LIB_OBJS += $(OUTPUT)util/alias.o 278LIB_OBJS += $(OUTPUT)util/alias.o
279LIB_OBJS += $(OUTPUT)util/annotate.o
437LIB_OBJS += $(OUTPUT)util/build-id.o 280LIB_OBJS += $(OUTPUT)util/build-id.o
438LIB_OBJS += $(OUTPUT)util/config.o 281LIB_OBJS += $(OUTPUT)util/config.o
439LIB_OBJS += $(OUTPUT)util/ctype.o 282LIB_OBJS += $(OUTPUT)util/ctype.o
440LIB_OBJS += $(OUTPUT)util/debugfs.o 283LIB_OBJS += $(OUTPUT)util/debugfs.o
441LIB_OBJS += $(OUTPUT)util/environment.o 284LIB_OBJS += $(OUTPUT)util/environment.o
442LIB_OBJS += $(OUTPUT)util/event.o 285LIB_OBJS += $(OUTPUT)util/event.o
286LIB_OBJS += $(OUTPUT)util/evlist.o
443LIB_OBJS += $(OUTPUT)util/evsel.o 287LIB_OBJS += $(OUTPUT)util/evsel.o
444LIB_OBJS += $(OUTPUT)util/exec_cmd.o 288LIB_OBJS += $(OUTPUT)util/exec_cmd.o
445LIB_OBJS += $(OUTPUT)util/help.o 289LIB_OBJS += $(OUTPUT)util/help.o
@@ -455,6 +299,8 @@ LIB_OBJS += $(OUTPUT)util/quote.o
455LIB_OBJS += $(OUTPUT)util/strbuf.o 299LIB_OBJS += $(OUTPUT)util/strbuf.o
456LIB_OBJS += $(OUTPUT)util/string.o 300LIB_OBJS += $(OUTPUT)util/string.o
457LIB_OBJS += $(OUTPUT)util/strlist.o 301LIB_OBJS += $(OUTPUT)util/strlist.o
302LIB_OBJS += $(OUTPUT)util/strfilter.o
303LIB_OBJS += $(OUTPUT)util/top.o
458LIB_OBJS += $(OUTPUT)util/usage.o 304LIB_OBJS += $(OUTPUT)util/usage.o
459LIB_OBJS += $(OUTPUT)util/wrapper.o 305LIB_OBJS += $(OUTPUT)util/wrapper.o
460LIB_OBJS += $(OUTPUT)util/sigchain.o 306LIB_OBJS += $(OUTPUT)util/sigchain.o
@@ -469,6 +315,7 @@ LIB_OBJS += $(OUTPUT)util/map.o
469LIB_OBJS += $(OUTPUT)util/pstack.o 315LIB_OBJS += $(OUTPUT)util/pstack.o
470LIB_OBJS += $(OUTPUT)util/session.o 316LIB_OBJS += $(OUTPUT)util/session.o
471LIB_OBJS += $(OUTPUT)util/thread.o 317LIB_OBJS += $(OUTPUT)util/thread.o
318LIB_OBJS += $(OUTPUT)util/thread_map.o
472LIB_OBJS += $(OUTPUT)util/trace-event-parse.o 319LIB_OBJS += $(OUTPUT)util/trace-event-parse.o
473LIB_OBJS += $(OUTPUT)util/trace-event-read.o 320LIB_OBJS += $(OUTPUT)util/trace-event-read.o
474LIB_OBJS += $(OUTPUT)util/trace-event-info.o 321LIB_OBJS += $(OUTPUT)util/trace-event-info.o
@@ -480,6 +327,7 @@ LIB_OBJS += $(OUTPUT)util/probe-event.o
480LIB_OBJS += $(OUTPUT)util/util.o 327LIB_OBJS += $(OUTPUT)util/util.o
481LIB_OBJS += $(OUTPUT)util/xyarray.o 328LIB_OBJS += $(OUTPUT)util/xyarray.o
482LIB_OBJS += $(OUTPUT)util/cpumap.o 329LIB_OBJS += $(OUTPUT)util/cpumap.o
330LIB_OBJS += $(OUTPUT)util/cgroup.o
483 331
484BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o 332BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
485 333
@@ -494,6 +342,7 @@ endif
494BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o 342BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o
495 343
496BUILTIN_OBJS += $(OUTPUT)builtin-diff.o 344BUILTIN_OBJS += $(OUTPUT)builtin-diff.o
345BUILTIN_OBJS += $(OUTPUT)builtin-evlist.o
497BUILTIN_OBJS += $(OUTPUT)builtin-help.o 346BUILTIN_OBJS += $(OUTPUT)builtin-help.o
498BUILTIN_OBJS += $(OUTPUT)builtin-sched.o 347BUILTIN_OBJS += $(OUTPUT)builtin-sched.o
499BUILTIN_OBJS += $(OUTPUT)builtin-buildid-list.o 348BUILTIN_OBJS += $(OUTPUT)builtin-buildid-list.o
@@ -514,6 +363,20 @@ BUILTIN_OBJS += $(OUTPUT)builtin-inject.o
514 363
515PERFLIBS = $(LIB_FILE) 364PERFLIBS = $(LIB_FILE)
516 365
366# Files needed for the python binding, perf.so
367# pyrf is just an internal name needed for all those wrappers.
368# This has to be in sync with what is in the 'sources' variable in
369# tools/perf/util/setup.py
370
371PYRF_OBJS += $(OUTPUT)util/cpumap.o
372PYRF_OBJS += $(OUTPUT)util/ctype.o
373PYRF_OBJS += $(OUTPUT)util/evlist.o
374PYRF_OBJS += $(OUTPUT)util/evsel.o
375PYRF_OBJS += $(OUTPUT)util/python.o
376PYRF_OBJS += $(OUTPUT)util/thread_map.o
377PYRF_OBJS += $(OUTPUT)util/util.o
378PYRF_OBJS += $(OUTPUT)util/xyarray.o
379
517# 380#
518# Platform specific tweaks 381# Platform specific tweaks
519# 382#
@@ -535,22 +398,6 @@ endif # NO_DWARF
535 398
536-include arch/$(ARCH)/Makefile 399-include arch/$(ARCH)/Makefile
537 400
538ifeq ($(uname_S),Darwin)
539 ifndef NO_FINK
540 ifeq ($(shell test -d /sw/lib && echo y),y)
541 BASIC_CFLAGS += -I/sw/include
542 BASIC_LDFLAGS += -L/sw/lib
543 endif
544 endif
545 ifndef NO_DARWIN_PORTS
546 ifeq ($(shell test -d /opt/local/lib && echo y),y)
547 BASIC_CFLAGS += -I/opt/local/include
548 BASIC_LDFLAGS += -L/opt/local/lib
549 endif
550 endif
551 PTHREAD_LIBS =
552endif
553
554ifneq ($(OUTPUT),) 401ifneq ($(OUTPUT),)
555 BASIC_CFLAGS += -I$(OUTPUT) 402 BASIC_CFLAGS += -I$(OUTPUT)
556endif 403endif
@@ -595,6 +442,7 @@ else
595 LIB_OBJS += $(OUTPUT)util/ui/browsers/annotate.o 442 LIB_OBJS += $(OUTPUT)util/ui/browsers/annotate.o
596 LIB_OBJS += $(OUTPUT)util/ui/browsers/hists.o 443 LIB_OBJS += $(OUTPUT)util/ui/browsers/hists.o
597 LIB_OBJS += $(OUTPUT)util/ui/browsers/map.o 444 LIB_OBJS += $(OUTPUT)util/ui/browsers/map.o
445 LIB_OBJS += $(OUTPUT)util/ui/browsers/top.o
598 LIB_OBJS += $(OUTPUT)util/ui/helpline.o 446 LIB_OBJS += $(OUTPUT)util/ui/helpline.o
599 LIB_OBJS += $(OUTPUT)util/ui/progress.o 447 LIB_OBJS += $(OUTPUT)util/ui/progress.o
600 LIB_OBJS += $(OUTPUT)util/ui/util.o 448 LIB_OBJS += $(OUTPUT)util/ui/util.o
@@ -604,6 +452,7 @@ else
604 LIB_H += util/ui/libslang.h 452 LIB_H += util/ui/libslang.h
605 LIB_H += util/ui/progress.h 453 LIB_H += util/ui/progress.h
606 LIB_H += util/ui/util.h 454 LIB_H += util/ui/util.h
455 LIB_H += util/ui/ui.h
607 endif 456 endif
608endif 457endif
609 458
@@ -635,12 +484,14 @@ else
635 PYTHON_EMBED_CCOPTS = `python-config --cflags 2>/dev/null` 484 PYTHON_EMBED_CCOPTS = `python-config --cflags 2>/dev/null`
636 FLAGS_PYTHON_EMBED=$(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS) 485 FLAGS_PYTHON_EMBED=$(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
637 ifneq ($(call try-cc,$(SOURCE_PYTHON_EMBED),$(FLAGS_PYTHON_EMBED)),y) 486 ifneq ($(call try-cc,$(SOURCE_PYTHON_EMBED),$(FLAGS_PYTHON_EMBED)),y)
487 msg := $(warning No Python.h found, install python-dev[el] to have python support in 'perf script' and to build the python bindings)
638 BASIC_CFLAGS += -DNO_LIBPYTHON 488 BASIC_CFLAGS += -DNO_LIBPYTHON
639 else 489 else
640 ALL_LDFLAGS += $(PYTHON_EMBED_LDFLAGS) 490 ALL_LDFLAGS += $(PYTHON_EMBED_LDFLAGS)
641 EXTLIBS += $(PYTHON_EMBED_LIBADD) 491 EXTLIBS += $(PYTHON_EMBED_LIBADD)
642 LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-python.o 492 LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-python.o
643 LIB_OBJS += $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o 493 LIB_OBJS += $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o
494 LANG_BINDINGS += $(OUTPUT)python/perf.so
644 endif 495 endif
645endif 496endif
646 497
@@ -690,201 +541,13 @@ else
690 endif 541 endif
691endif 542endif
692 543
693ifndef CC_LD_DYNPATH
694 ifdef NO_R_TO_GCC_LINKER
695 # Some gcc does not accept and pass -R to the linker to specify
696 # the runtime dynamic library path.
697 CC_LD_DYNPATH = -Wl,-rpath,
698 else
699 CC_LD_DYNPATH = -R
700 endif
701endif
702
703ifdef NEEDS_SOCKET
704 EXTLIBS += -lsocket
705endif
706ifdef NEEDS_NSL
707 EXTLIBS += -lnsl
708endif
709ifdef NO_D_TYPE_IN_DIRENT
710 BASIC_CFLAGS += -DNO_D_TYPE_IN_DIRENT
711endif
712ifdef NO_D_INO_IN_DIRENT
713 BASIC_CFLAGS += -DNO_D_INO_IN_DIRENT
714endif
715ifdef NO_ST_BLOCKS_IN_STRUCT_STAT
716 BASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT
717endif
718ifdef USE_NSEC
719 BASIC_CFLAGS += -DUSE_NSEC
720endif
721ifdef USE_ST_TIMESPEC
722 BASIC_CFLAGS += -DUSE_ST_TIMESPEC
723endif
724ifdef NO_NSEC
725 BASIC_CFLAGS += -DNO_NSEC
726endif
727ifdef NO_C99_FORMAT
728 BASIC_CFLAGS += -DNO_C99_FORMAT
729endif
730ifdef SNPRINTF_RETURNS_BOGUS
731 COMPAT_CFLAGS += -DSNPRINTF_RETURNS_BOGUS
732 COMPAT_OBJS += $(OUTPUT)compat/snprintf.o
733endif
734ifdef FREAD_READS_DIRECTORIES
735 COMPAT_CFLAGS += -DFREAD_READS_DIRECTORIES
736 COMPAT_OBJS += $(OUTPUT)compat/fopen.o
737endif
738ifdef NO_SYMLINK_HEAD
739 BASIC_CFLAGS += -DNO_SYMLINK_HEAD
740endif
741ifdef NO_STRCASESTR
742 COMPAT_CFLAGS += -DNO_STRCASESTR
743 COMPAT_OBJS += $(OUTPUT)compat/strcasestr.o
744endif
745ifdef NO_STRTOUMAX
746 COMPAT_CFLAGS += -DNO_STRTOUMAX
747 COMPAT_OBJS += $(OUTPUT)compat/strtoumax.o
748endif
749ifdef NO_STRTOULL
750 COMPAT_CFLAGS += -DNO_STRTOULL
751endif
752ifdef NO_SETENV
753 COMPAT_CFLAGS += -DNO_SETENV
754 COMPAT_OBJS += $(OUTPUT)compat/setenv.o
755endif
756ifdef NO_MKDTEMP
757 COMPAT_CFLAGS += -DNO_MKDTEMP
758 COMPAT_OBJS += $(OUTPUT)compat/mkdtemp.o
759endif
760ifdef NO_UNSETENV
761 COMPAT_CFLAGS += -DNO_UNSETENV
762 COMPAT_OBJS += $(OUTPUT)compat/unsetenv.o
763endif
764ifdef NO_SYS_SELECT_H
765 BASIC_CFLAGS += -DNO_SYS_SELECT_H
766endif
767ifdef NO_MMAP
768 COMPAT_CFLAGS += -DNO_MMAP
769 COMPAT_OBJS += $(OUTPUT)compat/mmap.o
770else
771 ifdef USE_WIN32_MMAP
772 COMPAT_CFLAGS += -DUSE_WIN32_MMAP
773 COMPAT_OBJS += $(OUTPUT)compat/win32mmap.o
774 endif
775endif
776ifdef NO_PREAD
777 COMPAT_CFLAGS += -DNO_PREAD
778 COMPAT_OBJS += $(OUTPUT)compat/pread.o
779endif
780ifdef NO_FAST_WORKING_DIRECTORY
781 BASIC_CFLAGS += -DNO_FAST_WORKING_DIRECTORY
782endif
783ifdef NO_TRUSTABLE_FILEMODE
784 BASIC_CFLAGS += -DNO_TRUSTABLE_FILEMODE
785endif
786ifdef NO_IPV6
787 BASIC_CFLAGS += -DNO_IPV6
788endif
789ifdef NO_UINTMAX_T
790 BASIC_CFLAGS += -Duintmax_t=uint32_t
791endif
792ifdef NO_SOCKADDR_STORAGE
793ifdef NO_IPV6
794 BASIC_CFLAGS += -Dsockaddr_storage=sockaddr_in
795else
796 BASIC_CFLAGS += -Dsockaddr_storage=sockaddr_in6
797endif
798endif
799ifdef NO_INET_NTOP
800 LIB_OBJS += $(OUTPUT)compat/inet_ntop.o
801endif
802ifdef NO_INET_PTON
803 LIB_OBJS += $(OUTPUT)compat/inet_pton.o
804endif
805
806ifdef NO_ICONV
807 BASIC_CFLAGS += -DNO_ICONV
808endif
809
810ifdef OLD_ICONV
811 BASIC_CFLAGS += -DOLD_ICONV
812endif
813
814ifdef NO_DEFLATE_BOUND
815 BASIC_CFLAGS += -DNO_DEFLATE_BOUND
816endif
817
818ifdef PPC_SHA1
819 SHA1_HEADER = "ppc/sha1.h"
820 LIB_OBJS += $(OUTPUT)ppc/sha1.o ppc/sha1ppc.o
821else
822ifdef ARM_SHA1
823 SHA1_HEADER = "arm/sha1.h"
824 LIB_OBJS += $(OUTPUT)arm/sha1.o $(OUTPUT)arm/sha1_arm.o
825else
826ifdef MOZILLA_SHA1
827 SHA1_HEADER = "mozilla-sha1/sha1.h"
828 LIB_OBJS += $(OUTPUT)mozilla-sha1/sha1.o
829else
830 SHA1_HEADER = <openssl/sha.h>
831 EXTLIBS += $(LIB_4_CRYPTO)
832endif
833endif
834endif
835ifdef NO_PERL_MAKEMAKER
836 export NO_PERL_MAKEMAKER
837endif
838ifdef NO_HSTRERROR
839 COMPAT_CFLAGS += -DNO_HSTRERROR
840 COMPAT_OBJS += $(OUTPUT)compat/hstrerror.o
841endif
842ifdef NO_MEMMEM
843 COMPAT_CFLAGS += -DNO_MEMMEM
844 COMPAT_OBJS += $(OUTPUT)compat/memmem.o
845endif
846ifdef INTERNAL_QSORT
847 COMPAT_CFLAGS += -DINTERNAL_QSORT
848 COMPAT_OBJS += $(OUTPUT)compat/qsort.o
849endif
850ifdef RUNTIME_PREFIX
851 COMPAT_CFLAGS += -DRUNTIME_PREFIX
852endif
853
854ifdef DIR_HAS_BSD_GROUP_SEMANTICS
855 COMPAT_CFLAGS += -DDIR_HAS_BSD_GROUP_SEMANTICS
856endif
857ifdef NO_EXTERNAL_GREP
858 BASIC_CFLAGS += -DNO_EXTERNAL_GREP
859endif
860
861ifeq ($(PERL_PATH),)
862NO_PERL=NoThanks
863endif
864
865QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir
866QUIET_SUBDIR1 =
867
868ifneq ($(findstring $(MAKEFLAGS),w),w)
869PRINT_DIR = --no-print-directory
870else # "make -w"
871NO_SUBDIR = :
872endif
873
874ifneq ($(findstring $(MAKEFLAGS),s),s) 544ifneq ($(findstring $(MAKEFLAGS),s),s)
875ifndef V 545ifndef V
876 QUIET_CC = @echo ' ' CC $@; 546 QUIET_CC = @echo ' ' CC $@;
877 QUIET_AR = @echo ' ' AR $@; 547 QUIET_AR = @echo ' ' AR $@;
878 QUIET_LINK = @echo ' ' LINK $@; 548 QUIET_LINK = @echo ' ' LINK $@;
879 QUIET_MKDIR = @echo ' ' MKDIR $@; 549 QUIET_MKDIR = @echo ' ' MKDIR $@;
880 QUIET_BUILT_IN = @echo ' ' BUILTIN $@;
881 QUIET_GEN = @echo ' ' GEN $@; 550 QUIET_GEN = @echo ' ' GEN $@;
882 QUIET_SUBDIR0 = +@subdir=
883 QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \
884 $(MAKE) $(PRINT_DIR) -C $$subdir
885 export V
886 export QUIET_GEN
887 export QUIET_BUILT_IN
888endif 551endif
889endif 552endif
890 553
@@ -894,7 +557,6 @@ endif
894 557
895# Shell quote (do not use $(call) to accommodate ancient setups); 558# Shell quote (do not use $(call) to accommodate ancient setups);
896 559
897SHA1_HEADER_SQ = $(subst ','\'',$(SHA1_HEADER))
898ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG)) 560ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG))
899 561
900DESTDIR_SQ = $(subst ','\'',$(DESTDIR)) 562DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
@@ -908,46 +570,36 @@ htmldir_SQ = $(subst ','\'',$(htmldir))
908prefix_SQ = $(subst ','\'',$(prefix)) 570prefix_SQ = $(subst ','\'',$(prefix))
909 571
910SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) 572SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
911PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH))
912 573
913LIBS = -Wl,--whole-archive $(PERFLIBS) -Wl,--no-whole-archive $(EXTLIBS) 574LIBS = -Wl,--whole-archive $(PERFLIBS) -Wl,--no-whole-archive $(EXTLIBS)
914 575
915BASIC_CFLAGS += -DSHA1_HEADER='$(SHA1_HEADER_SQ)' \
916 $(COMPAT_CFLAGS)
917LIB_OBJS += $(COMPAT_OBJS)
918
919ALL_CFLAGS += $(BASIC_CFLAGS) 576ALL_CFLAGS += $(BASIC_CFLAGS)
920ALL_CFLAGS += $(ARCH_CFLAGS) 577ALL_CFLAGS += $(ARCH_CFLAGS)
921ALL_LDFLAGS += $(BASIC_LDFLAGS) 578ALL_LDFLAGS += $(BASIC_LDFLAGS)
922 579
923export TAR INSTALL DESTDIR SHELL_PATH 580export INSTALL SHELL_PATH
924 581
925 582
926### Build rules 583### Build rules
927 584
928SHELL = $(SHELL_PATH) 585SHELL = $(SHELL_PATH)
929 586
930all:: shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) $(OUTPUT)PERF-BUILD-OPTIONS 587all: shell_compatibility_test $(ALL_PROGRAMS) $(LANG_BINDINGS) $(OTHER_PROGRAMS)
931ifneq (,$X)
932 $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) perf$X)), test '$p' -ef '$p$X' || $(RM) '$p';)
933endif
934
935all::
936 588
937please_set_SHELL_PATH_to_a_more_modern_shell: 589please_set_SHELL_PATH_to_a_more_modern_shell:
938 @$$(:) 590 @$$(:)
939 591
940shell_compatibility_test: please_set_SHELL_PATH_to_a_more_modern_shell 592shell_compatibility_test: please_set_SHELL_PATH_to_a_more_modern_shell
941 593
942strip: $(PROGRAMS) $(OUTPUT)perf$X 594strip: $(PROGRAMS) $(OUTPUT)perf
943 $(STRIP) $(STRIP_OPTS) $(PROGRAMS) $(OUTPUT)perf$X 595 $(STRIP) $(STRIP_OPTS) $(PROGRAMS) $(OUTPUT)perf
944 596
945$(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS 597$(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
946 $(QUIET_CC)$(CC) -DPERF_VERSION='"$(PERF_VERSION)"' \ 598 $(QUIET_CC)$(CC) -DPERF_VERSION='"$(PERF_VERSION)"' \
947 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ 599 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
948 $(ALL_CFLAGS) -c $(filter %.c,$^) -o $@ 600 $(ALL_CFLAGS) -c $(filter %.c,$^) -o $@
949 601
950$(OUTPUT)perf$X: $(OUTPUT)perf.o $(BUILTIN_OBJS) $(PERFLIBS) 602$(OUTPUT)perf: $(OUTPUT)perf.o $(BUILTIN_OBJS) $(PERFLIBS)
951 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) $(OUTPUT)perf.o \ 603 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) $(OUTPUT)perf.o \
952 $(BUILTIN_OBJS) $(LIBS) -o $@ 604 $(BUILTIN_OBJS) $(LIBS) -o $@
953 605
@@ -963,39 +615,17 @@ $(OUTPUT)builtin-timechart.o: builtin-timechart.c $(OUTPUT)common-cmds.h $(OUTPU
963 '-DPERF_MAN_PATH="$(mandir_SQ)"' \ 615 '-DPERF_MAN_PATH="$(mandir_SQ)"' \
964 '-DPERF_INFO_PATH="$(infodir_SQ)"' $< 616 '-DPERF_INFO_PATH="$(infodir_SQ)"' $<
965 617
966$(BUILT_INS): $(OUTPUT)perf$X
967 $(QUIET_BUILT_IN)$(RM) $@ && \
968 ln perf$X $@ 2>/dev/null || \
969 ln -s perf$X $@ 2>/dev/null || \
970 cp perf$X $@
971
972$(OUTPUT)common-cmds.h: util/generate-cmdlist.sh command-list.txt 618$(OUTPUT)common-cmds.h: util/generate-cmdlist.sh command-list.txt
973 619
974$(OUTPUT)common-cmds.h: $(wildcard Documentation/perf-*.txt) 620$(OUTPUT)common-cmds.h: $(wildcard Documentation/perf-*.txt)
975 $(QUIET_GEN). util/generate-cmdlist.sh > $@+ && mv $@+ $@ 621 $(QUIET_GEN). util/generate-cmdlist.sh > $@+ && mv $@+ $@
976 622
977$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh 623$(SCRIPTS) : % : %.sh
978 $(QUIET_GEN)$(RM) $(OUTPUT)$@ $(OUTPUT)$@+ && \ 624 $(QUIET_GEN)$(INSTALL) '$@.sh' '$(OUTPUT)$@'
979 sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
980 -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \
981 -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \
982 -e 's/@@PERF_VERSION@@/$(PERF_VERSION)/g' \
983 -e 's/@@NO_CURL@@/$(NO_CURL)/g' \
984 $@.sh > $(OUTPUT)$@+ && \
985 chmod +x $(OUTPUT)$@+ && \
986 mv $(OUTPUT)$@+ $(OUTPUT)$@
987
988configure: configure.ac
989 $(QUIET_GEN)$(RM) $@ $<+ && \
990 sed -e 's/@@PERF_VERSION@@/$(PERF_VERSION)/g' \
991 $< > $<+ && \
992 autoconf -o $@ $<+ && \
993 $(RM) $<+
994 625
995# These can record PERF_VERSION 626# These can record PERF_VERSION
996$(OUTPUT)perf.o perf.spec \ 627$(OUTPUT)perf.o perf.spec \
997 $(patsubst %.sh,%,$(SCRIPT_SH)) \ 628 $(SCRIPTS) \
998 $(patsubst %.perl,%,$(SCRIPT_PERL)) \
999 : $(OUTPUT)PERF-VERSION-FILE 629 : $(OUTPUT)PERF-VERSION-FILE
1000 630
1001$(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS 631$(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS
@@ -1012,9 +642,6 @@ $(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS
1012 '-DPREFIX="$(prefix_SQ)"' \ 642 '-DPREFIX="$(prefix_SQ)"' \
1013 $< 643 $<
1014 644
1015$(OUTPUT)builtin-init-db.o: builtin-init-db.c $(OUTPUT)PERF-CFLAGS
1016 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DDEFAULT_PERF_TEMPLATE_DIR='"$(template_dir_SQ)"' $<
1017
1018$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS 645$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS
1019 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< 646 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
1020 647
@@ -1024,6 +651,9 @@ $(OUTPUT)util/ui/browser.o: util/ui/browser.c $(OUTPUT)PERF-CFLAGS
1024$(OUTPUT)util/ui/browsers/annotate.o: util/ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS 651$(OUTPUT)util/ui/browsers/annotate.o: util/ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS
1025 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 652 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
1026 653
654$(OUTPUT)util/ui/browsers/top.o: util/ui/browsers/top.c $(OUTPUT)PERF-CFLAGS
655 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
656
1027$(OUTPUT)util/ui/browsers/hists.o: util/ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS 657$(OUTPUT)util/ui/browsers/hists.o: util/ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS
1028 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 658 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
1029 659
@@ -1045,12 +675,11 @@ $(OUTPUT)util/scripting-engines/trace-event-python.o: util/scripting-engines/tra
1045$(OUTPUT)scripts/python/Perf-Trace-Util/Context.o: scripts/python/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS 675$(OUTPUT)scripts/python/Perf-Trace-Util/Context.o: scripts/python/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS
1046 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $< 676 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $<
1047 677
1048$(OUTPUT)perf-%$X: %.o $(PERFLIBS) 678$(OUTPUT)perf-%: %.o $(PERFLIBS)
1049 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) 679 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
1050 680
1051$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H) 681$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
1052$(patsubst perf-%$X,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h) 682$(patsubst perf-%,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
1053builtin-revert.o wt-status.o: wt-status.h
1054 683
1055# we compile into subdirectories. if the target directory is not the source directory, they might not exists. So 684# we compile into subdirectories. if the target directory is not the source directory, they might not exists. So
1056# we depend the various files onto their directories. 685# we depend the various files onto their directories.
@@ -1063,6 +692,36 @@ $(sort $(dir $(DIRECTORY_DEPS))):
1063$(LIB_FILE): $(LIB_OBJS) 692$(LIB_FILE): $(LIB_OBJS)
1064 $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS) 693 $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS)
1065 694
695help:
696 @echo 'Perf make targets:'
697 @echo ' doc - make *all* documentation (see below)'
698 @echo ' man - make manpage documentation (access with man <foo>)'
699 @echo ' html - make html documentation'
700 @echo ' info - make GNU info documentation (access with info <foo>)'
701 @echo ' pdf - make pdf documentation'
702 @echo ' TAGS - use etags to make tag information for source browsing'
703 @echo ' tags - use ctags to make tag information for source browsing'
704 @echo ' cscope - use cscope to make interactive browsing database'
705 @echo ''
706 @echo 'Perf install targets:'
707 @echo ' NOTE: documentation build requires asciidoc, xmlto packages to be installed'
708 @echo ' HINT: use "make prefix=<path> <install target>" to install to a particular'
709 @echo ' path like make prefix=/usr/local install install-doc'
710 @echo ' install - install compiled binaries'
711 @echo ' install-doc - install *all* documentation'
712 @echo ' install-man - install manpage documentation'
713 @echo ' install-html - install html documentation'
714 @echo ' install-info - install GNU info documentation'
715 @echo ' install-pdf - install pdf documentation'
716 @echo ''
717 @echo ' quick-install-doc - alias for quick-install-man'
718 @echo ' quick-install-man - install the documentation quickly'
719 @echo ' quick-install-html - install the html documentation quickly'
720 @echo ''
721 @echo 'Perf maintainer targets:'
722 @echo ' distclean - alias to clean'
723 @echo ' clean - clean all binary objects and build output'
724
1066doc: 725doc:
1067 $(MAKE) -C Documentation all 726 $(MAKE) -C Documentation all
1068 727
@@ -1101,30 +760,12 @@ $(OUTPUT)PERF-CFLAGS: .FORCE-PERF-CFLAGS
1101 echo "$$FLAGS" >$(OUTPUT)PERF-CFLAGS; \ 760 echo "$$FLAGS" >$(OUTPUT)PERF-CFLAGS; \
1102 fi 761 fi
1103 762
1104# We need to apply sq twice, once to protect from the shell
1105# that runs $(OUTPUT)PERF-BUILD-OPTIONS, and then again to protect it
1106# and the first level quoting from the shell that runs "echo".
1107$(OUTPUT)PERF-BUILD-OPTIONS: .FORCE-PERF-BUILD-OPTIONS
1108 @echo SHELL_PATH=\''$(subst ','\'',$(SHELL_PATH_SQ))'\' >$@
1109 @echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@
1110 @echo NO_CURL=\''$(subst ','\'',$(subst ','\'',$(NO_CURL)))'\' >>$@
1111 @echo NO_PERL=\''$(subst ','\'',$(subst ','\'',$(NO_PERL)))'\' >>$@
1112
1113### Testing rules 763### Testing rules
1114 764
1115#
1116# None right now:
1117#
1118# TEST_PROGRAMS += test-something$X
1119
1120all:: $(TEST_PROGRAMS)
1121
1122# GNU make supports exporting all variables by "export" without parameters. 765# GNU make supports exporting all variables by "export" without parameters.
1123# However, the environment gets quite big, and some programs have problems 766# However, the environment gets quite big, and some programs have problems
1124# with that. 767# with that.
1125 768
1126export NO_SVN_TESTS
1127
1128check: $(OUTPUT)common-cmds.h 769check: $(OUTPUT)common-cmds.h
1129 if sparse; \ 770 if sparse; \
1130 then \ 771 then \
@@ -1133,33 +774,21 @@ check: $(OUTPUT)common-cmds.h
1133 sparse $(ALL_CFLAGS) $(SPARSE_FLAGS) $$i || exit; \ 774 sparse $(ALL_CFLAGS) $(SPARSE_FLAGS) $$i || exit; \
1134 done; \ 775 done; \
1135 else \ 776 else \
1136 echo 2>&1 "Did you mean 'make test'?"; \
1137 exit 1; \ 777 exit 1; \
1138 fi 778 fi
1139 779
1140remove-dashes:
1141 ./fixup-builtins $(BUILT_INS) $(PROGRAMS) $(SCRIPTS)
1142
1143### Installation rules 780### Installation rules
1144 781
1145ifneq ($(filter /%,$(firstword $(template_dir))),)
1146template_instdir = $(template_dir)
1147else
1148template_instdir = $(prefix)/$(template_dir)
1149endif
1150export template_instdir
1151
1152ifneq ($(filter /%,$(firstword $(perfexecdir))),) 782ifneq ($(filter /%,$(firstword $(perfexecdir))),)
1153perfexec_instdir = $(perfexecdir) 783perfexec_instdir = $(perfexecdir)
1154else 784else
1155perfexec_instdir = $(prefix)/$(perfexecdir) 785perfexec_instdir = $(prefix)/$(perfexecdir)
1156endif 786endif
1157perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir)) 787perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir))
1158export perfexec_instdir
1159 788
1160install: all 789install: all
1161 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' 790 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
1162 $(INSTALL) $(OUTPUT)perf$X '$(DESTDIR_SQ)$(bindir_SQ)' 791 $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)'
1163 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace' 792 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
1164 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin' 793 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
1165 $(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' 794 $(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
@@ -1172,14 +801,6 @@ install: all
1172 $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python' 801 $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python'
1173 $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin' 802 $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
1174 803
1175ifdef BUILT_INS
1176 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
1177 $(INSTALL) $(BUILT_INS) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
1178ifneq (,$X)
1179 $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) $(OUTPUT)perf$X)), $(RM) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/$p';)
1180endif
1181endif
1182
1183install-doc: 804install-doc:
1184 $(MAKE) -C Documentation install 805 $(MAKE) -C Documentation install
1185 806
@@ -1204,104 +825,17 @@ quick-install-man:
1204quick-install-html: 825quick-install-html:
1205 $(MAKE) -C Documentation quick-install-html 826 $(MAKE) -C Documentation quick-install-html
1206 827
1207
1208### Maintainer's dist rules
1209#
1210# None right now
1211#
1212#
1213# perf.spec: perf.spec.in
1214# sed -e 's/@@VERSION@@/$(PERF_VERSION)/g' < $< > $@+
1215# mv $@+ $@
1216#
1217# PERF_TARNAME=perf-$(PERF_VERSION)
1218# dist: perf.spec perf-archive$(X) configure
1219# ./perf-archive --format=tar \
1220# --prefix=$(PERF_TARNAME)/ HEAD^{tree} > $(PERF_TARNAME).tar
1221# @mkdir -p $(PERF_TARNAME)
1222# @cp perf.spec configure $(PERF_TARNAME)
1223# @echo $(PERF_VERSION) > $(PERF_TARNAME)/version
1224# $(TAR) rf $(PERF_TARNAME).tar \
1225# $(PERF_TARNAME)/perf.spec \
1226# $(PERF_TARNAME)/configure \
1227# $(PERF_TARNAME)/version
1228# @$(RM) -r $(PERF_TARNAME)
1229# gzip -f -9 $(PERF_TARNAME).tar
1230#
1231# htmldocs = perf-htmldocs-$(PERF_VERSION)
1232# manpages = perf-manpages-$(PERF_VERSION)
1233# dist-doc:
1234# $(RM) -r .doc-tmp-dir
1235# mkdir .doc-tmp-dir
1236# $(MAKE) -C Documentation WEBDOC_DEST=../.doc-tmp-dir install-webdoc
1237# cd .doc-tmp-dir && $(TAR) cf ../$(htmldocs).tar .
1238# gzip -n -9 -f $(htmldocs).tar
1239# :
1240# $(RM) -r .doc-tmp-dir
1241# mkdir -p .doc-tmp-dir/man1 .doc-tmp-dir/man5 .doc-tmp-dir/man7
1242# $(MAKE) -C Documentation DESTDIR=./ \
1243# man1dir=../.doc-tmp-dir/man1 \
1244# man5dir=../.doc-tmp-dir/man5 \
1245# man7dir=../.doc-tmp-dir/man7 \
1246# install
1247# cd .doc-tmp-dir && $(TAR) cf ../$(manpages).tar .
1248# gzip -n -9 -f $(manpages).tar
1249# $(RM) -r .doc-tmp-dir
1250#
1251# rpm: dist
1252# $(RPMBUILD) -ta $(PERF_TARNAME).tar.gz
1253
1254### Cleaning rules 828### Cleaning rules
1255 829
1256distclean: clean
1257# $(RM) configure
1258
1259clean: 830clean:
1260 $(RM) *.o */*.o */*/*.o */*/*/*.o $(LIB_FILE) 831 $(RM) $(OUTPUT){*.o,*/*.o,*/*/*.o,*/*/*/*.o,$(LIB_FILE),perf-archive}
1261 $(RM) $(ALL_PROGRAMS) $(BUILT_INS) perf$X 832 $(RM) $(ALL_PROGRAMS) perf
1262 $(RM) $(TEST_PROGRAMS)
1263 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* 833 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope*
1264 $(RM) -r autom4te.cache
1265 $(RM) config.log config.mak.autogen config.mak.append config.status config.cache
1266 $(RM) -r $(PERF_TARNAME) .doc-tmp-dir
1267 $(RM) $(PERF_TARNAME).tar.gz perf-core_$(PERF_VERSION)-*.tar.gz
1268 $(RM) $(htmldocs).tar.gz $(manpages).tar.gz
1269 $(MAKE) -C Documentation/ clean 834 $(MAKE) -C Documentation/ clean
1270 $(RM) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS $(OUTPUT)PERF-BUILD-OPTIONS 835 $(RM) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS
836 @python util/setup.py clean --build-lib='$(OUTPUT)python' \
837 --build-temp='$(OUTPUT)python/temp'
1271 838
1272.PHONY: all install clean strip 839.PHONY: all install clean strip
1273.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell 840.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
1274.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS 841.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS
1275.PHONY: .FORCE-PERF-BUILD-OPTIONS
1276
1277### Make sure built-ins do not have dups and listed in perf.c
1278#
1279check-builtins::
1280 ./check-builtins.sh
1281
1282### Test suite coverage testing
1283#
1284# None right now
1285#
1286# .PHONY: coverage coverage-clean coverage-build coverage-report
1287#
1288# coverage:
1289# $(MAKE) coverage-build
1290# $(MAKE) coverage-report
1291#
1292# coverage-clean:
1293# rm -f *.gcda *.gcno
1294#
1295# COVERAGE_CFLAGS = $(CFLAGS) -O0 -ftest-coverage -fprofile-arcs
1296# COVERAGE_LDFLAGS = $(CFLAGS) -O0 -lgcov
1297#
1298# coverage-build: coverage-clean
1299# $(MAKE) CFLAGS="$(COVERAGE_CFLAGS)" LDFLAGS="$(COVERAGE_LDFLAGS)" all
1300# $(MAKE) CFLAGS="$(COVERAGE_CFLAGS)" LDFLAGS="$(COVERAGE_LDFLAGS)" \
1301# -j1 test
1302#
1303# coverage-report:
1304# gcov -b *.c */*.c
1305# grep '^function.*called 0 ' *.c.gcov */*.c.gcov \
1306# | sed -e 's/\([^:]*\)\.gcov: *function \([^ ]*\) called.*/\1: \2/' \
1307# | tee coverage-untested-functions
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 8879463807e4..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 sample_data *sample, 81static int process_sample_event(union perf_event *event,
82 struct perf_sample *sample,
83 struct perf_evsel *evsel,
62 struct perf_session *session) 84 struct perf_session *session)
63{ 85{
64 struct addr_location al; 86 struct addr_location al;
65 87
66 if (event__preprocess_sample(event, session, &al, sample, 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 sample_data *sample,
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 %016" PRIx64, 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("%*" PRIx64 ": %" PRIu64 "\n", BITS_PER_LONG / 2,
274 sym->start + offset, h->ip[offset]);
275 printf("%*s: %" PRIu64 "\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,24 +146,24 @@ 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,
378 .ordered_samples = true, 167 .ordered_samples = true,
379 .ordering_requires_timestamps = true, 168 .ordering_requires_timestamps = true,
380}; 169};
@@ -383,6 +172,8 @@ static int __cmd_annotate(void)
383{ 172{
384 int ret; 173 int ret;
385 struct perf_session *session; 174 struct perf_session *session;
175 struct perf_evsel *pos;
176 u64 total_nr_samples;
386 177
387 session = perf_session__new(input_name, O_RDONLY, force, false, &event_ops); 178 session = perf_session__new(input_name, O_RDONLY, force, false, &event_ops);
388 if (session == NULL) 179 if (session == NULL)
@@ -403,12 +194,36 @@ static int __cmd_annotate(void)
403 if (verbose > 2) 194 if (verbose > 2)
404 perf_session__fprintf_dsos(session, stdout); 195 perf_session__fprintf_dsos(session, stdout);
405 196
406 hists__collapse_resort(&session->hists); 197 total_nr_samples = 0;
407 hists__output_resort(&session->hists); 198 list_for_each_entry(pos, &session->evlist->entries, node) {
408 hists__find_annotations(&session->hists); 199 struct hists *hists = &pos->hists;
409out_delete: 200 u32 nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
410 perf_session__delete(session);
411 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 */
412 return ret; 227 return ret;
413} 228}
414 229
@@ -451,9 +266,9 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used)
451 else if (use_tui) 266 else if (use_tui)
452 use_browser = 1; 267 use_browser = 1;
453 268
454 setup_browser(); 269 setup_browser(true);
455 270
456 symbol_conf.priv_size = sizeof(struct sym_priv); 271 symbol_conf.priv_size = sizeof(struct annotation);
457 symbol_conf.try_vmlinux_path = true; 272 symbol_conf.try_vmlinux_path = true;
458 273
459 if (symbol__init() < 0) 274 if (symbol__init() < 0)
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 3153e492dbcc..e8219990f8b8 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -30,13 +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, 33static int diff__process_sample_event(union perf_event *event,
34 struct sample_data *sample, 34 struct perf_sample *sample,
35 struct perf_evsel *evsel __used,
35 struct perf_session *session) 36 struct perf_session *session)
36{ 37{
37 struct addr_location al; 38 struct addr_location al;
38 39
39 if (event__preprocess_sample(event, session, &al, sample, NULL) < 0) { 40 if (perf_event__preprocess_sample(event, session, &al, sample, NULL) < 0) {
40 pr_warning("problem processing %d event, skipping it.\n", 41 pr_warning("problem processing %d event, skipping it.\n",
41 event->header.type); 42 event->header.type);
42 return -1; 43 return -1;
@@ -56,11 +57,11 @@ static int diff__process_sample_event(event_t *event,
56 57
57static struct perf_event_ops event_ops = { 58static struct perf_event_ops event_ops = {
58 .sample = diff__process_sample_event, 59 .sample = diff__process_sample_event,
59 .mmap = event__process_mmap, 60 .mmap = perf_event__process_mmap,
60 .comm = event__process_comm, 61 .comm = perf_event__process_comm,
61 .exit = event__process_task, 62 .exit = perf_event__process_task,
62 .fork = event__process_task, 63 .fork = perf_event__process_task,
63 .lost = event__process_lost, 64 .lost = perf_event__process_lost,
64 .ordered_samples = true, 65 .ordered_samples = true,
65 .ordering_requires_timestamps = true, 66 .ordering_requires_timestamps = true,
66}; 67};
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 0c78ffa7bf67..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_synth(event_t *event, 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,41 +36,52 @@ static int event__repipe_synth(event_t *event,
36 return 0; 36 return 0;
37} 37}
38 38
39static int event__repipe(event_t *event, struct sample_data *sample __used, 39static int perf_event__repipe(union perf_event *event,
40 struct perf_session *session) 40 struct perf_sample *sample __used,
41 struct perf_session *session)
41{ 42{
42 return event__repipe_synth(event, session); 43 return perf_event__repipe_synth(event, session);
43} 44}
44 45
45static int event__repipe_mmap(event_t *self, struct sample_data *sample, 46static int perf_event__repipe_sample(union perf_event *event,
47 struct perf_sample *sample __used,
48 struct perf_evsel *evsel __used,
46 struct perf_session *session) 49 struct perf_session *session)
47{ 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)
57{
48 int err; 58 int err;
49 59
50 err = event__process_mmap(self, sample, session); 60 err = perf_event__process_mmap(event, sample, session);
51 event__repipe(self, sample, session); 61 perf_event__repipe(event, sample, session);
52 62
53 return err; 63 return err;
54} 64}
55 65
56static int event__repipe_task(event_t *self, struct sample_data *sample, 66static int perf_event__repipe_task(union perf_event *event,
57 struct perf_session *session) 67 struct perf_sample *sample,
68 struct perf_session *session)
58{ 69{
59 int err; 70 int err;
60 71
61 err = event__process_task(self, sample, session); 72 err = perf_event__process_task(event, sample, session);
62 event__repipe(self, sample, session); 73 perf_event__repipe(event, sample, session);
63 74
64 return err; 75 return err;
65} 76}
66 77
67static int event__repipe_tracing_data(event_t *self, 78static int perf_event__repipe_tracing_data(union perf_event *event,
68 struct perf_session *session) 79 struct perf_session *session)
69{ 80{
70 int err; 81 int err;
71 82
72 event__repipe_synth(self, session); 83 perf_event__repipe_synth(event, session);
73 err = event__process_tracing_data(self, session); 84 err = perf_event__process_tracing_data(event, session);
74 85
75 return err; 86 return err;
76} 87}
@@ -109,8 +120,8 @@ static int dso__inject_build_id(struct dso *self, struct perf_session *session)
109 if (self->kernel) 120 if (self->kernel)
110 misc = PERF_RECORD_MISC_KERNEL; 121 misc = PERF_RECORD_MISC_KERNEL;
111 122
112 err = event__synthesize_build_id(self, misc, event__repipe, 123 err = perf_event__synthesize_build_id(self, misc, perf_event__repipe,
113 machine, session); 124 machine, session);
114 if (err) { 125 if (err) {
115 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);
116 return -1; 127 return -1;
@@ -119,8 +130,10 @@ static int dso__inject_build_id(struct dso *self, struct perf_session *session)
119 return 0; 130 return 0;
120} 131}
121 132
122static int event__inject_buildid(event_t *event, struct sample_data *sample, 133static int perf_event__inject_buildid(union perf_event *event,
123 struct perf_session *session) 134 struct perf_sample *sample,
135 struct perf_evsel *evsel __used,
136 struct perf_session *session)
124{ 137{
125 struct addr_location al; 138 struct addr_location al;
126 struct thread *thread; 139 struct thread *thread;
@@ -155,24 +168,24 @@ static int event__inject_buildid(event_t *event, struct sample_data *sample,
155 } 168 }
156 169
157repipe: 170repipe:
158 event__repipe(event, sample, session); 171 perf_event__repipe(event, sample, session);
159 return 0; 172 return 0;
160} 173}
161 174
162struct perf_event_ops inject_ops = { 175struct perf_event_ops inject_ops = {
163 .sample = event__repipe, 176 .sample = perf_event__repipe_sample,
164 .mmap = event__repipe, 177 .mmap = perf_event__repipe,
165 .comm = event__repipe, 178 .comm = perf_event__repipe,
166 .fork = event__repipe, 179 .fork = perf_event__repipe,
167 .exit = event__repipe, 180 .exit = perf_event__repipe,
168 .lost = event__repipe, 181 .lost = perf_event__repipe,
169 .read = event__repipe, 182 .read = perf_event__repipe,
170 .throttle = event__repipe, 183 .throttle = perf_event__repipe,
171 .unthrottle = event__repipe, 184 .unthrottle = perf_event__repipe,
172 .attr = event__repipe_synth, 185 .attr = perf_event__repipe_synth,
173 .event_type = event__repipe_synth, 186 .event_type = perf_event__repipe_synth,
174 .tracing_data = event__repipe_synth, 187 .tracing_data = perf_event__repipe_synth,
175 .build_id = event__repipe_synth, 188 .build_id = perf_event__repipe_synth,
176}; 189};
177 190
178extern volatile int session_done; 191extern volatile int session_done;
@@ -190,10 +203,10 @@ static int __cmd_inject(void)
190 signal(SIGINT, sig_handler); 203 signal(SIGINT, sig_handler);
191 204
192 if (inject_build_ids) { 205 if (inject_build_ids) {
193 inject_ops.sample = event__inject_buildid; 206 inject_ops.sample = perf_event__inject_buildid;
194 inject_ops.mmap = event__repipe_mmap; 207 inject_ops.mmap = perf_event__repipe_mmap;
195 inject_ops.fork = event__repipe_task; 208 inject_ops.fork = perf_event__repipe_task;
196 inject_ops.tracing_data = event__repipe_tracing_data; 209 inject_ops.tracing_data = perf_event__repipe_tracing_data;
197 } 210 }
198 211
199 session = perf_session__new(input_name, O_RDONLY, false, true, &inject_ops); 212 session = perf_session__new(input_name, O_RDONLY, false, true, &inject_ops);
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index d97256d65980..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,7 +303,9 @@ 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 sample_data *sample, 306static int process_sample_event(union perf_event *event,
307 struct perf_sample *sample,
308 struct perf_evsel *evsel __used,
308 struct perf_session *session) 309 struct perf_session *session)
309{ 310{
310 struct thread *thread = perf_session__findnew(session, event->ip.pid); 311 struct thread *thread = perf_session__findnew(session, event->ip.pid);
@@ -325,7 +326,7 @@ static int process_sample_event(event_t *event, struct sample_data *sample,
325 326
326static struct perf_event_ops event_ops = { 327static struct perf_event_ops event_ops = {
327 .sample = process_sample_event, 328 .sample = process_sample_event,
328 .comm = event__process_comm, 329 .comm = perf_event__process_comm,
329 .ordered_samples = true, 330 .ordered_samples = true,
330}; 331};
331 332
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 2b36defc5d73..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
@@ -834,14 +845,16 @@ 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 sample_data *sample, 848static int process_sample_event(union perf_event *event,
849 struct perf_sample *sample,
850 struct perf_evsel *evsel __used,
838 struct perf_session *s) 851 struct perf_session *s)
839{ 852{
840 struct thread *thread = perf_session__findnew(s, sample->tid); 853 struct thread *thread = perf_session__findnew(s, sample->tid);
841 854
842 if (thread == NULL) { 855 if (thread == NULL) {
843 pr_debug("problem processing %d event, skipping it.\n", 856 pr_debug("problem processing %d event, skipping it.\n",
844 self->header.type); 857 event->header.type);
845 return -1; 858 return -1;
846 } 859 }
847 860
@@ -852,7 +865,7 @@ static int process_sample_event(event_t *self, struct sample_data *sample,
852 865
853static struct perf_event_ops eops = { 866static struct perf_event_ops eops = {
854 .sample = process_sample_event, 867 .sample = process_sample_event,
855 .comm = event__process_comm, 868 .comm = perf_event__process_comm,
856 .ordered_samples = true, 869 .ordered_samples = true,
857}; 870};
858 871
@@ -893,7 +906,7 @@ static const char * const report_usage[] = {
893 906
894static const struct option report_options[] = { 907static const struct option report_options[] = {
895 OPT_STRING('k', "key", &sort_key, "acquired", 908 OPT_STRING('k', "key", &sort_key, "acquired",
896 "key for sorting"), 909 "key for sorting (acquired / contended / wait_total / wait_max / wait_min)"),
897 /* TODO: type */ 910 /* TODO: type */
898 OPT_END() 911 OPT_END()
899}; 912};
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index add163c9f0e7..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,7 +279,7 @@ 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
252 /* 285 /*
@@ -267,12 +300,41 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
267 pr_err(" Error: Don't use --list with --vars.\n"); 300 pr_err(" Error: Don't use --list with --vars.\n");
268 usage_with_options(probe_usage, options); 301 usage_with_options(probe_usage, options);
269 } 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 }
270 ret = show_perf_probe_events(); 307 ret = show_perf_probe_events();
271 if (ret < 0) 308 if (ret < 0)
272 pr_err(" Error: Failed to show event list. (%d)\n", 309 pr_err(" Error: Failed to show event list. (%d)\n",
273 ret); 310 ret);
274 return ret; 311 return ret;
275 } 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 }
276 338
277#ifdef DWARF_SUPPORT 339#ifdef DWARF_SUPPORT
278 if (params.show_lines) { 340 if (params.show_lines) {
@@ -297,10 +359,16 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
297 " --add/--del.\n"); 359 " --add/--del.\n");
298 usage_with_options(probe_usage, options); 360 usage_with_options(probe_usage, options);
299 } 361 }
362 if (!params.filter)
363 params.filter = strfilter__new(DEFAULT_VAR_FILTER,
364 NULL);
365
300 ret = show_available_vars(params.events, params.nevents, 366 ret = show_available_vars(params.events, params.nevents,
301 params.max_probe_points, 367 params.max_probe_points,
302 params.target_module, 368 params.target_module,
369 params.filter,
303 params.show_ext_vars); 370 params.show_ext_vars);
371 strfilter__delete(params.filter);
304 if (ret < 0) 372 if (ret < 0)
305 pr_err(" Error: Failed to show vars. (%d)\n", ret); 373 pr_err(" Error: Failed to show vars. (%d)\n", ret);
306 return ret; 374 return ret;
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index b2f729fdb317..17d1dcb3c667 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -18,11 +18,13 @@
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"
21#include "util/evsel.h" 22#include "util/evsel.h"
22#include "util/debug.h" 23#include "util/debug.h"
23#include "util/session.h" 24#include "util/session.h"
24#include "util/symbol.h" 25#include "util/symbol.h"
25#include "util/cpumap.h" 26#include "util/cpumap.h"
27#include "util/thread_map.h"
26 28
27#include <unistd.h> 29#include <unistd.h>
28#include <sched.h> 30#include <sched.h>
@@ -37,16 +39,14 @@ enum write_mode_t {
37 39
38static u64 user_interval = ULLONG_MAX; 40static u64 user_interval = ULLONG_MAX;
39static u64 default_interval = 0; 41static u64 default_interval = 0;
40static u64 sample_type;
41 42
42static struct cpu_map *cpus;
43static unsigned int page_size; 43static unsigned int page_size;
44static unsigned int mmap_pages = 128; 44static unsigned int mmap_pages = UINT_MAX;
45static unsigned int user_freq = UINT_MAX; 45static unsigned int user_freq = UINT_MAX;
46static int freq = 1000; 46static int freq = 1000;
47static int output; 47static int output;
48static int pipe_output = 0; 48static int pipe_output = 0;
49static const char *output_name = "perf.data"; 49static const char *output_name = NULL;
50static int group = 0; 50static int group = 0;
51static int realtime_prio = 0; 51static int realtime_prio = 0;
52static bool nodelay = false; 52static bool nodelay = false;
@@ -55,7 +55,6 @@ static bool sample_id_all_avail = true;
55static bool system_wide = false; 55static bool system_wide = false;
56static pid_t target_pid = -1; 56static pid_t target_pid = -1;
57static pid_t target_tid = -1; 57static pid_t target_tid = -1;
58static struct thread_map *threads;
59static pid_t child_pid = -1; 58static pid_t child_pid = -1;
60static bool no_inherit = false; 59static bool no_inherit = false;
61static enum write_mode_t write_mode = WRITE_FORCE; 60static enum write_mode_t write_mode = WRITE_FORCE;
@@ -66,51 +65,17 @@ static bool sample_address = false;
66static bool sample_time = false; 65static bool sample_time = false;
67static bool no_buildid = false; 66static bool no_buildid = false;
68static bool no_buildid_cache = false; 67static bool no_buildid_cache = false;
68static struct perf_evlist *evsel_list;
69 69
70static long samples = 0; 70static long samples = 0;
71static u64 bytes_written = 0; 71static u64 bytes_written = 0;
72 72
73static struct pollfd *event_array;
74
75static int nr_poll = 0;
76static int nr_cpu = 0;
77
78static int file_new = 1; 73static int file_new = 1;
79static off_t post_processing_offset; 74static off_t post_processing_offset;
80 75
81static struct perf_session *session; 76static struct perf_session *session;
82static const char *cpu_list; 77static const char *cpu_list;
83 78
84struct mmap_data {
85 void *base;
86 unsigned int mask;
87 unsigned int prev;
88};
89
90static struct mmap_data mmap_array[MAX_NR_CPUS];
91
92static unsigned long mmap_read_head(struct mmap_data *md)
93{
94 struct perf_event_mmap_page *pc = md->base;
95 long head;
96
97 head = pc->data_head;
98 rmb();
99
100 return head;
101}
102
103static void mmap_write_tail(struct mmap_data *md, unsigned long tail)
104{
105 struct perf_event_mmap_page *pc = md->base;
106
107 /*
108 * ensure all reads are done before we write the tail out.
109 */
110 /* mb(); */
111 pc->data_tail = tail;
112}
113
114static void advance_output(size_t size) 79static void advance_output(size_t size)
115{ 80{
116 bytes_written += size; 81 bytes_written += size;
@@ -131,42 +96,26 @@ static void write_output(void *buf, size_t size)
131 } 96 }
132} 97}
133 98
134static int process_synthesized_event(event_t *event, 99static int process_synthesized_event(union perf_event *event,
135 struct sample_data *sample __used, 100 struct perf_sample *sample __used,
136 struct perf_session *self __used) 101 struct perf_session *self __used)
137{ 102{
138 write_output(event, event->header.size); 103 write_output(event, event->header.size);
139 return 0; 104 return 0;
140} 105}
141 106
142static void mmap_read(struct mmap_data *md) 107static void mmap_read(struct perf_mmap *md)
143{ 108{
144 unsigned int head = mmap_read_head(md); 109 unsigned int head = perf_mmap__read_head(md);
145 unsigned int old = md->prev; 110 unsigned int old = md->prev;
146 unsigned char *data = md->base + page_size; 111 unsigned char *data = md->base + page_size;
147 unsigned long size; 112 unsigned long size;
148 void *buf; 113 void *buf;
149 int diff;
150 114
151 /* 115 if (old == head)
152 * If we're further behind than half the buffer, there's a chance 116 return;
153 * the writer will bite our tail and mess up the samples under us.
154 *
155 * If we somehow ended up ahead of the head, we got messed up.
156 *
157 * In either case, truncate and restart at head.
158 */
159 diff = head - old;
160 if (diff < 0) {
161 fprintf(stderr, "WARNING: failed to keep up with mmap data\n");
162 /*
163 * head points to a known good entry, start there.
164 */
165 old = head;
166 }
167 117
168 if (old != head) 118 samples++;
169 samples++;
170 119
171 size = head - old; 120 size = head - old;
172 121
@@ -185,7 +134,7 @@ static void mmap_read(struct mmap_data *md)
185 write_output(buf, size); 134 write_output(buf, size);
186 135
187 md->prev = old; 136 md->prev = old;
188 mmap_write_tail(md, old); 137 perf_mmap__write_tail(md, old);
189} 138}
190 139
191static volatile int done = 0; 140static volatile int done = 0;
@@ -209,53 +158,10 @@ static void sig_atexit(void)
209 kill(getpid(), signr); 158 kill(getpid(), signr);
210} 159}
211 160
212static int group_fd; 161static void config_attr(struct perf_evsel *evsel, struct perf_evlist *evlist)
213
214static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr)
215{ 162{
216 struct perf_header_attr *h_attr;
217
218 if (nr < session->header.attrs) {
219 h_attr = session->header.attr[nr];
220 } else {
221 h_attr = perf_header_attr__new(a);
222 if (h_attr != NULL)
223 if (perf_header__add_attr(&session->header, h_attr) < 0) {
224 perf_header_attr__delete(h_attr);
225 h_attr = NULL;
226 }
227 }
228
229 return h_attr;
230}
231
232static void create_counter(struct perf_evsel *evsel, int cpu)
233{
234 char *filter = evsel->filter;
235 struct perf_event_attr *attr = &evsel->attr; 163 struct perf_event_attr *attr = &evsel->attr;
236 struct perf_header_attr *h_attr;
237 int track = !evsel->idx; /* only the first counter needs these */ 164 int track = !evsel->idx; /* only the first counter needs these */
238 int thread_index;
239 int ret;
240 struct {
241 u64 count;
242 u64 time_enabled;
243 u64 time_running;
244 u64 id;
245 } read_data;
246 /*
247 * Check if parse_single_tracepoint_event has already asked for
248 * PERF_SAMPLE_TIME.
249 *
250 * XXX this is kludgy but short term fix for problems introduced by
251 * eac23d1c that broke 'perf script' by having different sample_types
252 * when using multiple tracepoint events when we use a perf binary
253 * that tries to use sample_id_all on an older kernel.
254 *
255 * We need to move counter creation to perf_session, support
256 * different sample_types, etc.
257 */
258 bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
259 165
260 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | 166 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
261 PERF_FORMAT_TOTAL_TIME_RUNNING | 167 PERF_FORMAT_TOTAL_TIME_RUNNING |
@@ -263,7 +169,7 @@ static void create_counter(struct perf_evsel *evsel, int cpu)
263 169
264 attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID; 170 attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID;
265 171
266 if (nr_counters > 1) 172 if (evlist->nr_entries > 1)
267 attr->sample_type |= PERF_SAMPLE_ID; 173 attr->sample_type |= PERF_SAMPLE_ID;
268 174
269 /* 175 /*
@@ -315,26 +221,64 @@ static void create_counter(struct perf_evsel *evsel, int cpu)
315 221
316 attr->mmap = track; 222 attr->mmap = track;
317 attr->comm = track; 223 attr->comm = track;
318 attr->inherit = !no_inherit; 224
319 if (target_pid == -1 && target_tid == -1 && !system_wide) { 225 if (target_pid == -1 && target_tid == -1 && !system_wide) {
320 attr->disabled = 1; 226 attr->disabled = 1;
321 attr->enable_on_exec = 1; 227 attr->enable_on_exec = 1;
322 } 228 }
323retry_sample_id: 229}
324 attr->sample_id_all = sample_id_all_avail ? 1 : 0;
325 230
326 for (thread_index = 0; thread_index < threads->nr; thread_index++) { 231static bool perf_evlist__equal(struct perf_evlist *evlist,
327try_again: 232 struct perf_evlist *other)
328 FD(evsel, nr_cpu, thread_index) = sys_perf_event_open(attr, threads->map[thread_index], cpu, group_fd, 0); 233{
234 struct perf_evsel *pos, *pair;
235
236 if (evlist->nr_entries != other->nr_entries)
237 return false;
238
239 pair = list_entry(other->entries.next, struct perf_evsel, node);
240
241 list_for_each_entry(pos, &evlist->entries, node) {
242 if (memcmp(&pos->attr, &pair->attr, sizeof(pos->attr) != 0))
243 return false;
244 pair = list_entry(pair->node.next, struct perf_evsel, node);
245 }
246
247 return true;
248}
329 249
330 if (FD(evsel, nr_cpu, thread_index) < 0) { 250static void open_counters(struct perf_evlist *evlist)
251{
252 struct perf_evsel *pos;
253
254 list_for_each_entry(pos, &evlist->entries, node) {
255 struct perf_event_attr *attr = &pos->attr;
256 /*
257 * Check if parse_single_tracepoint_event has already asked for
258 * PERF_SAMPLE_TIME.
259 *
260 * XXX this is kludgy but short term fix for problems introduced by
261 * eac23d1c that broke 'perf script' by having different sample_types
262 * when using multiple tracepoint events when we use a perf binary
263 * that tries to use sample_id_all on an older kernel.
264 *
265 * We need to move counter creation to perf_session, support
266 * different sample_types, etc.
267 */
268 bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
269
270 config_attr(pos, evlist);
271retry_sample_id:
272 attr->sample_id_all = sample_id_all_avail ? 1 : 0;
273try_again:
274 if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group,
275 !no_inherit) < 0) {
331 int err = errno; 276 int err = errno;
332 277
333 if (err == EPERM || err == EACCES) 278 if (err == EPERM || err == EACCES) {
334 die("Permission error - are you root?\n" 279 ui__warning_paranoid();
335 "\t Consider tweaking" 280 exit(EXIT_FAILURE);
336 " /proc/sys/kernel/perf_event_paranoid.\n"); 281 } else if (err == ENODEV && cpu_list) {
337 else if (err == ENODEV && cpu_list) {
338 die("No such device - did you specify" 282 die("No such device - did you specify"
339 " an out-of-range profile CPU?\n"); 283 " an out-of-range profile CPU?\n");
340 } else if (err == EINVAL && sample_id_all_avail) { 284 } else if (err == EINVAL && sample_id_all_avail) {
@@ -357,14 +301,22 @@ try_again:
357 && attr->config == PERF_COUNT_HW_CPU_CYCLES) { 301 && attr->config == PERF_COUNT_HW_CPU_CYCLES) {
358 302
359 if (verbose) 303 if (verbose)
360 warning(" ... trying to fall back to cpu-clock-ticks\n"); 304 ui__warning("The cycles event is not supported, "
305 "trying to fall back to cpu-clock-ticks\n");
361 attr->type = PERF_TYPE_SOFTWARE; 306 attr->type = PERF_TYPE_SOFTWARE;
362 attr->config = PERF_COUNT_SW_CPU_CLOCK; 307 attr->config = PERF_COUNT_SW_CPU_CLOCK;
363 goto try_again; 308 goto try_again;
364 } 309 }
310
311 if (err == ENOENT) {
312 ui__warning("The %s event is not supported.\n",
313 event_name(pos));
314 exit(EXIT_FAILURE);
315 }
316
365 printf("\n"); 317 printf("\n");
366 error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n", 318 error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n",
367 FD(evsel, nr_cpu, thread_index), strerror(err)); 319 err, strerror(err));
368 320
369#if defined(__i386__) || defined(__x86_64__) 321#if defined(__i386__) || defined(__x86_64__)
370 if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP) 322 if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP)
@@ -375,90 +327,28 @@ try_again:
375#endif 327#endif
376 328
377 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); 329 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
378 exit(-1);
379 } 330 }
331 }
380 332
381 h_attr = get_header_attr(attr, evsel->idx); 333 if (perf_evlist__set_filters(evlist)) {
382 if (h_attr == NULL) 334 error("failed to set filter with %d (%s)\n", errno,
383 die("nomem\n"); 335 strerror(errno));
384 336 exit(-1);
385 if (!file_new) { 337 }
386 if (memcmp(&h_attr->attr, attr, sizeof(*attr))) {
387 fprintf(stderr, "incompatible append\n");
388 exit(-1);
389 }
390 }
391 338
392 if (read(FD(evsel, nr_cpu, thread_index), &read_data, sizeof(read_data)) == -1) { 339 if (perf_evlist__mmap(evlist, mmap_pages, false) < 0)
393 perror("Unable to read perf file descriptor"); 340 die("failed to mmap with %d (%s)\n", errno, strerror(errno));
394 exit(-1);
395 }
396 341
397 if (perf_header_attr__add_id(h_attr, read_data.id) < 0) { 342 if (file_new)
398 pr_warning("Not enough memory to add id\n"); 343 session->evlist = evlist;
344 else {
345 if (!perf_evlist__equal(session->evlist, evlist)) {
346 fprintf(stderr, "incompatible append\n");
399 exit(-1); 347 exit(-1);
400 } 348 }
349 }
401 350
402 assert(FD(evsel, nr_cpu, thread_index) >= 0); 351 perf_session__update_sample_type(session);
403 fcntl(FD(evsel, nr_cpu, thread_index), F_SETFL, O_NONBLOCK);
404
405 /*
406 * First counter acts as the group leader:
407 */
408 if (group && group_fd == -1)
409 group_fd = FD(evsel, nr_cpu, thread_index);
410
411 if (evsel->idx || thread_index) {
412 struct perf_evsel *first;
413 first = list_entry(evsel_list.next, struct perf_evsel, node);
414 ret = ioctl(FD(evsel, nr_cpu, thread_index),
415 PERF_EVENT_IOC_SET_OUTPUT,
416 FD(first, nr_cpu, 0));
417 if (ret) {
418 error("failed to set output: %d (%s)\n", errno,
419 strerror(errno));
420 exit(-1);
421 }
422 } else {
423 mmap_array[nr_cpu].prev = 0;
424 mmap_array[nr_cpu].mask = mmap_pages*page_size - 1;
425 mmap_array[nr_cpu].base = mmap(NULL, (mmap_pages+1)*page_size,
426 PROT_READ | PROT_WRITE, MAP_SHARED, FD(evsel, nr_cpu, thread_index), 0);
427 if (mmap_array[nr_cpu].base == MAP_FAILED) {
428 error("failed to mmap with %d (%s)\n", errno, strerror(errno));
429 exit(-1);
430 }
431
432 event_array[nr_poll].fd = FD(evsel, nr_cpu, thread_index);
433 event_array[nr_poll].events = POLLIN;
434 nr_poll++;
435 }
436
437 if (filter != NULL) {
438 ret = ioctl(FD(evsel, nr_cpu, thread_index),
439 PERF_EVENT_IOC_SET_FILTER, filter);
440 if (ret) {
441 error("failed to set filter with %d (%s)\n", errno,
442 strerror(errno));
443 exit(-1);
444 }
445 }
446 }
447
448 if (!sample_type)
449 sample_type = attr->sample_type;
450}
451
452static void open_counters(int cpu)
453{
454 struct perf_evsel *pos;
455
456 group_fd = -1;
457
458 list_for_each_entry(pos, &evsel_list, node)
459 create_counter(pos, cpu);
460
461 nr_cpu++;
462} 352}
463 353
464static int process_buildids(void) 354static int process_buildids(void)
@@ -481,14 +371,14 @@ static void atexit_header(void)
481 371
482 if (!no_buildid) 372 if (!no_buildid)
483 process_buildids(); 373 process_buildids();
484 perf_header__write(&session->header, output, true); 374 perf_session__write_header(session, evsel_list, output, true);
485 perf_session__delete(session); 375 perf_session__delete(session);
486 perf_evsel_list__delete(); 376 perf_evlist__delete(evsel_list);
487 symbol__exit(); 377 symbol__exit();
488 } 378 }
489} 379}
490 380
491static void event__synthesize_guest_os(struct machine *machine, void *data) 381static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
492{ 382{
493 int err; 383 int err;
494 struct perf_session *psession = data; 384 struct perf_session *psession = data;
@@ -504,8 +394,8 @@ static void event__synthesize_guest_os(struct machine *machine, void *data)
504 *method is used to avoid symbol missing when the first addr is 394 *method is used to avoid symbol missing when the first addr is
505 *in module instead of in guest kernel. 395 *in module instead of in guest kernel.
506 */ 396 */
507 err = event__synthesize_modules(process_synthesized_event, 397 err = perf_event__synthesize_modules(process_synthesized_event,
508 psession, machine); 398 psession, machine);
509 if (err < 0) 399 if (err < 0)
510 pr_err("Couldn't record guest kernel [%d]'s reference" 400 pr_err("Couldn't record guest kernel [%d]'s reference"
511 " relocation symbol.\n", machine->pid); 401 " relocation symbol.\n", machine->pid);
@@ -514,11 +404,12 @@ static void event__synthesize_guest_os(struct machine *machine, void *data)
514 * We use _stext for guest kernel because guest kernel's /proc/kallsyms 404 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
515 * have no _text sometimes. 405 * have no _text sometimes.
516 */ 406 */
517 err = event__synthesize_kernel_mmap(process_synthesized_event, 407 err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
518 psession, machine, "_text"); 408 psession, machine, "_text");
519 if (err < 0) 409 if (err < 0)
520 err = event__synthesize_kernel_mmap(process_synthesized_event, 410 err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
521 psession, machine, "_stext"); 411 psession, machine,
412 "_stext");
522 if (err < 0) 413 if (err < 0)
523 pr_err("Couldn't record guest kernel [%d]'s reference" 414 pr_err("Couldn't record guest kernel [%d]'s reference"
524 " relocation symbol.\n", machine->pid); 415 " relocation symbol.\n", machine->pid);
@@ -533,9 +424,9 @@ static void mmap_read_all(void)
533{ 424{
534 int i; 425 int i;
535 426
536 for (i = 0; i < nr_cpu; i++) { 427 for (i = 0; i < evsel_list->cpus->nr; i++) {
537 if (mmap_array[i].base) 428 if (evsel_list->mmap[i].base)
538 mmap_read(&mmap_array[i]); 429 mmap_read(&evsel_list->mmap[i]);
539 } 430 }
540 431
541 if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO)) 432 if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO))
@@ -566,18 +457,26 @@ static int __cmd_record(int argc, const char **argv)
566 exit(-1); 457 exit(-1);
567 } 458 }
568 459
569 if (!strcmp(output_name, "-")) 460 if (!output_name) {
570 pipe_output = 1; 461 if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
571 else if (!stat(output_name, &st) && st.st_size) { 462 pipe_output = 1;
572 if (write_mode == WRITE_FORCE) { 463 else
573 char oldname[PATH_MAX]; 464 output_name = "perf.data";
574 snprintf(oldname, sizeof(oldname), "%s.old", 465 }
575 output_name); 466 if (output_name) {
576 unlink(oldname); 467 if (!strcmp(output_name, "-"))
577 rename(output_name, oldname); 468 pipe_output = 1;
469 else if (!stat(output_name, &st) && st.st_size) {
470 if (write_mode == WRITE_FORCE) {
471 char oldname[PATH_MAX];
472 snprintf(oldname, sizeof(oldname), "%s.old",
473 output_name);
474 unlink(oldname);
475 rename(output_name, oldname);
476 }
477 } else if (write_mode == WRITE_APPEND) {
478 write_mode = WRITE_FORCE;
578 } 479 }
579 } else if (write_mode == WRITE_APPEND) {
580 write_mode = WRITE_FORCE;
581 } 480 }
582 481
583 flags = O_CREAT|O_RDWR; 482 flags = O_CREAT|O_RDWR;
@@ -606,18 +505,17 @@ static int __cmd_record(int argc, const char **argv)
606 perf_header__set_feat(&session->header, HEADER_BUILD_ID); 505 perf_header__set_feat(&session->header, HEADER_BUILD_ID);
607 506
608 if (!file_new) { 507 if (!file_new) {
609 err = perf_header__read(session, output); 508 err = perf_session__read_header(session, output);
610 if (err < 0) 509 if (err < 0)
611 goto out_delete_session; 510 goto out_delete_session;
612 } 511 }
613 512
614 if (have_tracepoints(&evsel_list)) 513 if (have_tracepoints(&evsel_list->entries))
615 perf_header__set_feat(&session->header, HEADER_TRACE_INFO); 514 perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
616 515
617 /* 516 /* 512 kiB: default amount of unprivileged mlocked memory */
618 * perf_session__delete(session) will be called at atexit_header() 517 if (mmap_pages == UINT_MAX)
619 */ 518 mmap_pages = (512 * 1024) / page_size;
620 atexit(atexit_header);
621 519
622 if (forks) { 520 if (forks) {
623 child_pid = fork(); 521 child_pid = fork();
@@ -659,7 +557,7 @@ static int __cmd_record(int argc, const char **argv)
659 } 557 }
660 558
661 if (!system_wide && target_tid == -1 && target_pid == -1) 559 if (!system_wide && target_tid == -1 && target_pid == -1)
662 threads->map[0] = child_pid; 560 evsel_list->threads->map[0] = child_pid;
663 561
664 close(child_ready_pipe[1]); 562 close(child_ready_pipe[1]);
665 close(go_pipe[0]); 563 close(go_pipe[0]);
@@ -673,46 +571,42 @@ static int __cmd_record(int argc, const char **argv)
673 close(child_ready_pipe[0]); 571 close(child_ready_pipe[0]);
674 } 572 }
675 573
676 if (!system_wide && no_inherit && !cpu_list) { 574 open_counters(evsel_list);
677 open_counters(-1);
678 } else {
679 for (i = 0; i < cpus->nr; i++)
680 open_counters(cpus->map[i]);
681 }
682 575
683 perf_session__set_sample_type(session, sample_type); 576 /*
577 * perf_session__delete(session) will be called at atexit_header()
578 */
579 atexit(atexit_header);
684 580
685 if (pipe_output) { 581 if (pipe_output) {
686 err = perf_header__write_pipe(output); 582 err = perf_header__write_pipe(output);
687 if (err < 0) 583 if (err < 0)
688 return err; 584 return err;
689 } else if (file_new) { 585 } else if (file_new) {
690 err = perf_header__write(&session->header, output, false); 586 err = perf_session__write_header(session, evsel_list,
587 output, false);
691 if (err < 0) 588 if (err < 0)
692 return err; 589 return err;
693 } 590 }
694 591
695 post_processing_offset = lseek(output, 0, SEEK_CUR); 592 post_processing_offset = lseek(output, 0, SEEK_CUR);
696 593
697 perf_session__set_sample_id_all(session, sample_id_all_avail);
698
699 if (pipe_output) { 594 if (pipe_output) {
700 err = event__synthesize_attrs(&session->header, 595 err = perf_session__synthesize_attrs(session,
701 process_synthesized_event, 596 process_synthesized_event);
702 session);
703 if (err < 0) { 597 if (err < 0) {
704 pr_err("Couldn't synthesize attrs.\n"); 598 pr_err("Couldn't synthesize attrs.\n");
705 return err; 599 return err;
706 } 600 }
707 601
708 err = event__synthesize_event_types(process_synthesized_event, 602 err = perf_event__synthesize_event_types(process_synthesized_event,
709 session); 603 session);
710 if (err < 0) { 604 if (err < 0) {
711 pr_err("Couldn't synthesize event_types.\n"); 605 pr_err("Couldn't synthesize event_types.\n");
712 return err; 606 return err;
713 } 607 }
714 608
715 if (have_tracepoints(&evsel_list)) { 609 if (have_tracepoints(&evsel_list->entries)) {
716 /* 610 /*
717 * FIXME err <= 0 here actually means that 611 * FIXME err <= 0 here actually means that
718 * there were no tracepoints so its not really 612 * there were no tracepoints so its not really
@@ -721,9 +615,9 @@ static int __cmd_record(int argc, const char **argv)
721 * return this more properly and also 615 * return this more properly and also
722 * propagate errors that now are calling die() 616 * propagate errors that now are calling die()
723 */ 617 */
724 err = event__synthesize_tracing_data(output, &evsel_list, 618 err = perf_event__synthesize_tracing_data(output, evsel_list,
725 process_synthesized_event, 619 process_synthesized_event,
726 session); 620 session);
727 if (err <= 0) { 621 if (err <= 0) {
728 pr_err("Couldn't record tracing data.\n"); 622 pr_err("Couldn't record tracing data.\n");
729 return err; 623 return err;
@@ -738,31 +632,34 @@ static int __cmd_record(int argc, const char **argv)
738 return -1; 632 return -1;
739 } 633 }
740 634
741 err = event__synthesize_kernel_mmap(process_synthesized_event, 635 err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
742 session, machine, "_text"); 636 session, machine, "_text");
743 if (err < 0) 637 if (err < 0)
744 err = event__synthesize_kernel_mmap(process_synthesized_event, 638 err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
745 session, machine, "_stext"); 639 session, machine, "_stext");
746 if (err < 0) 640 if (err < 0)
747 pr_err("Couldn't record kernel reference relocation symbol\n" 641 pr_err("Couldn't record kernel reference relocation symbol\n"
748 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" 642 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
749 "Check /proc/kallsyms permission or run as root.\n"); 643 "Check /proc/kallsyms permission or run as root.\n");
750 644
751 err = event__synthesize_modules(process_synthesized_event, 645 err = perf_event__synthesize_modules(process_synthesized_event,
752 session, machine); 646 session, machine);
753 if (err < 0) 647 if (err < 0)
754 pr_err("Couldn't record kernel module information.\n" 648 pr_err("Couldn't record kernel module information.\n"
755 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" 649 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
756 "Check /proc/modules permission or run as root.\n"); 650 "Check /proc/modules permission or run as root.\n");
757 651
758 if (perf_guest) 652 if (perf_guest)
759 perf_session__process_machines(session, event__synthesize_guest_os); 653 perf_session__process_machines(session,
654 perf_event__synthesize_guest_os);
760 655
761 if (!system_wide) 656 if (!system_wide)
762 event__synthesize_thread(target_tid, process_synthesized_event, 657 perf_event__synthesize_thread_map(evsel_list->threads,
763 session); 658 process_synthesized_event,
659 session);
764 else 660 else
765 event__synthesize_threads(process_synthesized_event, session); 661 perf_event__synthesize_threads(process_synthesized_event,
662 session);
766 663
767 if (realtime_prio) { 664 if (realtime_prio) {
768 struct sched_param param; 665 struct sched_param param;
@@ -789,17 +686,17 @@ static int __cmd_record(int argc, const char **argv)
789 if (hits == samples) { 686 if (hits == samples) {
790 if (done) 687 if (done)
791 break; 688 break;
792 err = poll(event_array, nr_poll, -1); 689 err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
793 waking++; 690 waking++;
794 } 691 }
795 692
796 if (done) { 693 if (done) {
797 for (i = 0; i < nr_cpu; i++) { 694 for (i = 0; i < evsel_list->cpus->nr; i++) {
798 struct perf_evsel *pos; 695 struct perf_evsel *pos;
799 696
800 list_for_each_entry(pos, &evsel_list, node) { 697 list_for_each_entry(pos, &evsel_list->entries, node) {
801 for (thread = 0; 698 for (thread = 0;
802 thread < threads->nr; 699 thread < evsel_list->threads->nr;
803 thread++) 700 thread++)
804 ioctl(FD(pos, i, thread), 701 ioctl(FD(pos, i, thread),
805 PERF_EVENT_IOC_DISABLE); 702 PERF_EVENT_IOC_DISABLE);
@@ -838,10 +735,10 @@ static const char * const record_usage[] = {
838static bool force, append_file; 735static bool force, append_file;
839 736
840const struct option record_options[] = { 737const struct option record_options[] = {
841 OPT_CALLBACK('e', "event", NULL, "event", 738 OPT_CALLBACK('e', "event", &evsel_list, "event",
842 "event selector. use 'perf list' to list available events", 739 "event selector. use 'perf list' to list available events",
843 parse_events), 740 parse_events),
844 OPT_CALLBACK(0, "filter", NULL, "filter", 741 OPT_CALLBACK(0, "filter", &evsel_list, "filter",
845 "event filter", parse_filter), 742 "event filter", parse_filter),
846 OPT_INTEGER('p', "pid", &target_pid, 743 OPT_INTEGER('p', "pid", &target_pid,
847 "record events on existing process id"), 744 "record events on existing process id"),
@@ -884,6 +781,9 @@ const struct option record_options[] = {
884 "do not update the buildid cache"), 781 "do not update the buildid cache"),
885 OPT_BOOLEAN('B', "no-buildid", &no_buildid, 782 OPT_BOOLEAN('B', "no-buildid", &no_buildid,
886 "do not collect buildids in perf.data"), 783 "do not collect buildids in perf.data"),
784 OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
785 "monitor event in cgroup name only",
786 parse_cgroups),
887 OPT_END() 787 OPT_END()
888}; 788};
889 789
@@ -892,6 +792,10 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
892 int err = -ENOMEM; 792 int err = -ENOMEM;
893 struct perf_evsel *pos; 793 struct perf_evsel *pos;
894 794
795 evsel_list = perf_evlist__new(NULL, NULL);
796 if (evsel_list == NULL)
797 return -ENOMEM;
798
895 argc = parse_options(argc, argv, record_options, record_usage, 799 argc = parse_options(argc, argv, record_options, record_usage,
896 PARSE_OPT_STOP_AT_NON_OPTION); 800 PARSE_OPT_STOP_AT_NON_OPTION);
897 if (!argc && target_pid == -1 && target_tid == -1 && 801 if (!argc && target_pid == -1 && target_tid == -1 &&
@@ -908,12 +812,19 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
908 write_mode = WRITE_FORCE; 812 write_mode = WRITE_FORCE;
909 } 813 }
910 814
815 if (nr_cgroups && !system_wide) {
816 fprintf(stderr, "cgroup monitoring only available in"
817 " system-wide mode\n");
818 usage_with_options(record_usage, record_options);
819 }
820
911 symbol__init(); 821 symbol__init();
912 822
913 if (no_buildid_cache || no_buildid) 823 if (no_buildid_cache || no_buildid)
914 disable_buildid_cache(); 824 disable_buildid_cache();
915 825
916 if (list_empty(&evsel_list) && perf_evsel_list__create_default() < 0) { 826 if (evsel_list->nr_entries == 0 &&
827 perf_evlist__add_default(evsel_list) < 0) {
917 pr_err("Not enough memory for event selector list\n"); 828 pr_err("Not enough memory for event selector list\n");
918 goto out_symbol_exit; 829 goto out_symbol_exit;
919 } 830 }
@@ -921,27 +832,19 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
921 if (target_pid != -1) 832 if (target_pid != -1)
922 target_tid = target_pid; 833 target_tid = target_pid;
923 834
924 threads = thread_map__new(target_pid, target_tid); 835 if (perf_evlist__create_maps(evsel_list, target_pid,
925 if (threads == NULL) { 836 target_tid, cpu_list) < 0)
926 pr_err("Problems finding threads of monitor\n");
927 usage_with_options(record_usage, record_options); 837 usage_with_options(record_usage, record_options);
928 }
929 838
930 cpus = cpu_map__new(cpu_list); 839 list_for_each_entry(pos, &evsel_list->entries, node) {
931 if (cpus == NULL) { 840 if (perf_evsel__alloc_fd(pos, evsel_list->cpus->nr,
932 perror("failed to parse CPUs map"); 841 evsel_list->threads->nr) < 0)
933 return -1;
934 }
935
936 list_for_each_entry(pos, &evsel_list, node) {
937 if (perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0)
938 goto out_free_fd; 842 goto out_free_fd;
939 if (perf_header__push_event(pos->attr.config, event_name(pos))) 843 if (perf_header__push_event(pos->attr.config, event_name(pos)))
940 goto out_free_fd; 844 goto out_free_fd;
941 } 845 }
942 event_array = malloc((sizeof(struct pollfd) * MAX_NR_CPUS * 846
943 MAX_COUNTERS * threads->nr)); 847 if (perf_evlist__alloc_pollfd(evsel_list) < 0)
944 if (!event_array)
945 goto out_free_fd; 848 goto out_free_fd;
946 849
947 if (user_interval != ULLONG_MAX) 850 if (user_interval != ULLONG_MAX)
@@ -959,16 +862,12 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
959 } else { 862 } else {
960 fprintf(stderr, "frequency and count are zero, aborting\n"); 863 fprintf(stderr, "frequency and count are zero, aborting\n");
961 err = -EINVAL; 864 err = -EINVAL;
962 goto out_free_event_array; 865 goto out_free_fd;
963 } 866 }
964 867
965 err = __cmd_record(argc, argv); 868 err = __cmd_record(argc, argv);
966
967out_free_event_array:
968 free(event_array);
969out_free_fd: 869out_free_fd:
970 thread_map__delete(threads); 870 perf_evlist__delete_maps(evsel_list);
971 threads = NULL;
972out_symbol_exit: 871out_symbol_exit:
973 symbol__exit(); 872 symbol__exit();
974 return err; 873 return err;
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index c27e31f289e6..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 sample_data *sample, 101
102static int process_sample_event(union perf_event *event,
103 struct perf_sample *sample,
104 struct perf_evsel *evsel,
154 struct perf_session *session) 105 struct perf_session *session)
155{ 106{
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, sample, 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,31 +116,22 @@ static int process_sample_event(event_t *event, struct sample_data *sample,
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, sample)) { 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(sample->id, &session->header);
174
175 if (add_event_total(session, sample, 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 sample_data *sample __used, 127static int process_read_event(union perf_event *event,
184 struct perf_session *session __used) 128 struct perf_sample *sample __used,
129 struct perf_session *session)
185{ 130{
186 struct perf_event_attr *attr; 131 struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist,
187 132 event->read.id);
188 attr = perf_header__find_attr(event->read.id, &session->header);
189
190 if (show_threads) { 133 if (show_threads) {
191 const char *name = attr ? __event_name(attr->type, attr->config) 134 const char *name = evsel ? event_name(evsel) : "unknown";
192 : "unknown";
193 perf_read_values_add_value(&show_threads_values, 135 perf_read_values_add_value(&show_threads_values,
194 event->read.pid, event->read.tid, 136 event->read.pid, event->read.tid,
195 event->read.id, 137 event->read.id,
@@ -198,7 +140,7 @@ static int process_read_event(event_t *event, struct sample_data *sample __used,
198 } 140 }
199 141
200 dump_printf(": %d %d %s %" PRIu64 "\n", event->read.pid, event->read.tid, 142 dump_printf(": %d %d %s %" PRIu64 "\n", event->read.pid, event->read.tid,
201 attr ? __event_name(attr->type, attr->config) : "FAIL", 143 evsel ? event_name(evsel) : "FAIL",
202 event->read.value); 144 event->read.value);
203 145
204 return 0; 146 return 0;
@@ -222,7 +164,7 @@ static int perf_session__setup_sample_type(struct perf_session *self)
222 } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE && 164 } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE &&
223 !symbol_conf.use_callchain) { 165 !symbol_conf.use_callchain) {
224 symbol_conf.use_callchain = true; 166 symbol_conf.use_callchain = true;
225 if (register_callchain_param(&callchain_param) < 0) { 167 if (callchain_register_param(&callchain_param) < 0) {
226 fprintf(stderr, "Can't register callchain" 168 fprintf(stderr, "Can't register callchain"
227 " params\n"); 169 " params\n");
228 return -EINVAL; 170 return -EINVAL;
@@ -233,17 +175,17 @@ static int perf_session__setup_sample_type(struct perf_session *self)
233} 175}
234 176
235static struct perf_event_ops event_ops = { 177static struct perf_event_ops event_ops = {
236 .sample = process_sample_event, 178 .sample = process_sample_event,
237 .mmap = event__process_mmap, 179 .mmap = perf_event__process_mmap,
238 .comm = event__process_comm, 180 .comm = perf_event__process_comm,
239 .exit = event__process_task, 181 .exit = perf_event__process_task,
240 .fork = event__process_task, 182 .fork = perf_event__process_task,
241 .lost = event__process_lost, 183 .lost = perf_event__process_lost,
242 .read = process_read_event, 184 .read = process_read_event,
243 .attr = event__process_attr, 185 .attr = perf_event__process_attr,
244 .event_type = event__process_event_type, 186 .event_type = perf_event__process_event_type,
245 .tracing_data = event__process_tracing_data, 187 .tracing_data = perf_event__process_tracing_data,
246 .build_id = event__process_build_id, 188 .build_id = perf_event__process_build_id,
247 .ordered_samples = true, 189 .ordered_samples = true,
248 .ordering_requires_timestamps = true, 190 .ordering_requires_timestamps = true,
249}; 191};
@@ -269,21 +211,21 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self,
269 return ret + fprintf(fp, "\n#\n"); 211 return ret + fprintf(fp, "\n#\n");
270} 212}
271 213
272static 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)
273{ 216{
274 struct rb_node *next = rb_first(tree); 217 struct perf_evsel *pos;
275 218
276 while (next) { 219 list_for_each_entry(pos, &evlist->entries, node) {
277 struct hists *hists = rb_entry(next, struct hists, rb_node); 220 struct hists *hists = &pos->hists;
278 const char *evname = NULL; 221 const char *evname = NULL;
279 222
280 if (rb_first(&hists->entries) != rb_last(&hists->entries)) 223 if (rb_first(&hists->entries) != rb_last(&hists->entries))
281 evname = __event_name(hists->type, hists->config); 224 evname = event_name(pos);
282 225
283 hists__fprintf_nr_sample_events(hists, evname, stdout); 226 hists__fprintf_nr_sample_events(hists, evname, stdout);
284 hists__fprintf(hists, NULL, false, stdout); 227 hists__fprintf(hists, NULL, false, stdout);
285 fprintf(stdout, "\n\n"); 228 fprintf(stdout, "\n\n");
286 next = rb_next(&hists->rb_node);
287 } 229 }
288 230
289 if (sort_order == default_sort_order && 231 if (sort_order == default_sort_order &&
@@ -304,8 +246,9 @@ static int hists__tty_browse_tree(struct rb_root *tree, const char *help)
304static int __cmd_report(void) 246static int __cmd_report(void)
305{ 247{
306 int ret = -EINVAL; 248 int ret = -EINVAL;
249 u64 nr_samples;
307 struct perf_session *session; 250 struct perf_session *session;
308 struct rb_node *next; 251 struct perf_evsel *pos;
309 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";
310 253
311 signal(SIGINT, sig_handler); 254 signal(SIGINT, sig_handler);
@@ -336,20 +279,24 @@ static int __cmd_report(void)
336 if (verbose > 2) 279 if (verbose > 2)
337 perf_session__fprintf_dsos(session, stdout); 280 perf_session__fprintf_dsos(session, stdout);
338 281
339 next = rb_first(&session->hists_tree); 282 nr_samples = 0;
340 while (next) { 283 list_for_each_entry(pos, &session->evlist->entries, node) {
341 struct hists *hists; 284 struct hists *hists = &pos->hists;
342 285
343 hists = rb_entry(next, struct hists, rb_node);
344 hists__collapse_resort(hists); 286 hists__collapse_resort(hists);
345 hists__output_resort(hists); 287 hists__output_resort(hists);
346 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;
347 } 294 }
348 295
349 if (use_browser > 0) 296 if (use_browser > 0)
350 hists__tui_browse_tree(&session->hists_tree, help); 297 perf_evlist__tui_browse_hists(session->evlist, help);
351 else 298 else
352 hists__tty_browse_tree(&session->hists_tree, help); 299 perf_evlist__tty_browse_hists(session->evlist, help);
353 300
354out_delete: 301out_delete:
355 /* 302 /*
@@ -424,7 +371,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
424 if (tok2) 371 if (tok2)
425 callchain_param.print_limit = strtod(tok2, &endptr); 372 callchain_param.print_limit = strtod(tok2, &endptr);
426setup: 373setup:
427 if (register_callchain_param(&callchain_param) < 0) { 374 if (callchain_register_param(&callchain_param) < 0) {
428 fprintf(stderr, "Can't register callchain params\n"); 375 fprintf(stderr, "Can't register callchain params\n");
429 return -1; 376 return -1;
430 } 377 }
@@ -498,7 +445,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
498 use_browser = 1; 445 use_browser = 1;
499 446
500 if (strcmp(input_name, "-") != 0) 447 if (strcmp(input_name, "-") != 0)
501 setup_browser(); 448 setup_browser(true);
502 else 449 else
503 use_browser = 0; 450 use_browser = 0;
504 /* 451 /*
@@ -507,7 +454,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
507 * implementation. 454 * implementation.
508 */ 455 */
509 if (use_browser > 0) { 456 if (use_browser > 0) {
510 symbol_conf.priv_size = sizeof(struct sym_priv); 457 symbol_conf.priv_size = sizeof(struct annotation);
458 annotate_init = symbol__annotate_init;
511 /* 459 /*
512 * For searching by name on the "Browse map details". 460 * For searching by name on the "Browse map details".
513 * 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 29acb894e035..dcfe8873c9a1 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -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:
@@ -562,7 +557,7 @@ static void wait_for_tasks(void)
562 557
563static void run_one_test(void) 558static void run_one_test(void)
564{ 559{
565 u64 T0, T1, delta, avg_delta, fluct, std_dev; 560 u64 T0, T1, delta, avg_delta, fluct;
566 561
567 T0 = get_nsecs(); 562 T0 = get_nsecs();
568 wait_for_tasks(); 563 wait_for_tasks();
@@ -578,7 +573,6 @@ static void run_one_test(void)
578 else 573 else
579 fluct = delta - avg_delta; 574 fluct = delta - avg_delta;
580 sum_fluct += fluct; 575 sum_fluct += fluct;
581 std_dev = sum_fluct / nr_runs / sqrt(nr_runs);
582 if (!run_avg) 576 if (!run_avg)
583 run_avg = delta; 577 run_avg = delta;
584 run_avg = (run_avg*9 + delta)/10; 578 run_avg = (run_avg*9 + delta)/10;
@@ -799,7 +793,7 @@ replay_switch_event(struct trace_switch_event *switch_event,
799 u64 timestamp, 793 u64 timestamp,
800 struct thread *thread __used) 794 struct thread *thread __used)
801{ 795{
802 struct task_desc *prev, *next; 796 struct task_desc *prev, __used *next;
803 u64 timestamp0; 797 u64 timestamp0;
804 s64 delta; 798 s64 delta;
805 799
@@ -1404,7 +1398,7 @@ map_switch_event(struct trace_switch_event *switch_event,
1404 u64 timestamp, 1398 u64 timestamp,
1405 struct thread *thread __used) 1399 struct thread *thread __used)
1406{ 1400{
1407 struct thread *sched_out, *sched_in; 1401 struct thread *sched_out __used, *sched_in;
1408 int new_shortname; 1402 int new_shortname;
1409 u64 timestamp0; 1403 u64 timestamp0;
1410 s64 delta; 1404 s64 delta;
@@ -1580,9 +1574,9 @@ process_sched_migrate_task_event(void *data, struct perf_session *session,
1580 event, cpu, timestamp, thread); 1574 event, cpu, timestamp, thread);
1581} 1575}
1582 1576
1583static void 1577static void process_raw_event(union perf_event *raw_event __used,
1584process_raw_event(event_t *raw_event __used, struct perf_session *session, 1578 struct perf_session *session, void *data, int cpu,
1585 void *data, int cpu, u64 timestamp, struct thread *thread) 1579 u64 timestamp, struct thread *thread)
1586{ 1580{
1587 struct event *event; 1581 struct event *event;
1588 int type; 1582 int type;
@@ -1607,7 +1601,9 @@ process_raw_event(event_t *raw_event __used, struct perf_session *session,
1607 process_sched_migrate_task_event(data, session, event, cpu, timestamp, thread); 1601 process_sched_migrate_task_event(data, session, event, cpu, timestamp, thread);
1608} 1602}
1609 1603
1610static int process_sample_event(event_t *event, struct sample_data *sample, 1604static int process_sample_event(union perf_event *event,
1605 struct perf_sample *sample,
1606 struct perf_evsel *evsel __used,
1611 struct perf_session *session) 1607 struct perf_session *session)
1612{ 1608{
1613 struct thread *thread; 1609 struct thread *thread;
@@ -1635,9 +1631,9 @@ static int process_sample_event(event_t *event, struct sample_data *sample,
1635 1631
1636static struct perf_event_ops event_ops = { 1632static struct perf_event_ops event_ops = {
1637 .sample = process_sample_event, 1633 .sample = process_sample_event,
1638 .comm = event__process_comm, 1634 .comm = perf_event__process_comm,
1639 .lost = event__process_lost, 1635 .lost = perf_event__process_lost,
1640 .fork = event__process_task, 1636 .fork = perf_event__process_task,
1641 .ordered_samples = true, 1637 .ordered_samples = true,
1642}; 1638};
1643 1639
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index b766c2a9ac97..ac574ea23917 100644
--- a/tools/perf/builtin-script.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
@@ -63,7 +234,9 @@ static int cleanup_scripting(void)
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 sample_data *sample, 237static int process_sample_event(union perf_event *event,
238 struct perf_sample *sample,
239 struct perf_evsel *evsel,
67 struct perf_session *session) 240 struct perf_session *session)
68{ 241{
69 struct thread *thread = perf_session__findnew(session, event->ip.pid); 242 struct thread *thread = perf_session__findnew(session, event->ip.pid);
@@ -74,40 +247,34 @@ static int process_sample_event(event_t *event, struct sample_data *sample,
74 return -1; 247 return -1;
75 } 248 }
76 249
77 if (session->sample_type & PERF_SAMPLE_RAW) { 250 if (debug_mode) {
78 if (debug_mode) { 251 if (sample->time < last_timestamp) {
79 if (sample->time < last_timestamp) { 252 pr_err("Samples misordered, previous: %" PRIu64
80 pr_err("Samples misordered, previous: %" PRIu64 253 " this: %" PRIu64 "\n", last_timestamp,
81 " this: %" PRIu64 "\n", last_timestamp, 254 sample->time);
82 sample->time); 255 nr_unordered++;
83 nr_unordered++;
84 }
85 last_timestamp = sample->time;
86 return 0;
87 } 256 }
88 /* 257 last_timestamp = sample->time;
89 * FIXME: better resolve from pid from the struct trace_entry 258 return 0;
90 * field, although it should be the same than this perf
91 * event pid
92 */
93 scripting_ops->process_event(sample->cpu, sample->raw_data,
94 sample->raw_size,
95 sample->time, thread->comm);
96 } 259 }
260 scripting_ops->process_event(event, sample, evsel, session, thread);
97 261
98 session->hists.stats.total_period += sample->period; 262 session->hists.stats.total_period += sample->period;
99 return 0; 263 return 0;
100} 264}
101 265
102static struct perf_event_ops event_ops = { 266static struct perf_event_ops event_ops = {
103 .sample = process_sample_event, 267 .sample = process_sample_event,
104 .comm = event__process_comm, 268 .mmap = perf_event__process_mmap,
105 .attr = event__process_attr, 269 .comm = perf_event__process_comm,
106 .event_type = event__process_event_type, 270 .exit = perf_event__process_task,
107 .tracing_data = event__process_tracing_data, 271 .fork = perf_event__process_task,
108 .build_id = event__process_build_id, 272 .attr = perf_event__process_attr,
109 .ordering_requires_timestamps = true, 273 .event_type = perf_event__process_event_type,
274 .tracing_data = perf_event__process_tracing_data,
275 .build_id = perf_event__process_build_id,
110 .ordered_samples = true, 276 .ordered_samples = true,
277 .ordering_requires_timestamps = true,
111}; 278};
112 279
113extern volatile int session_done; 280extern volatile int session_done;
@@ -279,6 +446,68 @@ static int parse_scriptname(const struct option *opt __used,
279 return 0; 446 return 0;
280} 447}
281 448
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
282/* Helper function for filesystems that return a dent->d_type DT_UNKNOWN */ 511/* Helper function for filesystems that return a dent->d_type DT_UNKNOWN */
283static int is_directory(const char *base_path, const struct dirent *dent) 512static int is_directory(const char *base_path, const struct dirent *dent)
284{ 513{
@@ -591,6 +820,17 @@ static const struct option options[] = {
591 "input file name"), 820 "input file name"),
592 OPT_BOOLEAN('d', "debug-mode", &debug_mode, 821 OPT_BOOLEAN('d', "debug-mode", &debug_mode,
593 "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),
594 834
595 OPT_END() 835 OPT_END()
596}; 836};
@@ -771,14 +1011,22 @@ int cmd_script(int argc, const char **argv, const char *prefix __used)
771 if (session == NULL) 1011 if (session == NULL)
772 return -ENOMEM; 1012 return -ENOMEM;
773 1013
774 if (strcmp(input_name, "-") && 1014 if (!no_callchain)
775 !perf_session__has_traces(session, "record -R")) 1015 symbol_conf.use_callchain = true;
776 return -EINVAL; 1016 else
1017 symbol_conf.use_callchain = false;
777 1018
778 if (generate_script_lang) { 1019 if (generate_script_lang) {
779 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 }
780 1028
781 int input = open(input_name, O_RDONLY); 1029 input = open(input_name, O_RDONLY);
782 if (input < 0) { 1030 if (input < 0) {
783 perror("failed to open file"); 1031 perror("failed to open file");
784 exit(-1); 1032 exit(-1);
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index a482a191a0ca..e2109f9b43eb 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -43,11 +43,13 @@
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"
46#include "util/evsel.h" 47#include "util/evsel.h"
47#include "util/debug.h" 48#include "util/debug.h"
48#include "util/header.h" 49#include "util/header.h"
49#include "util/cpumap.h" 50#include "util/cpumap.h"
50#include "util/thread.h" 51#include "util/thread.h"
52#include "util/thread_map.h"
51 53
52#include <sys/prctl.h> 54#include <sys/prctl.h>
53#include <math.h> 55#include <math.h>
@@ -71,8 +73,9 @@ static struct perf_event_attr default_attrs[] = {
71 73
72}; 74};
73 75
76struct perf_evlist *evsel_list;
77
74static bool system_wide = false; 78static bool system_wide = false;
75static struct cpu_map *cpus;
76static int run_idx = 0; 79static int run_idx = 0;
77 80
78static int run_count = 1; 81static int run_count = 1;
@@ -81,7 +84,6 @@ static bool scale = true;
81static bool no_aggr = false; 84static bool no_aggr = false;
82static pid_t target_pid = -1; 85static pid_t target_pid = -1;
83static pid_t target_tid = -1; 86static pid_t target_tid = -1;
84static struct thread_map *threads;
85static pid_t child_pid = -1; 87static pid_t child_pid = -1;
86static bool null_run = false; 88static bool null_run = false;
87static bool big_num = true; 89static bool big_num = true;
@@ -166,7 +168,7 @@ static int create_perf_stat_counter(struct perf_evsel *evsel)
166 PERF_FORMAT_TOTAL_TIME_RUNNING; 168 PERF_FORMAT_TOTAL_TIME_RUNNING;
167 169
168 if (system_wide) 170 if (system_wide)
169 return perf_evsel__open_per_cpu(evsel, cpus); 171 return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, false, false);
170 172
171 attr->inherit = !no_inherit; 173 attr->inherit = !no_inherit;
172 if (target_pid == -1 && target_tid == -1) { 174 if (target_pid == -1 && target_tid == -1) {
@@ -174,7 +176,7 @@ static int create_perf_stat_counter(struct perf_evsel *evsel)
174 attr->enable_on_exec = 1; 176 attr->enable_on_exec = 1;
175 } 177 }
176 178
177 return perf_evsel__open_per_thread(evsel, threads); 179 return perf_evsel__open_per_thread(evsel, evsel_list->threads, false, false);
178} 180}
179 181
180/* 182/*
@@ -199,7 +201,8 @@ static int read_counter_aggr(struct perf_evsel *counter)
199 u64 *count = counter->counts->aggr.values; 201 u64 *count = counter->counts->aggr.values;
200 int i; 202 int i;
201 203
202 if (__perf_evsel__read(counter, cpus->nr, threads->nr, scale) < 0) 204 if (__perf_evsel__read(counter, evsel_list->cpus->nr,
205 evsel_list->threads->nr, scale) < 0)
203 return -1; 206 return -1;
204 207
205 for (i = 0; i < 3; i++) 208 for (i = 0; i < 3; i++)
@@ -232,7 +235,7 @@ static int read_counter(struct perf_evsel *counter)
232 u64 *count; 235 u64 *count;
233 int cpu; 236 int cpu;
234 237
235 for (cpu = 0; cpu < cpus->nr; cpu++) { 238 for (cpu = 0; cpu < evsel_list->cpus->nr; cpu++) {
236 if (__perf_evsel__read_on_cpu(counter, cpu, 0, scale) < 0) 239 if (__perf_evsel__read_on_cpu(counter, cpu, 0, scale) < 0)
237 return -1; 240 return -1;
238 241
@@ -297,7 +300,7 @@ static int run_perf_stat(int argc __used, const char **argv)
297 } 300 }
298 301
299 if (target_tid == -1 && target_pid == -1 && !system_wide) 302 if (target_tid == -1 && target_pid == -1 && !system_wide)
300 threads->map[0] = child_pid; 303 evsel_list->threads->map[0] = child_pid;
301 304
302 /* 305 /*
303 * Wait for the child to be ready to exec. 306 * Wait for the child to be ready to exec.
@@ -309,7 +312,7 @@ static int run_perf_stat(int argc __used, const char **argv)
309 close(child_ready_pipe[0]); 312 close(child_ready_pipe[0]);
310 } 313 }
311 314
312 list_for_each_entry(counter, &evsel_list, node) { 315 list_for_each_entry(counter, &evsel_list->entries, node) {
313 if (create_perf_stat_counter(counter) < 0) { 316 if (create_perf_stat_counter(counter) < 0) {
314 if (errno == -EPERM || errno == -EACCES) { 317 if (errno == -EPERM || errno == -EACCES) {
315 error("You may not have permission to collect %sstats.\n" 318 error("You may not have permission to collect %sstats.\n"
@@ -330,6 +333,12 @@ static int run_perf_stat(int argc __used, const char **argv)
330 } 333 }
331 } 334 }
332 335
336 if (perf_evlist__set_filters(evsel_list)) {
337 error("failed to set filter with %d (%s)\n", errno,
338 strerror(errno));
339 return -1;
340 }
341
333 /* 342 /*
334 * Enable counters and exec the command: 343 * Enable counters and exec the command:
335 */ 344 */
@@ -347,14 +356,15 @@ static int run_perf_stat(int argc __used, const char **argv)
347 update_stats(&walltime_nsecs_stats, t1 - t0); 356 update_stats(&walltime_nsecs_stats, t1 - t0);
348 357
349 if (no_aggr) { 358 if (no_aggr) {
350 list_for_each_entry(counter, &evsel_list, node) { 359 list_for_each_entry(counter, &evsel_list->entries, node) {
351 read_counter(counter); 360 read_counter(counter);
352 perf_evsel__close_fd(counter, cpus->nr, 1); 361 perf_evsel__close_fd(counter, evsel_list->cpus->nr, 1);
353 } 362 }
354 } else { 363 } else {
355 list_for_each_entry(counter, &evsel_list, node) { 364 list_for_each_entry(counter, &evsel_list->entries, node) {
356 read_counter_aggr(counter); 365 read_counter_aggr(counter);
357 perf_evsel__close_fd(counter, cpus->nr, threads->nr); 366 perf_evsel__close_fd(counter, evsel_list->cpus->nr,
367 evsel_list->threads->nr);
358 } 368 }
359 } 369 }
360 370
@@ -382,10 +392,13 @@ static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg)
382 if (no_aggr) 392 if (no_aggr)
383 sprintf(cpustr, "CPU%*d%s", 393 sprintf(cpustr, "CPU%*d%s",
384 csv_output ? 0 : -4, 394 csv_output ? 0 : -4,
385 cpus->map[cpu], csv_sep); 395 evsel_list->cpus->map[cpu], csv_sep);
386 396
387 fprintf(stderr, fmt, cpustr, msecs, csv_sep, event_name(evsel)); 397 fprintf(stderr, fmt, cpustr, msecs, csv_sep, event_name(evsel));
388 398
399 if (evsel->cgrp)
400 fprintf(stderr, "%s%s", csv_sep, evsel->cgrp->name);
401
389 if (csv_output) 402 if (csv_output)
390 return; 403 return;
391 404
@@ -410,12 +423,15 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
410 if (no_aggr) 423 if (no_aggr)
411 sprintf(cpustr, "CPU%*d%s", 424 sprintf(cpustr, "CPU%*d%s",
412 csv_output ? 0 : -4, 425 csv_output ? 0 : -4,
413 cpus->map[cpu], csv_sep); 426 evsel_list->cpus->map[cpu], csv_sep);
414 else 427 else
415 cpu = 0; 428 cpu = 0;
416 429
417 fprintf(stderr, fmt, cpustr, avg, csv_sep, event_name(evsel)); 430 fprintf(stderr, fmt, cpustr, avg, csv_sep, event_name(evsel));
418 431
432 if (evsel->cgrp)
433 fprintf(stderr, "%s%s", csv_sep, evsel->cgrp->name);
434
419 if (csv_output) 435 if (csv_output)
420 return; 436 return;
421 437
@@ -456,9 +472,17 @@ static void print_counter_aggr(struct perf_evsel *counter)
456 int scaled = counter->counts->scaled; 472 int scaled = counter->counts->scaled;
457 473
458 if (scaled == -1) { 474 if (scaled == -1) {
459 fprintf(stderr, "%*s%s%-24s\n", 475 fprintf(stderr, "%*s%s%*s",
460 csv_output ? 0 : 18, 476 csv_output ? 0 : 18,
461 "<not counted>", csv_sep, event_name(counter)); 477 "<not counted>",
478 csv_sep,
479 csv_output ? 0 : -24,
480 event_name(counter));
481
482 if (counter->cgrp)
483 fprintf(stderr, "%s%s", csv_sep, counter->cgrp->name);
484
485 fputc('\n', stderr);
462 return; 486 return;
463 } 487 }
464 488
@@ -483,7 +507,6 @@ static void print_counter_aggr(struct perf_evsel *counter)
483 fprintf(stderr, " (scaled from %.2f%%)", 507 fprintf(stderr, " (scaled from %.2f%%)",
484 100 * avg_running / avg_enabled); 508 100 * avg_running / avg_enabled);
485 } 509 }
486
487 fprintf(stderr, "\n"); 510 fprintf(stderr, "\n");
488} 511}
489 512
@@ -496,19 +519,23 @@ static void print_counter(struct perf_evsel *counter)
496 u64 ena, run, val; 519 u64 ena, run, val;
497 int cpu; 520 int cpu;
498 521
499 for (cpu = 0; cpu < cpus->nr; cpu++) { 522 for (cpu = 0; cpu < evsel_list->cpus->nr; cpu++) {
500 val = counter->counts->cpu[cpu].val; 523 val = counter->counts->cpu[cpu].val;
501 ena = counter->counts->cpu[cpu].ena; 524 ena = counter->counts->cpu[cpu].ena;
502 run = counter->counts->cpu[cpu].run; 525 run = counter->counts->cpu[cpu].run;
503 if (run == 0 || ena == 0) { 526 if (run == 0 || ena == 0) {
504 fprintf(stderr, "CPU%*d%s%*s%s%-24s", 527 fprintf(stderr, "CPU%*d%s%*s%s%*s",
505 csv_output ? 0 : -4, 528 csv_output ? 0 : -4,
506 cpus->map[cpu], csv_sep, 529 evsel_list->cpus->map[cpu], csv_sep,
507 csv_output ? 0 : 18, 530 csv_output ? 0 : 18,
508 "<not counted>", csv_sep, 531 "<not counted>", csv_sep,
532 csv_output ? 0 : -24,
509 event_name(counter)); 533 event_name(counter));
510 534
511 fprintf(stderr, "\n"); 535 if (counter->cgrp)
536 fprintf(stderr, "%s%s", csv_sep, counter->cgrp->name);
537
538 fputc('\n', stderr);
512 continue; 539 continue;
513 } 540 }
514 541
@@ -525,7 +552,7 @@ static void print_counter(struct perf_evsel *counter)
525 100.0 * run / ena); 552 100.0 * run / ena);
526 } 553 }
527 } 554 }
528 fprintf(stderr, "\n"); 555 fputc('\n', stderr);
529 } 556 }
530} 557}
531 558
@@ -555,10 +582,10 @@ static void print_stat(int argc, const char **argv)
555 } 582 }
556 583
557 if (no_aggr) { 584 if (no_aggr) {
558 list_for_each_entry(counter, &evsel_list, node) 585 list_for_each_entry(counter, &evsel_list->entries, node)
559 print_counter(counter); 586 print_counter(counter);
560 } else { 587 } else {
561 list_for_each_entry(counter, &evsel_list, node) 588 list_for_each_entry(counter, &evsel_list->entries, node)
562 print_counter_aggr(counter); 589 print_counter_aggr(counter);
563 } 590 }
564 591
@@ -610,9 +637,11 @@ static int stat__set_big_num(const struct option *opt __used,
610} 637}
611 638
612static const struct option options[] = { 639static const struct option options[] = {
613 OPT_CALLBACK('e', "event", NULL, "event", 640 OPT_CALLBACK('e', "event", &evsel_list, "event",
614 "event selector. use 'perf list' to list available events", 641 "event selector. use 'perf list' to list available events",
615 parse_events), 642 parse_events),
643 OPT_CALLBACK(0, "filter", &evsel_list, "filter",
644 "event filter", parse_filter),
616 OPT_BOOLEAN('i', "no-inherit", &no_inherit, 645 OPT_BOOLEAN('i', "no-inherit", &no_inherit,
617 "child tasks do not inherit counters"), 646 "child tasks do not inherit counters"),
618 OPT_INTEGER('p', "pid", &target_pid, 647 OPT_INTEGER('p', "pid", &target_pid,
@@ -638,6 +667,9 @@ static const struct option options[] = {
638 "disable CPU count aggregation"), 667 "disable CPU count aggregation"),
639 OPT_STRING('x', "field-separator", &csv_sep, "separator", 668 OPT_STRING('x', "field-separator", &csv_sep, "separator",
640 "print counts with custom separator"), 669 "print counts with custom separator"),
670 OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
671 "monitor event in cgroup name only",
672 parse_cgroups),
641 OPT_END() 673 OPT_END()
642}; 674};
643 675
@@ -648,6 +680,10 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
648 680
649 setlocale(LC_ALL, ""); 681 setlocale(LC_ALL, "");
650 682
683 evsel_list = perf_evlist__new(NULL, NULL);
684 if (evsel_list == NULL)
685 return -ENOMEM;
686
651 argc = parse_options(argc, argv, options, stat_usage, 687 argc = parse_options(argc, argv, options, stat_usage,
652 PARSE_OPT_STOP_AT_NON_OPTION); 688 PARSE_OPT_STOP_AT_NON_OPTION);
653 689
@@ -674,49 +710,50 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
674 if (run_count <= 0) 710 if (run_count <= 0)
675 usage_with_options(stat_usage, options); 711 usage_with_options(stat_usage, options);
676 712
677 /* no_aggr is for system-wide only */ 713 /* no_aggr, cgroup are for system-wide only */
678 if (no_aggr && !system_wide) 714 if ((no_aggr || nr_cgroups) && !system_wide) {
715 fprintf(stderr, "both cgroup and no-aggregation "
716 "modes only available in system-wide mode\n");
717
679 usage_with_options(stat_usage, options); 718 usage_with_options(stat_usage, options);
719 }
680 720
681 /* Set attrs and nr_counters if no event is selected and !null_run */ 721 /* Set attrs and nr_counters if no event is selected and !null_run */
682 if (!null_run && !nr_counters) { 722 if (!null_run && !evsel_list->nr_entries) {
683 size_t c; 723 size_t c;
684 724
685 nr_counters = ARRAY_SIZE(default_attrs);
686
687 for (c = 0; c < ARRAY_SIZE(default_attrs); ++c) { 725 for (c = 0; c < ARRAY_SIZE(default_attrs); ++c) {
688 pos = perf_evsel__new(&default_attrs[c], 726 pos = perf_evsel__new(&default_attrs[c], c);
689 nr_counters);
690 if (pos == NULL) 727 if (pos == NULL)
691 goto out; 728 goto out;
692 list_add(&pos->node, &evsel_list); 729 perf_evlist__add(evsel_list, pos);
693 } 730 }
694 } 731 }
695 732
696 if (target_pid != -1) 733 if (target_pid != -1)
697 target_tid = target_pid; 734 target_tid = target_pid;
698 735
699 threads = thread_map__new(target_pid, target_tid); 736 evsel_list->threads = thread_map__new(target_pid, target_tid);
700 if (threads == NULL) { 737 if (evsel_list->threads == NULL) {
701 pr_err("Problems finding threads of monitor\n"); 738 pr_err("Problems finding threads of monitor\n");
702 usage_with_options(stat_usage, options); 739 usage_with_options(stat_usage, options);
703 } 740 }
704 741
705 if (system_wide) 742 if (system_wide)
706 cpus = cpu_map__new(cpu_list); 743 evsel_list->cpus = cpu_map__new(cpu_list);
707 else 744 else
708 cpus = cpu_map__dummy_new(); 745 evsel_list->cpus = cpu_map__dummy_new();
709 746
710 if (cpus == NULL) { 747 if (evsel_list->cpus == NULL) {
711 perror("failed to parse CPUs map"); 748 perror("failed to parse CPUs map");
712 usage_with_options(stat_usage, options); 749 usage_with_options(stat_usage, options);
713 return -1; 750 return -1;
714 } 751 }
715 752
716 list_for_each_entry(pos, &evsel_list, node) { 753 list_for_each_entry(pos, &evsel_list->entries, node) {
717 if (perf_evsel__alloc_stat_priv(pos) < 0 || 754 if (perf_evsel__alloc_stat_priv(pos) < 0 ||
718 perf_evsel__alloc_counts(pos, cpus->nr) < 0 || 755 perf_evsel__alloc_counts(pos, evsel_list->cpus->nr) < 0 ||
719 perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0) 756 perf_evsel__alloc_fd(pos, evsel_list->cpus->nr, evsel_list->threads->nr) < 0)
720 goto out_free_fd; 757 goto out_free_fd;
721 } 758 }
722 759
@@ -741,11 +778,10 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
741 if (status != -1) 778 if (status != -1)
742 print_stat(argc, argv); 779 print_stat(argc, argv);
743out_free_fd: 780out_free_fd:
744 list_for_each_entry(pos, &evsel_list, node) 781 list_for_each_entry(pos, &evsel_list->entries, node)
745 perf_evsel__free_stat_priv(pos); 782 perf_evsel__free_stat_priv(pos);
746 perf_evsel_list__delete(); 783 perf_evlist__delete_maps(evsel_list);
747out: 784out:
748 thread_map__delete(threads); 785 perf_evlist__delete(evsel_list);
749 threads = NULL;
750 return status; 786 return status;
751} 787}
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 5dcdba653d70..1b2106c58f66 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
@@ -238,14 +239,14 @@ out:
238#include "util/evsel.h" 239#include "util/evsel.h"
239#include <sys/types.h> 240#include <sys/types.h>
240 241
241static int trace_event__id(const char *event_name) 242static int trace_event__id(const char *evname)
242{ 243{
243 char *filename; 244 char *filename;
244 int err = -1, fd; 245 int err = -1, fd;
245 246
246 if (asprintf(&filename, 247 if (asprintf(&filename,
247 "/sys/kernel/debug/tracing/events/syscalls/%s/id", 248 "/sys/kernel/debug/tracing/events/syscalls/%s/id",
248 event_name) < 0) 249 evname) < 0)
249 return -1; 250 return -1;
250 251
251 fd = open(filename, O_RDONLY); 252 fd = open(filename, O_RDONLY);
@@ -289,7 +290,7 @@ static int test__open_syscall_event(void)
289 goto out_thread_map_delete; 290 goto out_thread_map_delete;
290 } 291 }
291 292
292 if (perf_evsel__open_per_thread(evsel, threads) < 0) { 293 if (perf_evsel__open_per_thread(evsel, threads, false, false) < 0) {
293 pr_debug("failed to open counter: %s, " 294 pr_debug("failed to open counter: %s, "
294 "tweak /proc/sys/kernel/perf_event_paranoid?\n", 295 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
295 strerror(errno)); 296 strerror(errno));
@@ -347,9 +348,9 @@ static int test__open_syscall_event_on_all_cpus(void)
347 } 348 }
348 349
349 cpus = cpu_map__new(NULL); 350 cpus = cpu_map__new(NULL);
350 if (threads == NULL) { 351 if (cpus == NULL) {
351 pr_debug("thread_map__new\n"); 352 pr_debug("cpu_map__new\n");
352 return -1; 353 goto out_thread_map_delete;
353 } 354 }
354 355
355 356
@@ -364,7 +365,7 @@ static int test__open_syscall_event_on_all_cpus(void)
364 goto out_thread_map_delete; 365 goto out_thread_map_delete;
365 } 366 }
366 367
367 if (perf_evsel__open(evsel, cpus, threads) < 0) { 368 if (perf_evsel__open(evsel, cpus, threads, false, false) < 0) {
368 pr_debug("failed to open counter: %s, " 369 pr_debug("failed to open counter: %s, "
369 "tweak /proc/sys/kernel/perf_event_paranoid?\n", 370 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
370 strerror(errno)); 371 strerror(errno));
@@ -408,6 +409,8 @@ static int test__open_syscall_event_on_all_cpus(void)
408 goto out_close_fd; 409 goto out_close_fd;
409 } 410 }
410 411
412 err = 0;
413
411 for (cpu = 0; cpu < cpus->nr; ++cpu) { 414 for (cpu = 0; cpu < cpus->nr; ++cpu) {
412 unsigned int expected; 415 unsigned int expected;
413 416
@@ -416,18 +419,18 @@ static int test__open_syscall_event_on_all_cpus(void)
416 419
417 if (perf_evsel__read_on_cpu(evsel, cpu, 0) < 0) { 420 if (perf_evsel__read_on_cpu(evsel, cpu, 0) < 0) {
418 pr_debug("perf_evsel__open_read_on_cpu\n"); 421 pr_debug("perf_evsel__open_read_on_cpu\n");
419 goto out_close_fd; 422 err = -1;
423 break;
420 } 424 }
421 425
422 expected = nr_open_calls + cpu; 426 expected = nr_open_calls + cpu;
423 if (evsel->counts->cpu[cpu].val != expected) { 427 if (evsel->counts->cpu[cpu].val != expected) {
424 pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls on cpu %d, got %" PRIu64 "\n", 428 pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls on cpu %d, got %" PRIu64 "\n",
425 expected, cpus->map[cpu], evsel->counts->cpu[cpu].val); 429 expected, cpus->map[cpu], evsel->counts->cpu[cpu].val);
426 goto out_close_fd; 430 err = -1;
427 } 431 }
428 } 432 }
429 433
430 err = 0;
431out_close_fd: 434out_close_fd:
432 perf_evsel__close_fd(evsel, 1, threads->nr); 435 perf_evsel__close_fd(evsel, 1, threads->nr);
433out_evsel_delete: 436out_evsel_delete:
@@ -437,6 +440,159 @@ out_thread_map_delete:
437 return err; 440 return err;
438} 441}
439 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, 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
440static struct test { 596static struct test {
441 const char *desc; 597 const char *desc;
442 int (*func)(void); 598 int (*func)(void);
@@ -454,6 +610,10 @@ static struct test {
454 .func = test__open_syscall_event_on_all_cpus, 610 .func = test__open_syscall_event_on_all_cpus,
455 }, 611 },
456 { 612 {
613 .desc = "read samples using the mmap interface",
614 .func = test__basic_mmap,
615 },
616 {
457 .func = NULL, 617 .func = NULL,
458 }, 618 },
459}; 619};
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 746cf03cb05d..aa26f4d66d10 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -264,9 +264,6 @@ pid_put_sample(int pid, int type, unsigned int cpu, u64 start, u64 end)
264 c->start_time = start; 264 c->start_time = start;
265 if (p->start_time == 0 || p->start_time > start) 265 if (p->start_time == 0 || p->start_time > start)
266 p->start_time = start; 266 p->start_time = start;
267
268 if (cpu > numcpus)
269 numcpus = cpu;
270} 267}
271 268
272#define MAX_CPUS 4096 269#define MAX_CPUS 4096
@@ -276,21 +273,24 @@ static int cpus_cstate_state[MAX_CPUS];
276static u64 cpus_pstate_start_times[MAX_CPUS]; 273static u64 cpus_pstate_start_times[MAX_CPUS];
277static u64 cpus_pstate_state[MAX_CPUS]; 274static u64 cpus_pstate_state[MAX_CPUS];
278 275
279static int process_comm_event(event_t *event, struct sample_data *sample __used, 276static int process_comm_event(union perf_event *event,
277 struct perf_sample *sample __used,
280 struct perf_session *session __used) 278 struct perf_session *session __used)
281{ 279{
282 pid_set_comm(event->comm.tid, event->comm.comm); 280 pid_set_comm(event->comm.tid, event->comm.comm);
283 return 0; 281 return 0;
284} 282}
285 283
286static int process_fork_event(event_t *event, struct sample_data *sample __used, 284static int process_fork_event(union perf_event *event,
285 struct perf_sample *sample __used,
287 struct perf_session *session __used) 286 struct perf_session *session __used)
288{ 287{
289 pid_fork(event->fork.pid, event->fork.ppid, event->fork.time); 288 pid_fork(event->fork.pid, event->fork.ppid, event->fork.time);
290 return 0; 289 return 0;
291} 290}
292 291
293static int process_exit_event(event_t *event, struct sample_data *sample __used, 292static int process_exit_event(union perf_event *event,
293 struct perf_sample *sample __used,
294 struct perf_session *session __used) 294 struct perf_session *session __used)
295{ 295{
296 pid_exit(event->fork.pid, event->fork.time); 296 pid_exit(event->fork.pid, event->fork.time);
@@ -486,8 +486,9 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te)
486} 486}
487 487
488 488
489static int process_sample_event(event_t *event __used, 489static int process_sample_event(union perf_event *event __used,
490 struct sample_data *sample, 490 struct perf_sample *sample,
491 struct perf_evsel *evsel __used,
491 struct perf_session *session) 492 struct perf_session *session)
492{ 493{
493 struct trace_entry *te; 494 struct trace_entry *te;
@@ -506,11 +507,24 @@ static int process_sample_event(event_t *event __used,
506 struct power_entry_old *peo; 507 struct power_entry_old *peo;
507 peo = (void *)te; 508 peo = (void *)te;
508#endif 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 */
509 event_str = perf_header__find_event(te->type); 520 event_str = perf_header__find_event(te->type);
510 521
511 if (!event_str) 522 if (!event_str)
512 return 0; 523 return 0;
513 524
525 if (sample->cpu > numcpus)
526 numcpus = sample->cpu;
527
514 if (strcmp(event_str, "power:cpu_idle") == 0) { 528 if (strcmp(event_str, "power:cpu_idle") == 0) {
515 struct power_processor_entry *ppe = (void *)te; 529 struct power_processor_entry *ppe = (void *)te;
516 if (ppe->state == (u32)PWR_EVENT_EXIT) 530 if (ppe->state == (u32)PWR_EVENT_EXIT)
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index b6998e055767..fc1273e976c5 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -20,11 +20,16 @@
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"
24#include "util/evsel.h" 27#include "util/evsel.h"
25#include "util/session.h" 28#include "util/session.h"
26#include "util/symbol.h" 29#include "util/symbol.h"
27#include "util/thread.h" 30#include "util/thread.h"
31#include "util/thread_map.h"
32#include "util/top.h"
28#include "util/util.h" 33#include "util/util.h"
29#include <linux/rbtree.h> 34#include <linux/rbtree.h>
30#include "util/parse-options.h" 35#include "util/parse-options.h"
@@ -45,7 +50,6 @@
45#include <errno.h> 50#include <errno.h>
46#include <time.h> 51#include <time.h>
47#include <sched.h> 52#include <sched.h>
48#include <pthread.h>
49 53
50#include <sys/syscall.h> 54#include <sys/syscall.h>
51#include <sys/ioctl.h> 55#include <sys/ioctl.h>
@@ -60,85 +64,42 @@
60 64
61#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) 65#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
62 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};
78
63static bool system_wide = false; 79static bool system_wide = false;
64 80
65static int default_interval = 0; 81static bool use_tui, use_stdio;
66 82
67static int count_filter = 5; 83static int default_interval = 0;
68static int print_entries;
69 84
70static int target_pid = -1;
71static int target_tid = -1;
72static struct thread_map *threads;
73static bool inherit = false; 85static bool inherit = false;
74static struct cpu_map *cpus;
75static int realtime_prio = 0; 86static int realtime_prio = 0;
76static bool group = false; 87static bool group = false;
77static unsigned int page_size; 88static unsigned int page_size;
78static unsigned int mmap_pages = 16; 89static unsigned int mmap_pages = 128;
79static int freq = 1000; /* 1 KHz */
80 90
81static int delay_secs = 2;
82static bool zero = false;
83static bool dump_symtab = false; 91static bool dump_symtab = false;
84 92
85static bool hide_kernel_symbols = false;
86static bool hide_user_symbols = false;
87static struct winsize winsize; 93static struct winsize winsize;
88 94
89/*
90 * Source
91 */
92
93struct source_line {
94 u64 eip;
95 unsigned long count[MAX_COUNTERS];
96 char *line;
97 struct source_line *next;
98};
99
100static const char *sym_filter = NULL; 95static const char *sym_filter = NULL;
101struct sym_entry *sym_filter_entry = NULL;
102struct sym_entry *sym_filter_entry_sched = NULL; 96struct sym_entry *sym_filter_entry_sched = NULL;
103static int sym_pcnt_filter = 5; 97static int sym_pcnt_filter = 5;
104static int sym_counter = 0;
105static struct perf_evsel *sym_evsel = NULL;
106static int display_weighted = -1;
107static const char *cpu_list;
108
109/*
110 * Symbols
111 */
112
113struct sym_entry_source {
114 struct source_line *source;
115 struct source_line *lines;
116 struct source_line **lines_tail;
117 pthread_mutex_t lock;
118};
119
120struct sym_entry {
121 struct rb_node rb_node;
122 struct list_head node;
123 unsigned long snap_count;
124 double weight;
125 int skip;
126 u16 name_len;
127 u8 origin;
128 struct map *map;
129 struct sym_entry_source *src;
130 unsigned long count[0];
131};
132 98
133/* 99/*
134 * Source functions 100 * Source functions
135 */ 101 */
136 102
137static inline struct symbol *sym_entry__symbol(struct sym_entry *self)
138{
139 return ((void *)self) + symbol_conf.priv_size;
140}
141
142void get_term_dimensions(struct winsize *ws) 103void get_term_dimensions(struct winsize *ws)
143{ 104{
144 char *s = getenv("LINES"); 105 char *s = getenv("LINES");
@@ -163,10 +124,10 @@ void get_term_dimensions(struct winsize *ws)
163 124
164static void update_print_entries(struct winsize *ws) 125static void update_print_entries(struct winsize *ws)
165{ 126{
166 print_entries = ws->ws_row; 127 top.print_entries = ws->ws_row;
167 128
168 if (print_entries > 9) 129 if (top.print_entries > 9)
169 print_entries -= 9; 130 top.print_entries -= 9;
170} 131}
171 132
172static void sig_winch_handler(int sig __used) 133static void sig_winch_handler(int sig __used)
@@ -178,12 +139,9 @@ static void sig_winch_handler(int sig __used)
178static int parse_source(struct sym_entry *syme) 139static int parse_source(struct sym_entry *syme)
179{ 140{
180 struct symbol *sym; 141 struct symbol *sym;
181 struct sym_entry_source *source; 142 struct annotation *notes;
182 struct map *map; 143 struct map *map;
183 FILE *file; 144 int err = -1;
184 char command[PATH_MAX*2];
185 const char *path;
186 u64 len;
187 145
188 if (!syme) 146 if (!syme)
189 return -1; 147 return -1;
@@ -194,411 +152,137 @@ static int parse_source(struct sym_entry *syme)
194 /* 152 /*
195 * We can't annotate with just /proc/kallsyms 153 * We can't annotate with just /proc/kallsyms
196 */ 154 */
197 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);
198 return -1; 159 return -1;
199
200 if (syme->src == NULL) {
201 syme->src = zalloc(sizeof(*source));
202 if (syme->src == NULL)
203 return -1;
204 pthread_mutex_init(&syme->src->lock, NULL);
205 } 160 }
206 161
207 source = syme->src; 162 notes = symbol__annotation(sym);
208 163 if (notes->src != NULL) {
209 if (source->lines) { 164 pthread_mutex_lock(&notes->lock);
210 pthread_mutex_lock(&source->lock);
211 goto out_assign; 165 goto out_assign;
212 } 166 }
213 path = map->dso->long_name;
214
215 len = sym->end - sym->start;
216
217 sprintf(command,
218 "objdump --start-address=%#0*" PRIx64 " --stop-address=%#0*" PRIx64 " -dS %s",
219 BITS_PER_LONG / 4, map__rip_2objdump(map, sym->start),
220 BITS_PER_LONG / 4, map__rip_2objdump(map, sym->end), path);
221
222 file = popen(command, "r");
223 if (!file)
224 return -1;
225
226 pthread_mutex_lock(&source->lock);
227 source->lines_tail = &source->lines;
228 while (!feof(file)) {
229 struct source_line *src;
230 size_t dummy = 0;
231 char *c, *sep;
232 167
233 src = malloc(sizeof(struct source_line)); 168 pthread_mutex_lock(&notes->lock);
234 assert(src != NULL);
235 memset(src, 0, sizeof(struct source_line));
236 169
237 if (getline(&src->line, &dummy, file) < 0) 170 if (symbol__alloc_hist(sym, top.evlist->nr_entries) < 0) {
238 break; 171 pthread_mutex_unlock(&notes->lock);
239 if (!src->line) 172 pr_err("Not enough memory for annotating '%s' symbol!\n",
240 break; 173 sym->name);
241 174 sleep(1);
242 c = strchr(src->line, '\n'); 175 return err;
243 if (c)
244 *c = 0;
245
246 src->next = NULL;
247 *source->lines_tail = src;
248 source->lines_tail = &src->next;
249
250 src->eip = strtoull(src->line, &sep, 16);
251 if (*sep == ':')
252 src->eip = map__objdump_2ip(map, src->eip);
253 else /* this line has no ip info (e.g. source line) */
254 src->eip = 0;
255 } 176 }
256 pclose(file); 177
178 err = symbol__annotate(sym, syme->map, 0);
179 if (err == 0) {
257out_assign: 180out_assign:
258 sym_filter_entry = syme; 181 top.sym_filter_entry = syme;
259 pthread_mutex_unlock(&source->lock); 182 }
260 return 0; 183
184 pthread_mutex_unlock(&notes->lock);
185 return err;
261} 186}
262 187
263static void __zero_source_counters(struct sym_entry *syme) 188static void __zero_source_counters(struct sym_entry *syme)
264{ 189{
265 int i; 190 struct symbol *sym = sym_entry__symbol(syme);
266 struct source_line *line; 191 symbol__annotate_zero_histograms(sym);
267
268 line = syme->src->lines;
269 while (line) {
270 for (i = 0; i < nr_counters; i++)
271 line->count[i] = 0;
272 line = line->next;
273 }
274} 192}
275 193
276static 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)
277{ 195{
278 struct source_line *line; 196 struct annotation *notes;
279 197 struct symbol *sym;
280 if (syme != sym_filter_entry)
281 return;
282 198
283 if (pthread_mutex_trylock(&syme->src->lock)) 199 if (syme != top.sym_filter_entry)
284 return; 200 return;
285 201
286 if (syme->src == NULL || syme->src->source == NULL) 202 sym = sym_entry__symbol(syme);
287 goto out_unlock; 203 notes = symbol__annotation(sym);
288
289 for (line = syme->src->lines; line; line = line->next) {
290 /* skip lines without IP info */
291 if (line->eip == 0)
292 continue;
293 if (line->eip == ip) {
294 line->count[counter]++;
295 break;
296 }
297 if (line->eip > ip)
298 break;
299 }
300out_unlock:
301 pthread_mutex_unlock(&syme->src->lock);
302}
303
304#define PATTERN_LEN (BITS_PER_LONG / 4 + 2)
305
306static void lookup_sym_source(struct sym_entry *syme)
307{
308 struct symbol *symbol = sym_entry__symbol(syme);
309 struct source_line *line;
310 char pattern[PATTERN_LEN + 1];
311
312 sprintf(pattern, "%0*" PRIx64 " <", BITS_PER_LONG / 4,
313 map__rip_2objdump(syme->map, symbol->start));
314
315 pthread_mutex_lock(&syme->src->lock);
316 for (line = syme->src->lines; line; line = line->next) {
317 if (memcmp(line->line, pattern, PATTERN_LEN) == 0) {
318 syme->src->source = line;
319 break;
320 }
321 }
322 pthread_mutex_unlock(&syme->src->lock);
323}
324 204
325static void show_lines(struct source_line *queue, int count, int total) 205 if (pthread_mutex_trylock(&notes->lock))
326{ 206 return;
327 int i;
328 struct source_line *line;
329 207
330 line = queue; 208 ip = syme->map->map_ip(syme->map, ip);
331 for (i = 0; i < count; i++) { 209 symbol__inc_addr_samples(sym, syme->map, counter, ip);
332 float pcnt = 100.0*(float)line->count[sym_counter]/(float)total;
333 210
334 printf("%8li %4.1f%%\t%s\n", line->count[sym_counter], pcnt, line->line); 211 pthread_mutex_unlock(&notes->lock);
335 line = line->next;
336 }
337} 212}
338 213
339#define TRACE_COUNT 3
340
341static void show_details(struct sym_entry *syme) 214static void show_details(struct sym_entry *syme)
342{ 215{
216 struct annotation *notes;
343 struct symbol *symbol; 217 struct symbol *symbol;
344 struct source_line *line; 218 int more;
345 struct source_line *line_queue = NULL;
346 int displayed = 0;
347 int line_queue_count = 0, total = 0, more = 0;
348 219
349 if (!syme) 220 if (!syme)
350 return; 221 return;
351 222
352 if (!syme->src->source)
353 lookup_sym_source(syme);
354
355 if (!syme->src->source)
356 return;
357
358 symbol = sym_entry__symbol(syme); 223 symbol = sym_entry__symbol(syme);
359 printf("Showing %s for %s\n", event_name(sym_evsel), symbol->name); 224 notes = symbol__annotation(symbol);
360 printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter);
361
362 pthread_mutex_lock(&syme->src->lock);
363 line = syme->src->source;
364 while (line) {
365 total += line->count[sym_counter];
366 line = line->next;
367 }
368
369 line = syme->src->source;
370 while (line) {
371 float pcnt = 0.0;
372
373 if (!line_queue_count)
374 line_queue = line;
375 line_queue_count++;
376
377 if (line->count[sym_counter])
378 pcnt = 100.0 * line->count[sym_counter] / (float)total;
379 if (pcnt >= (float)sym_pcnt_filter) {
380 if (displayed <= print_entries)
381 show_lines(line_queue, line_queue_count, total);
382 else more++;
383 displayed += line_queue_count;
384 line_queue_count = 0;
385 line_queue = NULL;
386 } else if (line_queue_count > TRACE_COUNT) {
387 line_queue = line_queue->next;
388 line_queue_count--;
389 }
390
391 line->count[sym_counter] = zero ? 0 : line->count[sym_counter] * 7 / 8;
392 line = line->next;
393 }
394 pthread_mutex_unlock(&syme->src->lock);
395 if (more)
396 printf("%d lines not displayed, maybe increase display entries [e]\n", more);
397}
398
399/*
400 * Symbols will be added here in event__process_sample and will get out
401 * after decayed.
402 */
403static LIST_HEAD(active_symbols);
404static pthread_mutex_t active_symbols_lock = PTHREAD_MUTEX_INITIALIZER;
405 225
406/* 226 pthread_mutex_lock(&notes->lock);
407 * Ordering weight: count-1 * count-2 * ... / count-n
408 */
409static double sym_weight(const struct sym_entry *sym)
410{
411 double weight = sym->snap_count;
412 int counter;
413 227
414 if (!display_weighted) 228 if (notes->src == NULL)
415 return weight; 229 goto out_unlock;
416
417 for (counter = 1; counter < nr_counters-1; counter++)
418 weight *= sym->count[counter];
419 230
420 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);
421 233
422 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);
423} 244}
424 245
425static long samples;
426static long kernel_samples, us_samples;
427static long exact_samples;
428static long guest_us_samples, guest_kernel_samples;
429static const char CONSOLE_CLEAR[] = ""; 246static const char CONSOLE_CLEAR[] = "";
430 247
431static void __list_insert_active_sym(struct sym_entry *syme) 248static void __list_insert_active_sym(struct sym_entry *syme)
432{ 249{
433 list_add(&syme->node, &active_symbols); 250 list_add(&syme->node, &top.active_symbols);
434} 251}
435 252
436static void list_remove_active_sym(struct sym_entry *syme) 253static void print_sym_table(struct perf_session *session)
437{ 254{
438 pthread_mutex_lock(&active_symbols_lock); 255 char bf[160];
439 list_del_init(&syme->node); 256 int printed = 0;
440 pthread_mutex_unlock(&active_symbols_lock);
441}
442
443static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se)
444{
445 struct rb_node **p = &tree->rb_node;
446 struct rb_node *parent = NULL;
447 struct sym_entry *iter;
448
449 while (*p != NULL) {
450 parent = *p;
451 iter = rb_entry(parent, struct sym_entry, rb_node);
452
453 if (se->weight > iter->weight)
454 p = &(*p)->rb_left;
455 else
456 p = &(*p)->rb_right;
457 }
458
459 rb_link_node(&se->rb_node, parent, p);
460 rb_insert_color(&se->rb_node, tree);
461}
462
463static void print_sym_table(void)
464{
465 int printed = 0, j;
466 struct perf_evsel *counter;
467 int snap = !display_weighted ? sym_counter : 0;
468 float samples_per_sec = samples/delay_secs;
469 float ksamples_per_sec = kernel_samples/delay_secs;
470 float us_samples_per_sec = (us_samples)/delay_secs;
471 float guest_kernel_samples_per_sec = (guest_kernel_samples)/delay_secs;
472 float guest_us_samples_per_sec = (guest_us_samples)/delay_secs;
473 float esamples_percent = (100.0*exact_samples)/samples;
474 float sum_ksamples = 0.0;
475 struct sym_entry *syme, *n;
476 struct rb_root tmp = RB_ROOT;
477 struct rb_node *nd; 257 struct rb_node *nd;
478 int sym_width = 0, dso_width = 0, dso_short_width = 0; 258 struct sym_entry *syme;
259 struct rb_root tmp = RB_ROOT;
479 const int win_width = winsize.ws_col - 1; 260 const int win_width = winsize.ws_col - 1;
480 261 int sym_width, dso_width, dso_short_width;
481 samples = us_samples = kernel_samples = exact_samples = 0; 262 float sum_ksamples = perf_top__decay_samples(&top, &tmp);
482 guest_kernel_samples = guest_us_samples = 0;
483
484 /* Sort the active symbols */
485 pthread_mutex_lock(&active_symbols_lock);
486 syme = list_entry(active_symbols.next, struct sym_entry, node);
487 pthread_mutex_unlock(&active_symbols_lock);
488
489 list_for_each_entry_safe_from(syme, n, &active_symbols, node) {
490 syme->snap_count = syme->count[snap];
491 if (syme->snap_count != 0) {
492
493 if ((hide_user_symbols &&
494 syme->origin == PERF_RECORD_MISC_USER) ||
495 (hide_kernel_symbols &&
496 syme->origin == PERF_RECORD_MISC_KERNEL)) {
497 list_remove_active_sym(syme);
498 continue;
499 }
500 syme->weight = sym_weight(syme);
501 rb_insert_active_sym(&tmp, syme);
502 sum_ksamples += syme->snap_count;
503
504 for (j = 0; j < nr_counters; j++)
505 syme->count[j] = zero ? 0 : syme->count[j] * 7 / 8;
506 } else
507 list_remove_active_sym(syme);
508 }
509 263
510 puts(CONSOLE_CLEAR); 264 puts(CONSOLE_CLEAR);
511 265
512 printf("%-*.*s\n", win_width, win_width, graph_dotted_line); 266 perf_top__header_snprintf(&top, bf, sizeof(bf));
513 if (!perf_guest) { 267 printf("%s\n", bf);
514 printf(" PerfTop:%8.0f irqs/sec kernel:%4.1f%%"
515 " exact: %4.1f%% [",
516 samples_per_sec,
517 100.0 - (100.0 * ((samples_per_sec - ksamples_per_sec) /
518 samples_per_sec)),
519 esamples_percent);
520 } else {
521 printf(" PerfTop:%8.0f irqs/sec kernel:%4.1f%% us:%4.1f%%"
522 " guest kernel:%4.1f%% guest us:%4.1f%%"
523 " exact: %4.1f%% [",
524 samples_per_sec,
525 100.0 - (100.0 * ((samples_per_sec-ksamples_per_sec) /
526 samples_per_sec)),
527 100.0 - (100.0 * ((samples_per_sec-us_samples_per_sec) /
528 samples_per_sec)),
529 100.0 - (100.0 * ((samples_per_sec -
530 guest_kernel_samples_per_sec) /
531 samples_per_sec)),
532 100.0 - (100.0 * ((samples_per_sec -
533 guest_us_samples_per_sec) /
534 samples_per_sec)),
535 esamples_percent);
536 }
537
538 if (nr_counters == 1 || !display_weighted) {
539 struct perf_evsel *first;
540 first = list_entry(evsel_list.next, struct perf_evsel, node);
541 printf("%" PRIu64, (uint64_t)first->attr.sample_period);
542 if (freq)
543 printf("Hz ");
544 else
545 printf(" ");
546 }
547 268
548 if (!display_weighted) 269 perf_top__reset_sample_counters(&top);
549 printf("%s", event_name(sym_evsel));
550 else list_for_each_entry(counter, &evsel_list, node) {
551 if (counter->idx)
552 printf("/");
553
554 printf("%s", event_name(counter));
555 }
556
557 printf( "], ");
558
559 if (target_pid != -1)
560 printf(" (target_pid: %d", target_pid);
561 else if (target_tid != -1)
562 printf(" (target_tid: %d", target_tid);
563 else
564 printf(" (all");
565
566 if (cpu_list)
567 printf(", CPU%s: %s)\n", cpus->nr > 1 ? "s" : "", cpu_list);
568 else {
569 if (target_tid != -1)
570 printf(")\n");
571 else
572 printf(", %d CPU%s)\n", cpus->nr, cpus->nr > 1 ? "s" : "");
573 }
574 270
575 printf("%-*.*s\n", win_width, win_width, graph_dotted_line); 271 printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
576 272
577 if (sym_filter_entry) { 273 if (session->hists.stats.total_lost != 0) {
578 show_details(sym_filter_entry); 274 color_fprintf(stdout, PERF_COLOR_RED, "WARNING:");
579 return; 275 printf(" LOST %" PRIu64 " events, Check IO/CPU overload\n",
276 session->hists.stats.total_lost);
580 } 277 }
581 278
582 /* 279 if (top.sym_filter_entry) {
583 * Find the longest symbol name that will be displayed 280 show_details(top.sym_filter_entry);
584 */ 281 return;
585 for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
586 syme = rb_entry(nd, struct sym_entry, rb_node);
587 if (++printed > print_entries ||
588 (int)syme->snap_count < count_filter)
589 continue;
590
591 if (syme->map->dso->long_name_len > dso_width)
592 dso_width = syme->map->dso->long_name_len;
593
594 if (syme->map->dso->short_name_len > dso_short_width)
595 dso_short_width = syme->map->dso->short_name_len;
596
597 if (syme->name_len > sym_width)
598 sym_width = syme->name_len;
599 } 282 }
600 283
601 printed = 0; 284 perf_top__find_widths(&top, &tmp, &dso_width, &dso_short_width,
285 &sym_width);
602 286
603 if (sym_width + dso_width > winsize.ws_col - 29) { 287 if (sym_width + dso_width > winsize.ws_col - 29) {
604 dso_width = dso_short_width; 288 dso_width = dso_short_width;
@@ -606,7 +290,7 @@ static void print_sym_table(void)
606 sym_width = winsize.ws_col - dso_width - 29; 290 sym_width = winsize.ws_col - dso_width - 29;
607 } 291 }
608 putchar('\n'); 292 putchar('\n');
609 if (nr_counters == 1) 293 if (top.evlist->nr_entries == 1)
610 printf(" samples pcnt"); 294 printf(" samples pcnt");
611 else 295 else
612 printf(" weight samples pcnt"); 296 printf(" weight samples pcnt");
@@ -615,7 +299,7 @@ static void print_sym_table(void)
615 printf(" RIP "); 299 printf(" RIP ");
616 printf(" %-*.*s DSO\n", sym_width, sym_width, "function"); 300 printf(" %-*.*s DSO\n", sym_width, sym_width, "function");
617 printf(" %s _______ _____", 301 printf(" %s _______ _____",
618 nr_counters == 1 ? " " : "______"); 302 top.evlist->nr_entries == 1 ? " " : "______");
619 if (verbose) 303 if (verbose)
620 printf(" ________________"); 304 printf(" ________________");
621 printf(" %-*.*s", sym_width, sym_width, graph_line); 305 printf(" %-*.*s", sym_width, sym_width, graph_line);
@@ -628,13 +312,14 @@ static void print_sym_table(void)
628 312
629 syme = rb_entry(nd, struct sym_entry, rb_node); 313 syme = rb_entry(nd, struct sym_entry, rb_node);
630 sym = sym_entry__symbol(syme); 314 sym = sym_entry__symbol(syme);
631 if (++printed > print_entries || (int)syme->snap_count < count_filter) 315 if (++printed > top.print_entries ||
316 (int)syme->snap_count < top.count_filter)
632 continue; 317 continue;
633 318
634 pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) / 319 pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) /
635 sum_ksamples)); 320 sum_ksamples));
636 321
637 if (nr_counters == 1 || !display_weighted) 322 if (top.evlist->nr_entries == 1 || !top.display_weighted)
638 printf("%20.2f ", syme->weight); 323 printf("%20.2f ", syme->weight);
639 else 324 else
640 printf("%9.1f %10ld ", syme->weight, syme->snap_count); 325 printf("%9.1f %10ld ", syme->weight, syme->snap_count);
@@ -693,10 +378,8 @@ static void prompt_symbol(struct sym_entry **target, const char *msg)
693 378
694 /* zero counters of active symbol */ 379 /* zero counters of active symbol */
695 if (syme) { 380 if (syme) {
696 pthread_mutex_lock(&syme->src->lock);
697 __zero_source_counters(syme); 381 __zero_source_counters(syme);
698 *target = NULL; 382 *target = NULL;
699 pthread_mutex_unlock(&syme->src->lock);
700 } 383 }
701 384
702 fprintf(stdout, "\n%s: ", msg); 385 fprintf(stdout, "\n%s: ", msg);
@@ -707,11 +390,11 @@ static void prompt_symbol(struct sym_entry **target, const char *msg)
707 if (p) 390 if (p)
708 *p = 0; 391 *p = 0;
709 392
710 pthread_mutex_lock(&active_symbols_lock); 393 pthread_mutex_lock(&top.active_symbols_lock);
711 syme = list_entry(active_symbols.next, struct sym_entry, node); 394 syme = list_entry(top.active_symbols.next, struct sym_entry, node);
712 pthread_mutex_unlock(&active_symbols_lock); 395 pthread_mutex_unlock(&top.active_symbols_lock);
713 396
714 list_for_each_entry_safe_from(syme, n, &active_symbols, node) { 397 list_for_each_entry_safe_from(syme, n, &top.active_symbols, node) {
715 struct symbol *sym = sym_entry__symbol(syme); 398 struct symbol *sym = sym_entry__symbol(syme);
716 399
717 if (!strcmp(buf, sym->name)) { 400 if (!strcmp(buf, sym->name)) {
@@ -735,34 +418,34 @@ static void print_mapped_keys(void)
735{ 418{
736 char *name = NULL; 419 char *name = NULL;
737 420
738 if (sym_filter_entry) { 421 if (top.sym_filter_entry) {
739 struct symbol *sym = sym_entry__symbol(sym_filter_entry); 422 struct symbol *sym = sym_entry__symbol(top.sym_filter_entry);
740 name = sym->name; 423 name = sym->name;
741 } 424 }
742 425
743 fprintf(stdout, "\nMapped keys:\n"); 426 fprintf(stdout, "\nMapped keys:\n");
744 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);
745 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);
746 429
747 if (nr_counters > 1) 430 if (top.evlist->nr_entries > 1)
748 fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(sym_evsel)); 431 fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(top.sym_evsel));
749 432
750 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);
751 434
752 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);
753 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); 436 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL");
754 fprintf(stdout, "\t[S] stop annotation.\n"); 437 fprintf(stdout, "\t[S] stop annotation.\n");
755 438
756 if (nr_counters > 1) 439 if (top.evlist->nr_entries > 1)
757 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);
758 441
759 fprintf(stdout, 442 fprintf(stdout,
760 "\t[K] hide kernel_symbols symbols. \t(%s)\n", 443 "\t[K] hide kernel_symbols symbols. \t(%s)\n",
761 hide_kernel_symbols ? "yes" : "no"); 444 top.hide_kernel_symbols ? "yes" : "no");
762 fprintf(stdout, 445 fprintf(stdout,
763 "\t[U] hide user symbols. \t(%s)\n", 446 "\t[U] hide user symbols. \t(%s)\n",
764 hide_user_symbols ? "yes" : "no"); 447 top.hide_user_symbols ? "yes" : "no");
765 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);
766 fprintf(stdout, "\t[qQ] quit.\n"); 449 fprintf(stdout, "\t[qQ] quit.\n");
767} 450}
768 451
@@ -783,7 +466,7 @@ static int key_mapped(int c)
783 return 1; 466 return 1;
784 case 'E': 467 case 'E':
785 case 'w': 468 case 'w':
786 return nr_counters > 1 ? 1 : 0; 469 return top.evlist->nr_entries > 1 ? 1 : 0;
787 default: 470 default:
788 break; 471 break;
789 } 472 }
@@ -818,47 +501,50 @@ static void handle_keypress(struct perf_session *session, int c)
818 501
819 switch (c) { 502 switch (c) {
820 case 'd': 503 case 'd':
821 prompt_integer(&delay_secs, "Enter display delay"); 504 prompt_integer(&top.delay_secs, "Enter display delay");
822 if (delay_secs < 1) 505 if (top.delay_secs < 1)
823 delay_secs = 1; 506 top.delay_secs = 1;
824 break; 507 break;
825 case 'e': 508 case 'e':
826 prompt_integer(&print_entries, "Enter display entries (lines)"); 509 prompt_integer(&top.print_entries, "Enter display entries (lines)");
827 if (print_entries == 0) { 510 if (top.print_entries == 0) {
828 sig_winch_handler(SIGWINCH); 511 sig_winch_handler(SIGWINCH);
829 signal(SIGWINCH, sig_winch_handler); 512 signal(SIGWINCH, sig_winch_handler);
830 } else 513 } else
831 signal(SIGWINCH, SIG_DFL); 514 signal(SIGWINCH, SIG_DFL);
832 break; 515 break;
833 case 'E': 516 case 'E':
834 if (nr_counters > 1) { 517 if (top.evlist->nr_entries > 1) {
518 /* Select 0 as the default event: */
519 int counter = 0;
520
835 fprintf(stderr, "\nAvailable events:"); 521 fprintf(stderr, "\nAvailable events:");
836 522
837 list_for_each_entry(sym_evsel, &evsel_list, node) 523 list_for_each_entry(top.sym_evsel, &top.evlist->entries, node)
838 fprintf(stderr, "\n\t%d %s", sym_evsel->idx, event_name(sym_evsel)); 524 fprintf(stderr, "\n\t%d %s", top.sym_evsel->idx, event_name(top.sym_evsel));
839 525
840 prompt_integer(&sym_counter, "Enter details event counter"); 526 prompt_integer(&counter, "Enter details event counter");
841 527
842 if (sym_counter >= nr_counters) { 528 if (counter >= top.evlist->nr_entries) {
843 sym_evsel = list_entry(evsel_list.next, struct perf_evsel, node); 529 top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node);
844 sym_counter = 0; 530 fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(top.sym_evsel));
845 fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(sym_evsel));
846 sleep(1); 531 sleep(1);
847 break; 532 break;
848 } 533 }
849 list_for_each_entry(sym_evsel, &evsel_list, node) 534 list_for_each_entry(top.sym_evsel, &top.evlist->entries, node)
850 if (sym_evsel->idx == sym_counter) 535 if (top.sym_evsel->idx == counter)
851 break; 536 break;
852 } else sym_counter = 0; 537 } else
538 top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node);
853 break; 539 break;
854 case 'f': 540 case 'f':
855 prompt_integer(&count_filter, "Enter display event count filter"); 541 prompt_integer(&top.count_filter, "Enter display event count filter");
856 break; 542 break;
857 case 'F': 543 case 'F':
858 prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)"); 544 prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)");
859 break; 545 break;
860 case 'K': 546 case 'K':
861 hide_kernel_symbols = !hide_kernel_symbols; 547 top.hide_kernel_symbols = !top.hide_kernel_symbols;
862 break; 548 break;
863 case 'q': 549 case 'q':
864 case 'Q': 550 case 'Q':
@@ -867,34 +553,50 @@ static void handle_keypress(struct perf_session *session, int c)
867 perf_session__fprintf_dsos(session, stderr); 553 perf_session__fprintf_dsos(session, stderr);
868 exit(0); 554 exit(0);
869 case 's': 555 case 's':
870 prompt_symbol(&sym_filter_entry, "Enter details symbol"); 556 prompt_symbol(&top.sym_filter_entry, "Enter details symbol");
871 break; 557 break;
872 case 'S': 558 case 'S':
873 if (!sym_filter_entry) 559 if (!top.sym_filter_entry)
874 break; 560 break;
875 else { 561 else {
876 struct sym_entry *syme = sym_filter_entry; 562 struct sym_entry *syme = top.sym_filter_entry;
877 563
878 pthread_mutex_lock(&syme->src->lock); 564 top.sym_filter_entry = NULL;
879 sym_filter_entry = NULL;
880 __zero_source_counters(syme); 565 __zero_source_counters(syme);
881 pthread_mutex_unlock(&syme->src->lock);
882 } 566 }
883 break; 567 break;
884 case 'U': 568 case 'U':
885 hide_user_symbols = !hide_user_symbols; 569 top.hide_user_symbols = !top.hide_user_symbols;
886 break; 570 break;
887 case 'w': 571 case 'w':
888 display_weighted = ~display_weighted; 572 top.display_weighted = ~top.display_weighted;
889 break; 573 break;
890 case 'z': 574 case 'z':
891 zero = !zero; 575 top.zero = !top.zero;
892 break; 576 break;
893 default: 577 default:
894 break; 578 break;
895 } 579 }
896} 580}
897 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
898static void *display_thread(void *arg __used) 600static void *display_thread(void *arg __used)
899{ 601{
900 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; 602 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
@@ -909,13 +611,13 @@ static void *display_thread(void *arg __used)
909 tc.c_cc[VTIME] = 0; 611 tc.c_cc[VTIME] = 0;
910 612
911repeat: 613repeat:
912 delay_msecs = delay_secs * 1000; 614 delay_msecs = top.delay_secs * 1000;
913 tcsetattr(0, TCSANOW, &tc); 615 tcsetattr(0, TCSANOW, &tc);
914 /* trash return*/ 616 /* trash return*/
915 getc(stdin); 617 getc(stdin);
916 618
917 do { 619 do {
918 print_sym_table(); 620 print_sym_table(session);
919 } while (!poll(&stdin_poll, 1, delay_msecs) == 1); 621 } while (!poll(&stdin_poll, 1, delay_msecs) == 1);
920 622
921 c = getc(stdin); 623 c = getc(stdin);
@@ -930,6 +632,7 @@ repeat:
930/* Tag samples to be skipped. */ 632/* Tag samples to be skipped. */
931static const char *skip_symbols[] = { 633static const char *skip_symbols[] = {
932 "default_idle", 634 "default_idle",
635 "native_safe_halt",
933 "cpu_idle", 636 "cpu_idle",
934 "enter_idle", 637 "enter_idle",
935 "exit_idle", 638 "exit_idle",
@@ -965,9 +668,9 @@ static int symbol_filter(struct map *map, struct symbol *sym)
965 668
966 syme = symbol__priv(sym); 669 syme = symbol__priv(sym);
967 syme->map = map; 670 syme->map = map;
968 syme->src = NULL; 671 symbol__annotate_init(map, sym);
969 672
970 if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) { 673 if (!top.sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) {
971 /* schedule initial sym_filter_entry setup */ 674 /* schedule initial sym_filter_entry setup */
972 sym_filter_entry_sched = syme; 675 sym_filter_entry_sched = syme;
973 sym_filter = NULL; 676 sym_filter = NULL;
@@ -975,49 +678,45 @@ static int symbol_filter(struct map *map, struct symbol *sym)
975 678
976 for (i = 0; skip_symbols[i]; i++) { 679 for (i = 0; skip_symbols[i]; i++) {
977 if (!strcmp(skip_symbols[i], name)) { 680 if (!strcmp(skip_symbols[i], name)) {
978 syme->skip = 1; 681 sym->ignore = true;
979 break; 682 break;
980 } 683 }
981 } 684 }
982 685
983 if (!syme->skip)
984 syme->name_len = strlen(sym->name);
985
986 return 0; 686 return 0;
987} 687}
988 688
989static void event__process_sample(const event_t *self, 689static void perf_event__process_sample(const union perf_event *event,
990 struct sample_data *sample, 690 struct perf_sample *sample,
991 struct perf_session *session, 691 struct perf_session *session)
992 struct perf_evsel *evsel)
993{ 692{
994 u64 ip = self->ip.ip; 693 u64 ip = event->ip.ip;
995 struct sym_entry *syme; 694 struct sym_entry *syme;
996 struct addr_location al; 695 struct addr_location al;
997 struct machine *machine; 696 struct machine *machine;
998 u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 697 u8 origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
999 698
1000 ++samples; 699 ++top.samples;
1001 700
1002 switch (origin) { 701 switch (origin) {
1003 case PERF_RECORD_MISC_USER: 702 case PERF_RECORD_MISC_USER:
1004 ++us_samples; 703 ++top.us_samples;
1005 if (hide_user_symbols) 704 if (top.hide_user_symbols)
1006 return; 705 return;
1007 machine = perf_session__find_host_machine(session); 706 machine = perf_session__find_host_machine(session);
1008 break; 707 break;
1009 case PERF_RECORD_MISC_KERNEL: 708 case PERF_RECORD_MISC_KERNEL:
1010 ++kernel_samples; 709 ++top.kernel_samples;
1011 if (hide_kernel_symbols) 710 if (top.hide_kernel_symbols)
1012 return; 711 return;
1013 machine = perf_session__find_host_machine(session); 712 machine = perf_session__find_host_machine(session);
1014 break; 713 break;
1015 case PERF_RECORD_MISC_GUEST_KERNEL: 714 case PERF_RECORD_MISC_GUEST_KERNEL:
1016 ++guest_kernel_samples; 715 ++top.guest_kernel_samples;
1017 machine = perf_session__find_machine(session, self->ip.pid); 716 machine = perf_session__find_machine(session, event->ip.pid);
1018 break; 717 break;
1019 case PERF_RECORD_MISC_GUEST_USER: 718 case PERF_RECORD_MISC_GUEST_USER:
1020 ++guest_us_samples; 719 ++top.guest_us_samples;
1021 /* 720 /*
1022 * TODO: we don't process guest user from host side 721 * TODO: we don't process guest user from host side
1023 * except simple counting. 722 * except simple counting.
@@ -1029,15 +728,15 @@ static void event__process_sample(const event_t *self,
1029 728
1030 if (!machine && perf_guest) { 729 if (!machine && perf_guest) {
1031 pr_err("Can't find guest [%d]'s kernel information\n", 730 pr_err("Can't find guest [%d]'s kernel information\n",
1032 self->ip.pid); 731 event->ip.pid);
1033 return; 732 return;
1034 } 733 }
1035 734
1036 if (self->header.misc & PERF_RECORD_MISC_EXACT_IP) 735 if (event->header.misc & PERF_RECORD_MISC_EXACT_IP)
1037 exact_samples++; 736 top.exact_samples++;
1038 737
1039 if (event__preprocess_sample(self, session, &al, sample, 738 if (perf_event__preprocess_sample(event, session, &al, sample,
1040 symbol_filter) < 0 || 739 symbol_filter) < 0 ||
1041 al.filtered) 740 al.filtered)
1042 return; 741 return;
1043 742
@@ -1055,8 +754,9 @@ static void event__process_sample(const event_t *self,
1055 */ 754 */
1056 if (al.map == machine->vmlinux_maps[MAP__FUNCTION] && 755 if (al.map == machine->vmlinux_maps[MAP__FUNCTION] &&
1057 RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) { 756 RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) {
1058 pr_err("The %s file can't be used\n", 757 ui__warning("The %s file can't be used\n",
1059 symbol_conf.vmlinux_name); 758 symbol_conf.vmlinux_name);
759 exit_browser(0);
1060 exit(1); 760 exit(1);
1061 } 761 }
1062 762
@@ -1065,13 +765,13 @@ static void event__process_sample(const event_t *self,
1065 765
1066 /* 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 */
1067 if (sym_filter_entry_sched) { 767 if (sym_filter_entry_sched) {
1068 sym_filter_entry = sym_filter_entry_sched; 768 top.sym_filter_entry = sym_filter_entry_sched;
1069 sym_filter_entry_sched = NULL; 769 sym_filter_entry_sched = NULL;
1070 if (parse_source(sym_filter_entry) < 0) { 770 if (parse_source(top.sym_filter_entry) < 0) {
1071 struct symbol *sym = sym_entry__symbol(sym_filter_entry); 771 struct symbol *sym = sym_entry__symbol(top.sym_filter_entry);
1072 772
1073 pr_err("Can't annotate %s", sym->name); 773 pr_err("Can't annotate %s", sym->name);
1074 if (sym_filter_entry->map->dso->origin == DSO__ORIG_KERNEL) { 774 if (top.sym_filter_entry->map->dso->symtab_type == SYMTAB__KALLSYMS) {
1075 pr_err(": No vmlinux file was found in the path:\n"); 775 pr_err(": No vmlinux file was found in the path:\n");
1076 machine__fprintf_vmlinux_path(machine, stderr); 776 machine__fprintf_vmlinux_path(machine, stderr);
1077 } else 777 } else
@@ -1081,222 +781,127 @@ static void event__process_sample(const event_t *self,
1081 } 781 }
1082 782
1083 syme = symbol__priv(al.sym); 783 syme = symbol__priv(al.sym);
1084 if (!syme->skip) { 784 if (!al.sym->ignore) {
785 struct perf_evsel *evsel;
786
787 evsel = perf_evlist__id2evsel(top.evlist, sample->id);
788 assert(evsel != NULL);
1085 syme->count[evsel->idx]++; 789 syme->count[evsel->idx]++;
1086 syme->origin = origin;
1087 record_precise_ip(syme, evsel->idx, ip); 790 record_precise_ip(syme, evsel->idx, ip);
1088 pthread_mutex_lock(&active_symbols_lock); 791 pthread_mutex_lock(&top.active_symbols_lock);
1089 if (list_empty(&syme->node) || !syme->node.next) 792 if (list_empty(&syme->node) || !syme->node.next) {
793 static bool first = true;
1090 __list_insert_active_sym(syme); 794 __list_insert_active_sym(syme);
1091 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);
1092 } 801 }
1093} 802}
1094 803
1095struct mmap_data { 804static void perf_session__mmap_read_cpu(struct perf_session *self, int cpu)
1096 void *base;
1097 int mask;
1098 unsigned int prev;
1099};
1100
1101static int perf_evsel__alloc_mmap_per_thread(struct perf_evsel *evsel,
1102 int ncpus, int nthreads)
1103{
1104 evsel->priv = xyarray__new(ncpus, nthreads, sizeof(struct mmap_data));
1105 return evsel->priv != NULL ? 0 : -ENOMEM;
1106}
1107
1108static void perf_evsel__free_mmap(struct perf_evsel *evsel)
1109{
1110 xyarray__delete(evsel->priv);
1111 evsel->priv = NULL;
1112}
1113
1114static unsigned int mmap_read_head(struct mmap_data *md)
1115{ 805{
1116 struct perf_event_mmap_page *pc = md->base; 806 struct perf_sample sample;
1117 int head; 807 union perf_event *event;
1118
1119 head = pc->data_head;
1120 rmb();
1121
1122 return head;
1123}
1124
1125static void perf_session__mmap_read_counter(struct perf_session *self,
1126 struct perf_evsel *evsel,
1127 int cpu, int thread_idx)
1128{
1129 struct xyarray *mmap_array = evsel->priv;
1130 struct mmap_data *md = xyarray__entry(mmap_array, cpu, thread_idx);
1131 unsigned int head = mmap_read_head(md);
1132 unsigned int old = md->prev;
1133 unsigned char *data = md->base + page_size;
1134 struct sample_data sample;
1135 int diff;
1136
1137 /*
1138 * If we're further behind than half the buffer, there's a chance
1139 * the writer will bite our tail and mess up the samples under us.
1140 *
1141 * If we somehow ended up ahead of the head, we got messed up.
1142 *
1143 * In either case, truncate and restart at head.
1144 */
1145 diff = head - old;
1146 if (diff > md->mask / 2 || diff < 0) {
1147 fprintf(stderr, "WARNING: failed to keep up with mmap data.\n");
1148
1149 /*
1150 * head points to a known good entry, start there.
1151 */
1152 old = head;
1153 }
1154
1155 for (; old != head;) {
1156 event_t *event = (event_t *)&data[old & md->mask];
1157 808
1158 event_t event_copy; 809 while ((event = perf_evlist__read_on_cpu(top.evlist, cpu)) != NULL) {
810 perf_session__parse_sample(self, event, &sample);
1159 811
1160 size_t size = event->header.size;
1161
1162 /*
1163 * Event straddles the mmap boundary -- header should always
1164 * be inside due to u64 alignment of output.
1165 */
1166 if ((old & md->mask) + size != ((old + size) & md->mask)) {
1167 unsigned int offset = old;
1168 unsigned int len = min(sizeof(*event), size), cpy;
1169 void *dst = &event_copy;
1170
1171 do {
1172 cpy = min(md->mask + 1 - (offset & md->mask), len);
1173 memcpy(dst, &data[offset & md->mask], cpy);
1174 offset += cpy;
1175 dst += cpy;
1176 len -= cpy;
1177 } while (len);
1178
1179 event = &event_copy;
1180 }
1181
1182 event__parse_sample(event, self, &sample);
1183 if (event->header.type == PERF_RECORD_SAMPLE) 812 if (event->header.type == PERF_RECORD_SAMPLE)
1184 event__process_sample(event, &sample, self, evsel); 813 perf_event__process_sample(event, &sample, self);
1185 else 814 else
1186 event__process(event, &sample, self); 815 perf_event__process(event, &sample, self);
1187 old += size;
1188 } 816 }
1189
1190 md->prev = old;
1191} 817}
1192 818
1193static struct pollfd *event_array;
1194
1195static void perf_session__mmap_read(struct perf_session *self) 819static void perf_session__mmap_read(struct perf_session *self)
1196{ 820{
1197 struct perf_evsel *counter; 821 int i;
1198 int i, thread_index;
1199
1200 for (i = 0; i < cpus->nr; i++) {
1201 list_for_each_entry(counter, &evsel_list, node) {
1202 for (thread_index = 0;
1203 thread_index < threads->nr;
1204 thread_index++) {
1205 perf_session__mmap_read_counter(self,
1206 counter, i, thread_index);
1207 }
1208 }
1209 }
1210}
1211 822
1212int nr_poll; 823 for (i = 0; i < top.evlist->cpus->nr; i++)
1213int group_fd; 824 perf_session__mmap_read_cpu(self, i);
825}
1214 826
1215static void start_counter(int i, struct perf_evsel *evsel) 827static void start_counters(struct perf_evlist *evlist)
1216{ 828{
1217 struct xyarray *mmap_array = evsel->priv; 829 struct perf_evsel *counter;
1218 struct mmap_data *mm;
1219 struct perf_event_attr *attr;
1220 int cpu = -1;
1221 int thread_index;
1222
1223 if (target_tid == -1)
1224 cpu = cpus->map[i];
1225 830
1226 attr = &evsel->attr; 831 list_for_each_entry(counter, &evlist->entries, node) {
832 struct perf_event_attr *attr = &counter->attr;
1227 833
1228 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; 834 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
1229 835
1230 if (freq) { 836 if (top.freq) {
1231 attr->sample_type |= PERF_SAMPLE_PERIOD; 837 attr->sample_type |= PERF_SAMPLE_PERIOD;
1232 attr->freq = 1; 838 attr->freq = 1;
1233 attr->sample_freq = freq; 839 attr->sample_freq = top.freq;
1234 } 840 }
1235 841
1236 attr->inherit = (cpu < 0) && inherit; 842 if (evlist->nr_entries > 1) {
1237 attr->mmap = 1; 843 attr->sample_type |= PERF_SAMPLE_ID;
844 attr->read_format |= PERF_FORMAT_ID;
845 }
1238 846
1239 for (thread_index = 0; thread_index < threads->nr; thread_index++) { 847 attr->mmap = 1;
1240try_again: 848try_again:
1241 FD(evsel, i, thread_index) = sys_perf_event_open(attr, 849 if (perf_evsel__open(counter, top.evlist->cpus,
1242 threads->map[thread_index], cpu, group_fd, 0); 850 top.evlist->threads, group, inherit) < 0) {
1243
1244 if (FD(evsel, i, thread_index) < 0) {
1245 int err = errno; 851 int err = errno;
1246 852
1247 if (err == EPERM || err == EACCES) 853 if (err == EPERM || err == EACCES) {
1248 die("Permission error - are you root?\n" 854 ui__warning_paranoid();
1249 "\t Consider tweaking" 855 goto out_err;
1250 " /proc/sys/kernel/perf_event_paranoid.\n"); 856 }
1251 /* 857 /*
1252 * If it's cycles then fall back to hrtimer 858 * If it's cycles then fall back to hrtimer
1253 * based cpu-clock-tick sw counter, which 859 * based cpu-clock-tick sw counter, which
1254 * is always available even if no PMU support: 860 * is always available even if no PMU support:
1255 */ 861 */
1256 if (attr->type == PERF_TYPE_HARDWARE 862 if (attr->type == PERF_TYPE_HARDWARE &&
1257 && attr->config == PERF_COUNT_HW_CPU_CYCLES) { 863 attr->config == PERF_COUNT_HW_CPU_CYCLES) {
1258
1259 if (verbose) 864 if (verbose)
1260 warning(" ... trying to fall back to cpu-clock-ticks\n"); 865 ui__warning("Cycles event not supported,\n"
866 "trying to fall back to cpu-clock-ticks\n");
1261 867
1262 attr->type = PERF_TYPE_SOFTWARE; 868 attr->type = PERF_TYPE_SOFTWARE;
1263 attr->config = PERF_COUNT_SW_CPU_CLOCK; 869 attr->config = PERF_COUNT_SW_CPU_CLOCK;
1264 goto try_again; 870 goto try_again;
1265 } 871 }
1266 printf("\n"); 872
1267 error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n", 873 if (err == ENOENT) {
1268 FD(evsel, i, thread_index), strerror(err)); 874 ui__warning("The %s event is not supported.\n",
1269 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); 875 event_name(counter));
1270 exit(-1); 876 goto out_err;
877 }
878
879 ui__warning("The sys_perf_event_open() syscall "
880 "returned with %d (%s). /bin/dmesg "
881 "may provide additional information.\n"
882 "No CONFIG_PERF_EVENTS=y kernel support "
883 "configured?\n", err, strerror(err));
884 goto out_err;
1271 } 885 }
1272 assert(FD(evsel, i, thread_index) >= 0); 886 }
1273 fcntl(FD(evsel, i, thread_index), F_SETFL, O_NONBLOCK);
1274 887
1275 /* 888 if (perf_evlist__mmap(evlist, mmap_pages, false) < 0) {
1276 * First counter acts as the group leader: 889 ui__warning("Failed to mmap with %d (%s)\n",
1277 */ 890 errno, strerror(errno));
1278 if (group && group_fd == -1) 891 goto out_err;
1279 group_fd = FD(evsel, i, thread_index);
1280
1281 event_array[nr_poll].fd = FD(evsel, i, thread_index);
1282 event_array[nr_poll].events = POLLIN;
1283 nr_poll++;
1284
1285 mm = xyarray__entry(mmap_array, i, thread_index);
1286 mm->prev = 0;
1287 mm->mask = mmap_pages*page_size - 1;
1288 mm->base = mmap(NULL, (mmap_pages+1)*page_size,
1289 PROT_READ, MAP_SHARED, FD(evsel, i, thread_index), 0);
1290 if (mm->base == MAP_FAILED)
1291 die("failed to mmap with %d (%s)\n", errno, strerror(errno));
1292 } 892 }
893
894 return;
895
896out_err:
897 exit_browser(0);
898 exit(0);
1293} 899}
1294 900
1295static int __cmd_top(void) 901static int __cmd_top(void)
1296{ 902{
1297 pthread_t thread; 903 pthread_t thread;
1298 struct perf_evsel *counter; 904 int ret __used;
1299 int i, ret;
1300 /* 905 /*
1301 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this 906 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this
1302 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now. 907 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now.
@@ -1305,23 +910,23 @@ static int __cmd_top(void)
1305 if (session == NULL) 910 if (session == NULL)
1306 return -ENOMEM; 911 return -ENOMEM;
1307 912
1308 if (target_tid != -1) 913 if (top.target_tid != -1)
1309 event__synthesize_thread(target_tid, event__process, session); 914 perf_event__synthesize_thread_map(top.evlist->threads,
915 perf_event__process, session);
1310 else 916 else
1311 event__synthesize_threads(event__process, session); 917 perf_event__synthesize_threads(perf_event__process, session);
1312 918
1313 for (i = 0; i < cpus->nr; i++) { 919 start_counters(top.evlist);
1314 group_fd = -1; 920 session->evlist = top.evlist;
1315 list_for_each_entry(counter, &evsel_list, node) 921 perf_session__update_sample_type(session);
1316 start_counter(i, counter);
1317 }
1318 922
1319 /* Wait for a minimal set of events before starting the snapshot */ 923 /* Wait for a minimal set of events before starting the snapshot */
1320 poll(&event_array[0], nr_poll, 100); 924 poll(top.evlist->pollfd, top.evlist->nr_fds, 100);
1321 925
1322 perf_session__mmap_read(session); 926 perf_session__mmap_read(session);
1323 927
1324 if (pthread_create(&thread, NULL, display_thread, session)) { 928 if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui :
929 display_thread), session)) {
1325 printf("Could not create display thread.\n"); 930 printf("Could not create display thread.\n");
1326 exit(-1); 931 exit(-1);
1327 } 932 }
@@ -1337,12 +942,12 @@ static int __cmd_top(void)
1337 } 942 }
1338 943
1339 while (1) { 944 while (1) {
1340 int hits = samples; 945 u64 hits = top.samples;
1341 946
1342 perf_session__mmap_read(session); 947 perf_session__mmap_read(session);
1343 948
1344 if (hits == samples) 949 if (hits == top.samples)
1345 ret = poll(event_array, nr_poll, 100); 950 ret = poll(top.evlist->pollfd, top.evlist->nr_fds, 100);
1346 } 951 }
1347 952
1348 return 0; 953 return 0;
@@ -1354,31 +959,31 @@ static const char * const top_usage[] = {
1354}; 959};
1355 960
1356static const struct option options[] = { 961static const struct option options[] = {
1357 OPT_CALLBACK('e', "event", NULL, "event", 962 OPT_CALLBACK('e', "event", &top.evlist, "event",
1358 "event selector. use 'perf list' to list available events", 963 "event selector. use 'perf list' to list available events",
1359 parse_events), 964 parse_events),
1360 OPT_INTEGER('c', "count", &default_interval, 965 OPT_INTEGER('c', "count", &default_interval,
1361 "event period to sample"), 966 "event period to sample"),
1362 OPT_INTEGER('p', "pid", &target_pid, 967 OPT_INTEGER('p', "pid", &top.target_pid,
1363 "profile events on existing process id"), 968 "profile events on existing process id"),
1364 OPT_INTEGER('t', "tid", &target_tid, 969 OPT_INTEGER('t', "tid", &top.target_tid,
1365 "profile events on existing thread id"), 970 "profile events on existing thread id"),
1366 OPT_BOOLEAN('a', "all-cpus", &system_wide, 971 OPT_BOOLEAN('a', "all-cpus", &system_wide,
1367 "system-wide collection from all CPUs"), 972 "system-wide collection from all CPUs"),
1368 OPT_STRING('C', "cpu", &cpu_list, "cpu", 973 OPT_STRING('C', "cpu", &top.cpu_list, "cpu",
1369 "list of cpus to monitor"), 974 "list of cpus to monitor"),
1370 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 975 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
1371 "file", "vmlinux pathname"), 976 "file", "vmlinux pathname"),
1372 OPT_BOOLEAN('K', "hide_kernel_symbols", &hide_kernel_symbols, 977 OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols,
1373 "hide kernel symbols"), 978 "hide kernel symbols"),
1374 OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"), 979 OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"),
1375 OPT_INTEGER('r', "realtime", &realtime_prio, 980 OPT_INTEGER('r', "realtime", &realtime_prio,
1376 "collect data with this RT SCHED_FIFO priority"), 981 "collect data with this RT SCHED_FIFO priority"),
1377 OPT_INTEGER('d', "delay", &delay_secs, 982 OPT_INTEGER('d', "delay", &top.delay_secs,
1378 "number of seconds to delay between refreshes"), 983 "number of seconds to delay between refreshes"),
1379 OPT_BOOLEAN('D', "dump-symtab", &dump_symtab, 984 OPT_BOOLEAN('D', "dump-symtab", &dump_symtab,
1380 "dump the symbol table used for profiling"), 985 "dump the symbol table used for profiling"),
1381 OPT_INTEGER('f', "count-filter", &count_filter, 986 OPT_INTEGER('f', "count-filter", &top.count_filter,
1382 "only display functions with more events than this"), 987 "only display functions with more events than this"),
1383 OPT_BOOLEAN('g', "group", &group, 988 OPT_BOOLEAN('g', "group", &group,
1384 "put the counters into a counter group"), 989 "put the counters into a counter group"),
@@ -1386,14 +991,16 @@ static const struct option options[] = {
1386 "child tasks inherit counters"), 991 "child tasks inherit counters"),
1387 OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name", 992 OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name",
1388 "symbol to annotate"), 993 "symbol to annotate"),
1389 OPT_BOOLEAN('z', "zero", &zero, 994 OPT_BOOLEAN('z', "zero", &top.zero,
1390 "zero history across updates"), 995 "zero history across updates"),
1391 OPT_INTEGER('F', "freq", &freq, 996 OPT_INTEGER('F', "freq", &top.freq,
1392 "profile at this frequency"), 997 "profile at this frequency"),
1393 OPT_INTEGER('E', "entries", &print_entries, 998 OPT_INTEGER('E', "entries", &top.print_entries,
1394 "display this many functions"), 999 "display this many functions"),
1395 OPT_BOOLEAN('U', "hide_user_symbols", &hide_user_symbols, 1000 OPT_BOOLEAN('U', "hide_user_symbols", &top.hide_user_symbols,
1396 "hide user symbols"), 1001 "hide user symbols"),
1002 OPT_BOOLEAN(0, "tui", &use_tui, "Use the TUI interface"),
1003 OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"),
1397 OPT_INCR('v', "verbose", &verbose, 1004 OPT_INCR('v', "verbose", &verbose,
1398 "be more verbose (show counter open errors, etc)"), 1005 "be more verbose (show counter open errors, etc)"),
1399 OPT_END() 1006 OPT_END()
@@ -1404,64 +1011,68 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1404 struct perf_evsel *pos; 1011 struct perf_evsel *pos;
1405 int status = -ENOMEM; 1012 int status = -ENOMEM;
1406 1013
1014 top.evlist = perf_evlist__new(NULL, NULL);
1015 if (top.evlist == NULL)
1016 return -ENOMEM;
1017
1407 page_size = sysconf(_SC_PAGE_SIZE); 1018 page_size = sysconf(_SC_PAGE_SIZE);
1408 1019
1409 argc = parse_options(argc, argv, options, top_usage, 0); 1020 argc = parse_options(argc, argv, options, top_usage, 0);
1410 if (argc) 1021 if (argc)
1411 usage_with_options(top_usage, options); 1022 usage_with_options(top_usage, options);
1412 1023
1413 if (target_pid != -1) 1024 /*
1414 target_tid = target_pid; 1025 * XXX For now start disabled, only using TUI if explicitely asked for.
1026 * Change that when handle_keys equivalent gets written, live annotation
1027 * done, etc.
1028 */
1029 use_browser = 0;
1415 1030
1416 threads = thread_map__new(target_pid, target_tid); 1031 if (use_stdio)
1417 if (threads == NULL) { 1032 use_browser = 0;
1418 pr_err("Problems finding threads of monitor\n"); 1033 else if (use_tui)
1419 usage_with_options(top_usage, options); 1034 use_browser = 1;
1420 }
1421 1035
1422 event_array = malloc((sizeof(struct pollfd) * 1036 setup_browser(false);
1423 MAX_NR_CPUS * MAX_COUNTERS * threads->nr));
1424 if (!event_array)
1425 return -ENOMEM;
1426 1037
1427 /* CPU and PID are mutually exclusive */ 1038 /* CPU and PID are mutually exclusive */
1428 if (target_tid > 0 && cpu_list) { 1039 if (top.target_tid > 0 && top.cpu_list) {
1429 printf("WARNING: PID switch overriding CPU\n"); 1040 printf("WARNING: PID switch overriding CPU\n");
1430 sleep(1); 1041 sleep(1);
1431 cpu_list = NULL; 1042 top.cpu_list = NULL;
1432 } 1043 }
1433 1044
1434 if (!nr_counters && perf_evsel_list__create_default() < 0) { 1045 if (top.target_pid != -1)
1046 top.target_tid = top.target_pid;
1047
1048 if (perf_evlist__create_maps(top.evlist, top.target_pid,
1049 top.target_tid, top.cpu_list) < 0)
1050 usage_with_options(top_usage, options);
1051
1052 if (!top.evlist->nr_entries &&
1053 perf_evlist__add_default(top.evlist) < 0) {
1435 pr_err("Not enough memory for event selector list\n"); 1054 pr_err("Not enough memory for event selector list\n");
1436 return -ENOMEM; 1055 return -ENOMEM;
1437 } 1056 }
1438 1057
1439 if (delay_secs < 1) 1058 if (top.delay_secs < 1)
1440 delay_secs = 1; 1059 top.delay_secs = 1;
1441 1060
1442 /* 1061 /*
1443 * User specified count overrides default frequency. 1062 * User specified count overrides default frequency.
1444 */ 1063 */
1445 if (default_interval) 1064 if (default_interval)
1446 freq = 0; 1065 top.freq = 0;
1447 else if (freq) { 1066 else if (top.freq) {
1448 default_interval = freq; 1067 default_interval = top.freq;
1449 } else { 1068 } else {
1450 fprintf(stderr, "frequency and count are zero, aborting\n"); 1069 fprintf(stderr, "frequency and count are zero, aborting\n");
1451 exit(EXIT_FAILURE); 1070 exit(EXIT_FAILURE);
1452 } 1071 }
1453 1072
1454 if (target_tid != -1) 1073 list_for_each_entry(pos, &top.evlist->entries, node) {
1455 cpus = cpu_map__dummy_new(); 1074 if (perf_evsel__alloc_fd(pos, top.evlist->cpus->nr,
1456 else 1075 top.evlist->threads->nr) < 0)
1457 cpus = cpu_map__new(cpu_list);
1458
1459 if (cpus == NULL)
1460 usage_with_options(top_usage, options);
1461
1462 list_for_each_entry(pos, &evsel_list, node) {
1463 if (perf_evsel__alloc_mmap_per_thread(pos, cpus->nr, threads->nr) < 0 ||
1464 perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0)
1465 goto out_free_fd; 1076 goto out_free_fd;
1466 /* 1077 /*
1467 * Fill in the ones not specifically initialized via -c: 1078 * Fill in the ones not specifically initialized via -c:
@@ -1472,26 +1083,28 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1472 pos->attr.sample_period = default_interval; 1083 pos->attr.sample_period = default_interval;
1473 } 1084 }
1474 1085
1475 sym_evsel = list_entry(evsel_list.next, struct perf_evsel, node); 1086 if (perf_evlist__alloc_pollfd(top.evlist) < 0 ||
1087 perf_evlist__alloc_mmap(top.evlist) < 0)
1088 goto out_free_fd;
1089
1090 top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node);
1476 1091
1477 symbol_conf.priv_size = (sizeof(struct sym_entry) + 1092 symbol_conf.priv_size = (sizeof(struct sym_entry) + sizeof(struct annotation) +
1478 (nr_counters + 1) * sizeof(unsigned long)); 1093 (top.evlist->nr_entries + 1) * sizeof(unsigned long));
1479 1094
1480 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); 1095 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
1481 if (symbol__init() < 0) 1096 if (symbol__init() < 0)
1482 return -1; 1097 return -1;
1483 1098
1484 get_term_dimensions(&winsize); 1099 get_term_dimensions(&winsize);
1485 if (print_entries == 0) { 1100 if (top.print_entries == 0) {
1486 update_print_entries(&winsize); 1101 update_print_entries(&winsize);
1487 signal(SIGWINCH, sig_winch_handler); 1102 signal(SIGWINCH, sig_winch_handler);
1488 } 1103 }
1489 1104
1490 status = __cmd_top(); 1105 status = __cmd_top();
1491out_free_fd: 1106out_free_fd:
1492 list_for_each_entry(pos, &evsel_list, node) 1107 perf_evlist__delete(top.evlist);
1493 perf_evsel__free_mmap(pos);
1494 perf_evsel_list__delete();
1495 1108
1496 return status; 1109 return status;
1497} 1110}
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h
index c7798c7f24ed..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);
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt
index 16b5088cf8f4..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
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 595d0f4a7103..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 },
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/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 deffb8c96071..a91cd99f26ea 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -14,8 +14,9 @@
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, 17static int build_id__mark_dso_hit(union perf_event *event,
18 struct sample_data *sample __used, 18 struct perf_sample *sample __used,
19 struct perf_evsel *evsel __used,
19 struct perf_session *session) 20 struct perf_session *session)
20{ 21{
21 struct addr_location al; 22 struct addr_location al;
@@ -37,13 +38,14 @@ static int build_id__mark_dso_hit(event_t *event,
37 return 0; 38 return 0;
38} 39}
39 40
40static int event__exit_del_thread(event_t *self, struct sample_data *sample __used, 41static int perf_event__exit_del_thread(union perf_event *event,
41 struct perf_session *session) 42 struct perf_sample *sample __used,
43 struct perf_session *session)
42{ 44{
43 struct thread *thread = perf_session__findnew(session, self->fork.tid); 45 struct thread *thread = perf_session__findnew(session, event->fork.tid);
44 46
45 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,
46 self->fork.ppid, self->fork.ptid); 48 event->fork.ppid, event->fork.ptid);
47 49
48 if (thread) { 50 if (thread) {
49 rb_erase(&thread->rb_node, &session->threads); 51 rb_erase(&thread->rb_node, &session->threads);
@@ -56,9 +58,9 @@ static int event__exit_del_thread(event_t *self, struct sample_data *sample __us
56 58
57struct perf_event_ops build_id__mark_dso_hit_ops = { 59struct perf_event_ops build_id__mark_dso_hit_ops = {
58 .sample = build_id__mark_dso_hit, 60 .sample = build_id__mark_dso_hit,
59 .mmap = event__process_mmap, 61 .mmap = perf_event__process_mmap,
60 .fork = event__process_task, 62 .fork = perf_event__process_task,
61 .exit = event__exit_del_thread, 63 .exit = perf_event__exit_del_thread,
62}; 64};
63 65
64char *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 3ccaa1043383..6893eec693ab 100644
--- a/tools/perf/util/cpumap.c
+++ b/tools/perf/util/cpumap.c
@@ -177,3 +177,8 @@ struct cpu_map *cpu_map__dummy_new(void)
177 177
178 return cpus; 178 return cpus;
179} 179}
180
181void cpu_map__delete(struct cpu_map *map)
182{
183 free(map);
184}
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
index f7a4f42f6307..072c0a374794 100644
--- a/tools/perf/util/cpumap.h
+++ b/tools/perf/util/cpumap.h
@@ -8,6 +8,6 @@ struct cpu_map {
8 8
9struct cpu_map *cpu_map__new(const char *cpu_list); 9struct cpu_map *cpu_map__new(const char *cpu_list);
10struct cpu_map *cpu_map__dummy_new(void); 10struct cpu_map *cpu_map__dummy_new(void);
11void *cpu_map__delete(struct cpu_map *map); 11void cpu_map__delete(struct cpu_map *map);
12 12
13#endif /* __PERF_CPUMAP_H */ 13#endif /* __PERF_CPUMAP_H */
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index 01bbe8ecec3f..155749d74350 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -57,7 +57,17 @@ void ui__warning(const char *format, ...)
57} 57}
58#endif 58#endif
59 59
60void trace_event(event_t *event) 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}
69
70void trace_event(union perf_event *event)
61{ 71{
62 unsigned char *raw_event = (void *)event; 72 unsigned char *raw_event = (void *)event;
63 const char *color = PERF_COLOR_BLUE; 73 const char *color = PERF_COLOR_BLUE;
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index ca35fd66b5df..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
@@ -36,5 +36,6 @@ int ui_helpline__show_help(const char *format, va_list ap);
36#endif 36#endif
37 37
38void ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); 38void ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2)));
39void ui__warning_paranoid(void);
39 40
40#endif /* __PERF_DEBUG_H */ 41#endif /* __PERF_DEBUG_H */
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 1478ab4ee222..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
10static const 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",
@@ -25,16 +26,16 @@ static const char *event__name[] = {
25 [PERF_RECORD_FINISHED_ROUND] = "FINISHED_ROUND", 26 [PERF_RECORD_FINISHED_ROUND] = "FINISHED_ROUND",
26}; 27};
27 28
28const char *event__get_event_name(unsigned int id) 29const char *perf_event__name(unsigned int id)
29{ 30{
30 if (id >= ARRAY_SIZE(event__name)) 31 if (id >= ARRAY_SIZE(perf_event__names))
31 return "INVALID"; 32 return "INVALID";
32 if (!event__name[id]) 33 if (!perf_event__names[id])
33 return "UNKNOWN"; 34 return "UNKNOWN";
34 return event__name[id]; 35 return perf_event__names[id];
35} 36}
36 37
37static struct sample_data synth_sample = { 38static struct perf_sample synth_sample = {
38 .pid = -1, 39 .pid = -1,
39 .tid = -1, 40 .tid = -1,
40 .time = -1, 41 .time = -1,
@@ -43,9 +44,9 @@ static struct sample_data synth_sample = {
43 .period = 1, 44 .period = 1,
44}; 45};
45 46
46static pid_t event__synthesize_comm(event_t *event, pid_t pid, int full, 47static pid_t perf_event__synthesize_comm(union perf_event *event, pid_t pid,
47 event__handler_t process, 48 int full, perf_event__handler_t process,
48 struct perf_session *session) 49 struct perf_session *session)
49{ 50{
50 char filename[PATH_MAX]; 51 char filename[PATH_MAX];
51 char bf[BUFSIZ]; 52 char bf[BUFSIZ];
@@ -126,9 +127,10 @@ out:
126 return tgid; 127 return tgid;
127} 128}
128 129
129static int event__synthesize_mmap_events(event_t *event, pid_t pid, pid_t tgid, 130static int perf_event__synthesize_mmap_events(union perf_event *event,
130 event__handler_t process, 131 pid_t pid, pid_t tgid,
131 struct perf_session *session) 132 perf_event__handler_t process,
133 struct perf_session *session)
132{ 134{
133 char filename[PATH_MAX]; 135 char filename[PATH_MAX];
134 FILE *fp; 136 FILE *fp;
@@ -199,14 +201,14 @@ static int event__synthesize_mmap_events(event_t *event, pid_t pid, pid_t tgid,
199 return 0; 201 return 0;
200} 202}
201 203
202int event__synthesize_modules(event__handler_t process, 204int perf_event__synthesize_modules(perf_event__handler_t process,
203 struct perf_session *session, 205 struct perf_session *session,
204 struct machine *machine) 206 struct machine *machine)
205{ 207{
206 struct rb_node *nd; 208 struct rb_node *nd;
207 struct map_groups *kmaps = &machine->kmaps; 209 struct map_groups *kmaps = &machine->kmaps;
208 event_t *event = zalloc(sizeof(event->mmap) + session->id_hdr_size); 210 union perf_event *event = zalloc((sizeof(event->mmap) +
209 211 session->id_hdr_size));
210 if (event == NULL) { 212 if (event == NULL) {
211 pr_debug("Not enough memory synthesizing mmap event " 213 pr_debug("Not enough memory synthesizing mmap event "
212 "for kernel modules\n"); 214 "for kernel modules\n");
@@ -251,23 +253,25 @@ int event__synthesize_modules(event__handler_t process,
251 return 0; 253 return 0;
252} 254}
253 255
254static int __event__synthesize_thread(event_t *comm_event, event_t *mmap_event, 256static int __event__synthesize_thread(union perf_event *comm_event,
255 pid_t pid, event__handler_t process, 257 union perf_event *mmap_event,
258 pid_t pid, perf_event__handler_t process,
256 struct perf_session *session) 259 struct perf_session *session)
257{ 260{
258 pid_t tgid = event__synthesize_comm(comm_event, pid, 1, process, 261 pid_t tgid = perf_event__synthesize_comm(comm_event, pid, 1, process,
259 session); 262 session);
260 if (tgid == -1) 263 if (tgid == -1)
261 return -1; 264 return -1;
262 return event__synthesize_mmap_events(mmap_event, pid, tgid, 265 return perf_event__synthesize_mmap_events(mmap_event, pid, tgid,
263 process, session); 266 process, session);
264} 267}
265 268
266int event__synthesize_thread(pid_t pid, event__handler_t process, 269int perf_event__synthesize_thread_map(struct thread_map *threads,
267 struct perf_session *session) 270 perf_event__handler_t process,
271 struct perf_session *session)
268{ 272{
269 event_t *comm_event, *mmap_event; 273 union perf_event *comm_event, *mmap_event;
270 int err = -1; 274 int err = -1, thread;
271 275
272 comm_event = malloc(sizeof(comm_event->comm) + session->id_hdr_size); 276 comm_event = malloc(sizeof(comm_event->comm) + session->id_hdr_size);
273 if (comm_event == NULL) 277 if (comm_event == NULL)
@@ -277,8 +281,15 @@ int event__synthesize_thread(pid_t pid, event__handler_t process,
277 if (mmap_event == NULL) 281 if (mmap_event == NULL)
278 goto out_free_comm; 282 goto out_free_comm;
279 283
280 err = __event__synthesize_thread(comm_event, mmap_event, pid, 284 err = 0;
281 process, session); 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 }
282 free(mmap_event); 293 free(mmap_event);
283out_free_comm: 294out_free_comm:
284 free(comm_event); 295 free(comm_event);
@@ -286,12 +297,12 @@ out:
286 return err; 297 return err;
287} 298}
288 299
289int event__synthesize_threads(event__handler_t process, 300int perf_event__synthesize_threads(perf_event__handler_t process,
290 struct perf_session *session) 301 struct perf_session *session)
291{ 302{
292 DIR *proc; 303 DIR *proc;
293 struct dirent dirent, *next; 304 struct dirent dirent, *next;
294 event_t *comm_event, *mmap_event; 305 union perf_event *comm_event, *mmap_event;
295 int err = -1; 306 int err = -1;
296 307
297 comm_event = malloc(sizeof(comm_event->comm) + session->id_hdr_size); 308 comm_event = malloc(sizeof(comm_event->comm) + session->id_hdr_size);
@@ -349,10 +360,10 @@ static int find_symbol_cb(void *arg, const char *name, char type,
349 return 1; 360 return 1;
350} 361}
351 362
352int event__synthesize_kernel_mmap(event__handler_t process, 363int perf_event__synthesize_kernel_mmap(perf_event__handler_t process,
353 struct perf_session *session, 364 struct perf_session *session,
354 struct machine *machine, 365 struct machine *machine,
355 const char *symbol_name) 366 const char *symbol_name)
356{ 367{
357 size_t size; 368 size_t size;
358 const char *filename, *mmap_name; 369 const char *filename, *mmap_name;
@@ -366,8 +377,8 @@ int event__synthesize_kernel_mmap(event__handler_t process,
366 * kernels. 377 * kernels.
367 */ 378 */
368 struct process_symbol_args args = { .name = symbol_name, }; 379 struct process_symbol_args args = { .name = symbol_name, };
369 event_t *event = zalloc(sizeof(event->mmap) + session->id_hdr_size); 380 union perf_event *event = zalloc((sizeof(event->mmap) +
370 381 session->id_hdr_size));
371 if (event == NULL) { 382 if (event == NULL) {
372 pr_debug("Not enough memory synthesizing mmap event " 383 pr_debug("Not enough memory synthesizing mmap event "
373 "for kernel modules\n"); 384 "for kernel modules\n");
@@ -413,42 +424,15 @@ int event__synthesize_kernel_mmap(event__handler_t process,
413 return err; 424 return err;
414} 425}
415 426
416static void thread__comm_adjust(struct thread *self, struct hists *hists) 427int perf_event__process_comm(union perf_event *event,
417{ 428 struct perf_sample *sample __used,
418 char *comm = self->comm; 429 struct perf_session *session)
419
420 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
421 (!symbol_conf.comm_list ||
422 strlist__has_entry(symbol_conf.comm_list, comm))) {
423 u16 slen = strlen(comm);
424
425 if (hists__new_col_len(hists, HISTC_COMM, slen))
426 hists__set_col_len(hists, HISTC_THREAD, slen + 6);
427 }
428}
429
430static int thread__set_comm_adjust(struct thread *self, const char *comm,
431 struct hists *hists)
432{
433 int ret = thread__set_comm(self, comm);
434
435 if (ret)
436 return ret;
437
438 thread__comm_adjust(self, hists);
439
440 return 0;
441}
442
443int event__process_comm(event_t *self, struct sample_data *sample __used,
444 struct perf_session *session)
445{ 430{
446 struct thread *thread = perf_session__findnew(session, self->comm.tid); 431 struct thread *thread = perf_session__findnew(session, event->comm.tid);
447 432
448 dump_printf(": %s:%d\n", self->comm.comm, self->comm.tid); 433 dump_printf(": %s:%d\n", event->comm.comm, event->comm.tid);
449 434
450 if (thread == NULL || thread__set_comm_adjust(thread, self->comm.comm, 435 if (thread == NULL || thread__set_comm(thread, event->comm.comm)) {
451 &session->hists)) {
452 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); 436 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
453 return -1; 437 return -1;
454 } 438 }
@@ -456,19 +440,21 @@ int event__process_comm(event_t *self, struct sample_data *sample __used,
456 return 0; 440 return 0;
457} 441}
458 442
459int event__process_lost(event_t *self, struct sample_data *sample __used, 443int perf_event__process_lost(union perf_event *event,
460 struct perf_session *session) 444 struct perf_sample *sample __used,
445 struct perf_session *session)
461{ 446{
462 dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n", 447 dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n",
463 self->lost.id, self->lost.lost); 448 event->lost.id, event->lost.lost);
464 session->hists.stats.total_lost += self->lost.lost; 449 session->hists.stats.total_lost += event->lost.lost;
465 return 0; 450 return 0;
466} 451}
467 452
468static 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)
469{ 455{
470 maps[MAP__FUNCTION]->start = self->mmap.start; 456 maps[MAP__FUNCTION]->start = event->mmap.start;
471 maps[MAP__FUNCTION]->end = self->mmap.start + self->mmap.len; 457 maps[MAP__FUNCTION]->end = event->mmap.start + event->mmap.len;
472 /* 458 /*
473 * Be a bit paranoid here, some perf.data file came with 459 * Be a bit paranoid here, some perf.data file came with
474 * a zero sized synthesized MMAP event for the kernel. 460 * a zero sized synthesized MMAP event for the kernel.
@@ -477,8 +463,8 @@ static void event_set_kernel_mmap_len(struct map **maps, event_t *self)
477 maps[MAP__FUNCTION]->end = ~0ULL; 463 maps[MAP__FUNCTION]->end = ~0ULL;
478} 464}
479 465
480static int event__process_kernel_mmap(event_t *self, 466static int perf_event__process_kernel_mmap(union perf_event *event,
481 struct perf_session *session) 467 struct perf_session *session)
482{ 468{
483 struct map *map; 469 struct map *map;
484 char kmmap_prefix[PATH_MAX]; 470 char kmmap_prefix[PATH_MAX];
@@ -486,9 +472,9 @@ static int event__process_kernel_mmap(event_t *self,
486 enum dso_kernel_type kernel_type; 472 enum dso_kernel_type kernel_type;
487 bool is_kernel_mmap; 473 bool is_kernel_mmap;
488 474
489 machine = perf_session__findnew_machine(session, self->mmap.pid); 475 machine = perf_session__findnew_machine(session, event->mmap.pid);
490 if (!machine) { 476 if (!machine) {
491 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);
492 goto out_problem; 478 goto out_problem;
493 } 479 }
494 480
@@ -498,17 +484,17 @@ static int event__process_kernel_mmap(event_t *self,
498 else 484 else
499 kernel_type = DSO_TYPE_GUEST_KERNEL; 485 kernel_type = DSO_TYPE_GUEST_KERNEL;
500 486
501 is_kernel_mmap = memcmp(self->mmap.filename, 487 is_kernel_mmap = memcmp(event->mmap.filename,
502 kmmap_prefix, 488 kmmap_prefix,
503 strlen(kmmap_prefix)) == 0; 489 strlen(kmmap_prefix)) == 0;
504 if (self->mmap.filename[0] == '/' || 490 if (event->mmap.filename[0] == '/' ||
505 (!is_kernel_mmap && self->mmap.filename[0] == '[')) { 491 (!is_kernel_mmap && event->mmap.filename[0] == '[')) {
506 492
507 char short_module_name[1024]; 493 char short_module_name[1024];
508 char *name, *dot; 494 char *name, *dot;
509 495
510 if (self->mmap.filename[0] == '/') { 496 if (event->mmap.filename[0] == '/') {
511 name = strrchr(self->mmap.filename, '/'); 497 name = strrchr(event->mmap.filename, '/');
512 if (name == NULL) 498 if (name == NULL)
513 goto out_problem; 499 goto out_problem;
514 500
@@ -520,10 +506,10 @@ static int event__process_kernel_mmap(event_t *self,
520 "[%.*s]", (int)(dot - name), name); 506 "[%.*s]", (int)(dot - name), name);
521 strxfrchar(short_module_name, '-', '_'); 507 strxfrchar(short_module_name, '-', '_');
522 } else 508 } else
523 strcpy(short_module_name, self->mmap.filename); 509 strcpy(short_module_name, event->mmap.filename);
524 510
525 map = machine__new_module(machine, self->mmap.start, 511 map = machine__new_module(machine, event->mmap.start,
526 self->mmap.filename); 512 event->mmap.filename);
527 if (map == NULL) 513 if (map == NULL)
528 goto out_problem; 514 goto out_problem;
529 515
@@ -533,9 +519,9 @@ static int event__process_kernel_mmap(event_t *self,
533 519
534 map->dso->short_name = name; 520 map->dso->short_name = name;
535 map->dso->sname_alloc = 1; 521 map->dso->sname_alloc = 1;
536 map->end = map->start + self->mmap.len; 522 map->end = map->start + event->mmap.len;
537 } else if (is_kernel_mmap) { 523 } else if (is_kernel_mmap) {
538 const char *symbol_name = (self->mmap.filename + 524 const char *symbol_name = (event->mmap.filename +
539 strlen(kmmap_prefix)); 525 strlen(kmmap_prefix));
540 /* 526 /*
541 * Should be there already, from the build-id table in 527 * Should be there already, from the build-id table in
@@ -550,10 +536,10 @@ static int event__process_kernel_mmap(event_t *self,
550 if (__machine__create_kernel_maps(machine, kernel) < 0) 536 if (__machine__create_kernel_maps(machine, kernel) < 0)
551 goto out_problem; 537 goto out_problem;
552 538
553 event_set_kernel_mmap_len(machine->vmlinux_maps, self); 539 perf_event__set_kernel_mmap_len(event, machine->vmlinux_maps);
554 perf_session__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps, 540 perf_session__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps,
555 symbol_name, 541 symbol_name,
556 self->mmap.pgoff); 542 event->mmap.pgoff);
557 if (machine__is_default_guest(machine)) { 543 if (machine__is_default_guest(machine)) {
558 /* 544 /*
559 * preload dso of guest kernel and modules 545 * preload dso of guest kernel and modules
@@ -567,22 +553,23 @@ out_problem:
567 return -1; 553 return -1;
568} 554}
569 555
570int event__process_mmap(event_t *self, struct sample_data *sample __used, 556int perf_event__process_mmap(union perf_event *event,
571 struct perf_session *session) 557 struct perf_sample *sample __used,
558 struct perf_session *session)
572{ 559{
573 struct machine *machine; 560 struct machine *machine;
574 struct thread *thread; 561 struct thread *thread;
575 struct map *map; 562 struct map *map;
576 u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 563 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
577 int ret = 0; 564 int ret = 0;
578 565
579 dump_printf(" %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %s\n", 566 dump_printf(" %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %s\n",
580 self->mmap.pid, self->mmap.tid, self->mmap.start, 567 event->mmap.pid, event->mmap.tid, event->mmap.start,
581 self->mmap.len, self->mmap.pgoff, self->mmap.filename); 568 event->mmap.len, event->mmap.pgoff, event->mmap.filename);
582 569
583 if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL || 570 if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
584 cpumode == PERF_RECORD_MISC_KERNEL) { 571 cpumode == PERF_RECORD_MISC_KERNEL) {
585 ret = event__process_kernel_mmap(self, session); 572 ret = perf_event__process_kernel_mmap(event, session);
586 if (ret < 0) 573 if (ret < 0)
587 goto out_problem; 574 goto out_problem;
588 return 0; 575 return 0;
@@ -591,12 +578,12 @@ int event__process_mmap(event_t *self, struct sample_data *sample __used,
591 machine = perf_session__find_host_machine(session); 578 machine = perf_session__find_host_machine(session);
592 if (machine == NULL) 579 if (machine == NULL)
593 goto out_problem; 580 goto out_problem;
594 thread = perf_session__findnew(session, self->mmap.pid); 581 thread = perf_session__findnew(session, event->mmap.pid);
595 if (thread == NULL) 582 if (thread == NULL)
596 goto out_problem; 583 goto out_problem;
597 map = map__new(&machine->user_dsos, self->mmap.start, 584 map = map__new(&machine->user_dsos, event->mmap.start,
598 self->mmap.len, self->mmap.pgoff, 585 event->mmap.len, event->mmap.pgoff,
599 self->mmap.pid, self->mmap.filename, 586 event->mmap.pid, event->mmap.filename,
600 MAP__FUNCTION); 587 MAP__FUNCTION);
601 if (map == NULL) 588 if (map == NULL)
602 goto out_problem; 589 goto out_problem;
@@ -609,16 +596,17 @@ out_problem:
609 return 0; 596 return 0;
610} 597}
611 598
612int event__process_task(event_t *self, struct sample_data *sample __used, 599int perf_event__process_task(union perf_event *event,
613 struct perf_session *session) 600 struct perf_sample *sample __used,
601 struct perf_session *session)
614{ 602{
615 struct thread *thread = perf_session__findnew(session, self->fork.tid); 603 struct thread *thread = perf_session__findnew(session, event->fork.tid);
616 struct thread *parent = perf_session__findnew(session, self->fork.ptid); 604 struct thread *parent = perf_session__findnew(session, event->fork.ptid);
617 605
618 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,
619 self->fork.ppid, self->fork.ptid); 607 event->fork.ppid, event->fork.ptid);
620 608
621 if (self->header.type == PERF_RECORD_EXIT) { 609 if (event->header.type == PERF_RECORD_EXIT) {
622 perf_session__remove_thread(session, thread); 610 perf_session__remove_thread(session, thread);
623 return 0; 611 return 0;
624 } 612 }
@@ -632,20 +620,22 @@ int event__process_task(event_t *self, struct sample_data *sample __used,
632 return 0; 620 return 0;
633} 621}
634 622
635int event__process(event_t *event, struct sample_data *sample, 623int perf_event__process(union perf_event *event, struct perf_sample *sample,
636 struct perf_session *session) 624 struct perf_session *session)
637{ 625{
638 switch (event->header.type) { 626 switch (event->header.type) {
639 case PERF_RECORD_COMM: 627 case PERF_RECORD_COMM:
640 event__process_comm(event, sample, session); 628 perf_event__process_comm(event, sample, session);
641 break; 629 break;
642 case PERF_RECORD_MMAP: 630 case PERF_RECORD_MMAP:
643 event__process_mmap(event, sample, session); 631 perf_event__process_mmap(event, sample, session);
644 break; 632 break;
645 case PERF_RECORD_FORK: 633 case PERF_RECORD_FORK:
646 case PERF_RECORD_EXIT: 634 case PERF_RECORD_EXIT:
647 event__process_task(event, sample, session); 635 perf_event__process_task(event, sample, session);
648 break; 636 break;
637 case PERF_RECORD_LOST:
638 perf_event__process_lost(event, sample, session);
649 default: 639 default:
650 break; 640 break;
651 } 641 }
@@ -720,7 +710,7 @@ try_again:
720 * in the whole kernel symbol list. 710 * in the whole kernel symbol list.
721 */ 711 */
722 if ((long long)al->addr < 0 && 712 if ((long long)al->addr < 0 &&
723 cpumode == PERF_RECORD_MISC_KERNEL && 713 cpumode == PERF_RECORD_MISC_USER &&
724 machine && mg != &machine->kmaps) { 714 machine && mg != &machine->kmaps) {
725 mg = &machine->kmaps; 715 mg = &machine->kmaps;
726 goto try_again; 716 goto try_again;
@@ -742,24 +732,14 @@ void thread__find_addr_location(struct thread *self,
742 al->sym = NULL; 732 al->sym = NULL;
743} 733}
744 734
745static void dso__calc_col_width(struct dso *self, struct hists *hists) 735int perf_event__preprocess_sample(const union perf_event *event,
746{ 736 struct perf_session *session,
747 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep && 737 struct addr_location *al,
748 (!symbol_conf.dso_list || 738 struct perf_sample *sample,
749 strlist__has_entry(symbol_conf.dso_list, self->name))) { 739 symbol_filter_t filter)
750 u16 slen = dso__name_len(self);
751 hists__new_col_len(hists, HISTC_DSO, slen);
752 }
753
754 self->slen_calculated = 1;
755}
756
757int event__preprocess_sample(const event_t *self, struct perf_session *session,
758 struct addr_location *al, struct sample_data *data,
759 symbol_filter_t filter)
760{ 740{
761 u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 741 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
762 struct thread *thread = perf_session__findnew(session, self->ip.pid); 742 struct thread *thread = perf_session__findnew(session, event->ip.pid);
763 743
764 if (thread == NULL) 744 if (thread == NULL)
765 return -1; 745 return -1;
@@ -781,12 +761,12 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session,
781 machine__create_kernel_maps(&session->host_machine); 761 machine__create_kernel_maps(&session->host_machine);
782 762
783 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION, 763 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION,
784 self->ip.pid, self->ip.ip, al); 764 event->ip.pid, event->ip.ip, al);
785 dump_printf(" ...... dso: %s\n", 765 dump_printf(" ...... dso: %s\n",
786 al->map ? al->map->dso->long_name : 766 al->map ? al->map->dso->long_name :
787 al->level == 'H' ? "[hypervisor]" : "<not found>"); 767 al->level == 'H' ? "[hypervisor]" : "<not found>");
788 al->sym = NULL; 768 al->sym = NULL;
789 al->cpu = data->cpu; 769 al->cpu = sample->cpu;
790 770
791 if (al->map) { 771 if (al->map) {
792 if (symbol_conf.dso_list && 772 if (symbol_conf.dso_list &&
@@ -797,23 +777,8 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session,
797 strlist__has_entry(symbol_conf.dso_list, 777 strlist__has_entry(symbol_conf.dso_list,
798 al->map->dso->long_name))))) 778 al->map->dso->long_name)))))
799 goto out_filtered; 779 goto out_filtered;
800 /*
801 * We have to do this here as we may have a dso with no symbol
802 * hit that has a name longer than the ones with symbols
803 * sampled.
804 */
805 if (!sort_dso.elide && !al->map->dso->slen_calculated)
806 dso__calc_col_width(al->map->dso, &session->hists);
807 780
808 al->sym = map__find_symbol(al->map, al->addr, filter); 781 al->sym = map__find_symbol(al->map, al->addr, filter);
809 } else {
810 const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
811
812 if (hists__col_len(&session->hists, HISTC_DSO) < unresolved_col_width &&
813 !symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
814 !symbol_conf.dso_list)
815 hists__set_col_len(&session->hists, HISTC_DSO,
816 unresolved_col_width);
817 } 782 }
818 783
819 if (symbol_conf.sym_list && al->sym && 784 if (symbol_conf.sym_list && al->sym &&
@@ -826,128 +791,3 @@ out_filtered:
826 al->filtered = true; 791 al->filtered = true;
827 return 0; 792 return 0;
828} 793}
829
830static int event__parse_id_sample(const event_t *event,
831 struct perf_session *session,
832 struct sample_data *sample)
833{
834 const u64 *array;
835 u64 type;
836
837 sample->cpu = sample->pid = sample->tid = -1;
838 sample->stream_id = sample->id = sample->time = -1ULL;
839
840 if (!session->sample_id_all)
841 return 0;
842
843 array = event->sample.array;
844 array += ((event->header.size -
845 sizeof(event->header)) / sizeof(u64)) - 1;
846 type = session->sample_type;
847
848 if (type & PERF_SAMPLE_CPU) {
849 u32 *p = (u32 *)array;
850 sample->cpu = *p;
851 array--;
852 }
853
854 if (type & PERF_SAMPLE_STREAM_ID) {
855 sample->stream_id = *array;
856 array--;
857 }
858
859 if (type & PERF_SAMPLE_ID) {
860 sample->id = *array;
861 array--;
862 }
863
864 if (type & PERF_SAMPLE_TIME) {
865 sample->time = *array;
866 array--;
867 }
868
869 if (type & PERF_SAMPLE_TID) {
870 u32 *p = (u32 *)array;
871 sample->pid = p[0];
872 sample->tid = p[1];
873 }
874
875 return 0;
876}
877
878int event__parse_sample(const event_t *event, struct perf_session *session,
879 struct sample_data *data)
880{
881 const u64 *array;
882 u64 type;
883
884 if (event->header.type != PERF_RECORD_SAMPLE)
885 return event__parse_id_sample(event, session, data);
886
887 array = event->sample.array;
888 type = session->sample_type;
889
890 if (type & PERF_SAMPLE_IP) {
891 data->ip = event->ip.ip;
892 array++;
893 }
894
895 if (type & PERF_SAMPLE_TID) {
896 u32 *p = (u32 *)array;
897 data->pid = p[0];
898 data->tid = p[1];
899 array++;
900 }
901
902 if (type & PERF_SAMPLE_TIME) {
903 data->time = *array;
904 array++;
905 }
906
907 if (type & PERF_SAMPLE_ADDR) {
908 data->addr = *array;
909 array++;
910 }
911
912 data->id = -1ULL;
913 if (type & PERF_SAMPLE_ID) {
914 data->id = *array;
915 array++;
916 }
917
918 if (type & PERF_SAMPLE_STREAM_ID) {
919 data->stream_id = *array;
920 array++;
921 }
922
923 if (type & PERF_SAMPLE_CPU) {
924 u32 *p = (u32 *)array;
925 data->cpu = *p;
926 array++;
927 } else
928 data->cpu = -1;
929
930 if (type & PERF_SAMPLE_PERIOD) {
931 data->period = *array;
932 array++;
933 }
934
935 if (type & PERF_SAMPLE_READ) {
936 pr_debug("PERF_SAMPLE_READ is unsuported for now\n");
937 return -1;
938 }
939
940 if (type & PERF_SAMPLE_CALLCHAIN) {
941 data->callchain = (struct ip_callchain *)array;
942 array += 1 + data->callchain->nr;
943 }
944
945 if (type & PERF_SAMPLE_RAW) {
946 u32 *p = (u32 *)array;
947 data->raw_size = *p;
948 p++;
949 data->raw_data = p;
950 }
951
952 return 0;
953}
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 2b7e91902f10..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;
@@ -117,7 +117,7 @@ struct tracing_data_event {
117 u32 size; 117 u32 size;
118}; 118};
119 119
120typedef union event_union { 120union perf_event {
121 struct perf_event_header header; 121 struct perf_event_header header;
122 struct ip_event ip; 122 struct ip_event ip;
123 struct mmap_event mmap; 123 struct mmap_event mmap;
@@ -130,48 +130,54 @@ typedef union event_union {
130 struct event_type_event event_type; 130 struct event_type_event event_type;
131 struct tracing_data_event tracing_data; 131 struct tracing_data_event tracing_data;
132 struct build_id_event build_id; 132 struct build_id_event build_id;
133} event_t; 133};
134 134
135void event__print_totals(void); 135void perf_event__print_totals(void);
136 136
137struct perf_session; 137struct perf_session;
138struct thread_map;
138 139
139typedef int (*event__handler_synth_t)(event_t *event, 140typedef int (*perf_event__handler_synth_t)(union perf_event *event,
141 struct perf_session *session);
142typedef int (*perf_event__handler_t)(union perf_event *event,
143 struct perf_sample *sample,
140 struct perf_session *session); 144 struct perf_session *session);
141typedef int (*event__handler_t)(event_t *event, struct sample_data *sample,
142 struct perf_session *session);
143 145
144int event__synthesize_thread(pid_t pid, event__handler_t process, 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,
145 struct perf_session *session); 161 struct perf_session *session);
146int event__synthesize_threads(event__handler_t process, 162int perf_event__process_lost(union perf_event *event, struct perf_sample *sample,
147 struct perf_session *session); 163 struct perf_session *session);
148int event__synthesize_kernel_mmap(event__handler_t process, 164int perf_event__process_mmap(union perf_event *event, struct perf_sample *sample,
149 struct perf_session *session, 165 struct perf_session *session);
150 struct machine *machine, 166int perf_event__process_task(union perf_event *event, struct perf_sample *sample,
151 const char *symbol_name); 167 struct perf_session *session);
152 168int perf_event__process(union perf_event *event, struct perf_sample *sample,
153int event__synthesize_modules(event__handler_t process,
154 struct perf_session *session,
155 struct machine *machine);
156
157int event__process_comm(event_t *self, struct sample_data *sample,
158 struct perf_session *session);
159int event__process_lost(event_t *self, struct sample_data *sample,
160 struct perf_session *session);
161int event__process_mmap(event_t *self, struct sample_data *sample,
162 struct perf_session *session);
163int event__process_task(event_t *self, struct sample_data *sample,
164 struct perf_session *session); 169 struct perf_session *session);
165int event__process(event_t *event, struct sample_data *sample,
166 struct perf_session *session);
167 170
168struct addr_location; 171struct addr_location;
169int event__preprocess_sample(const event_t *self, struct perf_session *session, 172int perf_event__preprocess_sample(const union perf_event *self,
170 struct addr_location *al, struct sample_data *data, 173 struct perf_session *session,
171 symbol_filter_t filter); 174 struct addr_location *al,
172int event__parse_sample(const event_t *event, struct perf_session *session, 175 struct perf_sample *sample,
173 struct sample_data *sample); 176 symbol_filter_t filter);
177
178const char *perf_event__name(unsigned int id);
174 179
175const char *event__get_event_name(unsigned int id); 180int perf_event__parse_sample(const union perf_event *event, u64 type,
181 bool sample_id_all, struct perf_sample *sample);
176 182
177#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..d852cefa20de
--- /dev/null
+++ b/tools/perf/util/evlist.c
@@ -0,0 +1,394 @@
1/*
2 * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
3 *
4 * Parts came from builtin-{top,stat,record}.c, see those files for further
5 * copyright notes.
6 *
7 * Released under the GPL v2. (and only v2, not any later version)
8 */
9#include <poll.h>
10#include "cpumap.h"
11#include "thread_map.h"
12#include "evlist.h"
13#include "evsel.h"
14#include "util.h"
15
16#include <sys/mman.h>
17
18#include <linux/bitops.h>
19#include <linux/hash.h>
20
21#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
22#define SID(e, x, y) xyarray__entry(e->sample_id, x, y)
23
24void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
25 struct thread_map *threads)
26{
27 int i;
28
29 for (i = 0; i < PERF_EVLIST__HLIST_SIZE; ++i)
30 INIT_HLIST_HEAD(&evlist->heads[i]);
31 INIT_LIST_HEAD(&evlist->entries);
32 perf_evlist__set_maps(evlist, cpus, threads);
33}
34
35struct perf_evlist *perf_evlist__new(struct cpu_map *cpus,
36 struct thread_map *threads)
37{
38 struct perf_evlist *evlist = zalloc(sizeof(*evlist));
39
40 if (evlist != NULL)
41 perf_evlist__init(evlist, cpus, threads);
42
43 return evlist;
44}
45
46static void perf_evlist__purge(struct perf_evlist *evlist)
47{
48 struct perf_evsel *pos, *n;
49
50 list_for_each_entry_safe(pos, n, &evlist->entries, node) {
51 list_del_init(&pos->node);
52 perf_evsel__delete(pos);
53 }
54
55 evlist->nr_entries = 0;
56}
57
58void perf_evlist__exit(struct perf_evlist *evlist)
59{
60 free(evlist->mmap);
61 free(evlist->pollfd);
62 evlist->mmap = NULL;
63 evlist->pollfd = NULL;
64}
65
66void perf_evlist__delete(struct perf_evlist *evlist)
67{
68 perf_evlist__purge(evlist);
69 perf_evlist__exit(evlist);
70 free(evlist);
71}
72
73void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry)
74{
75 list_add_tail(&entry->node, &evlist->entries);
76 ++evlist->nr_entries;
77}
78
79int perf_evlist__add_default(struct perf_evlist *evlist)
80{
81 struct perf_event_attr attr = {
82 .type = PERF_TYPE_HARDWARE,
83 .config = PERF_COUNT_HW_CPU_CYCLES,
84 };
85 struct perf_evsel *evsel = perf_evsel__new(&attr, 0);
86
87 if (evsel == NULL)
88 return -ENOMEM;
89
90 perf_evlist__add(evlist, evsel);
91 return 0;
92}
93
94int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
95{
96 int nfds = evlist->cpus->nr * evlist->threads->nr * evlist->nr_entries;
97 evlist->pollfd = malloc(sizeof(struct pollfd) * nfds);
98 return evlist->pollfd != NULL ? 0 : -ENOMEM;
99}
100
101void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd)
102{
103 fcntl(fd, F_SETFL, O_NONBLOCK);
104 evlist->pollfd[evlist->nr_fds].fd = fd;
105 evlist->pollfd[evlist->nr_fds].events = POLLIN;
106 evlist->nr_fds++;
107}
108
109static void perf_evlist__id_hash(struct perf_evlist *evlist,
110 struct perf_evsel *evsel,
111 int cpu, int thread, u64 id)
112{
113 int hash;
114 struct perf_sample_id *sid = SID(evsel, cpu, thread);
115
116 sid->id = id;
117 sid->evsel = evsel;
118 hash = hash_64(sid->id, PERF_EVLIST__HLIST_BITS);
119 hlist_add_head(&sid->node, &evlist->heads[hash]);
120}
121
122void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel,
123 int cpu, int thread, u64 id)
124{
125 perf_evlist__id_hash(evlist, evsel, cpu, thread, id);
126 evsel->id[evsel->ids++] = id;
127}
128
129static int perf_evlist__id_add_fd(struct perf_evlist *evlist,
130 struct perf_evsel *evsel,
131 int cpu, int thread, int fd)
132{
133 u64 read_data[4] = { 0, };
134 int id_idx = 1; /* The first entry is the counter value */
135
136 if (!(evsel->attr.read_format & PERF_FORMAT_ID) ||
137 read(fd, &read_data, sizeof(read_data)) == -1)
138 return -1;
139
140 if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
141 ++id_idx;
142 if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
143 ++id_idx;
144
145 perf_evlist__id_add(evlist, evsel, cpu, thread, read_data[id_idx]);
146 return 0;
147}
148
149struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id)
150{
151 struct hlist_head *head;
152 struct hlist_node *pos;
153 struct perf_sample_id *sid;
154 int hash;
155
156 if (evlist->nr_entries == 1)
157 return list_entry(evlist->entries.next, struct perf_evsel, node);
158
159 hash = hash_64(id, PERF_EVLIST__HLIST_BITS);
160 head = &evlist->heads[hash];
161
162 hlist_for_each_entry(sid, pos, head, node)
163 if (sid->id == id)
164 return sid->evsel;
165 return NULL;
166}
167
168union perf_event *perf_evlist__read_on_cpu(struct perf_evlist *evlist, int cpu)
169{
170 /* XXX Move this to perf.c, making it generally available */
171 unsigned int page_size = sysconf(_SC_PAGE_SIZE);
172 struct perf_mmap *md = &evlist->mmap[cpu];
173 unsigned int head = perf_mmap__read_head(md);
174 unsigned int old = md->prev;
175 unsigned char *data = md->base + page_size;
176 union perf_event *event = NULL;
177
178 if (evlist->overwrite) {
179 /*
180 * If we're further behind than half the buffer, there's a chance
181 * the writer will bite our tail and mess up the samples under us.
182 *
183 * If we somehow ended up ahead of the head, we got messed up.
184 *
185 * In either case, truncate and restart at head.
186 */
187 int diff = head - old;
188 if (diff > md->mask / 2 || diff < 0) {
189 fprintf(stderr, "WARNING: failed to keep up with mmap data.\n");
190
191 /*
192 * head points to a known good entry, start there.
193 */
194 old = head;
195 }
196 }
197
198 if (old != head) {
199 size_t size;
200
201 event = (union perf_event *)&data[old & md->mask];
202 size = event->header.size;
203
204 /*
205 * Event straddles the mmap boundary -- header should always
206 * be inside due to u64 alignment of output.
207 */
208 if ((old & md->mask) + size != ((old + size) & md->mask)) {
209 unsigned int offset = old;
210 unsigned int len = min(sizeof(*event), size), cpy;
211 void *dst = &evlist->event_copy;
212
213 do {
214 cpy = min(md->mask + 1 - (offset & md->mask), len);
215 memcpy(dst, &data[offset & md->mask], cpy);
216 offset += cpy;
217 dst += cpy;
218 len -= cpy;
219 } while (len);
220
221 event = &evlist->event_copy;
222 }
223
224 old += size;
225 }
226
227 md->prev = old;
228
229 if (!evlist->overwrite)
230 perf_mmap__write_tail(md, old);
231
232 return event;
233}
234
235void perf_evlist__munmap(struct perf_evlist *evlist)
236{
237 int cpu;
238
239 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
240 if (evlist->mmap[cpu].base != NULL) {
241 munmap(evlist->mmap[cpu].base, evlist->mmap_len);
242 evlist->mmap[cpu].base = NULL;
243 }
244 }
245}
246
247int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
248{
249 evlist->mmap = zalloc(evlist->cpus->nr * sizeof(struct perf_mmap));
250 return evlist->mmap != NULL ? 0 : -ENOMEM;
251}
252
253static int __perf_evlist__mmap(struct perf_evlist *evlist, int cpu, int prot,
254 int mask, int fd)
255{
256 evlist->mmap[cpu].prev = 0;
257 evlist->mmap[cpu].mask = mask;
258 evlist->mmap[cpu].base = mmap(NULL, evlist->mmap_len, prot,
259 MAP_SHARED, fd, 0);
260 if (evlist->mmap[cpu].base == MAP_FAILED)
261 return -1;
262
263 perf_evlist__add_pollfd(evlist, fd);
264 return 0;
265}
266
267/** perf_evlist__mmap - Create per cpu maps to receive events
268 *
269 * @evlist - list of events
270 * @pages - map length in pages
271 * @overwrite - overwrite older events?
272 *
273 * If overwrite is false the user needs to signal event consuption using:
274 *
275 * struct perf_mmap *m = &evlist->mmap[cpu];
276 * unsigned int head = perf_mmap__read_head(m);
277 *
278 * perf_mmap__write_tail(m, head)
279 *
280 * Using perf_evlist__read_on_cpu does this automatically.
281 */
282int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite)
283{
284 unsigned int page_size = sysconf(_SC_PAGE_SIZE);
285 int mask = pages * page_size - 1, cpu;
286 struct perf_evsel *first_evsel, *evsel;
287 const struct cpu_map *cpus = evlist->cpus;
288 const struct thread_map *threads = evlist->threads;
289 int thread, prot = PROT_READ | (overwrite ? 0 : PROT_WRITE);
290
291 if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0)
292 return -ENOMEM;
293
294 if (evlist->pollfd == NULL && perf_evlist__alloc_pollfd(evlist) < 0)
295 return -ENOMEM;
296
297 evlist->overwrite = overwrite;
298 evlist->mmap_len = (pages + 1) * page_size;
299 first_evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
300
301 list_for_each_entry(evsel, &evlist->entries, node) {
302 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
303 evsel->sample_id == NULL &&
304 perf_evsel__alloc_id(evsel, cpus->nr, threads->nr) < 0)
305 return -ENOMEM;
306
307 for (cpu = 0; cpu < cpus->nr; cpu++) {
308 for (thread = 0; thread < threads->nr; thread++) {
309 int fd = FD(evsel, cpu, thread);
310
311 if (evsel->idx || thread) {
312 if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT,
313 FD(first_evsel, cpu, 0)) != 0)
314 goto out_unmap;
315 } else if (__perf_evlist__mmap(evlist, cpu, prot, mask, fd) < 0)
316 goto out_unmap;
317
318 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
319 perf_evlist__id_add_fd(evlist, evsel, cpu, thread, fd) < 0)
320 goto out_unmap;
321 }
322 }
323 }
324
325 return 0;
326
327out_unmap:
328 for (cpu = 0; cpu < cpus->nr; cpu++) {
329 if (evlist->mmap[cpu].base != NULL) {
330 munmap(evlist->mmap[cpu].base, evlist->mmap_len);
331 evlist->mmap[cpu].base = NULL;
332 }
333 }
334 return -1;
335}
336
337int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid,
338 pid_t target_tid, const char *cpu_list)
339{
340 evlist->threads = thread_map__new(target_pid, target_tid);
341
342 if (evlist->threads == NULL)
343 return -1;
344
345 if (target_tid != -1)
346 evlist->cpus = cpu_map__dummy_new();
347 else
348 evlist->cpus = cpu_map__new(cpu_list);
349
350 if (evlist->cpus == NULL)
351 goto out_delete_threads;
352
353 return 0;
354
355out_delete_threads:
356 thread_map__delete(evlist->threads);
357 return -1;
358}
359
360void perf_evlist__delete_maps(struct perf_evlist *evlist)
361{
362 cpu_map__delete(evlist->cpus);
363 thread_map__delete(evlist->threads);
364 evlist->cpus = NULL;
365 evlist->threads = NULL;
366}
367
368int perf_evlist__set_filters(struct perf_evlist *evlist)
369{
370 const struct thread_map *threads = evlist->threads;
371 const struct cpu_map *cpus = evlist->cpus;
372 struct perf_evsel *evsel;
373 char *filter;
374 int thread;
375 int cpu;
376 int err;
377 int fd;
378
379 list_for_each_entry(evsel, &evlist->entries, node) {
380 filter = evsel->filter;
381 if (!filter)
382 continue;
383 for (cpu = 0; cpu < cpus->nr; cpu++) {
384 for (thread = 0; thread < threads->nr; thread++) {
385 fd = FD(evsel, cpu, thread);
386 err = ioctl(fd, PERF_EVENT_IOC_SET_FILTER, filter);
387 if (err)
388 return err;
389 }
390 }
391 }
392
393 return 0;
394}
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
index f5cfed60af98..662596afd7f1 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -1,20 +1,34 @@
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
1#include "evsel.h" 10#include "evsel.h"
2#include "../perf.h" 11#include "evlist.h"
3#include "util.h" 12#include "util.h"
4#include "cpumap.h" 13#include "cpumap.h"
5#include "thread.h" 14#include "thread_map.h"
6 15
7#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) 16#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
8 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
9struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) 26struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
10{ 27{
11 struct perf_evsel *evsel = zalloc(sizeof(*evsel)); 28 struct perf_evsel *evsel = zalloc(sizeof(*evsel));
12 29
13 if (evsel != NULL) { 30 if (evsel != NULL)
14 evsel->idx = idx; 31 perf_evsel__init(evsel, attr, idx);
15 evsel->attr = *attr;
16 INIT_LIST_HEAD(&evsel->node);
17 }
18 32
19 return evsel; 33 return evsel;
20} 34}
@@ -25,6 +39,22 @@ int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
25 return evsel->fd != NULL ? 0 : -ENOMEM; 39 return evsel->fd != NULL ? 0 : -ENOMEM;
26} 40}
27 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
28int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus) 58int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus)
29{ 59{
30 evsel->counts = zalloc((sizeof(*evsel->counts) + 60 evsel->counts = zalloc((sizeof(*evsel->counts) +
@@ -38,6 +68,14 @@ void perf_evsel__free_fd(struct perf_evsel *evsel)
38 evsel->fd = NULL; 68 evsel->fd = NULL;
39} 69}
40 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
41void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads) 79void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
42{ 80{
43 int cpu, thread; 81 int cpu, thread;
@@ -49,10 +87,19 @@ void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
49 } 87 }
50} 88}
51 89
52void perf_evsel__delete(struct perf_evsel *evsel) 90void perf_evsel__exit(struct perf_evsel *evsel)
53{ 91{
54 assert(list_empty(&evsel->node)); 92 assert(list_empty(&evsel->node));
55 xyarray__delete(evsel->fd); 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);
56 free(evsel); 103 free(evsel);
57} 104}
58 105
@@ -90,7 +137,7 @@ int __perf_evsel__read(struct perf_evsel *evsel,
90 int cpu, thread; 137 int cpu, thread;
91 struct perf_counts_values *aggr = &evsel->counts->aggr, count; 138 struct perf_counts_values *aggr = &evsel->counts->aggr, count;
92 139
93 aggr->val = 0; 140 aggr->val = aggr->ena = aggr->run = 0;
94 141
95 for (cpu = 0; cpu < ncpus; cpu++) { 142 for (cpu = 0; cpu < ncpus; cpu++) {
96 for (thread = 0; thread < nthreads; thread++) { 143 for (thread = 0; thread < nthreads; thread++) {
@@ -128,21 +175,51 @@ int __perf_evsel__read(struct perf_evsel *evsel,
128} 175}
129 176
130static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, 177static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
131 struct thread_map *threads) 178 struct thread_map *threads, bool group, bool inherit)
132{ 179{
133 int cpu, thread; 180 int cpu, thread;
181 unsigned long flags = 0;
182 int pid = -1;
134 183
135 if (evsel->fd == NULL && 184 if (evsel->fd == NULL &&
136 perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0) 185 perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0)
137 return -1; 186 return -1;
138 187
188 if (evsel->cgrp) {
189 flags = PERF_FLAG_PID_CGROUP;
190 pid = evsel->cgrp->fd;
191 }
192
139 for (cpu = 0; cpu < cpus->nr; cpu++) { 193 for (cpu = 0; cpu < cpus->nr; cpu++) {
194 int group_fd = -1;
195 /*
196 * Don't allow mmap() of inherited per-task counters. This
197 * would create a performance issue due to all children writing
198 * to the same buffer.
199 *
200 * FIXME:
201 * Proper fix is not to pass 'inherit' to perf_evsel__open*,
202 * but a 'flags' parameter, with 'group' folded there as well,
203 * then introduce a PERF_O_{MMAP,GROUP,INHERIT} enum, and if
204 * O_MMAP is set, emit a warning if cpu < 0 and O_INHERIT is
205 * set. Lets go for the minimal fix first tho.
206 */
207 evsel->attr.inherit = (cpus->map[cpu] >= 0) && inherit;
208
140 for (thread = 0; thread < threads->nr; thread++) { 209 for (thread = 0; thread < threads->nr; thread++) {
210
211 if (!evsel->cgrp)
212 pid = threads->map[thread];
213
141 FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr, 214 FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr,
142 threads->map[thread], 215 pid,
143 cpus->map[cpu], -1, 0); 216 cpus->map[cpu],
217 group_fd, flags);
144 if (FD(evsel, cpu, thread) < 0) 218 if (FD(evsel, cpu, thread) < 0)
145 goto out_close; 219 goto out_close;
220
221 if (group && group_fd == -1)
222 group_fd = FD(evsel, cpu, thread);
146 } 223 }
147 } 224 }
148 225
@@ -175,10 +252,9 @@ static struct {
175 .threads = { -1, }, 252 .threads = { -1, },
176}; 253};
177 254
178int perf_evsel__open(struct perf_evsel *evsel, 255int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
179 struct cpu_map *cpus, struct thread_map *threads) 256 struct thread_map *threads, bool group, bool inherit)
180{ 257{
181
182 if (cpus == NULL) { 258 if (cpus == NULL) {
183 /* Work around old compiler warnings about strict aliasing */ 259 /* Work around old compiler warnings about strict aliasing */
184 cpus = &empty_cpu_map.map; 260 cpus = &empty_cpu_map.map;
@@ -187,15 +263,135 @@ int perf_evsel__open(struct perf_evsel *evsel,
187 if (threads == NULL) 263 if (threads == NULL)
188 threads = &empty_thread_map.map; 264 threads = &empty_thread_map.map;
189 265
190 return __perf_evsel__open(evsel, cpus, threads); 266 return __perf_evsel__open(evsel, cpus, threads, group, inherit);
191} 267}
192 268
193int perf_evsel__open_per_cpu(struct perf_evsel *evsel, struct cpu_map *cpus) 269int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
270 struct cpu_map *cpus, bool group, bool inherit)
194{ 271{
195 return __perf_evsel__open(evsel, cpus, &empty_thread_map.map); 272 return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group, inherit);
273}
274
275int perf_evsel__open_per_thread(struct perf_evsel *evsel,
276 struct thread_map *threads, bool group, bool inherit)
277{
278 return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group, inherit);
279}
280
281static int perf_event__parse_id_sample(const union perf_event *event, u64 type,
282 struct perf_sample *sample)
283{
284 const u64 *array = event->sample.array;
285
286 array += ((event->header.size -
287 sizeof(event->header)) / sizeof(u64)) - 1;
288
289 if (type & PERF_SAMPLE_CPU) {
290 u32 *p = (u32 *)array;
291 sample->cpu = *p;
292 array--;
293 }
294
295 if (type & PERF_SAMPLE_STREAM_ID) {
296 sample->stream_id = *array;
297 array--;
298 }
299
300 if (type & PERF_SAMPLE_ID) {
301 sample->id = *array;
302 array--;
303 }
304
305 if (type & PERF_SAMPLE_TIME) {
306 sample->time = *array;
307 array--;
308 }
309
310 if (type & PERF_SAMPLE_TID) {
311 u32 *p = (u32 *)array;
312 sample->pid = p[0];
313 sample->tid = p[1];
314 }
315
316 return 0;
196} 317}
197 318
198int perf_evsel__open_per_thread(struct perf_evsel *evsel, struct thread_map *threads) 319int perf_event__parse_sample(const union perf_event *event, u64 type,
320 bool sample_id_all, struct perf_sample *data)
199{ 321{
200 return __perf_evsel__open(evsel, &empty_cpu_map.map, threads); 322 const u64 *array;
323
324 data->cpu = data->pid = data->tid = -1;
325 data->stream_id = data->id = data->time = -1ULL;
326
327 if (event->header.type != PERF_RECORD_SAMPLE) {
328 if (!sample_id_all)
329 return 0;
330 return perf_event__parse_id_sample(event, type, data);
331 }
332
333 array = event->sample.array;
334
335 if (type & PERF_SAMPLE_IP) {
336 data->ip = event->ip.ip;
337 array++;
338 }
339
340 if (type & PERF_SAMPLE_TID) {
341 u32 *p = (u32 *)array;
342 data->pid = p[0];
343 data->tid = p[1];
344 array++;
345 }
346
347 if (type & PERF_SAMPLE_TIME) {
348 data->time = *array;
349 array++;
350 }
351
352 if (type & PERF_SAMPLE_ADDR) {
353 data->addr = *array;
354 array++;
355 }
356
357 data->id = -1ULL;
358 if (type & PERF_SAMPLE_ID) {
359 data->id = *array;
360 array++;
361 }
362
363 if (type & PERF_SAMPLE_STREAM_ID) {
364 data->stream_id = *array;
365 array++;
366 }
367
368 if (type & PERF_SAMPLE_CPU) {
369 u32 *p = (u32 *)array;
370 data->cpu = *p;
371 array++;
372 }
373
374 if (type & PERF_SAMPLE_PERIOD) {
375 data->period = *array;
376 array++;
377 }
378
379 if (type & PERF_SAMPLE_READ) {
380 fprintf(stderr, "PERF_SAMPLE_READ is unsuported for now\n");
381 return -1;
382 }
383
384 if (type & PERF_SAMPLE_CALLCHAIN) {
385 data->callchain = (struct ip_callchain *)array;
386 array += 1 + data->callchain->nr;
387 }
388
389 if (type & PERF_SAMPLE_RAW) {
390 u32 *p = (u32 *)array;
391 data->raw_size = *p;
392 p++;
393 data->raw_data = p;
394 }
395
396 return 0;
201} 397}
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index b2d755fe88a5..6710ab538342 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -6,6 +6,8 @@
6#include "../../../include/linux/perf_event.h" 6#include "../../../include/linux/perf_event.h"
7#include "types.h" 7#include "types.h"
8#include "xyarray.h" 8#include "xyarray.h"
9#include "cgroup.h"
10#include "hist.h"
9 11
10struct perf_counts_values { 12struct perf_counts_values {
11 union { 13 union {
@@ -24,31 +26,66 @@ struct perf_counts {
24 struct perf_counts_values cpu[]; 26 struct perf_counts_values cpu[];
25}; 27};
26 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 */
27struct perf_evsel { 47struct perf_evsel {
28 struct list_head node; 48 struct list_head node;
29 struct perf_event_attr attr; 49 struct perf_event_attr attr;
30 char *filter; 50 char *filter;
31 struct xyarray *fd; 51 struct xyarray *fd;
52 struct xyarray *sample_id;
53 u64 *id;
32 struct perf_counts *counts; 54 struct perf_counts *counts;
33 int idx; 55 int idx;
34 void *priv; 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;
35}; 64};
36 65
37struct cpu_map; 66struct cpu_map;
38struct thread_map; 67struct thread_map;
68struct perf_evlist;
39 69
40struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx); 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);
41void perf_evsel__delete(struct perf_evsel *evsel); 74void perf_evsel__delete(struct perf_evsel *evsel);
42 75
43int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); 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);
44int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); 78int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus);
45void perf_evsel__free_fd(struct perf_evsel *evsel); 79void perf_evsel__free_fd(struct perf_evsel *evsel);
80void perf_evsel__free_id(struct perf_evsel *evsel);
46void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); 81void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
47 82
48int perf_evsel__open_per_cpu(struct perf_evsel *evsel, struct cpu_map *cpus); 83int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
49int perf_evsel__open_per_thread(struct perf_evsel *evsel, struct thread_map *threads); 84 struct cpu_map *cpus, bool group, bool inherit);
50int perf_evsel__open(struct perf_evsel *evsel, 85int perf_evsel__open_per_thread(struct perf_evsel *evsel,
51 struct cpu_map *cpus, struct thread_map *threads); 86 struct thread_map *threads, bool group, bool inherit);
87int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
88 struct thread_map *threads, bool group, bool inherit);
52 89
53#define perf_evsel__match(evsel, t, c) \ 90#define perf_evsel__match(evsel, t, c) \
54 (evsel->attr.type == PERF_TYPE_##t && \ 91 (evsel->attr.type == PERF_TYPE_##t && \
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 f6a929e74981..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,19 +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
155void perf_header__clear_feat(struct perf_header *self, int feat) 74void perf_header__clear_feat(struct perf_header *header, int feat)
156{ 75{
157 clear_bit(feat, self->adds_features); 76 clear_bit(feat, header->adds_features);
158} 77}
159 78
160bool perf_header__has_feat(const struct perf_header *self, int feat) 79bool perf_header__has_feat(const struct perf_header *header, int feat)
161{ 80{
162 return test_bit(feat, self->adds_features); 81 return test_bit(feat, header->adds_features);
163} 82}
164 83
165static int do_write(int fd, const void *buf, size_t size) 84static int do_write(int fd, const void *buf, size_t size)
@@ -228,22 +147,22 @@ static int __dsos__write_buildid_table(struct list_head *head, pid_t pid,
228 return 0; 147 return 0;
229} 148}
230 149
231static int machine__write_buildid_table(struct machine *self, int fd) 150static int machine__write_buildid_table(struct machine *machine, int fd)
232{ 151{
233 int err; 152 int err;
234 u16 kmisc = PERF_RECORD_MISC_KERNEL, 153 u16 kmisc = PERF_RECORD_MISC_KERNEL,
235 umisc = PERF_RECORD_MISC_USER; 154 umisc = PERF_RECORD_MISC_USER;
236 155
237 if (!machine__is_host(self)) { 156 if (!machine__is_host(machine)) {
238 kmisc = PERF_RECORD_MISC_GUEST_KERNEL; 157 kmisc = PERF_RECORD_MISC_GUEST_KERNEL;
239 umisc = PERF_RECORD_MISC_GUEST_USER; 158 umisc = PERF_RECORD_MISC_GUEST_USER;
240 } 159 }
241 160
242 err = __dsos__write_buildid_table(&self->kernel_dsos, self->pid, 161 err = __dsos__write_buildid_table(&machine->kernel_dsos, machine->pid,
243 kmisc, fd); 162 kmisc, fd);
244 if (err == 0) 163 if (err == 0)
245 err = __dsos__write_buildid_table(&self->user_dsos, 164 err = __dsos__write_buildid_table(&machine->user_dsos,
246 self->pid, umisc, fd); 165 machine->pid, umisc, fd);
247 return err; 166 return err;
248} 167}
249 168
@@ -270,11 +189,15 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
270 const char *name, bool is_kallsyms) 189 const char *name, bool is_kallsyms)
271{ 190{
272 const size_t size = PATH_MAX; 191 const size_t size = PATH_MAX;
273 char *realname = realpath(name, NULL), 192 char *realname, *filename = malloc(size),
274 *filename = malloc(size),
275 *linkname = malloc(size), *targetname; 193 *linkname = malloc(size), *targetname;
276 int len, err = -1; 194 int len, err = -1;
277 195
196 if (is_kallsyms)
197 realname = (char *)name;
198 else
199 realname = realpath(name, NULL);
200
278 if (realname == NULL || filename == NULL || linkname == NULL) 201 if (realname == NULL || filename == NULL || linkname == NULL)
279 goto out_free; 202 goto out_free;
280 203
@@ -306,7 +229,8 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
306 if (symlink(targetname, linkname) == 0) 229 if (symlink(targetname, linkname) == 0)
307 err = 0; 230 err = 0;
308out_free: 231out_free:
309 free(realname); 232 if (!is_kallsyms)
233 free(realname);
310 free(filename); 234 free(filename);
311 free(linkname); 235 free(linkname);
312 return err; 236 return err;
@@ -361,12 +285,12 @@ out_free:
361 return err; 285 return err;
362} 286}
363 287
364static int dso__cache_build_id(struct dso *self, const char *debugdir) 288static int dso__cache_build_id(struct dso *dso, const char *debugdir)
365{ 289{
366 bool is_kallsyms = self->kernel && self->long_name[0] != '/'; 290 bool is_kallsyms = dso->kernel && dso->long_name[0] != '/';
367 291
368 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),
369 self->long_name, debugdir, is_kallsyms); 293 dso->long_name, debugdir, is_kallsyms);
370} 294}
371 295
372static 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)
@@ -381,14 +305,14 @@ static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir)
381 return err; 305 return err;
382} 306}
383 307
384static int machine__cache_build_ids(struct machine *self, const char *debugdir) 308static int machine__cache_build_ids(struct machine *machine, const char *debugdir)
385{ 309{
386 int ret = __dsos__cache_build_ids(&self->kernel_dsos, debugdir); 310 int ret = __dsos__cache_build_ids(&machine->kernel_dsos, debugdir);
387 ret |= __dsos__cache_build_ids(&self->user_dsos, debugdir); 311 ret |= __dsos__cache_build_ids(&machine->user_dsos, debugdir);
388 return ret; 312 return ret;
389} 313}
390 314
391static int perf_session__cache_build_ids(struct perf_session *self) 315static int perf_session__cache_build_ids(struct perf_session *session)
392{ 316{
393 struct rb_node *nd; 317 struct rb_node *nd;
394 int ret; 318 int ret;
@@ -399,28 +323,28 @@ static int perf_session__cache_build_ids(struct perf_session *self)
399 if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) 323 if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
400 return -1; 324 return -1;
401 325
402 ret = machine__cache_build_ids(&self->host_machine, debugdir); 326 ret = machine__cache_build_ids(&session->host_machine, debugdir);
403 327
404 for (nd = rb_first(&self->machines); nd; nd = rb_next(nd)) { 328 for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) {
405 struct machine *pos = rb_entry(nd, struct machine, rb_node); 329 struct machine *pos = rb_entry(nd, struct machine, rb_node);
406 ret |= machine__cache_build_ids(pos, debugdir); 330 ret |= machine__cache_build_ids(pos, debugdir);
407 } 331 }
408 return ret ? -1 : 0; 332 return ret ? -1 : 0;
409} 333}
410 334
411static bool machine__read_build_ids(struct machine *self, bool with_hits) 335static bool machine__read_build_ids(struct machine *machine, bool with_hits)
412{ 336{
413 bool ret = __dsos__read_build_ids(&self->kernel_dsos, with_hits); 337 bool ret = __dsos__read_build_ids(&machine->kernel_dsos, with_hits);
414 ret |= __dsos__read_build_ids(&self->user_dsos, with_hits); 338 ret |= __dsos__read_build_ids(&machine->user_dsos, with_hits);
415 return ret; 339 return ret;
416} 340}
417 341
418static 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)
419{ 343{
420 struct rb_node *nd; 344 struct rb_node *nd;
421 bool ret = machine__read_build_ids(&self->host_machine, with_hits); 345 bool ret = machine__read_build_ids(&session->host_machine, with_hits);
422 346
423 for (nd = rb_first(&self->machines); nd; nd = rb_next(nd)) { 347 for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) {
424 struct machine *pos = rb_entry(nd, struct machine, rb_node); 348 struct machine *pos = rb_entry(nd, struct machine, rb_node);
425 ret |= machine__read_build_ids(pos, with_hits); 349 ret |= machine__read_build_ids(pos, with_hits);
426 } 350 }
@@ -428,7 +352,8 @@ static bool perf_session__read_build_ids(struct perf_session *self, bool with_hi
428 return ret; 352 return ret;
429} 353}
430 354
431static 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)
432{ 357{
433 int nr_sections; 358 int nr_sections;
434 struct perf_session *session; 359 struct perf_session *session;
@@ -437,13 +362,13 @@ static int perf_header__adds_write(struct perf_header *self, int fd)
437 u64 sec_start; 362 u64 sec_start;
438 int idx = 0, err; 363 int idx = 0, err;
439 364
440 session = container_of(self, struct perf_session, header); 365 session = container_of(header, struct perf_session, header);
441 366
442 if (perf_header__has_feat(self, HEADER_BUILD_ID && 367 if (perf_header__has_feat(header, HEADER_BUILD_ID &&
443 !perf_session__read_build_ids(session, true))) 368 !perf_session__read_build_ids(session, true)))
444 perf_header__clear_feat(self, HEADER_BUILD_ID); 369 perf_header__clear_feat(header, HEADER_BUILD_ID);
445 370
446 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); 371 nr_sections = bitmap_weight(header->adds_features, HEADER_FEAT_BITS);
447 if (!nr_sections) 372 if (!nr_sections)
448 return 0; 373 return 0;
449 374
@@ -453,28 +378,28 @@ static int perf_header__adds_write(struct perf_header *self, int fd)
453 378
454 sec_size = sizeof(*feat_sec) * nr_sections; 379 sec_size = sizeof(*feat_sec) * nr_sections;
455 380
456 sec_start = self->data_offset + self->data_size; 381 sec_start = header->data_offset + header->data_size;
457 lseek(fd, sec_start + sec_size, SEEK_SET); 382 lseek(fd, sec_start + sec_size, SEEK_SET);
458 383
459 if (perf_header__has_feat(self, HEADER_TRACE_INFO)) { 384 if (perf_header__has_feat(header, HEADER_TRACE_INFO)) {
460 struct perf_file_section *trace_sec; 385 struct perf_file_section *trace_sec;
461 386
462 trace_sec = &feat_sec[idx++]; 387 trace_sec = &feat_sec[idx++];
463 388
464 /* Write trace info */ 389 /* Write trace info */
465 trace_sec->offset = lseek(fd, 0, SEEK_CUR); 390 trace_sec->offset = lseek(fd, 0, SEEK_CUR);
466 read_tracing_data(fd, &evsel_list); 391 read_tracing_data(fd, &evlist->entries);
467 trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset; 392 trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset;
468 } 393 }
469 394
470 if (perf_header__has_feat(self, HEADER_BUILD_ID)) { 395 if (perf_header__has_feat(header, HEADER_BUILD_ID)) {
471 struct perf_file_section *buildid_sec; 396 struct perf_file_section *buildid_sec;
472 397
473 buildid_sec = &feat_sec[idx++]; 398 buildid_sec = &feat_sec[idx++];
474 399
475 /* Write build-ids */ 400 /* Write build-ids */
476 buildid_sec->offset = lseek(fd, 0, SEEK_CUR); 401 buildid_sec->offset = lseek(fd, 0, SEEK_CUR);
477 err = dsos__write_buildid_table(self, fd); 402 err = dsos__write_buildid_table(header, fd);
478 if (err < 0) { 403 if (err < 0) {
479 pr_debug("failed to write buildid table\n"); 404 pr_debug("failed to write buildid table\n");
480 goto out_free; 405 goto out_free;
@@ -513,32 +438,41 @@ int perf_header__write_pipe(int fd)
513 return 0; 438 return 0;
514} 439}
515 440
516int 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)
517{ 444{
518 struct perf_file_header f_header; 445 struct perf_file_header f_header;
519 struct perf_file_attr f_attr; 446 struct perf_file_attr f_attr;
520 struct perf_header_attr *attr; 447 struct perf_header *header = &session->header;
521 int i, err; 448 struct perf_evsel *attr, *pair = NULL;
449 int err;
522 450
523 lseek(fd, sizeof(f_header), SEEK_SET); 451 lseek(fd, sizeof(f_header), SEEK_SET);
524 452
525 for (i = 0; i < self->attrs; i++) { 453 if (session->evlist != evlist)
526 attr = self->attr[i]; 454 pair = list_entry(session->evlist->entries.next, struct perf_evsel, node);
527 455
456 list_for_each_entry(attr, &evlist->entries, node) {
528 attr->id_offset = lseek(fd, 0, SEEK_CUR); 457 attr->id_offset = lseek(fd, 0, SEEK_CUR);
529 err = do_write(fd, attr->id, attr->ids * sizeof(u64)); 458 err = do_write(fd, attr->id, attr->ids * sizeof(u64));
530 if (err < 0) { 459 if (err < 0) {
460out_err_write:
531 pr_debug("failed to write perf header\n"); 461 pr_debug("failed to write perf header\n");
532 return err; 462 return err;
533 } 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 }
534 } 471 }
535 472
473 header->attr_offset = lseek(fd, 0, SEEK_CUR);
536 474
537 self->attr_offset = lseek(fd, 0, SEEK_CUR); 475 list_for_each_entry(attr, &evlist->entries, node) {
538
539 for (i = 0; i < self->attrs; i++) {
540 attr = self->attr[i];
541
542 f_attr = (struct perf_file_attr){ 476 f_attr = (struct perf_file_attr){
543 .attr = attr->attr, 477 .attr = attr->attr,
544 .ids = { 478 .ids = {
@@ -553,20 +487,20 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit)
553 } 487 }
554 } 488 }
555 489
556 self->event_offset = lseek(fd, 0, SEEK_CUR); 490 header->event_offset = lseek(fd, 0, SEEK_CUR);
557 self->event_size = event_count * sizeof(struct perf_trace_event_type); 491 header->event_size = event_count * sizeof(struct perf_trace_event_type);
558 if (events) { 492 if (events) {
559 err = do_write(fd, events, self->event_size); 493 err = do_write(fd, events, header->event_size);
560 if (err < 0) { 494 if (err < 0) {
561 pr_debug("failed to write perf header events\n"); 495 pr_debug("failed to write perf header events\n");
562 return err; 496 return err;
563 } 497 }
564 } 498 }
565 499
566 self->data_offset = lseek(fd, 0, SEEK_CUR); 500 header->data_offset = lseek(fd, 0, SEEK_CUR);
567 501
568 if (at_exit) { 502 if (at_exit) {
569 err = perf_header__adds_write(self, fd); 503 err = perf_header__adds_write(header, evlist, fd);
570 if (err < 0) 504 if (err < 0)
571 return err; 505 return err;
572 } 506 }
@@ -576,20 +510,20 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit)
576 .size = sizeof(f_header), 510 .size = sizeof(f_header),
577 .attr_size = sizeof(f_attr), 511 .attr_size = sizeof(f_attr),
578 .attrs = { 512 .attrs = {
579 .offset = self->attr_offset, 513 .offset = header->attr_offset,
580 .size = self->attrs * sizeof(f_attr), 514 .size = evlist->nr_entries * sizeof(f_attr),
581 }, 515 },
582 .data = { 516 .data = {
583 .offset = self->data_offset, 517 .offset = header->data_offset,
584 .size = self->data_size, 518 .size = header->data_size,
585 }, 519 },
586 .event_types = { 520 .event_types = {
587 .offset = self->event_offset, 521 .offset = header->event_offset,
588 .size = self->event_size, 522 .size = header->event_size,
589 }, 523 },
590 }; 524 };
591 525
592 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));
593 527
594 lseek(fd, 0, SEEK_SET); 528 lseek(fd, 0, SEEK_SET);
595 err = do_write(fd, &f_header, sizeof(f_header)); 529 err = do_write(fd, &f_header, sizeof(f_header));
@@ -597,26 +531,26 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit)
597 pr_debug("failed to write perf header\n"); 531 pr_debug("failed to write perf header\n");
598 return err; 532 return err;
599 } 533 }
600 lseek(fd, self->data_offset + self->data_size, SEEK_SET); 534 lseek(fd, header->data_offset + header->data_size, SEEK_SET);
601 535
602 self->frozen = 1; 536 header->frozen = 1;
603 return 0; 537 return 0;
604} 538}
605 539
606static int perf_header__getbuffer64(struct perf_header *self, 540static int perf_header__getbuffer64(struct perf_header *header,
607 int fd, void *buf, size_t size) 541 int fd, void *buf, size_t size)
608{ 542{
609 if (readn(fd, buf, size) <= 0) 543 if (readn(fd, buf, size) <= 0)
610 return -1; 544 return -1;
611 545
612 if (self->needs_swap) 546 if (header->needs_swap)
613 mem_bswap_64(buf, size); 547 mem_bswap_64(buf, size);
614 548
615 return 0; 549 return 0;
616} 550}
617 551
618int perf_header__process_sections(struct perf_header *self, int fd, 552int perf_header__process_sections(struct perf_header *header, int fd,
619 int (*process)(struct perf_file_section *self, 553 int (*process)(struct perf_file_section *section,
620 struct perf_header *ph, 554 struct perf_header *ph,
621 int feat, int fd)) 555 int feat, int fd))
622{ 556{
@@ -626,7 +560,7 @@ int perf_header__process_sections(struct perf_header *self, int fd,
626 int idx = 0; 560 int idx = 0;
627 int err = -1, feat = 1; 561 int err = -1, feat = 1;
628 562
629 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); 563 nr_sections = bitmap_weight(header->adds_features, HEADER_FEAT_BITS);
630 if (!nr_sections) 564 if (!nr_sections)
631 return 0; 565 return 0;
632 566
@@ -636,17 +570,17 @@ int perf_header__process_sections(struct perf_header *self, int fd,
636 570
637 sec_size = sizeof(*feat_sec) * nr_sections; 571 sec_size = sizeof(*feat_sec) * nr_sections;
638 572
639 lseek(fd, self->data_offset + self->data_size, SEEK_SET); 573 lseek(fd, header->data_offset + header->data_size, SEEK_SET);
640 574
641 if (perf_header__getbuffer64(self, fd, feat_sec, sec_size)) 575 if (perf_header__getbuffer64(header, fd, feat_sec, sec_size))
642 goto out_free; 576 goto out_free;
643 577
644 err = 0; 578 err = 0;
645 while (idx < nr_sections && feat < HEADER_LAST_FEATURE) { 579 while (idx < nr_sections && feat < HEADER_LAST_FEATURE) {
646 if (perf_header__has_feat(self, feat)) { 580 if (perf_header__has_feat(header, feat)) {
647 struct perf_file_section *sec = &feat_sec[idx++]; 581 struct perf_file_section *sec = &feat_sec[idx++];
648 582
649 err = process(sec, self, feat, fd); 583 err = process(sec, header, feat, fd);
650 if (err < 0) 584 if (err < 0)
651 break; 585 break;
652 } 586 }
@@ -657,35 +591,35 @@ out_free:
657 return err; 591 return err;
658} 592}
659 593
660int perf_file_header__read(struct perf_file_header *self, 594int perf_file_header__read(struct perf_file_header *header,
661 struct perf_header *ph, int fd) 595 struct perf_header *ph, int fd)
662{ 596{
663 lseek(fd, 0, SEEK_SET); 597 lseek(fd, 0, SEEK_SET);
664 598
665 if (readn(fd, self, sizeof(*self)) <= 0 || 599 if (readn(fd, header, sizeof(*header)) <= 0 ||
666 memcmp(&self->magic, __perf_magic, sizeof(self->magic))) 600 memcmp(&header->magic, __perf_magic, sizeof(header->magic)))
667 return -1; 601 return -1;
668 602
669 if (self->attr_size != sizeof(struct perf_file_attr)) { 603 if (header->attr_size != sizeof(struct perf_file_attr)) {
670 u64 attr_size = bswap_64(self->attr_size); 604 u64 attr_size = bswap_64(header->attr_size);
671 605
672 if (attr_size != sizeof(struct perf_file_attr)) 606 if (attr_size != sizeof(struct perf_file_attr))
673 return -1; 607 return -1;
674 608
675 mem_bswap_64(self, offsetof(struct perf_file_header, 609 mem_bswap_64(header, offsetof(struct perf_file_header,
676 adds_features)); 610 adds_features));
677 ph->needs_swap = true; 611 ph->needs_swap = true;
678 } 612 }
679 613
680 if (self->size != sizeof(*self)) { 614 if (header->size != sizeof(*header)) {
681 /* Support the previous format */ 615 /* Support the previous format */
682 if (self->size == offsetof(typeof(*self), adds_features)) 616 if (header->size == offsetof(typeof(*header), adds_features))
683 bitmap_zero(self->adds_features, HEADER_FEAT_BITS); 617 bitmap_zero(header->adds_features, HEADER_FEAT_BITS);
684 else 618 else
685 return -1; 619 return -1;
686 } 620 }
687 621
688 memcpy(&ph->adds_features, &self->adds_features, 622 memcpy(&ph->adds_features, &header->adds_features,
689 sizeof(ph->adds_features)); 623 sizeof(ph->adds_features));
690 /* 624 /*
691 * 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
@@ -699,10 +633,10 @@ int perf_file_header__read(struct perf_file_header *self,
699 perf_header__set_feat(ph, HEADER_BUILD_ID); 633 perf_header__set_feat(ph, HEADER_BUILD_ID);
700 } 634 }
701 635
702 ph->event_offset = self->event_types.offset; 636 ph->event_offset = header->event_types.offset;
703 ph->event_size = self->event_types.size; 637 ph->event_size = header->event_types.size;
704 ph->data_offset = self->data.offset; 638 ph->data_offset = header->data.offset;
705 ph->data_size = self->data.size; 639 ph->data_size = header->data.size;
706 return 0; 640 return 0;
707} 641}
708 642
@@ -761,14 +695,50 @@ out:
761 return err; 695 return err;
762} 696}
763 697
764static int perf_header__read_build_ids(struct perf_header *self, 698static int perf_header__read_build_ids_abi_quirk(struct perf_header *header,
765 int input, u64 offset, u64 size) 699 int input, u64 offset, u64 size)
766{ 700{
767 struct perf_session *session = container_of(self, 701 struct perf_session *session = container_of(header, struct perf_session, header);
768 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;
769 struct build_id_event bev; 707 struct build_id_event bev;
770 char filename[PATH_MAX]; 708 char filename[PATH_MAX];
771 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;
772 int err = -1; 742 int err = -1;
773 743
774 while (offset < limit) { 744 while (offset < limit) {
@@ -777,12 +747,30 @@ static int perf_header__read_build_ids(struct perf_header *self,
777 if (read(input, &bev, sizeof(bev)) != sizeof(bev)) 747 if (read(input, &bev, sizeof(bev)) != sizeof(bev))
778 goto out; 748 goto out;
779 749
780 if (self->needs_swap) 750 if (header->needs_swap)
781 perf_event_header__bswap(&bev.header); 751 perf_event_header__bswap(&bev.header);
782 752
783 len = bev.header.size - sizeof(bev); 753 len = bev.header.size - sizeof(bev);
784 if (read(input, filename, len) != len) 754 if (read(input, filename, len) != len)
785 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 }
786 774
787 __event_process_build_id(&bev, filename, session); 775 __event_process_build_id(&bev, filename, session);
788 776
@@ -793,13 +781,13 @@ out:
793 return err; 781 return err;
794} 782}
795 783
796static int perf_file_section__process(struct perf_file_section *self, 784static int perf_file_section__process(struct perf_file_section *section,
797 struct perf_header *ph, 785 struct perf_header *ph,
798 int feat, int fd) 786 int feat, int fd)
799{ 787{
800 if (lseek(fd, self->offset, SEEK_SET) == (off_t)-1) { 788 if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) {
801 pr_debug("Failed to lseek to %" PRIu64 " offset for feature " 789 pr_debug("Failed to lseek to %" PRIu64 " offset for feature "
802 "%d, continuing...\n", self->offset, feat); 790 "%d, continuing...\n", section->offset, feat);
803 return 0; 791 return 0;
804 } 792 }
805 793
@@ -809,7 +797,7 @@ static int perf_file_section__process(struct perf_file_section *self,
809 break; 797 break;
810 798
811 case HEADER_BUILD_ID: 799 case HEADER_BUILD_ID:
812 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))
813 pr_debug("Failed to read buildids, continuing...\n"); 801 pr_debug("Failed to read buildids, continuing...\n");
814 break; 802 break;
815 default: 803 default:
@@ -819,21 +807,21 @@ static int perf_file_section__process(struct perf_file_section *self,
819 return 0; 807 return 0;
820} 808}
821 809
822static 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,
823 struct perf_header *ph, int fd, 811 struct perf_header *ph, int fd,
824 bool repipe) 812 bool repipe)
825{ 813{
826 if (readn(fd, self, sizeof(*self)) <= 0 || 814 if (readn(fd, header, sizeof(*header)) <= 0 ||
827 memcmp(&self->magic, __perf_magic, sizeof(self->magic))) 815 memcmp(&header->magic, __perf_magic, sizeof(header->magic)))
828 return -1; 816 return -1;
829 817
830 if (repipe && do_write(STDOUT_FILENO, self, sizeof(*self)) < 0) 818 if (repipe && do_write(STDOUT_FILENO, header, sizeof(*header)) < 0)
831 return -1; 819 return -1;
832 820
833 if (self->size != sizeof(*self)) { 821 if (header->size != sizeof(*header)) {
834 u64 size = bswap_64(self->size); 822 u64 size = bswap_64(header->size);
835 823
836 if (size != sizeof(*self)) 824 if (size != sizeof(*header))
837 return -1; 825 return -1;
838 826
839 ph->needs_swap = true; 827 ph->needs_swap = true;
@@ -844,10 +832,10 @@ static int perf_file_header__read_pipe(struct perf_pipe_file_header *self,
844 832
845static int perf_header__read_pipe(struct perf_session *session, int fd) 833static int perf_header__read_pipe(struct perf_session *session, int fd)
846{ 834{
847 struct perf_header *self = &session->header; 835 struct perf_header *header = &session->header;
848 struct perf_pipe_file_header f_header; 836 struct perf_pipe_file_header f_header;
849 837
850 if (perf_file_header__read_pipe(&f_header, self, fd, 838 if (perf_file_header__read_pipe(&f_header, header, fd,
851 session->repipe) < 0) { 839 session->repipe) < 0) {
852 pr_debug("incompatible file format\n"); 840 pr_debug("incompatible file format\n");
853 return -EINVAL; 841 return -EINVAL;
@@ -858,18 +846,22 @@ static int perf_header__read_pipe(struct perf_session *session, int fd)
858 return 0; 846 return 0;
859} 847}
860 848
861int perf_header__read(struct perf_session *session, int fd) 849int perf_session__read_header(struct perf_session *session, int fd)
862{ 850{
863 struct perf_header *self = &session->header; 851 struct perf_header *header = &session->header;
864 struct perf_file_header f_header; 852 struct perf_file_header f_header;
865 struct perf_file_attr f_attr; 853 struct perf_file_attr f_attr;
866 u64 f_id; 854 u64 f_id;
867 int nr_attrs, nr_ids, i, j; 855 int nr_attrs, nr_ids, i, j;
868 856
857 session->evlist = perf_evlist__new(NULL, NULL);
858 if (session->evlist == NULL)
859 return -ENOMEM;
860
869 if (session->fd_pipe) 861 if (session->fd_pipe)
870 return perf_header__read_pipe(session, fd); 862 return perf_header__read_pipe(session, fd);
871 863
872 if (perf_file_header__read(&f_header, self, fd) < 0) { 864 if (perf_file_header__read(&f_header, header, fd) < 0) {
873 pr_debug("incompatible file format\n"); 865 pr_debug("incompatible file format\n");
874 return -EINVAL; 866 return -EINVAL;
875 } 867 }
@@ -878,33 +870,39 @@ int perf_header__read(struct perf_session *session, int fd)
878 lseek(fd, f_header.attrs.offset, SEEK_SET); 870 lseek(fd, f_header.attrs.offset, SEEK_SET);
879 871
880 for (i = 0; i < nr_attrs; i++) { 872 for (i = 0; i < nr_attrs; i++) {
881 struct perf_header_attr *attr; 873 struct perf_evsel *evsel;
882 off_t tmp; 874 off_t tmp;
883 875
884 if (perf_header__getbuffer64(self, fd, &f_attr, sizeof(f_attr))) 876 if (perf_header__getbuffer64(header, fd, &f_attr, sizeof(f_attr)))
885 goto out_errno; 877 goto out_errno;
886 878
887 tmp = lseek(fd, 0, SEEK_CUR); 879 tmp = lseek(fd, 0, SEEK_CUR);
880 evsel = perf_evsel__new(&f_attr.attr, i);
888 881
889 attr = perf_header_attr__new(&f_attr.attr); 882 if (evsel == NULL)
890 if (attr == NULL) 883 goto out_delete_evlist;
891 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);
892 889
893 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
894 lseek(fd, f_attr.ids.offset, SEEK_SET); 899 lseek(fd, f_attr.ids.offset, SEEK_SET);
895 900
896 for (j = 0; j < nr_ids; j++) { 901 for (j = 0; j < nr_ids; j++) {
897 if (perf_header__getbuffer64(self, fd, &f_id, sizeof(f_id))) 902 if (perf_header__getbuffer64(header, fd, &f_id, sizeof(f_id)))
898 goto out_errno; 903 goto out_errno;
899 904
900 if (perf_header_attr__add_id(attr, f_id) < 0) { 905 perf_evlist__id_add(session->evlist, evsel, 0, j, f_id);
901 perf_header_attr__delete(attr);
902 return -ENOMEM;
903 }
904 }
905 if (perf_header__add_attr(self, attr) < 0) {
906 perf_header_attr__delete(attr);
907 return -ENOMEM;
908 } 906 }
909 907
910 lseek(fd, tmp, SEEK_SET); 908 lseek(fd, tmp, SEEK_SET);
@@ -915,93 +913,63 @@ int perf_header__read(struct perf_session *session, int fd)
915 events = malloc(f_header.event_types.size); 913 events = malloc(f_header.event_types.size);
916 if (events == NULL) 914 if (events == NULL)
917 return -ENOMEM; 915 return -ENOMEM;
918 if (perf_header__getbuffer64(self, fd, events, 916 if (perf_header__getbuffer64(header, fd, events,
919 f_header.event_types.size)) 917 f_header.event_types.size))
920 goto out_errno; 918 goto out_errno;
921 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);
922 } 920 }
923 921
924 perf_header__process_sections(self, fd, perf_file_section__process); 922 perf_header__process_sections(header, fd, perf_file_section__process);
925 923
926 lseek(fd, self->data_offset, SEEK_SET); 924 lseek(fd, header->data_offset, SEEK_SET);
927 925
928 self->frozen = 1; 926 header->frozen = 1;
929 return 0; 927 return 0;
930out_errno: 928out_errno:
931 return -errno; 929 return -errno;
930
931out_delete_evlist:
932 perf_evlist__delete(session->evlist);
933 session->evlist = NULL;
934 return -ENOMEM;
932} 935}
933 936
934u64 perf_header__sample_type(struct perf_header *header) 937u64 perf_evlist__sample_type(struct perf_evlist *evlist)
935{ 938{
939 struct perf_evsel *pos;
936 u64 type = 0; 940 u64 type = 0;
937 int i;
938
939 for (i = 0; i < header->attrs; i++) {
940 struct perf_header_attr *attr = header->attr[i];
941 941
942 list_for_each_entry(pos, &evlist->entries, node) {
942 if (!type) 943 if (!type)
943 type = attr->attr.sample_type; 944 type = pos->attr.sample_type;
944 else if (type != attr->attr.sample_type) 945 else if (type != pos->attr.sample_type)
945 die("non matching sample_type"); 946 die("non matching sample_type");
946 } 947 }
947 948
948 return type; 949 return type;
949} 950}
950 951
951bool perf_header__sample_id_all(const struct perf_header *header) 952bool perf_evlist__sample_id_all(const struct perf_evlist *evlist)
952{ 953{
953 bool value = false, first = true; 954 bool value = false, first = true;
954 int i; 955 struct perf_evsel *pos;
955
956 for (i = 0; i < header->attrs; i++) {
957 struct perf_header_attr *attr = header->attr[i];
958 956
957 list_for_each_entry(pos, &evlist->entries, node) {
959 if (first) { 958 if (first) {
960 value = attr->attr.sample_id_all; 959 value = pos->attr.sample_id_all;
961 first = false; 960 first = false;
962 } else if (value != attr->attr.sample_id_all) 961 } else if (value != pos->attr.sample_id_all)
963 die("non matching sample_id_all"); 962 die("non matching sample_id_all");
964 } 963 }
965 964
966 return value; 965 return value;
967} 966}
968 967
969struct perf_event_attr * 968int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id,
970perf_header__find_attr(u64 id, struct perf_header *header) 969 perf_event__handler_t process,
971{ 970 struct perf_session *session)
972 int i;
973
974 /*
975 * We set id to -1 if the data file doesn't contain sample
976 * ids. This can happen when the data file contains one type
977 * of event and in that case, the header can still store the
978 * event attribute information. Check for this and avoid
979 * walking through the entire list of ids which may be large.
980 */
981 if (id == -1ULL) {
982 if (header->attrs > 0)
983 return &header->attr[0]->attr;
984 return NULL;
985 }
986
987 for (i = 0; i < header->attrs; i++) {
988 struct perf_header_attr *attr = header->attr[i];
989 int j;
990
991 for (j = 0; j < attr->ids; j++) {
992 if (attr->id[j] == id)
993 return &attr->attr;
994 }
995 }
996
997 return NULL;
998}
999
1000int event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id,
1001 event__handler_t process,
1002 struct perf_session *session)
1003{ 971{
1004 event_t *ev; 972 union perf_event *ev;
1005 size_t size; 973 size_t size;
1006 int err; 974 int err;
1007 975
@@ -1028,17 +996,15 @@ int event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id,
1028 return err; 996 return err;
1029} 997}
1030 998
1031int event__synthesize_attrs(struct perf_header *self, event__handler_t process, 999int perf_session__synthesize_attrs(struct perf_session *session,
1032 struct perf_session *session) 1000 perf_event__handler_t process)
1033{ 1001{
1034 struct perf_header_attr *attr; 1002 struct perf_evsel *attr;
1035 int i, err = 0; 1003 int err = 0;
1036
1037 for (i = 0; i < self->attrs; i++) {
1038 attr = self->attr[i];
1039 1004
1040 err = event__synthesize_attr(&attr->attr, attr->ids, attr->id, 1005 list_for_each_entry(attr, &session->evlist->entries, node) {
1041 process, session); 1006 err = perf_event__synthesize_attr(&attr->attr, attr->ids,
1007 attr->id, process, session);
1042 if (err) { 1008 if (err) {
1043 pr_debug("failed to create perf header attribute\n"); 1009 pr_debug("failed to create perf header attribute\n");
1044 return err; 1010 return err;
@@ -1048,29 +1014,39 @@ int event__synthesize_attrs(struct perf_header *self, event__handler_t process,
1048 return err; 1014 return err;
1049} 1015}
1050 1016
1051int event__process_attr(event_t *self, struct perf_session *session) 1017int perf_event__process_attr(union perf_event *event,
1018 struct perf_session *session)
1052{ 1019{
1053 struct perf_header_attr *attr;
1054 unsigned int i, ids, n_ids; 1020 unsigned int i, ids, n_ids;
1021 struct perf_evsel *evsel;
1055 1022
1056 attr = perf_header_attr__new(&self->attr.attr); 1023 if (session->evlist == NULL) {
1057 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)
1058 return -ENOMEM; 1032 return -ENOMEM;
1059 1033
1060 ids = self->header.size; 1034 perf_evlist__add(session->evlist, evsel);
1061 ids -= (void *)&self->attr.id - (void *)self; 1035
1036 ids = event->header.size;
1037 ids -= (void *)&event->attr.id - (void *)event;
1062 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;
1063 1046
1064 for (i = 0; i < n_ids; i++) { 1047 for (i = 0; i < n_ids; i++) {
1065 if (perf_header_attr__add_id(attr, self->attr.id[i]) < 0) { 1048 perf_evlist__id_add(session->evlist, evsel, 0, i,
1066 perf_header_attr__delete(attr); 1049 event->attr.id[i]);
1067 return -ENOMEM;
1068 }
1069 }
1070
1071 if (perf_header__add_attr(&session->header, attr) < 0) {
1072 perf_header_attr__delete(attr);
1073 return -ENOMEM;
1074 } 1050 }
1075 1051
1076 perf_session__update_sample_type(session); 1052 perf_session__update_sample_type(session);
@@ -1078,11 +1054,11 @@ int event__process_attr(event_t *self, struct perf_session *session)
1078 return 0; 1054 return 0;
1079} 1055}
1080 1056
1081int event__synthesize_event_type(u64 event_id, char *name, 1057int perf_event__synthesize_event_type(u64 event_id, char *name,
1082 event__handler_t process, 1058 perf_event__handler_t process,
1083 struct perf_session *session) 1059 struct perf_session *session)
1084{ 1060{
1085 event_t ev; 1061 union perf_event ev;
1086 size_t size = 0; 1062 size_t size = 0;
1087 int err = 0; 1063 int err = 0;
1088 1064
@@ -1103,8 +1079,8 @@ int event__synthesize_event_type(u64 event_id, char *name,
1103 return err; 1079 return err;
1104} 1080}
1105 1081
1106int event__synthesize_event_types(event__handler_t process, 1082int perf_event__synthesize_event_types(perf_event__handler_t process,
1107 struct perf_session *session) 1083 struct perf_session *session)
1108{ 1084{
1109 struct perf_trace_event_type *type; 1085 struct perf_trace_event_type *type;
1110 int i, err = 0; 1086 int i, err = 0;
@@ -1112,8 +1088,9 @@ int event__synthesize_event_types(event__handler_t process,
1112 for (i = 0; i < event_count; i++) { 1088 for (i = 0; i < event_count; i++) {
1113 type = &events[i]; 1089 type = &events[i];
1114 1090
1115 err = event__synthesize_event_type(type->event_id, type->name, 1091 err = perf_event__synthesize_event_type(type->event_id,
1116 process, session); 1092 type->name, process,
1093 session);
1117 if (err) { 1094 if (err) {
1118 pr_debug("failed to create perf header event type\n"); 1095 pr_debug("failed to create perf header event type\n");
1119 return err; 1096 return err;
@@ -1123,28 +1100,28 @@ int event__synthesize_event_types(event__handler_t process,
1123 return err; 1100 return err;
1124} 1101}
1125 1102
1126int event__process_event_type(event_t *self, 1103int perf_event__process_event_type(union perf_event *event,
1127 struct perf_session *session __unused) 1104 struct perf_session *session __unused)
1128{ 1105{
1129 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,
1130 self->event_type.event_type.name) < 0) 1107 event->event_type.event_type.name) < 0)
1131 return -ENOMEM; 1108 return -ENOMEM;
1132 1109
1133 return 0; 1110 return 0;
1134} 1111}
1135 1112
1136int event__synthesize_tracing_data(int fd, struct list_head *pattrs, 1113int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist,
1137 event__handler_t process, 1114 perf_event__handler_t process,
1138 struct perf_session *session __unused) 1115 struct perf_session *session __unused)
1139{ 1116{
1140 event_t ev; 1117 union perf_event ev;
1141 ssize_t size = 0, aligned_size = 0, padding; 1118 ssize_t size = 0, aligned_size = 0, padding;
1142 int err = 0; 1119 int err __used = 0;
1143 1120
1144 memset(&ev, 0, sizeof(ev)); 1121 memset(&ev, 0, sizeof(ev));
1145 1122
1146 ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA; 1123 ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA;
1147 size = read_tracing_data_size(fd, pattrs); 1124 size = read_tracing_data_size(fd, &evlist->entries);
1148 if (size <= 0) 1125 if (size <= 0)
1149 return size; 1126 return size;
1150 aligned_size = ALIGN(size, sizeof(u64)); 1127 aligned_size = ALIGN(size, sizeof(u64));
@@ -1154,16 +1131,16 @@ int event__synthesize_tracing_data(int fd, struct list_head *pattrs,
1154 1131
1155 process(&ev, NULL, session); 1132 process(&ev, NULL, session);
1156 1133
1157 err = read_tracing_data(fd, pattrs); 1134 err = read_tracing_data(fd, &evlist->entries);
1158 write_padded(fd, NULL, 0, padding); 1135 write_padded(fd, NULL, 0, padding);
1159 1136
1160 return aligned_size; 1137 return aligned_size;
1161} 1138}
1162 1139
1163int event__process_tracing_data(event_t *self, 1140int perf_event__process_tracing_data(union perf_event *event,
1164 struct perf_session *session) 1141 struct perf_session *session)
1165{ 1142{
1166 ssize_t size_read, padding, size = self->tracing_data.size; 1143 ssize_t size_read, padding, size = event->tracing_data.size;
1167 off_t offset = lseek(session->fd, 0, SEEK_CUR); 1144 off_t offset = lseek(session->fd, 0, SEEK_CUR);
1168 char buf[BUFSIZ]; 1145 char buf[BUFSIZ];
1169 1146
@@ -1189,12 +1166,12 @@ int event__process_tracing_data(event_t *self,
1189 return size_read + padding; 1166 return size_read + padding;
1190} 1167}
1191 1168
1192int event__synthesize_build_id(struct dso *pos, u16 misc, 1169int perf_event__synthesize_build_id(struct dso *pos, u16 misc,
1193 event__handler_t process, 1170 perf_event__handler_t process,
1194 struct machine *machine, 1171 struct machine *machine,
1195 struct perf_session *session) 1172 struct perf_session *session)
1196{ 1173{
1197 event_t ev; 1174 union perf_event ev;
1198 size_t len; 1175 size_t len;
1199 int err = 0; 1176 int err = 0;
1200 1177
@@ -1217,11 +1194,11 @@ int event__synthesize_build_id(struct dso *pos, u16 misc,
1217 return err; 1194 return err;
1218} 1195}
1219 1196
1220int event__process_build_id(event_t *self, 1197int perf_event__process_build_id(union perf_event *event,
1221 struct perf_session *session) 1198 struct perf_session *session)
1222{ 1199{
1223 __event_process_build_id(&self->build_id, 1200 __event_process_build_id(&event->build_id,
1224 self->build_id.filename, 1201 event->build_id.filename,
1225 session); 1202 session);
1226 return 0; 1203 return 0;
1227} 1204}
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 33f16be7b72f..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,34 +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);
84bool perf_header__sample_id_all(const struct perf_header *header);
85struct perf_event_attr *
86perf_header__find_attr(u64 id, struct perf_header *header);
87void perf_header__set_feat(struct perf_header *self, int feat);
88void perf_header__clear_feat(struct perf_header *self, int feat);
89bool perf_header__has_feat(const struct perf_header *self, int feat);
90
91int perf_header__process_sections(struct perf_header *self, int fd,
92 int (*process)(struct perf_file_section *self,
93 struct perf_header *ph, 75 struct perf_header *ph,
94 int feat, int fd)); 76 int feat, int fd));
95 77
@@ -97,32 +79,31 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
97 const char *name, bool is_kallsyms); 79 const char *name, bool is_kallsyms);
98int 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);
99 81
100int 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,
101 event__handler_t process, 83 perf_event__handler_t process,
102 struct perf_session *session);
103int event__synthesize_attrs(struct perf_header *self,
104 event__handler_t process,
105 struct perf_session *session);
106int event__process_attr(event_t *self, struct perf_session *session);
107
108int event__synthesize_event_type(u64 event_id, char *name,
109 event__handler_t process,
110 struct perf_session *session);
111int event__synthesize_event_types(event__handler_t process,
112 struct perf_session *session);
113int event__process_event_type(event_t *self,
114 struct perf_session *session);
115
116int event__synthesize_tracing_data(int fd, struct list_head *pattrs,
117 event__handler_t process,
118 struct perf_session *session);
119int event__process_tracing_data(event_t *self,
120 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);
121 96
122int event__synthesize_build_id(struct dso *pos, u16 misc, 97int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist,
123 event__handler_t process, 98 perf_event__handler_t process,
124 struct machine *machine, 99 struct perf_session *session);
125 struct perf_session *session); 100int perf_event__process_tracing_data(union perf_event *event,
126int event__process_build_id(event_t *self, struct perf_session *session); 101 struct perf_session *session);
127 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);
128#endif /* __PERF_HEADER_H */ 109#endif /* __PERF_HEADER_H */
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 32f4f1f2f6e4..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
@@ -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;
@@ -640,9 +658,9 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
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%" PRIu64, *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, "%11" PRIu64, 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,225 +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=%#" PRIx64 "\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("%#" PRIx64 " %s: period++ [ip: %#" PRIx64 ", %#" PRIx64
984 "] => %" PRIu64 "\n", self->ms.sym->start, self->ms.sym->name,
985 ip, ip - self->ms.sym->start, h->ip[offset]);
986 return 0;
987}
988
989static struct objdump_line *objdump_line__new(s64 offset, char *line, size_t privsize)
990{
991 struct objdump_line *self = malloc(sizeof(*self) + privsize);
992
993 if (self != NULL) {
994 self->offset = offset;
995 self->line = line;
996 }
997
998 return self;
999}
1000
1001void objdump_line__free(struct objdump_line *self)
1002{
1003 free(self->line);
1004 free(self);
1005}
1006
1007static void objdump__add_line(struct list_head *head, struct objdump_line *line)
1008{
1009 list_add_tail(&line->node, head);
1010}
1011
1012struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
1013 struct objdump_line *pos)
1014{
1015 list_for_each_entry_continue(pos, head, node)
1016 if (pos->offset >= 0)
1017 return pos;
1018
1019 return NULL;
1020}
1021
1022static int hist_entry__parse_objdump_line(struct hist_entry *self, FILE *file,
1023 struct list_head *head, size_t privsize)
1024{ 966{
1025 struct symbol *sym = self->ms.sym; 967 return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip);
1026 struct objdump_line *objdump_line;
1027 char *line = NULL, *tmp, *tmp2, *c;
1028 size_t line_len;
1029 s64 line_ip, offset = -1;
1030
1031 if (getline(&line, &line_len, file) < 0)
1032 return -1;
1033
1034 if (!line)
1035 return -1;
1036
1037 while (line_len != 0 && isspace(line[line_len - 1]))
1038 line[--line_len] = '\0';
1039
1040 c = strchr(line, '\n');
1041 if (c)
1042 *c = 0;
1043
1044 line_ip = -1;
1045
1046 /*
1047 * Strip leading spaces:
1048 */
1049 tmp = line;
1050 while (*tmp) {
1051 if (*tmp != ' ')
1052 break;
1053 tmp++;
1054 }
1055
1056 if (*tmp) {
1057 /*
1058 * Parse hexa addresses followed by ':'
1059 */
1060 line_ip = strtoull(tmp, &tmp2, 16);
1061 if (*tmp2 != ':' || tmp == tmp2 || tmp2[1] == '\0')
1062 line_ip = -1;
1063 }
1064
1065 if (line_ip != -1) {
1066 u64 start = map__rip_2objdump(self->ms.map, sym->start),
1067 end = map__rip_2objdump(self->ms.map, sym->end);
1068
1069 offset = line_ip - start;
1070 if (offset < 0 || (u64)line_ip > end)
1071 offset = -1;
1072 }
1073
1074 objdump_line = objdump_line__new(offset, line, privsize);
1075 if (objdump_line == NULL) {
1076 free(line);
1077 return -1;
1078 }
1079 objdump__add_line(head, objdump_line);
1080
1081 return 0;
1082} 968}
1083 969
1084int hist_entry__annotate(struct hist_entry *self, struct list_head *head, 970int hist_entry__annotate(struct hist_entry *he, size_t privsize)
1085 size_t privsize)
1086{ 971{
1087 struct symbol *sym = self->ms.sym; 972 return symbol__annotate(he->ms.sym, he->ms.map, privsize);
1088 struct map *map = self->ms.map;
1089 struct dso *dso = map->dso;
1090 char *filename = dso__build_id_filename(dso, NULL, 0);
1091 bool free_filename = true;
1092 char command[PATH_MAX * 2];
1093 FILE *file;
1094 int err = 0;
1095 u64 len;
1096 char symfs_filename[PATH_MAX];
1097
1098 if (filename) {
1099 snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
1100 symbol_conf.symfs, filename);
1101 }
1102
1103 if (filename == NULL) {
1104 if (dso->has_build_id) {
1105 pr_err("Can't annotate %s: not enough memory\n",
1106 sym->name);
1107 return -ENOMEM;
1108 }
1109 goto fallback;
1110 } else if (readlink(symfs_filename, command, sizeof(command)) < 0 ||
1111 strstr(command, "[kernel.kallsyms]") ||
1112 access(symfs_filename, R_OK)) {
1113 free(filename);
1114fallback:
1115 /*
1116 * If we don't have build-ids or the build-id file isn't in the
1117 * cache, or is just a kallsyms file, well, lets hope that this
1118 * DSO is the same as when 'perf record' ran.
1119 */
1120 filename = dso->long_name;
1121 snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
1122 symbol_conf.symfs, filename);
1123 free_filename = false;
1124 }
1125
1126 if (dso->origin == DSO__ORIG_KERNEL) {
1127 if (dso->annotate_warned)
1128 goto out_free_filename;
1129 err = -ENOENT;
1130 dso->annotate_warned = 1;
1131 pr_err("Can't annotate %s: No vmlinux file was found in the "
1132 "path\n", sym->name);
1133 goto out_free_filename;
1134 }
1135
1136 pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__,
1137 filename, sym->name, map->unmap_ip(map, sym->start),
1138 map->unmap_ip(map, sym->end));
1139
1140 len = sym->end - sym->start;
1141
1142 pr_debug("annotating [%p] %30s : [%p] %30s\n",
1143 dso, dso->long_name, sym, sym->name);
1144
1145 snprintf(command, sizeof(command),
1146 "objdump --start-address=0x%016" PRIx64 " --stop-address=0x%016" PRIx64 " -dS -C %s|grep -v %s|expand",
1147 map__rip_2objdump(map, sym->start),
1148 map__rip_2objdump(map, sym->end),
1149 symfs_filename, filename);
1150
1151 pr_debug("Executing: %s\n", command);
1152
1153 file = popen(command, "r");
1154 if (!file)
1155 goto out_free_filename;
1156
1157 while (!feof(file))
1158 if (hist_entry__parse_objdump_line(self, file, head, privsize) < 0)
1159 break;
1160
1161 pclose(file);
1162out_free_filename:
1163 if (free_filename)
1164 free(filename);
1165 return err;
1166} 973}
1167 974
1168void hists__inc_nr_events(struct hists *self, u32 type) 975void hists__inc_nr_events(struct hists *self, u32 type)
@@ -1177,8 +984,12 @@ size_t hists__fprintf_nr_events(struct hists *self, FILE *fp)
1177 size_t ret = 0; 984 size_t ret = 0;
1178 985
1179 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) { 986 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
1180 const char *name = event__get_event_name(i); 987 const char *name;
988
989 if (self->stats.nr_events[i] == 0)
990 continue;
1181 991
992 name = perf_event__name(i);
1182 if (!strcmp(name, "UNKNOWN")) 993 if (!strcmp(name, "UNKNOWN"))
1183 continue; 994 continue;
1184 995
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index ee789856a8c9..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
@@ -56,6 +29,7 @@ struct events_stats {
56 u32 nr_events[PERF_RECORD_HEADER_MAX]; 29 u32 nr_events[PERF_RECORD_HEADER_MAX];
57 u32 nr_unknown_events; 30 u32 nr_unknown_events;
58 u32 nr_invalid_chains; 31 u32 nr_invalid_chains;
32 u32 nr_unknown_id;
59}; 33};
60 34
61enum hist_column { 35enum hist_column {
@@ -69,14 +43,13 @@ enum hist_column {
69}; 43};
70 44
71struct hists { 45struct hists {
72 struct rb_node rb_node;
73 struct rb_root entries; 46 struct rb_root entries;
74 u64 nr_entries; 47 u64 nr_entries;
75 struct events_stats stats; 48 struct events_stats stats;
76 u64 config;
77 u64 event_stream; 49 u64 event_stream;
78 u32 type;
79 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;
80}; 53};
81 54
82struct hist_entry *__hists__add_entry(struct hists *self, 55struct hist_entry *__hists__add_entry(struct hists *self,
@@ -102,9 +75,8 @@ size_t hists__fprintf_nr_events(struct hists *self, FILE *fp);
102size_t hists__fprintf(struct hists *self, struct hists *pair, 75size_t hists__fprintf(struct hists *self, struct hists *pair,
103 bool show_displacement, FILE *fp); 76 bool show_displacement, FILE *fp);
104 77
105int 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);
106int hist_entry__annotate(struct hist_entry *self, struct list_head *head, 79int hist_entry__annotate(struct hist_entry *self, size_t privsize);
107 size_t privsize);
108 80
109void hists__filter_by_dso(struct hists *self, const struct dso *dso); 81void hists__filter_by_dso(struct hists *self, const struct dso *dso);
110void hists__filter_by_thread(struct hists *self, const struct thread *thread); 82void hists__filter_by_thread(struct hists *self, const struct thread *thread);
@@ -113,21 +85,18 @@ u16 hists__col_len(struct hists *self, enum hist_column col);
113void 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);
114bool 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);
115 87
116#ifdef NO_NEWT_SUPPORT 88struct perf_evlist;
117static inline int hists__browse(struct hists *self __used,
118 const char *helpline __used,
119 const char *ev_name __used)
120{
121 return 0;
122}
123 89
124static inline int hists__tui_browse_tree(struct rb_root *self __used, 90#ifdef NO_NEWT_SUPPORT
125 const char *help __used) 91static inline
92int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __used,
93 const char *help __used)
126{ 94{
127 return 0; 95 return 0;
128} 96}
129 97
130static 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)
131{ 100{
132 return 0; 101 return 0;
133} 102}
@@ -135,14 +104,12 @@ static inline int hist_entry__tui_annotate(struct hist_entry *self __used)
135#define KEY_RIGHT -2 104#define KEY_RIGHT -2
136#else 105#else
137#include <newt.h> 106#include <newt.h>
138int hists__browse(struct hists *self, const char *helpline, 107int hist_entry__tui_annotate(struct hist_entry *self, int evidx);
139 const char *ev_name);
140int hist_entry__tui_annotate(struct hist_entry *self);
141 108
142#define KEY_LEFT NEWT_KEY_LEFT 109#define KEY_LEFT NEWT_KEY_LEFT
143#define KEY_RIGHT NEWT_KEY_RIGHT 110#define KEY_RIGHT NEWT_KEY_RIGHT
144 111
145int hists__tui_browse_tree(struct rb_root *self, const char *help); 112int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help);
146#endif 113#endif
147 114
148unsigned int hists__sort_list_width(struct hists *self); 115unsigned int hists__sort_list_width(struct hists *self);
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/parse-events.c b/tools/perf/util/parse-events.c
index 135f69baf966..952b4ae3d954 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1,6 +1,7 @@
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"
4#include "evsel.h" 5#include "evsel.h"
5#include "parse-options.h" 6#include "parse-options.h"
6#include "parse-events.h" 7#include "parse-events.h"
@@ -11,10 +12,6 @@
11#include "header.h" 12#include "header.h"
12#include "debugfs.h" 13#include "debugfs.h"
13 14
14int nr_counters;
15
16LIST_HEAD(evsel_list);
17
18struct event_symbol { 15struct event_symbol {
19 u8 type; 16 u8 type;
20 u64 config; 17 u64 config;
@@ -266,11 +263,36 @@ static char *event_cache_name(u8 cache_type, u8 cache_op, u8 cache_result)
266 return name; 263 return name;
267} 264}
268 265
266const char *event_type(int type)
267{
268 switch (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
269const char *event_name(struct perf_evsel *evsel) 288const char *event_name(struct perf_evsel *evsel)
270{ 289{
271 u64 config = evsel->attr.config; 290 u64 config = evsel->attr.config;
272 int type = evsel->attr.type; 291 int type = evsel->attr.type;
273 292
293 if (evsel->name)
294 return evsel->name;
295
274 return __event_name(type, config); 296 return __event_name(type, config);
275} 297}
276 298
@@ -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,15 +505,16 @@ 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
493static enum event_result parse_tracepoint_event(const char **strp, 515static enum event_result
494 struct perf_event_attr *attr) 516parse_tracepoint_event(const struct option *opt, const char **strp,
517 struct perf_event_attr *attr)
495{ 518{
496 const char *evt_name; 519 const char *evt_name;
497 char *flags = NULL, *comma_loc; 520 char *flags = NULL, *comma_loc;
@@ -530,7 +553,7 @@ static enum event_result parse_tracepoint_event(const char **strp,
530 return EVT_FAILED; 553 return EVT_FAILED;
531 if (strpbrk(evt_name, "*?")) { 554 if (strpbrk(evt_name, "*?")) {
532 *strp += strlen(sys_name) + evt_length + 1; /* 1 == the ':' */ 555 *strp += strlen(sys_name) + evt_length + 1; /* 1 == the ':' */
533 return parse_multiple_tracepoint_event(sys_name, evt_name, 556 return parse_multiple_tracepoint_event(opt, sys_name, evt_name,
534 flags); 557 flags);
535 } else { 558 } else {
536 return parse_single_tracepoint_event(sys_name, evt_name, 559 return parse_single_tracepoint_event(sys_name, evt_name,
@@ -740,11 +763,12 @@ parse_event_modifier(const char **strp, struct perf_event_attr *attr)
740 * Symbolic names are (almost) exactly matched. 763 * Symbolic names are (almost) exactly matched.
741 */ 764 */
742static enum event_result 765static enum event_result
743parse_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)
744{ 768{
745 enum event_result ret; 769 enum event_result ret;
746 770
747 ret = parse_tracepoint_event(str, attr); 771 ret = parse_tracepoint_event(opt, str, attr);
748 if (ret != EVT_FAILED) 772 if (ret != EVT_FAILED)
749 goto modifier; 773 goto modifier;
750 774
@@ -778,14 +802,17 @@ modifier:
778 return ret; 802 return ret;
779} 803}
780 804
781int parse_events(const struct option *opt __used, const char *str, int unset __used) 805int parse_events(const struct option *opt, const char *str, int unset __used)
782{ 806{
807 struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
783 struct perf_event_attr attr; 808 struct perf_event_attr attr;
784 enum event_result ret; 809 enum event_result ret;
810 const char *ostr;
785 811
786 for (;;) { 812 for (;;) {
813 ostr = str;
787 memset(&attr, 0, sizeof(attr)); 814 memset(&attr, 0, sizeof(attr));
788 ret = parse_event_symbols(&str, &attr); 815 ret = parse_event_symbols(opt, &str, &attr);
789 if (ret == EVT_FAILED) 816 if (ret == EVT_FAILED)
790 return -1; 817 return -1;
791 818
@@ -794,12 +821,15 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u
794 821
795 if (ret != EVT_HANDLED_ALL) { 822 if (ret != EVT_HANDLED_ALL) {
796 struct perf_evsel *evsel; 823 struct perf_evsel *evsel;
797 evsel = perf_evsel__new(&attr, 824 evsel = perf_evsel__new(&attr, evlist->nr_entries);
798 nr_counters);
799 if (evsel == NULL) 825 if (evsel == NULL)
800 return -1; 826 return -1;
801 list_add_tail(&evsel->node, &evsel_list); 827 perf_evlist__add(evlist, evsel);
802 ++nr_counters; 828
829 evsel->name = calloc(str - ostr + 1, 1);
830 if (!evsel->name)
831 return -1;
832 strncpy(evsel->name, ostr, str - ostr);
803 } 833 }
804 834
805 if (*str == 0) 835 if (*str == 0)
@@ -813,13 +843,14 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u
813 return 0; 843 return 0;
814} 844}
815 845
816int parse_filter(const struct option *opt __used, const char *str, 846int parse_filter(const struct option *opt, const char *str,
817 int unset __used) 847 int unset __used)
818{ 848{
849 struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
819 struct perf_evsel *last = NULL; 850 struct perf_evsel *last = NULL;
820 851
821 if (!list_empty(&evsel_list)) 852 if (evlist->nr_entries > 0)
822 last = list_entry(evsel_list.prev, struct perf_evsel, node); 853 last = list_entry(evlist->entries.prev, struct perf_evsel, node);
823 854
824 if (last == NULL || last->attr.type != PERF_TYPE_TRACEPOINT) { 855 if (last == NULL || last->attr.type != PERF_TYPE_TRACEPOINT) {
825 fprintf(stderr, 856 fprintf(stderr,
@@ -849,7 +880,7 @@ static const char * const event_type_descriptors[] = {
849 * Print the events from <debugfs_mount_point>/tracing/events 880 * Print the events from <debugfs_mount_point>/tracing/events
850 */ 881 */
851 882
852static void print_tracepoint_events(void) 883void print_tracepoint_events(const char *subsys_glob, const char *event_glob)
853{ 884{
854 DIR *sys_dir, *evt_dir; 885 DIR *sys_dir, *evt_dir;
855 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; 886 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
@@ -864,6 +895,9 @@ static void print_tracepoint_events(void)
864 return; 895 return;
865 896
866 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;
867 901
868 snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path, 902 snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path,
869 sys_dirent.d_name); 903 sys_dirent.d_name);
@@ -872,6 +906,10 @@ static void print_tracepoint_events(void)
872 continue; 906 continue;
873 907
874 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
875 snprintf(evt_path, MAXPATHLEN, "%s:%s", 913 snprintf(evt_path, MAXPATHLEN, "%s:%s",
876 sys_dirent.d_name, evt_dirent.d_name); 914 sys_dirent.d_name, evt_dirent.d_name);
877 printf(" %-42s [%s]\n", evt_path, 915 printf(" %-42s [%s]\n", evt_path,
@@ -923,13 +961,61 @@ int is_valid_tracepoint(const char *event_string)
923 return 0; 961 return 0;
924} 962}
925 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
926/* 1012/*
927 * Print the help text for the event symbols: 1013 * Print the help text for the event symbols:
928 */ 1014 */
929void print_events(void) 1015void print_events(const char *event_glob)
930{ 1016{
931 struct event_symbol *syms = event_symbols; 1017 struct event_symbol *syms = event_symbols;
932 unsigned int i, type, op, prev_type = -1; 1018 unsigned int i, type, prev_type = -1, printed = 0, ntypes_printed = 0;
933 char name[40]; 1019 char name[40];
934 1020
935 printf("\n"); 1021 printf("\n");
@@ -938,8 +1024,16 @@ void print_events(void)
938 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { 1024 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
939 type = syms->type; 1025 type = syms->type;
940 1026
941 if (type != prev_type) 1027 if (type != prev_type && printed) {
942 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;
943 1037
944 if (strlen(syms->alias)) 1038 if (strlen(syms->alias))
945 sprintf(name, "%s OR %s", syms->symbol, syms->alias); 1039 sprintf(name, "%s OR %s", syms->symbol, syms->alias);
@@ -949,22 +1043,17 @@ void print_events(void)
949 event_type_descriptors[type]); 1043 event_type_descriptors[type]);
950 1044
951 prev_type = type; 1045 prev_type = type;
1046 ++printed;
952 } 1047 }
953 1048
954 printf("\n"); 1049 if (ntypes_printed) {
955 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { 1050 printed = 0;
956 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { 1051 printf("\n");
957 /* skip invalid cache type */
958 if (!is_cache_op_valid(type, op))
959 continue;
960
961 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
962 printf(" %-42s [%s]\n",
963 event_cache_name(type, op, i),
964 event_type_descriptors[PERF_TYPE_HW_CACHE]);
965 }
966 }
967 } 1052 }
1053 print_hwcache_events(event_glob);
1054
1055 if (event_glob != NULL)
1056 return;
968 1057
969 printf("\n"); 1058 printf("\n");
970 printf(" %-42s [%s]\n", 1059 printf(" %-42s [%s]\n",
@@ -977,37 +1066,7 @@ void print_events(void)
977 event_type_descriptors[PERF_TYPE_BREAKPOINT]); 1066 event_type_descriptors[PERF_TYPE_BREAKPOINT]);
978 printf("\n"); 1067 printf("\n");
979 1068
980 print_tracepoint_events(); 1069 print_tracepoint_events(NULL, NULL);
981 1070
982 exit(129); 1071 exit(129);
983} 1072}
984
985int perf_evsel_list__create_default(void)
986{
987 struct perf_evsel *evsel;
988 struct perf_event_attr attr;
989
990 memset(&attr, 0, sizeof(attr));
991 attr.type = PERF_TYPE_HARDWARE;
992 attr.config = PERF_COUNT_HW_CPU_CYCLES;
993
994 evsel = perf_evsel__new(&attr, 0);
995
996 if (evsel == NULL)
997 return -ENOMEM;
998
999 list_add(&evsel->node, &evsel_list);
1000 ++nr_counters;
1001 return 0;
1002}
1003
1004void perf_evsel_list__delete(void)
1005{
1006 struct perf_evsel *pos, *n;
1007
1008 list_for_each_entry_safe(pos, n, &evsel_list, node) {
1009 list_del_init(&pos->node);
1010 perf_evsel__delete(pos);
1011 }
1012 nr_counters = 0;
1013}
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 458e3ecf17af..746d3fcbfc2a 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -9,11 +9,6 @@
9struct list_head; 9struct list_head;
10struct perf_evsel; 10struct perf_evsel;
11 11
12extern struct list_head evsel_list;
13
14int perf_evsel_list__create_default(void);
15void perf_evsel_list__delete(void);
16
17struct option; 12struct option;
18 13
19struct tracepoint_path { 14struct tracepoint_path {
@@ -25,8 +20,7 @@ struct tracepoint_path {
25extern struct tracepoint_path *tracepoint_id_to_path(u64 config); 20extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
26extern bool have_tracepoints(struct list_head *evlist); 21extern bool have_tracepoints(struct list_head *evlist);
27 22
28extern int nr_counters; 23const char *event_type(int type);
29
30const char *event_name(struct perf_evsel *event); 24const char *event_name(struct perf_evsel *event);
31extern const char *__event_name(int type, u64 config); 25extern const char *__event_name(int type, u64 config);
32 26
@@ -35,7 +29,10 @@ extern int parse_filter(const struct option *opt, const char *str, int unset);
35 29
36#define EVENTS_HELP_MAX (128*1024) 30#define EVENTS_HELP_MAX (128*1024)
37 31
38extern 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);
39extern int is_valid_tracepoint(const char *event_string); 36extern int is_valid_tracepoint(const char *event_string);
40 37
41extern char debugfs_path[]; 38extern char debugfs_path[];
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 6e29d9c9dccc..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"
@@ -111,7 +112,25 @@ 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;
117 struct map *map; 136 struct map *map;
@@ -141,7 +160,13 @@ const char *kernel_get_module_path(const char *module)
141 } 160 }
142 } 161 }
143found: 162found:
144 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;
145} 170}
146 171
147#ifdef DWARF_SUPPORT 172#ifdef DWARF_SUPPORT
@@ -209,7 +234,6 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
209 234
210 /* Searching trace events corresponding to probe event */ 235 /* Searching trace events corresponding to probe event */
211 ntevs = find_probe_trace_events(fd, pev, tevs, max_tevs); 236 ntevs = find_probe_trace_events(fd, pev, tevs, max_tevs);
212 close(fd);
213 237
214 if (ntevs > 0) { /* Succeeded to find trace events */ 238 if (ntevs > 0) { /* Succeeded to find trace events */
215 pr_debug("find %d probe_trace_events.\n", ntevs); 239 pr_debug("find %d probe_trace_events.\n", ntevs);
@@ -363,7 +387,6 @@ int show_line_range(struct line_range *lr, const char *module)
363 } 387 }
364 388
365 ret = find_line_range(fd, lr); 389 ret = find_line_range(fd, lr);
366 close(fd);
367 if (ret == 0) { 390 if (ret == 0) {
368 pr_warning("Specified source line is not found.\n"); 391 pr_warning("Specified source line is not found.\n");
369 return -ENOENT; 392 return -ENOENT;
@@ -384,7 +407,7 @@ int show_line_range(struct line_range *lr, const char *module)
384 setup_pager(); 407 setup_pager();
385 408
386 if (lr->function) 409 if (lr->function)
387 fprintf(stdout, "<%s:%d>\n", lr->function, 410 fprintf(stdout, "<%s@%s:%d>\n", lr->function, lr->path,
388 lr->start - lr->offset); 411 lr->start - lr->offset);
389 else 412 else
390 fprintf(stdout, "<%s:%d>\n", lr->path, lr->start); 413 fprintf(stdout, "<%s:%d>\n", lr->path, lr->start);
@@ -426,12 +449,14 @@ end:
426} 449}
427 450
428static 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,
429 int max_vls, bool externs) 452 int max_vls, struct strfilter *_filter,
453 bool externs)
430{ 454{
431 char *buf; 455 char *buf;
432 int ret, i; 456 int ret, i, nvars;
433 struct str_node *node; 457 struct str_node *node;
434 struct variable_list *vls = NULL, *vl; 458 struct variable_list *vls = NULL, *vl;
459 const char *var;
435 460
436 buf = synthesize_perf_probe_point(&pev->point); 461 buf = synthesize_perf_probe_point(&pev->point);
437 if (!buf) 462 if (!buf)
@@ -439,36 +464,45 @@ static int show_available_vars_at(int fd, struct perf_probe_event *pev,
439 pr_debug("Searching variables at %s\n", buf); 464 pr_debug("Searching variables at %s\n", buf);
440 465
441 ret = find_available_vars_at(fd, pev, &vls, max_vls, externs); 466 ret = find_available_vars_at(fd, pev, &vls, max_vls, externs);
442 if (ret > 0) { 467 if (ret <= 0) {
443 /* Some variables were found */ 468 pr_err("Failed to find variables at %s (%d)\n", buf, ret);
444 fprintf(stdout, "Available variables at %s\n", buf); 469 goto end;
445 for (i = 0; i < ret; i++) { 470 }
446 vl = &vls[i]; 471 /* Some variables are found */
447 /* 472 fprintf(stdout, "Available variables at %s\n", buf);
448 * A probe point might be converted to 473 for (i = 0; i < ret; i++) {
449 * several trace points. 474 vl = &vls[i];
450 */ 475 /*
451 fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol, 476 * A probe point might be converted to
452 vl->point.offset); 477 * several trace points.
453 free(vl->point.symbol); 478 */
454 if (vl->vars) { 479 fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol,
455 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)) {
456 fprintf(stdout, "\t\t%s\n", node->s); 487 fprintf(stdout, "\t\t%s\n", node->s);
457 strlist__delete(vl->vars); 488 nvars++;
458 } else 489 }
459 fprintf(stdout, "(No variables)\n"); 490 }
491 strlist__delete(vl->vars);
460 } 492 }
461 free(vls); 493 if (nvars == 0)
462 } else 494 fprintf(stdout, "\t\t(No matched variables)\n");
463 pr_err("Failed to find variables at %s (%d)\n", buf, ret); 495 }
464 496 free(vls);
497end:
465 free(buf); 498 free(buf);
466 return ret; 499 return ret;
467} 500}
468 501
469/* Show available variables on given probe point */ 502/* Show available variables on given probe point */
470int show_available_vars(struct perf_probe_event *pevs, int npevs, 503int show_available_vars(struct perf_probe_event *pevs, int npevs,
471 int max_vls, const char *module, bool externs) 504 int max_vls, const char *module,
505 struct strfilter *_filter, bool externs)
472{ 506{
473 int i, fd, ret = 0; 507 int i, fd, ret = 0;
474 508
@@ -476,18 +510,18 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
476 if (ret < 0) 510 if (ret < 0)
477 return ret; 511 return ret;
478 512
479 fd = open_vmlinux(module);
480 if (fd < 0) {
481 pr_warning("Failed to open debug information file.\n");
482 return fd;
483 }
484
485 setup_pager(); 513 setup_pager();
486 514
487 for (i = 0; i < npevs && ret >= 0; i++) 515 for (i = 0; i < npevs && ret >= 0; i++) {
488 ret = show_available_vars_at(fd, &pevs[i], max_vls, externs); 516 fd = open_vmlinux(module);
489 517 if (fd < 0) {
490 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 }
491 return ret; 525 return ret;
492} 526}
493 527
@@ -531,7 +565,9 @@ int show_line_range(struct line_range *lr __unused, const char *module __unused)
531 565
532int show_available_vars(struct perf_probe_event *pevs __unused, 566int show_available_vars(struct perf_probe_event *pevs __unused,
533 int npevs __unused, int max_vls __unused, 567 int npevs __unused, int max_vls __unused,
534 const char *module __unused, bool externs __unused) 568 const char *module __unused,
569 struct strfilter *filter __unused,
570 bool externs __unused)
535{ 571{
536 pr_warning("Debuginfo-analysis is not supported.\n"); 572 pr_warning("Debuginfo-analysis is not supported.\n");
537 return -ENOSYS; 573 return -ENOSYS;
@@ -556,11 +592,11 @@ static int parse_line_num(char **ptr, int *val, const char *what)
556 * The line range syntax is described by: 592 * The line range syntax is described by:
557 * 593 *
558 * SRC[:SLN[+NUM|-ELN]] 594 * SRC[:SLN[+NUM|-ELN]]
559 * FNC[:SLN[+NUM|-ELN]] 595 * FNC[@SRC][:SLN[+NUM|-ELN]]
560 */ 596 */
561int parse_line_range_desc(const char *arg, struct line_range *lr) 597int parse_line_range_desc(const char *arg, struct line_range *lr)
562{ 598{
563 char *range, *name = strdup(arg); 599 char *range, *file, *name = strdup(arg);
564 int err; 600 int err;
565 601
566 if (!name) 602 if (!name)
@@ -610,7 +646,16 @@ int parse_line_range_desc(const char *arg, struct line_range *lr)
610 } 646 }
611 } 647 }
612 648
613 if (strchr(name, '.')) 649 file = strchr(name, '@');
650 if (file) {
651 *file = '\0';
652 lr->file = strdup(++file);
653 if (lr->file == NULL) {
654 err = -ENOMEM;
655 goto err;
656 }
657 lr->function = name;
658 } else if (strchr(name, '.'))
614 lr->file = name; 659 lr->file = name;
615 else 660 else
616 lr->function = name; 661 lr->function = name;
@@ -1784,9 +1829,12 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
1784 } 1829 }
1785 1830
1786 /* Loop 2: add all events */ 1831 /* Loop 2: add all events */
1787 for (i = 0; i < npevs && ret >= 0; i++) 1832 for (i = 0; i < npevs; i++) {
1788 ret = __add_probe_trace_events(pkgs[i].pev, pkgs[i].tevs, 1833 ret = __add_probe_trace_events(pkgs[i].pev, pkgs[i].tevs,
1789 pkgs[i].ntevs, force_add); 1834 pkgs[i].ntevs, force_add);
1835 if (ret < 0)
1836 break;
1837 }
1790end: 1838end:
1791 /* Loop 3: cleanup and free trace events */ 1839 /* Loop 3: cleanup and free trace events */
1792 for (i = 0; i < npevs; i++) { 1840 for (i = 0; i < npevs; i++) {
@@ -1912,4 +1960,46 @@ int del_perf_probe_events(struct strlist *dellist)
1912 1960
1913 return ret; 1961 return ret;
1914} 1962}
1963/* TODO: don't use a global variable for filter ... */
1964static struct strfilter *available_func_filter;
1965
1966/*
1967 * If a symbol corresponds to a function with global binding and
1968 * matches filter return 0. For all others return 1.
1969 */
1970static int filter_available_functions(struct map *map __unused,
1971 struct symbol *sym)
1972{
1973 if (sym->binding == STB_GLOBAL &&
1974 strfilter__compare(available_func_filter, sym->name))
1975 return 0;
1976 return 1;
1977}
1915 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 ab83b6ac5d65..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"
@@ -272,6 +273,25 @@ static const char *cu_get_comp_dir(Dwarf_Die *cu_die)
272 return dwarf_formstring(&attr); 273 return dwarf_formstring(&attr);
273} 274}
274 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
275/* Compare diename and tname */ 295/* Compare diename and tname */
276static bool die_compare_name(Dwarf_Die *dw_die, const char *tname) 296static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
277{ 297{
@@ -280,6 +300,19 @@ static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
280 return name ? (strcmp(tname, name) == 0) : false; 300 return name ? (strcmp(tname, name) == 0) : false;
281} 301}
282 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
283/* Get type die */ 316/* Get type die */
284static 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)
285{ 318{
@@ -320,13 +353,23 @@ static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
320 return vr_die; 353 return vr_die;
321} 354}
322 355
323static 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)
324{ 358{
325 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{
326 Dwarf_Word ret; 370 Dwarf_Word ret;
327 371
328 if (dwarf_attr(tp_die, DW_AT_encoding, &attr) == NULL || 372 if (die_get_attr_udata(tp_die, DW_AT_encoding, &ret))
329 dwarf_formudata(&attr, &ret) != 0)
330 return false; 373 return false;
331 374
332 return (ret == DW_ATE_signed_char || ret == DW_ATE_signed || 375 return (ret == DW_ATE_signed_char || ret == DW_ATE_signed ||
@@ -335,11 +378,29 @@ static bool die_is_signed_type(Dwarf_Die *tp_die)
335 378
336static int die_get_byte_size(Dwarf_Die *tp_die) 379static int die_get_byte_size(Dwarf_Die *tp_die)
337{ 380{
338 Dwarf_Attribute attr;
339 Dwarf_Word ret; 381 Dwarf_Word ret;
340 382
341 if (dwarf_attr(tp_die, DW_AT_byte_size, &attr) == NULL || 383 if (die_get_attr_udata(tp_die, DW_AT_byte_size, &ret))
342 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))
343 return 0; 404 return 0;
344 405
345 return (int)ret; 406 return (int)ret;
@@ -455,7 +516,165 @@ static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data)
455static 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,
456 Dwarf_Die *die_mem) 517 Dwarf_Die *die_mem)
457{ 518{
458 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;
459} 678}
460 679
461struct __find_variable_param { 680struct __find_variable_param {
@@ -669,6 +888,8 @@ static_var:
669 return 0; 888 return 0;
670} 889}
671 890
891#define BYTES_TO_BITS(nb) ((nb) * BITS_PER_LONG / sizeof(long))
892
672static int convert_variable_type(Dwarf_Die *vr_die, 893static int convert_variable_type(Dwarf_Die *vr_die,
673 struct probe_trace_arg *tvar, 894 struct probe_trace_arg *tvar,
674 const char *cast) 895 const char *cast)
@@ -685,6 +906,14 @@ static int convert_variable_type(Dwarf_Die *vr_die,
685 return (tvar->type == NULL) ? -ENOMEM : 0; 906 return (tvar->type == NULL) ? -ENOMEM : 0;
686 } 907 }
687 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
688 if (die_get_real_type(vr_die, &type) == NULL) { 917 if (die_get_real_type(vr_die, &type) == NULL) {
689 pr_warning("Failed to get a type information of %s.\n", 918 pr_warning("Failed to get a type information of %s.\n",
690 dwarf_diename(vr_die)); 919 dwarf_diename(vr_die));
@@ -729,29 +958,31 @@ static int convert_variable_type(Dwarf_Die *vr_die,
729 return (tvar->type == NULL) ? -ENOMEM : 0; 958 return (tvar->type == NULL) ? -ENOMEM : 0;
730 } 959 }
731 960
732 ret = die_get_byte_size(&type) * 8; 961 ret = BYTES_TO_BITS(die_get_byte_size(&type));
733 if (ret) { 962 if (!ret)
734 /* Check the bitwidth */ 963 /* No size ... try to use default type */
735 if (ret > MAX_BASIC_TYPE_BITS) { 964 return 0;
736 pr_info("%s exceeds max-bitwidth."
737 " Cut down to %d bits.\n",
738 dwarf_diename(&type), MAX_BASIC_TYPE_BITS);
739 ret = MAX_BASIC_TYPE_BITS;
740 }
741 965
742 ret = snprintf(buf, 16, "%c%d", 966 /* Check the bitwidth */
743 die_is_signed_type(&type) ? 's' : 'u', ret); 967 if (ret > MAX_BASIC_TYPE_BITS) {
744 if (ret < 0 || ret >= 16) { 968 pr_info("%s exceeds max-bitwidth. Cut down to %d bits.\n",
745 if (ret >= 16) 969 dwarf_diename(&type), MAX_BASIC_TYPE_BITS);
746 ret = -E2BIG; 970 ret = MAX_BASIC_TYPE_BITS;
747 pr_warning("Failed to convert variable type: %s\n", 971 }
748 strerror(-ret)); 972 ret = snprintf(buf, 16, "%c%d",
749 return ret; 973 die_is_signed_type(&type) ? 's' : 'u', ret);
750 } 974
751 tvar->type = strdup(buf); 975formatted:
752 if (tvar->type == NULL) 976 if (ret < 0 || ret >= 16) {
753 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;
754 } 982 }
983 tvar->type = strdup(buf);
984 if (tvar->type == NULL)
985 return -ENOMEM;
755 return 0; 986 return 0;
756} 987}
757 988
@@ -1050,157 +1281,102 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf)
1050 return ret; 1281 return ret;
1051} 1282}
1052 1283
1053/* Find probe point from its line number */ 1284static int probe_point_line_walker(const char *fname, int lineno,
1054static int find_probe_point_by_line(struct probe_finder *pf) 1285 Dwarf_Addr addr, void *data)
1055{ 1286{
1056 Dwarf_Lines *lines; 1287 struct probe_finder *pf = data;
1057 Dwarf_Line *line; 1288 int ret;
1058 size_t nlines, i;
1059 Dwarf_Addr addr;
1060 int lineno;
1061 int ret = 0;
1062
1063 if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) {
1064 pr_warning("No source lines found.\n");
1065 return -ENOENT;
1066 }
1067 1289
1068 for (i = 0; i < nlines && ret == 0; i++) { 1290 if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0)
1069 line = dwarf_onesrcline(lines, i); 1291 return 0;
1070 if (dwarf_lineno(line, &lineno) != 0 ||
1071 lineno != pf->lno)
1072 continue;
1073 1292
1074 /* TODO: Get fileno from line, but how? */ 1293 pf->addr = addr;
1075 if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0) 1294 ret = call_probe_finder(NULL, pf);
1076 continue;
1077 1295
1078 if (dwarf_lineaddr(line, &addr) != 0) { 1296 /* Continue if no error, because the line will be in inline function */
1079 pr_warning("Failed to get the address of the line.\n"); 1297 return ret < 0 ? ret : 0;
1080 return -ENOENT; 1298}
1081 }
1082 pr_debug("Probe line found: line[%d]:%d addr:0x%jx\n",
1083 (int)i, lineno, (uintmax_t)addr);
1084 pf->addr = addr;
1085 1299
1086 ret = call_probe_finder(NULL, pf); 1300/* Find probe point from its line number */
1087 /* Continuing, because target line might be inlined. */ 1301static int find_probe_point_by_line(struct probe_finder *pf)
1088 } 1302{
1089 return ret; 1303 return die_walk_lines(&pf->cu_die, probe_point_line_walker, pf);
1090} 1304}
1091 1305
1092/* Find lines which match lazy pattern */ 1306/* Find lines which match lazy pattern */
1093static int find_lazy_match_lines(struct list_head *head, 1307static int find_lazy_match_lines(struct list_head *head,
1094 const char *fname, const char *pat) 1308 const char *fname, const char *pat)
1095{ 1309{
1096 char *fbuf, *p1, *p2; 1310 FILE *fp;
1097 int fd, line, nlines = -1; 1311 char *line = NULL;
1098 struct stat st; 1312 size_t line_len;
1099 1313 ssize_t len;
1100 fd = open(fname, O_RDONLY); 1314 int count = 0, linenum = 1;
1101 if (fd < 0) { 1315
1102 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));
1103 return -errno; 1319 return -errno;
1104 } 1320 }
1105 1321
1106 if (fstat(fd, &st) < 0) { 1322 while ((len = getline(&line, &line_len, fp)) > 0) {
1107 pr_warning("Failed to get the size of %s: %s\n", 1323
1108 fname, strerror(errno)); 1324 if (line[len - 1] == '\n')
1109 nlines = -errno; 1325 line[len - 1] = '\0';
1110 goto out_close; 1326
1111 } 1327 if (strlazymatch(line, pat)) {
1112 1328 line_list__add_line(head, linenum);
1113 nlines = -ENOMEM; 1329 count++;
1114 fbuf = malloc(st.st_size + 2);
1115 if (fbuf == NULL)
1116 goto out_close;
1117 if (read(fd, fbuf, st.st_size) < 0) {
1118 pr_warning("Failed to read %s: %s\n", fname, strerror(errno));
1119 nlines = -errno;
1120 goto out_free_fbuf;
1121 }
1122 fbuf[st.st_size] = '\n'; /* Dummy line */
1123 fbuf[st.st_size + 1] = '\0';
1124 p1 = fbuf;
1125 line = 1;
1126 nlines = 0;
1127 while ((p2 = strchr(p1, '\n')) != NULL) {
1128 *p2 = '\0';
1129 if (strlazymatch(p1, pat)) {
1130 line_list__add_line(head, line);
1131 nlines++;
1132 } 1330 }
1133 line++; 1331 linenum++;
1134 p1 = p2 + 1;
1135 } 1332 }
1136out_free_fbuf: 1333
1137 free(fbuf); 1334 if (ferror(fp))
1138out_close: 1335 count = -errno;
1139 close(fd); 1336 free(line);
1140 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;
1141} 1364}
1142 1365
1143/* Find probe points from lazy pattern */ 1366/* Find probe points from lazy pattern */
1144static 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)
1145{ 1368{
1146 Dwarf_Lines *lines;
1147 Dwarf_Line *line;
1148 size_t nlines, i;
1149 Dwarf_Addr addr;
1150 Dwarf_Die die_mem;
1151 int lineno;
1152 int ret = 0; 1369 int ret = 0;
1153 1370
1154 if (list_empty(&pf->lcache)) { 1371 if (list_empty(&pf->lcache)) {
1155 /* Matching lazy line pattern */ 1372 /* Matching lazy line pattern */
1156 ret = find_lazy_match_lines(&pf->lcache, pf->fname, 1373 ret = find_lazy_match_lines(&pf->lcache, pf->fname,
1157 pf->pev->point.lazy_line); 1374 pf->pev->point.lazy_line);
1158 if (ret == 0) { 1375 if (ret <= 0)
1159 pr_debug("No matched lines found in %s.\n", pf->fname);
1160 return 0;
1161 } else if (ret < 0)
1162 return ret; 1376 return ret;
1163 } 1377 }
1164 1378
1165 if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) { 1379 return die_walk_lines(sp_die, probe_point_lazy_walker, pf);
1166 pr_warning("No source lines found.\n");
1167 return -ENOENT;
1168 }
1169
1170 for (i = 0; i < nlines && ret >= 0; i++) {
1171 line = dwarf_onesrcline(lines, i);
1172
1173 if (dwarf_lineno(line, &lineno) != 0 ||
1174 !line_list__has_line(&pf->lcache, lineno))
1175 continue;
1176
1177 /* TODO: Get fileno from line, but how? */
1178 if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
1179 continue;
1180
1181 if (dwarf_lineaddr(line, &addr) != 0) {
1182 pr_debug("Failed to get the address of line %d.\n",
1183 lineno);
1184 continue;
1185 }
1186 if (sp_die) {
1187 /* Address filtering 1: does sp_die include addr? */
1188 if (!dwarf_haspc(sp_die, addr))
1189 continue;
1190 /* Address filtering 2: No child include addr? */
1191 if (die_find_inlinefunc(sp_die, addr, &die_mem))
1192 continue;
1193 }
1194
1195 pr_debug("Probe line found: line[%d]:%d addr:0x%llx\n",
1196 (int)i, lineno, (unsigned long long)addr);
1197 pf->addr = addr;
1198
1199 ret = call_probe_finder(sp_die, pf);
1200 /* Continuing, because target line might be inlined. */
1201 }
1202 /* TODO: deallocate lines, but how? */
1203 return ret;
1204} 1380}
1205 1381
1206/* Callback parameter with return value */ 1382/* Callback parameter with return value */
@@ -1251,6 +1427,10 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
1251 !die_compare_name(sp_die, pp->function)) 1427 !die_compare_name(sp_die, pp->function))
1252 return DWARF_CB_OK; 1428 return DWARF_CB_OK;
1253 1429
1430 /* Check declared file */
1431 if (pp->file && strtailcmp(pp->file, dwarf_decl_file(sp_die)))
1432 return DWARF_CB_OK;
1433
1254 pf->fname = dwarf_decl_file(sp_die); 1434 pf->fname = dwarf_decl_file(sp_die);
1255 if (pp->line) { /* Function relative line */ 1435 if (pp->line) { /* Function relative line */
1256 dwarf_decl_line(sp_die, &pf->lno); 1436 dwarf_decl_line(sp_die, &pf->lno);
@@ -1307,6 +1487,7 @@ static int find_probes(int fd, struct probe_finder *pf)
1307 if (!dbg) { 1487 if (!dbg) {
1308 pr_warning("No debug information found in the vmlinux - " 1488 pr_warning("No debug information found in the vmlinux - "
1309 "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. */
1310 return -EBADF; 1491 return -EBADF;
1311 } 1492 }
1312 1493
@@ -1318,8 +1499,7 @@ static int find_probes(int fd, struct probe_finder *pf)
1318 off = 0; 1499 off = 0;
1319 line_list__init(&pf->lcache); 1500 line_list__init(&pf->lcache);
1320 /* Loop on CUs (Compilation Unit) */ 1501 /* Loop on CUs (Compilation Unit) */
1321 while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) && 1502 while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL)) {
1322 ret >= 0) {
1323 /* Get the DIE(Debugging Information Entry) of this CU */ 1503 /* Get the DIE(Debugging Information Entry) of this CU */
1324 diep = dwarf_offdie(dbg, off + cuhl, &pf->cu_die); 1504 diep = dwarf_offdie(dbg, off + cuhl, &pf->cu_die);
1325 if (!diep) 1505 if (!diep)
@@ -1340,6 +1520,8 @@ static int find_probes(int fd, struct probe_finder *pf)
1340 pf->lno = pp->line; 1520 pf->lno = pp->line;
1341 ret = find_probe_point_by_line(pf); 1521 ret = find_probe_point_by_line(pf);
1342 } 1522 }
1523 if (ret < 0)
1524 break;
1343 } 1525 }
1344 off = noff; 1526 off = noff;
1345 } 1527 }
@@ -1541,11 +1723,9 @@ int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt)
1541 Dwarf_Die cudie, spdie, indie; 1723 Dwarf_Die cudie, spdie, indie;
1542 Dwarf *dbg = NULL; 1724 Dwarf *dbg = NULL;
1543 Dwfl *dwfl = NULL; 1725 Dwfl *dwfl = NULL;
1544 Dwarf_Line *line; 1726 Dwarf_Addr _addr, baseaddr, bias = 0;
1545 Dwarf_Addr laddr, eaddr, bias = 0; 1727 const char *fname = NULL, *func = NULL, *tmp;
1546 const char *tmp; 1728 int baseline = 0, lineno = 0, ret = 0;
1547 int lineno, ret = 0;
1548 bool found = false;
1549 1729
1550 /* Open the live linux kernel */ 1730 /* Open the live linux kernel */
1551 dbg = dwfl_init_live_kernel_dwarf(addr, &dwfl, &bias); 1731 dbg = dwfl_init_live_kernel_dwarf(addr, &dwfl, &bias);
@@ -1566,68 +1746,79 @@ int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt)
1566 goto end; 1746 goto end;
1567 } 1747 }
1568 1748
1569 /* Find a corresponding line */ 1749 /* Find a corresponding line (filename and lineno) */
1570 line = dwarf_getsrc_die(&cudie, (Dwarf_Addr)addr); 1750 cu_find_lineinfo(&cudie, addr, &fname, &lineno);
1571 if (line) { 1751 /* Don't care whether it failed or not */
1572 if (dwarf_lineaddr(line, &laddr) == 0 &&
1573 (Dwarf_Addr)addr == laddr &&
1574 dwarf_lineno(line, &lineno) == 0) {
1575 tmp = dwarf_linesrc(line, NULL, NULL);
1576 if (tmp) {
1577 ppt->line = lineno;
1578 ppt->file = strdup(tmp);
1579 if (ppt->file == NULL) {
1580 ret = -ENOMEM;
1581 goto end;
1582 }
1583 found = true;
1584 }
1585 }
1586 }
1587 1752
1588 /* Find a corresponding function */ 1753 /* Find a corresponding function (name, baseline and baseaddr) */
1589 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 */
1590 tmp = dwarf_diename(&spdie); 1756 tmp = dwarf_diename(&spdie);
1591 if (!tmp || dwarf_entrypc(&spdie, &eaddr) != 0) 1757 if (!tmp ||
1592 goto end; 1758 dwarf_entrypc(&spdie, &baseaddr) != 0 ||
1593 1759 dwarf_decl_line(&spdie, &baseline) != 0)
1594 if (ppt->line) { 1760 goto post;
1595 if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr, 1761 func = tmp;
1596 &indie)) { 1762
1597 /* 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 */
1598 tmp = dwarf_diename(&indie); 1783 tmp = dwarf_diename(&indie);
1599 if (!tmp) 1784 if (tmp &&
1600 goto end; 1785 dwarf_decl_line(&spdie, &baseline) == 0)
1601 ret = dwarf_decl_line(&indie, &lineno); 1786 func = tmp;
1602 } else {
1603 if (eaddr == addr) { /* Function entry */
1604 lineno = ppt->line;
1605 ret = 0;
1606 } else
1607 ret = dwarf_decl_line(&spdie, &lineno);
1608 }
1609 if (ret == 0) {
1610 /* Make a relative line number */
1611 ppt->line -= lineno;
1612 goto found;
1613 } 1787 }
1614 } 1788 }
1615 /* We don't have a line number, let's use offset */ 1789 }
1616 ppt->offset = addr - (unsigned long)eaddr; 1790
1617found: 1791post:
1618 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);
1619 if (ppt->function == NULL) { 1801 if (ppt->function == NULL) {
1620 ret = -ENOMEM; 1802 ret = -ENOMEM;
1621 goto end; 1803 goto end;
1622 } 1804 }
1623 found = true;
1624 } 1805 }
1625 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 }
1626end: 1817end:
1627 if (dwfl) 1818 if (dwfl)
1628 dwfl_end(dwfl); 1819 dwfl_end(dwfl);
1629 if (ret >= 0) 1820 if (ret == 0 && (fname || func))
1630 ret = found ? 1 : 0; 1821 ret = 1; /* Found a point */
1631 return ret; 1822 return ret;
1632} 1823}
1633 1824
@@ -1644,91 +1835,28 @@ static int line_range_add_line(const char *src, unsigned int lineno,
1644 return line_list__add_line(&lr->line_list, lineno); 1835 return line_list__add_line(&lr->line_list, lineno);
1645} 1836}
1646 1837
1647/* Search function declaration lines */ 1838static int line_range_walk_cb(const char *fname, int lineno,
1648static int line_range_funcdecl_cb(Dwarf_Die *sp_die, void *data) 1839 Dwarf_Addr addr __used,
1840 void *data)
1649{ 1841{
1650 struct dwarf_callback_param *param = data; 1842 struct line_finder *lf = data;
1651 struct line_finder *lf = param->data;
1652 const char *src;
1653 int lineno;
1654
1655 src = dwarf_decl_file(sp_die);
1656 if (src && strtailcmp(src, lf->fname) != 0)
1657 return DWARF_CB_OK;
1658 1843
1659 if (dwarf_decl_line(sp_die, &lineno) != 0 || 1844 if ((strtailcmp(fname, lf->fname) != 0) ||
1660 (lf->lno_s > lineno || lf->lno_e < lineno)) 1845 (lf->lno_s > lineno || lf->lno_e < lineno))
1661 return DWARF_CB_OK; 1846 return 0;
1662 1847
1663 param->retval = line_range_add_line(src, lineno, lf->lr); 1848 if (line_range_add_line(fname, lineno, lf->lr) < 0)
1664 if (param->retval < 0) 1849 return -EINVAL;
1665 return DWARF_CB_ABORT;
1666 return DWARF_CB_OK;
1667}
1668 1850
1669static int find_line_range_func_decl_lines(struct line_finder *lf) 1851 return 0;
1670{
1671 struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0};
1672 dwarf_getfuncs(&lf->cu_die, line_range_funcdecl_cb, &param, 0);
1673 return param.retval;
1674} 1852}
1675 1853
1676/* Find line range from its line number */ 1854/* Find line range from its line number */
1677static 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)
1678{ 1856{
1679 Dwarf_Lines *lines; 1857 int ret;
1680 Dwarf_Line *line;
1681 size_t nlines, i;
1682 Dwarf_Addr addr;
1683 int lineno, ret = 0;
1684 const char *src;
1685 Dwarf_Die die_mem;
1686
1687 line_list__init(&lf->lr->line_list);
1688 if (dwarf_getsrclines(&lf->cu_die, &lines, &nlines) != 0) {
1689 pr_warning("No source lines found.\n");
1690 return -ENOENT;
1691 }
1692
1693 /* Search probable lines on lines list */
1694 for (i = 0; i < nlines; i++) {
1695 line = dwarf_onesrcline(lines, i);
1696 if (dwarf_lineno(line, &lineno) != 0 ||
1697 (lf->lno_s > lineno || lf->lno_e < lineno))
1698 continue;
1699
1700 if (sp_die) {
1701 /* Address filtering 1: does sp_die include addr? */
1702 if (dwarf_lineaddr(line, &addr) != 0 ||
1703 !dwarf_haspc(sp_die, addr))
1704 continue;
1705
1706 /* Address filtering 2: No child include addr? */
1707 if (die_find_inlinefunc(sp_die, addr, &die_mem))
1708 continue;
1709 }
1710
1711 /* TODO: Get fileno from line, but how? */
1712 src = dwarf_linesrc(line, NULL, NULL);
1713 if (strtailcmp(src, lf->fname) != 0)
1714 continue;
1715
1716 ret = line_range_add_line(src, lineno, lf->lr);
1717 if (ret < 0)
1718 return ret;
1719 }
1720 1858
1721 /* 1859 ret = die_walk_lines(sp_die ?: &lf->cu_die, line_range_walk_cb, lf);
1722 * Dwarf lines doesn't include function declarations. We have to
1723 * check functions list or given function.
1724 */
1725 if (sp_die) {
1726 src = dwarf_decl_file(sp_die);
1727 if (src && dwarf_decl_line(sp_die, &lineno) == 0 &&
1728 (lf->lno_s <= lineno && lf->lno_e >= lineno))
1729 ret = line_range_add_line(src, lineno, lf->lr);
1730 } else
1731 ret = find_line_range_func_decl_lines(lf);
1732 1860
1733 /* Update status */ 1861 /* Update status */
1734 if (ret >= 0) 1862 if (ret >= 0)
@@ -1758,9 +1886,10 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
1758 struct line_finder *lf = param->data; 1886 struct line_finder *lf = param->data;
1759 struct line_range *lr = lf->lr; 1887 struct line_range *lr = lf->lr;
1760 1888
1761 pr_debug("find (%llx) %s\n", 1889 /* Check declared file */
1762 (unsigned long long)dwarf_dieoffset(sp_die), 1890 if (lr->file && strtailcmp(lr->file, dwarf_decl_file(sp_die)))
1763 dwarf_diename(sp_die)); 1891 return DWARF_CB_OK;
1892
1764 if (dwarf_tag(sp_die) == DW_TAG_subprogram && 1893 if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
1765 die_compare_name(sp_die, lr->function)) { 1894 die_compare_name(sp_die, lr->function)) {
1766 lf->fname = dwarf_decl_file(sp_die); 1895 lf->fname = dwarf_decl_file(sp_die);
@@ -1813,6 +1942,7 @@ int find_line_range(int fd, struct line_range *lr)
1813 if (!dbg) { 1942 if (!dbg) {
1814 pr_warning("No debug information found in the vmlinux - " 1943 pr_warning("No debug information found in the vmlinux - "
1815 "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. */
1816 return -EBADF; 1946 return -EBADF;
1817 } 1947 }
1818 1948
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
new file mode 100644
index 000000000000..a9f2d7e1204d
--- /dev/null
+++ b/tools/perf/util/python.c
@@ -0,0 +1,896 @@
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, overwrite = 0;
502 static char *kwlist[] = {"cpus", "threads", "group", "overwrite", NULL, NULL};
503
504 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOii", kwlist,
505 &pcpus, &pthreads, &group, &overwrite))
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 if (perf_evsel__open(evsel, cpus, threads, group, overwrite) < 0) {
515 PyErr_SetFromErrno(PyExc_OSError);
516 return NULL;
517 }
518
519 Py_INCREF(Py_None);
520 return Py_None;
521}
522
523static PyMethodDef pyrf_evsel__methods[] = {
524 {
525 .ml_name = "open",
526 .ml_meth = (PyCFunction)pyrf_evsel__open,
527 .ml_flags = METH_VARARGS | METH_KEYWORDS,
528 .ml_doc = PyDoc_STR("open the event selector file descriptor table.")
529 },
530 { .ml_name = NULL, }
531};
532
533static char pyrf_evsel__doc[] = PyDoc_STR("perf event selector list object.");
534
535static PyTypeObject pyrf_evsel__type = {
536 PyVarObject_HEAD_INIT(NULL, 0)
537 .tp_name = "perf.evsel",
538 .tp_basicsize = sizeof(struct pyrf_evsel),
539 .tp_dealloc = (destructor)pyrf_evsel__delete,
540 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
541 .tp_doc = pyrf_evsel__doc,
542 .tp_methods = pyrf_evsel__methods,
543 .tp_init = (initproc)pyrf_evsel__init,
544};
545
546static int pyrf_evsel__setup_types(void)
547{
548 pyrf_evsel__type.tp_new = PyType_GenericNew;
549 return PyType_Ready(&pyrf_evsel__type);
550}
551
552struct pyrf_evlist {
553 PyObject_HEAD
554
555 struct perf_evlist evlist;
556};
557
558static int pyrf_evlist__init(struct pyrf_evlist *pevlist,
559 PyObject *args, PyObject *kwargs __used)
560{
561 PyObject *pcpus = NULL, *pthreads = NULL;
562 struct cpu_map *cpus;
563 struct thread_map *threads;
564
565 if (!PyArg_ParseTuple(args, "OO", &pcpus, &pthreads))
566 return -1;
567
568 threads = ((struct pyrf_thread_map *)pthreads)->threads;
569 cpus = ((struct pyrf_cpu_map *)pcpus)->cpus;
570 perf_evlist__init(&pevlist->evlist, cpus, threads);
571 return 0;
572}
573
574static void pyrf_evlist__delete(struct pyrf_evlist *pevlist)
575{
576 perf_evlist__exit(&pevlist->evlist);
577 pevlist->ob_type->tp_free((PyObject*)pevlist);
578}
579
580static PyObject *pyrf_evlist__mmap(struct pyrf_evlist *pevlist,
581 PyObject *args, PyObject *kwargs)
582{
583 struct perf_evlist *evlist = &pevlist->evlist;
584 static char *kwlist[] = {"pages", "overwrite",
585 NULL, NULL};
586 int pages = 128, overwrite = false;
587
588 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii", kwlist,
589 &pages, &overwrite))
590 return NULL;
591
592 if (perf_evlist__mmap(evlist, pages, overwrite) < 0) {
593 PyErr_SetFromErrno(PyExc_OSError);
594 return NULL;
595 }
596
597 Py_INCREF(Py_None);
598 return Py_None;
599}
600
601static PyObject *pyrf_evlist__poll(struct pyrf_evlist *pevlist,
602 PyObject *args, PyObject *kwargs)
603{
604 struct perf_evlist *evlist = &pevlist->evlist;
605 static char *kwlist[] = {"timeout", NULL, NULL};
606 int timeout = -1, n;
607
608 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i", kwlist, &timeout))
609 return NULL;
610
611 n = poll(evlist->pollfd, evlist->nr_fds, timeout);
612 if (n < 0) {
613 PyErr_SetFromErrno(PyExc_OSError);
614 return NULL;
615 }
616
617 return Py_BuildValue("i", n);
618}
619
620static PyObject *pyrf_evlist__get_pollfd(struct pyrf_evlist *pevlist,
621 PyObject *args __used, PyObject *kwargs __used)
622{
623 struct perf_evlist *evlist = &pevlist->evlist;
624 PyObject *list = PyList_New(0);
625 int i;
626
627 for (i = 0; i < evlist->nr_fds; ++i) {
628 PyObject *file;
629 FILE *fp = fdopen(evlist->pollfd[i].fd, "r");
630
631 if (fp == NULL)
632 goto free_list;
633
634 file = PyFile_FromFile(fp, "perf", "r", NULL);
635 if (file == NULL)
636 goto free_list;
637
638 if (PyList_Append(list, file) != 0) {
639 Py_DECREF(file);
640 goto free_list;
641 }
642
643 Py_DECREF(file);
644 }
645
646 return list;
647free_list:
648 return PyErr_NoMemory();
649}
650
651
652static PyObject *pyrf_evlist__add(struct pyrf_evlist *pevlist,
653 PyObject *args, PyObject *kwargs __used)
654{
655 struct perf_evlist *evlist = &pevlist->evlist;
656 PyObject *pevsel;
657 struct perf_evsel *evsel;
658
659 if (!PyArg_ParseTuple(args, "O", &pevsel))
660 return NULL;
661
662 Py_INCREF(pevsel);
663 evsel = &((struct pyrf_evsel *)pevsel)->evsel;
664 evsel->idx = evlist->nr_entries;
665 perf_evlist__add(evlist, evsel);
666
667 return Py_BuildValue("i", evlist->nr_entries);
668}
669
670static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
671 PyObject *args, PyObject *kwargs)
672{
673 struct perf_evlist *evlist = &pevlist->evlist;
674 union perf_event *event;
675 int sample_id_all = 1, cpu;
676 static char *kwlist[] = {"sample_id_all", NULL, NULL};
677
678 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|i", kwlist,
679 &cpu, &sample_id_all))
680 return NULL;
681
682 event = perf_evlist__read_on_cpu(evlist, cpu);
683 if (event != NULL) {
684 struct perf_evsel *first;
685 PyObject *pyevent = pyrf_event__new(event);
686 struct pyrf_event *pevent = (struct pyrf_event *)pyevent;
687
688 if (pyevent == NULL)
689 return PyErr_NoMemory();
690
691 first = list_entry(evlist->entries.next, struct perf_evsel, node);
692 perf_event__parse_sample(event, first->attr.sample_type, sample_id_all,
693 &pevent->sample);
694 return pyevent;
695 }
696
697 Py_INCREF(Py_None);
698 return Py_None;
699}
700
701static PyMethodDef pyrf_evlist__methods[] = {
702 {
703 .ml_name = "mmap",
704 .ml_meth = (PyCFunction)pyrf_evlist__mmap,
705 .ml_flags = METH_VARARGS | METH_KEYWORDS,
706 .ml_doc = PyDoc_STR("mmap the file descriptor table.")
707 },
708 {
709 .ml_name = "poll",
710 .ml_meth = (PyCFunction)pyrf_evlist__poll,
711 .ml_flags = METH_VARARGS | METH_KEYWORDS,
712 .ml_doc = PyDoc_STR("poll the file descriptor table.")
713 },
714 {
715 .ml_name = "get_pollfd",
716 .ml_meth = (PyCFunction)pyrf_evlist__get_pollfd,
717 .ml_flags = METH_VARARGS | METH_KEYWORDS,
718 .ml_doc = PyDoc_STR("get the poll file descriptor table.")
719 },
720 {
721 .ml_name = "add",
722 .ml_meth = (PyCFunction)pyrf_evlist__add,
723 .ml_flags = METH_VARARGS | METH_KEYWORDS,
724 .ml_doc = PyDoc_STR("adds an event selector to the list.")
725 },
726 {
727 .ml_name = "read_on_cpu",
728 .ml_meth = (PyCFunction)pyrf_evlist__read_on_cpu,
729 .ml_flags = METH_VARARGS | METH_KEYWORDS,
730 .ml_doc = PyDoc_STR("reads an event.")
731 },
732 { .ml_name = NULL, }
733};
734
735static Py_ssize_t pyrf_evlist__length(PyObject *obj)
736{
737 struct pyrf_evlist *pevlist = (void *)obj;
738
739 return pevlist->evlist.nr_entries;
740}
741
742static PyObject *pyrf_evlist__item(PyObject *obj, Py_ssize_t i)
743{
744 struct pyrf_evlist *pevlist = (void *)obj;
745 struct perf_evsel *pos;
746
747 if (i >= pevlist->evlist.nr_entries)
748 return NULL;
749
750 list_for_each_entry(pos, &pevlist->evlist.entries, node)
751 if (i-- == 0)
752 break;
753
754 return Py_BuildValue("O", container_of(pos, struct pyrf_evsel, evsel));
755}
756
757static PySequenceMethods pyrf_evlist__sequence_methods = {
758 .sq_length = pyrf_evlist__length,
759 .sq_item = pyrf_evlist__item,
760};
761
762static char pyrf_evlist__doc[] = PyDoc_STR("perf event selector list object.");
763
764static PyTypeObject pyrf_evlist__type = {
765 PyVarObject_HEAD_INIT(NULL, 0)
766 .tp_name = "perf.evlist",
767 .tp_basicsize = sizeof(struct pyrf_evlist),
768 .tp_dealloc = (destructor)pyrf_evlist__delete,
769 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
770 .tp_as_sequence = &pyrf_evlist__sequence_methods,
771 .tp_doc = pyrf_evlist__doc,
772 .tp_methods = pyrf_evlist__methods,
773 .tp_init = (initproc)pyrf_evlist__init,
774};
775
776static int pyrf_evlist__setup_types(void)
777{
778 pyrf_evlist__type.tp_new = PyType_GenericNew;
779 return PyType_Ready(&pyrf_evlist__type);
780}
781
782static struct {
783 const char *name;
784 int value;
785} perf__constants[] = {
786 { "TYPE_HARDWARE", PERF_TYPE_HARDWARE },
787 { "TYPE_SOFTWARE", PERF_TYPE_SOFTWARE },
788 { "TYPE_TRACEPOINT", PERF_TYPE_TRACEPOINT },
789 { "TYPE_HW_CACHE", PERF_TYPE_HW_CACHE },
790 { "TYPE_RAW", PERF_TYPE_RAW },
791 { "TYPE_BREAKPOINT", PERF_TYPE_BREAKPOINT },
792
793 { "COUNT_HW_CPU_CYCLES", PERF_COUNT_HW_CPU_CYCLES },
794 { "COUNT_HW_INSTRUCTIONS", PERF_COUNT_HW_INSTRUCTIONS },
795 { "COUNT_HW_CACHE_REFERENCES", PERF_COUNT_HW_CACHE_REFERENCES },
796 { "COUNT_HW_CACHE_MISSES", PERF_COUNT_HW_CACHE_MISSES },
797 { "COUNT_HW_BRANCH_INSTRUCTIONS", PERF_COUNT_HW_BRANCH_INSTRUCTIONS },
798 { "COUNT_HW_BRANCH_MISSES", PERF_COUNT_HW_BRANCH_MISSES },
799 { "COUNT_HW_BUS_CYCLES", PERF_COUNT_HW_BUS_CYCLES },
800 { "COUNT_HW_CACHE_L1D", PERF_COUNT_HW_CACHE_L1D },
801 { "COUNT_HW_CACHE_L1I", PERF_COUNT_HW_CACHE_L1I },
802 { "COUNT_HW_CACHE_LL", PERF_COUNT_HW_CACHE_LL },
803 { "COUNT_HW_CACHE_DTLB", PERF_COUNT_HW_CACHE_DTLB },
804 { "COUNT_HW_CACHE_ITLB", PERF_COUNT_HW_CACHE_ITLB },
805 { "COUNT_HW_CACHE_BPU", PERF_COUNT_HW_CACHE_BPU },
806 { "COUNT_HW_CACHE_OP_READ", PERF_COUNT_HW_CACHE_OP_READ },
807 { "COUNT_HW_CACHE_OP_WRITE", PERF_COUNT_HW_CACHE_OP_WRITE },
808 { "COUNT_HW_CACHE_OP_PREFETCH", PERF_COUNT_HW_CACHE_OP_PREFETCH },
809 { "COUNT_HW_CACHE_RESULT_ACCESS", PERF_COUNT_HW_CACHE_RESULT_ACCESS },
810 { "COUNT_HW_CACHE_RESULT_MISS", PERF_COUNT_HW_CACHE_RESULT_MISS },
811
812 { "COUNT_SW_CPU_CLOCK", PERF_COUNT_SW_CPU_CLOCK },
813 { "COUNT_SW_TASK_CLOCK", PERF_COUNT_SW_TASK_CLOCK },
814 { "COUNT_SW_PAGE_FAULTS", PERF_COUNT_SW_PAGE_FAULTS },
815 { "COUNT_SW_CONTEXT_SWITCHES", PERF_COUNT_SW_CONTEXT_SWITCHES },
816 { "COUNT_SW_CPU_MIGRATIONS", PERF_COUNT_SW_CPU_MIGRATIONS },
817 { "COUNT_SW_PAGE_FAULTS_MIN", PERF_COUNT_SW_PAGE_FAULTS_MIN },
818 { "COUNT_SW_PAGE_FAULTS_MAJ", PERF_COUNT_SW_PAGE_FAULTS_MAJ },
819 { "COUNT_SW_ALIGNMENT_FAULTS", PERF_COUNT_SW_ALIGNMENT_FAULTS },
820 { "COUNT_SW_EMULATION_FAULTS", PERF_COUNT_SW_EMULATION_FAULTS },
821
822 { "SAMPLE_IP", PERF_SAMPLE_IP },
823 { "SAMPLE_TID", PERF_SAMPLE_TID },
824 { "SAMPLE_TIME", PERF_SAMPLE_TIME },
825 { "SAMPLE_ADDR", PERF_SAMPLE_ADDR },
826 { "SAMPLE_READ", PERF_SAMPLE_READ },
827 { "SAMPLE_CALLCHAIN", PERF_SAMPLE_CALLCHAIN },
828 { "SAMPLE_ID", PERF_SAMPLE_ID },
829 { "SAMPLE_CPU", PERF_SAMPLE_CPU },
830 { "SAMPLE_PERIOD", PERF_SAMPLE_PERIOD },
831 { "SAMPLE_STREAM_ID", PERF_SAMPLE_STREAM_ID },
832 { "SAMPLE_RAW", PERF_SAMPLE_RAW },
833
834 { "FORMAT_TOTAL_TIME_ENABLED", PERF_FORMAT_TOTAL_TIME_ENABLED },
835 { "FORMAT_TOTAL_TIME_RUNNING", PERF_FORMAT_TOTAL_TIME_RUNNING },
836 { "FORMAT_ID", PERF_FORMAT_ID },
837 { "FORMAT_GROUP", PERF_FORMAT_GROUP },
838
839 { "RECORD_MMAP", PERF_RECORD_MMAP },
840 { "RECORD_LOST", PERF_RECORD_LOST },
841 { "RECORD_COMM", PERF_RECORD_COMM },
842 { "RECORD_EXIT", PERF_RECORD_EXIT },
843 { "RECORD_THROTTLE", PERF_RECORD_THROTTLE },
844 { "RECORD_UNTHROTTLE", PERF_RECORD_UNTHROTTLE },
845 { "RECORD_FORK", PERF_RECORD_FORK },
846 { "RECORD_READ", PERF_RECORD_READ },
847 { "RECORD_SAMPLE", PERF_RECORD_SAMPLE },
848 { .name = NULL, },
849};
850
851static PyMethodDef perf__methods[] = {
852 { .ml_name = NULL, }
853};
854
855PyMODINIT_FUNC initperf(void)
856{
857 PyObject *obj;
858 int i;
859 PyObject *dict, *module = Py_InitModule("perf", perf__methods);
860
861 if (module == NULL ||
862 pyrf_event__setup_types() < 0 ||
863 pyrf_evlist__setup_types() < 0 ||
864 pyrf_evsel__setup_types() < 0 ||
865 pyrf_thread_map__setup_types() < 0 ||
866 pyrf_cpu_map__setup_types() < 0)
867 return;
868
869 Py_INCREF(&pyrf_evlist__type);
870 PyModule_AddObject(module, "evlist", (PyObject*)&pyrf_evlist__type);
871
872 Py_INCREF(&pyrf_evsel__type);
873 PyModule_AddObject(module, "evsel", (PyObject*)&pyrf_evsel__type);
874
875 Py_INCREF(&pyrf_thread_map__type);
876 PyModule_AddObject(module, "thread_map", (PyObject*)&pyrf_thread_map__type);
877
878 Py_INCREF(&pyrf_cpu_map__type);
879 PyModule_AddObject(module, "cpu_map", (PyObject*)&pyrf_cpu_map__type);
880
881 dict = PyModule_GetDict(module);
882 if (dict == NULL)
883 goto error;
884
885 for (i = 0; perf__constants[i].name != NULL; i++) {
886 obj = PyInt_FromLong(perf__constants[i].value);
887 if (obj == NULL)
888 goto error;
889 PyDict_SetItemString(dict, perf__constants[i].name, obj);
890 Py_DECREF(obj);
891 }
892
893error:
894 if (PyErr_Occurred())
895 PyErr_SetString(PyExc_ImportError, "perf: Init failed!");
896}
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index 93680818e244..74350ffb57fe 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -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
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index c6d99334bdfa..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));
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 105f00bfd555..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 }
@@ -67,7 +69,7 @@ out_close:
67 69
68static void perf_session__id_header_size(struct perf_session *session) 70static void perf_session__id_header_size(struct perf_session *session)
69{ 71{
70 struct sample_data *data; 72 struct perf_sample *data;
71 u64 sample_type = session->sample_type; 73 u64 sample_type = session->sample_type;
72 u16 size = 0; 74 u16 size = 0;
73 75
@@ -92,21 +94,10 @@ out:
92 session->id_hdr_size = size; 94 session->id_hdr_size = size;
93} 95}
94 96
95void perf_session__set_sample_id_all(struct perf_session *session, bool value)
96{
97 session->sample_id_all = value;
98 perf_session__id_header_size(session);
99}
100
101void perf_session__set_sample_type(struct perf_session *session, u64 type)
102{
103 session->sample_type = type;
104}
105
106void perf_session__update_sample_type(struct perf_session *self) 97void perf_session__update_sample_type(struct perf_session *self)
107{ 98{
108 self->sample_type = perf_header__sample_type(&self->header); 99 self->sample_type = perf_evlist__sample_type(self->evlist);
109 self->sample_id_all = perf_header__sample_id_all(&self->header); 100 self->sample_id_all = perf_evlist__sample_id_all(self->evlist);
110 perf_session__id_header_size(self); 101 perf_session__id_header_size(self);
111} 102}
112 103
@@ -135,13 +126,9 @@ struct perf_session *perf_session__new(const char *filename, int mode,
135 if (self == NULL) 126 if (self == NULL)
136 goto out; 127 goto out;
137 128
138 if (perf_header__init(&self->header) < 0)
139 goto out_free;
140
141 memcpy(self->filename, filename, len); 129 memcpy(self->filename, filename, len);
142 self->threads = RB_ROOT; 130 self->threads = RB_ROOT;
143 INIT_LIST_HEAD(&self->dead_threads); 131 INIT_LIST_HEAD(&self->dead_threads);
144 self->hists_tree = RB_ROOT;
145 self->last_match = NULL; 132 self->last_match = NULL;
146 /* 133 /*
147 * On 64bit we can mmap the data file in one go. No need for tiny mmap 134 * On 64bit we can mmap the data file in one go. No need for tiny mmap
@@ -162,17 +149,16 @@ struct perf_session *perf_session__new(const char *filename, int mode,
162 if (mode == O_RDONLY) { 149 if (mode == O_RDONLY) {
163 if (perf_session__open(self, force) < 0) 150 if (perf_session__open(self, force) < 0)
164 goto out_delete; 151 goto out_delete;
152 perf_session__update_sample_type(self);
165 } else if (mode == O_WRONLY) { 153 } else if (mode == O_WRONLY) {
166 /* 154 /*
167 * In O_RDONLY mode this will be performed when reading the 155 * In O_RDONLY mode this will be performed when reading the
168 * kernel MMAP event, in event__process_mmap(). 156 * kernel MMAP event, in perf_event__process_mmap().
169 */ 157 */
170 if (perf_session__create_kernel_maps(self) < 0) 158 if (perf_session__create_kernel_maps(self) < 0)
171 goto out_delete; 159 goto out_delete;
172 } 160 }
173 161
174 perf_session__update_sample_type(self);
175
176 if (ops && ops->ordering_requires_timestamps && 162 if (ops && ops->ordering_requires_timestamps &&
177 ops->ordered_samples && !self->sample_id_all) { 163 ops->ordered_samples && !self->sample_id_all) {
178 dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n"); 164 dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n");
@@ -181,9 +167,6 @@ struct perf_session *perf_session__new(const char *filename, int mode,
181 167
182out: 168out:
183 return self; 169 return self;
184out_free:
185 free(self);
186 return NULL;
187out_delete: 170out_delete:
188 perf_session__delete(self); 171 perf_session__delete(self);
189 return NULL; 172 return NULL;
@@ -214,7 +197,6 @@ static void perf_session__delete_threads(struct perf_session *self)
214 197
215void perf_session__delete(struct perf_session *self) 198void perf_session__delete(struct perf_session *self)
216{ 199{
217 perf_header__exit(&self->header);
218 perf_session__destroy_kernel_maps(self); 200 perf_session__destroy_kernel_maps(self);
219 perf_session__delete_dead_threads(self); 201 perf_session__delete_dead_threads(self);
220 perf_session__delete_threads(self); 202 perf_session__delete_threads(self);
@@ -242,17 +224,16 @@ static bool symbol__match_parent_regex(struct symbol *sym)
242 return 0; 224 return 0;
243} 225}
244 226
245struct map_symbol *perf_session__resolve_callchain(struct perf_session *self, 227int perf_session__resolve_callchain(struct perf_session *self,
246 struct thread *thread, 228 struct thread *thread,
247 struct ip_callchain *chain, 229 struct ip_callchain *chain,
248 struct symbol **parent) 230 struct symbol **parent)
249{ 231{
250 u8 cpumode = PERF_RECORD_MISC_USER; 232 u8 cpumode = PERF_RECORD_MISC_USER;
251 unsigned int i; 233 unsigned int i;
252 struct map_symbol *syms = calloc(chain->nr, sizeof(*syms)); 234 int err;
253 235
254 if (!syms) 236 callchain_cursor_reset(&self->callchain_cursor);
255 return NULL;
256 237
257 for (i = 0; i < chain->nr; i++) { 238 for (i = 0; i < chain->nr; i++) {
258 u64 ip = chain->ips[i]; 239 u64 ip = chain->ips[i];
@@ -281,30 +262,42 @@ struct map_symbol *perf_session__resolve_callchain(struct perf_session *self,
281 *parent = al.sym; 262 *parent = al.sym;
282 if (!symbol_conf.use_callchain) 263 if (!symbol_conf.use_callchain)
283 break; 264 break;
284 syms[i].map = al.map;
285 syms[i].sym = al.sym;
286 } 265 }
266
267 err = callchain_cursor_append(&self->callchain_cursor,
268 ip, al.map, al.sym);
269 if (err)
270 return err;
287 } 271 }
288 272
289 return syms; 273 return 0;
290} 274}
291 275
292static int process_event_synth_stub(event_t *event __used, 276static int process_event_synth_stub(union perf_event *event __used,
293 struct perf_session *session __used) 277 struct perf_session *session __used)
294{ 278{
295 dump_printf(": unhandled!\n"); 279 dump_printf(": unhandled!\n");
296 return 0; 280 return 0;
297} 281}
298 282
299static int process_event_stub(event_t *event __used, 283static int process_event_sample_stub(union perf_event *event __used,
300 struct sample_data *sample __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,
301 struct perf_session *session __used) 294 struct perf_session *session __used)
302{ 295{
303 dump_printf(": unhandled!\n"); 296 dump_printf(": unhandled!\n");
304 return 0; 297 return 0;
305} 298}
306 299
307static int process_finished_round_stub(event_t *event __used, 300static int process_finished_round_stub(union perf_event *event __used,
308 struct perf_session *session __used, 301 struct perf_session *session __used,
309 struct perf_event_ops *ops __used) 302 struct perf_event_ops *ops __used)
310{ 303{
@@ -312,14 +305,14 @@ static int process_finished_round_stub(event_t *event __used,
312 return 0; 305 return 0;
313} 306}
314 307
315static int process_finished_round(event_t *event, 308static int process_finished_round(union perf_event *event,
316 struct perf_session *session, 309 struct perf_session *session,
317 struct perf_event_ops *ops); 310 struct perf_event_ops *ops);
318 311
319static void perf_event_ops__fill_defaults(struct perf_event_ops *handler) 312static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
320{ 313{
321 if (handler->sample == NULL) 314 if (handler->sample == NULL)
322 handler->sample = process_event_stub; 315 handler->sample = process_event_sample_stub;
323 if (handler->mmap == NULL) 316 if (handler->mmap == NULL)
324 handler->mmap = process_event_stub; 317 handler->mmap = process_event_stub;
325 if (handler->comm == NULL) 318 if (handler->comm == NULL)
@@ -329,7 +322,7 @@ static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
329 if (handler->exit == NULL) 322 if (handler->exit == NULL)
330 handler->exit = process_event_stub; 323 handler->exit = process_event_stub;
331 if (handler->lost == NULL) 324 if (handler->lost == NULL)
332 handler->lost = event__process_lost; 325 handler->lost = perf_event__process_lost;
333 if (handler->read == NULL) 326 if (handler->read == NULL)
334 handler->read = process_event_stub; 327 handler->read = process_event_stub;
335 if (handler->throttle == NULL) 328 if (handler->throttle == NULL)
@@ -363,98 +356,98 @@ void mem_bswap_64(void *src, int byte_size)
363 } 356 }
364} 357}
365 358
366static void event__all64_swap(event_t *self) 359static void perf_event__all64_swap(union perf_event *event)
367{ 360{
368 struct perf_event_header *hdr = &self->header; 361 struct perf_event_header *hdr = &event->header;
369 mem_bswap_64(hdr + 1, self->header.size - sizeof(*hdr)); 362 mem_bswap_64(hdr + 1, event->header.size - sizeof(*hdr));
370} 363}
371 364
372static void event__comm_swap(event_t *self) 365static void perf_event__comm_swap(union perf_event *event)
373{ 366{
374 self->comm.pid = bswap_32(self->comm.pid); 367 event->comm.pid = bswap_32(event->comm.pid);
375 self->comm.tid = bswap_32(self->comm.tid); 368 event->comm.tid = bswap_32(event->comm.tid);
376} 369}
377 370
378static void event__mmap_swap(event_t *self) 371static void perf_event__mmap_swap(union perf_event *event)
379{ 372{
380 self->mmap.pid = bswap_32(self->mmap.pid); 373 event->mmap.pid = bswap_32(event->mmap.pid);
381 self->mmap.tid = bswap_32(self->mmap.tid); 374 event->mmap.tid = bswap_32(event->mmap.tid);
382 self->mmap.start = bswap_64(self->mmap.start); 375 event->mmap.start = bswap_64(event->mmap.start);
383 self->mmap.len = bswap_64(self->mmap.len); 376 event->mmap.len = bswap_64(event->mmap.len);
384 self->mmap.pgoff = bswap_64(self->mmap.pgoff); 377 event->mmap.pgoff = bswap_64(event->mmap.pgoff);
385} 378}
386 379
387static void event__task_swap(event_t *self) 380static void perf_event__task_swap(union perf_event *event)
388{ 381{
389 self->fork.pid = bswap_32(self->fork.pid); 382 event->fork.pid = bswap_32(event->fork.pid);
390 self->fork.tid = bswap_32(self->fork.tid); 383 event->fork.tid = bswap_32(event->fork.tid);
391 self->fork.ppid = bswap_32(self->fork.ppid); 384 event->fork.ppid = bswap_32(event->fork.ppid);
392 self->fork.ptid = bswap_32(self->fork.ptid); 385 event->fork.ptid = bswap_32(event->fork.ptid);
393 self->fork.time = bswap_64(self->fork.time); 386 event->fork.time = bswap_64(event->fork.time);
394} 387}
395 388
396static void event__read_swap(event_t *self) 389static void perf_event__read_swap(union perf_event *event)
397{ 390{
398 self->read.pid = bswap_32(self->read.pid); 391 event->read.pid = bswap_32(event->read.pid);
399 self->read.tid = bswap_32(self->read.tid); 392 event->read.tid = bswap_32(event->read.tid);
400 self->read.value = bswap_64(self->read.value); 393 event->read.value = bswap_64(event->read.value);
401 self->read.time_enabled = bswap_64(self->read.time_enabled); 394 event->read.time_enabled = bswap_64(event->read.time_enabled);
402 self->read.time_running = bswap_64(self->read.time_running); 395 event->read.time_running = bswap_64(event->read.time_running);
403 self->read.id = bswap_64(self->read.id); 396 event->read.id = bswap_64(event->read.id);
404} 397}
405 398
406static void event__attr_swap(event_t *self) 399static void perf_event__attr_swap(union perf_event *event)
407{ 400{
408 size_t size; 401 size_t size;
409 402
410 self->attr.attr.type = bswap_32(self->attr.attr.type); 403 event->attr.attr.type = bswap_32(event->attr.attr.type);
411 self->attr.attr.size = bswap_32(self->attr.attr.size); 404 event->attr.attr.size = bswap_32(event->attr.attr.size);
412 self->attr.attr.config = bswap_64(self->attr.attr.config); 405 event->attr.attr.config = bswap_64(event->attr.attr.config);
413 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);
414 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);
415 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);
416 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);
417 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);
418 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);
419 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);
420 413
421 size = self->header.size; 414 size = event->header.size;
422 size -= (void *)&self->attr.id - (void *)self; 415 size -= (void *)&event->attr.id - (void *)event;
423 mem_bswap_64(self->attr.id, size); 416 mem_bswap_64(event->attr.id, size);
424} 417}
425 418
426static void event__event_type_swap(event_t *self) 419static void perf_event__event_type_swap(union perf_event *event)
427{ 420{
428 self->event_type.event_type.event_id = 421 event->event_type.event_type.event_id =
429 bswap_64(self->event_type.event_type.event_id); 422 bswap_64(event->event_type.event_type.event_id);
430} 423}
431 424
432static void event__tracing_data_swap(event_t *self) 425static void perf_event__tracing_data_swap(union perf_event *event)
433{ 426{
434 self->tracing_data.size = bswap_32(self->tracing_data.size); 427 event->tracing_data.size = bswap_32(event->tracing_data.size);
435} 428}
436 429
437typedef void (*event__swap_op)(event_t *self); 430typedef void (*perf_event__swap_op)(union perf_event *event);
438 431
439static event__swap_op event__swap_ops[] = { 432static perf_event__swap_op perf_event__swap_ops[] = {
440 [PERF_RECORD_MMAP] = event__mmap_swap, 433 [PERF_RECORD_MMAP] = perf_event__mmap_swap,
441 [PERF_RECORD_COMM] = event__comm_swap, 434 [PERF_RECORD_COMM] = perf_event__comm_swap,
442 [PERF_RECORD_FORK] = event__task_swap, 435 [PERF_RECORD_FORK] = perf_event__task_swap,
443 [PERF_RECORD_EXIT] = event__task_swap, 436 [PERF_RECORD_EXIT] = perf_event__task_swap,
444 [PERF_RECORD_LOST] = event__all64_swap, 437 [PERF_RECORD_LOST] = perf_event__all64_swap,
445 [PERF_RECORD_READ] = event__read_swap, 438 [PERF_RECORD_READ] = perf_event__read_swap,
446 [PERF_RECORD_SAMPLE] = event__all64_swap, 439 [PERF_RECORD_SAMPLE] = perf_event__all64_swap,
447 [PERF_RECORD_HEADER_ATTR] = event__attr_swap, 440 [PERF_RECORD_HEADER_ATTR] = perf_event__attr_swap,
448 [PERF_RECORD_HEADER_EVENT_TYPE] = event__event_type_swap, 441 [PERF_RECORD_HEADER_EVENT_TYPE] = perf_event__event_type_swap,
449 [PERF_RECORD_HEADER_TRACING_DATA] = event__tracing_data_swap, 442 [PERF_RECORD_HEADER_TRACING_DATA] = perf_event__tracing_data_swap,
450 [PERF_RECORD_HEADER_BUILD_ID] = NULL, 443 [PERF_RECORD_HEADER_BUILD_ID] = NULL,
451 [PERF_RECORD_HEADER_MAX] = NULL, 444 [PERF_RECORD_HEADER_MAX] = NULL,
452}; 445};
453 446
454struct sample_queue { 447struct sample_queue {
455 u64 timestamp; 448 u64 timestamp;
456 u64 file_offset; 449 u64 file_offset;
457 event_t *event; 450 union perf_event *event;
458 struct list_head list; 451 struct list_head list;
459}; 452};
460 453
@@ -472,8 +465,8 @@ static void perf_session_free_sample_buffers(struct perf_session *session)
472} 465}
473 466
474static int perf_session_deliver_event(struct perf_session *session, 467static int perf_session_deliver_event(struct perf_session *session,
475 event_t *event, 468 union perf_event *event,
476 struct sample_data *sample, 469 struct perf_sample *sample,
477 struct perf_event_ops *ops, 470 struct perf_event_ops *ops,
478 u64 file_offset); 471 u64 file_offset);
479 472
@@ -483,7 +476,7 @@ static void flush_sample_queue(struct perf_session *s,
483 struct ordered_samples *os = &s->ordered_samples; 476 struct ordered_samples *os = &s->ordered_samples;
484 struct list_head *head = &os->samples; 477 struct list_head *head = &os->samples;
485 struct sample_queue *tmp, *iter; 478 struct sample_queue *tmp, *iter;
486 struct sample_data sample; 479 struct perf_sample sample;
487 u64 limit = os->next_flush; 480 u64 limit = os->next_flush;
488 u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL; 481 u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL;
489 482
@@ -494,7 +487,7 @@ static void flush_sample_queue(struct perf_session *s,
494 if (iter->timestamp > limit) 487 if (iter->timestamp > limit)
495 break; 488 break;
496 489
497 event__parse_sample(iter->event, s, &sample); 490 perf_session__parse_sample(s, iter->event, &sample);
498 perf_session_deliver_event(s, iter->event, &sample, ops, 491 perf_session_deliver_event(s, iter->event, &sample, ops,
499 iter->file_offset); 492 iter->file_offset);
500 493
@@ -550,7 +543,7 @@ static void flush_sample_queue(struct perf_session *s,
550 * Flush every events below timestamp 7 543 * Flush every events below timestamp 7
551 * etc... 544 * etc...
552 */ 545 */
553static int process_finished_round(event_t *event __used, 546static int process_finished_round(union perf_event *event __used,
554 struct perf_session *session, 547 struct perf_session *session,
555 struct perf_event_ops *ops) 548 struct perf_event_ops *ops)
556{ 549{
@@ -607,12 +600,12 @@ static void __queue_event(struct sample_queue *new, struct perf_session *s)
607 600
608#define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct sample_queue)) 601#define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct sample_queue))
609 602
610static int perf_session_queue_event(struct perf_session *s, event_t *event, 603static int perf_session_queue_event(struct perf_session *s, union perf_event *event,
611 struct sample_data *data, u64 file_offset) 604 struct perf_sample *sample, u64 file_offset)
612{ 605{
613 struct ordered_samples *os = &s->ordered_samples; 606 struct ordered_samples *os = &s->ordered_samples;
614 struct list_head *sc = &os->sample_cache; 607 struct list_head *sc = &os->sample_cache;
615 u64 timestamp = data->time; 608 u64 timestamp = sample->time;
616 struct sample_queue *new; 609 struct sample_queue *new;
617 610
618 if (!timestamp || timestamp == ~0ULL) 611 if (!timestamp || timestamp == ~0ULL)
@@ -648,7 +641,7 @@ static int perf_session_queue_event(struct perf_session *s, event_t *event,
648 return 0; 641 return 0;
649} 642}
650 643
651static void callchain__printf(struct sample_data *sample) 644static void callchain__printf(struct perf_sample *sample)
652{ 645{
653 unsigned int i; 646 unsigned int i;
654 647
@@ -660,8 +653,8 @@ static void callchain__printf(struct sample_data *sample)
660} 653}
661 654
662static void perf_session__print_tstamp(struct perf_session *session, 655static void perf_session__print_tstamp(struct perf_session *session,
663 event_t *event, 656 union perf_event *event,
664 struct sample_data *sample) 657 struct perf_sample *sample)
665{ 658{
666 if (event->header.type != PERF_RECORD_SAMPLE && 659 if (event->header.type != PERF_RECORD_SAMPLE &&
667 !session->sample_id_all) { 660 !session->sample_id_all) {
@@ -676,8 +669,8 @@ static void perf_session__print_tstamp(struct perf_session *session,
676 printf("%" PRIu64 " ", sample->time); 669 printf("%" PRIu64 " ", sample->time);
677} 670}
678 671
679static void dump_event(struct perf_session *session, event_t *event, 672static void dump_event(struct perf_session *session, union perf_event *event,
680 u64 file_offset, struct sample_data *sample) 673 u64 file_offset, struct perf_sample *sample)
681{ 674{
682 if (!dump_trace) 675 if (!dump_trace)
683 return; 676 return;
@@ -691,11 +684,11 @@ static void dump_event(struct perf_session *session, event_t *event,
691 perf_session__print_tstamp(session, event, sample); 684 perf_session__print_tstamp(session, event, sample);
692 685
693 printf("%#" PRIx64 " [%#x]: PERF_RECORD_%s", file_offset, 686 printf("%#" PRIx64 " [%#x]: PERF_RECORD_%s", file_offset,
694 event->header.size, event__get_event_name(event->header.type)); 687 event->header.size, perf_event__name(event->header.type));
695} 688}
696 689
697static void dump_sample(struct perf_session *session, event_t *event, 690static void dump_sample(struct perf_session *session, union perf_event *event,
698 struct sample_data *sample) 691 struct perf_sample *sample)
699{ 692{
700 if (!dump_trace) 693 if (!dump_trace)
701 return; 694 return;
@@ -709,17 +702,24 @@ static void dump_sample(struct perf_session *session, event_t *event,
709} 702}
710 703
711static int perf_session_deliver_event(struct perf_session *session, 704static int perf_session_deliver_event(struct perf_session *session,
712 event_t *event, 705 union perf_event *event,
713 struct sample_data *sample, 706 struct perf_sample *sample,
714 struct perf_event_ops *ops, 707 struct perf_event_ops *ops,
715 u64 file_offset) 708 u64 file_offset)
716{ 709{
710 struct perf_evsel *evsel;
711
717 dump_event(session, event, file_offset, sample); 712 dump_event(session, event, file_offset, sample);
718 713
719 switch (event->header.type) { 714 switch (event->header.type) {
720 case PERF_RECORD_SAMPLE: 715 case PERF_RECORD_SAMPLE:
721 dump_sample(session, event, sample); 716 dump_sample(session, event, sample);
722 return ops->sample(event, sample, session); 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);
723 case PERF_RECORD_MMAP: 723 case PERF_RECORD_MMAP:
724 return ops->mmap(event, sample, session); 724 return ops->mmap(event, sample, session);
725 case PERF_RECORD_COMM: 725 case PERF_RECORD_COMM:
@@ -743,7 +743,7 @@ static int perf_session_deliver_event(struct perf_session *session,
743} 743}
744 744
745static int perf_session__preprocess_sample(struct perf_session *session, 745static int perf_session__preprocess_sample(struct perf_session *session,
746 event_t *event, struct sample_data *sample) 746 union perf_event *event, struct perf_sample *sample)
747{ 747{
748 if (event->header.type != PERF_RECORD_SAMPLE || 748 if (event->header.type != PERF_RECORD_SAMPLE ||
749 !(session->sample_type & PERF_SAMPLE_CALLCHAIN)) 749 !(session->sample_type & PERF_SAMPLE_CALLCHAIN))
@@ -758,7 +758,7 @@ static int perf_session__preprocess_sample(struct perf_session *session,
758 return 0; 758 return 0;
759} 759}
760 760
761static int perf_session__process_user_event(struct perf_session *session, event_t *event, 761static int perf_session__process_user_event(struct perf_session *session, union perf_event *event,
762 struct perf_event_ops *ops, u64 file_offset) 762 struct perf_event_ops *ops, u64 file_offset)
763{ 763{
764 dump_event(session, event, file_offset, NULL); 764 dump_event(session, event, file_offset, NULL);
@@ -783,15 +783,16 @@ static int perf_session__process_user_event(struct perf_session *session, event_
783} 783}
784 784
785static int perf_session__process_event(struct perf_session *session, 785static int perf_session__process_event(struct perf_session *session,
786 event_t *event, 786 union perf_event *event,
787 struct perf_event_ops *ops, 787 struct perf_event_ops *ops,
788 u64 file_offset) 788 u64 file_offset)
789{ 789{
790 struct sample_data sample; 790 struct perf_sample sample;
791 int ret; 791 int ret;
792 792
793 if (session->header.needs_swap && event__swap_ops[event->header.type]) 793 if (session->header.needs_swap &&
794 event__swap_ops[event->header.type](event); 794 perf_event__swap_ops[event->header.type])
795 perf_event__swap_ops[event->header.type](event);
795 796
796 if (event->header.type >= PERF_RECORD_HEADER_MAX) 797 if (event->header.type >= PERF_RECORD_HEADER_MAX)
797 return -EINVAL; 798 return -EINVAL;
@@ -804,7 +805,7 @@ static int perf_session__process_event(struct perf_session *session,
804 /* 805 /*
805 * For all kernel events we get the sample data 806 * For all kernel events we get the sample data
806 */ 807 */
807 event__parse_sample(event, session, &sample); 808 perf_session__parse_sample(session, event, &sample);
808 809
809 /* Preprocess sample records - precheck callchains */ 810 /* Preprocess sample records - precheck callchains */
810 if (perf_session__preprocess_sample(session, event, &sample)) 811 if (perf_session__preprocess_sample(session, event, &sample))
@@ -843,7 +844,7 @@ static struct thread *perf_session__register_idle_thread(struct perf_session *se
843static void perf_session__warn_about_errors(const struct perf_session *session, 844static void perf_session__warn_about_errors(const struct perf_session *session,
844 const struct perf_event_ops *ops) 845 const struct perf_event_ops *ops)
845{ 846{
846 if (ops->lost == event__process_lost && 847 if (ops->lost == perf_event__process_lost &&
847 session->hists.stats.total_lost != 0) { 848 session->hists.stats.total_lost != 0) {
848 ui__warning("Processed %" PRIu64 " events and LOST %" PRIu64 849 ui__warning("Processed %" PRIu64 " events and LOST %" PRIu64
849 "!\n\nCheck IO/CPU overload!\n\n", 850 "!\n\nCheck IO/CPU overload!\n\n",
@@ -860,6 +861,11 @@ static void perf_session__warn_about_errors(const struct perf_session *session,
860 session->hists.stats.nr_unknown_events); 861 session->hists.stats.nr_unknown_events);
861 } 862 }
862 863
864 if (session->hists.stats.nr_unknown_id != 0) {
865 ui__warning("%u samples with id not present in the header\n",
866 session->hists.stats.nr_unknown_id);
867 }
868
863 if (session->hists.stats.nr_invalid_chains != 0) { 869 if (session->hists.stats.nr_invalid_chains != 0) {
864 ui__warning("Found invalid callchains!\n\n" 870 ui__warning("Found invalid callchains!\n\n"
865 "%u out of %u events were discarded for this reason.\n\n" 871 "%u out of %u events were discarded for this reason.\n\n"
@@ -875,7 +881,7 @@ volatile int session_done;
875static int __perf_session__process_pipe_events(struct perf_session *self, 881static int __perf_session__process_pipe_events(struct perf_session *self,
876 struct perf_event_ops *ops) 882 struct perf_event_ops *ops)
877{ 883{
878 event_t event; 884 union perf_event event;
879 uint32_t size; 885 uint32_t size;
880 int skip = 0; 886 int skip = 0;
881 u64 head; 887 u64 head;
@@ -956,7 +962,7 @@ int __perf_session__process_events(struct perf_session *session,
956 struct ui_progress *progress; 962 struct ui_progress *progress;
957 size_t page_size, mmap_size; 963 size_t page_size, mmap_size;
958 char *buf, *mmaps[8]; 964 char *buf, *mmaps[8];
959 event_t *event; 965 union perf_event *event;
960 uint32_t size; 966 uint32_t size;
961 967
962 perf_event_ops__fill_defaults(ops); 968 perf_event_ops__fill_defaults(ops);
@@ -1001,7 +1007,7 @@ remap:
1001 file_pos = file_offset + head; 1007 file_pos = file_offset + head;
1002 1008
1003more: 1009more:
1004 event = (event_t *)(buf + head); 1010 event = (union perf_event *)(buf + head);
1005 1011
1006 if (session->header.needs_swap) 1012 if (session->header.needs_swap)
1007 perf_event_header__bswap(&event->header); 1013 perf_event_header__bswap(&event->header);
@@ -1134,3 +1140,79 @@ size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp,
1134 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);
1135 return ret + machines__fprintf_dsos_buildid(&self->machines, fp, with_hits); 1141 return ret + machines__fprintf_dsos_buildid(&self->machines, fp, with_hits);
1136} 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 decd83f274fd..1ac481fc1100 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -34,12 +34,12 @@ struct perf_session {
34 struct thread *last_match; 34 struct thread *last_match;
35 struct machine host_machine; 35 struct machine host_machine;
36 struct rb_root machines; 36 struct rb_root machines;
37 struct rb_root hists_tree; 37 struct perf_evlist *evlist;
38 /* 38 /*
39 * FIXME: should point to the first entry in hists_tree and 39 * FIXME: Need to split this up further, we need global
40 * be a hists instance. Right now its only 'report' 40 * stats + per event stats. 'perf diff' also needs
41 * that is using ->hists_tree while all the rest use 41 * to properly support multiple events in a single
42 * ->hists. 42 * perf.data file.
43 */ 43 */
44 struct hists hists; 44 struct hists hists;
45 u64 sample_type; 45 u64 sample_type;
@@ -51,20 +51,25 @@ struct perf_session {
51 int cwdlen; 51 int cwdlen;
52 char *cwd; 52 char *cwd;
53 struct ordered_samples ordered_samples; 53 struct ordered_samples ordered_samples;
54 char filename[0]; 54 struct callchain_cursor callchain_cursor;
55 char filename[0];
55}; 56};
56 57
58struct perf_evsel;
57struct perf_event_ops; 59struct perf_event_ops;
58 60
59typedef int (*event_op)(event_t *self, struct sample_data *sample, 61typedef int (*event_sample)(union perf_event *event, struct perf_sample *sample,
62 struct perf_evsel *evsel, struct perf_session *session);
63typedef int (*event_op)(union perf_event *self, struct perf_sample *sample,
60 struct perf_session *session); 64 struct perf_session *session);
61typedef int (*event_synth_op)(event_t *self, struct perf_session *session); 65typedef int (*event_synth_op)(union perf_event *self,
62typedef int (*event_op2)(event_t *self, struct perf_session *session, 66 struct perf_session *session);
67typedef int (*event_op2)(union perf_event *self, struct perf_session *session,
63 struct perf_event_ops *ops); 68 struct perf_event_ops *ops);
64 69
65struct perf_event_ops { 70struct perf_event_ops {
66 event_op sample, 71 event_sample sample;
67 mmap, 72 event_op mmap,
68 comm, 73 comm,
69 fork, 74 fork,
70 exit, 75 exit,
@@ -94,10 +99,10 @@ int __perf_session__process_events(struct perf_session *self,
94int perf_session__process_events(struct perf_session *self, 99int perf_session__process_events(struct perf_session *self,
95 struct perf_event_ops *event_ops); 100 struct perf_event_ops *event_ops);
96 101
97struct map_symbol *perf_session__resolve_callchain(struct perf_session *self, 102int perf_session__resolve_callchain(struct perf_session *self,
98 struct thread *thread, 103 struct thread *thread,
99 struct ip_callchain *chain, 104 struct ip_callchain *chain,
100 struct symbol **parent); 105 struct symbol **parent);
101 106
102bool perf_session__has_traces(struct perf_session *self, const char *msg); 107bool perf_session__has_traces(struct perf_session *self, const char *msg);
103 108
@@ -110,8 +115,6 @@ void mem_bswap_64(void *src, int byte_size);
110int perf_session__create_kernel_maps(struct perf_session *self); 115int perf_session__create_kernel_maps(struct perf_session *self);
111 116
112void perf_session__update_sample_type(struct perf_session *self); 117void perf_session__update_sample_type(struct perf_session *self);
113void perf_session__set_sample_id_all(struct perf_session *session, bool value);
114void perf_session__set_sample_type(struct perf_session *session, u64 type);
115void perf_session__remove_thread(struct perf_session *self, struct thread *th); 118void perf_session__remove_thread(struct perf_session *self, struct thread *th);
116 119
117static inline 120static inline
@@ -149,9 +152,18 @@ size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp);
149size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, 152size_t perf_session__fprintf_dsos_buildid(struct perf_session *self,
150 FILE *fp, bool with_hits); 153 FILE *fp, bool with_hits);
151 154
152static inline 155size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp);
153size_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)
154{ 160{
155 return hists__fprintf_nr_events(&self->hists, fp); 161 return perf_event__parse_sample(event, session->sample_type,
162 session->sample_id_all, sample);
156} 163}
164
165void perf_session__print_symbols(union perf_event *event,
166 struct perf_sample *sample,
167 struct perf_session *session);
168
157#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/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 8fc0bd3a3a4a..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{
diff --git a/tools/perf/util/svghelper.c b/tools/perf/util/svghelper.c
index fb737fe9be91..96c866045d60 100644
--- a/tools/perf/util/svghelper.c
+++ b/tools/perf/util/svghelper.c
@@ -456,9 +456,9 @@ void svg_legenda(void)
456 return; 456 return;
457 457
458 svg_legenda_box(0, "Running", "sample"); 458 svg_legenda_box(0, "Running", "sample");
459 svg_legenda_box(100, "Idle","rect.c1"); 459 svg_legenda_box(100, "Idle","c1");
460 svg_legenda_box(200, "Deeper Idle", "rect.c3"); 460 svg_legenda_box(200, "Deeper Idle", "c3");
461 svg_legenda_box(350, "Deepest Idle", "rect.c6"); 461 svg_legenda_box(350, "Deepest Idle", "c6");
462 svg_legenda_box(550, "Sleeping", "process2"); 462 svg_legenda_box(550, "Sleeping", "process2");
463 svg_legenda_box(650, "Waiting for cpu", "waiting"); 463 svg_legenda_box(650, "Waiting for cpu", "waiting");
464 svg_legenda_box(800, "Blocked on IO", "blocked"); 464 svg_legenda_box(800, "Blocked on IO", "blocked");
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 7821d0e6866f..f06c10f092ba 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -207,8 +207,7 @@ struct dso *dso__new(const char *name)
207 dso__set_short_name(self, self->name); 207 dso__set_short_name(self, self->name);
208 for (i = 0; i < MAP__NR_TYPES; ++i) 208 for (i = 0; i < MAP__NR_TYPES; ++i)
209 self->symbols[i] = self->symbol_names[i] = RB_ROOT; 209 self->symbols[i] = self->symbol_names[i] = RB_ROOT;
210 self->slen_calculated = 0; 210 self->symtab_type = SYMTAB__NOT_FOUND;
211 self->origin = DSO__ORIG_NOT_FOUND;
212 self->loaded = 0; 211 self->loaded = 0;
213 self->sorted_by_name = 0; 212 self->sorted_by_name = 0;
214 self->has_build_id = 0; 213 self->has_build_id = 0;
@@ -681,9 +680,9 @@ int dso__load_kallsyms(struct dso *self, const char *filename,
681 return -1; 680 return -1;
682 681
683 if (self->kernel == DSO_TYPE_GUEST_KERNEL) 682 if (self->kernel == DSO_TYPE_GUEST_KERNEL)
684 self->origin = DSO__ORIG_GUEST_KERNEL; 683 self->symtab_type = SYMTAB__GUEST_KALLSYMS;
685 else 684 else
686 self->origin = DSO__ORIG_KERNEL; 685 self->symtab_type = SYMTAB__KALLSYMS;
687 686
688 return dso__split_kallsyms(self, map, filter); 687 return dso__split_kallsyms(self, map, filter);
689} 688}
@@ -1197,6 +1196,8 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
1197 if (curr_dso == NULL) 1196 if (curr_dso == NULL)
1198 goto out_elf_end; 1197 goto out_elf_end;
1199 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;
1200 curr_map = map__new2(start, curr_dso, 1201 curr_map = map__new2(start, curr_dso,
1201 map->type); 1202 map->type);
1202 if (curr_map == NULL) { 1203 if (curr_map == NULL) {
@@ -1205,7 +1206,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
1205 } 1206 }
1206 curr_map->map_ip = identity__map_ip; 1207 curr_map->map_ip = identity__map_ip;
1207 curr_map->unmap_ip = identity__map_ip; 1208 curr_map->unmap_ip = identity__map_ip;
1208 curr_dso->origin = self->origin; 1209 curr_dso->symtab_type = self->symtab_type;
1209 map_groups__insert(kmap->kmaps, curr_map); 1210 map_groups__insert(kmap->kmaps, curr_map);
1210 dsos__add(&self->node, curr_dso); 1211 dsos__add(&self->node, curr_dso);
1211 dso__set_loaded(curr_dso, map->type); 1212 dso__set_loaded(curr_dso, map->type);
@@ -1431,21 +1432,21 @@ out:
1431char dso__symtab_origin(const struct dso *self) 1432char dso__symtab_origin(const struct dso *self)
1432{ 1433{
1433 static const char origin[] = { 1434 static const char origin[] = {
1434 [DSO__ORIG_KERNEL] = 'k', 1435 [SYMTAB__KALLSYMS] = 'k',
1435 [DSO__ORIG_JAVA_JIT] = 'j', 1436 [SYMTAB__JAVA_JIT] = 'j',
1436 [DSO__ORIG_BUILD_ID_CACHE] = 'B', 1437 [SYMTAB__BUILD_ID_CACHE] = 'B',
1437 [DSO__ORIG_FEDORA] = 'f', 1438 [SYMTAB__FEDORA_DEBUGINFO] = 'f',
1438 [DSO__ORIG_UBUNTU] = 'u', 1439 [SYMTAB__UBUNTU_DEBUGINFO] = 'u',
1439 [DSO__ORIG_BUILDID] = 'b', 1440 [SYMTAB__BUILDID_DEBUGINFO] = 'b',
1440 [DSO__ORIG_DSO] = 'd', 1441 [SYMTAB__SYSTEM_PATH_DSO] = 'd',
1441 [DSO__ORIG_KMODULE] = 'K', 1442 [SYMTAB__SYSTEM_PATH_KMODULE] = 'K',
1442 [DSO__ORIG_GUEST_KERNEL] = 'g', 1443 [SYMTAB__GUEST_KALLSYMS] = 'g',
1443 [DSO__ORIG_GUEST_KMODULE] = 'G', 1444 [SYMTAB__GUEST_KMODULE] = 'G',
1444 }; 1445 };
1445 1446
1446 if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) 1447 if (self == NULL || self->symtab_type == SYMTAB__NOT_FOUND)
1447 return '!'; 1448 return '!';
1448 return origin[self->origin]; 1449 return origin[self->symtab_type];
1449} 1450}
1450 1451
1451int 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)
@@ -1478,8 +1479,8 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
1478 1479
1479 if (strncmp(self->name, "/tmp/perf-", 10) == 0) { 1480 if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
1480 ret = dso__load_perf_map(self, map, filter); 1481 ret = dso__load_perf_map(self, map, filter);
1481 self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : 1482 self->symtab_type = ret > 0 ? SYMTAB__JAVA_JIT :
1482 DSO__ORIG_NOT_FOUND; 1483 SYMTAB__NOT_FOUND;
1483 return ret; 1484 return ret;
1484 } 1485 }
1485 1486
@@ -1487,26 +1488,28 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
1487 * 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.
1488 * Failing that, do a second pass where we accept .dynsym also 1489 * Failing that, do a second pass where we accept .dynsym also
1489 */ 1490 */
1490 for (self->origin = DSO__ORIG_BUILD_ID_CACHE, want_symtab = 1; 1491 want_symtab = 1;
1491 self->origin != DSO__ORIG_NOT_FOUND; 1492restart:
1492 self->origin++) { 1493 for (self->symtab_type = SYMTAB__BUILD_ID_CACHE;
1493 switch (self->origin) { 1494 self->symtab_type != SYMTAB__NOT_FOUND;
1494 case DSO__ORIG_BUILD_ID_CACHE: 1495 self->symtab_type++) {
1496 switch (self->symtab_type) {
1497 case SYMTAB__BUILD_ID_CACHE:
1495 /* skip the locally configured cache if a symfs is given */ 1498 /* skip the locally configured cache if a symfs is given */
1496 if (symbol_conf.symfs[0] || 1499 if (symbol_conf.symfs[0] ||
1497 (dso__build_id_filename(self, name, size) == NULL)) { 1500 (dso__build_id_filename(self, name, size) == NULL)) {
1498 continue; 1501 continue;
1499 } 1502 }
1500 break; 1503 break;
1501 case DSO__ORIG_FEDORA: 1504 case SYMTAB__FEDORA_DEBUGINFO:
1502 snprintf(name, size, "%s/usr/lib/debug%s.debug", 1505 snprintf(name, size, "%s/usr/lib/debug%s.debug",
1503 symbol_conf.symfs, self->long_name); 1506 symbol_conf.symfs, self->long_name);
1504 break; 1507 break;
1505 case DSO__ORIG_UBUNTU: 1508 case SYMTAB__UBUNTU_DEBUGINFO:
1506 snprintf(name, size, "%s/usr/lib/debug%s", 1509 snprintf(name, size, "%s/usr/lib/debug%s",
1507 symbol_conf.symfs, self->long_name); 1510 symbol_conf.symfs, self->long_name);
1508 break; 1511 break;
1509 case DSO__ORIG_BUILDID: { 1512 case SYMTAB__BUILDID_DEBUGINFO: {
1510 char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 1513 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
1511 1514
1512 if (!self->has_build_id) 1515 if (!self->has_build_id)
@@ -1520,34 +1523,24 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
1520 symbol_conf.symfs, build_id_hex, build_id_hex + 2); 1523 symbol_conf.symfs, build_id_hex, build_id_hex + 2);
1521 } 1524 }
1522 break; 1525 break;
1523 case DSO__ORIG_DSO: 1526 case SYMTAB__SYSTEM_PATH_DSO:
1524 snprintf(name, size, "%s%s", 1527 snprintf(name, size, "%s%s",
1525 symbol_conf.symfs, self->long_name); 1528 symbol_conf.symfs, self->long_name);
1526 break; 1529 break;
1527 case DSO__ORIG_GUEST_KMODULE: 1530 case SYMTAB__GUEST_KMODULE:
1528 if (map->groups && map->groups->machine) 1531 if (map->groups && machine)
1529 root_dir = map->groups->machine->root_dir; 1532 root_dir = machine->root_dir;
1530 else 1533 else
1531 root_dir = ""; 1534 root_dir = "";
1532 snprintf(name, size, "%s%s%s", symbol_conf.symfs, 1535 snprintf(name, size, "%s%s%s", symbol_conf.symfs,
1533 root_dir, self->long_name); 1536 root_dir, self->long_name);
1534 break; 1537 break;
1535 1538
1536 case DSO__ORIG_KMODULE: 1539 case SYMTAB__SYSTEM_PATH_KMODULE:
1537 snprintf(name, size, "%s%s", symbol_conf.symfs, 1540 snprintf(name, size, "%s%s", symbol_conf.symfs,
1538 self->long_name); 1541 self->long_name);
1539 break; 1542 break;
1540 1543 default:;
1541 default:
1542 /*
1543 * If we wanted a full symtab but no image had one,
1544 * relax our requirements and repeat the search.
1545 */
1546 if (want_symtab) {
1547 want_symtab = 0;
1548 self->origin = DSO__ORIG_BUILD_ID_CACHE;
1549 } else
1550 continue;
1551 } 1544 }
1552 1545
1553 /* Name is now the name of the next image to try */ 1546 /* Name is now the name of the next image to try */
@@ -1574,6 +1567,15 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
1574 } 1567 }
1575 } 1568 }
1576 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
1577 free(name); 1579 free(name);
1578 if (ret < 0 && strstr(self->name, " (deleted)") != NULL) 1580 if (ret < 0 && strstr(self->name, " (deleted)") != NULL)
1579 return 0; 1581 return 0;
@@ -1758,9 +1760,9 @@ struct map *machine__new_module(struct machine *self, u64 start,
1758 return NULL; 1760 return NULL;
1759 1761
1760 if (machine__is_host(self)) 1762 if (machine__is_host(self))
1761 dso->origin = DSO__ORIG_KMODULE; 1763 dso->symtab_type = SYMTAB__SYSTEM_PATH_KMODULE;
1762 else 1764 else
1763 dso->origin = DSO__ORIG_GUEST_KMODULE; 1765 dso->symtab_type = SYMTAB__GUEST_KMODULE;
1764 map_groups__insert(&self->kmaps, map); 1766 map_groups__insert(&self->kmaps, map);
1765 return map; 1767 return map;
1766} 1768}
@@ -1836,12 +1838,13 @@ int dso__load_vmlinux(struct dso *self, struct map *map,
1836 int err = -1, fd; 1838 int err = -1, fd;
1837 char symfs_vmlinux[PATH_MAX]; 1839 char symfs_vmlinux[PATH_MAX];
1838 1840
1839 snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s/%s", 1841 snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s",
1840 symbol_conf.symfs, vmlinux); 1842 symbol_conf.symfs, vmlinux);
1841 fd = open(symfs_vmlinux, O_RDONLY); 1843 fd = open(symfs_vmlinux, O_RDONLY);
1842 if (fd < 0) 1844 if (fd < 0)
1843 return -1; 1845 return -1;
1844 1846
1847 dso__set_long_name(self, (char *)vmlinux);
1845 dso__set_loaded(self, map->type); 1848 dso__set_loaded(self, map->type);
1846 err = dso__load_sym(self, map, symfs_vmlinux, fd, filter, 0, 0); 1849 err = dso__load_sym(self, map, symfs_vmlinux, fd, filter, 0, 0);
1847 close(fd); 1850 close(fd);
@@ -2403,6 +2406,8 @@ int symbol__init(void)
2403 if (symbol_conf.initialized) 2406 if (symbol_conf.initialized)
2404 return 0; 2407 return 0;
2405 2408
2409 symbol_conf.priv_size = ALIGN(symbol_conf.priv_size, sizeof(u64));
2410
2406 elf_version(EV_CURRENT); 2411 elf_version(EV_CURRENT);
2407 if (symbol_conf.sort_by_name) 2412 if (symbol_conf.sort_by_name)
2408 symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - 2413 symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 670cd1c88f54..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
@@ -132,13 +137,12 @@ struct dso {
132 struct rb_root symbol_names[MAP__NR_TYPES]; 137 struct rb_root symbol_names[MAP__NR_TYPES];
133 enum dso_kernel_type kernel; 138 enum dso_kernel_type kernel;
134 u8 adjust_symbols:1; 139 u8 adjust_symbols:1;
135 u8 slen_calculated:1;
136 u8 has_build_id:1; 140 u8 has_build_id:1;
137 u8 hit:1; 141 u8 hit:1;
138 u8 annotate_warned:1; 142 u8 annotate_warned:1;
139 u8 sname_alloc:1; 143 u8 sname_alloc:1;
140 u8 lname_alloc:1; 144 u8 lname_alloc:1;
141 unsigned char origin; 145 unsigned char symtab_type;
142 u8 sorted_by_name; 146 u8 sorted_by_name;
143 u8 loaded; 147 u8 loaded;
144 u8 build_id[BUILD_ID_SIZE]; 148 u8 build_id[BUILD_ID_SIZE];
@@ -189,18 +193,18 @@ size_t dso__fprintf_buildid(struct dso *self, FILE *fp);
189size_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);
190size_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);
191 195
192enum dso_origin { 196enum symtab_type {
193 DSO__ORIG_KERNEL = 0, 197 SYMTAB__KALLSYMS = 0,
194 DSO__ORIG_GUEST_KERNEL, 198 SYMTAB__GUEST_KALLSYMS,
195 DSO__ORIG_JAVA_JIT, 199 SYMTAB__JAVA_JIT,
196 DSO__ORIG_BUILD_ID_CACHE, 200 SYMTAB__BUILD_ID_CACHE,
197 DSO__ORIG_FEDORA, 201 SYMTAB__FEDORA_DEBUGINFO,
198 DSO__ORIG_UBUNTU, 202 SYMTAB__UBUNTU_DEBUGINFO,
199 DSO__ORIG_BUILDID, 203 SYMTAB__BUILDID_DEBUGINFO,
200 DSO__ORIG_DSO, 204 SYMTAB__SYSTEM_PATH_DSO,
201 DSO__ORIG_GUEST_KMODULE, 205 SYMTAB__GUEST_KMODULE,
202 DSO__ORIG_KMODULE, 206 SYMTAB__SYSTEM_PATH_KMODULE,
203 DSO__ORIG_NOT_FOUND, 207 SYMTAB__NOT_FOUND,
204}; 208};
205 209
206char dso__symtab_origin(const struct dso *self); 210char dso__symtab_origin(const struct dso *self);
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 00f4eade2e3e..d5d3b22250f3 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -7,61 +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
19struct thread_map *thread_map__new_by_pid(pid_t pid)
20{
21 struct thread_map *threads;
22 char name[256];
23 int items;
24 struct dirent **namelist = NULL;
25 int i;
26
27 sprintf(name, "/proc/%d/task", pid);
28 items = scandir(name, &namelist, filter, NULL);
29 if (items <= 0)
30 return NULL;
31
32 threads = malloc(sizeof(*threads) + sizeof(pid_t) * items);
33 if (threads != NULL) {
34 for (i = 0; i < items; i++)
35 threads->map[i] = atoi(namelist[i]->d_name);
36 threads->nr = items;
37 }
38
39 for (i=0; i<items; i++)
40 free(namelist[i]);
41 free(namelist);
42
43 return threads;
44}
45
46struct thread_map *thread_map__new_by_tid(pid_t tid)
47{
48 struct thread_map *threads = malloc(sizeof(*threads) + sizeof(pid_t));
49
50 if (threads != NULL) {
51 threads->map[0] = tid;
52 threads->nr = 1;
53 }
54
55 return threads;
56}
57
58struct thread_map *thread_map__new(pid_t pid, pid_t tid)
59{
60 if (pid != -1)
61 return thread_map__new_by_pid(pid);
62 return thread_map__new_by_tid(tid);
63}
64
65static struct thread *thread__new(pid_t pid) 10static struct thread *thread__new(pid_t pid)
66{ 11{
67 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 d7574101054a..e5f2401c1b5e 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -18,24 +18,10 @@ struct thread {
18 int comm_len; 18 int comm_len;
19}; 19};
20 20
21struct thread_map {
22 int nr;
23 int map[];
24};
25
26struct perf_session; 21struct perf_session;
27 22
28void thread__delete(struct thread *self); 23void thread__delete(struct thread *self);
29 24
30struct thread_map *thread_map__new_by_pid(pid_t pid);
31struct thread_map *thread_map__new_by_tid(pid_t tid);
32struct thread_map *thread_map__new(pid_t pid, pid_t tid);
33
34static inline void thread_map__delete(struct thread_map *threads)
35{
36 free(threads);
37}
38
39int thread__set_comm(struct thread *self, const char *comm); 25int thread__set_comm(struct thread *self, const char *comm);
40int thread__comm_len(struct thread *self); 26int thread__comm_len(struct thread *self);
41struct 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-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 b5f12ca24d99..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;
@@ -278,8 +278,11 @@ struct scripting_ops {
278 const char *name; 278 const char *name;
279 int (*start_script) (const char *script, int argc, const char **argv); 279 int (*start_script) (const char *script, int argc, const char **argv);
280 int (*stop_script) (void); 280 int (*stop_script) (void);
281 void (*process_event) (int cpu, void *data, int size, 281 void (*process_event) (union perf_event *event,
282 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);
283 int (*generate_script) (const char *outfile); 286 int (*generate_script) (const char *outfile);
284}; 287};
285 288
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..8c17a8730e4a 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,161 @@ 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 = symbol__annotation(sym);
186 LIST_HEAD(head);
187 struct annotate_browser browser = { 260 struct annotate_browser browser = {
188 .b = { 261 .b = {
189 .entries = &head, 262 .entries = &notes->src->source,
190 .refresh = ui_browser__list_head_refresh, 263 .refresh = ui_browser__list_head_refresh,
191 .seek = ui_browser__list_head_seek, 264 .seek = ui_browser__list_head_seek,
192 .write = annotate_browser__write, 265 .write = annotate_browser__write,
193 .priv = self, 266 .priv = sym,
194 }, 267 },
195 }; 268 };
196 int ret; 269 int ret;
197 270
198 if (self->ms.sym == NULL) 271 if (sym == NULL)
199 return -1; 272 return -1;
200 273
201 if (self->ms.map->dso->annotate_warned) 274 if (map->dso->annotate_warned)
202 return -1; 275 return -1;
203 276
204 if (hist_entry__annotate(self, &head, sizeof(*rbpos)) < 0) { 277 if (symbol__annotate(sym, map, sizeof(struct objdump_line_rb_node)) < 0) {
205 ui__error_window(ui_helpline__last_msg); 278 ui__error_window(ui_helpline__last_msg);
206 return -1; 279 return -1;
207 } 280 }
208 281
209 ui_helpline__push("Press <- or ESC to exit"); 282 ui_helpline__push("Press <- or ESC to exit");
210 283
211 list_for_each_entry(pos, &head, node) { 284 list_for_each_entry(pos, &notes->src->source, node) {
285 struct objdump_line_rb_node *rbpos;
212 size_t line_len = strlen(pos->line); 286 size_t line_len = strlen(pos->line);
287
213 if (browser.b.width < line_len) 288 if (browser.b.width < line_len)
214 browser.b.width = line_len; 289 browser.b.width = line_len;
215 rbpos = objdump_line__rb(pos); 290 rbpos = objdump_line__rb(pos);
216 rbpos->idx = browser.b.nr_entries++; 291 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 } 292 }
222 293
223 /*
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 */ 294 browser.b.width += 18; /* Percentage */
231 ret = annotate_browser__run(&browser); 295 ret = annotate_browser__run(&browser, evidx, refresh);
232 list_for_each_entry_safe(pos, n, &head, node) { 296 list_for_each_entry_safe(pos, n, &notes->src->source, node) {
233 list_del(&pos->node); 297 list_del(&pos->node);
234 objdump_line__free(pos); 298 objdump_line__free(pos);
235 } 299 }
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c
index 60c463c16028..798efdca3ead 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;
@@ -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->map == 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 e5158369106e..8462bffe20bc 100644
--- a/tools/perf/util/ui/browsers/map.c
+++ b/tools/perf/util/ui/browsers/map.c
@@ -41,7 +41,7 @@ static int ui_entry__read(const char *title, char *bf, size_t size, int width)
41out_free_form: 41out_free_form:
42 newtPopWindow(); 42 newtPopWindow();
43 newtFormDestroy(form); 43 newtFormDestroy(form);
44 return 0; 44 return err;
45} 45}
46 46
47struct map_browser { 47struct map_browser {
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 7b5a8926624e..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)
@@ -118,10 +119,12 @@ void ui__warning(const char *format, ...)
118 va_list args; 119 va_list args;
119 120
120 va_start(args, format); 121 va_start(args, format);
121 if (use_browser > 0) 122 if (use_browser > 0) {
123 pthread_mutex_lock(&ui__lock);
122 newtWinMessagev((char *)warning_str, (char *)ok, 124 newtWinMessagev((char *)warning_str, (char *)ok,
123 (char *)format, args); 125 (char *)format, args);
124 else 126 pthread_mutex_unlock(&ui__lock);
127 } else
125 vfprintf(stderr, format, args); 128 vfprintf(stderr, format, args);
126 va_end(args); 129 va_end(args);
127} 130}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index e833f26f3bfc..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
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
index 4c6983de6fd9..362a0cb448db 100644
--- a/tools/power/x86/turbostat/turbostat.c
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -72,7 +72,7 @@ int need_reinitialize;
72 72
73int num_cpus; 73int num_cpus;
74 74
75typedef struct per_cpu_counters { 75struct counters {
76 unsigned long long tsc; /* per thread */ 76 unsigned long long tsc; /* per thread */
77 unsigned long long aperf; /* per thread */ 77 unsigned long long aperf; /* per thread */
78 unsigned long long mperf; /* per thread */ 78 unsigned long long mperf; /* per thread */
@@ -88,13 +88,13 @@ typedef struct per_cpu_counters {
88 int pkg; 88 int pkg;
89 int core; 89 int core;
90 int cpu; 90 int cpu;
91 struct per_cpu_counters *next; 91 struct counters *next;
92} PCC; 92};
93 93
94PCC *pcc_even; 94struct counters *cnt_even;
95PCC *pcc_odd; 95struct counters *cnt_odd;
96PCC *pcc_delta; 96struct counters *cnt_delta;
97PCC *pcc_average; 97struct counters *cnt_average;
98struct timeval tv_even; 98struct timeval tv_even;
99struct timeval tv_odd; 99struct timeval tv_odd;
100struct timeval tv_delta; 100struct timeval tv_delta;
@@ -125,7 +125,7 @@ unsigned long long get_msr(int cpu, off_t offset)
125 return msr; 125 return msr;
126} 126}
127 127
128void print_header() 128void print_header(void)
129{ 129{
130 if (show_pkg) 130 if (show_pkg)
131 fprintf(stderr, "pkg "); 131 fprintf(stderr, "pkg ");
@@ -160,39 +160,39 @@ void print_header()
160 putc('\n', stderr); 160 putc('\n', stderr);
161} 161}
162 162
163void dump_pcc(PCC *pcc) 163void dump_cnt(struct counters *cnt)
164{ 164{
165 fprintf(stderr, "package: %d ", pcc->pkg); 165 fprintf(stderr, "package: %d ", cnt->pkg);
166 fprintf(stderr, "core:: %d ", pcc->core); 166 fprintf(stderr, "core:: %d ", cnt->core);
167 fprintf(stderr, "CPU: %d ", pcc->cpu); 167 fprintf(stderr, "CPU: %d ", cnt->cpu);
168 fprintf(stderr, "TSC: %016llX\n", pcc->tsc); 168 fprintf(stderr, "TSC: %016llX\n", cnt->tsc);
169 fprintf(stderr, "c3: %016llX\n", pcc->c3); 169 fprintf(stderr, "c3: %016llX\n", cnt->c3);
170 fprintf(stderr, "c6: %016llX\n", pcc->c6); 170 fprintf(stderr, "c6: %016llX\n", cnt->c6);
171 fprintf(stderr, "c7: %016llX\n", pcc->c7); 171 fprintf(stderr, "c7: %016llX\n", cnt->c7);
172 fprintf(stderr, "aperf: %016llX\n", pcc->aperf); 172 fprintf(stderr, "aperf: %016llX\n", cnt->aperf);
173 fprintf(stderr, "pc2: %016llX\n", pcc->pc2); 173 fprintf(stderr, "pc2: %016llX\n", cnt->pc2);
174 fprintf(stderr, "pc3: %016llX\n", pcc->pc3); 174 fprintf(stderr, "pc3: %016llX\n", cnt->pc3);
175 fprintf(stderr, "pc6: %016llX\n", pcc->pc6); 175 fprintf(stderr, "pc6: %016llX\n", cnt->pc6);
176 fprintf(stderr, "pc7: %016llX\n", pcc->pc7); 176 fprintf(stderr, "pc7: %016llX\n", cnt->pc7);
177 fprintf(stderr, "msr0x%x: %016llX\n", extra_msr_offset, pcc->extra_msr); 177 fprintf(stderr, "msr0x%x: %016llX\n", extra_msr_offset, cnt->extra_msr);
178} 178}
179 179
180void dump_list(PCC *pcc) 180void dump_list(struct counters *cnt)
181{ 181{
182 printf("dump_list 0x%p\n", pcc); 182 printf("dump_list 0x%p\n", cnt);
183 183
184 for (; pcc; pcc = pcc->next) 184 for (; cnt; cnt = cnt->next)
185 dump_pcc(pcc); 185 dump_cnt(cnt);
186} 186}
187 187
188void print_pcc(PCC *p) 188void print_cnt(struct counters *p)
189{ 189{
190 double interval_float; 190 double interval_float;
191 191
192 interval_float = tv_delta.tv_sec + tv_delta.tv_usec/1000000.0; 192 interval_float = tv_delta.tv_sec + tv_delta.tv_usec/1000000.0;
193 193
194 /* topology columns, print blanks on 1st (average) line */ 194 /* topology columns, print blanks on 1st (average) line */
195 if (p == pcc_average) { 195 if (p == cnt_average) {
196 if (show_pkg) 196 if (show_pkg)
197 fprintf(stderr, " "); 197 fprintf(stderr, " ");
198 if (show_core) 198 if (show_core)
@@ -262,24 +262,24 @@ void print_pcc(PCC *p)
262 putc('\n', stderr); 262 putc('\n', stderr);
263} 263}
264 264
265void print_counters(PCC *cnt) 265void print_counters(struct counters *counters)
266{ 266{
267 PCC *pcc; 267 struct counters *cnt;
268 268
269 print_header(); 269 print_header();
270 270
271 if (num_cpus > 1) 271 if (num_cpus > 1)
272 print_pcc(pcc_average); 272 print_cnt(cnt_average);
273 273
274 for (pcc = cnt; pcc != NULL; pcc = pcc->next) 274 for (cnt = counters; cnt != NULL; cnt = cnt->next)
275 print_pcc(pcc); 275 print_cnt(cnt);
276 276
277} 277}
278 278
279#define SUBTRACT_COUNTER(after, before, delta) (delta = (after - before), (before > after)) 279#define SUBTRACT_COUNTER(after, before, delta) (delta = (after - before), (before > after))
280 280
281 281int compute_delta(struct counters *after,
282int compute_delta(PCC *after, PCC *before, PCC *delta) 282 struct counters *before, struct counters *delta)
283{ 283{
284 int errors = 0; 284 int errors = 0;
285 int perf_err = 0; 285 int perf_err = 0;
@@ -391,20 +391,20 @@ int compute_delta(PCC *after, PCC *before, PCC *delta)
391 delta->extra_msr = after->extra_msr; 391 delta->extra_msr = after->extra_msr;
392 if (errors) { 392 if (errors) {
393 fprintf(stderr, "ERROR cpu%d before:\n", before->cpu); 393 fprintf(stderr, "ERROR cpu%d before:\n", before->cpu);
394 dump_pcc(before); 394 dump_cnt(before);
395 fprintf(stderr, "ERROR cpu%d after:\n", before->cpu); 395 fprintf(stderr, "ERROR cpu%d after:\n", before->cpu);
396 dump_pcc(after); 396 dump_cnt(after);
397 errors = 0; 397 errors = 0;
398 } 398 }
399 } 399 }
400 return 0; 400 return 0;
401} 401}
402 402
403void compute_average(PCC *delta, PCC *avg) 403void compute_average(struct counters *delta, struct counters *avg)
404{ 404{
405 PCC *sum; 405 struct counters *sum;
406 406
407 sum = calloc(1, sizeof(PCC)); 407 sum = calloc(1, sizeof(struct counters));
408 if (sum == NULL) { 408 if (sum == NULL) {
409 perror("calloc sum"); 409 perror("calloc sum");
410 exit(1); 410 exit(1);
@@ -438,35 +438,34 @@ void compute_average(PCC *delta, PCC *avg)
438 free(sum); 438 free(sum);
439} 439}
440 440
441void get_counters(PCC *pcc) 441void get_counters(struct counters *cnt)
442{ 442{
443 for ( ; pcc; pcc = pcc->next) { 443 for ( ; cnt; cnt = cnt->next) {
444 pcc->tsc = get_msr(pcc->cpu, MSR_TSC); 444 cnt->tsc = get_msr(cnt->cpu, MSR_TSC);
445 if (do_nhm_cstates) 445 if (do_nhm_cstates)
446 pcc->c3 = get_msr(pcc->cpu, MSR_CORE_C3_RESIDENCY); 446 cnt->c3 = get_msr(cnt->cpu, MSR_CORE_C3_RESIDENCY);
447 if (do_nhm_cstates) 447 if (do_nhm_cstates)
448 pcc->c6 = get_msr(pcc->cpu, MSR_CORE_C6_RESIDENCY); 448 cnt->c6 = get_msr(cnt->cpu, MSR_CORE_C6_RESIDENCY);
449 if (do_snb_cstates) 449 if (do_snb_cstates)
450 pcc->c7 = get_msr(pcc->cpu, MSR_CORE_C7_RESIDENCY); 450 cnt->c7 = get_msr(cnt->cpu, MSR_CORE_C7_RESIDENCY);
451 if (has_aperf) 451 if (has_aperf)
452 pcc->aperf = get_msr(pcc->cpu, MSR_APERF); 452 cnt->aperf = get_msr(cnt->cpu, MSR_APERF);
453 if (has_aperf) 453 if (has_aperf)
454 pcc->mperf = get_msr(pcc->cpu, MSR_MPERF); 454 cnt->mperf = get_msr(cnt->cpu, MSR_MPERF);
455 if (do_snb_cstates) 455 if (do_snb_cstates)
456 pcc->pc2 = get_msr(pcc->cpu, MSR_PKG_C2_RESIDENCY); 456 cnt->pc2 = get_msr(cnt->cpu, MSR_PKG_C2_RESIDENCY);
457 if (do_nhm_cstates) 457 if (do_nhm_cstates)
458 pcc->pc3 = get_msr(pcc->cpu, MSR_PKG_C3_RESIDENCY); 458 cnt->pc3 = get_msr(cnt->cpu, MSR_PKG_C3_RESIDENCY);
459 if (do_nhm_cstates) 459 if (do_nhm_cstates)
460 pcc->pc6 = get_msr(pcc->cpu, MSR_PKG_C6_RESIDENCY); 460 cnt->pc6 = get_msr(cnt->cpu, MSR_PKG_C6_RESIDENCY);
461 if (do_snb_cstates) 461 if (do_snb_cstates)
462 pcc->pc7 = get_msr(pcc->cpu, MSR_PKG_C7_RESIDENCY); 462 cnt->pc7 = get_msr(cnt->cpu, MSR_PKG_C7_RESIDENCY);
463 if (extra_msr_offset) 463 if (extra_msr_offset)
464 pcc->extra_msr = get_msr(pcc->cpu, extra_msr_offset); 464 cnt->extra_msr = get_msr(cnt->cpu, extra_msr_offset);
465 } 465 }
466} 466}
467 467
468 468void print_nehalem_info(void)
469void print_nehalem_info()
470{ 469{
471 unsigned long long msr; 470 unsigned long long msr;
472 unsigned int ratio; 471 unsigned int ratio;
@@ -514,38 +513,38 @@ void print_nehalem_info()
514 513
515} 514}
516 515
517void free_counter_list(PCC *list) 516void free_counter_list(struct counters *list)
518{ 517{
519 PCC *p; 518 struct counters *p;
520 519
521 for (p = list; p; ) { 520 for (p = list; p; ) {
522 PCC *free_me; 521 struct counters *free_me;
523 522
524 free_me = p; 523 free_me = p;
525 p = p->next; 524 p = p->next;
526 free(free_me); 525 free(free_me);
527 } 526 }
528 return;
529} 527}
530 528
531void free_all_counters(void) 529void free_all_counters(void)
532{ 530{
533 free_counter_list(pcc_even); 531 free_counter_list(cnt_even);
534 pcc_even = NULL; 532 cnt_even = NULL;
535 533
536 free_counter_list(pcc_odd); 534 free_counter_list(cnt_odd);
537 pcc_odd = NULL; 535 cnt_odd = NULL;
538 536
539 free_counter_list(pcc_delta); 537 free_counter_list(cnt_delta);
540 pcc_delta = NULL; 538 cnt_delta = NULL;
541 539
542 free_counter_list(pcc_average); 540 free_counter_list(cnt_average);
543 pcc_average = NULL; 541 cnt_average = NULL;
544} 542}
545 543
546void insert_cpu_counters(PCC **list, PCC *new) 544void insert_counters(struct counters **list,
545 struct counters *new)
547{ 546{
548 PCC *prev; 547 struct counters *prev;
549 548
550 /* 549 /*
551 * list was empty 550 * list was empty
@@ -594,18 +593,16 @@ void insert_cpu_counters(PCC **list, PCC *new)
594 */ 593 */
595 new->next = prev->next; 594 new->next = prev->next;
596 prev->next = new; 595 prev->next = new;
597
598 return;
599} 596}
600 597
601void alloc_new_cpu_counters(int pkg, int core, int cpu) 598void alloc_new_counters(int pkg, int core, int cpu)
602{ 599{
603 PCC *new; 600 struct counters *new;
604 601
605 if (verbose > 1) 602 if (verbose > 1)
606 printf("pkg%d core%d, cpu%d\n", pkg, core, cpu); 603 printf("pkg%d core%d, cpu%d\n", pkg, core, cpu);
607 604
608 new = (PCC *)calloc(1, sizeof(PCC)); 605 new = (struct counters *)calloc(1, sizeof(struct counters));
609 if (new == NULL) { 606 if (new == NULL) {
610 perror("calloc"); 607 perror("calloc");
611 exit(1); 608 exit(1);
@@ -613,9 +610,10 @@ void alloc_new_cpu_counters(int pkg, int core, int cpu)
613 new->pkg = pkg; 610 new->pkg = pkg;
614 new->core = core; 611 new->core = core;
615 new->cpu = cpu; 612 new->cpu = cpu;
616 insert_cpu_counters(&pcc_odd, new); 613 insert_counters(&cnt_odd, new);
617 614
618 new = (PCC *)calloc(1, sizeof(PCC)); 615 new = (struct counters *)calloc(1,
616 sizeof(struct counters));
619 if (new == NULL) { 617 if (new == NULL) {
620 perror("calloc"); 618 perror("calloc");
621 exit(1); 619 exit(1);
@@ -623,9 +621,9 @@ void alloc_new_cpu_counters(int pkg, int core, int cpu)
623 new->pkg = pkg; 621 new->pkg = pkg;
624 new->core = core; 622 new->core = core;
625 new->cpu = cpu; 623 new->cpu = cpu;
626 insert_cpu_counters(&pcc_even, new); 624 insert_counters(&cnt_even, new);
627 625
628 new = (PCC *)calloc(1, sizeof(PCC)); 626 new = (struct counters *)calloc(1, sizeof(struct counters));
629 if (new == NULL) { 627 if (new == NULL) {
630 perror("calloc"); 628 perror("calloc");
631 exit(1); 629 exit(1);
@@ -633,9 +631,9 @@ void alloc_new_cpu_counters(int pkg, int core, int cpu)
633 new->pkg = pkg; 631 new->pkg = pkg;
634 new->core = core; 632 new->core = core;
635 new->cpu = cpu; 633 new->cpu = cpu;
636 insert_cpu_counters(&pcc_delta, new); 634 insert_counters(&cnt_delta, new);
637 635
638 new = (PCC *)calloc(1, sizeof(PCC)); 636 new = (struct counters *)calloc(1, sizeof(struct counters));
639 if (new == NULL) { 637 if (new == NULL) {
640 perror("calloc"); 638 perror("calloc");
641 exit(1); 639 exit(1);
@@ -643,7 +641,7 @@ void alloc_new_cpu_counters(int pkg, int core, int cpu)
643 new->pkg = pkg; 641 new->pkg = pkg;
644 new->core = core; 642 new->core = core;
645 new->cpu = cpu; 643 new->cpu = cpu;
646 pcc_average = new; 644 cnt_average = new;
647} 645}
648 646
649int get_physical_package_id(int cpu) 647int get_physical_package_id(int cpu)
@@ -719,7 +717,7 @@ void re_initialize(void)
719{ 717{
720 printf("turbostat: topology changed, re-initializing.\n"); 718 printf("turbostat: topology changed, re-initializing.\n");
721 free_all_counters(); 719 free_all_counters();
722 num_cpus = for_all_cpus(alloc_new_cpu_counters); 720 num_cpus = for_all_cpus(alloc_new_counters);
723 need_reinitialize = 0; 721 need_reinitialize = 0;
724 printf("num_cpus is now %d\n", num_cpus); 722 printf("num_cpus is now %d\n", num_cpus);
725} 723}
@@ -728,7 +726,7 @@ void dummy(int pkg, int core, int cpu) { return; }
728/* 726/*
729 * check to see if a cpu came on-line 727 * check to see if a cpu came on-line
730 */ 728 */
731void verify_num_cpus() 729void verify_num_cpus(void)
732{ 730{
733 int new_num_cpus; 731 int new_num_cpus;
734 732
@@ -740,14 +738,12 @@ void verify_num_cpus()
740 num_cpus, new_num_cpus); 738 num_cpus, new_num_cpus);
741 need_reinitialize = 1; 739 need_reinitialize = 1;
742 } 740 }
743
744 return;
745} 741}
746 742
747void turbostat_loop() 743void turbostat_loop()
748{ 744{
749restart: 745restart:
750 get_counters(pcc_even); 746 get_counters(cnt_even);
751 gettimeofday(&tv_even, (struct timezone *)NULL); 747 gettimeofday(&tv_even, (struct timezone *)NULL);
752 748
753 while (1) { 749 while (1) {
@@ -757,24 +753,24 @@ restart:
757 goto restart; 753 goto restart;
758 } 754 }
759 sleep(interval_sec); 755 sleep(interval_sec);
760 get_counters(pcc_odd); 756 get_counters(cnt_odd);
761 gettimeofday(&tv_odd, (struct timezone *)NULL); 757 gettimeofday(&tv_odd, (struct timezone *)NULL);
762 758
763 compute_delta(pcc_odd, pcc_even, pcc_delta); 759 compute_delta(cnt_odd, cnt_even, cnt_delta);
764 timersub(&tv_odd, &tv_even, &tv_delta); 760 timersub(&tv_odd, &tv_even, &tv_delta);
765 compute_average(pcc_delta, pcc_average); 761 compute_average(cnt_delta, cnt_average);
766 print_counters(pcc_delta); 762 print_counters(cnt_delta);
767 if (need_reinitialize) { 763 if (need_reinitialize) {
768 re_initialize(); 764 re_initialize();
769 goto restart; 765 goto restart;
770 } 766 }
771 sleep(interval_sec); 767 sleep(interval_sec);
772 get_counters(pcc_even); 768 get_counters(cnt_even);
773 gettimeofday(&tv_even, (struct timezone *)NULL); 769 gettimeofday(&tv_even, (struct timezone *)NULL);
774 compute_delta(pcc_even, pcc_odd, pcc_delta); 770 compute_delta(cnt_even, cnt_odd, cnt_delta);
775 timersub(&tv_even, &tv_odd, &tv_delta); 771 timersub(&tv_even, &tv_odd, &tv_delta);
776 compute_average(pcc_delta, pcc_average); 772 compute_average(cnt_delta, cnt_average);
777 print_counters(pcc_delta); 773 print_counters(cnt_delta);
778 } 774 }
779} 775}
780 776
@@ -892,7 +888,7 @@ void check_cpuid()
892 * this check is valid for both Intel and AMD 888 * this check is valid for both Intel and AMD
893 */ 889 */
894 asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x80000007)); 890 asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x80000007));
895 has_invariant_tsc = edx && (1 << 8); 891 has_invariant_tsc = edx & (1 << 8);
896 892
897 if (!has_invariant_tsc) { 893 if (!has_invariant_tsc) {
898 fprintf(stderr, "No invariant TSC\n"); 894 fprintf(stderr, "No invariant TSC\n");
@@ -905,7 +901,7 @@ void check_cpuid()
905 */ 901 */
906 902
907 asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x6)); 903 asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x6));
908 has_aperf = ecx && (1 << 0); 904 has_aperf = ecx & (1 << 0);
909 if (!has_aperf) { 905 if (!has_aperf) {
910 fprintf(stderr, "No APERF MSR\n"); 906 fprintf(stderr, "No APERF MSR\n");
911 exit(1); 907 exit(1);
@@ -952,7 +948,7 @@ void turbostat_init()
952 check_dev_msr(); 948 check_dev_msr();
953 check_super_user(); 949 check_super_user();
954 950
955 num_cpus = for_all_cpus(alloc_new_cpu_counters); 951 num_cpus = for_all_cpus(alloc_new_counters);
956 952
957 if (verbose) 953 if (verbose)
958 print_nehalem_info(); 954 print_nehalem_info();
@@ -962,7 +958,7 @@ int fork_it(char **argv)
962{ 958{
963 int retval; 959 int retval;
964 pid_t child_pid; 960 pid_t child_pid;
965 get_counters(pcc_even); 961 get_counters(cnt_even);
966 gettimeofday(&tv_even, (struct timezone *)NULL); 962 gettimeofday(&tv_even, (struct timezone *)NULL);
967 963
968 child_pid = fork(); 964 child_pid = fork();
@@ -985,14 +981,14 @@ int fork_it(char **argv)
985 exit(1); 981 exit(1);
986 } 982 }
987 } 983 }
988 get_counters(pcc_odd); 984 get_counters(cnt_odd);
989 gettimeofday(&tv_odd, (struct timezone *)NULL); 985 gettimeofday(&tv_odd, (struct timezone *)NULL);
990 retval = compute_delta(pcc_odd, pcc_even, pcc_delta); 986 retval = compute_delta(cnt_odd, cnt_even, cnt_delta);
991 987
992 timersub(&tv_odd, &tv_even, &tv_delta); 988 timersub(&tv_odd, &tv_even, &tv_delta);
993 compute_average(pcc_delta, pcc_average); 989 compute_average(cnt_delta, cnt_average);
994 if (!retval) 990 if (!retval)
995 print_counters(pcc_delta); 991 print_counters(cnt_delta);
996 992
997 fprintf(stderr, "%.6f sec\n", tv_delta.tv_sec + tv_delta.tv_usec/1000000.0);; 993 fprintf(stderr, "%.6f sec\n", tv_delta.tv_sec + tv_delta.tv_usec/1000000.0);;
998 994
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
index d9678a34dd70..2618ef2ba31f 100644
--- 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
@@ -46,7 +46,7 @@ int cpu = -1;
46 * 46 *
47 * performance 47 * performance
48 * Performance is paramount. 48 * Performance is paramount.
49 * Unwilling to sacrafice any performance 49 * Unwilling to sacrifice any performance
50 * for the sake of energy saving. (hardware default) 50 * for the sake of energy saving. (hardware default)
51 * 51 *
52 * normal 52 * normal
diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl
index e1c62eeb88f5..8ce792ea08e9 100755
--- a/tools/testing/ktest/ktest.pl
+++ b/tools/testing/ktest/ktest.pl
@@ -1,6 +1,6 @@
1#!/usr/bin/perl -w 1#!/usr/bin/perl -w
2# 2#
3# Copywrite 2010 - Steven Rostedt <srostedt@redhat.com>, Red Hat Inc. 3# Copyright 2010 - Steven Rostedt <srostedt@redhat.com>, Red Hat Inc.
4# Licensed under the terms of the GNU GPL License version 2 4# Licensed under the terms of the GNU GPL License version 2
5# 5#
6 6
@@ -37,6 +37,8 @@ $default{"POWEROFF_ON_SUCCESS"} = 0;
37$default{"BUILD_OPTIONS"} = ""; 37$default{"BUILD_OPTIONS"} = "";
38$default{"BISECT_SLEEP_TIME"} = 60; # sleep time between bisects 38$default{"BISECT_SLEEP_TIME"} = 60; # sleep time between bisects
39$default{"CLEAR_LOG"} = 0; 39$default{"CLEAR_LOG"} = 0;
40$default{"BISECT_MANUAL"} = 0;
41$default{"BISECT_SKIP"} = 1;
40$default{"SUCCESS_LINE"} = "login:"; 42$default{"SUCCESS_LINE"} = "login:";
41$default{"BOOTED_TIMEOUT"} = 1; 43$default{"BOOTED_TIMEOUT"} = 1;
42$default{"DIE_ON_FAILURE"} = 1; 44$default{"DIE_ON_FAILURE"} = 1;
@@ -45,6 +47,7 @@ $default{"SCP_TO_TARGET"} = "scp \$SRC_FILE \$SSH_USER\@\$MACHINE:\$DST_FILE";
45$default{"REBOOT"} = "ssh \$SSH_USER\@\$MACHINE reboot"; 47$default{"REBOOT"} = "ssh \$SSH_USER\@\$MACHINE reboot";
46$default{"STOP_AFTER_SUCCESS"} = 10; 48$default{"STOP_AFTER_SUCCESS"} = 10;
47$default{"STOP_AFTER_FAILURE"} = 60; 49$default{"STOP_AFTER_FAILURE"} = 60;
50$default{"STOP_TEST_AFTER"} = 600;
48$default{"LOCALVERSION"} = "-test"; 51$default{"LOCALVERSION"} = "-test";
49 52
50my $ktest_config; 53my $ktest_config;
@@ -81,6 +84,8 @@ my $addconfig;
81my $in_bisect = 0; 84my $in_bisect = 0;
82my $bisect_bad = ""; 85my $bisect_bad = "";
83my $reverse_bisect; 86my $reverse_bisect;
87my $bisect_manual;
88my $bisect_skip;
84my $in_patchcheck = 0; 89my $in_patchcheck = 0;
85my $run_test; 90my $run_test;
86my $redirect; 91my $redirect;
@@ -98,6 +103,7 @@ my $console;
98my $success_line; 103my $success_line;
99my $stop_after_success; 104my $stop_after_success;
100my $stop_after_failure; 105my $stop_after_failure;
106my $stop_test_after;
101my $build_target; 107my $build_target;
102my $target_image; 108my $target_image;
103my $localversion; 109my $localversion;
@@ -462,6 +468,10 @@ sub dodie {
462 `$power_off`; 468 `$power_off`;
463 } 469 }
464 470
471 if (defined($opt{"LOG_FILE"})) {
472 print " See $opt{LOG_FILE} for more info.\n";
473 }
474
465 die @_, "\n"; 475 die @_, "\n";
466} 476}
467 477
@@ -760,8 +770,10 @@ sub monitor {
760 770
761 my $success_start; 771 my $success_start;
762 my $failure_start; 772 my $failure_start;
773 my $monitor_start = time;
774 my $done = 0;
763 775
764 for (;;) { 776 while (!$done) {
765 777
766 if ($booted) { 778 if ($booted) {
767 $line = wait_for_input($monitor_fp, $booted_timeout); 779 $line = wait_for_input($monitor_fp, $booted_timeout);
@@ -796,7 +808,7 @@ sub monitor {
796 } 808 }
797 809
798 if ($full_line =~ /call trace:/i) { 810 if ($full_line =~ /call trace:/i) {
799 if (!$skip_call_trace) { 811 if (!$bug && !$skip_call_trace) {
800 $bug = 1; 812 $bug = 1;
801 $failure_start = time; 813 $failure_start = time;
802 } 814 }
@@ -816,12 +828,19 @@ sub monitor {
816 } 828 }
817 829
818 if ($full_line =~ /Kernel panic -/) { 830 if ($full_line =~ /Kernel panic -/) {
831 $failure_start = time;
819 $bug = 1; 832 $bug = 1;
820 } 833 }
821 834
822 if ($line =~ /\n/) { 835 if ($line =~ /\n/) {
823 $full_line = ""; 836 $full_line = "";
824 } 837 }
838
839 if ($stop_test_after > 0 && !$booted && !$bug) {
840 if (time - $monitor_start > $stop_test_after) {
841 $done = 1;
842 }
843 }
825 } 844 }
826 845
827 close(DMESG); 846 close(DMESG);
@@ -925,6 +944,18 @@ sub check_buildlog {
925 return 1; 944 return 1;
926} 945}
927 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
928sub build { 959sub build {
929 my ($type) = @_; 960 my ($type) = @_;
930 my $defconfig = ""; 961 my $defconfig = "";
@@ -970,8 +1001,12 @@ sub build {
970 $defconfig = "KCONFIG_ALLCONFIG=$minconfig"; 1001 $defconfig = "KCONFIG_ALLCONFIG=$minconfig";
971 } 1002 }
972 1003
973 run_command "$defconfig $make $type" or 1004 if ($type eq "oldnoconfig") {
974 dodie "failed make config"; 1005 make_oldconfig $defconfig;
1006 } else {
1007 run_command "$defconfig $make $type" or
1008 dodie "failed make config";
1009 }
975 1010
976 $redirect = "$buildlog"; 1011 $redirect = "$buildlog";
977 if (!run_command "$make $build_options") { 1012 if (!run_command "$make $build_options") {
@@ -1025,6 +1060,21 @@ sub get_version {
1025 doprint "$version\n"; 1060 doprint "$version\n";
1026} 1061}
1027 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
1028sub child_run_test { 1078sub child_run_test {
1029 my $failed = 0; 1079 my $failed = 0;
1030 1080
@@ -1070,6 +1120,7 @@ sub do_run_test {
1070 1120
1071 # we are not guaranteed to get a full line 1121 # we are not guaranteed to get a full line
1072 $full_line .= $line; 1122 $full_line .= $line;
1123 doprint $line;
1073 1124
1074 if ($full_line =~ /call trace:/i) { 1125 if ($full_line =~ /call trace:/i) {
1075 $bug = 1; 1126 $bug = 1;
@@ -1086,6 +1137,19 @@ sub do_run_test {
1086 } while (!$child_done && !$bug); 1137 } while (!$child_done && !$bug);
1087 1138
1088 if ($bug) { 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
1089 doprint "Detected kernel crash!\n"; 1153 doprint "Detected kernel crash!\n";
1090 # kill the child with extreme prejudice 1154 # kill the child with extreme prejudice
1091 kill 9, $child_pid; 1155 kill 9, $child_pid;
@@ -1131,7 +1195,15 @@ sub run_git_bisect {
1131 return 1; 1195 return 1;
1132} 1196}
1133 1197
1134# returns 1 on success, 0 on failure 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
1135sub run_bisect_test { 1207sub run_bisect_test {
1136 my ($type, $buildtype) = @_; 1208 my ($type, $buildtype) = @_;
1137 1209
@@ -1145,6 +1217,10 @@ sub run_bisect_test {
1145 build $buildtype or $failed = 1; 1217 build $buildtype or $failed = 1;
1146 1218
1147 if ($type ne "build") { 1219 if ($type ne "build") {
1220 if ($failed && $bisect_skip) {
1221 $in_bisect = 0;
1222 return -1;
1223 }
1148 dodie "Failed on build" if $failed; 1224 dodie "Failed on build" if $failed;
1149 1225
1150 # Now boot the box 1226 # Now boot the box
@@ -1156,6 +1232,12 @@ sub run_bisect_test {
1156 monitor or $failed = 1; 1232 monitor or $failed = 1;
1157 1233
1158 if ($type ne "boot") { 1234 if ($type ne "boot") {
1235 if ($failed && $bisect_skip) {
1236 end_monitor;
1237 bisect_reboot;
1238 $in_bisect = 0;
1239 return -1;
1240 }
1159 dodie "Failed on boot" if $failed; 1241 dodie "Failed on boot" if $failed;
1160 1242
1161 do_run_test or $failed = 1; 1243 do_run_test or $failed = 1;
@@ -1168,11 +1250,7 @@ sub run_bisect_test {
1168 1250
1169 # reboot the box to a good kernel 1251 # reboot the box to a good kernel
1170 if ($type ne "build") { 1252 if ($type ne "build") {
1171 doprint "Reboot and sleep $bisect_sleep_time seconds\n"; 1253 bisect_reboot;
1172 reboot;
1173 start_monitor;
1174 wait_for_monitor $bisect_sleep_time;
1175 end_monitor;
1176 } 1254 }
1177 } else { 1255 } else {
1178 $result = 1; 1256 $result = 1;
@@ -1193,16 +1271,22 @@ sub run_bisect {
1193 1271
1194 my $ret = run_bisect_test $type, $buildtype; 1272 my $ret = run_bisect_test $type, $buildtype;
1195 1273
1274 if ($bisect_manual) {
1275 $ret = answer_bisect;
1276 }
1196 1277
1197 # Are we looking for where it worked, not failed? 1278 # Are we looking for where it worked, not failed?
1198 if ($reverse_bisect) { 1279 if ($reverse_bisect) {
1199 $ret = !$ret; 1280 $ret = !$ret;
1200 } 1281 }
1201 1282
1202 if ($ret) { 1283 if ($ret > 0) {
1203 return "good"; 1284 return "good";
1204 } else { 1285 } elsif ($ret == 0) {
1205 return "bad"; 1286 return "bad";
1287 } elsif ($bisect_skip) {
1288 doprint "HIT A BAD COMMIT ... SKIPPING\n";
1289 return "skip";
1206 } 1290 }
1207} 1291}
1208 1292
@@ -1220,6 +1304,13 @@ sub bisect {
1220 my $type = $opt{"BISECT_TYPE[$i]"}; 1304 my $type = $opt{"BISECT_TYPE[$i]"};
1221 my $start = $opt{"BISECT_START[$i]"}; 1305 my $start = $opt{"BISECT_START[$i]"};
1222 my $replay = $opt{"BISECT_REPLAY[$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 }
1223 1314
1224 # convert to true sha1's 1315 # convert to true sha1's
1225 $good = get_sha1($good); 1316 $good = get_sha1($good);
@@ -1273,7 +1364,7 @@ sub bisect {
1273 die "Failed to checkout $head"; 1364 die "Failed to checkout $head";
1274 } 1365 }
1275 1366
1276 run_command "git bisect start" or 1367 run_command "git bisect start$start_files" or
1277 dodie "could not start bisect"; 1368 dodie "could not start bisect";
1278 1369
1279 run_command "git bisect good $good" or 1370 run_command "git bisect good $good" or
@@ -1390,9 +1481,7 @@ sub create_config {
1390 close(OUT); 1481 close(OUT);
1391 1482
1392# exit; 1483# exit;
1393 run_command "$make oldnoconfig" or 1484 make_oldconfig "";
1394 dodie "failed make config oldconfig";
1395
1396} 1485}
1397 1486
1398sub compare_configs { 1487sub compare_configs {
@@ -1505,7 +1594,9 @@ sub run_config_bisect {
1505 } 1594 }
1506 1595
1507 $ret = run_config_bisect_test $type; 1596 $ret = run_config_bisect_test $type;
1508 1597 if ($bisect_manual) {
1598 $ret = answer_bisect;
1599 }
1509 if ($ret) { 1600 if ($ret) {
1510 process_passed %current_config; 1601 process_passed %current_config;
1511 return 0; 1602 return 0;
@@ -1536,7 +1627,13 @@ sub run_config_bisect {
1536 $half = int($#start_list / 2); 1627 $half = int($#start_list / 2);
1537 } while ($half > 0); 1628 } while ($half > 0);
1538 1629
1539 # we found a single config, try it again 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
1540 my @tophalf = @start_list[0 .. 0]; 1637 my @tophalf = @start_list[0 .. 0];
1541 1638
1542 $ret = run_config_bisect_test $type; 1639 $ret = run_config_bisect_test $type;
@@ -1594,8 +1691,7 @@ sub config_bisect {
1594 close(IN); 1691 close(IN);
1595 1692
1596 # Now run oldconfig with the minconfig (and addconfigs) 1693 # Now run oldconfig with the minconfig (and addconfigs)
1597 run_command "$defconfig $make oldnoconfig" or 1694 make_oldconfig $defconfig;
1598 dodie "failed make config oldconfig";
1599 1695
1600 # check to see what we lost (or gained) 1696 # check to see what we lost (or gained)
1601 open (IN, $output_config) 1697 open (IN, $output_config)
@@ -1907,6 +2003,8 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
1907 $poweroff_after_halt = set_test_option("POWEROFF_AFTER_HALT", $i); 2003 $poweroff_after_halt = set_test_option("POWEROFF_AFTER_HALT", $i);
1908 $sleep_time = set_test_option("SLEEP_TIME", $i); 2004 $sleep_time = set_test_option("SLEEP_TIME", $i);
1909 $bisect_sleep_time = set_test_option("BISECT_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);
1910 $store_failures = set_test_option("STORE_FAILURES", $i); 2008 $store_failures = set_test_option("STORE_FAILURES", $i);
1911 $timeout = set_test_option("TIMEOUT", $i); 2009 $timeout = set_test_option("TIMEOUT", $i);
1912 $booted_timeout = set_test_option("BOOTED_TIMEOUT", $i); 2010 $booted_timeout = set_test_option("BOOTED_TIMEOUT", $i);
@@ -1914,6 +2012,7 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
1914 $success_line = set_test_option("SUCCESS_LINE", $i); 2012 $success_line = set_test_option("SUCCESS_LINE", $i);
1915 $stop_after_success = set_test_option("STOP_AFTER_SUCCESS", $i); 2013 $stop_after_success = set_test_option("STOP_AFTER_SUCCESS", $i);
1916 $stop_after_failure = set_test_option("STOP_AFTER_FAILURE", $i); 2014 $stop_after_failure = set_test_option("STOP_AFTER_FAILURE", $i);
2015 $stop_test_after = set_test_option("STOP_TEST_AFTER", $i);
1917 $build_target = set_test_option("BUILD_TARGET", $i); 2016 $build_target = set_test_option("BUILD_TARGET", $i);
1918 $ssh_exec = set_test_option("SSH_EXEC", $i); 2017 $ssh_exec = set_test_option("SSH_EXEC", $i);
1919 $scp_to_target = set_test_option("SCP_TO_TARGET", $i); 2018 $scp_to_target = set_test_option("SCP_TO_TARGET", $i);
diff --git a/tools/testing/ktest/sample.conf b/tools/testing/ktest/sample.conf
index 3408c594b2de..4c5d6bd74a02 100644
--- a/tools/testing/ktest/sample.conf
+++ b/tools/testing/ktest/sample.conf
@@ -306,6 +306,14 @@
306# (default 60) 306# (default 60)
307#STOP_AFTER_FAILURE = 60 307#STOP_AFTER_FAILURE = 60
308 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
309# Stop testing if a build fails. If set, the script will end if 317# Stop testing if a build fails. If set, the script will end if
310# a failure is detected, otherwise it will save off the .config, 318# a failure is detected, otherwise it will save off the .config,
311# dmesg and bootlog in a directory called 319# dmesg and bootlog in a directory called
@@ -519,6 +527,24 @@
519# git bisect good, git bisect bad, and running the git bisect replay 527# git bisect good, git bisect bad, and running the git bisect replay
520# if the BISECT_REPLAY is set. 528# if the BISECT_REPLAY is set.
521# 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#
522# BISECT_REVERSE = 1 (optional, default 0) 548# BISECT_REVERSE = 1 (optional, default 0)
523# 549#
524# In those strange instances where it was broken forever 550# In those strange instances where it was broken forever
@@ -528,6 +554,15 @@
528# With BISECT_REVERSE = 1, The test will consider failures as 554# With BISECT_REVERSE = 1, The test will consider failures as
529# good, and success as bad. 555# good, and success as bad.
530# 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#
531# BISECT_CHECK = 1 (optional, default 0) 566# BISECT_CHECK = 1 (optional, default 0)
532# 567#
533# Just to be sure the good is good and bad is bad, setting 568# Just to be sure the good is good and bad is bad, setting
@@ -613,10 +648,17 @@
613# 648#
614# CONFIG_BISECT is the config that failed to boot 649# CONFIG_BISECT is the config that failed to boot
615# 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#
616# Example: 657# Example:
617# TEST_START 658# TEST_START
618# TEST_TYPE = config_bisect 659# TEST_TYPE = config_bisect
619# CONFIG_BISECT_TYPE = build 660# CONFIG_BISECT_TYPE = build
620# CONFIG_BISECT = /home/test/¢onfig-bad 661# CONFIG_BISECT = /home/test/¢onfig-bad
621# MIN_CONFIG = /home/test/config-min 662# MIN_CONFIG = /home/test/config-min
663# BISECT_MANUAL = 1
622# 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