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/Makefile659
-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.c15
-rw-r--r--tools/perf/builtin-list.c43
-rw-r--r--tools/perf/builtin-lock.c29
-rw-r--r--tools/perf/builtin-probe.c70
-rw-r--r--tools/perf/builtin-record.c452
-rw-r--r--tools/perf/builtin-report.c218
-rw-r--r--tools/perf/builtin-sched.c48
-rw-r--r--tools/perf/builtin-script.c312
-rw-r--r--tools/perf/builtin-stat.c130
-rw-r--r--tools/perf/builtin-test.c238
-rw-r--r--tools/perf/builtin-timechart.c30
-rw-r--r--tools/perf/builtin-top.c1038
-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.c2
-rw-r--r--tools/perf/util/debug.h2
-rw-r--r--tools/perf/util/event.c389
-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.c603
-rw-r--r--tools/perf/util/header.h95
-rw-r--r--tools/perf/util/hist.c258
-rw-r--r--tools/perf/util/hist.h61
-rw-r--r--tools/perf/util/include/linux/bitops.h1
-rw-r--r--tools/perf/util/include/linux/list.h1
-rw-r--r--tools/perf/util/map.c3
-rw-r--r--tools/perf/util/parse-events.c199
-rw-r--r--tools/perf/util/parse-events.h15
-rw-r--r--tools/perf/util/probe-event.c161
-rw-r--r--tools/perf/util/probe-event.h4
-rw-r--r--tools/perf/util/probe-finder.c533
-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.c378
-rw-r--r--tools/perf/util/session.h52
-rw-r--r--tools/perf/util/setup.py19
-rw-r--r--tools/perf/util/strfilter.c199
-rw-r--r--tools/perf/util/strfilter.h48
-rw-r--r--tools/perf/util/svghelper.c15
-rw-r--r--tools/perf/util/symbol.c108
-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/types.h10
-rw-r--r--tools/perf/util/ui/browser.c25
-rw-r--r--tools/perf/util/ui/browser.h3
-rw-r--r--tools/perf/util/ui/browsers/annotate.c178
-rw-r--r--tools/perf/util/ui/browsers/hists.c199
-rw-r--r--tools/perf/util/ui/browsers/map.c7
-rw-r--r--tools/perf/util/ui/browsers/top.c213
-rw-r--r--tools/perf/util/ui/helpline.c5
-rw-r--r--tools/perf/util/ui/libslang.h6
-rw-r--r--tools/perf/util/ui/setup.c8
-rw-r--r--tools/perf/util/ui/ui.h8
-rw-r--r--tools/perf/util/ui/util.c7
-rw-r--r--tools/perf/util/util.h26
-rw-r--r--tools/perf/util/values.c10
-rw-r--r--tools/power/x86/turbostat/turbostat.c200
-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
104 files changed, 7796 insertions, 4362 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 2b5387d53ba5..158c30e8210c 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#
@@ -204,13 +57,11 @@ EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wshadow
204EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Winit-self 57EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Winit-self
205EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wpacked 58EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wpacked
206EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wredundant-decls 59EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wredundant-decls
207EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstack-protector
208EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-aliasing=3 60EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-aliasing=3
209EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wswitch-default 61EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wswitch-default
210EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wswitch-enum 62EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wswitch-enum
211EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wno-system-headers 63EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wno-system-headers
212EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wundef 64EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wundef
213EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wvolatile-register-var
214EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wwrite-strings 65EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wwrite-strings
215EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wbad-function-cast 66EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wbad-function-cast
216EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wmissing-declarations 67EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wmissing-declarations
@@ -272,28 +123,26 @@ CC = $(CROSS_COMPILE)gcc
272AR = $(CROSS_COMPILE)ar 123AR = $(CROSS_COMPILE)ar
273RM = rm -f 124RM = rm -f
274MKDIR = mkdir 125MKDIR = mkdir
275TAR = tar
276FIND = find 126FIND = find
277INSTALL = install 127INSTALL = install
278RPMBUILD = rpmbuild
279PTHREAD_LIBS = -lpthread
280 128
281# 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
282# explicitly what architecture to check for. Fix this up for yours.. 130# explicitly what architecture to check for. Fix this up for yours..
283SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__ 131SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
284 132
285ifeq ($(V), 2)
286 QUIET_STDERR = ">/dev/null"
287else
288 QUIET_STDERR = ">/dev/null 2>&1"
289endif
290
291-include feature-tests.mak 133-include feature-tests.mak
292 134
293ifeq ($(call try-cc,$(SOURCE_HELLO),-Werror -fstack-protector-all),y) 135ifeq ($(call try-cc,$(SOURCE_HELLO),-Werror -fstack-protector-all),y)
294 CFLAGS := $(CFLAGS) -fstack-protector-all 136 CFLAGS := $(CFLAGS) -fstack-protector-all
295endif 137endif
296 138
139ifeq ($(call try-cc,$(SOURCE_HELLO),-Werror -Wstack-protector),y)
140 CFLAGS := $(CFLAGS) -Wstack-protector
141endif
142
143ifeq ($(call try-cc,$(SOURCE_HELLO),-Werror -Wvolatile-register-var),y)
144 CFLAGS := $(CFLAGS) -Wvolatile-register-var
145endif
297 146
298### --- END CONFIGURATION SECTION --- 147### --- END CONFIGURATION SECTION ---
299 148
@@ -305,49 +154,37 @@ BASIC_LDFLAGS =
305 154
306# Guard against environment variables 155# Guard against environment variables
307BUILTIN_OBJS = 156BUILTIN_OBJS =
308BUILT_INS =
309COMPAT_CFLAGS =
310COMPAT_OBJS =
311LIB_H = 157LIB_H =
312LIB_OBJS = 158LIB_OBJS =
313SCRIPT_PERL = 159PYRF_OBJS =
314SCRIPT_SH = 160SCRIPT_SH =
315TEST_PROGRAMS =
316 161
317SCRIPT_SH += perf-archive.sh 162SCRIPT_SH += perf-archive.sh
318 163
319grep-libs = $(filter -l%,$(1)) 164grep-libs = $(filter -l%,$(1))
320strip-libs = $(filter-out -l%,$(1)) 165strip-libs = $(filter-out -l%,$(1))
321 166
167$(OUTPUT)python/perf.so: $(PYRF_OBJS)
168 $(QUIET_GEN)python util/setup.py --quiet build_ext --build-lib='$(OUTPUT)python' \
169 --build-temp='$(OUTPUT)python/temp'
322# 170#
323# No Perl scripts right now: 171# No Perl scripts right now:
324# 172#
325 173
326# SCRIPT_PERL += perf-add--interactive.perl 174SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH))
327
328SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \
329 $(patsubst %.perl,%,$(SCRIPT_PERL))
330
331# Empty...
332EXTRA_PROGRAMS =
333
334# ... and all the rest that could be moved out of bindir to perfexecdir
335PROGRAMS += $(EXTRA_PROGRAMS)
336 175
337# 176#
338# Single 'perf' binary right now: 177# Single 'perf' binary right now:
339# 178#
340PROGRAMS += $(OUTPUT)perf 179PROGRAMS += $(OUTPUT)perf
341 180
342# List built-in command $C whose implementation cmd_$C() is not in 181LANG_BINDINGS =
343# builtin-$C.o but is linked in as part of some other command.
344#
345 182
346# what 'all' will build and 'install' will install, in perfexecdir 183# what 'all' will build and 'install' will install, in perfexecdir
347ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS) 184ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
348 185
349# what 'all' will build but not install in perfexecdir 186# what 'all' will build but not install in perfexecdir
350OTHER_PROGRAMS = $(OUTPUT)perf$X 187OTHER_PROGRAMS = $(OUTPUT)perf
351 188
352# Set paths to tools early so that they can be used for version tests. 189# Set paths to tools early so that they can be used for version tests.
353ifndef SHELL_PATH 190ifndef SHELL_PATH
@@ -390,6 +227,7 @@ LIB_H += util/include/dwarf-regs.h
390LIB_H += util/include/asm/dwarf2.h 227LIB_H += util/include/asm/dwarf2.h
391LIB_H += util/include/asm/cpufeature.h 228LIB_H += util/include/asm/cpufeature.h
392LIB_H += perf.h 229LIB_H += perf.h
230LIB_H += util/annotate.h
393LIB_H += util/cache.h 231LIB_H += util/cache.h
394LIB_H += util/callchain.h 232LIB_H += util/callchain.h
395LIB_H += util/build-id.h 233LIB_H += util/build-id.h
@@ -397,6 +235,7 @@ LIB_H += util/debug.h
397LIB_H += util/debugfs.h 235LIB_H += util/debugfs.h
398LIB_H += util/event.h 236LIB_H += util/event.h
399LIB_H += util/evsel.h 237LIB_H += util/evsel.h
238LIB_H += util/evlist.h
400LIB_H += util/exec_cmd.h 239LIB_H += util/exec_cmd.h
401LIB_H += util/types.h 240LIB_H += util/types.h
402LIB_H += util/levenshtein.h 241LIB_H += util/levenshtein.h
@@ -411,6 +250,7 @@ LIB_H += util/help.h
411LIB_H += util/session.h 250LIB_H += util/session.h
412LIB_H += util/strbuf.h 251LIB_H += util/strbuf.h
413LIB_H += util/strlist.h 252LIB_H += util/strlist.h
253LIB_H += util/strfilter.h
414LIB_H += util/svghelper.h 254LIB_H += util/svghelper.h
415LIB_H += util/run-command.h 255LIB_H += util/run-command.h
416LIB_H += util/sigchain.h 256LIB_H += util/sigchain.h
@@ -420,21 +260,26 @@ LIB_H += util/values.h
420LIB_H += util/sort.h 260LIB_H += util/sort.h
421LIB_H += util/hist.h 261LIB_H += util/hist.h
422LIB_H += util/thread.h 262LIB_H += util/thread.h
263LIB_H += util/thread_map.h
423LIB_H += util/trace-event.h 264LIB_H += util/trace-event.h
424LIB_H += util/probe-finder.h 265LIB_H += util/probe-finder.h
425LIB_H += util/probe-event.h 266LIB_H += util/probe-event.h
426LIB_H += util/pstack.h 267LIB_H += util/pstack.h
427LIB_H += util/cpumap.h 268LIB_H += util/cpumap.h
269LIB_H += util/top.h
428LIB_H += $(ARCH_INCLUDE) 270LIB_H += $(ARCH_INCLUDE)
271LIB_H += util/cgroup.h
429 272
430LIB_OBJS += $(OUTPUT)util/abspath.o 273LIB_OBJS += $(OUTPUT)util/abspath.o
431LIB_OBJS += $(OUTPUT)util/alias.o 274LIB_OBJS += $(OUTPUT)util/alias.o
275LIB_OBJS += $(OUTPUT)util/annotate.o
432LIB_OBJS += $(OUTPUT)util/build-id.o 276LIB_OBJS += $(OUTPUT)util/build-id.o
433LIB_OBJS += $(OUTPUT)util/config.o 277LIB_OBJS += $(OUTPUT)util/config.o
434LIB_OBJS += $(OUTPUT)util/ctype.o 278LIB_OBJS += $(OUTPUT)util/ctype.o
435LIB_OBJS += $(OUTPUT)util/debugfs.o 279LIB_OBJS += $(OUTPUT)util/debugfs.o
436LIB_OBJS += $(OUTPUT)util/environment.o 280LIB_OBJS += $(OUTPUT)util/environment.o
437LIB_OBJS += $(OUTPUT)util/event.o 281LIB_OBJS += $(OUTPUT)util/event.o
282LIB_OBJS += $(OUTPUT)util/evlist.o
438LIB_OBJS += $(OUTPUT)util/evsel.o 283LIB_OBJS += $(OUTPUT)util/evsel.o
439LIB_OBJS += $(OUTPUT)util/exec_cmd.o 284LIB_OBJS += $(OUTPUT)util/exec_cmd.o
440LIB_OBJS += $(OUTPUT)util/help.o 285LIB_OBJS += $(OUTPUT)util/help.o
@@ -450,6 +295,8 @@ LIB_OBJS += $(OUTPUT)util/quote.o
450LIB_OBJS += $(OUTPUT)util/strbuf.o 295LIB_OBJS += $(OUTPUT)util/strbuf.o
451LIB_OBJS += $(OUTPUT)util/string.o 296LIB_OBJS += $(OUTPUT)util/string.o
452LIB_OBJS += $(OUTPUT)util/strlist.o 297LIB_OBJS += $(OUTPUT)util/strlist.o
298LIB_OBJS += $(OUTPUT)util/strfilter.o
299LIB_OBJS += $(OUTPUT)util/top.o
453LIB_OBJS += $(OUTPUT)util/usage.o 300LIB_OBJS += $(OUTPUT)util/usage.o
454LIB_OBJS += $(OUTPUT)util/wrapper.o 301LIB_OBJS += $(OUTPUT)util/wrapper.o
455LIB_OBJS += $(OUTPUT)util/sigchain.o 302LIB_OBJS += $(OUTPUT)util/sigchain.o
@@ -464,6 +311,7 @@ LIB_OBJS += $(OUTPUT)util/map.o
464LIB_OBJS += $(OUTPUT)util/pstack.o 311LIB_OBJS += $(OUTPUT)util/pstack.o
465LIB_OBJS += $(OUTPUT)util/session.o 312LIB_OBJS += $(OUTPUT)util/session.o
466LIB_OBJS += $(OUTPUT)util/thread.o 313LIB_OBJS += $(OUTPUT)util/thread.o
314LIB_OBJS += $(OUTPUT)util/thread_map.o
467LIB_OBJS += $(OUTPUT)util/trace-event-parse.o 315LIB_OBJS += $(OUTPUT)util/trace-event-parse.o
468LIB_OBJS += $(OUTPUT)util/trace-event-read.o 316LIB_OBJS += $(OUTPUT)util/trace-event-read.o
469LIB_OBJS += $(OUTPUT)util/trace-event-info.o 317LIB_OBJS += $(OUTPUT)util/trace-event-info.o
@@ -475,6 +323,7 @@ LIB_OBJS += $(OUTPUT)util/probe-event.o
475LIB_OBJS += $(OUTPUT)util/util.o 323LIB_OBJS += $(OUTPUT)util/util.o
476LIB_OBJS += $(OUTPUT)util/xyarray.o 324LIB_OBJS += $(OUTPUT)util/xyarray.o
477LIB_OBJS += $(OUTPUT)util/cpumap.o 325LIB_OBJS += $(OUTPUT)util/cpumap.o
326LIB_OBJS += $(OUTPUT)util/cgroup.o
478 327
479BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o 328BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
480 329
@@ -489,6 +338,7 @@ endif
489BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o 338BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o
490 339
491BUILTIN_OBJS += $(OUTPUT)builtin-diff.o 340BUILTIN_OBJS += $(OUTPUT)builtin-diff.o
341BUILTIN_OBJS += $(OUTPUT)builtin-evlist.o
492BUILTIN_OBJS += $(OUTPUT)builtin-help.o 342BUILTIN_OBJS += $(OUTPUT)builtin-help.o
493BUILTIN_OBJS += $(OUTPUT)builtin-sched.o 343BUILTIN_OBJS += $(OUTPUT)builtin-sched.o
494BUILTIN_OBJS += $(OUTPUT)builtin-buildid-list.o 344BUILTIN_OBJS += $(OUTPUT)builtin-buildid-list.o
@@ -509,6 +359,20 @@ BUILTIN_OBJS += $(OUTPUT)builtin-inject.o
509 359
510PERFLIBS = $(LIB_FILE) 360PERFLIBS = $(LIB_FILE)
511 361
362# Files needed for the python binding, perf.so
363# pyrf is just an internal name needed for all those wrappers.
364# This has to be in sync with what is in the 'sources' variable in
365# tools/perf/util/setup.py
366
367PYRF_OBJS += $(OUTPUT)util/cpumap.o
368PYRF_OBJS += $(OUTPUT)util/ctype.o
369PYRF_OBJS += $(OUTPUT)util/evlist.o
370PYRF_OBJS += $(OUTPUT)util/evsel.o
371PYRF_OBJS += $(OUTPUT)util/python.o
372PYRF_OBJS += $(OUTPUT)util/thread_map.o
373PYRF_OBJS += $(OUTPUT)util/util.o
374PYRF_OBJS += $(OUTPUT)util/xyarray.o
375
512# 376#
513# Platform specific tweaks 377# Platform specific tweaks
514# 378#
@@ -530,22 +394,6 @@ endif # NO_DWARF
530 394
531-include arch/$(ARCH)/Makefile 395-include arch/$(ARCH)/Makefile
532 396
533ifeq ($(uname_S),Darwin)
534 ifndef NO_FINK
535 ifeq ($(shell test -d /sw/lib && echo y),y)
536 BASIC_CFLAGS += -I/sw/include
537 BASIC_LDFLAGS += -L/sw/lib
538 endif
539 endif
540 ifndef NO_DARWIN_PORTS
541 ifeq ($(shell test -d /opt/local/lib && echo y),y)
542 BASIC_CFLAGS += -I/opt/local/include
543 BASIC_LDFLAGS += -L/opt/local/lib
544 endif
545 endif
546 PTHREAD_LIBS =
547endif
548
549ifneq ($(OUTPUT),) 397ifneq ($(OUTPUT),)
550 BASIC_CFLAGS += -I$(OUTPUT) 398 BASIC_CFLAGS += -I$(OUTPUT)
551endif 399endif
@@ -590,6 +438,7 @@ else
590 LIB_OBJS += $(OUTPUT)util/ui/browsers/annotate.o 438 LIB_OBJS += $(OUTPUT)util/ui/browsers/annotate.o
591 LIB_OBJS += $(OUTPUT)util/ui/browsers/hists.o 439 LIB_OBJS += $(OUTPUT)util/ui/browsers/hists.o
592 LIB_OBJS += $(OUTPUT)util/ui/browsers/map.o 440 LIB_OBJS += $(OUTPUT)util/ui/browsers/map.o
441 LIB_OBJS += $(OUTPUT)util/ui/browsers/top.o
593 LIB_OBJS += $(OUTPUT)util/ui/helpline.o 442 LIB_OBJS += $(OUTPUT)util/ui/helpline.o
594 LIB_OBJS += $(OUTPUT)util/ui/progress.o 443 LIB_OBJS += $(OUTPUT)util/ui/progress.o
595 LIB_OBJS += $(OUTPUT)util/ui/util.o 444 LIB_OBJS += $(OUTPUT)util/ui/util.o
@@ -599,6 +448,7 @@ else
599 LIB_H += util/ui/libslang.h 448 LIB_H += util/ui/libslang.h
600 LIB_H += util/ui/progress.h 449 LIB_H += util/ui/progress.h
601 LIB_H += util/ui/util.h 450 LIB_H += util/ui/util.h
451 LIB_H += util/ui/ui.h
602 endif 452 endif
603endif 453endif
604 454
@@ -630,12 +480,14 @@ else
630 PYTHON_EMBED_CCOPTS = `python-config --cflags 2>/dev/null` 480 PYTHON_EMBED_CCOPTS = `python-config --cflags 2>/dev/null`
631 FLAGS_PYTHON_EMBED=$(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS) 481 FLAGS_PYTHON_EMBED=$(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
632 ifneq ($(call try-cc,$(SOURCE_PYTHON_EMBED),$(FLAGS_PYTHON_EMBED)),y) 482 ifneq ($(call try-cc,$(SOURCE_PYTHON_EMBED),$(FLAGS_PYTHON_EMBED)),y)
483 msg := $(warning No Python.h found, install python-dev[el] to have python support in 'perf script' and to build the python bindings)
633 BASIC_CFLAGS += -DNO_LIBPYTHON 484 BASIC_CFLAGS += -DNO_LIBPYTHON
634 else 485 else
635 ALL_LDFLAGS += $(PYTHON_EMBED_LDFLAGS) 486 ALL_LDFLAGS += $(PYTHON_EMBED_LDFLAGS)
636 EXTLIBS += $(PYTHON_EMBED_LIBADD) 487 EXTLIBS += $(PYTHON_EMBED_LIBADD)
637 LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-python.o 488 LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-python.o
638 LIB_OBJS += $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o 489 LIB_OBJS += $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o
490 LANG_BINDINGS += $(OUTPUT)python/perf.so
639 endif 491 endif
640endif 492endif
641 493
@@ -685,201 +537,13 @@ else
685 endif 537 endif
686endif 538endif
687 539
688ifndef CC_LD_DYNPATH
689 ifdef NO_R_TO_GCC_LINKER
690 # Some gcc does not accept and pass -R to the linker to specify
691 # the runtime dynamic library path.
692 CC_LD_DYNPATH = -Wl,-rpath,
693 else
694 CC_LD_DYNPATH = -R
695 endif
696endif
697
698ifdef NEEDS_SOCKET
699 EXTLIBS += -lsocket
700endif
701ifdef NEEDS_NSL
702 EXTLIBS += -lnsl
703endif
704ifdef NO_D_TYPE_IN_DIRENT
705 BASIC_CFLAGS += -DNO_D_TYPE_IN_DIRENT
706endif
707ifdef NO_D_INO_IN_DIRENT
708 BASIC_CFLAGS += -DNO_D_INO_IN_DIRENT
709endif
710ifdef NO_ST_BLOCKS_IN_STRUCT_STAT
711 BASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT
712endif
713ifdef USE_NSEC
714 BASIC_CFLAGS += -DUSE_NSEC
715endif
716ifdef USE_ST_TIMESPEC
717 BASIC_CFLAGS += -DUSE_ST_TIMESPEC
718endif
719ifdef NO_NSEC
720 BASIC_CFLAGS += -DNO_NSEC
721endif
722ifdef NO_C99_FORMAT
723 BASIC_CFLAGS += -DNO_C99_FORMAT
724endif
725ifdef SNPRINTF_RETURNS_BOGUS
726 COMPAT_CFLAGS += -DSNPRINTF_RETURNS_BOGUS
727 COMPAT_OBJS += $(OUTPUT)compat/snprintf.o
728endif
729ifdef FREAD_READS_DIRECTORIES
730 COMPAT_CFLAGS += -DFREAD_READS_DIRECTORIES
731 COMPAT_OBJS += $(OUTPUT)compat/fopen.o
732endif
733ifdef NO_SYMLINK_HEAD
734 BASIC_CFLAGS += -DNO_SYMLINK_HEAD
735endif
736ifdef NO_STRCASESTR
737 COMPAT_CFLAGS += -DNO_STRCASESTR
738 COMPAT_OBJS += $(OUTPUT)compat/strcasestr.o
739endif
740ifdef NO_STRTOUMAX
741 COMPAT_CFLAGS += -DNO_STRTOUMAX
742 COMPAT_OBJS += $(OUTPUT)compat/strtoumax.o
743endif
744ifdef NO_STRTOULL
745 COMPAT_CFLAGS += -DNO_STRTOULL
746endif
747ifdef NO_SETENV
748 COMPAT_CFLAGS += -DNO_SETENV
749 COMPAT_OBJS += $(OUTPUT)compat/setenv.o
750endif
751ifdef NO_MKDTEMP
752 COMPAT_CFLAGS += -DNO_MKDTEMP
753 COMPAT_OBJS += $(OUTPUT)compat/mkdtemp.o
754endif
755ifdef NO_UNSETENV
756 COMPAT_CFLAGS += -DNO_UNSETENV
757 COMPAT_OBJS += $(OUTPUT)compat/unsetenv.o
758endif
759ifdef NO_SYS_SELECT_H
760 BASIC_CFLAGS += -DNO_SYS_SELECT_H
761endif
762ifdef NO_MMAP
763 COMPAT_CFLAGS += -DNO_MMAP
764 COMPAT_OBJS += $(OUTPUT)compat/mmap.o
765else
766 ifdef USE_WIN32_MMAP
767 COMPAT_CFLAGS += -DUSE_WIN32_MMAP
768 COMPAT_OBJS += $(OUTPUT)compat/win32mmap.o
769 endif
770endif
771ifdef NO_PREAD
772 COMPAT_CFLAGS += -DNO_PREAD
773 COMPAT_OBJS += $(OUTPUT)compat/pread.o
774endif
775ifdef NO_FAST_WORKING_DIRECTORY
776 BASIC_CFLAGS += -DNO_FAST_WORKING_DIRECTORY
777endif
778ifdef NO_TRUSTABLE_FILEMODE
779 BASIC_CFLAGS += -DNO_TRUSTABLE_FILEMODE
780endif
781ifdef NO_IPV6
782 BASIC_CFLAGS += -DNO_IPV6
783endif
784ifdef NO_UINTMAX_T
785 BASIC_CFLAGS += -Duintmax_t=uint32_t
786endif
787ifdef NO_SOCKADDR_STORAGE
788ifdef NO_IPV6
789 BASIC_CFLAGS += -Dsockaddr_storage=sockaddr_in
790else
791 BASIC_CFLAGS += -Dsockaddr_storage=sockaddr_in6
792endif
793endif
794ifdef NO_INET_NTOP
795 LIB_OBJS += $(OUTPUT)compat/inet_ntop.o
796endif
797ifdef NO_INET_PTON
798 LIB_OBJS += $(OUTPUT)compat/inet_pton.o
799endif
800
801ifdef NO_ICONV
802 BASIC_CFLAGS += -DNO_ICONV
803endif
804
805ifdef OLD_ICONV
806 BASIC_CFLAGS += -DOLD_ICONV
807endif
808
809ifdef NO_DEFLATE_BOUND
810 BASIC_CFLAGS += -DNO_DEFLATE_BOUND
811endif
812
813ifdef PPC_SHA1
814 SHA1_HEADER = "ppc/sha1.h"
815 LIB_OBJS += $(OUTPUT)ppc/sha1.o ppc/sha1ppc.o
816else
817ifdef ARM_SHA1
818 SHA1_HEADER = "arm/sha1.h"
819 LIB_OBJS += $(OUTPUT)arm/sha1.o $(OUTPUT)arm/sha1_arm.o
820else
821ifdef MOZILLA_SHA1
822 SHA1_HEADER = "mozilla-sha1/sha1.h"
823 LIB_OBJS += $(OUTPUT)mozilla-sha1/sha1.o
824else
825 SHA1_HEADER = <openssl/sha.h>
826 EXTLIBS += $(LIB_4_CRYPTO)
827endif
828endif
829endif
830ifdef NO_PERL_MAKEMAKER
831 export NO_PERL_MAKEMAKER
832endif
833ifdef NO_HSTRERROR
834 COMPAT_CFLAGS += -DNO_HSTRERROR
835 COMPAT_OBJS += $(OUTPUT)compat/hstrerror.o
836endif
837ifdef NO_MEMMEM
838 COMPAT_CFLAGS += -DNO_MEMMEM
839 COMPAT_OBJS += $(OUTPUT)compat/memmem.o
840endif
841ifdef INTERNAL_QSORT
842 COMPAT_CFLAGS += -DINTERNAL_QSORT
843 COMPAT_OBJS += $(OUTPUT)compat/qsort.o
844endif
845ifdef RUNTIME_PREFIX
846 COMPAT_CFLAGS += -DRUNTIME_PREFIX
847endif
848
849ifdef DIR_HAS_BSD_GROUP_SEMANTICS
850 COMPAT_CFLAGS += -DDIR_HAS_BSD_GROUP_SEMANTICS
851endif
852ifdef NO_EXTERNAL_GREP
853 BASIC_CFLAGS += -DNO_EXTERNAL_GREP
854endif
855
856ifeq ($(PERL_PATH),)
857NO_PERL=NoThanks
858endif
859
860QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir
861QUIET_SUBDIR1 =
862
863ifneq ($(findstring $(MAKEFLAGS),w),w)
864PRINT_DIR = --no-print-directory
865else # "make -w"
866NO_SUBDIR = :
867endif
868
869ifneq ($(findstring $(MAKEFLAGS),s),s) 540ifneq ($(findstring $(MAKEFLAGS),s),s)
870ifndef V 541ifndef V
871 QUIET_CC = @echo ' ' CC $@; 542 QUIET_CC = @echo ' ' CC $@;
872 QUIET_AR = @echo ' ' AR $@; 543 QUIET_AR = @echo ' ' AR $@;
873 QUIET_LINK = @echo ' ' LINK $@; 544 QUIET_LINK = @echo ' ' LINK $@;
874 QUIET_MKDIR = @echo ' ' MKDIR $@; 545 QUIET_MKDIR = @echo ' ' MKDIR $@;
875 QUIET_BUILT_IN = @echo ' ' BUILTIN $@;
876 QUIET_GEN = @echo ' ' GEN $@; 546 QUIET_GEN = @echo ' ' GEN $@;
877 QUIET_SUBDIR0 = +@subdir=
878 QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \
879 $(MAKE) $(PRINT_DIR) -C $$subdir
880 export V
881 export QUIET_GEN
882 export QUIET_BUILT_IN
883endif 547endif
884endif 548endif
885 549
@@ -889,7 +553,6 @@ endif
889 553
890# Shell quote (do not use $(call) to accommodate ancient setups); 554# Shell quote (do not use $(call) to accommodate ancient setups);
891 555
892SHA1_HEADER_SQ = $(subst ','\'',$(SHA1_HEADER))
893ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG)) 556ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG))
894 557
895DESTDIR_SQ = $(subst ','\'',$(DESTDIR)) 558DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
@@ -903,46 +566,36 @@ htmldir_SQ = $(subst ','\'',$(htmldir))
903prefix_SQ = $(subst ','\'',$(prefix)) 566prefix_SQ = $(subst ','\'',$(prefix))
904 567
905SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) 568SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
906PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH))
907 569
908LIBS = -Wl,--whole-archive $(PERFLIBS) -Wl,--no-whole-archive $(EXTLIBS) 570LIBS = -Wl,--whole-archive $(PERFLIBS) -Wl,--no-whole-archive $(EXTLIBS)
909 571
910BASIC_CFLAGS += -DSHA1_HEADER='$(SHA1_HEADER_SQ)' \
911 $(COMPAT_CFLAGS)
912LIB_OBJS += $(COMPAT_OBJS)
913
914ALL_CFLAGS += $(BASIC_CFLAGS) 572ALL_CFLAGS += $(BASIC_CFLAGS)
915ALL_CFLAGS += $(ARCH_CFLAGS) 573ALL_CFLAGS += $(ARCH_CFLAGS)
916ALL_LDFLAGS += $(BASIC_LDFLAGS) 574ALL_LDFLAGS += $(BASIC_LDFLAGS)
917 575
918export TAR INSTALL DESTDIR SHELL_PATH 576export INSTALL SHELL_PATH
919 577
920 578
921### Build rules 579### Build rules
922 580
923SHELL = $(SHELL_PATH) 581SHELL = $(SHELL_PATH)
924 582
925all:: shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) $(OUTPUT)PERF-BUILD-OPTIONS 583all: shell_compatibility_test $(ALL_PROGRAMS) $(LANG_BINDINGS) $(OTHER_PROGRAMS)
926ifneq (,$X)
927 $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) perf$X)), test '$p' -ef '$p$X' || $(RM) '$p';)
928endif
929
930all::
931 584
932please_set_SHELL_PATH_to_a_more_modern_shell: 585please_set_SHELL_PATH_to_a_more_modern_shell:
933 @$$(:) 586 @$$(:)
934 587
935shell_compatibility_test: please_set_SHELL_PATH_to_a_more_modern_shell 588shell_compatibility_test: please_set_SHELL_PATH_to_a_more_modern_shell
936 589
937strip: $(PROGRAMS) $(OUTPUT)perf$X 590strip: $(PROGRAMS) $(OUTPUT)perf
938 $(STRIP) $(STRIP_OPTS) $(PROGRAMS) $(OUTPUT)perf$X 591 $(STRIP) $(STRIP_OPTS) $(PROGRAMS) $(OUTPUT)perf
939 592
940$(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS 593$(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
941 $(QUIET_CC)$(CC) -DPERF_VERSION='"$(PERF_VERSION)"' \ 594 $(QUIET_CC)$(CC) -DPERF_VERSION='"$(PERF_VERSION)"' \
942 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ 595 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
943 $(ALL_CFLAGS) -c $(filter %.c,$^) -o $@ 596 $(ALL_CFLAGS) -c $(filter %.c,$^) -o $@
944 597
945$(OUTPUT)perf$X: $(OUTPUT)perf.o $(BUILTIN_OBJS) $(PERFLIBS) 598$(OUTPUT)perf: $(OUTPUT)perf.o $(BUILTIN_OBJS) $(PERFLIBS)
946 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) $(OUTPUT)perf.o \ 599 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) $(OUTPUT)perf.o \
947 $(BUILTIN_OBJS) $(LIBS) -o $@ 600 $(BUILTIN_OBJS) $(LIBS) -o $@
948 601
@@ -958,39 +611,17 @@ $(OUTPUT)builtin-timechart.o: builtin-timechart.c $(OUTPUT)common-cmds.h $(OUTPU
958 '-DPERF_MAN_PATH="$(mandir_SQ)"' \ 611 '-DPERF_MAN_PATH="$(mandir_SQ)"' \
959 '-DPERF_INFO_PATH="$(infodir_SQ)"' $< 612 '-DPERF_INFO_PATH="$(infodir_SQ)"' $<
960 613
961$(BUILT_INS): $(OUTPUT)perf$X
962 $(QUIET_BUILT_IN)$(RM) $@ && \
963 ln perf$X $@ 2>/dev/null || \
964 ln -s perf$X $@ 2>/dev/null || \
965 cp perf$X $@
966
967$(OUTPUT)common-cmds.h: util/generate-cmdlist.sh command-list.txt 614$(OUTPUT)common-cmds.h: util/generate-cmdlist.sh command-list.txt
968 615
969$(OUTPUT)common-cmds.h: $(wildcard Documentation/perf-*.txt) 616$(OUTPUT)common-cmds.h: $(wildcard Documentation/perf-*.txt)
970 $(QUIET_GEN). util/generate-cmdlist.sh > $@+ && mv $@+ $@ 617 $(QUIET_GEN). util/generate-cmdlist.sh > $@+ && mv $@+ $@
971 618
972$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh 619$(SCRIPTS) : % : %.sh
973 $(QUIET_GEN)$(RM) $(OUTPUT)$@ $(OUTPUT)$@+ && \ 620 $(QUIET_GEN)$(INSTALL) '$@.sh' '$(OUTPUT)$@'
974 sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
975 -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \
976 -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \
977 -e 's/@@PERF_VERSION@@/$(PERF_VERSION)/g' \
978 -e 's/@@NO_CURL@@/$(NO_CURL)/g' \
979 $@.sh > $(OUTPUT)$@+ && \
980 chmod +x $(OUTPUT)$@+ && \
981 mv $(OUTPUT)$@+ $(OUTPUT)$@
982
983configure: configure.ac
984 $(QUIET_GEN)$(RM) $@ $<+ && \
985 sed -e 's/@@PERF_VERSION@@/$(PERF_VERSION)/g' \
986 $< > $<+ && \
987 autoconf -o $@ $<+ && \
988 $(RM) $<+
989 621
990# These can record PERF_VERSION 622# These can record PERF_VERSION
991$(OUTPUT)perf.o perf.spec \ 623$(OUTPUT)perf.o perf.spec \
992 $(patsubst %.sh,%,$(SCRIPT_SH)) \ 624 $(SCRIPTS) \
993 $(patsubst %.perl,%,$(SCRIPT_PERL)) \
994 : $(OUTPUT)PERF-VERSION-FILE 625 : $(OUTPUT)PERF-VERSION-FILE
995 626
996$(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS 627$(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS
@@ -1007,9 +638,6 @@ $(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS
1007 '-DPREFIX="$(prefix_SQ)"' \ 638 '-DPREFIX="$(prefix_SQ)"' \
1008 $< 639 $<
1009 640
1010$(OUTPUT)builtin-init-db.o: builtin-init-db.c $(OUTPUT)PERF-CFLAGS
1011 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DDEFAULT_PERF_TEMPLATE_DIR='"$(template_dir_SQ)"' $<
1012
1013$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS 641$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS
1014 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< 642 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
1015 643
@@ -1019,6 +647,9 @@ $(OUTPUT)util/ui/browser.o: util/ui/browser.c $(OUTPUT)PERF-CFLAGS
1019$(OUTPUT)util/ui/browsers/annotate.o: util/ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS 647$(OUTPUT)util/ui/browsers/annotate.o: util/ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS
1020 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 648 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
1021 649
650$(OUTPUT)util/ui/browsers/top.o: util/ui/browsers/top.c $(OUTPUT)PERF-CFLAGS
651 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
652
1022$(OUTPUT)util/ui/browsers/hists.o: util/ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS 653$(OUTPUT)util/ui/browsers/hists.o: util/ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS
1023 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 654 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
1024 655
@@ -1040,12 +671,11 @@ $(OUTPUT)util/scripting-engines/trace-event-python.o: util/scripting-engines/tra
1040$(OUTPUT)scripts/python/Perf-Trace-Util/Context.o: scripts/python/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS 671$(OUTPUT)scripts/python/Perf-Trace-Util/Context.o: scripts/python/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS
1041 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $< 672 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $<
1042 673
1043$(OUTPUT)perf-%$X: %.o $(PERFLIBS) 674$(OUTPUT)perf-%: %.o $(PERFLIBS)
1044 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) 675 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
1045 676
1046$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H) 677$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
1047$(patsubst perf-%$X,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h) 678$(patsubst perf-%,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
1048builtin-revert.o wt-status.o: wt-status.h
1049 679
1050# we compile into subdirectories. if the target directory is not the source directory, they might not exists. So 680# we compile into subdirectories. if the target directory is not the source directory, they might not exists. So
1051# we depend the various files onto their directories. 681# we depend the various files onto their directories.
@@ -1058,6 +688,36 @@ $(sort $(dir $(DIRECTORY_DEPS))):
1058$(LIB_FILE): $(LIB_OBJS) 688$(LIB_FILE): $(LIB_OBJS)
1059 $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS) 689 $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS)
1060 690
691help:
692 @echo 'Perf make targets:'
693 @echo ' doc - make *all* documentation (see below)'
694 @echo ' man - make manpage documentation (access with man <foo>)'
695 @echo ' html - make html documentation'
696 @echo ' info - make GNU info documentation (access with info <foo>)'
697 @echo ' pdf - make pdf documentation'
698 @echo ' TAGS - use etags to make tag information for source browsing'
699 @echo ' tags - use ctags to make tag information for source browsing'
700 @echo ' cscope - use cscope to make interactive browsing database'
701 @echo ''
702 @echo 'Perf install targets:'
703 @echo ' NOTE: documentation build requires asciidoc, xmlto packages to be installed'
704 @echo ' HINT: use "make prefix=<path> <install target>" to install to a particular'
705 @echo ' path like make prefix=/usr/local install install-doc'
706 @echo ' install - install compiled binaries'
707 @echo ' install-doc - install *all* documentation'
708 @echo ' install-man - install manpage documentation'
709 @echo ' install-html - install html documentation'
710 @echo ' install-info - install GNU info documentation'
711 @echo ' install-pdf - install pdf documentation'
712 @echo ''
713 @echo ' quick-install-doc - alias for quick-install-man'
714 @echo ' quick-install-man - install the documentation quickly'
715 @echo ' quick-install-html - install the html documentation quickly'
716 @echo ''
717 @echo 'Perf maintainer targets:'
718 @echo ' distclean - alias to clean'
719 @echo ' clean - clean all binary objects and build output'
720
1061doc: 721doc:
1062 $(MAKE) -C Documentation all 722 $(MAKE) -C Documentation all
1063 723
@@ -1096,30 +756,12 @@ $(OUTPUT)PERF-CFLAGS: .FORCE-PERF-CFLAGS
1096 echo "$$FLAGS" >$(OUTPUT)PERF-CFLAGS; \ 756 echo "$$FLAGS" >$(OUTPUT)PERF-CFLAGS; \
1097 fi 757 fi
1098 758
1099# We need to apply sq twice, once to protect from the shell
1100# that runs $(OUTPUT)PERF-BUILD-OPTIONS, and then again to protect it
1101# and the first level quoting from the shell that runs "echo".
1102$(OUTPUT)PERF-BUILD-OPTIONS: .FORCE-PERF-BUILD-OPTIONS
1103 @echo SHELL_PATH=\''$(subst ','\'',$(SHELL_PATH_SQ))'\' >$@
1104 @echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@
1105 @echo NO_CURL=\''$(subst ','\'',$(subst ','\'',$(NO_CURL)))'\' >>$@
1106 @echo NO_PERL=\''$(subst ','\'',$(subst ','\'',$(NO_PERL)))'\' >>$@
1107
1108### Testing rules 759### Testing rules
1109 760
1110#
1111# None right now:
1112#
1113# TEST_PROGRAMS += test-something$X
1114
1115all:: $(TEST_PROGRAMS)
1116
1117# GNU make supports exporting all variables by "export" without parameters. 761# GNU make supports exporting all variables by "export" without parameters.
1118# However, the environment gets quite big, and some programs have problems 762# However, the environment gets quite big, and some programs have problems
1119# with that. 763# with that.
1120 764
1121export NO_SVN_TESTS
1122
1123check: $(OUTPUT)common-cmds.h 765check: $(OUTPUT)common-cmds.h
1124 if sparse; \ 766 if sparse; \
1125 then \ 767 then \
@@ -1128,33 +770,21 @@ check: $(OUTPUT)common-cmds.h
1128 sparse $(ALL_CFLAGS) $(SPARSE_FLAGS) $$i || exit; \ 770 sparse $(ALL_CFLAGS) $(SPARSE_FLAGS) $$i || exit; \
1129 done; \ 771 done; \
1130 else \ 772 else \
1131 echo 2>&1 "Did you mean 'make test'?"; \
1132 exit 1; \ 773 exit 1; \
1133 fi 774 fi
1134 775
1135remove-dashes:
1136 ./fixup-builtins $(BUILT_INS) $(PROGRAMS) $(SCRIPTS)
1137
1138### Installation rules 776### Installation rules
1139 777
1140ifneq ($(filter /%,$(firstword $(template_dir))),)
1141template_instdir = $(template_dir)
1142else
1143template_instdir = $(prefix)/$(template_dir)
1144endif
1145export template_instdir
1146
1147ifneq ($(filter /%,$(firstword $(perfexecdir))),) 778ifneq ($(filter /%,$(firstword $(perfexecdir))),)
1148perfexec_instdir = $(perfexecdir) 779perfexec_instdir = $(perfexecdir)
1149else 780else
1150perfexec_instdir = $(prefix)/$(perfexecdir) 781perfexec_instdir = $(prefix)/$(perfexecdir)
1151endif 782endif
1152perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir)) 783perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir))
1153export perfexec_instdir
1154 784
1155install: all 785install: all
1156 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' 786 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
1157 $(INSTALL) $(OUTPUT)perf$X '$(DESTDIR_SQ)$(bindir_SQ)' 787 $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)'
1158 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace' 788 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
1159 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin' 789 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
1160 $(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' 790 $(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
@@ -1167,14 +797,6 @@ install: all
1167 $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python' 797 $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python'
1168 $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin' 798 $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
1169 799
1170ifdef BUILT_INS
1171 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
1172 $(INSTALL) $(BUILT_INS) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
1173ifneq (,$X)
1174 $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) $(OUTPUT)perf$X)), $(RM) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/$p';)
1175endif
1176endif
1177
1178install-doc: 800install-doc:
1179 $(MAKE) -C Documentation install 801 $(MAKE) -C Documentation install
1180 802
@@ -1199,104 +821,17 @@ quick-install-man:
1199quick-install-html: 821quick-install-html:
1200 $(MAKE) -C Documentation quick-install-html 822 $(MAKE) -C Documentation quick-install-html
1201 823
1202
1203### Maintainer's dist rules
1204#
1205# None right now
1206#
1207#
1208# perf.spec: perf.spec.in
1209# sed -e 's/@@VERSION@@/$(PERF_VERSION)/g' < $< > $@+
1210# mv $@+ $@
1211#
1212# PERF_TARNAME=perf-$(PERF_VERSION)
1213# dist: perf.spec perf-archive$(X) configure
1214# ./perf-archive --format=tar \
1215# --prefix=$(PERF_TARNAME)/ HEAD^{tree} > $(PERF_TARNAME).tar
1216# @mkdir -p $(PERF_TARNAME)
1217# @cp perf.spec configure $(PERF_TARNAME)
1218# @echo $(PERF_VERSION) > $(PERF_TARNAME)/version
1219# $(TAR) rf $(PERF_TARNAME).tar \
1220# $(PERF_TARNAME)/perf.spec \
1221# $(PERF_TARNAME)/configure \
1222# $(PERF_TARNAME)/version
1223# @$(RM) -r $(PERF_TARNAME)
1224# gzip -f -9 $(PERF_TARNAME).tar
1225#
1226# htmldocs = perf-htmldocs-$(PERF_VERSION)
1227# manpages = perf-manpages-$(PERF_VERSION)
1228# dist-doc:
1229# $(RM) -r .doc-tmp-dir
1230# mkdir .doc-tmp-dir
1231# $(MAKE) -C Documentation WEBDOC_DEST=../.doc-tmp-dir install-webdoc
1232# cd .doc-tmp-dir && $(TAR) cf ../$(htmldocs).tar .
1233# gzip -n -9 -f $(htmldocs).tar
1234# :
1235# $(RM) -r .doc-tmp-dir
1236# mkdir -p .doc-tmp-dir/man1 .doc-tmp-dir/man5 .doc-tmp-dir/man7
1237# $(MAKE) -C Documentation DESTDIR=./ \
1238# man1dir=../.doc-tmp-dir/man1 \
1239# man5dir=../.doc-tmp-dir/man5 \
1240# man7dir=../.doc-tmp-dir/man7 \
1241# install
1242# cd .doc-tmp-dir && $(TAR) cf ../$(manpages).tar .
1243# gzip -n -9 -f $(manpages).tar
1244# $(RM) -r .doc-tmp-dir
1245#
1246# rpm: dist
1247# $(RPMBUILD) -ta $(PERF_TARNAME).tar.gz
1248
1249### Cleaning rules 824### Cleaning rules
1250 825
1251distclean: clean
1252# $(RM) configure
1253
1254clean: 826clean:
1255 $(RM) *.o */*.o */*/*.o */*/*/*.o $(LIB_FILE) 827 $(RM) $(OUTPUT){*.o,*/*.o,*/*/*.o,*/*/*/*.o,$(LIB_FILE),perf-archive}
1256 $(RM) $(ALL_PROGRAMS) $(BUILT_INS) perf$X 828 $(RM) $(ALL_PROGRAMS) perf
1257 $(RM) $(TEST_PROGRAMS)
1258 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* 829 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope*
1259 $(RM) -r autom4te.cache
1260 $(RM) config.log config.mak.autogen config.mak.append config.status config.cache
1261 $(RM) -r $(PERF_TARNAME) .doc-tmp-dir
1262 $(RM) $(PERF_TARNAME).tar.gz perf-core_$(PERF_VERSION)-*.tar.gz
1263 $(RM) $(htmldocs).tar.gz $(manpages).tar.gz
1264 $(MAKE) -C Documentation/ clean 830 $(MAKE) -C Documentation/ clean
1265 $(RM) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS $(OUTPUT)PERF-BUILD-OPTIONS 831 $(RM) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS
832 @python util/setup.py clean --build-lib='$(OUTPUT)python' \
833 --build-temp='$(OUTPUT)python/temp'
1266 834
1267.PHONY: all install clean strip 835.PHONY: all install clean strip
1268.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell 836.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
1269.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS 837.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS
1270.PHONY: .FORCE-PERF-BUILD-OPTIONS
1271
1272### Make sure built-ins do not have dups and listed in perf.c
1273#
1274check-builtins::
1275 ./check-builtins.sh
1276
1277### Test suite coverage testing
1278#
1279# None right now
1280#
1281# .PHONY: coverage coverage-clean coverage-build coverage-report
1282#
1283# coverage:
1284# $(MAKE) coverage-build
1285# $(MAKE) coverage-report
1286#
1287# coverage-clean:
1288# rm -f *.gcda *.gcno
1289#
1290# COVERAGE_CFLAGS = $(CFLAGS) -O0 -ftest-coverage -fprofile-arcs
1291# COVERAGE_LDFLAGS = $(CFLAGS) -O0 -lgcov
1292#
1293# coverage-build: coverage-clean
1294# $(MAKE) CFLAGS="$(COVERAGE_CFLAGS)" LDFLAGS="$(COVERAGE_LDFLAGS)" all
1295# $(MAKE) CFLAGS="$(COVERAGE_CFLAGS)" LDFLAGS="$(COVERAGE_LDFLAGS)" \
1296# -j1 test
1297#
1298# coverage-report:
1299# gcov -b *.c */*.c
1300# grep '^function.*called 0 ' *.c.gcov */*.c.gcov \
1301# | sed -e 's/\([^:]*\)\.gcov: *function \([^ ]*\) called.*/\1: \2/' \
1302# | 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 c056cdc06912..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 %016llx", filename, offset);
216 fp = popen(cmd, "r");
217 if (!fp)
218 continue;
219
220 if (getline(&path, &line_len, fp) < 0 || !line_len)
221 goto next;
222
223 sym_ext[i].path = malloc(sizeof(char) * line_len + 1);
224 if (!sym_ext[i].path)
225 goto next;
226
227 strcpy(sym_ext[i].path, path);
228 insert_source_line(&sym_ext[i]);
229
230 next:
231 pclose(fp);
232 }
233}
234
235static void print_summary(const char *filename)
236{
237 struct sym_ext *sym_ext;
238 struct rb_node *node;
239
240 printf("\nSorted summary for file %s\n", filename);
241 printf("----------------------------------------------\n\n");
242
243 if (RB_EMPTY_ROOT(&root_sym_ext)) {
244 printf(" Nothing higher than %1.1f%%\n", MIN_GREEN);
245 return;
246 }
247
248 node = rb_first(&root_sym_ext);
249 while (node) {
250 double percent;
251 const char *color;
252 char *path;
253
254 sym_ext = rb_entry(node, struct sym_ext, node);
255 percent = sym_ext->percent;
256 color = get_percent_color(percent);
257 path = sym_ext->path;
258
259 color_fprintf(stdout, color, " %7.2f %s", percent, path);
260 node = rb_next(node);
261 }
262}
263
264static void hist_entry__print_hits(struct hist_entry *self)
265{
266 struct symbol *sym = self->ms.sym;
267 struct sym_priv *priv = symbol__priv(sym);
268 struct sym_hist *h = priv->hist;
269 u64 len = sym->end - sym->start, offset;
270
271 for (offset = 0; offset < len; ++offset)
272 if (h->ip[offset] != 0)
273 printf("%*Lx: %Lu\n", BITS_PER_LONG / 2,
274 sym->start + offset, h->ip[offset]);
275 printf("%*s: %Lu\n", BITS_PER_LONG / 2, "h->sum", h->sum);
276}
277
278static int hist_entry__tty_annotate(struct hist_entry *he)
279{ 106{
280 struct map *map = he->ms.map; 107 return symbol__tty_annotate(he->ms.sym, he->ms.map, evidx,
281 struct dso *dso = map->dso; 108 print_line, full_paths, 0, 0);
282 struct symbol *sym = he->ms.sym;
283 const char *filename = dso->long_name, *d_filename;
284 u64 len;
285 LIST_HEAD(head);
286 struct objdump_line *pos, *n;
287
288 if (hist_entry__annotate(he, &head, 0) < 0)
289 return -1;
290
291 if (full_paths)
292 d_filename = filename;
293 else
294 d_filename = basename(filename);
295
296 len = sym->end - sym->start;
297
298 if (print_line) {
299 get_source_line(he, len, filename);
300 print_summary(filename);
301 }
302
303 printf("\n\n------------------------------------------------\n");
304 printf(" Percent | Source code & Disassembly of %s\n", d_filename);
305 printf("------------------------------------------------\n");
306
307 if (verbose)
308 hist_entry__print_hits(he);
309
310 list_for_each_entry_safe(pos, n, &head, node) {
311 objdump_line__print(pos, &head, he, len);
312 list_del(&pos->node);
313 objdump_line__free(pos);
314 }
315
316 if (print_line)
317 free_source_line(he, len);
318
319 return 0;
320} 109}
321 110
322static void hists__find_annotations(struct hists *self) 111static void hists__find_annotations(struct hists *self, int evidx)
323{ 112{
324 struct rb_node *nd = rb_first(&self->entries), *next; 113 struct rb_node *nd = rb_first(&self->entries), *next;
325 int key = KEY_RIGHT; 114 int key = KEY_RIGHT;
326 115
327 while (nd) { 116 while (nd) {
328 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); 117 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
329 struct sym_priv *priv; 118 struct annotation *notes;
330 119
331 if (he->ms.sym == NULL || he->ms.map->dso->annotate_warned) 120 if (he->ms.sym == NULL || he->ms.map->dso->annotate_warned)
332 goto find_next; 121 goto find_next;
333 122
334 priv = symbol__priv(he->ms.sym); 123 notes = symbol__annotation(he->ms.sym);
335 if (priv->hist == NULL) { 124 if (notes->src == NULL) {
336find_next: 125find_next:
337 if (key == KEY_LEFT) 126 if (key == KEY_LEFT)
338 nd = rb_prev(nd); 127 nd = rb_prev(nd);
@@ -342,7 +131,7 @@ find_next:
342 } 131 }
343 132
344 if (use_browser > 0) { 133 if (use_browser > 0) {
345 key = hist_entry__tui_annotate(he); 134 key = hist_entry__tui_annotate(he, evidx);
346 switch (key) { 135 switch (key) {
347 case KEY_RIGHT: 136 case KEY_RIGHT:
348 next = rb_next(nd); 137 next = rb_next(nd);
@@ -357,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 def7ddc2fd4f..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
@@ -371,10 +372,10 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
371 addr = data->ptr; 372 addr = data->ptr;
372 373
373 if (sym != NULL) 374 if (sym != NULL)
374 snprintf(buf, sizeof(buf), "%s+%Lx", sym->name, 375 snprintf(buf, sizeof(buf), "%s+%" PRIx64 "", sym->name,
375 addr - map->unmap_ip(map, sym->start)); 376 addr - map->unmap_ip(map, sym->start));
376 else 377 else
377 snprintf(buf, sizeof(buf), "%#Lx", addr); 378 snprintf(buf, sizeof(buf), "%#" PRIx64 "", addr);
378 printf(" %-34s |", buf); 379 printf(" %-34s |", buf);
379 380
380 printf(" %9llu/%-5lu | %9llu/%-5lu | %8lu | %8lu | %6.3f%%\n", 381 printf(" %9llu/%-5lu | %9llu/%-5lu | %8lu | %8lu | %6.3f%%\n",
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 b9c6e5432971..9ac05aafd9b2 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -202,9 +202,20 @@ static struct thread_stat *thread_stat_findnew_first(u32 tid)
202SINGLE_KEY(nr_acquired) 202SINGLE_KEY(nr_acquired)
203SINGLE_KEY(nr_contended) 203SINGLE_KEY(nr_contended)
204SINGLE_KEY(wait_time_total) 204SINGLE_KEY(wait_time_total)
205SINGLE_KEY(wait_time_min)
206SINGLE_KEY(wait_time_max) 205SINGLE_KEY(wait_time_max)
207 206
207static int lock_stat_key_wait_time_min(struct lock_stat *one,
208 struct lock_stat *two)
209{
210 u64 s1 = one->wait_time_min;
211 u64 s2 = two->wait_time_min;
212 if (s1 == ULLONG_MAX)
213 s1 = 0;
214 if (s2 == ULLONG_MAX)
215 s2 = 0;
216 return s1 > s2;
217}
218
208struct lock_key { 219struct lock_key {
209 /* 220 /*
210 * name: the value for specify by user 221 * name: the value for specify by user
@@ -782,9 +793,9 @@ static void print_result(void)
782 pr_info("%10u ", st->nr_acquired); 793 pr_info("%10u ", st->nr_acquired);
783 pr_info("%10u ", st->nr_contended); 794 pr_info("%10u ", st->nr_contended);
784 795
785 pr_info("%15llu ", st->wait_time_total); 796 pr_info("%15" PRIu64 " ", st->wait_time_total);
786 pr_info("%15llu ", st->wait_time_max); 797 pr_info("%15" PRIu64 " ", st->wait_time_max);
787 pr_info("%15llu ", st->wait_time_min == ULLONG_MAX ? 798 pr_info("%15" PRIu64 " ", st->wait_time_min == ULLONG_MAX ?
788 0 : st->wait_time_min); 799 0 : st->wait_time_min);
789 pr_info("\n"); 800 pr_info("\n");
790 } 801 }
@@ -834,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 fcd29e8af29f..6febcc168a8c 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 = 128;
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{
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{ 162{
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,19 +221,58 @@ 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);
329 240
330 if (FD(evsel, nr_cpu, thread_index) < 0) { 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}
249
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)
@@ -364,7 +309,7 @@ try_again:
364 } 309 }
365 printf("\n"); 310 printf("\n");
366 error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n", 311 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)); 312 err, strerror(err));
368 313
369#if defined(__i386__) || defined(__x86_64__) 314#if defined(__i386__) || defined(__x86_64__)
370 if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP) 315 if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP)
@@ -375,90 +320,28 @@ try_again:
375#endif 320#endif
376 321
377 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); 322 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
378 exit(-1);
379 } 323 }
324 }
380 325
381 h_attr = get_header_attr(attr, evsel->idx); 326 if (perf_evlist__set_filters(evlist)) {
382 if (h_attr == NULL) 327 error("failed to set filter with %d (%s)\n", errno,
383 die("nomem\n"); 328 strerror(errno));
329 exit(-1);
330 }
384 331
385 if (!file_new) { 332 if (perf_evlist__mmap(evlist, mmap_pages, false) < 0)
386 if (memcmp(&h_attr->attr, attr, sizeof(*attr))) { 333 die("failed to mmap with %d (%s)\n", errno, strerror(errno));
387 fprintf(stderr, "incompatible append\n");
388 exit(-1);
389 }
390 }
391 334
392 if (read(FD(evsel, nr_cpu, thread_index), &read_data, sizeof(read_data)) == -1) { 335 if (file_new)
393 perror("Unable to read perf file descriptor"); 336 session->evlist = evlist;
337 else {
338 if (!perf_evlist__equal(session->evlist, evlist)) {
339 fprintf(stderr, "incompatible append\n");
394 exit(-1); 340 exit(-1);
395 } 341 }
342 }
396 343
397 if (perf_header_attr__add_id(h_attr, read_data.id) < 0) { 344 perf_session__update_sample_type(session);
398 pr_warning("Not enough memory to add id\n");
399 exit(-1);
400 }
401
402 assert(FD(evsel, nr_cpu, thread_index) >= 0);
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} 345}
463 346
464static int process_buildids(void) 347static int process_buildids(void)
@@ -481,14 +364,14 @@ static void atexit_header(void)
481 364
482 if (!no_buildid) 365 if (!no_buildid)
483 process_buildids(); 366 process_buildids();
484 perf_header__write(&session->header, output, true); 367 perf_session__write_header(session, evsel_list, output, true);
485 perf_session__delete(session); 368 perf_session__delete(session);
486 perf_evsel_list__delete(); 369 perf_evlist__delete(evsel_list);
487 symbol__exit(); 370 symbol__exit();
488 } 371 }
489} 372}
490 373
491static void event__synthesize_guest_os(struct machine *machine, void *data) 374static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
492{ 375{
493 int err; 376 int err;
494 struct perf_session *psession = data; 377 struct perf_session *psession = data;
@@ -504,8 +387,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 387 *method is used to avoid symbol missing when the first addr is
505 *in module instead of in guest kernel. 388 *in module instead of in guest kernel.
506 */ 389 */
507 err = event__synthesize_modules(process_synthesized_event, 390 err = perf_event__synthesize_modules(process_synthesized_event,
508 psession, machine); 391 psession, machine);
509 if (err < 0) 392 if (err < 0)
510 pr_err("Couldn't record guest kernel [%d]'s reference" 393 pr_err("Couldn't record guest kernel [%d]'s reference"
511 " relocation symbol.\n", machine->pid); 394 " relocation symbol.\n", machine->pid);
@@ -514,11 +397,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 397 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
515 * have no _text sometimes. 398 * have no _text sometimes.
516 */ 399 */
517 err = event__synthesize_kernel_mmap(process_synthesized_event, 400 err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
518 psession, machine, "_text"); 401 psession, machine, "_text");
519 if (err < 0) 402 if (err < 0)
520 err = event__synthesize_kernel_mmap(process_synthesized_event, 403 err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
521 psession, machine, "_stext"); 404 psession, machine,
405 "_stext");
522 if (err < 0) 406 if (err < 0)
523 pr_err("Couldn't record guest kernel [%d]'s reference" 407 pr_err("Couldn't record guest kernel [%d]'s reference"
524 " relocation symbol.\n", machine->pid); 408 " relocation symbol.\n", machine->pid);
@@ -533,9 +417,9 @@ static void mmap_read_all(void)
533{ 417{
534 int i; 418 int i;
535 419
536 for (i = 0; i < nr_cpu; i++) { 420 for (i = 0; i < evsel_list->cpus->nr; i++) {
537 if (mmap_array[i].base) 421 if (evsel_list->mmap[i].base)
538 mmap_read(&mmap_array[i]); 422 mmap_read(&evsel_list->mmap[i]);
539 } 423 }
540 424
541 if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO)) 425 if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO))
@@ -566,18 +450,26 @@ static int __cmd_record(int argc, const char **argv)
566 exit(-1); 450 exit(-1);
567 } 451 }
568 452
569 if (!strcmp(output_name, "-")) 453 if (!output_name) {
570 pipe_output = 1; 454 if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
571 else if (!stat(output_name, &st) && st.st_size) { 455 pipe_output = 1;
572 if (write_mode == WRITE_FORCE) { 456 else
573 char oldname[PATH_MAX]; 457 output_name = "perf.data";
574 snprintf(oldname, sizeof(oldname), "%s.old", 458 }
575 output_name); 459 if (output_name) {
576 unlink(oldname); 460 if (!strcmp(output_name, "-"))
577 rename(output_name, oldname); 461 pipe_output = 1;
462 else if (!stat(output_name, &st) && st.st_size) {
463 if (write_mode == WRITE_FORCE) {
464 char oldname[PATH_MAX];
465 snprintf(oldname, sizeof(oldname), "%s.old",
466 output_name);
467 unlink(oldname);
468 rename(output_name, oldname);
469 }
470 } else if (write_mode == WRITE_APPEND) {
471 write_mode = WRITE_FORCE;
578 } 472 }
579 } else if (write_mode == WRITE_APPEND) {
580 write_mode = WRITE_FORCE;
581 } 473 }
582 474
583 flags = O_CREAT|O_RDWR; 475 flags = O_CREAT|O_RDWR;
@@ -606,19 +498,14 @@ static int __cmd_record(int argc, const char **argv)
606 perf_header__set_feat(&session->header, HEADER_BUILD_ID); 498 perf_header__set_feat(&session->header, HEADER_BUILD_ID);
607 499
608 if (!file_new) { 500 if (!file_new) {
609 err = perf_header__read(session, output); 501 err = perf_session__read_header(session, output);
610 if (err < 0) 502 if (err < 0)
611 goto out_delete_session; 503 goto out_delete_session;
612 } 504 }
613 505
614 if (have_tracepoints(&evsel_list)) 506 if (have_tracepoints(&evsel_list->entries))
615 perf_header__set_feat(&session->header, HEADER_TRACE_INFO); 507 perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
616 508
617 /*
618 * perf_session__delete(session) will be called at atexit_header()
619 */
620 atexit(atexit_header);
621
622 if (forks) { 509 if (forks) {
623 child_pid = fork(); 510 child_pid = fork();
624 if (child_pid < 0) { 511 if (child_pid < 0) {
@@ -659,7 +546,7 @@ static int __cmd_record(int argc, const char **argv)
659 } 546 }
660 547
661 if (!system_wide && target_tid == -1 && target_pid == -1) 548 if (!system_wide && target_tid == -1 && target_pid == -1)
662 threads->map[0] = child_pid; 549 evsel_list->threads->map[0] = child_pid;
663 550
664 close(child_ready_pipe[1]); 551 close(child_ready_pipe[1]);
665 close(go_pipe[0]); 552 close(go_pipe[0]);
@@ -673,46 +560,42 @@ static int __cmd_record(int argc, const char **argv)
673 close(child_ready_pipe[0]); 560 close(child_ready_pipe[0]);
674 } 561 }
675 562
676 if (!system_wide && no_inherit && !cpu_list) { 563 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 564
683 perf_session__set_sample_type(session, sample_type); 565 /*
566 * perf_session__delete(session) will be called at atexit_header()
567 */
568 atexit(atexit_header);
684 569
685 if (pipe_output) { 570 if (pipe_output) {
686 err = perf_header__write_pipe(output); 571 err = perf_header__write_pipe(output);
687 if (err < 0) 572 if (err < 0)
688 return err; 573 return err;
689 } else if (file_new) { 574 } else if (file_new) {
690 err = perf_header__write(&session->header, output, false); 575 err = perf_session__write_header(session, evsel_list,
576 output, false);
691 if (err < 0) 577 if (err < 0)
692 return err; 578 return err;
693 } 579 }
694 580
695 post_processing_offset = lseek(output, 0, SEEK_CUR); 581 post_processing_offset = lseek(output, 0, SEEK_CUR);
696 582
697 perf_session__set_sample_id_all(session, sample_id_all_avail);
698
699 if (pipe_output) { 583 if (pipe_output) {
700 err = event__synthesize_attrs(&session->header, 584 err = perf_session__synthesize_attrs(session,
701 process_synthesized_event, 585 process_synthesized_event);
702 session);
703 if (err < 0) { 586 if (err < 0) {
704 pr_err("Couldn't synthesize attrs.\n"); 587 pr_err("Couldn't synthesize attrs.\n");
705 return err; 588 return err;
706 } 589 }
707 590
708 err = event__synthesize_event_types(process_synthesized_event, 591 err = perf_event__synthesize_event_types(process_synthesized_event,
709 session); 592 session);
710 if (err < 0) { 593 if (err < 0) {
711 pr_err("Couldn't synthesize event_types.\n"); 594 pr_err("Couldn't synthesize event_types.\n");
712 return err; 595 return err;
713 } 596 }
714 597
715 if (have_tracepoints(&evsel_list)) { 598 if (have_tracepoints(&evsel_list->entries)) {
716 /* 599 /*
717 * FIXME err <= 0 here actually means that 600 * FIXME err <= 0 here actually means that
718 * there were no tracepoints so its not really 601 * there were no tracepoints so its not really
@@ -721,9 +604,9 @@ static int __cmd_record(int argc, const char **argv)
721 * return this more properly and also 604 * return this more properly and also
722 * propagate errors that now are calling die() 605 * propagate errors that now are calling die()
723 */ 606 */
724 err = event__synthesize_tracing_data(output, &evsel_list, 607 err = perf_event__synthesize_tracing_data(output, evsel_list,
725 process_synthesized_event, 608 process_synthesized_event,
726 session); 609 session);
727 if (err <= 0) { 610 if (err <= 0) {
728 pr_err("Couldn't record tracing data.\n"); 611 pr_err("Couldn't record tracing data.\n");
729 return err; 612 return err;
@@ -738,31 +621,34 @@ static int __cmd_record(int argc, const char **argv)
738 return -1; 621 return -1;
739 } 622 }
740 623
741 err = event__synthesize_kernel_mmap(process_synthesized_event, 624 err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
742 session, machine, "_text"); 625 session, machine, "_text");
743 if (err < 0) 626 if (err < 0)
744 err = event__synthesize_kernel_mmap(process_synthesized_event, 627 err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
745 session, machine, "_stext"); 628 session, machine, "_stext");
746 if (err < 0) 629 if (err < 0)
747 pr_err("Couldn't record kernel reference relocation symbol\n" 630 pr_err("Couldn't record kernel reference relocation symbol\n"
748 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" 631 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
749 "Check /proc/kallsyms permission or run as root.\n"); 632 "Check /proc/kallsyms permission or run as root.\n");
750 633
751 err = event__synthesize_modules(process_synthesized_event, 634 err = perf_event__synthesize_modules(process_synthesized_event,
752 session, machine); 635 session, machine);
753 if (err < 0) 636 if (err < 0)
754 pr_err("Couldn't record kernel module information.\n" 637 pr_err("Couldn't record kernel module information.\n"
755 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" 638 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
756 "Check /proc/modules permission or run as root.\n"); 639 "Check /proc/modules permission or run as root.\n");
757 640
758 if (perf_guest) 641 if (perf_guest)
759 perf_session__process_machines(session, event__synthesize_guest_os); 642 perf_session__process_machines(session,
643 perf_event__synthesize_guest_os);
760 644
761 if (!system_wide) 645 if (!system_wide)
762 event__synthesize_thread(target_tid, process_synthesized_event, 646 perf_event__synthesize_thread_map(evsel_list->threads,
763 session); 647 process_synthesized_event,
648 session);
764 else 649 else
765 event__synthesize_threads(process_synthesized_event, session); 650 perf_event__synthesize_threads(process_synthesized_event,
651 session);
766 652
767 if (realtime_prio) { 653 if (realtime_prio) {
768 struct sched_param param; 654 struct sched_param param;
@@ -789,17 +675,17 @@ static int __cmd_record(int argc, const char **argv)
789 if (hits == samples) { 675 if (hits == samples) {
790 if (done) 676 if (done)
791 break; 677 break;
792 err = poll(event_array, nr_poll, -1); 678 err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
793 waking++; 679 waking++;
794 } 680 }
795 681
796 if (done) { 682 if (done) {
797 for (i = 0; i < nr_cpu; i++) { 683 for (i = 0; i < evsel_list->cpus->nr; i++) {
798 struct perf_evsel *pos; 684 struct perf_evsel *pos;
799 685
800 list_for_each_entry(pos, &evsel_list, node) { 686 list_for_each_entry(pos, &evsel_list->entries, node) {
801 for (thread = 0; 687 for (thread = 0;
802 thread < threads->nr; 688 thread < evsel_list->threads->nr;
803 thread++) 689 thread++)
804 ioctl(FD(pos, i, thread), 690 ioctl(FD(pos, i, thread),
805 PERF_EVENT_IOC_DISABLE); 691 PERF_EVENT_IOC_DISABLE);
@@ -817,7 +703,7 @@ static int __cmd_record(int argc, const char **argv)
817 * Approximate RIP event size: 24 bytes. 703 * Approximate RIP event size: 24 bytes.
818 */ 704 */
819 fprintf(stderr, 705 fprintf(stderr,
820 "[ perf record: Captured and wrote %.3f MB %s (~%lld samples) ]\n", 706 "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
821 (double)bytes_written / 1024.0 / 1024.0, 707 (double)bytes_written / 1024.0 / 1024.0,
822 output_name, 708 output_name,
823 bytes_written / 24); 709 bytes_written / 24);
@@ -838,10 +724,10 @@ static const char * const record_usage[] = {
838static bool force, append_file; 724static bool force, append_file;
839 725
840const struct option record_options[] = { 726const struct option record_options[] = {
841 OPT_CALLBACK('e', "event", NULL, "event", 727 OPT_CALLBACK('e', "event", &evsel_list, "event",
842 "event selector. use 'perf list' to list available events", 728 "event selector. use 'perf list' to list available events",
843 parse_events), 729 parse_events),
844 OPT_CALLBACK(0, "filter", NULL, "filter", 730 OPT_CALLBACK(0, "filter", &evsel_list, "filter",
845 "event filter", parse_filter), 731 "event filter", parse_filter),
846 OPT_INTEGER('p', "pid", &target_pid, 732 OPT_INTEGER('p', "pid", &target_pid,
847 "record events on existing process id"), 733 "record events on existing process id"),
@@ -884,6 +770,9 @@ const struct option record_options[] = {
884 "do not update the buildid cache"), 770 "do not update the buildid cache"),
885 OPT_BOOLEAN('B', "no-buildid", &no_buildid, 771 OPT_BOOLEAN('B', "no-buildid", &no_buildid,
886 "do not collect buildids in perf.data"), 772 "do not collect buildids in perf.data"),
773 OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
774 "monitor event in cgroup name only",
775 parse_cgroups),
887 OPT_END() 776 OPT_END()
888}; 777};
889 778
@@ -892,6 +781,10 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
892 int err = -ENOMEM; 781 int err = -ENOMEM;
893 struct perf_evsel *pos; 782 struct perf_evsel *pos;
894 783
784 evsel_list = perf_evlist__new(NULL, NULL);
785 if (evsel_list == NULL)
786 return -ENOMEM;
787
895 argc = parse_options(argc, argv, record_options, record_usage, 788 argc = parse_options(argc, argv, record_options, record_usage,
896 PARSE_OPT_STOP_AT_NON_OPTION); 789 PARSE_OPT_STOP_AT_NON_OPTION);
897 if (!argc && target_pid == -1 && target_tid == -1 && 790 if (!argc && target_pid == -1 && target_tid == -1 &&
@@ -908,12 +801,19 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
908 write_mode = WRITE_FORCE; 801 write_mode = WRITE_FORCE;
909 } 802 }
910 803
804 if (nr_cgroups && !system_wide) {
805 fprintf(stderr, "cgroup monitoring only available in"
806 " system-wide mode\n");
807 usage_with_options(record_usage, record_options);
808 }
809
911 symbol__init(); 810 symbol__init();
912 811
913 if (no_buildid_cache || no_buildid) 812 if (no_buildid_cache || no_buildid)
914 disable_buildid_cache(); 813 disable_buildid_cache();
915 814
916 if (list_empty(&evsel_list) && perf_evsel_list__create_default() < 0) { 815 if (evsel_list->nr_entries == 0 &&
816 perf_evlist__add_default(evsel_list) < 0) {
917 pr_err("Not enough memory for event selector list\n"); 817 pr_err("Not enough memory for event selector list\n");
918 goto out_symbol_exit; 818 goto out_symbol_exit;
919 } 819 }
@@ -921,27 +821,19 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
921 if (target_pid != -1) 821 if (target_pid != -1)
922 target_tid = target_pid; 822 target_tid = target_pid;
923 823
924 threads = thread_map__new(target_pid, target_tid); 824 if (perf_evlist__create_maps(evsel_list, target_pid,
925 if (threads == NULL) { 825 target_tid, cpu_list) < 0)
926 pr_err("Problems finding threads of monitor\n");
927 usage_with_options(record_usage, record_options); 826 usage_with_options(record_usage, record_options);
928 }
929 827
930 cpus = cpu_map__new(cpu_list); 828 list_for_each_entry(pos, &evsel_list->entries, node) {
931 if (cpus == NULL) { 829 if (perf_evsel__alloc_fd(pos, evsel_list->cpus->nr,
932 perror("failed to parse CPUs map"); 830 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; 831 goto out_free_fd;
939 if (perf_header__push_event(pos->attr.config, event_name(pos))) 832 if (perf_header__push_event(pos->attr.config, event_name(pos)))
940 goto out_free_fd; 833 goto out_free_fd;
941 } 834 }
942 event_array = malloc((sizeof(struct pollfd) * MAX_NR_CPUS * 835
943 MAX_COUNTERS * threads->nr)); 836 if (perf_evlist__alloc_pollfd(evsel_list) < 0)
944 if (!event_array)
945 goto out_free_fd; 837 goto out_free_fd;
946 838
947 if (user_interval != ULLONG_MAX) 839 if (user_interval != ULLONG_MAX)
@@ -959,16 +851,12 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
959 } else { 851 } else {
960 fprintf(stderr, "frequency and count are zero, aborting\n"); 852 fprintf(stderr, "frequency and count are zero, aborting\n");
961 err = -EINVAL; 853 err = -EINVAL;
962 goto out_free_event_array; 854 goto out_free_fd;
963 } 855 }
964 856
965 err = __cmd_record(argc, argv); 857 err = __cmd_record(argc, argv);
966
967out_free_event_array:
968 free(event_array);
969out_free_fd: 858out_free_fd:
970 thread_map__delete(threads); 859 perf_evlist__delete_maps(evsel_list);
971 threads = NULL;
972out_symbol_exit: 860out_symbol_exit:
973 symbol__exit(); 861 symbol__exit();
974 return err; 862 return err;
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 75183a4518e6..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,
@@ -197,8 +139,8 @@ static int process_read_event(event_t *event, struct sample_data *sample __used,
197 event->read.value); 139 event->read.value);
198 } 140 }
199 141
200 dump_printf(": %d %d %s %Lu\n", event->read.pid, event->read.tid, 142 dump_printf(": %d %d %s %" PRIu64 "\n", event->read.pid, event->read.tid,
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 29e7ffd85690..dcfe8873c9a1 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -193,7 +193,7 @@ static void calibrate_run_measurement_overhead(void)
193 } 193 }
194 run_measurement_overhead = min_delta; 194 run_measurement_overhead = min_delta;
195 195
196 printf("run measurement overhead: %Ld nsecs\n", min_delta); 196 printf("run measurement overhead: %" PRIu64 " nsecs\n", min_delta);
197} 197}
198 198
199static void calibrate_sleep_measurement_overhead(void) 199static void calibrate_sleep_measurement_overhead(void)
@@ -211,7 +211,7 @@ static void calibrate_sleep_measurement_overhead(void)
211 min_delta -= 10000; 211 min_delta -= 10000;
212 sleep_measurement_overhead = min_delta; 212 sleep_measurement_overhead = min_delta;
213 213
214 printf("sleep measurement overhead: %Ld nsecs\n", min_delta); 214 printf("sleep measurement overhead: %" PRIu64 " nsecs\n", min_delta);
215} 215}
216 216
217static struct sched_atom * 217static struct sched_atom *
@@ -369,11 +369,6 @@ static void
369process_sched_event(struct task_desc *this_task __used, struct sched_atom *atom) 369process_sched_event(struct task_desc *this_task __used, struct sched_atom *atom)
370{ 370{
371 int ret = 0; 371 int ret = 0;
372 u64 now;
373 long long delta;
374
375 now = get_nsecs();
376 delta = start_time + atom->timestamp - now;
377 372
378 switch (atom->type) { 373 switch (atom->type) {
379 case SCHED_EVENT_RUN: 374 case SCHED_EVENT_RUN:
@@ -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;
@@ -617,13 +611,13 @@ static void test_calibrations(void)
617 burn_nsecs(1e6); 611 burn_nsecs(1e6);
618 T1 = get_nsecs(); 612 T1 = get_nsecs();
619 613
620 printf("the run test took %Ld nsecs\n", T1-T0); 614 printf("the run test took %" PRIu64 " nsecs\n", T1 - T0);
621 615
622 T0 = get_nsecs(); 616 T0 = get_nsecs();
623 sleep_nsecs(1e6); 617 sleep_nsecs(1e6);
624 T1 = get_nsecs(); 618 T1 = get_nsecs();
625 619
626 printf("the sleep test took %Ld nsecs\n", T1-T0); 620 printf("the sleep test took %" PRIu64 " nsecs\n", T1 - T0);
627} 621}
628 622
629#define FILL_FIELD(ptr, field, event, data) \ 623#define FILL_FIELD(ptr, field, event, data) \
@@ -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
@@ -816,10 +810,10 @@ replay_switch_event(struct trace_switch_event *switch_event,
816 delta = 0; 810 delta = 0;
817 811
818 if (delta < 0) 812 if (delta < 0)
819 die("hm, delta: %Ld < 0 ?\n", delta); 813 die("hm, delta: %" PRIu64 " < 0 ?\n", delta);
820 814
821 if (verbose) { 815 if (verbose) {
822 printf(" ... switch from %s/%d to %s/%d [ran %Ld nsecs]\n", 816 printf(" ... switch from %s/%d to %s/%d [ran %" PRIu64 " nsecs]\n",
823 switch_event->prev_comm, switch_event->prev_pid, 817 switch_event->prev_comm, switch_event->prev_pid,
824 switch_event->next_comm, switch_event->next_pid, 818 switch_event->next_comm, switch_event->next_pid,
825 delta); 819 delta);
@@ -1048,7 +1042,7 @@ latency_switch_event(struct trace_switch_event *switch_event,
1048 delta = 0; 1042 delta = 0;
1049 1043
1050 if (delta < 0) 1044 if (delta < 0)
1051 die("hm, delta: %Ld < 0 ?\n", delta); 1045 die("hm, delta: %" PRIu64 " < 0 ?\n", delta);
1052 1046
1053 1047
1054 sched_out = perf_session__findnew(session, switch_event->prev_pid); 1048 sched_out = perf_session__findnew(session, switch_event->prev_pid);
@@ -1221,7 +1215,7 @@ static void output_lat_thread(struct work_atoms *work_list)
1221 1215
1222 avg = work_list->total_lat / work_list->nb_atoms; 1216 avg = work_list->total_lat / work_list->nb_atoms;
1223 1217
1224 printf("|%11.3f ms |%9llu | avg:%9.3f ms | max:%9.3f ms | max at: %9.6f s\n", 1218 printf("|%11.3f ms |%9" PRIu64 " | avg:%9.3f ms | max:%9.3f ms | max at: %9.6f s\n",
1225 (double)work_list->total_runtime / 1e6, 1219 (double)work_list->total_runtime / 1e6,
1226 work_list->nb_atoms, (double)avg / 1e6, 1220 work_list->nb_atoms, (double)avg / 1e6,
1227 (double)work_list->max_lat / 1e6, 1221 (double)work_list->max_lat / 1e6,
@@ -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;
@@ -1423,7 +1417,7 @@ map_switch_event(struct trace_switch_event *switch_event,
1423 delta = 0; 1417 delta = 0;
1424 1418
1425 if (delta < 0) 1419 if (delta < 0)
1426 die("hm, delta: %Ld < 0 ?\n", delta); 1420 die("hm, delta: %" PRIu64 " < 0 ?\n", delta);
1427 1421
1428 1422
1429 sched_out = perf_session__findnew(session, switch_event->prev_pid); 1423 sched_out = perf_session__findnew(session, switch_event->prev_pid);
@@ -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
@@ -1713,7 +1709,7 @@ static void __cmd_lat(void)
1713 } 1709 }
1714 1710
1715 printf(" -----------------------------------------------------------------------------------------\n"); 1711 printf(" -----------------------------------------------------------------------------------------\n");
1716 printf(" TOTAL: |%11.3f ms |%9Ld |\n", 1712 printf(" TOTAL: |%11.3f ms |%9" PRIu64 " |\n",
1717 (double)all_runtime/1e6, all_count); 1713 (double)all_runtime/1e6, all_count);
1718 1714
1719 printf(" ---------------------------------------------------\n"); 1715 printf(" ---------------------------------------------------\n");
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 150a606002eb..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: %llu " 253 " this: %" PRIu64 "\n", last_timestamp,
81 "this: %llu\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;
@@ -126,7 +293,7 @@ static int __cmd_script(struct perf_session *session)
126 ret = perf_session__process_events(session, &event_ops); 293 ret = perf_session__process_events(session, &event_ops);
127 294
128 if (debug_mode) 295 if (debug_mode)
129 pr_err("Misordered timestamps: %llu\n", nr_unordered); 296 pr_err("Misordered timestamps: %" PRIu64 "\n", nr_unordered);
130 297
131 return ret; 298 return ret;
132} 299}
@@ -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 0ff11d9b13be..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,15 +201,16 @@ 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++)
206 update_stats(&ps->res_stats[i], count[i]); 209 update_stats(&ps->res_stats[i], count[i]);
207 210
208 if (verbose) { 211 if (verbose) {
209 fprintf(stderr, "%s: %Ld %Ld %Ld\n", event_name(counter), 212 fprintf(stderr, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
210 count[0], count[1], count[2]); 213 event_name(counter), count[0], count[1], count[2]);
211 } 214 }
212 215
213 /* 216 /*
@@ -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 ed5696198d3d..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
@@ -146,7 +147,7 @@ next_pair:
146 if (llabs(skew) < page_size) 147 if (llabs(skew) < page_size)
147 continue; 148 continue;
148 149
149 pr_debug("%#Lx: diff end addr for %s v: %#Lx k: %#Lx\n", 150 pr_debug("%#" PRIx64 ": diff end addr for %s v: %#" PRIx64 " k: %#" PRIx64 "\n",
150 sym->start, sym->name, sym->end, pair->end); 151 sym->start, sym->name, sym->end, pair->end);
151 } else { 152 } else {
152 struct rb_node *nnd; 153 struct rb_node *nnd;
@@ -168,11 +169,11 @@ detour:
168 goto detour; 169 goto detour;
169 } 170 }
170 171
171 pr_debug("%#Lx: diff name v: %s k: %s\n", 172 pr_debug("%#" PRIx64 ": diff name v: %s k: %s\n",
172 sym->start, sym->name, pair->name); 173 sym->start, sym->name, pair->name);
173 } 174 }
174 } else 175 } else
175 pr_debug("%#Lx: %s not on kallsyms\n", sym->start, sym->name); 176 pr_debug("%#" PRIx64 ": %s not on kallsyms\n", sym->start, sym->name);
176 177
177 err = -1; 178 err = -1;
178 } 179 }
@@ -211,10 +212,10 @@ detour:
211 212
212 if (pair->start == pos->start) { 213 if (pair->start == pos->start) {
213 pair->priv = 1; 214 pair->priv = 1;
214 pr_info(" %Lx-%Lx %Lx %s in kallsyms as", 215 pr_info(" %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s in kallsyms as",
215 pos->start, pos->end, pos->pgoff, pos->dso->name); 216 pos->start, pos->end, pos->pgoff, pos->dso->name);
216 if (pos->pgoff != pair->pgoff || pos->end != pair->end) 217 if (pos->pgoff != pair->pgoff || pos->end != pair->end)
217 pr_info(": \n*%Lx-%Lx %Lx", 218 pr_info(": \n*%" PRIx64 "-%" PRIx64 " %" PRIx64 "",
218 pair->start, pair->end, pair->pgoff); 219 pair->start, pair->end, pair->pgoff);
219 pr_info(" %s\n", pair->dso->name); 220 pr_info(" %s\n", pair->dso->name);
220 pair->priv = 1; 221 pair->priv = 1;
@@ -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));
@@ -307,7 +308,7 @@ static int test__open_syscall_event(void)
307 } 308 }
308 309
309 if (evsel->counts->cpu[0].val != nr_open_calls) { 310 if (evsel->counts->cpu[0].val != nr_open_calls) {
310 pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls, got %Ld\n", 311 pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls, got %" PRIu64 "\n",
311 nr_open_calls, evsel->counts->cpu[0].val); 312 nr_open_calls, evsel->counts->cpu[0].val);
312 goto out_close_fd; 313 goto out_close_fd;
313 } 314 }
@@ -332,8 +333,7 @@ static int test__open_syscall_event_on_all_cpus(void)
332 struct perf_evsel *evsel; 333 struct perf_evsel *evsel;
333 struct perf_event_attr attr; 334 struct perf_event_attr attr;
334 unsigned int nr_open_calls = 111, i; 335 unsigned int nr_open_calls = 111, i;
335 cpu_set_t *cpu_set; 336 cpu_set_t cpu_set;
336 size_t cpu_set_size;
337 int id = trace_event__id("sys_enter_open"); 337 int id = trace_event__id("sys_enter_open");
338 338
339 if (id < 0) { 339 if (id < 0) {
@@ -348,18 +348,13 @@ static int test__open_syscall_event_on_all_cpus(void)
348 } 348 }
349 349
350 cpus = cpu_map__new(NULL); 350 cpus = cpu_map__new(NULL);
351 if (threads == NULL) { 351 if (cpus == NULL) {
352 pr_debug("thread_map__new\n"); 352 pr_debug("cpu_map__new\n");
353 return -1; 353 goto out_thread_map_delete;
354 } 354 }
355 355
356 cpu_set = CPU_ALLOC(cpus->nr);
357
358 if (cpu_set == NULL)
359 goto out_thread_map_delete;
360 356
361 cpu_set_size = CPU_ALLOC_SIZE(cpus->nr); 357 CPU_ZERO(&cpu_set);
362 CPU_ZERO_S(cpu_set_size, cpu_set);
363 358
364 memset(&attr, 0, sizeof(attr)); 359 memset(&attr, 0, sizeof(attr));
365 attr.type = PERF_TYPE_TRACEPOINT; 360 attr.type = PERF_TYPE_TRACEPOINT;
@@ -367,10 +362,10 @@ static int test__open_syscall_event_on_all_cpus(void)
367 evsel = perf_evsel__new(&attr, 0); 362 evsel = perf_evsel__new(&attr, 0);
368 if (evsel == NULL) { 363 if (evsel == NULL) {
369 pr_debug("perf_evsel__new\n"); 364 pr_debug("perf_evsel__new\n");
370 goto out_cpu_free; 365 goto out_thread_map_delete;
371 } 366 }
372 367
373 if (perf_evsel__open(evsel, cpus, threads) < 0) { 368 if (perf_evsel__open(evsel, cpus, threads, false, false) < 0) {
374 pr_debug("failed to open counter: %s, " 369 pr_debug("failed to open counter: %s, "
375 "tweak /proc/sys/kernel/perf_event_paranoid?\n", 370 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
376 strerror(errno)); 371 strerror(errno));
@@ -379,14 +374,29 @@ static int test__open_syscall_event_on_all_cpus(void)
379 374
380 for (cpu = 0; cpu < cpus->nr; ++cpu) { 375 for (cpu = 0; cpu < cpus->nr; ++cpu) {
381 unsigned int ncalls = nr_open_calls + cpu; 376 unsigned int ncalls = nr_open_calls + cpu;
377 /*
378 * XXX eventually lift this restriction in a way that
379 * keeps perf building on older glibc installations
380 * without CPU_ALLOC. 1024 cpus in 2010 still seems
381 * a reasonable upper limit tho :-)
382 */
383 if (cpus->map[cpu] >= CPU_SETSIZE) {
384 pr_debug("Ignoring CPU %d\n", cpus->map[cpu]);
385 continue;
386 }
382 387
383 CPU_SET(cpu, cpu_set); 388 CPU_SET(cpus->map[cpu], &cpu_set);
384 sched_setaffinity(0, cpu_set_size, cpu_set); 389 if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) {
390 pr_debug("sched_setaffinity() failed on CPU %d: %s ",
391 cpus->map[cpu],
392 strerror(errno));
393 goto out_close_fd;
394 }
385 for (i = 0; i < ncalls; ++i) { 395 for (i = 0; i < ncalls; ++i) {
386 fd = open("/etc/passwd", O_RDONLY); 396 fd = open("/etc/passwd", O_RDONLY);
387 close(fd); 397 close(fd);
388 } 398 }
389 CPU_CLR(cpu, cpu_set); 399 CPU_CLR(cpus->map[cpu], &cpu_set);
390 } 400 }
391 401
392 /* 402 /*
@@ -399,34 +409,190 @@ static int test__open_syscall_event_on_all_cpus(void)
399 goto out_close_fd; 409 goto out_close_fd;
400 } 410 }
401 411
412 err = 0;
413
402 for (cpu = 0; cpu < cpus->nr; ++cpu) { 414 for (cpu = 0; cpu < cpus->nr; ++cpu) {
403 unsigned int expected; 415 unsigned int expected;
404 416
417 if (cpus->map[cpu] >= CPU_SETSIZE)
418 continue;
419
405 if (perf_evsel__read_on_cpu(evsel, cpu, 0) < 0) { 420 if (perf_evsel__read_on_cpu(evsel, cpu, 0) < 0) {
406 pr_debug("perf_evsel__open_read_on_cpu\n"); 421 pr_debug("perf_evsel__open_read_on_cpu\n");
407 goto out_close_fd; 422 err = -1;
423 break;
408 } 424 }
409 425
410 expected = nr_open_calls + cpu; 426 expected = nr_open_calls + cpu;
411 if (evsel->counts->cpu[cpu].val != expected) { 427 if (evsel->counts->cpu[cpu].val != expected) {
412 pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls on cpu %d, got %Ld\n", 428 pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls on cpu %d, got %" PRIu64 "\n",
413 expected, cpu, evsel->counts->cpu[cpu].val); 429 expected, cpus->map[cpu], evsel->counts->cpu[cpu].val);
414 goto out_close_fd; 430 err = -1;
415 } 431 }
416 } 432 }
417 433
418 err = 0;
419out_close_fd: 434out_close_fd:
420 perf_evsel__close_fd(evsel, 1, threads->nr); 435 perf_evsel__close_fd(evsel, 1, threads->nr);
421out_evsel_delete: 436out_evsel_delete:
422 perf_evsel__delete(evsel); 437 perf_evsel__delete(evsel);
423out_cpu_free:
424 CPU_FREE(cpu_set);
425out_thread_map_delete: 438out_thread_map_delete:
426 thread_map__delete(threads); 439 thread_map__delete(threads);
427 return err; 440 return err;
428} 441}
429 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
430static struct test { 596static struct test {
431 const char *desc; 597 const char *desc;
432 int (*func)(void); 598 int (*func)(void);
@@ -444,6 +610,10 @@ static struct test {
444 .func = test__open_syscall_event_on_all_cpus, 610 .func = test__open_syscall_event_on_all_cpus,
445 }, 611 },
446 { 612 {
613 .desc = "read samples using the mmap interface",
614 .func = test__basic_mmap,
615 },
616 {
447 .func = NULL, 617 .func = NULL,
448 }, 618 },
449}; 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 05344c6210ac..676b4fb0070f 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"
@@ -40,11 +45,11 @@
40#include <stdio.h> 45#include <stdio.h>
41#include <termios.h> 46#include <termios.h>
42#include <unistd.h> 47#include <unistd.h>
48#include <inttypes.h>
43 49
44#include <errno.h> 50#include <errno.h>
45#include <time.h> 51#include <time.h>
46#include <sched.h> 52#include <sched.h>
47#include <pthread.h>
48 53
49#include <sys/syscall.h> 54#include <sys/syscall.h>
50#include <sys/ioctl.h> 55#include <sys/ioctl.h>
@@ -59,85 +64,42 @@
59 64
60#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))
61 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
62static bool system_wide = false; 79static bool system_wide = false;
63 80
64static int default_interval = 0; 81static bool use_tui, use_stdio;
65 82
66static int count_filter = 5; 83static int default_interval = 0;
67static int print_entries;
68 84
69static int target_pid = -1;
70static int target_tid = -1;
71static struct thread_map *threads;
72static bool inherit = false; 85static bool inherit = false;
73static struct cpu_map *cpus;
74static int realtime_prio = 0; 86static int realtime_prio = 0;
75static bool group = false; 87static bool group = false;
76static unsigned int page_size; 88static unsigned int page_size;
77static unsigned int mmap_pages = 16; 89static unsigned int mmap_pages = 128;
78static int freq = 1000; /* 1 KHz */
79 90
80static int delay_secs = 2;
81static bool zero = false;
82static bool dump_symtab = false; 91static bool dump_symtab = false;
83 92
84static bool hide_kernel_symbols = false;
85static bool hide_user_symbols = false;
86static struct winsize winsize; 93static struct winsize winsize;
87 94
88/*
89 * Source
90 */
91
92struct source_line {
93 u64 eip;
94 unsigned long count[MAX_COUNTERS];
95 char *line;
96 struct source_line *next;
97};
98
99static const char *sym_filter = NULL; 95static const char *sym_filter = NULL;
100struct sym_entry *sym_filter_entry = NULL;
101struct sym_entry *sym_filter_entry_sched = NULL; 96struct sym_entry *sym_filter_entry_sched = NULL;
102static int sym_pcnt_filter = 5; 97static int sym_pcnt_filter = 5;
103static int sym_counter = 0;
104static struct perf_evsel *sym_evsel = NULL;
105static int display_weighted = -1;
106static const char *cpu_list;
107
108/*
109 * Symbols
110 */
111
112struct sym_entry_source {
113 struct source_line *source;
114 struct source_line *lines;
115 struct source_line **lines_tail;
116 pthread_mutex_t lock;
117};
118
119struct sym_entry {
120 struct rb_node rb_node;
121 struct list_head node;
122 unsigned long snap_count;
123 double weight;
124 int skip;
125 u16 name_len;
126 u8 origin;
127 struct map *map;
128 struct sym_entry_source *src;
129 unsigned long count[0];
130};
131 98
132/* 99/*
133 * Source functions 100 * Source functions
134 */ 101 */
135 102
136static inline struct symbol *sym_entry__symbol(struct sym_entry *self)
137{
138 return ((void *)self) + symbol_conf.priv_size;
139}
140
141void get_term_dimensions(struct winsize *ws) 103void get_term_dimensions(struct winsize *ws)
142{ 104{
143 char *s = getenv("LINES"); 105 char *s = getenv("LINES");
@@ -162,10 +124,10 @@ void get_term_dimensions(struct winsize *ws)
162 124
163static void update_print_entries(struct winsize *ws) 125static void update_print_entries(struct winsize *ws)
164{ 126{
165 print_entries = ws->ws_row; 127 top.print_entries = ws->ws_row;
166 128
167 if (print_entries > 9) 129 if (top.print_entries > 9)
168 print_entries -= 9; 130 top.print_entries -= 9;
169} 131}
170 132
171static void sig_winch_handler(int sig __used) 133static void sig_winch_handler(int sig __used)
@@ -177,12 +139,9 @@ static void sig_winch_handler(int sig __used)
177static int parse_source(struct sym_entry *syme) 139static int parse_source(struct sym_entry *syme)
178{ 140{
179 struct symbol *sym; 141 struct symbol *sym;
180 struct sym_entry_source *source; 142 struct annotation *notes;
181 struct map *map; 143 struct map *map;
182 FILE *file; 144 int err = -1;
183 char command[PATH_MAX*2];
184 const char *path;
185 u64 len;
186 145
187 if (!syme) 146 if (!syme)
188 return -1; 147 return -1;
@@ -193,411 +152,137 @@ static int parse_source(struct sym_entry *syme)
193 /* 152 /*
194 * We can't annotate with just /proc/kallsyms 153 * We can't annotate with just /proc/kallsyms
195 */ 154 */
196 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);
197 return -1; 159 return -1;
198
199 if (syme->src == NULL) {
200 syme->src = zalloc(sizeof(*source));
201 if (syme->src == NULL)
202 return -1;
203 pthread_mutex_init(&syme->src->lock, NULL);
204 } 160 }
205 161
206 source = syme->src; 162 notes = symbol__annotation(sym);
207 163 if (notes->src != NULL) {
208 if (source->lines) { 164 pthread_mutex_lock(&notes->lock);
209 pthread_mutex_lock(&source->lock);
210 goto out_assign; 165 goto out_assign;
211 } 166 }
212 path = map->dso->long_name;
213
214 len = sym->end - sym->start;
215
216 sprintf(command,
217 "objdump --start-address=%#0*Lx --stop-address=%#0*Lx -dS %s",
218 BITS_PER_LONG / 4, map__rip_2objdump(map, sym->start),
219 BITS_PER_LONG / 4, map__rip_2objdump(map, sym->end), path);
220
221 file = popen(command, "r");
222 if (!file)
223 return -1;
224
225 pthread_mutex_lock(&source->lock);
226 source->lines_tail = &source->lines;
227 while (!feof(file)) {
228 struct source_line *src;
229 size_t dummy = 0;
230 char *c, *sep;
231 167
232 src = malloc(sizeof(struct source_line)); 168 pthread_mutex_lock(&notes->lock);
233 assert(src != NULL);
234 memset(src, 0, sizeof(struct source_line));
235 169
236 if (getline(&src->line, &dummy, file) < 0) 170 if (symbol__alloc_hist(sym, top.evlist->nr_entries) < 0) {
237 break; 171 pthread_mutex_unlock(&notes->lock);
238 if (!src->line) 172 pr_err("Not enough memory for annotating '%s' symbol!\n",
239 break; 173 sym->name);
240 174 sleep(1);
241 c = strchr(src->line, '\n'); 175 return err;
242 if (c)
243 *c = 0;
244
245 src->next = NULL;
246 *source->lines_tail = src;
247 source->lines_tail = &src->next;
248
249 src->eip = strtoull(src->line, &sep, 16);
250 if (*sep == ':')
251 src->eip = map__objdump_2ip(map, src->eip);
252 else /* this line has no ip info (e.g. source line) */
253 src->eip = 0;
254 } 176 }
255 pclose(file); 177
178 err = symbol__annotate(sym, syme->map, 0);
179 if (err == 0) {
256out_assign: 180out_assign:
257 sym_filter_entry = syme; 181 top.sym_filter_entry = syme;
258 pthread_mutex_unlock(&source->lock); 182 }
259 return 0; 183
184 pthread_mutex_unlock(&notes->lock);
185 return err;
260} 186}
261 187
262static void __zero_source_counters(struct sym_entry *syme) 188static void __zero_source_counters(struct sym_entry *syme)
263{ 189{
264 int i; 190 struct symbol *sym = sym_entry__symbol(syme);
265 struct source_line *line; 191 symbol__annotate_zero_histograms(sym);
266
267 line = syme->src->lines;
268 while (line) {
269 for (i = 0; i < nr_counters; i++)
270 line->count[i] = 0;
271 line = line->next;
272 }
273} 192}
274 193
275static 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)
276{ 195{
277 struct source_line *line; 196 struct annotation *notes;
278 197 struct symbol *sym;
279 if (syme != sym_filter_entry)
280 return;
281 198
282 if (pthread_mutex_trylock(&syme->src->lock)) 199 if (syme != top.sym_filter_entry)
283 return; 200 return;
284 201
285 if (syme->src == NULL || syme->src->source == NULL) 202 sym = sym_entry__symbol(syme);
286 goto out_unlock; 203 notes = symbol__annotation(sym);
287
288 for (line = syme->src->lines; line; line = line->next) {
289 /* skip lines without IP info */
290 if (line->eip == 0)
291 continue;
292 if (line->eip == ip) {
293 line->count[counter]++;
294 break;
295 }
296 if (line->eip > ip)
297 break;
298 }
299out_unlock:
300 pthread_mutex_unlock(&syme->src->lock);
301}
302
303#define PATTERN_LEN (BITS_PER_LONG / 4 + 2)
304
305static void lookup_sym_source(struct sym_entry *syme)
306{
307 struct symbol *symbol = sym_entry__symbol(syme);
308 struct source_line *line;
309 char pattern[PATTERN_LEN + 1];
310
311 sprintf(pattern, "%0*Lx <", BITS_PER_LONG / 4,
312 map__rip_2objdump(syme->map, symbol->start));
313
314 pthread_mutex_lock(&syme->src->lock);
315 for (line = syme->src->lines; line; line = line->next) {
316 if (memcmp(line->line, pattern, PATTERN_LEN) == 0) {
317 syme->src->source = line;
318 break;
319 }
320 }
321 pthread_mutex_unlock(&syme->src->lock);
322}
323 204
324static void show_lines(struct source_line *queue, int count, int total) 205 if (pthread_mutex_trylock(&notes->lock))
325{ 206 return;
326 int i;
327 struct source_line *line;
328 207
329 line = queue; 208 ip = syme->map->map_ip(syme->map, ip);
330 for (i = 0; i < count; i++) { 209 symbol__inc_addr_samples(sym, syme->map, counter, ip);
331 float pcnt = 100.0*(float)line->count[sym_counter]/(float)total;
332 210
333 printf("%8li %4.1f%%\t%s\n", line->count[sym_counter], pcnt, line->line); 211 pthread_mutex_unlock(&notes->lock);
334 line = line->next;
335 }
336} 212}
337 213
338#define TRACE_COUNT 3
339
340static void show_details(struct sym_entry *syme) 214static void show_details(struct sym_entry *syme)
341{ 215{
216 struct annotation *notes;
342 struct symbol *symbol; 217 struct symbol *symbol;
343 struct source_line *line; 218 int more;
344 struct source_line *line_queue = NULL;
345 int displayed = 0;
346 int line_queue_count = 0, total = 0, more = 0;
347 219
348 if (!syme) 220 if (!syme)
349 return; 221 return;
350 222
351 if (!syme->src->source)
352 lookup_sym_source(syme);
353
354 if (!syme->src->source)
355 return;
356
357 symbol = sym_entry__symbol(syme); 223 symbol = sym_entry__symbol(syme);
358 printf("Showing %s for %s\n", event_name(sym_evsel), symbol->name); 224 notes = symbol__annotation(symbol);
359 printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter);
360
361 pthread_mutex_lock(&syme->src->lock);
362 line = syme->src->source;
363 while (line) {
364 total += line->count[sym_counter];
365 line = line->next;
366 }
367
368 line = syme->src->source;
369 while (line) {
370 float pcnt = 0.0;
371
372 if (!line_queue_count)
373 line_queue = line;
374 line_queue_count++;
375
376 if (line->count[sym_counter])
377 pcnt = 100.0 * line->count[sym_counter] / (float)total;
378 if (pcnt >= (float)sym_pcnt_filter) {
379 if (displayed <= print_entries)
380 show_lines(line_queue, line_queue_count, total);
381 else more++;
382 displayed += line_queue_count;
383 line_queue_count = 0;
384 line_queue = NULL;
385 } else if (line_queue_count > TRACE_COUNT) {
386 line_queue = line_queue->next;
387 line_queue_count--;
388 }
389
390 line->count[sym_counter] = zero ? 0 : line->count[sym_counter] * 7 / 8;
391 line = line->next;
392 }
393 pthread_mutex_unlock(&syme->src->lock);
394 if (more)
395 printf("%d lines not displayed, maybe increase display entries [e]\n", more);
396}
397 225
398/* 226 pthread_mutex_lock(&notes->lock);
399 * Symbols will be added here in event__process_sample and will get out
400 * after decayed.
401 */
402static LIST_HEAD(active_symbols);
403static pthread_mutex_t active_symbols_lock = PTHREAD_MUTEX_INITIALIZER;
404
405/*
406 * Ordering weight: count-1 * count-2 * ... / count-n
407 */
408static double sym_weight(const struct sym_entry *sym)
409{
410 double weight = sym->snap_count;
411 int counter;
412
413 if (!display_weighted)
414 return weight;
415 227
416 for (counter = 1; counter < nr_counters-1; counter++) 228 if (notes->src == NULL)
417 weight *= sym->count[counter]; 229 goto out_unlock;
418 230
419 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);
420 233
421 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);
422} 244}
423 245
424static long samples;
425static long kernel_samples, us_samples;
426static long exact_samples;
427static long guest_us_samples, guest_kernel_samples;
428static const char CONSOLE_CLEAR[] = ""; 246static const char CONSOLE_CLEAR[] = "";
429 247
430static void __list_insert_active_sym(struct sym_entry *syme) 248static void __list_insert_active_sym(struct sym_entry *syme)
431{ 249{
432 list_add(&syme->node, &active_symbols); 250 list_add(&syme->node, &top.active_symbols);
433}
434
435static void list_remove_active_sym(struct sym_entry *syme)
436{
437 pthread_mutex_lock(&active_symbols_lock);
438 list_del_init(&syme->node);
439 pthread_mutex_unlock(&active_symbols_lock);
440} 251}
441 252
442static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se) 253static void print_sym_table(struct perf_session *session)
443{ 254{
444 struct rb_node **p = &tree->rb_node; 255 char bf[160];
445 struct rb_node *parent = NULL; 256 int printed = 0;
446 struct sym_entry *iter;
447
448 while (*p != NULL) {
449 parent = *p;
450 iter = rb_entry(parent, struct sym_entry, rb_node);
451
452 if (se->weight > iter->weight)
453 p = &(*p)->rb_left;
454 else
455 p = &(*p)->rb_right;
456 }
457
458 rb_link_node(&se->rb_node, parent, p);
459 rb_insert_color(&se->rb_node, tree);
460}
461
462static void print_sym_table(void)
463{
464 int printed = 0, j;
465 struct perf_evsel *counter;
466 int snap = !display_weighted ? sym_counter : 0;
467 float samples_per_sec = samples/delay_secs;
468 float ksamples_per_sec = kernel_samples/delay_secs;
469 float us_samples_per_sec = (us_samples)/delay_secs;
470 float guest_kernel_samples_per_sec = (guest_kernel_samples)/delay_secs;
471 float guest_us_samples_per_sec = (guest_us_samples)/delay_secs;
472 float esamples_percent = (100.0*exact_samples)/samples;
473 float sum_ksamples = 0.0;
474 struct sym_entry *syme, *n;
475 struct rb_root tmp = RB_ROOT;
476 struct rb_node *nd; 257 struct rb_node *nd;
477 int sym_width = 0, dso_width = 0, dso_short_width = 0; 258 struct sym_entry *syme;
259 struct rb_root tmp = RB_ROOT;
478 const int win_width = winsize.ws_col - 1; 260 const int win_width = winsize.ws_col - 1;
479 261 int sym_width, dso_width, dso_short_width;
480 samples = us_samples = kernel_samples = exact_samples = 0; 262 float sum_ksamples = perf_top__decay_samples(&top, &tmp);
481 guest_kernel_samples = guest_us_samples = 0;
482
483 /* Sort the active symbols */
484 pthread_mutex_lock(&active_symbols_lock);
485 syme = list_entry(active_symbols.next, struct sym_entry, node);
486 pthread_mutex_unlock(&active_symbols_lock);
487
488 list_for_each_entry_safe_from(syme, n, &active_symbols, node) {
489 syme->snap_count = syme->count[snap];
490 if (syme->snap_count != 0) {
491
492 if ((hide_user_symbols &&
493 syme->origin == PERF_RECORD_MISC_USER) ||
494 (hide_kernel_symbols &&
495 syme->origin == PERF_RECORD_MISC_KERNEL)) {
496 list_remove_active_sym(syme);
497 continue;
498 }
499 syme->weight = sym_weight(syme);
500 rb_insert_active_sym(&tmp, syme);
501 sum_ksamples += syme->snap_count;
502
503 for (j = 0; j < nr_counters; j++)
504 syme->count[j] = zero ? 0 : syme->count[j] * 7 / 8;
505 } else
506 list_remove_active_sym(syme);
507 }
508 263
509 puts(CONSOLE_CLEAR); 264 puts(CONSOLE_CLEAR);
510 265
511 printf("%-*.*s\n", win_width, win_width, graph_dotted_line); 266 perf_top__header_snprintf(&top, bf, sizeof(bf));
512 if (!perf_guest) { 267 printf("%s\n", bf);
513 printf(" PerfTop:%8.0f irqs/sec kernel:%4.1f%%"
514 " exact: %4.1f%% [",
515 samples_per_sec,
516 100.0 - (100.0 * ((samples_per_sec - ksamples_per_sec) /
517 samples_per_sec)),
518 esamples_percent);
519 } else {
520 printf(" PerfTop:%8.0f irqs/sec kernel:%4.1f%% us:%4.1f%%"
521 " guest kernel:%4.1f%% guest us:%4.1f%%"
522 " exact: %4.1f%% [",
523 samples_per_sec,
524 100.0 - (100.0 * ((samples_per_sec-ksamples_per_sec) /
525 samples_per_sec)),
526 100.0 - (100.0 * ((samples_per_sec-us_samples_per_sec) /
527 samples_per_sec)),
528 100.0 - (100.0 * ((samples_per_sec -
529 guest_kernel_samples_per_sec) /
530 samples_per_sec)),
531 100.0 - (100.0 * ((samples_per_sec -
532 guest_us_samples_per_sec) /
533 samples_per_sec)),
534 esamples_percent);
535 }
536
537 if (nr_counters == 1 || !display_weighted) {
538 struct perf_evsel *first;
539 first = list_entry(evsel_list.next, struct perf_evsel, node);
540 printf("%Ld", first->attr.sample_period);
541 if (freq)
542 printf("Hz ");
543 else
544 printf(" ");
545 }
546
547 if (!display_weighted)
548 printf("%s", event_name(sym_evsel));
549 else list_for_each_entry(counter, &evsel_list, node) {
550 if (counter->idx)
551 printf("/");
552
553 printf("%s", event_name(counter));
554 }
555 268
556 printf( "], "); 269 perf_top__reset_sample_counters(&top);
557
558 if (target_pid != -1)
559 printf(" (target_pid: %d", target_pid);
560 else if (target_tid != -1)
561 printf(" (target_tid: %d", target_tid);
562 else
563 printf(" (all");
564
565 if (cpu_list)
566 printf(", CPU%s: %s)\n", cpus->nr > 1 ? "s" : "", cpu_list);
567 else {
568 if (target_tid != -1)
569 printf(")\n");
570 else
571 printf(", %d CPU%s)\n", cpus->nr, cpus->nr > 1 ? "s" : "");
572 }
573 270
574 printf("%-*.*s\n", win_width, win_width, graph_dotted_line); 271 printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
575 272
576 if (sym_filter_entry) { 273 if (session->hists.stats.total_lost != 0) {
577 show_details(sym_filter_entry); 274 color_fprintf(stdout, PERF_COLOR_RED, "WARNING:");
578 return; 275 printf(" LOST %" PRIu64 " events, Check IO/CPU overload\n",
276 session->hists.stats.total_lost);
579 } 277 }
580 278
581 /* 279 if (top.sym_filter_entry) {
582 * Find the longest symbol name that will be displayed 280 show_details(top.sym_filter_entry);
583 */ 281 return;
584 for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
585 syme = rb_entry(nd, struct sym_entry, rb_node);
586 if (++printed > print_entries ||
587 (int)syme->snap_count < count_filter)
588 continue;
589
590 if (syme->map->dso->long_name_len > dso_width)
591 dso_width = syme->map->dso->long_name_len;
592
593 if (syme->map->dso->short_name_len > dso_short_width)
594 dso_short_width = syme->map->dso->short_name_len;
595
596 if (syme->name_len > sym_width)
597 sym_width = syme->name_len;
598 } 282 }
599 283
600 printed = 0; 284 perf_top__find_widths(&top, &tmp, &dso_width, &dso_short_width,
285 &sym_width);
601 286
602 if (sym_width + dso_width > winsize.ws_col - 29) { 287 if (sym_width + dso_width > winsize.ws_col - 29) {
603 dso_width = dso_short_width; 288 dso_width = dso_short_width;
@@ -605,7 +290,7 @@ static void print_sym_table(void)
605 sym_width = winsize.ws_col - dso_width - 29; 290 sym_width = winsize.ws_col - dso_width - 29;
606 } 291 }
607 putchar('\n'); 292 putchar('\n');
608 if (nr_counters == 1) 293 if (top.evlist->nr_entries == 1)
609 printf(" samples pcnt"); 294 printf(" samples pcnt");
610 else 295 else
611 printf(" weight samples pcnt"); 296 printf(" weight samples pcnt");
@@ -614,7 +299,7 @@ static void print_sym_table(void)
614 printf(" RIP "); 299 printf(" RIP ");
615 printf(" %-*.*s DSO\n", sym_width, sym_width, "function"); 300 printf(" %-*.*s DSO\n", sym_width, sym_width, "function");
616 printf(" %s _______ _____", 301 printf(" %s _______ _____",
617 nr_counters == 1 ? " " : "______"); 302 top.evlist->nr_entries == 1 ? " " : "______");
618 if (verbose) 303 if (verbose)
619 printf(" ________________"); 304 printf(" ________________");
620 printf(" %-*.*s", sym_width, sym_width, graph_line); 305 printf(" %-*.*s", sym_width, sym_width, graph_line);
@@ -627,20 +312,21 @@ static void print_sym_table(void)
627 312
628 syme = rb_entry(nd, struct sym_entry, rb_node); 313 syme = rb_entry(nd, struct sym_entry, rb_node);
629 sym = sym_entry__symbol(syme); 314 sym = sym_entry__symbol(syme);
630 if (++printed > print_entries || (int)syme->snap_count < count_filter) 315 if (++printed > top.print_entries ||
316 (int)syme->snap_count < top.count_filter)
631 continue; 317 continue;
632 318
633 pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) / 319 pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) /
634 sum_ksamples)); 320 sum_ksamples));
635 321
636 if (nr_counters == 1 || !display_weighted) 322 if (top.evlist->nr_entries == 1 || !top.display_weighted)
637 printf("%20.2f ", syme->weight); 323 printf("%20.2f ", syme->weight);
638 else 324 else
639 printf("%9.1f %10ld ", syme->weight, syme->snap_count); 325 printf("%9.1f %10ld ", syme->weight, syme->snap_count);
640 326
641 percent_color_fprintf(stdout, "%4.1f%%", pcnt); 327 percent_color_fprintf(stdout, "%4.1f%%", pcnt);
642 if (verbose) 328 if (verbose)
643 printf(" %016llx", sym->start); 329 printf(" %016" PRIx64, sym->start);
644 printf(" %-*.*s", sym_width, sym_width, sym->name); 330 printf(" %-*.*s", sym_width, sym_width, sym->name);
645 printf(" %-*.*s\n", dso_width, dso_width, 331 printf(" %-*.*s\n", dso_width, dso_width,
646 dso_width >= syme->map->dso->long_name_len ? 332 dso_width >= syme->map->dso->long_name_len ?
@@ -692,10 +378,8 @@ static void prompt_symbol(struct sym_entry **target, const char *msg)
692 378
693 /* zero counters of active symbol */ 379 /* zero counters of active symbol */
694 if (syme) { 380 if (syme) {
695 pthread_mutex_lock(&syme->src->lock);
696 __zero_source_counters(syme); 381 __zero_source_counters(syme);
697 *target = NULL; 382 *target = NULL;
698 pthread_mutex_unlock(&syme->src->lock);
699 } 383 }
700 384
701 fprintf(stdout, "\n%s: ", msg); 385 fprintf(stdout, "\n%s: ", msg);
@@ -706,11 +390,11 @@ static void prompt_symbol(struct sym_entry **target, const char *msg)
706 if (p) 390 if (p)
707 *p = 0; 391 *p = 0;
708 392
709 pthread_mutex_lock(&active_symbols_lock); 393 pthread_mutex_lock(&top.active_symbols_lock);
710 syme = list_entry(active_symbols.next, struct sym_entry, node); 394 syme = list_entry(top.active_symbols.next, struct sym_entry, node);
711 pthread_mutex_unlock(&active_symbols_lock); 395 pthread_mutex_unlock(&top.active_symbols_lock);
712 396
713 list_for_each_entry_safe_from(syme, n, &active_symbols, node) { 397 list_for_each_entry_safe_from(syme, n, &top.active_symbols, node) {
714 struct symbol *sym = sym_entry__symbol(syme); 398 struct symbol *sym = sym_entry__symbol(syme);
715 399
716 if (!strcmp(buf, sym->name)) { 400 if (!strcmp(buf, sym->name)) {
@@ -734,34 +418,34 @@ static void print_mapped_keys(void)
734{ 418{
735 char *name = NULL; 419 char *name = NULL;
736 420
737 if (sym_filter_entry) { 421 if (top.sym_filter_entry) {
738 struct symbol *sym = sym_entry__symbol(sym_filter_entry); 422 struct symbol *sym = sym_entry__symbol(top.sym_filter_entry);
739 name = sym->name; 423 name = sym->name;
740 } 424 }
741 425
742 fprintf(stdout, "\nMapped keys:\n"); 426 fprintf(stdout, "\nMapped keys:\n");
743 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);
744 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);
745 429
746 if (nr_counters > 1) 430 if (top.evlist->nr_entries > 1)
747 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));
748 432
749 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);
750 434
751 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);
752 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); 436 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL");
753 fprintf(stdout, "\t[S] stop annotation.\n"); 437 fprintf(stdout, "\t[S] stop annotation.\n");
754 438
755 if (nr_counters > 1) 439 if (top.evlist->nr_entries > 1)
756 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);
757 441
758 fprintf(stdout, 442 fprintf(stdout,
759 "\t[K] hide kernel_symbols symbols. \t(%s)\n", 443 "\t[K] hide kernel_symbols symbols. \t(%s)\n",
760 hide_kernel_symbols ? "yes" : "no"); 444 top.hide_kernel_symbols ? "yes" : "no");
761 fprintf(stdout, 445 fprintf(stdout,
762 "\t[U] hide user symbols. \t(%s)\n", 446 "\t[U] hide user symbols. \t(%s)\n",
763 hide_user_symbols ? "yes" : "no"); 447 top.hide_user_symbols ? "yes" : "no");
764 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);
765 fprintf(stdout, "\t[qQ] quit.\n"); 449 fprintf(stdout, "\t[qQ] quit.\n");
766} 450}
767 451
@@ -782,7 +466,7 @@ static int key_mapped(int c)
782 return 1; 466 return 1;
783 case 'E': 467 case 'E':
784 case 'w': 468 case 'w':
785 return nr_counters > 1 ? 1 : 0; 469 return top.evlist->nr_entries > 1 ? 1 : 0;
786 default: 470 default:
787 break; 471 break;
788 } 472 }
@@ -817,47 +501,50 @@ static void handle_keypress(struct perf_session *session, int c)
817 501
818 switch (c) { 502 switch (c) {
819 case 'd': 503 case 'd':
820 prompt_integer(&delay_secs, "Enter display delay"); 504 prompt_integer(&top.delay_secs, "Enter display delay");
821 if (delay_secs < 1) 505 if (top.delay_secs < 1)
822 delay_secs = 1; 506 top.delay_secs = 1;
823 break; 507 break;
824 case 'e': 508 case 'e':
825 prompt_integer(&print_entries, "Enter display entries (lines)"); 509 prompt_integer(&top.print_entries, "Enter display entries (lines)");
826 if (print_entries == 0) { 510 if (top.print_entries == 0) {
827 sig_winch_handler(SIGWINCH); 511 sig_winch_handler(SIGWINCH);
828 signal(SIGWINCH, sig_winch_handler); 512 signal(SIGWINCH, sig_winch_handler);
829 } else 513 } else
830 signal(SIGWINCH, SIG_DFL); 514 signal(SIGWINCH, SIG_DFL);
831 break; 515 break;
832 case 'E': 516 case 'E':
833 if (nr_counters > 1) { 517 if (top.evlist->nr_entries > 1) {
518 /* Select 0 as the default event: */
519 int counter = 0;
520
834 fprintf(stderr, "\nAvailable events:"); 521 fprintf(stderr, "\nAvailable events:");
835 522
836 list_for_each_entry(sym_evsel, &evsel_list, node) 523 list_for_each_entry(top.sym_evsel, &top.evlist->entries, node)
837 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));
838 525
839 prompt_integer(&sym_counter, "Enter details event counter"); 526 prompt_integer(&counter, "Enter details event counter");
840 527
841 if (sym_counter >= nr_counters) { 528 if (counter >= top.evlist->nr_entries) {
842 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);
843 sym_counter = 0; 530 fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(top.sym_evsel));
844 fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(sym_evsel));
845 sleep(1); 531 sleep(1);
846 break; 532 break;
847 } 533 }
848 list_for_each_entry(sym_evsel, &evsel_list, node) 534 list_for_each_entry(top.sym_evsel, &top.evlist->entries, node)
849 if (sym_evsel->idx == sym_counter) 535 if (top.sym_evsel->idx == counter)
850 break; 536 break;
851 } else sym_counter = 0; 537 } else
538 top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node);
852 break; 539 break;
853 case 'f': 540 case 'f':
854 prompt_integer(&count_filter, "Enter display event count filter"); 541 prompt_integer(&top.count_filter, "Enter display event count filter");
855 break; 542 break;
856 case 'F': 543 case 'F':
857 prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)"); 544 prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)");
858 break; 545 break;
859 case 'K': 546 case 'K':
860 hide_kernel_symbols = !hide_kernel_symbols; 547 top.hide_kernel_symbols = !top.hide_kernel_symbols;
861 break; 548 break;
862 case 'q': 549 case 'q':
863 case 'Q': 550 case 'Q':
@@ -866,34 +553,50 @@ static void handle_keypress(struct perf_session *session, int c)
866 perf_session__fprintf_dsos(session, stderr); 553 perf_session__fprintf_dsos(session, stderr);
867 exit(0); 554 exit(0);
868 case 's': 555 case 's':
869 prompt_symbol(&sym_filter_entry, "Enter details symbol"); 556 prompt_symbol(&top.sym_filter_entry, "Enter details symbol");
870 break; 557 break;
871 case 'S': 558 case 'S':
872 if (!sym_filter_entry) 559 if (!top.sym_filter_entry)
873 break; 560 break;
874 else { 561 else {
875 struct sym_entry *syme = sym_filter_entry; 562 struct sym_entry *syme = top.sym_filter_entry;
876 563
877 pthread_mutex_lock(&syme->src->lock); 564 top.sym_filter_entry = NULL;
878 sym_filter_entry = NULL;
879 __zero_source_counters(syme); 565 __zero_source_counters(syme);
880 pthread_mutex_unlock(&syme->src->lock);
881 } 566 }
882 break; 567 break;
883 case 'U': 568 case 'U':
884 hide_user_symbols = !hide_user_symbols; 569 top.hide_user_symbols = !top.hide_user_symbols;
885 break; 570 break;
886 case 'w': 571 case 'w':
887 display_weighted = ~display_weighted; 572 top.display_weighted = ~top.display_weighted;
888 break; 573 break;
889 case 'z': 574 case 'z':
890 zero = !zero; 575 top.zero = !top.zero;
891 break; 576 break;
892 default: 577 default:
893 break; 578 break;
894 } 579 }
895} 580}
896 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
897static void *display_thread(void *arg __used) 600static void *display_thread(void *arg __used)
898{ 601{
899 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; 602 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
@@ -908,13 +611,13 @@ static void *display_thread(void *arg __used)
908 tc.c_cc[VTIME] = 0; 611 tc.c_cc[VTIME] = 0;
909 612
910repeat: 613repeat:
911 delay_msecs = delay_secs * 1000; 614 delay_msecs = top.delay_secs * 1000;
912 tcsetattr(0, TCSANOW, &tc); 615 tcsetattr(0, TCSANOW, &tc);
913 /* trash return*/ 616 /* trash return*/
914 getc(stdin); 617 getc(stdin);
915 618
916 do { 619 do {
917 print_sym_table(); 620 print_sym_table(session);
918 } while (!poll(&stdin_poll, 1, delay_msecs) == 1); 621 } while (!poll(&stdin_poll, 1, delay_msecs) == 1);
919 622
920 c = getc(stdin); 623 c = getc(stdin);
@@ -929,6 +632,7 @@ repeat:
929/* Tag samples to be skipped. */ 632/* Tag samples to be skipped. */
930static const char *skip_symbols[] = { 633static const char *skip_symbols[] = {
931 "default_idle", 634 "default_idle",
635 "native_safe_halt",
932 "cpu_idle", 636 "cpu_idle",
933 "enter_idle", 637 "enter_idle",
934 "exit_idle", 638 "exit_idle",
@@ -964,9 +668,9 @@ static int symbol_filter(struct map *map, struct symbol *sym)
964 668
965 syme = symbol__priv(sym); 669 syme = symbol__priv(sym);
966 syme->map = map; 670 syme->map = map;
967 syme->src = NULL; 671 symbol__annotate_init(map, sym);
968 672
969 if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) { 673 if (!top.sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) {
970 /* schedule initial sym_filter_entry setup */ 674 /* schedule initial sym_filter_entry setup */
971 sym_filter_entry_sched = syme; 675 sym_filter_entry_sched = syme;
972 sym_filter = NULL; 676 sym_filter = NULL;
@@ -974,49 +678,45 @@ static int symbol_filter(struct map *map, struct symbol *sym)
974 678
975 for (i = 0; skip_symbols[i]; i++) { 679 for (i = 0; skip_symbols[i]; i++) {
976 if (!strcmp(skip_symbols[i], name)) { 680 if (!strcmp(skip_symbols[i], name)) {
977 syme->skip = 1; 681 sym->ignore = true;
978 break; 682 break;
979 } 683 }
980 } 684 }
981 685
982 if (!syme->skip)
983 syme->name_len = strlen(sym->name);
984
985 return 0; 686 return 0;
986} 687}
987 688
988static void event__process_sample(const event_t *self, 689static void perf_event__process_sample(const union perf_event *event,
989 struct sample_data *sample, 690 struct perf_sample *sample,
990 struct perf_session *session, 691 struct perf_session *session)
991 struct perf_evsel *evsel)
992{ 692{
993 u64 ip = self->ip.ip; 693 u64 ip = event->ip.ip;
994 struct sym_entry *syme; 694 struct sym_entry *syme;
995 struct addr_location al; 695 struct addr_location al;
996 struct machine *machine; 696 struct machine *machine;
997 u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 697 u8 origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
998 698
999 ++samples; 699 ++top.samples;
1000 700
1001 switch (origin) { 701 switch (origin) {
1002 case PERF_RECORD_MISC_USER: 702 case PERF_RECORD_MISC_USER:
1003 ++us_samples; 703 ++top.us_samples;
1004 if (hide_user_symbols) 704 if (top.hide_user_symbols)
1005 return; 705 return;
1006 machine = perf_session__find_host_machine(session); 706 machine = perf_session__find_host_machine(session);
1007 break; 707 break;
1008 case PERF_RECORD_MISC_KERNEL: 708 case PERF_RECORD_MISC_KERNEL:
1009 ++kernel_samples; 709 ++top.kernel_samples;
1010 if (hide_kernel_symbols) 710 if (top.hide_kernel_symbols)
1011 return; 711 return;
1012 machine = perf_session__find_host_machine(session); 712 machine = perf_session__find_host_machine(session);
1013 break; 713 break;
1014 case PERF_RECORD_MISC_GUEST_KERNEL: 714 case PERF_RECORD_MISC_GUEST_KERNEL:
1015 ++guest_kernel_samples; 715 ++top.guest_kernel_samples;
1016 machine = perf_session__find_machine(session, self->ip.pid); 716 machine = perf_session__find_machine(session, event->ip.pid);
1017 break; 717 break;
1018 case PERF_RECORD_MISC_GUEST_USER: 718 case PERF_RECORD_MISC_GUEST_USER:
1019 ++guest_us_samples; 719 ++top.guest_us_samples;
1020 /* 720 /*
1021 * TODO: we don't process guest user from host side 721 * TODO: we don't process guest user from host side
1022 * except simple counting. 722 * except simple counting.
@@ -1028,15 +728,15 @@ static void event__process_sample(const event_t *self,
1028 728
1029 if (!machine && perf_guest) { 729 if (!machine && perf_guest) {
1030 pr_err("Can't find guest [%d]'s kernel information\n", 730 pr_err("Can't find guest [%d]'s kernel information\n",
1031 self->ip.pid); 731 event->ip.pid);
1032 return; 732 return;
1033 } 733 }
1034 734
1035 if (self->header.misc & PERF_RECORD_MISC_EXACT_IP) 735 if (event->header.misc & PERF_RECORD_MISC_EXACT_IP)
1036 exact_samples++; 736 top.exact_samples++;
1037 737
1038 if (event__preprocess_sample(self, session, &al, sample, 738 if (perf_event__preprocess_sample(event, session, &al, sample,
1039 symbol_filter) < 0 || 739 symbol_filter) < 0 ||
1040 al.filtered) 740 al.filtered)
1041 return; 741 return;
1042 742
@@ -1054,8 +754,9 @@ static void event__process_sample(const event_t *self,
1054 */ 754 */
1055 if (al.map == machine->vmlinux_maps[MAP__FUNCTION] && 755 if (al.map == machine->vmlinux_maps[MAP__FUNCTION] &&
1056 RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) { 756 RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) {
1057 pr_err("The %s file can't be used\n", 757 ui__warning("The %s file can't be used\n",
1058 symbol_conf.vmlinux_name); 758 symbol_conf.vmlinux_name);
759 exit_browser(0);
1059 exit(1); 760 exit(1);
1060 } 761 }
1061 762
@@ -1064,13 +765,13 @@ static void event__process_sample(const event_t *self,
1064 765
1065 /* 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 */
1066 if (sym_filter_entry_sched) { 767 if (sym_filter_entry_sched) {
1067 sym_filter_entry = sym_filter_entry_sched; 768 top.sym_filter_entry = sym_filter_entry_sched;
1068 sym_filter_entry_sched = NULL; 769 sym_filter_entry_sched = NULL;
1069 if (parse_source(sym_filter_entry) < 0) { 770 if (parse_source(top.sym_filter_entry) < 0) {
1070 struct symbol *sym = sym_entry__symbol(sym_filter_entry); 771 struct symbol *sym = sym_entry__symbol(top.sym_filter_entry);
1071 772
1072 pr_err("Can't annotate %s", sym->name); 773 pr_err("Can't annotate %s", sym->name);
1073 if (sym_filter_entry->map->dso->origin == DSO__ORIG_KERNEL) { 774 if (top.sym_filter_entry->map->dso->symtab_type == SYMTAB__KALLSYMS) {
1074 pr_err(": No vmlinux file was found in the path:\n"); 775 pr_err(": No vmlinux file was found in the path:\n");
1075 machine__fprintf_vmlinux_path(machine, stderr); 776 machine__fprintf_vmlinux_path(machine, stderr);
1076 } else 777 } else
@@ -1080,167 +781,73 @@ static void event__process_sample(const event_t *self,
1080 } 781 }
1081 782
1082 syme = symbol__priv(al.sym); 783 syme = symbol__priv(al.sym);
1083 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);
1084 syme->count[evsel->idx]++; 789 syme->count[evsel->idx]++;
1085 syme->origin = origin;
1086 record_precise_ip(syme, evsel->idx, ip); 790 record_precise_ip(syme, evsel->idx, ip);
1087 pthread_mutex_lock(&active_symbols_lock); 791 pthread_mutex_lock(&top.active_symbols_lock);
1088 if (list_empty(&syme->node) || !syme->node.next) 792 if (list_empty(&syme->node) || !syme->node.next) {
793 static bool first = true;
1089 __list_insert_active_sym(syme); 794 __list_insert_active_sym(syme);
1090 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);
1091 } 801 }
1092} 802}
1093 803
1094struct mmap_data { 804static void perf_session__mmap_read_cpu(struct perf_session *self, int cpu)
1095 void *base;
1096 int mask;
1097 unsigned int prev;
1098};
1099
1100static int perf_evsel__alloc_mmap_per_thread(struct perf_evsel *evsel,
1101 int ncpus, int nthreads)
1102{
1103 evsel->priv = xyarray__new(ncpus, nthreads, sizeof(struct mmap_data));
1104 return evsel->priv != NULL ? 0 : -ENOMEM;
1105}
1106
1107static void perf_evsel__free_mmap(struct perf_evsel *evsel)
1108{
1109 xyarray__delete(evsel->priv);
1110 evsel->priv = NULL;
1111}
1112
1113static unsigned int mmap_read_head(struct mmap_data *md)
1114{
1115 struct perf_event_mmap_page *pc = md->base;
1116 int head;
1117
1118 head = pc->data_head;
1119 rmb();
1120
1121 return head;
1122}
1123
1124static void perf_session__mmap_read_counter(struct perf_session *self,
1125 struct perf_evsel *evsel,
1126 int cpu, int thread_idx)
1127{ 805{
1128 struct xyarray *mmap_array = evsel->priv; 806 struct perf_sample sample;
1129 struct mmap_data *md = xyarray__entry(mmap_array, cpu, thread_idx); 807 union perf_event *event;
1130 unsigned int head = mmap_read_head(md);
1131 unsigned int old = md->prev;
1132 unsigned char *data = md->base + page_size;
1133 struct sample_data sample;
1134 int diff;
1135
1136 /*
1137 * If we're further behind than half the buffer, there's a chance
1138 * the writer will bite our tail and mess up the samples under us.
1139 *
1140 * If we somehow ended up ahead of the head, we got messed up.
1141 *
1142 * In either case, truncate and restart at head.
1143 */
1144 diff = head - old;
1145 if (diff > md->mask / 2 || diff < 0) {
1146 fprintf(stderr, "WARNING: failed to keep up with mmap data.\n");
1147
1148 /*
1149 * head points to a known good entry, start there.
1150 */
1151 old = head;
1152 }
1153
1154 for (; old != head;) {
1155 event_t *event = (event_t *)&data[old & md->mask];
1156
1157 event_t event_copy;
1158 808
1159 size_t size = event->header.size; 809 while ((event = perf_evlist__read_on_cpu(top.evlist, cpu)) != NULL) {
810 perf_session__parse_sample(self, event, &sample);
1160 811
1161 /*
1162 * Event straddles the mmap boundary -- header should always
1163 * be inside due to u64 alignment of output.
1164 */
1165 if ((old & md->mask) + size != ((old + size) & md->mask)) {
1166 unsigned int offset = old;
1167 unsigned int len = min(sizeof(*event), size), cpy;
1168 void *dst = &event_copy;
1169
1170 do {
1171 cpy = min(md->mask + 1 - (offset & md->mask), len);
1172 memcpy(dst, &data[offset & md->mask], cpy);
1173 offset += cpy;
1174 dst += cpy;
1175 len -= cpy;
1176 } while (len);
1177
1178 event = &event_copy;
1179 }
1180
1181 event__parse_sample(event, self, &sample);
1182 if (event->header.type == PERF_RECORD_SAMPLE) 812 if (event->header.type == PERF_RECORD_SAMPLE)
1183 event__process_sample(event, &sample, self, evsel); 813 perf_event__process_sample(event, &sample, self);
1184 else 814 else
1185 event__process(event, &sample, self); 815 perf_event__process(event, &sample, self);
1186 old += size;
1187 } 816 }
1188
1189 md->prev = old;
1190} 817}
1191 818
1192static struct pollfd *event_array;
1193
1194static void perf_session__mmap_read(struct perf_session *self) 819static void perf_session__mmap_read(struct perf_session *self)
1195{ 820{
1196 struct perf_evsel *counter; 821 int i;
1197 int i, thread_index;
1198
1199 for (i = 0; i < cpus->nr; i++) {
1200 list_for_each_entry(counter, &evsel_list, node) {
1201 for (thread_index = 0;
1202 thread_index < threads->nr;
1203 thread_index++) {
1204 perf_session__mmap_read_counter(self,
1205 counter, i, thread_index);
1206 }
1207 }
1208 }
1209}
1210 822
1211int nr_poll; 823 for (i = 0; i < top.evlist->cpus->nr; i++)
1212int group_fd; 824 perf_session__mmap_read_cpu(self, i);
825}
1213 826
1214static void start_counter(int i, struct perf_evsel *evsel) 827static void start_counters(struct perf_evlist *evlist)
1215{ 828{
1216 struct xyarray *mmap_array = evsel->priv; 829 struct perf_evsel *counter;
1217 struct mmap_data *mm;
1218 struct perf_event_attr *attr;
1219 int cpu = -1;
1220 int thread_index;
1221
1222 if (target_tid == -1)
1223 cpu = cpus->map[i];
1224 830
1225 attr = &evsel->attr; 831 list_for_each_entry(counter, &evlist->entries, node) {
832 struct perf_event_attr *attr = &counter->attr;
1226 833
1227 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; 834 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
1228 835
1229 if (freq) { 836 if (top.freq) {
1230 attr->sample_type |= PERF_SAMPLE_PERIOD; 837 attr->sample_type |= PERF_SAMPLE_PERIOD;
1231 attr->freq = 1; 838 attr->freq = 1;
1232 attr->sample_freq = freq; 839 attr->sample_freq = top.freq;
1233 } 840 }
1234 841
1235 attr->inherit = (cpu < 0) && inherit; 842 if (evlist->nr_entries > 1) {
1236 attr->mmap = 1; 843 attr->sample_type |= PERF_SAMPLE_ID;
844 attr->read_format |= PERF_FORMAT_ID;
845 }
1237 846
1238 for (thread_index = 0; thread_index < threads->nr; thread_index++) { 847 attr->mmap = 1;
1239try_again: 848try_again:
1240 FD(evsel, i, thread_index) = sys_perf_event_open(attr, 849 if (perf_evsel__open(counter, top.evlist->cpus,
1241 threads->map[thread_index], cpu, group_fd, 0); 850 top.evlist->threads, group, inherit) < 0) {
1242
1243 if (FD(evsel, i, thread_index) < 0) {
1244 int err = errno; 851 int err = errno;
1245 852
1246 if (err == EPERM || err == EACCES) 853 if (err == EPERM || err == EACCES)
@@ -1252,8 +859,8 @@ try_again:
1252 * based cpu-clock-tick sw counter, which 859 * based cpu-clock-tick sw counter, which
1253 * is always available even if no PMU support: 860 * is always available even if no PMU support:
1254 */ 861 */
1255 if (attr->type == PERF_TYPE_HARDWARE 862 if (attr->type == PERF_TYPE_HARDWARE &&
1256 && attr->config == PERF_COUNT_HW_CPU_CYCLES) { 863 attr->config == PERF_COUNT_HW_CPU_CYCLES) {
1257 864
1258 if (verbose) 865 if (verbose)
1259 warning(" ... trying to fall back to cpu-clock-ticks\n"); 866 warning(" ... trying to fall back to cpu-clock-ticks\n");
@@ -1263,39 +870,22 @@ try_again:
1263 goto try_again; 870 goto try_again;
1264 } 871 }
1265 printf("\n"); 872 printf("\n");
1266 error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n", 873 error("sys_perf_event_open() syscall returned with %d "
1267 FD(evsel, i, thread_index), strerror(err)); 874 "(%s). /bin/dmesg may provide additional information.\n",
875 err, strerror(err));
1268 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); 876 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
1269 exit(-1); 877 exit(-1);
1270 } 878 }
1271 assert(FD(evsel, i, thread_index) >= 0);
1272 fcntl(FD(evsel, i, thread_index), F_SETFL, O_NONBLOCK);
1273
1274 /*
1275 * First counter acts as the group leader:
1276 */
1277 if (group && group_fd == -1)
1278 group_fd = FD(evsel, i, thread_index);
1279
1280 event_array[nr_poll].fd = FD(evsel, i, thread_index);
1281 event_array[nr_poll].events = POLLIN;
1282 nr_poll++;
1283
1284 mm = xyarray__entry(mmap_array, i, thread_index);
1285 mm->prev = 0;
1286 mm->mask = mmap_pages*page_size - 1;
1287 mm->base = mmap(NULL, (mmap_pages+1)*page_size,
1288 PROT_READ, MAP_SHARED, FD(evsel, i, thread_index), 0);
1289 if (mm->base == MAP_FAILED)
1290 die("failed to mmap with %d (%s)\n", errno, strerror(errno));
1291 } 879 }
880
881 if (perf_evlist__mmap(evlist, mmap_pages, false) < 0)
882 die("failed to mmap with %d (%s)\n", errno, strerror(errno));
1292} 883}
1293 884
1294static int __cmd_top(void) 885static int __cmd_top(void)
1295{ 886{
1296 pthread_t thread; 887 pthread_t thread;
1297 struct perf_evsel *counter; 888 int ret __used;
1298 int i, ret;
1299 /* 889 /*
1300 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this 890 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this
1301 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now. 891 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now.
@@ -1304,23 +894,23 @@ static int __cmd_top(void)
1304 if (session == NULL) 894 if (session == NULL)
1305 return -ENOMEM; 895 return -ENOMEM;
1306 896
1307 if (target_tid != -1) 897 if (top.target_tid != -1)
1308 event__synthesize_thread(target_tid, event__process, session); 898 perf_event__synthesize_thread_map(top.evlist->threads,
899 perf_event__process, session);
1309 else 900 else
1310 event__synthesize_threads(event__process, session); 901 perf_event__synthesize_threads(perf_event__process, session);
1311 902
1312 for (i = 0; i < cpus->nr; i++) { 903 start_counters(top.evlist);
1313 group_fd = -1; 904 session->evlist = top.evlist;
1314 list_for_each_entry(counter, &evsel_list, node) 905 perf_session__update_sample_type(session);
1315 start_counter(i, counter);
1316 }
1317 906
1318 /* Wait for a minimal set of events before starting the snapshot */ 907 /* Wait for a minimal set of events before starting the snapshot */
1319 poll(&event_array[0], nr_poll, 100); 908 poll(top.evlist->pollfd, top.evlist->nr_fds, 100);
1320 909
1321 perf_session__mmap_read(session); 910 perf_session__mmap_read(session);
1322 911
1323 if (pthread_create(&thread, NULL, display_thread, session)) { 912 if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui :
913 display_thread), session)) {
1324 printf("Could not create display thread.\n"); 914 printf("Could not create display thread.\n");
1325 exit(-1); 915 exit(-1);
1326 } 916 }
@@ -1336,12 +926,12 @@ static int __cmd_top(void)
1336 } 926 }
1337 927
1338 while (1) { 928 while (1) {
1339 int hits = samples; 929 u64 hits = top.samples;
1340 930
1341 perf_session__mmap_read(session); 931 perf_session__mmap_read(session);
1342 932
1343 if (hits == samples) 933 if (hits == top.samples)
1344 ret = poll(event_array, nr_poll, 100); 934 ret = poll(top.evlist->pollfd, top.evlist->nr_fds, 100);
1345 } 935 }
1346 936
1347 return 0; 937 return 0;
@@ -1353,31 +943,31 @@ static const char * const top_usage[] = {
1353}; 943};
1354 944
1355static const struct option options[] = { 945static const struct option options[] = {
1356 OPT_CALLBACK('e', "event", NULL, "event", 946 OPT_CALLBACK('e', "event", &top.evlist, "event",
1357 "event selector. use 'perf list' to list available events", 947 "event selector. use 'perf list' to list available events",
1358 parse_events), 948 parse_events),
1359 OPT_INTEGER('c', "count", &default_interval, 949 OPT_INTEGER('c', "count", &default_interval,
1360 "event period to sample"), 950 "event period to sample"),
1361 OPT_INTEGER('p', "pid", &target_pid, 951 OPT_INTEGER('p', "pid", &top.target_pid,
1362 "profile events on existing process id"), 952 "profile events on existing process id"),
1363 OPT_INTEGER('t', "tid", &target_tid, 953 OPT_INTEGER('t', "tid", &top.target_tid,
1364 "profile events on existing thread id"), 954 "profile events on existing thread id"),
1365 OPT_BOOLEAN('a', "all-cpus", &system_wide, 955 OPT_BOOLEAN('a', "all-cpus", &system_wide,
1366 "system-wide collection from all CPUs"), 956 "system-wide collection from all CPUs"),
1367 OPT_STRING('C', "cpu", &cpu_list, "cpu", 957 OPT_STRING('C', "cpu", &top.cpu_list, "cpu",
1368 "list of cpus to monitor"), 958 "list of cpus to monitor"),
1369 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 959 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
1370 "file", "vmlinux pathname"), 960 "file", "vmlinux pathname"),
1371 OPT_BOOLEAN('K', "hide_kernel_symbols", &hide_kernel_symbols, 961 OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols,
1372 "hide kernel symbols"), 962 "hide kernel symbols"),
1373 OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"), 963 OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"),
1374 OPT_INTEGER('r', "realtime", &realtime_prio, 964 OPT_INTEGER('r', "realtime", &realtime_prio,
1375 "collect data with this RT SCHED_FIFO priority"), 965 "collect data with this RT SCHED_FIFO priority"),
1376 OPT_INTEGER('d', "delay", &delay_secs, 966 OPT_INTEGER('d', "delay", &top.delay_secs,
1377 "number of seconds to delay between refreshes"), 967 "number of seconds to delay between refreshes"),
1378 OPT_BOOLEAN('D', "dump-symtab", &dump_symtab, 968 OPT_BOOLEAN('D', "dump-symtab", &dump_symtab,
1379 "dump the symbol table used for profiling"), 969 "dump the symbol table used for profiling"),
1380 OPT_INTEGER('f', "count-filter", &count_filter, 970 OPT_INTEGER('f', "count-filter", &top.count_filter,
1381 "only display functions with more events than this"), 971 "only display functions with more events than this"),
1382 OPT_BOOLEAN('g', "group", &group, 972 OPT_BOOLEAN('g', "group", &group,
1383 "put the counters into a counter group"), 973 "put the counters into a counter group"),
@@ -1385,14 +975,16 @@ static const struct option options[] = {
1385 "child tasks inherit counters"), 975 "child tasks inherit counters"),
1386 OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name", 976 OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name",
1387 "symbol to annotate"), 977 "symbol to annotate"),
1388 OPT_BOOLEAN('z', "zero", &zero, 978 OPT_BOOLEAN('z', "zero", &top.zero,
1389 "zero history across updates"), 979 "zero history across updates"),
1390 OPT_INTEGER('F', "freq", &freq, 980 OPT_INTEGER('F', "freq", &top.freq,
1391 "profile at this frequency"), 981 "profile at this frequency"),
1392 OPT_INTEGER('E', "entries", &print_entries, 982 OPT_INTEGER('E', "entries", &top.print_entries,
1393 "display this many functions"), 983 "display this many functions"),
1394 OPT_BOOLEAN('U', "hide_user_symbols", &hide_user_symbols, 984 OPT_BOOLEAN('U', "hide_user_symbols", &top.hide_user_symbols,
1395 "hide user symbols"), 985 "hide user symbols"),
986 OPT_BOOLEAN(0, "tui", &use_tui, "Use the TUI interface"),
987 OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"),
1396 OPT_INCR('v', "verbose", &verbose, 988 OPT_INCR('v', "verbose", &verbose,
1397 "be more verbose (show counter open errors, etc)"), 989 "be more verbose (show counter open errors, etc)"),
1398 OPT_END() 990 OPT_END()
@@ -1403,64 +995,68 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1403 struct perf_evsel *pos; 995 struct perf_evsel *pos;
1404 int status = -ENOMEM; 996 int status = -ENOMEM;
1405 997
998 top.evlist = perf_evlist__new(NULL, NULL);
999 if (top.evlist == NULL)
1000 return -ENOMEM;
1001
1406 page_size = sysconf(_SC_PAGE_SIZE); 1002 page_size = sysconf(_SC_PAGE_SIZE);
1407 1003
1408 argc = parse_options(argc, argv, options, top_usage, 0); 1004 argc = parse_options(argc, argv, options, top_usage, 0);
1409 if (argc) 1005 if (argc)
1410 usage_with_options(top_usage, options); 1006 usage_with_options(top_usage, options);
1411 1007
1412 if (target_pid != -1) 1008 /*
1413 target_tid = target_pid; 1009 * XXX For now start disabled, only using TUI if explicitely asked for.
1010 * Change that when handle_keys equivalent gets written, live annotation
1011 * done, etc.
1012 */
1013 use_browser = 0;
1414 1014
1415 threads = thread_map__new(target_pid, target_tid); 1015 if (use_stdio)
1416 if (threads == NULL) { 1016 use_browser = 0;
1417 pr_err("Problems finding threads of monitor\n"); 1017 else if (use_tui)
1418 usage_with_options(top_usage, options); 1018 use_browser = 1;
1419 }
1420 1019
1421 event_array = malloc((sizeof(struct pollfd) * 1020 setup_browser(false);
1422 MAX_NR_CPUS * MAX_COUNTERS * threads->nr));
1423 if (!event_array)
1424 return -ENOMEM;
1425 1021
1426 /* CPU and PID are mutually exclusive */ 1022 /* CPU and PID are mutually exclusive */
1427 if (target_tid > 0 && cpu_list) { 1023 if (top.target_tid > 0 && top.cpu_list) {
1428 printf("WARNING: PID switch overriding CPU\n"); 1024 printf("WARNING: PID switch overriding CPU\n");
1429 sleep(1); 1025 sleep(1);
1430 cpu_list = NULL; 1026 top.cpu_list = NULL;
1431 } 1027 }
1432 1028
1433 if (!nr_counters && perf_evsel_list__create_default() < 0) { 1029 if (top.target_pid != -1)
1030 top.target_tid = top.target_pid;
1031
1032 if (perf_evlist__create_maps(top.evlist, top.target_pid,
1033 top.target_tid, top.cpu_list) < 0)
1034 usage_with_options(top_usage, options);
1035
1036 if (!top.evlist->nr_entries &&
1037 perf_evlist__add_default(top.evlist) < 0) {
1434 pr_err("Not enough memory for event selector list\n"); 1038 pr_err("Not enough memory for event selector list\n");
1435 return -ENOMEM; 1039 return -ENOMEM;
1436 } 1040 }
1437 1041
1438 if (delay_secs < 1) 1042 if (top.delay_secs < 1)
1439 delay_secs = 1; 1043 top.delay_secs = 1;
1440 1044
1441 /* 1045 /*
1442 * User specified count overrides default frequency. 1046 * User specified count overrides default frequency.
1443 */ 1047 */
1444 if (default_interval) 1048 if (default_interval)
1445 freq = 0; 1049 top.freq = 0;
1446 else if (freq) { 1050 else if (top.freq) {
1447 default_interval = freq; 1051 default_interval = top.freq;
1448 } else { 1052 } else {
1449 fprintf(stderr, "frequency and count are zero, aborting\n"); 1053 fprintf(stderr, "frequency and count are zero, aborting\n");
1450 exit(EXIT_FAILURE); 1054 exit(EXIT_FAILURE);
1451 } 1055 }
1452 1056
1453 if (target_tid != -1) 1057 list_for_each_entry(pos, &top.evlist->entries, node) {
1454 cpus = cpu_map__dummy_new(); 1058 if (perf_evsel__alloc_fd(pos, top.evlist->cpus->nr,
1455 else 1059 top.evlist->threads->nr) < 0)
1456 cpus = cpu_map__new(cpu_list);
1457
1458 if (cpus == NULL)
1459 usage_with_options(top_usage, options);
1460
1461 list_for_each_entry(pos, &evsel_list, node) {
1462 if (perf_evsel__alloc_mmap_per_thread(pos, cpus->nr, threads->nr) < 0 ||
1463 perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0)
1464 goto out_free_fd; 1060 goto out_free_fd;
1465 /* 1061 /*
1466 * Fill in the ones not specifically initialized via -c: 1062 * Fill in the ones not specifically initialized via -c:
@@ -1471,26 +1067,28 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1471 pos->attr.sample_period = default_interval; 1067 pos->attr.sample_period = default_interval;
1472 } 1068 }
1473 1069
1474 sym_evsel = list_entry(evsel_list.next, struct perf_evsel, node); 1070 if (perf_evlist__alloc_pollfd(top.evlist) < 0 ||
1071 perf_evlist__alloc_mmap(top.evlist) < 0)
1072 goto out_free_fd;
1073
1074 top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node);
1475 1075
1476 symbol_conf.priv_size = (sizeof(struct sym_entry) + 1076 symbol_conf.priv_size = (sizeof(struct sym_entry) + sizeof(struct annotation) +
1477 (nr_counters + 1) * sizeof(unsigned long)); 1077 (top.evlist->nr_entries + 1) * sizeof(unsigned long));
1478 1078
1479 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); 1079 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
1480 if (symbol__init() < 0) 1080 if (symbol__init() < 0)
1481 return -1; 1081 return -1;
1482 1082
1483 get_term_dimensions(&winsize); 1083 get_term_dimensions(&winsize);
1484 if (print_entries == 0) { 1084 if (top.print_entries == 0) {
1485 update_print_entries(&winsize); 1085 update_print_entries(&winsize);
1486 signal(SIGWINCH, sig_winch_handler); 1086 signal(SIGWINCH, sig_winch_handler);
1487 } 1087 }
1488 1088
1489 status = __cmd_top(); 1089 status = __cmd_top();
1490out_free_fd: 1090out_free_fd:
1491 list_for_each_entry(pos, &evsel_list, node) 1091 perf_evlist__delete(top.evlist);
1492 perf_evsel__free_mmap(pos);
1493 perf_evsel_list__delete();
1494 1092
1495 return status; 1093 return status;
1496} 1094}
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..9fea75535221
--- /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;
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..d4536a9e0d8c 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -57,7 +57,7 @@ void ui__warning(const char *format, ...)
57} 57}
58#endif 58#endif
59 59
60void trace_event(event_t *event) 60void trace_event(union perf_event *event)
61{ 61{
62 unsigned char *raw_event = (void *)event; 62 unsigned char *raw_event = (void *)event;
63 const char *color = PERF_COLOR_BLUE; 63 const char *color = PERF_COLOR_BLUE;
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index ca35fd66b5df..93516cf4682c 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
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 2302ec051bb4..2b15c362ef56 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,18 +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:%Ld: lost:%Ld\n", self->lost.id, self->lost.lost); 447 dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n",
463 session->hists.stats.total_lost += self->lost.lost; 448 event->lost.id, event->lost.lost);
449 session->hists.stats.total_lost += event->lost.lost;
464 return 0; 450 return 0;
465} 451}
466 452
467static 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)
468{ 455{
469 maps[MAP__FUNCTION]->start = self->mmap.start; 456 maps[MAP__FUNCTION]->start = event->mmap.start;
470 maps[MAP__FUNCTION]->end = self->mmap.start + self->mmap.len; 457 maps[MAP__FUNCTION]->end = event->mmap.start + event->mmap.len;
471 /* 458 /*
472 * Be a bit paranoid here, some perf.data file came with 459 * Be a bit paranoid here, some perf.data file came with
473 * a zero sized synthesized MMAP event for the kernel. 460 * a zero sized synthesized MMAP event for the kernel.
@@ -476,8 +463,8 @@ static void event_set_kernel_mmap_len(struct map **maps, event_t *self)
476 maps[MAP__FUNCTION]->end = ~0ULL; 463 maps[MAP__FUNCTION]->end = ~0ULL;
477} 464}
478 465
479static int event__process_kernel_mmap(event_t *self, 466static int perf_event__process_kernel_mmap(union perf_event *event,
480 struct perf_session *session) 467 struct perf_session *session)
481{ 468{
482 struct map *map; 469 struct map *map;
483 char kmmap_prefix[PATH_MAX]; 470 char kmmap_prefix[PATH_MAX];
@@ -485,9 +472,9 @@ static int event__process_kernel_mmap(event_t *self,
485 enum dso_kernel_type kernel_type; 472 enum dso_kernel_type kernel_type;
486 bool is_kernel_mmap; 473 bool is_kernel_mmap;
487 474
488 machine = perf_session__findnew_machine(session, self->mmap.pid); 475 machine = perf_session__findnew_machine(session, event->mmap.pid);
489 if (!machine) { 476 if (!machine) {
490 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);
491 goto out_problem; 478 goto out_problem;
492 } 479 }
493 480
@@ -497,17 +484,17 @@ static int event__process_kernel_mmap(event_t *self,
497 else 484 else
498 kernel_type = DSO_TYPE_GUEST_KERNEL; 485 kernel_type = DSO_TYPE_GUEST_KERNEL;
499 486
500 is_kernel_mmap = memcmp(self->mmap.filename, 487 is_kernel_mmap = memcmp(event->mmap.filename,
501 kmmap_prefix, 488 kmmap_prefix,
502 strlen(kmmap_prefix)) == 0; 489 strlen(kmmap_prefix)) == 0;
503 if (self->mmap.filename[0] == '/' || 490 if (event->mmap.filename[0] == '/' ||
504 (!is_kernel_mmap && self->mmap.filename[0] == '[')) { 491 (!is_kernel_mmap && event->mmap.filename[0] == '[')) {
505 492
506 char short_module_name[1024]; 493 char short_module_name[1024];
507 char *name, *dot; 494 char *name, *dot;
508 495
509 if (self->mmap.filename[0] == '/') { 496 if (event->mmap.filename[0] == '/') {
510 name = strrchr(self->mmap.filename, '/'); 497 name = strrchr(event->mmap.filename, '/');
511 if (name == NULL) 498 if (name == NULL)
512 goto out_problem; 499 goto out_problem;
513 500
@@ -519,10 +506,10 @@ static int event__process_kernel_mmap(event_t *self,
519 "[%.*s]", (int)(dot - name), name); 506 "[%.*s]", (int)(dot - name), name);
520 strxfrchar(short_module_name, '-', '_'); 507 strxfrchar(short_module_name, '-', '_');
521 } else 508 } else
522 strcpy(short_module_name, self->mmap.filename); 509 strcpy(short_module_name, event->mmap.filename);
523 510
524 map = machine__new_module(machine, self->mmap.start, 511 map = machine__new_module(machine, event->mmap.start,
525 self->mmap.filename); 512 event->mmap.filename);
526 if (map == NULL) 513 if (map == NULL)
527 goto out_problem; 514 goto out_problem;
528 515
@@ -532,9 +519,9 @@ static int event__process_kernel_mmap(event_t *self,
532 519
533 map->dso->short_name = name; 520 map->dso->short_name = name;
534 map->dso->sname_alloc = 1; 521 map->dso->sname_alloc = 1;
535 map->end = map->start + self->mmap.len; 522 map->end = map->start + event->mmap.len;
536 } else if (is_kernel_mmap) { 523 } else if (is_kernel_mmap) {
537 const char *symbol_name = (self->mmap.filename + 524 const char *symbol_name = (event->mmap.filename +
538 strlen(kmmap_prefix)); 525 strlen(kmmap_prefix));
539 /* 526 /*
540 * Should be there already, from the build-id table in 527 * Should be there already, from the build-id table in
@@ -549,10 +536,10 @@ static int event__process_kernel_mmap(event_t *self,
549 if (__machine__create_kernel_maps(machine, kernel) < 0) 536 if (__machine__create_kernel_maps(machine, kernel) < 0)
550 goto out_problem; 537 goto out_problem;
551 538
552 event_set_kernel_mmap_len(machine->vmlinux_maps, self); 539 perf_event__set_kernel_mmap_len(event, machine->vmlinux_maps);
553 perf_session__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps, 540 perf_session__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps,
554 symbol_name, 541 symbol_name,
555 self->mmap.pgoff); 542 event->mmap.pgoff);
556 if (machine__is_default_guest(machine)) { 543 if (machine__is_default_guest(machine)) {
557 /* 544 /*
558 * preload dso of guest kernel and modules 545 * preload dso of guest kernel and modules
@@ -566,22 +553,23 @@ out_problem:
566 return -1; 553 return -1;
567} 554}
568 555
569int event__process_mmap(event_t *self, struct sample_data *sample __used, 556int perf_event__process_mmap(union perf_event *event,
570 struct perf_session *session) 557 struct perf_sample *sample __used,
558 struct perf_session *session)
571{ 559{
572 struct machine *machine; 560 struct machine *machine;
573 struct thread *thread; 561 struct thread *thread;
574 struct map *map; 562 struct map *map;
575 u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 563 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
576 int ret = 0; 564 int ret = 0;
577 565
578 dump_printf(" %d/%d: [%#Lx(%#Lx) @ %#Lx]: %s\n", 566 dump_printf(" %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %s\n",
579 self->mmap.pid, self->mmap.tid, self->mmap.start, 567 event->mmap.pid, event->mmap.tid, event->mmap.start,
580 self->mmap.len, self->mmap.pgoff, self->mmap.filename); 568 event->mmap.len, event->mmap.pgoff, event->mmap.filename);
581 569
582 if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL || 570 if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
583 cpumode == PERF_RECORD_MISC_KERNEL) { 571 cpumode == PERF_RECORD_MISC_KERNEL) {
584 ret = event__process_kernel_mmap(self, session); 572 ret = perf_event__process_kernel_mmap(event, session);
585 if (ret < 0) 573 if (ret < 0)
586 goto out_problem; 574 goto out_problem;
587 return 0; 575 return 0;
@@ -590,12 +578,12 @@ int event__process_mmap(event_t *self, struct sample_data *sample __used,
590 machine = perf_session__find_host_machine(session); 578 machine = perf_session__find_host_machine(session);
591 if (machine == NULL) 579 if (machine == NULL)
592 goto out_problem; 580 goto out_problem;
593 thread = perf_session__findnew(session, self->mmap.pid); 581 thread = perf_session__findnew(session, event->mmap.pid);
594 if (thread == NULL) 582 if (thread == NULL)
595 goto out_problem; 583 goto out_problem;
596 map = map__new(&machine->user_dsos, self->mmap.start, 584 map = map__new(&machine->user_dsos, event->mmap.start,
597 self->mmap.len, self->mmap.pgoff, 585 event->mmap.len, event->mmap.pgoff,
598 self->mmap.pid, self->mmap.filename, 586 event->mmap.pid, event->mmap.filename,
599 MAP__FUNCTION); 587 MAP__FUNCTION);
600 if (map == NULL) 588 if (map == NULL)
601 goto out_problem; 589 goto out_problem;
@@ -608,16 +596,17 @@ out_problem:
608 return 0; 596 return 0;
609} 597}
610 598
611int event__process_task(event_t *self, struct sample_data *sample __used, 599int perf_event__process_task(union perf_event *event,
612 struct perf_session *session) 600 struct perf_sample *sample __used,
601 struct perf_session *session)
613{ 602{
614 struct thread *thread = perf_session__findnew(session, self->fork.tid); 603 struct thread *thread = perf_session__findnew(session, event->fork.tid);
615 struct thread *parent = perf_session__findnew(session, self->fork.ptid); 604 struct thread *parent = perf_session__findnew(session, event->fork.ptid);
616 605
617 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,
618 self->fork.ppid, self->fork.ptid); 607 event->fork.ppid, event->fork.ptid);
619 608
620 if (self->header.type == PERF_RECORD_EXIT) { 609 if (event->header.type == PERF_RECORD_EXIT) {
621 perf_session__remove_thread(session, thread); 610 perf_session__remove_thread(session, thread);
622 return 0; 611 return 0;
623 } 612 }
@@ -631,20 +620,22 @@ int event__process_task(event_t *self, struct sample_data *sample __used,
631 return 0; 620 return 0;
632} 621}
633 622
634int event__process(event_t *event, struct sample_data *sample, 623int perf_event__process(union perf_event *event, struct perf_sample *sample,
635 struct perf_session *session) 624 struct perf_session *session)
636{ 625{
637 switch (event->header.type) { 626 switch (event->header.type) {
638 case PERF_RECORD_COMM: 627 case PERF_RECORD_COMM:
639 event__process_comm(event, sample, session); 628 perf_event__process_comm(event, sample, session);
640 break; 629 break;
641 case PERF_RECORD_MMAP: 630 case PERF_RECORD_MMAP:
642 event__process_mmap(event, sample, session); 631 perf_event__process_mmap(event, sample, session);
643 break; 632 break;
644 case PERF_RECORD_FORK: 633 case PERF_RECORD_FORK:
645 case PERF_RECORD_EXIT: 634 case PERF_RECORD_EXIT:
646 event__process_task(event, sample, session); 635 perf_event__process_task(event, sample, session);
647 break; 636 break;
637 case PERF_RECORD_LOST:
638 perf_event__process_lost(event, sample, session);
648 default: 639 default:
649 break; 640 break;
650 } 641 }
@@ -741,24 +732,14 @@ void thread__find_addr_location(struct thread *self,
741 al->sym = NULL; 732 al->sym = NULL;
742} 733}
743 734
744static void dso__calc_col_width(struct dso *self, struct hists *hists) 735int perf_event__preprocess_sample(const union perf_event *event,
745{ 736 struct perf_session *session,
746 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep && 737 struct addr_location *al,
747 (!symbol_conf.dso_list || 738 struct perf_sample *sample,
748 strlist__has_entry(symbol_conf.dso_list, self->name))) { 739 symbol_filter_t filter)
749 u16 slen = dso__name_len(self);
750 hists__new_col_len(hists, HISTC_DSO, slen);
751 }
752
753 self->slen_calculated = 1;
754}
755
756int event__preprocess_sample(const event_t *self, struct perf_session *session,
757 struct addr_location *al, struct sample_data *data,
758 symbol_filter_t filter)
759{ 740{
760 u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 741 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
761 struct thread *thread = perf_session__findnew(session, self->ip.pid); 742 struct thread *thread = perf_session__findnew(session, event->ip.pid);
762 743
763 if (thread == NULL) 744 if (thread == NULL)
764 return -1; 745 return -1;
@@ -780,12 +761,12 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session,
780 machine__create_kernel_maps(&session->host_machine); 761 machine__create_kernel_maps(&session->host_machine);
781 762
782 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION, 763 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION,
783 self->ip.pid, self->ip.ip, al); 764 event->ip.pid, event->ip.ip, al);
784 dump_printf(" ...... dso: %s\n", 765 dump_printf(" ...... dso: %s\n",
785 al->map ? al->map->dso->long_name : 766 al->map ? al->map->dso->long_name :
786 al->level == 'H' ? "[hypervisor]" : "<not found>"); 767 al->level == 'H' ? "[hypervisor]" : "<not found>");
787 al->sym = NULL; 768 al->sym = NULL;
788 al->cpu = data->cpu; 769 al->cpu = sample->cpu;
789 770
790 if (al->map) { 771 if (al->map) {
791 if (symbol_conf.dso_list && 772 if (symbol_conf.dso_list &&
@@ -796,23 +777,8 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session,
796 strlist__has_entry(symbol_conf.dso_list, 777 strlist__has_entry(symbol_conf.dso_list,
797 al->map->dso->long_name))))) 778 al->map->dso->long_name)))))
798 goto out_filtered; 779 goto out_filtered;
799 /*
800 * We have to do this here as we may have a dso with no symbol
801 * hit that has a name longer than the ones with symbols
802 * sampled.
803 */
804 if (!sort_dso.elide && !al->map->dso->slen_calculated)
805 dso__calc_col_width(al->map->dso, &session->hists);
806 780
807 al->sym = map__find_symbol(al->map, al->addr, filter); 781 al->sym = map__find_symbol(al->map, al->addr, filter);
808 } else {
809 const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
810
811 if (hists__col_len(&session->hists, HISTC_DSO) < unresolved_col_width &&
812 !symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
813 !symbol_conf.dso_list)
814 hists__set_col_len(&session->hists, HISTC_DSO,
815 unresolved_col_width);
816 } 782 }
817 783
818 if (symbol_conf.sym_list && al->sym && 784 if (symbol_conf.sym_list && al->sym &&
@@ -825,128 +791,3 @@ out_filtered:
825 al->filtered = true; 791 al->filtered = true;
826 return 0; 792 return 0;
827} 793}
828
829static int event__parse_id_sample(const event_t *event,
830 struct perf_session *session,
831 struct sample_data *sample)
832{
833 const u64 *array;
834 u64 type;
835
836 sample->cpu = sample->pid = sample->tid = -1;
837 sample->stream_id = sample->id = sample->time = -1ULL;
838
839 if (!session->sample_id_all)
840 return 0;
841
842 array = event->sample.array;
843 array += ((event->header.size -
844 sizeof(event->header)) / sizeof(u64)) - 1;
845 type = session->sample_type;
846
847 if (type & PERF_SAMPLE_CPU) {
848 u32 *p = (u32 *)array;
849 sample->cpu = *p;
850 array--;
851 }
852
853 if (type & PERF_SAMPLE_STREAM_ID) {
854 sample->stream_id = *array;
855 array--;
856 }
857
858 if (type & PERF_SAMPLE_ID) {
859 sample->id = *array;
860 array--;
861 }
862
863 if (type & PERF_SAMPLE_TIME) {
864 sample->time = *array;
865 array--;
866 }
867
868 if (type & PERF_SAMPLE_TID) {
869 u32 *p = (u32 *)array;
870 sample->pid = p[0];
871 sample->tid = p[1];
872 }
873
874 return 0;
875}
876
877int event__parse_sample(const event_t *event, struct perf_session *session,
878 struct sample_data *data)
879{
880 const u64 *array;
881 u64 type;
882
883 if (event->header.type != PERF_RECORD_SAMPLE)
884 return event__parse_id_sample(event, session, data);
885
886 array = event->sample.array;
887 type = session->sample_type;
888
889 if (type & PERF_SAMPLE_IP) {
890 data->ip = event->ip.ip;
891 array++;
892 }
893
894 if (type & PERF_SAMPLE_TID) {
895 u32 *p = (u32 *)array;
896 data->pid = p[0];
897 data->tid = p[1];
898 array++;
899 }
900
901 if (type & PERF_SAMPLE_TIME) {
902 data->time = *array;
903 array++;
904 }
905
906 if (type & PERF_SAMPLE_ADDR) {
907 data->addr = *array;
908 array++;
909 }
910
911 data->id = -1ULL;
912 if (type & PERF_SAMPLE_ID) {
913 data->id = *array;
914 array++;
915 }
916
917 if (type & PERF_SAMPLE_STREAM_ID) {
918 data->stream_id = *array;
919 array++;
920 }
921
922 if (type & PERF_SAMPLE_CPU) {
923 u32 *p = (u32 *)array;
924 data->cpu = *p;
925 array++;
926 } else
927 data->cpu = -1;
928
929 if (type & PERF_SAMPLE_PERIOD) {
930 data->period = *array;
931 array++;
932 }
933
934 if (type & PERF_SAMPLE_READ) {
935 pr_debug("PERF_SAMPLE_READ is unsuported for now\n");
936 return -1;
937 }
938
939 if (type & PERF_SAMPLE_CALLCHAIN) {
940 data->callchain = (struct ip_callchain *)array;
941 array += 1 + data->callchain->nr;
942 }
943
944 if (type & PERF_SAMPLE_RAW) {
945 u32 *p = (u32 *)array;
946 data->raw_size = *p;
947 p++;
948 data->raw_data = p;
949 }
950
951 return 0;
952}
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 989fa2dee2fd..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 %Ld offset for feature %d, " 789 pr_debug("Failed to lseek to %" PRIu64 " offset for feature "
802 "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 c749ba6136a0..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;
@@ -636,13 +654,13 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
636 } 654 }
637 } 655 }
638 } else 656 } else
639 ret = snprintf(s, size, sep ? "%lld" : "%12lld ", period); 657 ret = snprintf(s, size, sep ? "%" PRIu64 : "%12" PRIu64 " ", period);
640 658
641 if (symbol_conf.show_nr_samples) { 659 if (symbol_conf.show_nr_samples) {
642 if (sep) 660 if (sep)
643 ret += snprintf(s + ret, size - ret, "%c%lld", *sep, period); 661 ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, nr_events);
644 else 662 else
645 ret += snprintf(s + ret, size - ret, "%11lld", period); 663 ret += snprintf(s + ret, size - ret, "%11" PRIu64, nr_events);
646 } 664 }
647 665
648 if (pair_hists) { 666 if (pair_hists) {
@@ -944,224 +962,14 @@ void hists__filter_by_thread(struct hists *self, const struct thread *thread)
944 } 962 }
945} 963}
946 964
947static int symbol__alloc_hist(struct symbol *self) 965int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip)
948{
949 struct sym_priv *priv = symbol__priv(self);
950 const int size = (sizeof(*priv->hist) +
951 (self->end - self->start) * sizeof(u64));
952
953 priv->hist = zalloc(size);
954 return priv->hist == NULL ? -1 : 0;
955}
956
957int hist_entry__inc_addr_samples(struct hist_entry *self, u64 ip)
958{
959 unsigned int sym_size, offset;
960 struct symbol *sym = self->ms.sym;
961 struct sym_priv *priv;
962 struct sym_hist *h;
963
964 if (!sym || !self->ms.map)
965 return 0;
966
967 priv = symbol__priv(sym);
968 if (priv->hist == NULL && symbol__alloc_hist(sym) < 0)
969 return -ENOMEM;
970
971 sym_size = sym->end - sym->start;
972 offset = ip - sym->start;
973
974 pr_debug3("%s: ip=%#Lx\n", __func__, self->ms.map->unmap_ip(self->ms.map, ip));
975
976 if (offset >= sym_size)
977 return 0;
978
979 h = priv->hist;
980 h->sum++;
981 h->ip[offset]++;
982
983 pr_debug3("%#Lx %s: period++ [ip: %#Lx, %#Lx] => %Ld\n", self->ms.sym->start,
984 self->ms.sym->name, ip, ip - self->ms.sym->start, h->ip[offset]);
985 return 0;
986}
987
988static struct objdump_line *objdump_line__new(s64 offset, char *line, size_t privsize)
989{
990 struct objdump_line *self = malloc(sizeof(*self) + privsize);
991
992 if (self != NULL) {
993 self->offset = offset;
994 self->line = line;
995 }
996
997 return self;
998}
999
1000void objdump_line__free(struct objdump_line *self)
1001{
1002 free(self->line);
1003 free(self);
1004}
1005
1006static void objdump__add_line(struct list_head *head, struct objdump_line *line)
1007{
1008 list_add_tail(&line->node, head);
1009}
1010
1011struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
1012 struct objdump_line *pos)
1013{
1014 list_for_each_entry_continue(pos, head, node)
1015 if (pos->offset >= 0)
1016 return pos;
1017
1018 return NULL;
1019}
1020
1021static int hist_entry__parse_objdump_line(struct hist_entry *self, FILE *file,
1022 struct list_head *head, size_t privsize)
1023{ 966{
1024 struct symbol *sym = self->ms.sym; 967 return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip);
1025 struct objdump_line *objdump_line;
1026 char *line = NULL, *tmp, *tmp2, *c;
1027 size_t line_len;
1028 s64 line_ip, offset = -1;
1029
1030 if (getline(&line, &line_len, file) < 0)
1031 return -1;
1032
1033 if (!line)
1034 return -1;
1035
1036 while (line_len != 0 && isspace(line[line_len - 1]))
1037 line[--line_len] = '\0';
1038
1039 c = strchr(line, '\n');
1040 if (c)
1041 *c = 0;
1042
1043 line_ip = -1;
1044
1045 /*
1046 * Strip leading spaces:
1047 */
1048 tmp = line;
1049 while (*tmp) {
1050 if (*tmp != ' ')
1051 break;
1052 tmp++;
1053 }
1054
1055 if (*tmp) {
1056 /*
1057 * Parse hexa addresses followed by ':'
1058 */
1059 line_ip = strtoull(tmp, &tmp2, 16);
1060 if (*tmp2 != ':' || tmp == tmp2 || tmp2[1] == '\0')
1061 line_ip = -1;
1062 }
1063
1064 if (line_ip != -1) {
1065 u64 start = map__rip_2objdump(self->ms.map, sym->start),
1066 end = map__rip_2objdump(self->ms.map, sym->end);
1067
1068 offset = line_ip - start;
1069 if (offset < 0 || (u64)line_ip > end)
1070 offset = -1;
1071 }
1072
1073 objdump_line = objdump_line__new(offset, line, privsize);
1074 if (objdump_line == NULL) {
1075 free(line);
1076 return -1;
1077 }
1078 objdump__add_line(head, objdump_line);
1079
1080 return 0;
1081} 968}
1082 969
1083int hist_entry__annotate(struct hist_entry *self, struct list_head *head, 970int hist_entry__annotate(struct hist_entry *he, size_t privsize)
1084 size_t privsize)
1085{ 971{
1086 struct symbol *sym = self->ms.sym; 972 return symbol__annotate(he->ms.sym, he->ms.map, privsize);
1087 struct map *map = self->ms.map;
1088 struct dso *dso = map->dso;
1089 char *filename = dso__build_id_filename(dso, NULL, 0);
1090 bool free_filename = true;
1091 char command[PATH_MAX * 2];
1092 FILE *file;
1093 int err = 0;
1094 u64 len;
1095 char symfs_filename[PATH_MAX];
1096
1097 if (filename) {
1098 snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
1099 symbol_conf.symfs, filename);
1100 }
1101
1102 if (filename == NULL) {
1103 if (dso->has_build_id) {
1104 pr_err("Can't annotate %s: not enough memory\n",
1105 sym->name);
1106 return -ENOMEM;
1107 }
1108 goto fallback;
1109 } else if (readlink(symfs_filename, command, sizeof(command)) < 0 ||
1110 strstr(command, "[kernel.kallsyms]") ||
1111 access(symfs_filename, R_OK)) {
1112 free(filename);
1113fallback:
1114 /*
1115 * If we don't have build-ids or the build-id file isn't in the
1116 * cache, or is just a kallsyms file, well, lets hope that this
1117 * DSO is the same as when 'perf record' ran.
1118 */
1119 filename = dso->long_name;
1120 snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
1121 symbol_conf.symfs, filename);
1122 free_filename = false;
1123 }
1124
1125 if (dso->origin == DSO__ORIG_KERNEL) {
1126 if (dso->annotate_warned)
1127 goto out_free_filename;
1128 err = -ENOENT;
1129 dso->annotate_warned = 1;
1130 pr_err("Can't annotate %s: No vmlinux file was found in the "
1131 "path\n", sym->name);
1132 goto out_free_filename;
1133 }
1134
1135 pr_debug("%s: filename=%s, sym=%s, start=%#Lx, end=%#Lx\n", __func__,
1136 filename, sym->name, map->unmap_ip(map, sym->start),
1137 map->unmap_ip(map, sym->end));
1138
1139 len = sym->end - sym->start;
1140
1141 pr_debug("annotating [%p] %30s : [%p] %30s\n",
1142 dso, dso->long_name, sym, sym->name);
1143
1144 snprintf(command, sizeof(command),
1145 "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS -C %s|grep -v %s|expand",
1146 map__rip_2objdump(map, sym->start),
1147 map__rip_2objdump(map, sym->end),
1148 symfs_filename, filename);
1149
1150 pr_debug("Executing: %s\n", command);
1151
1152 file = popen(command, "r");
1153 if (!file)
1154 goto out_free_filename;
1155
1156 while (!feof(file))
1157 if (hist_entry__parse_objdump_line(self, file, head, privsize) < 0)
1158 break;
1159
1160 pclose(file);
1161out_free_filename:
1162 if (free_filename)
1163 free(filename);
1164 return err;
1165} 973}
1166 974
1167void hists__inc_nr_events(struct hists *self, u32 type) 975void hists__inc_nr_events(struct hists *self, u32 type)
@@ -1176,8 +984,12 @@ size_t hists__fprintf_nr_events(struct hists *self, FILE *fp)
1176 size_t ret = 0; 984 size_t ret = 0;
1177 985
1178 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) { 986 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
1179 const char *name = event__get_event_name(i); 987 const char *name;
988
989 if (self->stats.nr_events[i] == 0)
990 continue;
1180 991
992 name = perf_event__name(i);
1181 if (!strcmp(name, "UNKNOWN")) 993 if (!strcmp(name, "UNKNOWN"))
1182 continue; 994 continue;
1183 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/bitops.h b/tools/perf/util/include/linux/bitops.h
index 8be0b968ca0b..305c8484f200 100644
--- a/tools/perf/util/include/linux/bitops.h
+++ b/tools/perf/util/include/linux/bitops.h
@@ -2,6 +2,7 @@
2#define _PERF_LINUX_BITOPS_H_ 2#define _PERF_LINUX_BITOPS_H_
3 3
4#include <linux/kernel.h> 4#include <linux/kernel.h>
5#include <linux/compiler.h>
5#include <asm/hweight.h> 6#include <asm/hweight.h>
6 7
7#define BITS_PER_LONG __WORDSIZE 8#define BITS_PER_LONG __WORDSIZE
diff --git a/tools/perf/util/include/linux/list.h b/tools/perf/util/include/linux/list.h
index f5ca26e53fbb..356c7e467b83 100644
--- a/tools/perf/util/include/linux/list.h
+++ b/tools/perf/util/include/linux/list.h
@@ -1,3 +1,4 @@
1#include <linux/kernel.h>
1#include "../../../../include/linux/list.h" 2#include "../../../../include/linux/list.h"
2 3
3#ifndef PERF_LIST_H 4#ifndef PERF_LIST_H
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 3a7eb6ec0eec..a16ecab5229d 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -1,5 +1,6 @@
1#include "symbol.h" 1#include "symbol.h"
2#include <errno.h> 2#include <errno.h>
3#include <inttypes.h>
3#include <limits.h> 4#include <limits.h>
4#include <stdlib.h> 5#include <stdlib.h>
5#include <string.h> 6#include <string.h>
@@ -195,7 +196,7 @@ int map__overlap(struct map *l, struct map *r)
195 196
196size_t map__fprintf(struct map *self, FILE *fp) 197size_t map__fprintf(struct map *self, FILE *fp)
197{ 198{
198 return fprintf(fp, " %Lx-%Lx %Lx %s\n", 199 return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s\n",
199 self->start, self->end, self->pgoff, self->dso->name); 200 self->start, self->end, self->pgoff, self->dso->name);
200} 201}
201 202
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index bc2732ee23eb..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
@@ -279,7 +301,7 @@ const char *__event_name(int type, u64 config)
279 static char buf[32]; 301 static char buf[32];
280 302
281 if (type == PERF_TYPE_RAW) { 303 if (type == PERF_TYPE_RAW) {
282 sprintf(buf, "raw 0x%llx", config); 304 sprintf(buf, "raw 0x%" PRIx64, config);
283 return buf; 305 return buf;
284 } 306 }
285 307
@@ -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 b82cafb83772..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 {
@@ -23,10 +18,9 @@ struct tracepoint_path {
23}; 18};
24 19
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 *evsel_list); 21extern bool have_tracepoints(struct list_head *evlist);
27
28extern int nr_counters;
29 22
23const char *event_type(int type);
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 128aaab0aeda..5ddee66020a7 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
@@ -172,7 +197,7 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
172 sym = __find_kernel_function_by_name(tp->symbol, &map); 197 sym = __find_kernel_function_by_name(tp->symbol, &map);
173 if (sym) { 198 if (sym) {
174 addr = map->unmap_ip(map, sym->start + tp->offset); 199 addr = map->unmap_ip(map, sym->start + tp->offset);
175 pr_debug("try to find %s+%ld@%llx\n", tp->symbol, 200 pr_debug("try to find %s+%ld@%" PRIx64 "\n", tp->symbol,
176 tp->offset, addr); 201 tp->offset, addr);
177 ret = find_perf_probe_point((unsigned long)addr, pp); 202 ret = find_perf_probe_point((unsigned long)addr, pp);
178 } 203 }
@@ -384,7 +409,7 @@ int show_line_range(struct line_range *lr, const char *module)
384 setup_pager(); 409 setup_pager();
385 410
386 if (lr->function) 411 if (lr->function)
387 fprintf(stdout, "<%s:%d>\n", lr->function, 412 fprintf(stdout, "<%s@%s:%d>\n", lr->function, lr->path,
388 lr->start - lr->offset); 413 lr->start - lr->offset);
389 else 414 else
390 fprintf(stdout, "<%s:%d>\n", lr->path, lr->start); 415 fprintf(stdout, "<%s:%d>\n", lr->path, lr->start);
@@ -426,12 +451,14 @@ end:
426} 451}
427 452
428static int show_available_vars_at(int fd, struct perf_probe_event *pev, 453static int show_available_vars_at(int fd, struct perf_probe_event *pev,
429 int max_vls, bool externs) 454 int max_vls, struct strfilter *_filter,
455 bool externs)
430{ 456{
431 char *buf; 457 char *buf;
432 int ret, i; 458 int ret, i, nvars;
433 struct str_node *node; 459 struct str_node *node;
434 struct variable_list *vls = NULL, *vl; 460 struct variable_list *vls = NULL, *vl;
461 const char *var;
435 462
436 buf = synthesize_perf_probe_point(&pev->point); 463 buf = synthesize_perf_probe_point(&pev->point);
437 if (!buf) 464 if (!buf)
@@ -439,36 +466,45 @@ static int show_available_vars_at(int fd, struct perf_probe_event *pev,
439 pr_debug("Searching variables at %s\n", buf); 466 pr_debug("Searching variables at %s\n", buf);
440 467
441 ret = find_available_vars_at(fd, pev, &vls, max_vls, externs); 468 ret = find_available_vars_at(fd, pev, &vls, max_vls, externs);
442 if (ret > 0) { 469 if (ret <= 0) {
443 /* Some variables were found */ 470 pr_err("Failed to find variables at %s (%d)\n", buf, ret);
444 fprintf(stdout, "Available variables at %s\n", buf); 471 goto end;
445 for (i = 0; i < ret; i++) { 472 }
446 vl = &vls[i]; 473 /* Some variables are found */
447 /* 474 fprintf(stdout, "Available variables at %s\n", buf);
448 * A probe point might be converted to 475 for (i = 0; i < ret; i++) {
449 * several trace points. 476 vl = &vls[i];
450 */ 477 /*
451 fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol, 478 * A probe point might be converted to
452 vl->point.offset); 479 * several trace points.
453 free(vl->point.symbol); 480 */
454 if (vl->vars) { 481 fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol,
455 strlist__for_each(node, vl->vars) 482 vl->point.offset);
483 free(vl->point.symbol);
484 nvars = 0;
485 if (vl->vars) {
486 strlist__for_each(node, vl->vars) {
487 var = strchr(node->s, '\t') + 1;
488 if (strfilter__compare(_filter, var)) {
456 fprintf(stdout, "\t\t%s\n", node->s); 489 fprintf(stdout, "\t\t%s\n", node->s);
457 strlist__delete(vl->vars); 490 nvars++;
458 } else 491 }
459 fprintf(stdout, "(No variables)\n"); 492 }
493 strlist__delete(vl->vars);
460 } 494 }
461 free(vls); 495 if (nvars == 0)
462 } else 496 fprintf(stdout, "\t\t(No matched variables)\n");
463 pr_err("Failed to find variables at %s (%d)\n", buf, ret); 497 }
464 498 free(vls);
499end:
465 free(buf); 500 free(buf);
466 return ret; 501 return ret;
467} 502}
468 503
469/* Show available variables on given probe point */ 504/* Show available variables on given probe point */
470int show_available_vars(struct perf_probe_event *pevs, int npevs, 505int show_available_vars(struct perf_probe_event *pevs, int npevs,
471 int max_vls, const char *module, bool externs) 506 int max_vls, const char *module,
507 struct strfilter *_filter, bool externs)
472{ 508{
473 int i, fd, ret = 0; 509 int i, fd, ret = 0;
474 510
@@ -485,7 +521,8 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
485 setup_pager(); 521 setup_pager();
486 522
487 for (i = 0; i < npevs && ret >= 0; i++) 523 for (i = 0; i < npevs && ret >= 0; i++)
488 ret = show_available_vars_at(fd, &pevs[i], max_vls, externs); 524 ret = show_available_vars_at(fd, &pevs[i], max_vls, _filter,
525 externs);
489 526
490 close(fd); 527 close(fd);
491 return ret; 528 return ret;
@@ -531,7 +568,9 @@ int show_line_range(struct line_range *lr __unused, const char *module __unused)
531 568
532int show_available_vars(struct perf_probe_event *pevs __unused, 569int show_available_vars(struct perf_probe_event *pevs __unused,
533 int npevs __unused, int max_vls __unused, 570 int npevs __unused, int max_vls __unused,
534 const char *module __unused, bool externs __unused) 571 const char *module __unused,
572 struct strfilter *filter __unused,
573 bool externs __unused)
535{ 574{
536 pr_warning("Debuginfo-analysis is not supported.\n"); 575 pr_warning("Debuginfo-analysis is not supported.\n");
537 return -ENOSYS; 576 return -ENOSYS;
@@ -556,11 +595,11 @@ static int parse_line_num(char **ptr, int *val, const char *what)
556 * The line range syntax is described by: 595 * The line range syntax is described by:
557 * 596 *
558 * SRC[:SLN[+NUM|-ELN]] 597 * SRC[:SLN[+NUM|-ELN]]
559 * FNC[:SLN[+NUM|-ELN]] 598 * FNC[@SRC][:SLN[+NUM|-ELN]]
560 */ 599 */
561int parse_line_range_desc(const char *arg, struct line_range *lr) 600int parse_line_range_desc(const char *arg, struct line_range *lr)
562{ 601{
563 char *range, *name = strdup(arg); 602 char *range, *file, *name = strdup(arg);
564 int err; 603 int err;
565 604
566 if (!name) 605 if (!name)
@@ -610,7 +649,16 @@ int parse_line_range_desc(const char *arg, struct line_range *lr)
610 } 649 }
611 } 650 }
612 651
613 if (strchr(name, '.')) 652 file = strchr(name, '@');
653 if (file) {
654 *file = '\0';
655 lr->file = strdup(++file);
656 if (lr->file == NULL) {
657 err = -ENOMEM;
658 goto err;
659 }
660 lr->function = name;
661 } else if (strchr(name, '.'))
614 lr->file = name; 662 lr->file = name;
615 else 663 else
616 lr->function = name; 664 lr->function = name;
@@ -1784,9 +1832,12 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
1784 } 1832 }
1785 1833
1786 /* Loop 2: add all events */ 1834 /* Loop 2: add all events */
1787 for (i = 0; i < npevs && ret >= 0; i++) 1835 for (i = 0; i < npevs; i++) {
1788 ret = __add_probe_trace_events(pkgs[i].pev, pkgs[i].tevs, 1836 ret = __add_probe_trace_events(pkgs[i].pev, pkgs[i].tevs,
1789 pkgs[i].ntevs, force_add); 1837 pkgs[i].ntevs, force_add);
1838 if (ret < 0)
1839 break;
1840 }
1790end: 1841end:
1791 /* Loop 3: cleanup and free trace events */ 1842 /* Loop 3: cleanup and free trace events */
1792 for (i = 0; i < npevs; i++) { 1843 for (i = 0; i < npevs; i++) {
@@ -1912,4 +1963,46 @@ int del_perf_probe_events(struct strlist *dellist)
1912 1963
1913 return ret; 1964 return ret;
1914} 1965}
1966/* TODO: don't use a global variable for filter ... */
1967static struct strfilter *available_func_filter;
1968
1969/*
1970 * If a symbol corresponds to a function with global binding and
1971 * matches filter return 0. For all others return 1.
1972 */
1973static int filter_available_functions(struct map *map __unused,
1974 struct symbol *sym)
1975{
1976 if (sym->binding == STB_GLOBAL &&
1977 strfilter__compare(available_func_filter, sym->name))
1978 return 0;
1979 return 1;
1980}
1981
1982int show_available_funcs(const char *module, struct strfilter *_filter)
1983{
1984 struct map *map;
1985 int ret;
1986
1987 setup_pager();
1988
1989 ret = init_vmlinux();
1990 if (ret < 0)
1991 return ret;
1915 1992
1993 map = kernel_get_module_map(module);
1994 if (!map) {
1995 pr_err("Failed to find %s map.\n", (module) ? : "kernel");
1996 return -EINVAL;
1997 }
1998 available_func_filter = _filter;
1999 if (map__load(map, filter_available_functions)) {
2000 pr_err("Failed to load map.\n");
2001 return -EINVAL;
2002 }
2003 if (!dso__sorted_by_name(map->dso, map->type))
2004 dso__sort_by_name(map->dso, map->type);
2005
2006 dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
2007 return 0;
2008}
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..194f9e2a3285 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"
@@ -280,6 +281,19 @@ static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
280 return name ? (strcmp(tname, name) == 0) : false; 281 return name ? (strcmp(tname, name) == 0) : false;
281} 282}
282 283
284/* Get callsite line number of inline-function instance */
285static int die_get_call_lineno(Dwarf_Die *in_die)
286{
287 Dwarf_Attribute attr;
288 Dwarf_Word ret;
289
290 if (!dwarf_attr(in_die, DW_AT_call_line, &attr))
291 return -ENOENT;
292
293 dwarf_formudata(&attr, &ret);
294 return (int)ret;
295}
296
283/* Get type die */ 297/* Get type die */
284static Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) 298static Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
285{ 299{
@@ -320,13 +334,23 @@ static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
320 return vr_die; 334 return vr_die;
321} 335}
322 336
323static bool die_is_signed_type(Dwarf_Die *tp_die) 337static int die_get_attr_udata(Dwarf_Die *tp_die, unsigned int attr_name,
338 Dwarf_Word *result)
324{ 339{
325 Dwarf_Attribute attr; 340 Dwarf_Attribute attr;
341
342 if (dwarf_attr(tp_die, attr_name, &attr) == NULL ||
343 dwarf_formudata(&attr, result) != 0)
344 return -ENOENT;
345
346 return 0;
347}
348
349static bool die_is_signed_type(Dwarf_Die *tp_die)
350{
326 Dwarf_Word ret; 351 Dwarf_Word ret;
327 352
328 if (dwarf_attr(tp_die, DW_AT_encoding, &attr) == NULL || 353 if (die_get_attr_udata(tp_die, DW_AT_encoding, &ret))
329 dwarf_formudata(&attr, &ret) != 0)
330 return false; 354 return false;
331 355
332 return (ret == DW_ATE_signed_char || ret == DW_ATE_signed || 356 return (ret == DW_ATE_signed_char || ret == DW_ATE_signed ||
@@ -335,11 +359,29 @@ static bool die_is_signed_type(Dwarf_Die *tp_die)
335 359
336static int die_get_byte_size(Dwarf_Die *tp_die) 360static int die_get_byte_size(Dwarf_Die *tp_die)
337{ 361{
338 Dwarf_Attribute attr;
339 Dwarf_Word ret; 362 Dwarf_Word ret;
340 363
341 if (dwarf_attr(tp_die, DW_AT_byte_size, &attr) == NULL || 364 if (die_get_attr_udata(tp_die, DW_AT_byte_size, &ret))
342 dwarf_formudata(&attr, &ret) != 0) 365 return 0;
366
367 return (int)ret;
368}
369
370static int die_get_bit_size(Dwarf_Die *tp_die)
371{
372 Dwarf_Word ret;
373
374 if (die_get_attr_udata(tp_die, DW_AT_bit_size, &ret))
375 return 0;
376
377 return (int)ret;
378}
379
380static int die_get_bit_offset(Dwarf_Die *tp_die)
381{
382 Dwarf_Word ret;
383
384 if (die_get_attr_udata(tp_die, DW_AT_bit_offset, &ret))
343 return 0; 385 return 0;
344 386
345 return (int)ret; 387 return (int)ret;
@@ -458,6 +500,151 @@ static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
458 return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem); 500 return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem);
459} 501}
460 502
503/* Walker on lines (Note: line number will not be sorted) */
504typedef int (* line_walk_handler_t) (const char *fname, int lineno,
505 Dwarf_Addr addr, void *data);
506
507struct __line_walk_param {
508 const char *fname;
509 line_walk_handler_t handler;
510 void *data;
511 int retval;
512};
513
514static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data)
515{
516 struct __line_walk_param *lw = data;
517 Dwarf_Addr addr;
518 int lineno;
519
520 if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) {
521 lineno = die_get_call_lineno(in_die);
522 if (lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) {
523 lw->retval = lw->handler(lw->fname, lineno, addr,
524 lw->data);
525 if (lw->retval != 0)
526 return DIE_FIND_CB_FOUND;
527 }
528 }
529 return DIE_FIND_CB_SIBLING;
530}
531
532/* Walk on lines of blocks included in given DIE */
533static int __die_walk_funclines(Dwarf_Die *sp_die,
534 line_walk_handler_t handler, void *data)
535{
536 struct __line_walk_param lw = {
537 .handler = handler,
538 .data = data,
539 .retval = 0,
540 };
541 Dwarf_Die die_mem;
542 Dwarf_Addr addr;
543 int lineno;
544
545 /* Handle function declaration line */
546 lw.fname = dwarf_decl_file(sp_die);
547 if (lw.fname && dwarf_decl_line(sp_die, &lineno) == 0 &&
548 dwarf_entrypc(sp_die, &addr) == 0) {
549 lw.retval = handler(lw.fname, lineno, addr, data);
550 if (lw.retval != 0)
551 goto done;
552 }
553 die_find_child(sp_die, __die_walk_funclines_cb, &lw, &die_mem);
554done:
555 return lw.retval;
556}
557
558static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data)
559{
560 struct __line_walk_param *lw = data;
561
562 lw->retval = __die_walk_funclines(sp_die, lw->handler, lw->data);
563 if (lw->retval != 0)
564 return DWARF_CB_ABORT;
565
566 return DWARF_CB_OK;
567}
568
569/*
570 * Walk on lines inside given PDIE. If the PDIE is subprogram, walk only on
571 * the lines inside the subprogram, otherwise PDIE must be a CU DIE.
572 */
573static int die_walk_lines(Dwarf_Die *pdie, line_walk_handler_t handler,
574 void *data)
575{
576 Dwarf_Lines *lines;
577 Dwarf_Line *line;
578 Dwarf_Addr addr;
579 const char *fname;
580 int lineno, ret = 0;
581 Dwarf_Die die_mem, *cu_die;
582 size_t nlines, i;
583
584 /* Get the CU die */
585 if (dwarf_tag(pdie) == DW_TAG_subprogram)
586 cu_die = dwarf_diecu(pdie, &die_mem, NULL, NULL);
587 else
588 cu_die = pdie;
589 if (!cu_die) {
590 pr_debug2("Failed to get CU from subprogram\n");
591 return -EINVAL;
592 }
593
594 /* Get lines list in the CU */
595 if (dwarf_getsrclines(cu_die, &lines, &nlines) != 0) {
596 pr_debug2("Failed to get source lines on this CU.\n");
597 return -ENOENT;
598 }
599 pr_debug2("Get %zd lines from this CU\n", nlines);
600
601 /* Walk on the lines on lines list */
602 for (i = 0; i < nlines; i++) {
603 line = dwarf_onesrcline(lines, i);
604 if (line == NULL ||
605 dwarf_lineno(line, &lineno) != 0 ||
606 dwarf_lineaddr(line, &addr) != 0) {
607 pr_debug2("Failed to get line info. "
608 "Possible error in debuginfo.\n");
609 continue;
610 }
611 /* Filter lines based on address */
612 if (pdie != cu_die)
613 /*
614 * Address filtering
615 * The line is included in given function, and
616 * no inline block includes it.
617 */
618 if (!dwarf_haspc(pdie, addr) ||
619 die_find_inlinefunc(pdie, addr, &die_mem))
620 continue;
621 /* Get source line */
622 fname = dwarf_linesrc(line, NULL, NULL);
623
624 ret = handler(fname, lineno, addr, data);
625 if (ret != 0)
626 return ret;
627 }
628
629 /*
630 * Dwarf lines doesn't include function declarations and inlined
631 * subroutines. We have to check functions list or given function.
632 */
633 if (pdie != cu_die)
634 ret = __die_walk_funclines(pdie, handler, data);
635 else {
636 struct __line_walk_param param = {
637 .handler = handler,
638 .data = data,
639 .retval = 0,
640 };
641 dwarf_getfuncs(cu_die, __die_walk_culines_cb, &param, 0);
642 ret = param.retval;
643 }
644
645 return ret;
646}
647
461struct __find_variable_param { 648struct __find_variable_param {
462 const char *name; 649 const char *name;
463 Dwarf_Addr addr; 650 Dwarf_Addr addr;
@@ -669,6 +856,8 @@ static_var:
669 return 0; 856 return 0;
670} 857}
671 858
859#define BYTES_TO_BITS(nb) ((nb) * BITS_PER_LONG / sizeof(long))
860
672static int convert_variable_type(Dwarf_Die *vr_die, 861static int convert_variable_type(Dwarf_Die *vr_die,
673 struct probe_trace_arg *tvar, 862 struct probe_trace_arg *tvar,
674 const char *cast) 863 const char *cast)
@@ -685,6 +874,14 @@ static int convert_variable_type(Dwarf_Die *vr_die,
685 return (tvar->type == NULL) ? -ENOMEM : 0; 874 return (tvar->type == NULL) ? -ENOMEM : 0;
686 } 875 }
687 876
877 if (die_get_bit_size(vr_die) != 0) {
878 /* This is a bitfield */
879 ret = snprintf(buf, 16, "b%d@%d/%zd", die_get_bit_size(vr_die),
880 die_get_bit_offset(vr_die),
881 BYTES_TO_BITS(die_get_byte_size(vr_die)));
882 goto formatted;
883 }
884
688 if (die_get_real_type(vr_die, &type) == NULL) { 885 if (die_get_real_type(vr_die, &type) == NULL) {
689 pr_warning("Failed to get a type information of %s.\n", 886 pr_warning("Failed to get a type information of %s.\n",
690 dwarf_diename(vr_die)); 887 dwarf_diename(vr_die));
@@ -729,29 +926,31 @@ static int convert_variable_type(Dwarf_Die *vr_die,
729 return (tvar->type == NULL) ? -ENOMEM : 0; 926 return (tvar->type == NULL) ? -ENOMEM : 0;
730 } 927 }
731 928
732 ret = die_get_byte_size(&type) * 8; 929 ret = BYTES_TO_BITS(die_get_byte_size(&type));
733 if (ret) { 930 if (!ret)
734 /* Check the bitwidth */ 931 /* No size ... try to use default type */
735 if (ret > MAX_BASIC_TYPE_BITS) { 932 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 933
742 ret = snprintf(buf, 16, "%c%d", 934 /* Check the bitwidth */
743 die_is_signed_type(&type) ? 's' : 'u', ret); 935 if (ret > MAX_BASIC_TYPE_BITS) {
744 if (ret < 0 || ret >= 16) { 936 pr_info("%s exceeds max-bitwidth. Cut down to %d bits.\n",
745 if (ret >= 16) 937 dwarf_diename(&type), MAX_BASIC_TYPE_BITS);
746 ret = -E2BIG; 938 ret = MAX_BASIC_TYPE_BITS;
747 pr_warning("Failed to convert variable type: %s\n", 939 }
748 strerror(-ret)); 940 ret = snprintf(buf, 16, "%c%d",
749 return ret; 941 die_is_signed_type(&type) ? 's' : 'u', ret);
750 } 942
751 tvar->type = strdup(buf); 943formatted:
752 if (tvar->type == NULL) 944 if (ret < 0 || ret >= 16) {
753 return -ENOMEM; 945 if (ret >= 16)
946 ret = -E2BIG;
947 pr_warning("Failed to convert variable type: %s\n",
948 strerror(-ret));
949 return ret;
754 } 950 }
951 tvar->type = strdup(buf);
952 if (tvar->type == NULL)
953 return -ENOMEM;
755 return 0; 954 return 0;
756} 955}
757 956
@@ -1050,157 +1249,102 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf)
1050 return ret; 1249 return ret;
1051} 1250}
1052 1251
1053/* Find probe point from its line number */ 1252static int probe_point_line_walker(const char *fname, int lineno,
1054static int find_probe_point_by_line(struct probe_finder *pf) 1253 Dwarf_Addr addr, void *data)
1055{ 1254{
1056 Dwarf_Lines *lines; 1255 struct probe_finder *pf = data;
1057 Dwarf_Line *line; 1256 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 1257
1068 for (i = 0; i < nlines && ret == 0; i++) { 1258 if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0)
1069 line = dwarf_onesrcline(lines, i); 1259 return 0;
1070 if (dwarf_lineno(line, &lineno) != 0 ||
1071 lineno != pf->lno)
1072 continue;
1073 1260
1074 /* TODO: Get fileno from line, but how? */ 1261 pf->addr = addr;
1075 if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0) 1262 ret = call_probe_finder(NULL, pf);
1076 continue;
1077 1263
1078 if (dwarf_lineaddr(line, &addr) != 0) { 1264 /* Continue if no error, because the line will be in inline function */
1079 pr_warning("Failed to get the address of the line.\n"); 1265 return ret < 0 ? ret : 0;
1080 return -ENOENT; 1266}
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 1267
1086 ret = call_probe_finder(NULL, pf); 1268/* Find probe point from its line number */
1087 /* Continuing, because target line might be inlined. */ 1269static int find_probe_point_by_line(struct probe_finder *pf)
1088 } 1270{
1089 return ret; 1271 return die_walk_lines(&pf->cu_die, probe_point_line_walker, pf);
1090} 1272}
1091 1273
1092/* Find lines which match lazy pattern */ 1274/* Find lines which match lazy pattern */
1093static int find_lazy_match_lines(struct list_head *head, 1275static int find_lazy_match_lines(struct list_head *head,
1094 const char *fname, const char *pat) 1276 const char *fname, const char *pat)
1095{ 1277{
1096 char *fbuf, *p1, *p2; 1278 FILE *fp;
1097 int fd, line, nlines = -1; 1279 char *line = NULL;
1098 struct stat st; 1280 size_t line_len;
1099 1281 ssize_t len;
1100 fd = open(fname, O_RDONLY); 1282 int count = 0, linenum = 1;
1101 if (fd < 0) { 1283
1102 pr_warning("Failed to open %s: %s\n", fname, strerror(-fd)); 1284 fp = fopen(fname, "r");
1285 if (!fp) {
1286 pr_warning("Failed to open %s: %s\n", fname, strerror(errno));
1103 return -errno; 1287 return -errno;
1104 } 1288 }
1105 1289
1106 if (fstat(fd, &st) < 0) { 1290 while ((len = getline(&line, &line_len, fp)) > 0) {
1107 pr_warning("Failed to get the size of %s: %s\n", 1291
1108 fname, strerror(errno)); 1292 if (line[len - 1] == '\n')
1109 nlines = -errno; 1293 line[len - 1] = '\0';
1110 goto out_close; 1294
1111 } 1295 if (strlazymatch(line, pat)) {
1112 1296 line_list__add_line(head, linenum);
1113 nlines = -ENOMEM; 1297 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 } 1298 }
1133 line++; 1299 linenum++;
1134 p1 = p2 + 1;
1135 } 1300 }
1136out_free_fbuf: 1301
1137 free(fbuf); 1302 if (ferror(fp))
1138out_close: 1303 count = -errno;
1139 close(fd); 1304 free(line);
1140 return nlines; 1305 fclose(fp);
1306
1307 if (count == 0)
1308 pr_debug("No matched lines found in %s.\n", fname);
1309 return count;
1310}
1311
1312static int probe_point_lazy_walker(const char *fname, int lineno,
1313 Dwarf_Addr addr, void *data)
1314{
1315 struct probe_finder *pf = data;
1316 int ret;
1317
1318 if (!line_list__has_line(&pf->lcache, lineno) ||
1319 strtailcmp(fname, pf->fname) != 0)
1320 return 0;
1321
1322 pr_debug("Probe line found: line:%d addr:0x%llx\n",
1323 lineno, (unsigned long long)addr);
1324 pf->addr = addr;
1325 ret = call_probe_finder(NULL, pf);
1326
1327 /*
1328 * Continue if no error, because the lazy pattern will match
1329 * to other lines
1330 */
1331 return ret < 0 ? ret : 0;
1141} 1332}
1142 1333
1143/* Find probe points from lazy pattern */ 1334/* Find probe points from lazy pattern */
1144static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) 1335static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
1145{ 1336{
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; 1337 int ret = 0;
1153 1338
1154 if (list_empty(&pf->lcache)) { 1339 if (list_empty(&pf->lcache)) {
1155 /* Matching lazy line pattern */ 1340 /* Matching lazy line pattern */
1156 ret = find_lazy_match_lines(&pf->lcache, pf->fname, 1341 ret = find_lazy_match_lines(&pf->lcache, pf->fname,
1157 pf->pev->point.lazy_line); 1342 pf->pev->point.lazy_line);
1158 if (ret == 0) { 1343 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; 1344 return ret;
1163 } 1345 }
1164 1346
1165 if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) { 1347 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} 1348}
1205 1349
1206/* Callback parameter with return value */ 1350/* Callback parameter with return value */
@@ -1318,8 +1462,7 @@ static int find_probes(int fd, struct probe_finder *pf)
1318 off = 0; 1462 off = 0;
1319 line_list__init(&pf->lcache); 1463 line_list__init(&pf->lcache);
1320 /* Loop on CUs (Compilation Unit) */ 1464 /* Loop on CUs (Compilation Unit) */
1321 while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) && 1465 while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL)) {
1322 ret >= 0) {
1323 /* Get the DIE(Debugging Information Entry) of this CU */ 1466 /* Get the DIE(Debugging Information Entry) of this CU */
1324 diep = dwarf_offdie(dbg, off + cuhl, &pf->cu_die); 1467 diep = dwarf_offdie(dbg, off + cuhl, &pf->cu_die);
1325 if (!diep) 1468 if (!diep)
@@ -1340,6 +1483,8 @@ static int find_probes(int fd, struct probe_finder *pf)
1340 pf->lno = pp->line; 1483 pf->lno = pp->line;
1341 ret = find_probe_point_by_line(pf); 1484 ret = find_probe_point_by_line(pf);
1342 } 1485 }
1486 if (ret < 0)
1487 break;
1343 } 1488 }
1344 off = noff; 1489 off = noff;
1345 } 1490 }
@@ -1644,91 +1789,28 @@ static int line_range_add_line(const char *src, unsigned int lineno,
1644 return line_list__add_line(&lr->line_list, lineno); 1789 return line_list__add_line(&lr->line_list, lineno);
1645} 1790}
1646 1791
1647/* Search function declaration lines */ 1792static int line_range_walk_cb(const char *fname, int lineno,
1648static int line_range_funcdecl_cb(Dwarf_Die *sp_die, void *data) 1793 Dwarf_Addr addr __used,
1794 void *data)
1649{ 1795{
1650 struct dwarf_callback_param *param = data; 1796 struct line_finder *lf = data;
1651 struct line_finder *lf = param->data;
1652 const char *src;
1653 int lineno;
1654 1797
1655 src = dwarf_decl_file(sp_die); 1798 if ((strtailcmp(fname, lf->fname) != 0) ||
1656 if (src && strtailcmp(src, lf->fname) != 0)
1657 return DWARF_CB_OK;
1658
1659 if (dwarf_decl_line(sp_die, &lineno) != 0 ||
1660 (lf->lno_s > lineno || lf->lno_e < lineno)) 1799 (lf->lno_s > lineno || lf->lno_e < lineno))
1661 return DWARF_CB_OK; 1800 return 0;
1662 1801
1663 param->retval = line_range_add_line(src, lineno, lf->lr); 1802 if (line_range_add_line(fname, lineno, lf->lr) < 0)
1664 if (param->retval < 0) 1803 return -EINVAL;
1665 return DWARF_CB_ABORT;
1666 return DWARF_CB_OK;
1667}
1668 1804
1669static int find_line_range_func_decl_lines(struct line_finder *lf) 1805 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} 1806}
1675 1807
1676/* Find line range from its line number */ 1808/* Find line range from its line number */
1677static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) 1809static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
1678{ 1810{
1679 Dwarf_Lines *lines; 1811 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 1812
1721 /* 1813 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 1814
1733 /* Update status */ 1815 /* Update status */
1734 if (ret >= 0) 1816 if (ret >= 0)
@@ -1758,9 +1840,6 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
1758 struct line_finder *lf = param->data; 1840 struct line_finder *lf = param->data;
1759 struct line_range *lr = lf->lr; 1841 struct line_range *lr = lf->lr;
1760 1842
1761 pr_debug("find (%llx) %s\n",
1762 (unsigned long long)dwarf_dieoffset(sp_die),
1763 dwarf_diename(sp_die));
1764 if (dwarf_tag(sp_die) == DW_TAG_subprogram && 1843 if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
1765 die_compare_name(sp_die, lr->function)) { 1844 die_compare_name(sp_die, lr->function)) {
1766 lf->fname = dwarf_decl_file(sp_die); 1845 lf->fname = dwarf_decl_file(sp_die);
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 313dac2d94ce..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,19 +641,20 @@ 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
655 printf("... chain: nr:%Lu\n", sample->callchain->nr); 648 printf("... chain: nr:%" PRIu64 "\n", sample->callchain->nr);
656 649
657 for (i = 0; i < sample->callchain->nr; i++) 650 for (i = 0; i < sample->callchain->nr; i++)
658 printf("..... %2d: %016Lx\n", i, sample->callchain->ips[i]); 651 printf("..... %2d: %016" PRIx64 "\n",
652 i, sample->callchain->ips[i]);
659} 653}
660 654
661static void perf_session__print_tstamp(struct perf_session *session, 655static void perf_session__print_tstamp(struct perf_session *session,
662 event_t *event, 656 union perf_event *event,
663 struct sample_data *sample) 657 struct perf_sample *sample)
664{ 658{
665 if (event->header.type != PERF_RECORD_SAMPLE && 659 if (event->header.type != PERF_RECORD_SAMPLE &&
666 !session->sample_id_all) { 660 !session->sample_id_all) {
@@ -672,52 +666,60 @@ static void perf_session__print_tstamp(struct perf_session *session,
672 printf("%u ", sample->cpu); 666 printf("%u ", sample->cpu);
673 667
674 if (session->sample_type & PERF_SAMPLE_TIME) 668 if (session->sample_type & PERF_SAMPLE_TIME)
675 printf("%Lu ", sample->time); 669 printf("%" PRIu64 " ", sample->time);
676} 670}
677 671
678static void dump_event(struct perf_session *session, event_t *event, 672static void dump_event(struct perf_session *session, union perf_event *event,
679 u64 file_offset, struct sample_data *sample) 673 u64 file_offset, struct perf_sample *sample)
680{ 674{
681 if (!dump_trace) 675 if (!dump_trace)
682 return; 676 return;
683 677
684 printf("\n%#Lx [%#x]: event: %d\n", file_offset, event->header.size, 678 printf("\n%#" PRIx64 " [%#x]: event: %d\n",
685 event->header.type); 679 file_offset, event->header.size, event->header.type);
686 680
687 trace_event(event); 681 trace_event(event);
688 682
689 if (sample) 683 if (sample)
690 perf_session__print_tstamp(session, event, sample); 684 perf_session__print_tstamp(session, event, sample);
691 685
692 printf("%#Lx [%#x]: PERF_RECORD_%s", file_offset, event->header.size, 686 printf("%#" PRIx64 " [%#x]: PERF_RECORD_%s", file_offset,
693 event__get_event_name(event->header.type)); 687 event->header.size, perf_event__name(event->header.type));
694} 688}
695 689
696static void dump_sample(struct perf_session *session, event_t *event, 690static void dump_sample(struct perf_session *session, union perf_event *event,
697 struct sample_data *sample) 691 struct perf_sample *sample)
698{ 692{
699 if (!dump_trace) 693 if (!dump_trace)
700 return; 694 return;
701 695
702 printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc, 696 printf("(IP, %d): %d/%d: %#" PRIx64 " period: %" PRIu64 "\n",
703 sample->pid, sample->tid, sample->ip, sample->period); 697 event->header.misc, sample->pid, sample->tid, sample->ip,
698 sample->period);
704 699
705 if (session->sample_type & PERF_SAMPLE_CALLCHAIN) 700 if (session->sample_type & PERF_SAMPLE_CALLCHAIN)
706 callchain__printf(sample); 701 callchain__printf(sample);
707} 702}
708 703
709static int perf_session_deliver_event(struct perf_session *session, 704static int perf_session_deliver_event(struct perf_session *session,
710 event_t *event, 705 union perf_event *event,
711 struct sample_data *sample, 706 struct perf_sample *sample,
712 struct perf_event_ops *ops, 707 struct perf_event_ops *ops,
713 u64 file_offset) 708 u64 file_offset)
714{ 709{
710 struct perf_evsel *evsel;
711
715 dump_event(session, event, file_offset, sample); 712 dump_event(session, event, file_offset, sample);
716 713
717 switch (event->header.type) { 714 switch (event->header.type) {
718 case PERF_RECORD_SAMPLE: 715 case PERF_RECORD_SAMPLE:
719 dump_sample(session, event, sample); 716 dump_sample(session, event, sample);
720 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);
721 case PERF_RECORD_MMAP: 723 case PERF_RECORD_MMAP:
722 return ops->mmap(event, sample, session); 724 return ops->mmap(event, sample, session);
723 case PERF_RECORD_COMM: 725 case PERF_RECORD_COMM:
@@ -741,7 +743,7 @@ static int perf_session_deliver_event(struct perf_session *session,
741} 743}
742 744
743static int perf_session__preprocess_sample(struct perf_session *session, 745static int perf_session__preprocess_sample(struct perf_session *session,
744 event_t *event, struct sample_data *sample) 746 union perf_event *event, struct perf_sample *sample)
745{ 747{
746 if (event->header.type != PERF_RECORD_SAMPLE || 748 if (event->header.type != PERF_RECORD_SAMPLE ||
747 !(session->sample_type & PERF_SAMPLE_CALLCHAIN)) 749 !(session->sample_type & PERF_SAMPLE_CALLCHAIN))
@@ -756,7 +758,7 @@ static int perf_session__preprocess_sample(struct perf_session *session,
756 return 0; 758 return 0;
757} 759}
758 760
759static 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,
760 struct perf_event_ops *ops, u64 file_offset) 762 struct perf_event_ops *ops, u64 file_offset)
761{ 763{
762 dump_event(session, event, file_offset, NULL); 764 dump_event(session, event, file_offset, NULL);
@@ -781,15 +783,16 @@ static int perf_session__process_user_event(struct perf_session *session, event_
781} 783}
782 784
783static int perf_session__process_event(struct perf_session *session, 785static int perf_session__process_event(struct perf_session *session,
784 event_t *event, 786 union perf_event *event,
785 struct perf_event_ops *ops, 787 struct perf_event_ops *ops,
786 u64 file_offset) 788 u64 file_offset)
787{ 789{
788 struct sample_data sample; 790 struct perf_sample sample;
789 int ret; 791 int ret;
790 792
791 if (session->header.needs_swap && event__swap_ops[event->header.type]) 793 if (session->header.needs_swap &&
792 event__swap_ops[event->header.type](event); 794 perf_event__swap_ops[event->header.type])
795 perf_event__swap_ops[event->header.type](event);
793 796
794 if (event->header.type >= PERF_RECORD_HEADER_MAX) 797 if (event->header.type >= PERF_RECORD_HEADER_MAX)
795 return -EINVAL; 798 return -EINVAL;
@@ -802,7 +805,7 @@ static int perf_session__process_event(struct perf_session *session,
802 /* 805 /*
803 * For all kernel events we get the sample data 806 * For all kernel events we get the sample data
804 */ 807 */
805 event__parse_sample(event, session, &sample); 808 perf_session__parse_sample(session, event, &sample);
806 809
807 /* Preprocess sample records - precheck callchains */ 810 /* Preprocess sample records - precheck callchains */
808 if (perf_session__preprocess_sample(session, event, &sample)) 811 if (perf_session__preprocess_sample(session, event, &sample))
@@ -841,10 +844,10 @@ static struct thread *perf_session__register_idle_thread(struct perf_session *se
841static void perf_session__warn_about_errors(const struct perf_session *session, 844static void perf_session__warn_about_errors(const struct perf_session *session,
842 const struct perf_event_ops *ops) 845 const struct perf_event_ops *ops)
843{ 846{
844 if (ops->lost == event__process_lost && 847 if (ops->lost == perf_event__process_lost &&
845 session->hists.stats.total_lost != 0) { 848 session->hists.stats.total_lost != 0) {
846 ui__warning("Processed %Lu events and LOST %Lu!\n\n" 849 ui__warning("Processed %" PRIu64 " events and LOST %" PRIu64
847 "Check IO/CPU overload!\n\n", 850 "!\n\nCheck IO/CPU overload!\n\n",
848 session->hists.stats.total_period, 851 session->hists.stats.total_period,
849 session->hists.stats.total_lost); 852 session->hists.stats.total_lost);
850 } 853 }
@@ -858,6 +861,11 @@ static void perf_session__warn_about_errors(const struct perf_session *session,
858 session->hists.stats.nr_unknown_events); 861 session->hists.stats.nr_unknown_events);
859 } 862 }
860 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
861 if (session->hists.stats.nr_invalid_chains != 0) { 869 if (session->hists.stats.nr_invalid_chains != 0) {
862 ui__warning("Found invalid callchains!\n\n" 870 ui__warning("Found invalid callchains!\n\n"
863 "%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"
@@ -873,7 +881,7 @@ volatile int session_done;
873static int __perf_session__process_pipe_events(struct perf_session *self, 881static int __perf_session__process_pipe_events(struct perf_session *self,
874 struct perf_event_ops *ops) 882 struct perf_event_ops *ops)
875{ 883{
876 event_t event; 884 union perf_event event;
877 uint32_t size; 885 uint32_t size;
878 int skip = 0; 886 int skip = 0;
879 u64 head; 887 u64 head;
@@ -918,7 +926,7 @@ more:
918 926
919 if (size == 0 || 927 if (size == 0 ||
920 (skip = perf_session__process_event(self, &event, ops, head)) < 0) { 928 (skip = perf_session__process_event(self, &event, ops, head)) < 0) {
921 dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n", 929 dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n",
922 head, event.header.size, event.header.type); 930 head, event.header.size, event.header.type);
923 /* 931 /*
924 * assume we lost track of the stream, check alignment, and 932 * assume we lost track of the stream, check alignment, and
@@ -954,7 +962,7 @@ int __perf_session__process_events(struct perf_session *session,
954 struct ui_progress *progress; 962 struct ui_progress *progress;
955 size_t page_size, mmap_size; 963 size_t page_size, mmap_size;
956 char *buf, *mmaps[8]; 964 char *buf, *mmaps[8];
957 event_t *event; 965 union perf_event *event;
958 uint32_t size; 966 uint32_t size;
959 967
960 perf_event_ops__fill_defaults(ops); 968 perf_event_ops__fill_defaults(ops);
@@ -999,7 +1007,7 @@ remap:
999 file_pos = file_offset + head; 1007 file_pos = file_offset + head;
1000 1008
1001more: 1009more:
1002 event = (event_t *)(buf + head); 1010 event = (union perf_event *)(buf + head);
1003 1011
1004 if (session->header.needs_swap) 1012 if (session->header.needs_swap)
1005 perf_event_header__bswap(&event->header); 1013 perf_event_header__bswap(&event->header);
@@ -1023,7 +1031,7 @@ more:
1023 1031
1024 if (size == 0 || 1032 if (size == 0 ||
1025 perf_session__process_event(session, event, ops, file_pos) < 0) { 1033 perf_session__process_event(session, event, ops, file_pos) < 0) {
1026 dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n", 1034 dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n",
1027 file_offset + head, event->header.size, 1035 file_offset + head, event->header.size,
1028 event->header.type); 1036 event->header.type);
1029 /* 1037 /*
@@ -1132,3 +1140,79 @@ size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp,
1132 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);
1133 return ret + machines__fprintf_dsos_buildid(&self->machines, fp, with_hits); 1141 return ret + machines__fprintf_dsos_buildid(&self->machines, fp, with_hits);
1134} 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..e24ffadb20b2
--- /dev/null
+++ b/tools/perf/util/setup.py
@@ -0,0 +1,19 @@
1#!/usr/bin/python2
2
3from distutils.core import setup, Extension
4
5perf = Extension('perf',
6 sources = ['util/python.c', 'util/ctype.c', 'util/evlist.c',
7 'util/evsel.c', 'util/cpumap.c', 'util/thread_map.c',
8 'util/util.c', 'util/xyarray.c', 'util/cgroup.c'],
9 include_dirs = ['util/include'],
10 extra_compile_args = ['-fno-strict-aliasing', '-Wno-write-strings'])
11
12setup(name='perf',
13 version='0.1',
14 description='Interface with the Linux profiling infrastructure',
15 author='Arnaldo Carvalho de Melo',
16 author_email='acme@redhat.com',
17 license='GPLv2',
18 url='http://perf.wiki.kernel.org',
19 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/svghelper.c b/tools/perf/util/svghelper.c
index b3637db025a2..96c866045d60 100644
--- a/tools/perf/util/svghelper.c
+++ b/tools/perf/util/svghelper.c
@@ -12,6 +12,7 @@
12 * of the License. 12 * of the License.
13 */ 13 */
14 14
15#include <inttypes.h>
15#include <stdio.h> 16#include <stdio.h>
16#include <stdlib.h> 17#include <stdlib.h>
17#include <unistd.h> 18#include <unistd.h>
@@ -43,11 +44,11 @@ static double cpu2y(int cpu)
43 return cpu2slot(cpu) * SLOT_MULT; 44 return cpu2slot(cpu) * SLOT_MULT;
44} 45}
45 46
46static double time2pixels(u64 time) 47static double time2pixels(u64 __time)
47{ 48{
48 double X; 49 double X;
49 50
50 X = 1.0 * svg_page_width * (time - first_time) / (last_time - first_time); 51 X = 1.0 * svg_page_width * (__time - first_time) / (last_time - first_time);
51 return X; 52 return X;
52} 53}
53 54
@@ -94,7 +95,7 @@ void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end)
94 95
95 total_height = (1 + rows + cpu2slot(cpus)) * SLOT_MULT; 96 total_height = (1 + rows + cpu2slot(cpus)) * SLOT_MULT;
96 fprintf(svgfile, "<?xml version=\"1.0\" standalone=\"no\"?> \n"); 97 fprintf(svgfile, "<?xml version=\"1.0\" standalone=\"no\"?> \n");
97 fprintf(svgfile, "<svg width=\"%i\" height=\"%llu\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n", svg_page_width, total_height); 98 fprintf(svgfile, "<svg width=\"%i\" height=\"%" PRIu64 "\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n", svg_page_width, total_height);
98 99
99 fprintf(svgfile, "<defs>\n <style type=\"text/css\">\n <![CDATA[\n"); 100 fprintf(svgfile, "<defs>\n <style type=\"text/css\">\n <![CDATA[\n");
100 101
@@ -455,9 +456,9 @@ void svg_legenda(void)
455 return; 456 return;
456 457
457 svg_legenda_box(0, "Running", "sample"); 458 svg_legenda_box(0, "Running", "sample");
458 svg_legenda_box(100, "Idle","rect.c1"); 459 svg_legenda_box(100, "Idle","c1");
459 svg_legenda_box(200, "Deeper Idle", "rect.c3"); 460 svg_legenda_box(200, "Deeper Idle", "c3");
460 svg_legenda_box(350, "Deepest Idle", "rect.c6"); 461 svg_legenda_box(350, "Deepest Idle", "c6");
461 svg_legenda_box(550, "Sleeping", "process2"); 462 svg_legenda_box(550, "Sleeping", "process2");
462 svg_legenda_box(650, "Waiting for cpu", "waiting"); 463 svg_legenda_box(650, "Waiting for cpu", "waiting");
463 svg_legenda_box(800, "Blocked on IO", "blocked"); 464 svg_legenda_box(800, "Blocked on IO", "blocked");
@@ -483,7 +484,7 @@ void svg_time_grid(void)
483 color = 128; 484 color = 128;
484 } 485 }
485 486
486 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%llu\" style=\"stroke:rgb(%i,%i,%i);stroke-width:%1.3f\"/>\n", 487 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%" PRIu64 "\" style=\"stroke:rgb(%i,%i,%i);stroke-width:%1.3f\"/>\n",
487 time2pixels(i), SLOT_MULT/2, time2pixels(i), total_height, color, color, color, thickness); 488 time2pixels(i), SLOT_MULT/2, time2pixels(i), total_height, color, color, color, thickness);
488 489
489 i += 10000000; 490 i += 10000000;
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 15ccfba8cdf8..17df793c8924 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -11,6 +11,7 @@
11#include <sys/param.h> 11#include <sys/param.h>
12#include <fcntl.h> 12#include <fcntl.h>
13#include <unistd.h> 13#include <unistd.h>
14#include <inttypes.h>
14#include "build-id.h" 15#include "build-id.h"
15#include "debug.h" 16#include "debug.h"
16#include "symbol.h" 17#include "symbol.h"
@@ -153,7 +154,7 @@ static struct symbol *symbol__new(u64 start, u64 len, u8 binding,
153 self->binding = binding; 154 self->binding = binding;
154 self->namelen = namelen - 1; 155 self->namelen = namelen - 1;
155 156
156 pr_debug4("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end); 157 pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n", __func__, name, start, self->end);
157 158
158 memcpy(self->name, name, namelen); 159 memcpy(self->name, name, namelen);
159 160
@@ -167,7 +168,7 @@ void symbol__delete(struct symbol *self)
167 168
168static size_t symbol__fprintf(struct symbol *self, FILE *fp) 169static size_t symbol__fprintf(struct symbol *self, FILE *fp)
169{ 170{
170 return fprintf(fp, " %llx-%llx %c %s\n", 171 return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n",
171 self->start, self->end, 172 self->start, self->end,
172 self->binding == STB_GLOBAL ? 'g' : 173 self->binding == STB_GLOBAL ? 'g' :
173 self->binding == STB_LOCAL ? 'l' : 'w', 174 self->binding == STB_LOCAL ? 'l' : 'w',
@@ -206,8 +207,7 @@ struct dso *dso__new(const char *name)
206 dso__set_short_name(self, self->name); 207 dso__set_short_name(self, self->name);
207 for (i = 0; i < MAP__NR_TYPES; ++i) 208 for (i = 0; i < MAP__NR_TYPES; ++i)
208 self->symbols[i] = self->symbol_names[i] = RB_ROOT; 209 self->symbols[i] = self->symbol_names[i] = RB_ROOT;
209 self->slen_calculated = 0; 210 self->symtab_type = SYMTAB__NOT_FOUND;
210 self->origin = DSO__ORIG_NOT_FOUND;
211 self->loaded = 0; 211 self->loaded = 0;
212 self->sorted_by_name = 0; 212 self->sorted_by_name = 0;
213 self->has_build_id = 0; 213 self->has_build_id = 0;
@@ -680,9 +680,9 @@ int dso__load_kallsyms(struct dso *self, const char *filename,
680 return -1; 680 return -1;
681 681
682 if (self->kernel == DSO_TYPE_GUEST_KERNEL) 682 if (self->kernel == DSO_TYPE_GUEST_KERNEL)
683 self->origin = DSO__ORIG_GUEST_KERNEL; 683 self->symtab_type = SYMTAB__GUEST_KALLSYMS;
684 else 684 else
685 self->origin = DSO__ORIG_KERNEL; 685 self->symtab_type = SYMTAB__KALLSYMS;
686 686
687 return dso__split_kallsyms(self, map, filter); 687 return dso__split_kallsyms(self, map, filter);
688} 688}
@@ -1161,6 +1161,13 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
1161 1161
1162 section_name = elf_sec__name(&shdr, secstrs); 1162 section_name = elf_sec__name(&shdr, secstrs);
1163 1163
1164 /* On ARM, symbols for thumb functions have 1 added to
1165 * the symbol address as a flag - remove it */
1166 if ((ehdr.e_machine == EM_ARM) &&
1167 (map->type == MAP__FUNCTION) &&
1168 (sym.st_value & 1))
1169 --sym.st_value;
1170
1164 if (self->kernel != DSO_TYPE_USER || kmodule) { 1171 if (self->kernel != DSO_TYPE_USER || kmodule) {
1165 char dso_name[PATH_MAX]; 1172 char dso_name[PATH_MAX];
1166 1173
@@ -1197,7 +1204,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
1197 } 1204 }
1198 curr_map->map_ip = identity__map_ip; 1205 curr_map->map_ip = identity__map_ip;
1199 curr_map->unmap_ip = identity__map_ip; 1206 curr_map->unmap_ip = identity__map_ip;
1200 curr_dso->origin = self->origin; 1207 curr_dso->symtab_type = self->symtab_type;
1201 map_groups__insert(kmap->kmaps, curr_map); 1208 map_groups__insert(kmap->kmaps, curr_map);
1202 dsos__add(&self->node, curr_dso); 1209 dsos__add(&self->node, curr_dso);
1203 dso__set_loaded(curr_dso, map->type); 1210 dso__set_loaded(curr_dso, map->type);
@@ -1208,8 +1215,8 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
1208 } 1215 }
1209 1216
1210 if (curr_dso->adjust_symbols) { 1217 if (curr_dso->adjust_symbols) {
1211 pr_debug4("%s: adjusting symbol: st_value: %#Lx " 1218 pr_debug4("%s: adjusting symbol: st_value: %#" PRIx64 " "
1212 "sh_addr: %#Lx sh_offset: %#Lx\n", __func__, 1219 "sh_addr: %#" PRIx64 " sh_offset: %#" PRIx64 "\n", __func__,
1213 (u64)sym.st_value, (u64)shdr.sh_addr, 1220 (u64)sym.st_value, (u64)shdr.sh_addr,
1214 (u64)shdr.sh_offset); 1221 (u64)shdr.sh_offset);
1215 sym.st_value -= shdr.sh_addr - shdr.sh_offset; 1222 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
@@ -1423,21 +1430,21 @@ out:
1423char dso__symtab_origin(const struct dso *self) 1430char dso__symtab_origin(const struct dso *self)
1424{ 1431{
1425 static const char origin[] = { 1432 static const char origin[] = {
1426 [DSO__ORIG_KERNEL] = 'k', 1433 [SYMTAB__KALLSYMS] = 'k',
1427 [DSO__ORIG_JAVA_JIT] = 'j', 1434 [SYMTAB__JAVA_JIT] = 'j',
1428 [DSO__ORIG_BUILD_ID_CACHE] = 'B', 1435 [SYMTAB__BUILD_ID_CACHE] = 'B',
1429 [DSO__ORIG_FEDORA] = 'f', 1436 [SYMTAB__FEDORA_DEBUGINFO] = 'f',
1430 [DSO__ORIG_UBUNTU] = 'u', 1437 [SYMTAB__UBUNTU_DEBUGINFO] = 'u',
1431 [DSO__ORIG_BUILDID] = 'b', 1438 [SYMTAB__BUILDID_DEBUGINFO] = 'b',
1432 [DSO__ORIG_DSO] = 'd', 1439 [SYMTAB__SYSTEM_PATH_DSO] = 'd',
1433 [DSO__ORIG_KMODULE] = 'K', 1440 [SYMTAB__SYSTEM_PATH_KMODULE] = 'K',
1434 [DSO__ORIG_GUEST_KERNEL] = 'g', 1441 [SYMTAB__GUEST_KALLSYMS] = 'g',
1435 [DSO__ORIG_GUEST_KMODULE] = 'G', 1442 [SYMTAB__GUEST_KMODULE] = 'G',
1436 }; 1443 };
1437 1444
1438 if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) 1445 if (self == NULL || self->symtab_type == SYMTAB__NOT_FOUND)
1439 return '!'; 1446 return '!';
1440 return origin[self->origin]; 1447 return origin[self->symtab_type];
1441} 1448}
1442 1449
1443int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) 1450int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
@@ -1470,8 +1477,8 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
1470 1477
1471 if (strncmp(self->name, "/tmp/perf-", 10) == 0) { 1478 if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
1472 ret = dso__load_perf_map(self, map, filter); 1479 ret = dso__load_perf_map(self, map, filter);
1473 self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : 1480 self->symtab_type = ret > 0 ? SYMTAB__JAVA_JIT :
1474 DSO__ORIG_NOT_FOUND; 1481 SYMTAB__NOT_FOUND;
1475 return ret; 1482 return ret;
1476 } 1483 }
1477 1484
@@ -1479,26 +1486,28 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
1479 * On the first pass, only load images if they have a full symtab. 1486 * On the first pass, only load images if they have a full symtab.
1480 * Failing that, do a second pass where we accept .dynsym also 1487 * Failing that, do a second pass where we accept .dynsym also
1481 */ 1488 */
1482 for (self->origin = DSO__ORIG_BUILD_ID_CACHE, want_symtab = 1; 1489 want_symtab = 1;
1483 self->origin != DSO__ORIG_NOT_FOUND; 1490restart:
1484 self->origin++) { 1491 for (self->symtab_type = SYMTAB__BUILD_ID_CACHE;
1485 switch (self->origin) { 1492 self->symtab_type != SYMTAB__NOT_FOUND;
1486 case DSO__ORIG_BUILD_ID_CACHE: 1493 self->symtab_type++) {
1494 switch (self->symtab_type) {
1495 case SYMTAB__BUILD_ID_CACHE:
1487 /* skip the locally configured cache if a symfs is given */ 1496 /* skip the locally configured cache if a symfs is given */
1488 if (symbol_conf.symfs[0] || 1497 if (symbol_conf.symfs[0] ||
1489 (dso__build_id_filename(self, name, size) == NULL)) { 1498 (dso__build_id_filename(self, name, size) == NULL)) {
1490 continue; 1499 continue;
1491 } 1500 }
1492 break; 1501 break;
1493 case DSO__ORIG_FEDORA: 1502 case SYMTAB__FEDORA_DEBUGINFO:
1494 snprintf(name, size, "%s/usr/lib/debug%s.debug", 1503 snprintf(name, size, "%s/usr/lib/debug%s.debug",
1495 symbol_conf.symfs, self->long_name); 1504 symbol_conf.symfs, self->long_name);
1496 break; 1505 break;
1497 case DSO__ORIG_UBUNTU: 1506 case SYMTAB__UBUNTU_DEBUGINFO:
1498 snprintf(name, size, "%s/usr/lib/debug%s", 1507 snprintf(name, size, "%s/usr/lib/debug%s",
1499 symbol_conf.symfs, self->long_name); 1508 symbol_conf.symfs, self->long_name);
1500 break; 1509 break;
1501 case DSO__ORIG_BUILDID: { 1510 case SYMTAB__BUILDID_DEBUGINFO: {
1502 char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 1511 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
1503 1512
1504 if (!self->has_build_id) 1513 if (!self->has_build_id)
@@ -1512,34 +1521,24 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
1512 symbol_conf.symfs, build_id_hex, build_id_hex + 2); 1521 symbol_conf.symfs, build_id_hex, build_id_hex + 2);
1513 } 1522 }
1514 break; 1523 break;
1515 case DSO__ORIG_DSO: 1524 case SYMTAB__SYSTEM_PATH_DSO:
1516 snprintf(name, size, "%s%s", 1525 snprintf(name, size, "%s%s",
1517 symbol_conf.symfs, self->long_name); 1526 symbol_conf.symfs, self->long_name);
1518 break; 1527 break;
1519 case DSO__ORIG_GUEST_KMODULE: 1528 case SYMTAB__GUEST_KMODULE:
1520 if (map->groups && map->groups->machine) 1529 if (map->groups && machine)
1521 root_dir = map->groups->machine->root_dir; 1530 root_dir = machine->root_dir;
1522 else 1531 else
1523 root_dir = ""; 1532 root_dir = "";
1524 snprintf(name, size, "%s%s%s", symbol_conf.symfs, 1533 snprintf(name, size, "%s%s%s", symbol_conf.symfs,
1525 root_dir, self->long_name); 1534 root_dir, self->long_name);
1526 break; 1535 break;
1527 1536
1528 case DSO__ORIG_KMODULE: 1537 case SYMTAB__SYSTEM_PATH_KMODULE:
1529 snprintf(name, size, "%s%s", symbol_conf.symfs, 1538 snprintf(name, size, "%s%s", symbol_conf.symfs,
1530 self->long_name); 1539 self->long_name);
1531 break; 1540 break;
1532 1541 default:;
1533 default:
1534 /*
1535 * If we wanted a full symtab but no image had one,
1536 * relax our requirements and repeat the search.
1537 */
1538 if (want_symtab) {
1539 want_symtab = 0;
1540 self->origin = DSO__ORIG_BUILD_ID_CACHE;
1541 } else
1542 continue;
1543 } 1542 }
1544 1543
1545 /* Name is now the name of the next image to try */ 1544 /* Name is now the name of the next image to try */
@@ -1566,6 +1565,15 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
1566 } 1565 }
1567 } 1566 }
1568 1567
1568 /*
1569 * If we wanted a full symtab but no image had one,
1570 * relax our requirements and repeat the search.
1571 */
1572 if (ret <= 0 && want_symtab) {
1573 want_symtab = 0;
1574 goto restart;
1575 }
1576
1569 free(name); 1577 free(name);
1570 if (ret < 0 && strstr(self->name, " (deleted)") != NULL) 1578 if (ret < 0 && strstr(self->name, " (deleted)") != NULL)
1571 return 0; 1579 return 0;
@@ -1750,9 +1758,9 @@ struct map *machine__new_module(struct machine *self, u64 start,
1750 return NULL; 1758 return NULL;
1751 1759
1752 if (machine__is_host(self)) 1760 if (machine__is_host(self))
1753 dso->origin = DSO__ORIG_KMODULE; 1761 dso->symtab_type = SYMTAB__SYSTEM_PATH_KMODULE;
1754 else 1762 else
1755 dso->origin = DSO__ORIG_GUEST_KMODULE; 1763 dso->symtab_type = SYMTAB__GUEST_KMODULE;
1756 map_groups__insert(&self->kmaps, map); 1764 map_groups__insert(&self->kmaps, map);
1757 return map; 1765 return map;
1758} 1766}
@@ -1828,7 +1836,7 @@ int dso__load_vmlinux(struct dso *self, struct map *map,
1828 int err = -1, fd; 1836 int err = -1, fd;
1829 char symfs_vmlinux[PATH_MAX]; 1837 char symfs_vmlinux[PATH_MAX];
1830 1838
1831 snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s/%s", 1839 snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s",
1832 symbol_conf.symfs, vmlinux); 1840 symbol_conf.symfs, vmlinux);
1833 fd = open(symfs_vmlinux, O_RDONLY); 1841 fd = open(symfs_vmlinux, O_RDONLY);
1834 if (fd < 0) 1842 if (fd < 0)
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/types.h b/tools/perf/util/types.h
index 7d6b8331f898..5f3689a3d085 100644
--- a/tools/perf/util/types.h
+++ b/tools/perf/util/types.h
@@ -1,12 +1,14 @@
1#ifndef __PERF_TYPES_H 1#ifndef __PERF_TYPES_H
2#define __PERF_TYPES_H 2#define __PERF_TYPES_H
3 3
4#include <stdint.h>
5
4/* 6/*
5 * We define u64 as unsigned long long for every architecture 7 * We define u64 as uint64_t for every architecture
6 * so that we can print it with %Lx without getting warnings. 8 * so that we can print it with "%"PRIx64 without getting warnings.
7 */ 9 */
8typedef unsigned long long u64; 10typedef uint64_t u64;
9typedef signed long long s64; 11typedef int64_t s64;
10typedef unsigned int u32; 12typedef unsigned int u32;
11typedef signed int s32; 13typedef signed int s32;
12typedef unsigned short u16; 14typedef unsigned short u16;
diff --git a/tools/perf/util/ui/browser.c b/tools/perf/util/ui/browser.c
index 8bc010edca25..611219f80680 100644
--- a/tools/perf/util/ui/browser.c
+++ b/tools/perf/util/ui/browser.c
@@ -1,4 +1,5 @@
1#include "libslang.h" 1#include "libslang.h"
2#include "ui.h"
2#include <linux/compiler.h> 3#include <linux/compiler.h>
3#include <linux/list.h> 4#include <linux/list.h>
4#include <linux/rbtree.h> 5#include <linux/rbtree.h>
@@ -156,6 +157,20 @@ void ui_browser__add_exit_keys(struct ui_browser *self, int keys[])
156 } 157 }
157} 158}
158 159
160void __ui_browser__show_title(struct ui_browser *browser, const char *title)
161{
162 SLsmg_gotorc(0, 0);
163 ui_browser__set_color(browser, NEWT_COLORSET_ROOT);
164 slsmg_write_nstring(title, browser->width);
165}
166
167void ui_browser__show_title(struct ui_browser *browser, const char *title)
168{
169 pthread_mutex_lock(&ui__lock);
170 __ui_browser__show_title(browser, title);
171 pthread_mutex_unlock(&ui__lock);
172}
173
159int ui_browser__show(struct ui_browser *self, const char *title, 174int ui_browser__show(struct ui_browser *self, const char *title,
160 const char *helpline, ...) 175 const char *helpline, ...)
161{ 176{
@@ -178,9 +193,8 @@ int ui_browser__show(struct ui_browser *self, const char *title,
178 if (self->sb == NULL) 193 if (self->sb == NULL)
179 return -1; 194 return -1;
180 195
181 SLsmg_gotorc(0, 0); 196 pthread_mutex_lock(&ui__lock);
182 ui_browser__set_color(self, NEWT_COLORSET_ROOT); 197 __ui_browser__show_title(self, title);
183 slsmg_write_nstring(title, self->width);
184 198
185 ui_browser__add_exit_keys(self, keys); 199 ui_browser__add_exit_keys(self, keys);
186 newtFormAddComponent(self->form, self->sb); 200 newtFormAddComponent(self->form, self->sb);
@@ -188,25 +202,30 @@ int ui_browser__show(struct ui_browser *self, const char *title,
188 va_start(ap, helpline); 202 va_start(ap, helpline);
189 ui_helpline__vpush(helpline, ap); 203 ui_helpline__vpush(helpline, ap);
190 va_end(ap); 204 va_end(ap);
205 pthread_mutex_unlock(&ui__lock);
191 return 0; 206 return 0;
192} 207}
193 208
194void ui_browser__hide(struct ui_browser *self) 209void ui_browser__hide(struct ui_browser *self)
195{ 210{
211 pthread_mutex_lock(&ui__lock);
196 newtFormDestroy(self->form); 212 newtFormDestroy(self->form);
197 self->form = NULL; 213 self->form = NULL;
198 ui_helpline__pop(); 214 ui_helpline__pop();
215 pthread_mutex_unlock(&ui__lock);
199} 216}
200 217
201int ui_browser__refresh(struct ui_browser *self) 218int ui_browser__refresh(struct ui_browser *self)
202{ 219{
203 int row; 220 int row;
204 221
222 pthread_mutex_lock(&ui__lock);
205 newtScrollbarSet(self->sb, self->index, self->nr_entries - 1); 223 newtScrollbarSet(self->sb, self->index, self->nr_entries - 1);
206 row = self->refresh(self); 224 row = self->refresh(self);
207 ui_browser__set_color(self, HE_COLORSET_NORMAL); 225 ui_browser__set_color(self, HE_COLORSET_NORMAL);
208 SLsmg_fill_region(self->y + row, self->x, 226 SLsmg_fill_region(self->y + row, self->x,
209 self->height - row, self->width, ' '); 227 self->height - row, self->width, ' ');
228 pthread_mutex_unlock(&ui__lock);
210 229
211 return 0; 230 return 0;
212} 231}
diff --git a/tools/perf/util/ui/browser.h b/tools/perf/util/ui/browser.h
index 0dc7e4da36f5..fc63dda10910 100644
--- a/tools/perf/util/ui/browser.h
+++ b/tools/perf/util/ui/browser.h
@@ -24,7 +24,6 @@ struct ui_browser {
24 u32 nr_entries; 24 u32 nr_entries;
25}; 25};
26 26
27
28void ui_browser__set_color(struct ui_browser *self, int color); 27void ui_browser__set_color(struct ui_browser *self, int color);
29void ui_browser__set_percent_color(struct ui_browser *self, 28void ui_browser__set_percent_color(struct ui_browser *self,
30 double percent, bool current); 29 double percent, bool current);
@@ -35,6 +34,8 @@ void ui_browser__reset_index(struct ui_browser *self);
35void ui_browser__gotorc(struct ui_browser *self, int y, int x); 34void ui_browser__gotorc(struct ui_browser *self, int y, int x);
36void ui_browser__add_exit_key(struct ui_browser *self, int key); 35void ui_browser__add_exit_key(struct ui_browser *self, int key);
37void ui_browser__add_exit_keys(struct ui_browser *self, int keys[]); 36void ui_browser__add_exit_keys(struct ui_browser *self, int keys[]);
37void __ui_browser__show_title(struct ui_browser *browser, const char *title);
38void ui_browser__show_title(struct ui_browser *browser, const char *title);
38int ui_browser__show(struct ui_browser *self, const char *title, 39int ui_browser__show(struct ui_browser *self, const char *title,
39 const char *helpline, ...); 40 const char *helpline, ...);
40void ui_browser__hide(struct ui_browser *self); 41void ui_browser__hide(struct ui_browser *self);
diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c
index 82b78f99251b..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 ebda8c3fde9e..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;
@@ -350,7 +353,7 @@ static char *callchain_list__sym_name(struct callchain_list *self,
350 if (self->ms.sym) 353 if (self->ms.sym)
351 return self->ms.sym->name; 354 return self->ms.sym->name;
352 355
353 snprintf(bf, bfsize, "%#Lx", self->ip); 356 snprintf(bf, bfsize, "%#" PRIx64, self->ip);
354 return bf; 357 return bf;
355} 358}
356 359
@@ -377,7 +380,7 @@ static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *self,
377 while (node) { 380 while (node) {
378 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); 381 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
379 struct rb_node *next = rb_next(node); 382 struct rb_node *next = rb_next(node);
380 u64 cumul = cumul_hits(child); 383 u64 cumul = callchain_cumul_hits(child);
381 struct callchain_list *chain; 384 struct callchain_list *chain;
382 char folded_sign = ' '; 385 char folded_sign = ' ';
383 int first = true; 386 int first = true;
@@ -638,6 +641,9 @@ static void ui_browser__hists_seek(struct ui_browser *self,
638 struct rb_node *nd; 641 struct rb_node *nd;
639 bool first = true; 642 bool first = true;
640 643
644 if (self->nr_entries == 0)
645 return;
646
641 switch (whence) { 647 switch (whence) {
642 case SEEK_SET: 648 case SEEK_SET:
643 nd = hists__filter_entries(rb_first(self->entries)); 649 nd = hists__filter_entries(rb_first(self->entries));
@@ -797,8 +803,11 @@ static int hists__browser_title(struct hists *self, char *bf, size_t size,
797 return printed; 803 return printed;
798} 804}
799 805
800int hists__browse(struct hists *self, const char *helpline, const char *ev_name) 806static int perf_evsel__hists_browse(struct perf_evsel *evsel,
807 const char *helpline, const char *ev_name,
808 bool left_exits)
801{ 809{
810 struct hists *self = &evsel->hists;
802 struct hist_browser *browser = hist_browser__new(self); 811 struct hist_browser *browser = hist_browser__new(self);
803 struct pstack *fstack; 812 struct pstack *fstack;
804 const struct thread *thread_filter = NULL; 813 const struct thread *thread_filter = NULL;
@@ -818,8 +827,8 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
818 hists__browser_title(self, msg, sizeof(msg), ev_name, 827 hists__browser_title(self, msg, sizeof(msg), ev_name,
819 dso_filter, thread_filter); 828 dso_filter, thread_filter);
820 while (1) { 829 while (1) {
821 const struct thread *thread; 830 const struct thread *thread = NULL;
822 const struct dso *dso; 831 const struct dso *dso = NULL;
823 char *options[16]; 832 char *options[16];
824 int nr_options = 0, choice = 0, i, 833 int nr_options = 0, choice = 0, i,
825 annotate = -2, zoom_dso = -2, zoom_thread = -2, 834 annotate = -2, zoom_dso = -2, zoom_thread = -2,
@@ -827,8 +836,10 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
827 836
828 key = hist_browser__run(browser, msg); 837 key = hist_browser__run(browser, msg);
829 838
830 thread = hist_browser__selected_thread(browser); 839 if (browser->he_selection != NULL) {
831 dso = browser->selection->map ? browser->selection->map->dso : NULL; 840 thread = hist_browser__selected_thread(browser);
841 dso = browser->selection->map ? browser->selection->map->dso : NULL;
842 }
832 843
833 switch (key) { 844 switch (key) {
834 case NEWT_KEY_TAB: 845 case NEWT_KEY_TAB:
@@ -839,7 +850,8 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
839 */ 850 */
840 goto out_free_stack; 851 goto out_free_stack;
841 case 'a': 852 case 'a':
842 if (browser->selection->map == NULL && 853 if (browser->selection == NULL ||
854 browser->selection->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 e35437dfa5b4..8462bffe20bc 100644
--- a/tools/perf/util/ui/browsers/map.c
+++ b/tools/perf/util/ui/browsers/map.c
@@ -1,5 +1,6 @@
1#include "../libslang.h" 1#include "../libslang.h"
2#include <elf.h> 2#include <elf.h>
3#include <inttypes.h>
3#include <sys/ttydefaults.h> 4#include <sys/ttydefaults.h>
4#include <ctype.h> 5#include <ctype.h>
5#include <string.h> 6#include <string.h>
@@ -40,7 +41,7 @@ static int ui_entry__read(const char *title, char *bf, size_t size, int width)
40out_free_form: 41out_free_form:
41 newtPopWindow(); 42 newtPopWindow();
42 newtFormDestroy(form); 43 newtFormDestroy(form);
43 return 0; 44 return err;
44} 45}
45 46
46struct map_browser { 47struct map_browser {
@@ -57,7 +58,7 @@ static void map_browser__write(struct ui_browser *self, void *nd, int row)
57 int width; 58 int width;
58 59
59 ui_browser__set_percent_color(self, 0, current_entry); 60 ui_browser__set_percent_color(self, 0, current_entry);
60 slsmg_printf("%*llx %*llx %c ", 61 slsmg_printf("%*" PRIx64 " %*" PRIx64 " %c ",
61 mb->addrlen, sym->start, mb->addrlen, sym->end, 62 mb->addrlen, sym->start, mb->addrlen, sym->end,
62 sym->binding == STB_GLOBAL ? 'g' : 63 sym->binding == STB_GLOBAL ? 'g' :
63 sym->binding == STB_LOCAL ? 'l' : 'w'); 64 sym->binding == STB_LOCAL ? 'l' : 'w');
@@ -150,6 +151,6 @@ int map__browse(struct map *self)
150 ++mb.b.nr_entries; 151 ++mb.b.nr_entries;
151 } 152 }
152 153
153 mb.addrlen = snprintf(tmp, sizeof(tmp), "%llx", maxaddr); 154 mb.addrlen = snprintf(tmp, sizeof(tmp), "%" PRIx64, maxaddr);
154 return map_browser__run(&mb); 155 return map_browser__run(&mb);
155} 156}
diff --git a/tools/perf/util/ui/browsers/top.c b/tools/perf/util/ui/browsers/top.c
new file mode 100644
index 000000000000..5a06538532af
--- /dev/null
+++ b/tools/perf/util/ui/browsers/top.c
@@ -0,0 +1,213 @@
1/*
2 * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
3 *
4 * Parts came from builtin-{top,stat,record}.c, see those files for further
5 * copyright notes.
6 *
7 * Released under the GPL v2. (and only v2, not any later version)
8 */
9#include "../browser.h"
10#include "../../annotate.h"
11#include "../helpline.h"
12#include "../libslang.h"
13#include "../util.h"
14#include "../../evlist.h"
15#include "../../hist.h"
16#include "../../sort.h"
17#include "../../symbol.h"
18#include "../../top.h"
19
20struct perf_top_browser {
21 struct ui_browser b;
22 struct rb_root root;
23 struct sym_entry *selection;
24 float sum_ksamples;
25 int dso_width;
26 int dso_short_width;
27 int sym_width;
28};
29
30static void perf_top_browser__write(struct ui_browser *browser, void *entry, int row)
31{
32 struct perf_top_browser *top_browser = container_of(browser, struct perf_top_browser, b);
33 struct sym_entry *syme = rb_entry(entry, struct sym_entry, rb_node);
34 bool current_entry = ui_browser__is_current_entry(browser, row);
35 struct symbol *symbol = sym_entry__symbol(syme);
36 struct perf_top *top = browser->priv;
37 int width = browser->width;
38 double pcnt;
39
40 pcnt = 100.0 - (100.0 * ((top_browser->sum_ksamples - syme->snap_count) /
41 top_browser->sum_ksamples));
42 ui_browser__set_percent_color(browser, pcnt, current_entry);
43
44 if (top->evlist->nr_entries == 1 || !top->display_weighted) {
45 slsmg_printf("%20.2f ", syme->weight);
46 width -= 24;
47 } else {
48 slsmg_printf("%9.1f %10ld ", syme->weight, syme->snap_count);
49 width -= 23;
50 }
51
52 slsmg_printf("%4.1f%%", pcnt);
53 width -= 7;
54
55 if (verbose) {
56 slsmg_printf(" %016" PRIx64, symbol->start);
57 width -= 17;
58 }
59
60 slsmg_printf(" %-*.*s ", top_browser->sym_width, top_browser->sym_width,
61 symbol->name);
62 width -= top_browser->sym_width;
63 slsmg_write_nstring(width >= syme->map->dso->long_name_len ?
64 syme->map->dso->long_name :
65 syme->map->dso->short_name, width);
66
67 if (current_entry)
68 top_browser->selection = syme;
69}
70
71static void perf_top_browser__update_rb_tree(struct perf_top_browser *browser)
72{
73 struct perf_top *top = browser->b.priv;
74 u64 top_idx = browser->b.top_idx;
75
76 browser->root = RB_ROOT;
77 browser->b.top = NULL;
78 browser->sum_ksamples = perf_top__decay_samples(top, &browser->root);
79 /*
80 * No active symbols
81 */
82 if (top->rb_entries == 0)
83 return;
84
85 perf_top__find_widths(top, &browser->root, &browser->dso_width,
86 &browser->dso_short_width,
87 &browser->sym_width);
88 if (browser->sym_width + browser->dso_width > browser->b.width - 29) {
89 browser->dso_width = browser->dso_short_width;
90 if (browser->sym_width + browser->dso_width > browser->b.width - 29)
91 browser->sym_width = browser->b.width - browser->dso_width - 29;
92 }
93
94 /*
95 * Adjust the ui_browser indexes since the entries in the browser->root
96 * rb_tree may have changed, then seek it from start, so that we get a
97 * possible new top of the screen.
98 */
99 browser->b.nr_entries = top->rb_entries;
100
101 if (top_idx >= browser->b.nr_entries) {
102 if (browser->b.height >= browser->b.nr_entries)
103 top_idx = browser->b.nr_entries - browser->b.height;
104 else
105 top_idx = 0;
106 }
107
108 if (browser->b.index >= top_idx + browser->b.height)
109 browser->b.index = top_idx + browser->b.index - browser->b.top_idx;
110
111 if (browser->b.index >= browser->b.nr_entries)
112 browser->b.index = browser->b.nr_entries - 1;
113
114 browser->b.top_idx = top_idx;
115 browser->b.seek(&browser->b, top_idx, SEEK_SET);
116}
117
118static void perf_top_browser__annotate(struct perf_top_browser *browser)
119{
120 struct sym_entry *syme = browser->selection;
121 struct symbol *sym = sym_entry__symbol(syme);
122 struct annotation *notes = symbol__annotation(sym);
123 struct perf_top *top = browser->b.priv;
124
125 if (notes->src != NULL)
126 goto do_annotation;
127
128 pthread_mutex_lock(&notes->lock);
129
130 top->sym_filter_entry = NULL;
131
132 if (symbol__alloc_hist(sym, top->evlist->nr_entries) < 0) {
133 pr_err("Not enough memory for annotating '%s' symbol!\n",
134 sym->name);
135 pthread_mutex_unlock(&notes->lock);
136 return;
137 }
138
139 top->sym_filter_entry = syme;
140
141 pthread_mutex_unlock(&notes->lock);
142do_annotation:
143 symbol__tui_annotate(sym, syme->map, 0, top->delay_secs * 1000);
144}
145
146static int perf_top_browser__run(struct perf_top_browser *browser)
147{
148 int key;
149 char title[160];
150 struct perf_top *top = browser->b.priv;
151 int delay_msecs = top->delay_secs * 1000;
152 int exit_keys[] = { 'a', NEWT_KEY_ENTER, NEWT_KEY_RIGHT, 0, };
153
154 perf_top_browser__update_rb_tree(browser);
155 perf_top__header_snprintf(top, title, sizeof(title));
156 perf_top__reset_sample_counters(top);
157
158 if (ui_browser__show(&browser->b, title,
159 "ESC: exit, ENTER|->|a: Live Annotate") < 0)
160 return -1;
161
162 newtFormSetTimer(browser->b.form, delay_msecs);
163 ui_browser__add_exit_keys(&browser->b, exit_keys);
164
165 while (1) {
166 key = ui_browser__run(&browser->b);
167
168 switch (key) {
169 case -1:
170 /* FIXME we need to check if it was es.reason == NEWT_EXIT_TIMER */
171 perf_top_browser__update_rb_tree(browser);
172 perf_top__header_snprintf(top, title, sizeof(title));
173 perf_top__reset_sample_counters(top);
174 ui_browser__set_color(&browser->b, NEWT_COLORSET_ROOT);
175 SLsmg_gotorc(0, 0);
176 slsmg_write_nstring(title, browser->b.width);
177 break;
178 case 'a':
179 case NEWT_KEY_RIGHT:
180 case NEWT_KEY_ENTER:
181 if (browser->selection)
182 perf_top_browser__annotate(browser);
183 break;
184 case NEWT_KEY_LEFT:
185 continue;
186 case NEWT_KEY_ESCAPE:
187 if (!ui__dialog_yesno("Do you really want to exit?"))
188 continue;
189 /* Fall thru */
190 default:
191 goto out;
192 }
193 }
194out:
195 ui_browser__hide(&browser->b);
196 return key;
197}
198
199int perf_top__tui_browser(struct perf_top *top)
200{
201 struct perf_top_browser browser = {
202 .b = {
203 .entries = &browser.root,
204 .refresh = ui_browser__rb_tree_refresh,
205 .seek = ui_browser__rb_tree_seek,
206 .write = perf_top_browser__write,
207 .priv = top,
208 },
209 };
210
211 ui_helpline__push("Press <- or ESC to exit");
212 return perf_top_browser__run(&browser);
213}
diff --git a/tools/perf/util/ui/helpline.c b/tools/perf/util/ui/helpline.c
index 8d79daa4458a..f36d2ff509ed 100644
--- a/tools/perf/util/ui/helpline.c
+++ b/tools/perf/util/ui/helpline.c
@@ -5,6 +5,7 @@
5 5
6#include "../debug.h" 6#include "../debug.h"
7#include "helpline.h" 7#include "helpline.h"
8#include "ui.h"
8 9
9void ui_helpline__pop(void) 10void ui_helpline__pop(void)
10{ 11{
@@ -55,7 +56,8 @@ int ui_helpline__show_help(const char *format, va_list ap)
55 int ret; 56 int ret;
56 static int backlog; 57 static int backlog;
57 58
58 ret = vsnprintf(ui_helpline__last_msg + backlog, 59 pthread_mutex_lock(&ui__lock);
60 ret = vsnprintf(ui_helpline__last_msg + backlog,
59 sizeof(ui_helpline__last_msg) - backlog, format, ap); 61 sizeof(ui_helpline__last_msg) - backlog, format, ap);
60 backlog += ret; 62 backlog += ret;
61 63
@@ -64,6 +66,7 @@ int ui_helpline__show_help(const char *format, va_list ap)
64 newtRefresh(); 66 newtRefresh();
65 backlog = 0; 67 backlog = 0;
66 } 68 }
69 pthread_mutex_unlock(&ui__lock);
67 70
68 return ret; 71 return ret;
69} 72}
diff --git a/tools/perf/util/ui/libslang.h b/tools/perf/util/ui/libslang.h
index 5623da8e8080..2b63e1c9b181 100644
--- a/tools/perf/util/ui/libslang.h
+++ b/tools/perf/util/ui/libslang.h
@@ -13,11 +13,11 @@
13 13
14#if SLANG_VERSION < 20104 14#if SLANG_VERSION < 20104
15#define slsmg_printf(msg, args...) \ 15#define slsmg_printf(msg, args...) \
16 SLsmg_printf((char *)msg, ##args) 16 SLsmg_printf((char *)(msg), ##args)
17#define slsmg_write_nstring(msg, len) \ 17#define slsmg_write_nstring(msg, len) \
18 SLsmg_write_nstring((char *)msg, len) 18 SLsmg_write_nstring((char *)(msg), len)
19#define sltt_set_color(obj, name, fg, bg) \ 19#define sltt_set_color(obj, name, fg, bg) \
20 SLtt_set_color(obj,(char *)name, (char *)fg, (char *)bg) 20 SLtt_set_color(obj,(char *)(name), (char *)(fg), (char *)(bg))
21#else 21#else
22#define slsmg_printf SLsmg_printf 22#define slsmg_printf SLsmg_printf
23#define slsmg_write_nstring SLsmg_write_nstring 23#define slsmg_write_nstring SLsmg_write_nstring
diff --git a/tools/perf/util/ui/setup.c b/tools/perf/util/ui/setup.c
index 662085032eb7..ee46d671db59 100644
--- a/tools/perf/util/ui/setup.c
+++ b/tools/perf/util/ui/setup.c
@@ -6,6 +6,9 @@
6#include "../debug.h" 6#include "../debug.h"
7#include "browser.h" 7#include "browser.h"
8#include "helpline.h" 8#include "helpline.h"
9#include "ui.h"
10
11pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER;
9 12
10static void newt_suspend(void *d __used) 13static void newt_suspend(void *d __used)
11{ 14{
@@ -14,11 +17,12 @@ static void newt_suspend(void *d __used)
14 newtResume(); 17 newtResume();
15} 18}
16 19
17void setup_browser(void) 20void setup_browser(bool fallback_to_pager)
18{ 21{
19 if (!isatty(1) || !use_browser || dump_trace) { 22 if (!isatty(1) || !use_browser || dump_trace) {
20 use_browser = 0; 23 use_browser = 0;
21 setup_pager(); 24 if (fallback_to_pager)
25 setup_pager();
22 return; 26 return;
23 } 27 }
24 28
diff --git a/tools/perf/util/ui/ui.h b/tools/perf/util/ui/ui.h
new file mode 100644
index 000000000000..d264e059c829
--- /dev/null
+++ b/tools/perf/util/ui/ui.h
@@ -0,0 +1,8 @@
1#ifndef _PERF_UI_H_
2#define _PERF_UI_H_ 1
3
4#include <pthread.h>
5
6extern pthread_mutex_t ui__lock;
7
8#endif /* _PERF_UI_H_ */
diff --git a/tools/perf/util/ui/util.c b/tools/perf/util/ui/util.c
index 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/perf/util/values.c b/tools/perf/util/values.c
index cfa55d686e3b..bdd33470b235 100644
--- a/tools/perf/util/values.c
+++ b/tools/perf/util/values.c
@@ -150,7 +150,7 @@ static void perf_read_values__display_pretty(FILE *fp,
150 if (width > tidwidth) 150 if (width > tidwidth)
151 tidwidth = width; 151 tidwidth = width;
152 for (j = 0; j < values->counters; j++) { 152 for (j = 0; j < values->counters; j++) {
153 width = snprintf(NULL, 0, "%Lu", values->value[i][j]); 153 width = snprintf(NULL, 0, "%" PRIu64, values->value[i][j]);
154 if (width > counterwidth[j]) 154 if (width > counterwidth[j])
155 counterwidth[j] = width; 155 counterwidth[j] = width;
156 } 156 }
@@ -165,7 +165,7 @@ static void perf_read_values__display_pretty(FILE *fp,
165 fprintf(fp, " %*d %*d", pidwidth, values->pid[i], 165 fprintf(fp, " %*d %*d", pidwidth, values->pid[i],
166 tidwidth, values->tid[i]); 166 tidwidth, values->tid[i]);
167 for (j = 0; j < values->counters; j++) 167 for (j = 0; j < values->counters; j++)
168 fprintf(fp, " %*Lu", 168 fprintf(fp, " %*" PRIu64,
169 counterwidth[j], values->value[i][j]); 169 counterwidth[j], values->value[i][j]);
170 fprintf(fp, "\n"); 170 fprintf(fp, "\n");
171 } 171 }
@@ -196,13 +196,13 @@ static void perf_read_values__display_raw(FILE *fp,
196 width = strlen(values->countername[j]); 196 width = strlen(values->countername[j]);
197 if (width > namewidth) 197 if (width > namewidth)
198 namewidth = width; 198 namewidth = width;
199 width = snprintf(NULL, 0, "%llx", values->counterrawid[j]); 199 width = snprintf(NULL, 0, "%" PRIx64, values->counterrawid[j]);
200 if (width > rawwidth) 200 if (width > rawwidth)
201 rawwidth = width; 201 rawwidth = width;
202 } 202 }
203 for (i = 0; i < values->threads; i++) { 203 for (i = 0; i < values->threads; i++) {
204 for (j = 0; j < values->counters; j++) { 204 for (j = 0; j < values->counters; j++) {
205 width = snprintf(NULL, 0, "%Lu", values->value[i][j]); 205 width = snprintf(NULL, 0, "%" PRIu64, values->value[i][j]);
206 if (width > countwidth) 206 if (width > countwidth)
207 countwidth = width; 207 countwidth = width;
208 } 208 }
@@ -214,7 +214,7 @@ static void perf_read_values__display_raw(FILE *fp,
214 countwidth, "Count"); 214 countwidth, "Count");
215 for (i = 0; i < values->threads; i++) 215 for (i = 0; i < values->threads; i++)
216 for (j = 0; j < values->counters; j++) 216 for (j = 0; j < values->counters; j++)
217 fprintf(fp, " %*d %*d %*s %*llx %*Lu\n", 217 fprintf(fp, " %*d %*d %*s %*" PRIx64 " %*" PRIu64,
218 pidwidth, values->pid[i], 218 pidwidth, values->pid[i],
219 tidwidth, values->tid[i], 219 tidwidth, values->tid[i],
220 namewidth, values->countername[j], 220 namewidth, values->countername[j],
diff --git a/tools/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/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