aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
authorFlorian Tobias Schandinat <FlorianSchandinat@gmx.de>2011-08-17 12:14:01 -0400
committerFlorian Tobias Schandinat <FlorianSchandinat@gmx.de>2011-08-17 12:14:01 -0400
commit94bd217e2d683719ab21a4ac117d8a1b91cbedc9 (patch)
treef2d506818cc1643ca816f609518ab5d1cdb28e66 /tools/perf
parent5dd72f12df00cbabc16de770b79b17ced63138be (diff)
parent93ee7a9340d64f20295aacc3fb6a22b759323280 (diff)
Merge commit 'v3.1-rc2' into HEAD
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/.gitignore1
-rw-r--r--tools/perf/Documentation/Makefile19
-rw-r--r--tools/perf/Documentation/perf-annotate.txt6
-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.txt32
-rw-r--r--tools/perf/Documentation/perf-record.txt11
-rw-r--r--tools/perf/Documentation/perf-report.txt21
-rw-r--r--tools/perf/Documentation/perf-script-perl.txt1
-rw-r--r--tools/perf/Documentation/perf-script-python.txt1
-rw-r--r--tools/perf/Documentation/perf-script.txt76
-rw-r--r--tools/perf/Documentation/perf-stat.txt11
-rw-r--r--tools/perf/Makefile767
-rw-r--r--tools/perf/bench/sched-pipe.c2
-rw-r--r--tools/perf/builtin-annotate.c356
-rw-r--r--tools/perf/builtin-diff.c17
-rw-r--r--tools/perf/builtin-evlist.c54
-rw-r--r--tools/perf/builtin-inject.c89
-rw-r--r--tools/perf/builtin-kmem.c11
-rw-r--r--tools/perf/builtin-list.c43
-rw-r--r--tools/perf/builtin-lock.c31
-rw-r--r--tools/perf/builtin-probe.c73
-rw-r--r--tools/perf/builtin-record.c501
-rw-r--r--tools/perf/builtin-report.c307
-rw-r--r--tools/perf/builtin-sched.c52
-rw-r--r--tools/perf/builtin-script.c574
-rw-r--r--tools/perf/builtin-stat.c712
-rw-r--r--tools/perf/builtin-test.c442
-rw-r--r--tools/perf/builtin-timechart.c24
-rw-r--r--tools/perf/builtin-top.c1104
-rw-r--r--tools/perf/builtin.h1
-rw-r--r--tools/perf/command-list.txt1
-rw-r--r--tools/perf/config/feature-tests.mak (renamed from tools/perf/feature-tests.mak)16
-rw-r--r--tools/perf/config/utilities.mak188
-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-GEN7
-rw-r--r--tools/perf/util/annotate.c605
-rw-r--r--tools/perf/util/annotate.h103
-rw-r--r--tools/perf/util/build-id.c22
-rw-r--r--tools/perf/util/cache.h7
-rw-r--r--tools/perf/util/callchain.c227
-rw-r--r--tools/perf/util/callchain.h82
-rw-r--r--tools/perf/util/cgroup.c178
-rw-r--r--tools/perf/util/cgroup.h17
-rw-r--r--tools/perf/util/config.c32
-rw-r--r--tools/perf/util/cpumap.c5
-rw-r--r--tools/perf/util/cpumap.h2
-rw-r--r--tools/perf/util/debug.c12
-rw-r--r--tools/perf/util/debug.h3
-rw-r--r--tools/perf/util/dwarf-aux.c663
-rw-r--r--tools/perf/util/dwarf-aux.h100
-rw-r--r--tools/perf/util/event.c421
-rw-r--r--tools/perf/util/event.h86
-rw-r--r--tools/perf/util/evlist.c513
-rw-r--r--tools/perf/util/evlist.h76
-rw-r--r--tools/perf/util/evsel.c278
-rw-r--r--tools/perf/util/evsel.h55
-rw-r--r--tools/perf/util/exec_cmd.c19
-rw-r--r--tools/perf/util/header.c623
-rw-r--r--tools/perf/util/header.h93
-rw-r--r--tools/perf/util/hist.c256
-rw-r--r--tools/perf/util/hist.h61
-rw-r--r--tools/perf/util/include/asm/alternative-asm.h8
-rw-r--r--tools/perf/util/include/linux/const.h1
-rw-r--r--tools/perf/util/include/linux/list.h5
-rw-r--r--tools/perf/util/parse-events.c331
-rw-r--r--tools/perf/util/parse-events.h19
-rw-r--r--tools/perf/util/probe-event.c321
-rw-r--r--tools/perf/util/probe-event.h5
-rw-r--r--tools/perf/util/probe-finder.c1039
-rw-r--r--tools/perf/util/probe-finder.h45
-rw-r--r--tools/perf/util/python.c1015
-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.c488
-rw-r--r--tools/perf/util/session.h62
-rw-r--r--tools/perf/util/setup.py43
-rw-r--r--tools/perf/util/sort.c223
-rw-r--r--tools/perf/util/sort.h14
-rw-r--r--tools/perf/util/strfilter.c199
-rw-r--r--tools/perf/util/strfilter.h48
-rw-r--r--tools/perf/util/string.c21
-rw-r--r--tools/perf/util/symbol.c757
-rw-r--r--tools/perf/util/symbol.h115
-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-info.c120
-rw-r--r--tools/perf/util/trace-event-parse.c112
-rw-r--r--tools/perf/util/trace-event-scripting.c10
-rw-r--r--tools/perf/util/trace-event.h11
-rw-r--r--tools/perf/util/ui/browser.c25
-rw-r--r--tools/perf/util/ui/browser.h3
-rw-r--r--tools/perf/util/ui/browsers/annotate.c179
-rw-r--r--tools/perf/util/ui/browsers/hists.c197
-rw-r--r--tools/perf/util/ui/browsers/map.c2
-rw-r--r--tools/perf/util/ui/browsers/top.c213
-rw-r--r--tools/perf/util/ui/helpline.c5
-rw-r--r--tools/perf/util/ui/libslang.h6
-rw-r--r--tools/perf/util/ui/setup.c8
-rw-r--r--tools/perf/util/ui/ui.h8
-rw-r--r--tools/perf/util/ui/util.c7
-rw-r--r--tools/perf/util/util.h27
109 files changed, 10879 insertions, 5509 deletions
diff --git a/tools/perf/.gitignore b/tools/perf/.gitignore
index cb43289e447f..416684be0ad3 100644
--- a/tools/perf/.gitignore
+++ b/tools/perf/.gitignore
@@ -1,4 +1,3 @@
1PERF-BUILD-OPTIONS
2PERF-CFLAGS 1PERF-CFLAGS
3PERF-GUI-VARS 2PERF-GUI-VARS
4PERF-VERSION-FILE 3PERF-VERSION-FILE
diff --git a/tools/perf/Documentation/Makefile b/tools/perf/Documentation/Makefile
index bd498d496952..4626a398836a 100644
--- a/tools/perf/Documentation/Makefile
+++ b/tools/perf/Documentation/Makefile
@@ -178,8 +178,8 @@ install-pdf: pdf
178 $(INSTALL) -d -m 755 $(DESTDIR)$(pdfdir) 178 $(INSTALL) -d -m 755 $(DESTDIR)$(pdfdir)
179 $(INSTALL) -m 644 user-manual.pdf $(DESTDIR)$(pdfdir) 179 $(INSTALL) -m 644 user-manual.pdf $(DESTDIR)$(pdfdir)
180 180
181install-html: html 181#install-html: html
182 '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(DESTDIR)$(htmldir) 182# '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(DESTDIR)$(htmldir)
183 183
184../PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE 184../PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
185 $(QUIET_SUBDIR0)../ $(QUIET_SUBDIR1) PERF-VERSION-FILE 185 $(QUIET_SUBDIR0)../ $(QUIET_SUBDIR1) PERF-VERSION-FILE
@@ -288,15 +288,16 @@ $(patsubst %.txt,%.html,$(wildcard howto/*.txt)): %.html : %.txt
288 sed -e '1,/^$$/d' $< | $(ASCIIDOC) -b xhtml11 - >$@+ && \ 288 sed -e '1,/^$$/d' $< | $(ASCIIDOC) -b xhtml11 - >$@+ && \
289 mv $@+ $@ 289 mv $@+ $@
290 290
291install-webdoc : html 291# UNIMPLEMENTED
292 '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(WEBDOC_DEST) 292#install-webdoc : html
293# '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(WEBDOC_DEST)
293 294
294quick-install: quick-install-man 295# quick-install: quick-install-man
295 296
296quick-install-man: 297# quick-install-man:
297 '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(DOC_REF) $(DESTDIR)$(mandir) 298# '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(DOC_REF) $(DESTDIR)$(mandir)
298 299
299quick-install-html: 300#quick-install-html:
300 '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(HTML_REF) $(DESTDIR)$(htmldir) 301# '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(HTML_REF) $(DESTDIR)$(htmldir)
301 302
302.PHONY: .FORCE-PERF-VERSION-FILE 303.PHONY: .FORCE-PERF-VERSION-FILE
diff --git a/tools/perf/Documentation/perf-annotate.txt b/tools/perf/Documentation/perf-annotate.txt
index 6f5a498608b2..85c5f026930d 100644
--- a/tools/perf/Documentation/perf-annotate.txt
+++ b/tools/perf/Documentation/perf-annotate.txt
@@ -66,6 +66,12 @@ OPTIONS
66 used. This interfaces starts by centering on the line with more 66 used. This interfaces starts by centering on the line with more
67 samples, TAB/UNTAB cycles through the lines with more samples. 67 samples, TAB/UNTAB cycles through the lines with more samples.
68 68
69-c::
70--cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can
71 be provided as a comma-separated list with no space: 0,1. Ranges of
72 CPUs are specified with -: 0-2. Default is to report samples on all
73 CPUs.
74
69SEE ALSO 75SEE ALSO
70-------- 76--------
71linkperf:perf-record[1], linkperf:perf-report[1] 77linkperf:perf-record[1], linkperf:perf-report[1]
diff --git a/tools/perf/Documentation/perf-evlist.txt b/tools/perf/Documentation/perf-evlist.txt
new file mode 100644
index 000000000000..0cada9e053dc
--- /dev/null
+++ b/tools/perf/Documentation/perf-evlist.txt
@@ -0,0 +1,26 @@
1perf-evlist(1)
2==============
3
4NAME
5----
6perf-evlist - List the event names in a perf.data file
7
8SYNOPSIS
9--------
10[verse]
11'perf evlist <options>'
12
13DESCRIPTION
14-----------
15This command displays the names of events sampled in a perf.data file.
16
17OPTIONS
18-------
19-i::
20--input=::
21 Input file name. (default: perf.data)
22
23SEE ALSO
24--------
25linkperf:perf-record[1], linkperf:perf-list[1],
26linkperf:perf-report[1]
diff --git a/tools/perf/Documentation/perf-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..2780d9ce48bf 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
@@ -34,9 +34,11 @@ OPTIONS
34 Specify vmlinux path which has debuginfo (Dwarf binary). 34 Specify vmlinux path which has debuginfo (Dwarf binary).
35 35
36-m:: 36-m::
37--module=MODNAME:: 37--module=MODNAME|PATH::
38 Specify module name in which perf-probe searches probe points 38 Specify module name in which perf-probe searches probe points
39 or lines. 39 or lines. If a path of module file is passed, perf-probe
40 treat it as an offline module (this means you can add a probe on
41 a module which has not been loaded yet).
40 42
41-s:: 43-s::
42--source=PATH:: 44--source=PATH::
@@ -73,6 +75,17 @@ OPTIONS
73 (Only for --vars) Show external defined variables in addition to local 75 (Only for --vars) Show external defined variables in addition to local
74 variables. 76 variables.
75 77
78-F::
79--funcs::
80 Show available functions in given module or kernel.
81
82--filter=FILTER::
83 (Only for --vars and --funcs) Set filter. FILTER is a combination of glob
84 pattern, see FILTER PATTERN for detail.
85 Default FILTER is "!__k???tab_* & !__crc_*" for --vars, and "!_*"
86 for --funcs.
87 If several filters are specified, only the last filter is used.
88
76-f:: 89-f::
77--force:: 90--force::
78 Forcibly add events with existing name. 91 Forcibly add events with existing name.
@@ -117,13 +130,14 @@ LINE SYNTAX
117----------- 130-----------
118Line range is described by following syntax. 131Line range is described by following syntax.
119 132
120 "FUNC[:RLN[+NUM|-RLN2]]|SRC[:ALN[+NUM|-ALN2]]" 133 "FUNC[@SRC][:RLN[+NUM|-RLN2]]|SRC[:ALN[+NUM|-ALN2]]"
121 134
122FUNC specifies the function name of showing lines. 'RLN' is the start line 135FUNC 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 136number 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, 137probe 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 138and 'ALN2' is end line number in the file. It is also possible to specify how
126many lines to show by using 'NUM'. 139many lines to show by using 'NUM'. Moreover, 'FUNC@SRC' combination is good
140for 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. 141So, "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 142
129LAZY MATCHING 143LAZY MATCHING
@@ -135,6 +149,14 @@ e.g.
135 149
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.) 150This 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 151
152FILTER PATTERN
153--------------
154 The filter pattern is a glob matching pattern(s) to filter variables.
155 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 "(" ")".
156
157e.g.
158 With --filter "foo* | bar*", perf probe -V shows variables which start with "foo" or "bar".
159 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 160
139EXAMPLES 161EXAMPLES
140-------- 162--------
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-report.txt b/tools/perf/Documentation/perf-report.txt
index 8ba03d6e5398..04253c07d19a 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -80,15 +80,24 @@ OPTIONS
80--dump-raw-trace:: 80--dump-raw-trace::
81 Dump raw trace in ASCII. 81 Dump raw trace in ASCII.
82 82
83-g [type,min]:: 83-g [type,min,order]::
84--call-graph:: 84--call-graph::
85 Display call chains using type and min percent threshold. 85 Display call chains using type, min percent threshold and order.
86 type can be either: 86 type can be either:
87 - flat: single column, linear exposure of call chains. 87 - flat: single column, linear exposure of call chains.
88 - graph: use a graph tree, displaying absolute overhead rates. 88 - graph: use a graph tree, displaying absolute overhead rates.
89 - fractal: like graph, but displays relative rates. Each branch of 89 - fractal: like graph, but displays relative rates. Each branch of
90 the tree is considered as a new profiled object. + 90 the tree is considered as a new profiled object. +
91 Default: fractal,0.5. 91
92 order can be either:
93 - callee: callee based call graph.
94 - caller: inverted caller based call graph.
95
96 Default: fractal,0.5,callee.
97
98-G::
99--inverted::
100 alias for inverted caller based call graph.
92 101
93--pretty=<key>:: 102--pretty=<key>::
94 Pretty printing style. key: normal, raw 103 Pretty printing style. key: normal, raw
@@ -119,6 +128,12 @@ OPTIONS
119--symfs=<directory>:: 128--symfs=<directory>::
120 Look for files with symbols relative to this directory. 129 Look for files with symbols relative to this directory.
121 130
131-c::
132--cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can
133 be provided as a comma-separated list with no space: 0,1. Ranges of
134 CPUs are specified with -: 0-2. Default is to report samples on all
135 CPUs.
136
122SEE ALSO 137SEE ALSO
123-------- 138--------
124linkperf:perf-stat[1] 139linkperf:perf-stat[1]
diff --git a/tools/perf/Documentation/perf-script-perl.txt b/tools/perf/Documentation/perf-script-perl.txt
index 5bb41e55a3ac..3152cca15501 100644
--- a/tools/perf/Documentation/perf-script-perl.txt
+++ b/tools/perf/Documentation/perf-script-perl.txt
@@ -63,7 +63,6 @@ The format file for the sched_wakep event defines the following fields
63 field:unsigned char common_flags; 63 field:unsigned char common_flags;
64 field:unsigned char common_preempt_count; 64 field:unsigned char common_preempt_count;
65 field:int common_pid; 65 field:int common_pid;
66 field:int common_lock_depth;
67 66
68 field:char comm[TASK_COMM_LEN]; 67 field:char comm[TASK_COMM_LEN];
69 field:pid_t pid; 68 field:pid_t pid;
diff --git a/tools/perf/Documentation/perf-script-python.txt b/tools/perf/Documentation/perf-script-python.txt
index 36b38277422c..471022069119 100644
--- a/tools/perf/Documentation/perf-script-python.txt
+++ b/tools/perf/Documentation/perf-script-python.txt
@@ -463,7 +463,6 @@ The format file for the sched_wakep event defines the following fields
463 field:unsigned char common_flags; 463 field:unsigned char common_flags;
464 field:unsigned char common_preempt_count; 464 field:unsigned char common_preempt_count;
465 field:int common_pid; 465 field:int common_pid;
466 field:int common_lock_depth;
467 466
468 field:char comm[TASK_COMM_LEN]; 467 field:char comm[TASK_COMM_LEN];
469 field:pid_t pid; 468 field:pid_t pid;
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt
index 29ad94293cd2..db017867d9e8 100644
--- a/tools/perf/Documentation/perf-script.txt
+++ b/tools/perf/Documentation/perf-script.txt
@@ -112,6 +112,82 @@ 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, ip, sym, dso, addr.
119 Field list can be prepended with the type, trace, sw or hw,
120 to indicate to which event type the field list applies.
121 e.g., -f sw:comm,tid,time,ip,sym and -f trace:time,cpu,trace
122
123 perf script -f <fields>
124
125 is equivalent to:
126
127 perf script -f trace:<fields> -f sw:<fields> -f hw:<fields>
128
129 i.e., the specified fields apply to all event types if the type string
130 is not given.
131
132 The arguments are processed in the order received. A later usage can
133 reset a prior request. e.g.:
134
135 -f trace: -f comm,tid,time,ip,sym
136
137 The first -f suppresses trace events (field list is ""), but then the
138 second invocation sets the fields to comm,tid,time,ip,sym. In this case a
139 warning is given to the user:
140
141 "Overriding previous field request for all events."
142
143 Alternativey, consider the order:
144
145 -f comm,tid,time,ip,sym -f trace:
146
147 The first -f sets the fields for all events and the second -f
148 suppresses trace events. The user is given a warning message about
149 the override, and the result of the above is that only S/W and H/W
150 events are displayed with the given fields.
151
152 For the 'wildcard' option if a user selected field is invalid for an
153 event type, a message is displayed to the user that the option is
154 ignored for that type. For example:
155
156 $ perf script -f comm,tid,trace
157 'trace' not valid for hardware events. Ignoring.
158 'trace' not valid for software events. Ignoring.
159
160 Alternatively, if the type is given an invalid field is specified it
161 is an error. For example:
162
163 perf script -v -f sw:comm,tid,trace
164 'trace' not valid for software events.
165
166 At this point usage is displayed, and perf-script exits.
167
168 Finally, a user may not set fields to none for all event types.
169 i.e., -f "" is not allowed.
170
171-k::
172--vmlinux=<file>::
173 vmlinux pathname
174
175--kallsyms=<file>::
176 kallsyms pathname
177
178--symfs=<directory>::
179 Look for files with symbols relative to this directory.
180
181-G::
182--hide-call-graph::
183 When printing symbols do not display call chain.
184
185-c::
186--cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can
187 be provided as a comma-separated list with no space: 0,1. Ranges of
188 CPUs are specified with -: 0-2. Default is to report samples on all
189 CPUs.
190
115SEE ALSO 191SEE ALSO
116-------- 192--------
117linkperf:perf-record[1], linkperf:perf-script-perl[1], 193linkperf:perf-record[1], linkperf:perf-script-perl[1],
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index b6da7affbbee..918cc38ee6d1 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -83,6 +83,17 @@ This option is only valid in system-wide mode.
83print counts using a CSV-style output to make it easy to import directly into 83print counts using a CSV-style output to make it easy to import directly into
84spreadsheets. Columns are separated by the string specified in SEP. 84spreadsheets. Columns are separated by the string specified in SEP.
85 85
86-G name::
87--cgroup name::
88monitor only in the container (cgroup) called "name". This option is available only
89in per-cpu mode. The cgroup filesystem must be mounted. All threads belonging to
90container "name" are monitored when they run on the monitored CPUs. Multiple cgroups
91can be provided. Each cgroup is applied to the corresponding event, i.e., first cgroup
92to first event, second cgroup to second event and so on. It is possible to provide
93an empty cgroup (monitor all the time) using, e.g., -G foo,,bar. Cgroups must have
94corresponding events, i.e., they always refer to events defined earlier on the command
95line.
96
86EXAMPLES 97EXAMPLES
87-------- 98--------
88 99
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 7141c42e1469..3b8f7b80376b 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -3,7 +3,9 @@ ifeq ("$(origin O)", "command line")
3endif 3endif
4 4
5# The default target of this Makefile is... 5# The default target of this Makefile is...
6all:: 6all:
7
8include config/utilities.mak
7 9
8ifneq ($(OUTPUT),) 10ifneq ($(OUTPUT),)
9# check that the output directory actually exists 11# check that the output directory actually exists
@@ -11,152 +13,18 @@ OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd)
11$(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist)) 13$(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist))
12endif 14endif
13 15
14# Define V=1 to have a more verbose compile. 16# Define V to have a more verbose compile.
15# Define V=2 to have an even more verbose compile.
16#
17# Define SNPRINTF_RETURNS_BOGUS if your are on a system which snprintf()
18# or vsnprintf() return -1 instead of number of characters which would
19# have been written to the final string if enough space had been available.
20#
21# Define FREAD_READS_DIRECTORIES if your are on a system which succeeds
22# when attempting to read from an fopen'ed directory.
23#
24# Define NO_OPENSSL environment variable if you do not have OpenSSL.
25# This also implies MOZILLA_SHA1.
26#
27# Define CURLDIR=/foo/bar if your curl header and library files are in
28# /foo/bar/include and /foo/bar/lib directories.
29#
30# Define EXPATDIR=/foo/bar if your expat header and library files are in
31# /foo/bar/include and /foo/bar/lib directories.
32#
33# Define NO_D_INO_IN_DIRENT if you don't have d_ino in your struct dirent.
34#
35# Define NO_D_TYPE_IN_DIRENT if your platform defines DT_UNKNOWN but lacks
36# d_type in struct dirent (latest Cygwin -- will be fixed soonish).
37#
38# Define NO_C99_FORMAT if your formatted IO functions (printf/scanf et.al.)
39# do not support the 'size specifiers' introduced by C99, namely ll, hh,
40# j, z, t. (representing long long int, char, intmax_t, size_t, ptrdiff_t).
41# some C compilers supported these specifiers prior to C99 as an extension.
42#
43# Define NO_STRCASESTR if you don't have strcasestr.
44#
45# Define NO_MEMMEM if you don't have memmem.
46#
47# Define NO_STRTOUMAX if you don't have strtoumax in the C library.
48# If your compiler also does not support long long or does not have
49# strtoull, define NO_STRTOULL.
50#
51# Define NO_SETENV if you don't have setenv in the C library.
52#
53# Define NO_UNSETENV if you don't have unsetenv in the C library.
54#
55# Define NO_MKDTEMP if you don't have mkdtemp in the C library.
56#
57# Define NO_SYS_SELECT_H if you don't have sys/select.h.
58#
59# Define NO_SYMLINK_HEAD if you never want .perf/HEAD to be a symbolic link.
60# Enable it on Windows. By default, symrefs are still used.
61#
62# Define NO_SVN_TESTS if you want to skip time-consuming SVN interoperability
63# tests. These tests take up a significant amount of the total test time
64# but are not needed unless you plan to talk to SVN repos.
65#
66# Define NO_FINK if you are building on Darwin/Mac OS X, have Fink
67# installed in /sw, but don't want PERF to link against any libraries
68# installed there. If defined you may specify your own (or Fink's)
69# include directories and library directories by defining CFLAGS
70# and LDFLAGS appropriately.
71#
72# Define NO_DARWIN_PORTS if you are building on Darwin/Mac OS X,
73# have DarwinPorts installed in /opt/local, but don't want PERF to
74# link against any libraries installed there. If defined you may
75# specify your own (or DarwinPort's) include directories and
76# library directories by defining CFLAGS and LDFLAGS appropriately.
77#
78# Define PPC_SHA1 environment variable when running make to make use of
79# a bundled SHA1 routine optimized for PowerPC.
80#
81# Define ARM_SHA1 environment variable when running make to make use of
82# a bundled SHA1 routine optimized for ARM.
83#
84# Define MOZILLA_SHA1 environment variable when running make to make use of
85# a bundled SHA1 routine coming from Mozilla. It is GPL'd and should be fast
86# on non-x86 architectures (e.g. PowerPC), while the OpenSSL version (default
87# choice) has very fast version optimized for i586.
88# 17#
89# Define NEEDS_SSL_WITH_CRYPTO if you need -lcrypto with -lssl (Darwin). 18# Define PYTHON to point to the python binary if the default
19# `python' is not correct; for example: PYTHON=python2
90# 20#
91# Define NEEDS_LIBICONV if linking with libc is not enough (Darwin). 21# Define PYTHON_CONFIG to point to the python-config binary if
92# 22# the default `$(PYTHON)-config' is not correct.
93# Define NEEDS_SOCKET if linking with libc is not enough (SunOS,
94# Patrick Mauritz).
95#
96# Define NO_MMAP if you want to avoid mmap.
97#
98# Define NO_PTHREADS if you do not have or do not want to use Pthreads.
99#
100# Define NO_PREAD if you have a problem with pread() system call (e.g.
101# cygwin.dll before v1.5.22).
102#
103# Define NO_FAST_WORKING_DIRECTORY if accessing objects in pack files is
104# generally faster on your platform than accessing the working directory.
105#
106# Define NO_TRUSTABLE_FILEMODE if your filesystem may claim to support
107# the executable mode bit, but doesn't really do so.
108#
109# Define NO_IPV6 if you lack IPv6 support and getaddrinfo().
110#
111# Define NO_SOCKADDR_STORAGE if your platform does not have struct
112# sockaddr_storage.
113#
114# Define NO_ICONV if your libc does not properly support iconv.
115#
116# Define OLD_ICONV if your library has an old iconv(), where the second
117# (input buffer pointer) parameter is declared with type (const char **).
118#
119# Define NO_DEFLATE_BOUND if your zlib does not have deflateBound.
120#
121# Define NO_R_TO_GCC_LINKER if your gcc does not like "-R/path/lib"
122# that tells runtime paths to dynamic libraries;
123# "-Wl,-rpath=/path/lib" is used instead.
124#
125# Define USE_NSEC below if you want perf to care about sub-second file mtimes
126# and ctimes. Note that you need recent glibc (at least 2.2.4) for this, and
127# it will BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely
128# randomly break unless your underlying filesystem supports those sub-second
129# times (my ext3 doesn't).
130#
131# Define USE_ST_TIMESPEC if your "struct stat" uses "st_ctimespec" instead of
132# "st_ctim"
133#
134# Define NO_NSEC if your "struct stat" does not have "st_ctim.tv_nsec"
135# available. This automatically turns USE_NSEC off.
136#
137# Define USE_STDEV below if you want perf to care about the underlying device
138# change being considered an inode change from the update-index perspective.
139#
140# Define NO_ST_BLOCKS_IN_STRUCT_STAT if your platform does not have st_blocks
141# field that counts the on-disk footprint in 512-byte blocks.
142# 23#
143# Define ASCIIDOC8 if you want to format documentation with AsciiDoc 8 24# Define ASCIIDOC8 if you want to format documentation with AsciiDoc 8
144# 25#
145# Define DOCBOOK_XSL_172 if you want to format man pages with DocBook XSL v1.72. 26# Define DOCBOOK_XSL_172 if you want to format man pages with DocBook XSL v1.72.
146# 27#
147# Define NO_PERL_MAKEMAKER if you cannot use Makefiles generated by perl's
148# MakeMaker (e.g. using ActiveState under Cygwin).
149#
150# Define NO_PERL if you do not want Perl scripts or libraries at all.
151#
152# Define INTERNAL_QSORT to use Git's implementation of qsort(), which
153# is a simplified version of the merge sort used in glibc. This is
154# recommended if Git triggers O(n^2) behavior in your platform's qsort().
155#
156# Define NO_EXTERNAL_GREP if you don't want "perf grep" to ever call
157# your external grep (e.g., if your system lacks grep, if its grep is
158# broken, or spawning external process is slower than built-in grep perf has).
159#
160# Define LDFLAGS=-static to build a static binary. 28# Define LDFLAGS=-static to build a static binary.
161# 29#
162# Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds. 30# Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds.
@@ -167,12 +35,7 @@ $(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
167 @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT) 35 @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT)
168-include $(OUTPUT)PERF-VERSION-FILE 36-include $(OUTPUT)PERF-VERSION-FILE
169 37
170uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') 38uname_M := $(shell uname -m 2>/dev/null || echo not)
171uname_M := $(shell sh -c 'uname -m 2>/dev/null || echo not')
172uname_O := $(shell sh -c 'uname -o 2>/dev/null || echo not')
173uname_R := $(shell sh -c 'uname -r 2>/dev/null || echo not')
174uname_P := $(shell sh -c 'uname -p 2>/dev/null || echo not')
175uname_V := $(shell sh -c 'uname -v 2>/dev/null || echo not')
176 39
177ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \ 40ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
178 -e s/arm.*/arm/ -e s/sa110/arm/ \ 41 -e s/arm.*/arm/ -e s/sa110/arm/ \
@@ -180,19 +43,26 @@ ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
180 -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \ 43 -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
181 -e s/sh[234].*/sh/ ) 44 -e s/sh[234].*/sh/ )
182 45
46CC = $(CROSS_COMPILE)gcc
47AR = $(CROSS_COMPILE)ar
48
183# Additional ARCH settings for x86 49# Additional ARCH settings for x86
184ifeq ($(ARCH),i386) 50ifeq ($(ARCH),i386)
185 ARCH := x86 51 ARCH := x86
186endif 52endif
187ifeq ($(ARCH),x86_64) 53ifeq ($(ARCH),x86_64)
188 RAW_ARCH := x86_64 54 ARCH := x86
189 ARCH := x86 55 IS_X86_64 := 0
190 ARCH_CFLAGS := -DARCH_X86_64 56 ifeq (, $(findstring m32,$(EXTRA_CFLAGS)))
191 ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S 57 IS_X86_64 := $(shell echo __x86_64__ | ${CC} -E -xc - | tail -n 1)
58 endif
59 ifeq (${IS_X86_64}, 1)
60 RAW_ARCH := x86_64
61 ARCH_CFLAGS := -DARCH_X86_64
62 ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S
63 endif
192endif 64endif
193 65
194# CFLAGS and LDFLAGS are for the users to override from the command line.
195
196# 66#
197# Include saner warnings here, which can catch bugs: 67# Include saner warnings here, which can catch bugs:
198# 68#
@@ -266,27 +136,16 @@ lib = lib
266 136
267export prefix bindir sharedir sysconfdir 137export prefix bindir sharedir sysconfdir
268 138
269CC = $(CROSS_COMPILE)gcc
270AR = $(CROSS_COMPILE)ar
271RM = rm -f 139RM = rm -f
272MKDIR = mkdir 140MKDIR = mkdir
273TAR = tar
274FIND = find 141FIND = find
275INSTALL = install 142INSTALL = install
276RPMBUILD = rpmbuild
277PTHREAD_LIBS = -lpthread
278 143
279# sparse is architecture-neutral, which means that we need to tell it 144# sparse is architecture-neutral, which means that we need to tell it
280# explicitly what architecture to check for. Fix this up for yours.. 145# explicitly what architecture to check for. Fix this up for yours..
281SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__ 146SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
282 147
283ifeq ($(V), 2) 148-include config/feature-tests.mak
284 QUIET_STDERR = ">/dev/null"
285else
286 QUIET_STDERR = ">/dev/null 2>&1"
287endif
288
289-include feature-tests.mak
290 149
291ifeq ($(call try-cc,$(SOURCE_HELLO),-Werror -fstack-protector-all),y) 150ifeq ($(call try-cc,$(SOURCE_HELLO),-Werror -fstack-protector-all),y)
292 CFLAGS := $(CFLAGS) -fstack-protector-all 151 CFLAGS := $(CFLAGS) -fstack-protector-all
@@ -310,49 +169,39 @@ BASIC_LDFLAGS =
310 169
311# Guard against environment variables 170# Guard against environment variables
312BUILTIN_OBJS = 171BUILTIN_OBJS =
313BUILT_INS =
314COMPAT_CFLAGS =
315COMPAT_OBJS =
316LIB_H = 172LIB_H =
317LIB_OBJS = 173LIB_OBJS =
318SCRIPT_PERL = 174PYRF_OBJS =
319SCRIPT_SH = 175SCRIPT_SH =
320TEST_PROGRAMS =
321 176
322SCRIPT_SH += perf-archive.sh 177SCRIPT_SH += perf-archive.sh
323 178
324grep-libs = $(filter -l%,$(1)) 179grep-libs = $(filter -l%,$(1))
325strip-libs = $(filter-out -l%,$(1)) 180strip-libs = $(filter-out -l%,$(1))
326 181
182$(OUTPUT)python/perf.so: $(PYRF_OBJS)
183 $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \
184 --quiet build_ext; \
185 mkdir -p $(OUTPUT)python && \
186 cp $(PYTHON_EXTBUILD_LIB)perf.so $(OUTPUT)python/
327# 187#
328# No Perl scripts right now: 188# No Perl scripts right now:
329# 189#
330 190
331# SCRIPT_PERL += perf-add--interactive.perl 191SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH))
332
333SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \
334 $(patsubst %.perl,%,$(SCRIPT_PERL))
335
336# Empty...
337EXTRA_PROGRAMS =
338
339# ... and all the rest that could be moved out of bindir to perfexecdir
340PROGRAMS += $(EXTRA_PROGRAMS)
341 192
342# 193#
343# Single 'perf' binary right now: 194# Single 'perf' binary right now:
344# 195#
345PROGRAMS += $(OUTPUT)perf 196PROGRAMS += $(OUTPUT)perf
346 197
347# List built-in command $C whose implementation cmd_$C() is not in 198LANG_BINDINGS =
348# builtin-$C.o but is linked in as part of some other command.
349#
350 199
351# what 'all' will build and 'install' will install, in perfexecdir 200# what 'all' will build and 'install' will install, in perfexecdir
352ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS) 201ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
353 202
354# what 'all' will build but not install in perfexecdir 203# what 'all' will build but not install in perfexecdir
355OTHER_PROGRAMS = $(OUTPUT)perf$X 204OTHER_PROGRAMS = $(OUTPUT)perf
356 205
357# Set paths to tools early so that they can be used for version tests. 206# Set paths to tools early so that they can be used for version tests.
358ifndef SHELL_PATH 207ifndef SHELL_PATH
@@ -369,11 +218,13 @@ LIB_FILE=$(OUTPUT)libperf.a
369LIB_H += ../../include/linux/perf_event.h 218LIB_H += ../../include/linux/perf_event.h
370LIB_H += ../../include/linux/rbtree.h 219LIB_H += ../../include/linux/rbtree.h
371LIB_H += ../../include/linux/list.h 220LIB_H += ../../include/linux/list.h
221LIB_H += ../../include/linux/const.h
372LIB_H += ../../include/linux/hash.h 222LIB_H += ../../include/linux/hash.h
373LIB_H += ../../include/linux/stringify.h 223LIB_H += ../../include/linux/stringify.h
374LIB_H += util/include/linux/bitmap.h 224LIB_H += util/include/linux/bitmap.h
375LIB_H += util/include/linux/bitops.h 225LIB_H += util/include/linux/bitops.h
376LIB_H += util/include/linux/compiler.h 226LIB_H += util/include/linux/compiler.h
227LIB_H += util/include/linux/const.h
377LIB_H += util/include/linux/ctype.h 228LIB_H += util/include/linux/ctype.h
378LIB_H += util/include/linux/kernel.h 229LIB_H += util/include/linux/kernel.h
379LIB_H += util/include/linux/list.h 230LIB_H += util/include/linux/list.h
@@ -395,6 +246,7 @@ LIB_H += util/include/dwarf-regs.h
395LIB_H += util/include/asm/dwarf2.h 246LIB_H += util/include/asm/dwarf2.h
396LIB_H += util/include/asm/cpufeature.h 247LIB_H += util/include/asm/cpufeature.h
397LIB_H += perf.h 248LIB_H += perf.h
249LIB_H += util/annotate.h
398LIB_H += util/cache.h 250LIB_H += util/cache.h
399LIB_H += util/callchain.h 251LIB_H += util/callchain.h
400LIB_H += util/build-id.h 252LIB_H += util/build-id.h
@@ -402,6 +254,7 @@ LIB_H += util/debug.h
402LIB_H += util/debugfs.h 254LIB_H += util/debugfs.h
403LIB_H += util/event.h 255LIB_H += util/event.h
404LIB_H += util/evsel.h 256LIB_H += util/evsel.h
257LIB_H += util/evlist.h
405LIB_H += util/exec_cmd.h 258LIB_H += util/exec_cmd.h
406LIB_H += util/types.h 259LIB_H += util/types.h
407LIB_H += util/levenshtein.h 260LIB_H += util/levenshtein.h
@@ -416,6 +269,7 @@ LIB_H += util/help.h
416LIB_H += util/session.h 269LIB_H += util/session.h
417LIB_H += util/strbuf.h 270LIB_H += util/strbuf.h
418LIB_H += util/strlist.h 271LIB_H += util/strlist.h
272LIB_H += util/strfilter.h
419LIB_H += util/svghelper.h 273LIB_H += util/svghelper.h
420LIB_H += util/run-command.h 274LIB_H += util/run-command.h
421LIB_H += util/sigchain.h 275LIB_H += util/sigchain.h
@@ -425,21 +279,27 @@ LIB_H += util/values.h
425LIB_H += util/sort.h 279LIB_H += util/sort.h
426LIB_H += util/hist.h 280LIB_H += util/hist.h
427LIB_H += util/thread.h 281LIB_H += util/thread.h
282LIB_H += util/thread_map.h
428LIB_H += util/trace-event.h 283LIB_H += util/trace-event.h
429LIB_H += util/probe-finder.h 284LIB_H += util/probe-finder.h
285LIB_H += util/dwarf-aux.h
430LIB_H += util/probe-event.h 286LIB_H += util/probe-event.h
431LIB_H += util/pstack.h 287LIB_H += util/pstack.h
432LIB_H += util/cpumap.h 288LIB_H += util/cpumap.h
289LIB_H += util/top.h
433LIB_H += $(ARCH_INCLUDE) 290LIB_H += $(ARCH_INCLUDE)
291LIB_H += util/cgroup.h
434 292
435LIB_OBJS += $(OUTPUT)util/abspath.o 293LIB_OBJS += $(OUTPUT)util/abspath.o
436LIB_OBJS += $(OUTPUT)util/alias.o 294LIB_OBJS += $(OUTPUT)util/alias.o
295LIB_OBJS += $(OUTPUT)util/annotate.o
437LIB_OBJS += $(OUTPUT)util/build-id.o 296LIB_OBJS += $(OUTPUT)util/build-id.o
438LIB_OBJS += $(OUTPUT)util/config.o 297LIB_OBJS += $(OUTPUT)util/config.o
439LIB_OBJS += $(OUTPUT)util/ctype.o 298LIB_OBJS += $(OUTPUT)util/ctype.o
440LIB_OBJS += $(OUTPUT)util/debugfs.o 299LIB_OBJS += $(OUTPUT)util/debugfs.o
441LIB_OBJS += $(OUTPUT)util/environment.o 300LIB_OBJS += $(OUTPUT)util/environment.o
442LIB_OBJS += $(OUTPUT)util/event.o 301LIB_OBJS += $(OUTPUT)util/event.o
302LIB_OBJS += $(OUTPUT)util/evlist.o
443LIB_OBJS += $(OUTPUT)util/evsel.o 303LIB_OBJS += $(OUTPUT)util/evsel.o
444LIB_OBJS += $(OUTPUT)util/exec_cmd.o 304LIB_OBJS += $(OUTPUT)util/exec_cmd.o
445LIB_OBJS += $(OUTPUT)util/help.o 305LIB_OBJS += $(OUTPUT)util/help.o
@@ -455,6 +315,8 @@ LIB_OBJS += $(OUTPUT)util/quote.o
455LIB_OBJS += $(OUTPUT)util/strbuf.o 315LIB_OBJS += $(OUTPUT)util/strbuf.o
456LIB_OBJS += $(OUTPUT)util/string.o 316LIB_OBJS += $(OUTPUT)util/string.o
457LIB_OBJS += $(OUTPUT)util/strlist.o 317LIB_OBJS += $(OUTPUT)util/strlist.o
318LIB_OBJS += $(OUTPUT)util/strfilter.o
319LIB_OBJS += $(OUTPUT)util/top.o
458LIB_OBJS += $(OUTPUT)util/usage.o 320LIB_OBJS += $(OUTPUT)util/usage.o
459LIB_OBJS += $(OUTPUT)util/wrapper.o 321LIB_OBJS += $(OUTPUT)util/wrapper.o
460LIB_OBJS += $(OUTPUT)util/sigchain.o 322LIB_OBJS += $(OUTPUT)util/sigchain.o
@@ -469,6 +331,7 @@ LIB_OBJS += $(OUTPUT)util/map.o
469LIB_OBJS += $(OUTPUT)util/pstack.o 331LIB_OBJS += $(OUTPUT)util/pstack.o
470LIB_OBJS += $(OUTPUT)util/session.o 332LIB_OBJS += $(OUTPUT)util/session.o
471LIB_OBJS += $(OUTPUT)util/thread.o 333LIB_OBJS += $(OUTPUT)util/thread.o
334LIB_OBJS += $(OUTPUT)util/thread_map.o
472LIB_OBJS += $(OUTPUT)util/trace-event-parse.o 335LIB_OBJS += $(OUTPUT)util/trace-event-parse.o
473LIB_OBJS += $(OUTPUT)util/trace-event-read.o 336LIB_OBJS += $(OUTPUT)util/trace-event-read.o
474LIB_OBJS += $(OUTPUT)util/trace-event-info.o 337LIB_OBJS += $(OUTPUT)util/trace-event-info.o
@@ -480,6 +343,7 @@ LIB_OBJS += $(OUTPUT)util/probe-event.o
480LIB_OBJS += $(OUTPUT)util/util.o 343LIB_OBJS += $(OUTPUT)util/util.o
481LIB_OBJS += $(OUTPUT)util/xyarray.o 344LIB_OBJS += $(OUTPUT)util/xyarray.o
482LIB_OBJS += $(OUTPUT)util/cpumap.o 345LIB_OBJS += $(OUTPUT)util/cpumap.o
346LIB_OBJS += $(OUTPUT)util/cgroup.o
483 347
484BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o 348BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
485 349
@@ -494,6 +358,7 @@ endif
494BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o 358BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o
495 359
496BUILTIN_OBJS += $(OUTPUT)builtin-diff.o 360BUILTIN_OBJS += $(OUTPUT)builtin-diff.o
361BUILTIN_OBJS += $(OUTPUT)builtin-evlist.o
497BUILTIN_OBJS += $(OUTPUT)builtin-help.o 362BUILTIN_OBJS += $(OUTPUT)builtin-help.o
498BUILTIN_OBJS += $(OUTPUT)builtin-sched.o 363BUILTIN_OBJS += $(OUTPUT)builtin-sched.o
499BUILTIN_OBJS += $(OUTPUT)builtin-buildid-list.o 364BUILTIN_OBJS += $(OUTPUT)builtin-buildid-list.o
@@ -514,6 +379,20 @@ BUILTIN_OBJS += $(OUTPUT)builtin-inject.o
514 379
515PERFLIBS = $(LIB_FILE) 380PERFLIBS = $(LIB_FILE)
516 381
382# Files needed for the python binding, perf.so
383# pyrf is just an internal name needed for all those wrappers.
384# This has to be in sync with what is in the 'sources' variable in
385# tools/perf/util/setup.py
386
387PYRF_OBJS += $(OUTPUT)util/cpumap.o
388PYRF_OBJS += $(OUTPUT)util/ctype.o
389PYRF_OBJS += $(OUTPUT)util/evlist.o
390PYRF_OBJS += $(OUTPUT)util/evsel.o
391PYRF_OBJS += $(OUTPUT)util/python.o
392PYRF_OBJS += $(OUTPUT)util/thread_map.o
393PYRF_OBJS += $(OUTPUT)util/util.o
394PYRF_OBJS += $(OUTPUT)util/xyarray.o
395
517# 396#
518# Platform specific tweaks 397# Platform specific tweaks
519# 398#
@@ -535,22 +414,6 @@ endif # NO_DWARF
535 414
536-include arch/$(ARCH)/Makefile 415-include arch/$(ARCH)/Makefile
537 416
538ifeq ($(uname_S),Darwin)
539 ifndef NO_FINK
540 ifeq ($(shell test -d /sw/lib && echo y),y)
541 BASIC_CFLAGS += -I/sw/include
542 BASIC_LDFLAGS += -L/sw/lib
543 endif
544 endif
545 ifndef NO_DARWIN_PORTS
546 ifeq ($(shell test -d /opt/local/lib && echo y),y)
547 BASIC_CFLAGS += -I/opt/local/include
548 BASIC_LDFLAGS += -L/opt/local/lib
549 endif
550 endif
551 PTHREAD_LIBS =
552endif
553
554ifneq ($(OUTPUT),) 417ifneq ($(OUTPUT),)
555 BASIC_CFLAGS += -I$(OUTPUT) 418 BASIC_CFLAGS += -I$(OUTPUT)
556endif 419endif
@@ -576,6 +439,7 @@ else
576 BASIC_CFLAGS += -DDWARF_SUPPORT 439 BASIC_CFLAGS += -DDWARF_SUPPORT
577 EXTLIBS += -lelf -ldw 440 EXTLIBS += -lelf -ldw
578 LIB_OBJS += $(OUTPUT)util/probe-finder.o 441 LIB_OBJS += $(OUTPUT)util/probe-finder.o
442 LIB_OBJS += $(OUTPUT)util/dwarf-aux.o
579endif # PERF_HAVE_DWARF_REGS 443endif # PERF_HAVE_DWARF_REGS
580endif # NO_DWARF 444endif # NO_DWARF
581 445
@@ -595,6 +459,7 @@ else
595 LIB_OBJS += $(OUTPUT)util/ui/browsers/annotate.o 459 LIB_OBJS += $(OUTPUT)util/ui/browsers/annotate.o
596 LIB_OBJS += $(OUTPUT)util/ui/browsers/hists.o 460 LIB_OBJS += $(OUTPUT)util/ui/browsers/hists.o
597 LIB_OBJS += $(OUTPUT)util/ui/browsers/map.o 461 LIB_OBJS += $(OUTPUT)util/ui/browsers/map.o
462 LIB_OBJS += $(OUTPUT)util/ui/browsers/top.o
598 LIB_OBJS += $(OUTPUT)util/ui/helpline.o 463 LIB_OBJS += $(OUTPUT)util/ui/helpline.o
599 LIB_OBJS += $(OUTPUT)util/ui/progress.o 464 LIB_OBJS += $(OUTPUT)util/ui/progress.o
600 LIB_OBJS += $(OUTPUT)util/ui/util.o 465 LIB_OBJS += $(OUTPUT)util/ui/util.o
@@ -604,6 +469,7 @@ else
604 LIB_H += util/ui/libslang.h 469 LIB_H += util/ui/libslang.h
605 LIB_H += util/ui/progress.h 470 LIB_H += util/ui/progress.h
606 LIB_H += util/ui/util.h 471 LIB_H += util/ui/util.h
472 LIB_H += util/ui/ui.h
607 endif 473 endif
608endif 474endif
609 475
@@ -626,22 +492,78 @@ else
626 endif 492 endif
627endif 493endif
628 494
629ifdef NO_LIBPYTHON 495disable-python = $(eval $(disable-python_code))
630 BASIC_CFLAGS += -DNO_LIBPYTHON 496define disable-python_code
497 BASIC_CFLAGS += -DNO_LIBPYTHON
498 $(if $(1),$(warning No $(1) was found))
499 $(warning Python support won't be built)
500endef
501
502override PYTHON := \
503 $(call get-executable-or-default,PYTHON,python)
504
505ifndef PYTHON
506 $(call disable-python,python interpreter)
507 python-clean :=
631else 508else
632 PYTHON_EMBED_LDOPTS = $(shell python-config --ldflags 2>/dev/null) 509
633 PYTHON_EMBED_LDFLAGS = $(call strip-libs,$(PYTHON_EMBED_LDOPTS)) 510 PYTHON_WORD := $(call shell-wordify,$(PYTHON))
634 PYTHON_EMBED_LIBADD = $(call grep-libs,$(PYTHON_EMBED_LDOPTS)) 511
635 PYTHON_EMBED_CCOPTS = `python-config --cflags 2>/dev/null` 512 # python extension build directories
636 FLAGS_PYTHON_EMBED=$(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS) 513 PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/
637 ifneq ($(call try-cc,$(SOURCE_PYTHON_EMBED),$(FLAGS_PYTHON_EMBED)),y) 514 PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/
638 BASIC_CFLAGS += -DNO_LIBPYTHON 515 PYTHON_EXTBUILD_TMP := $(PYTHON_EXTBUILD)tmp/
639 else 516 export PYTHON_EXTBUILD_LIB PYTHON_EXTBUILD_TMP
640 ALL_LDFLAGS += $(PYTHON_EMBED_LDFLAGS) 517
641 EXTLIBS += $(PYTHON_EMBED_LIBADD) 518 python-clean := rm -rf $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so
642 LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-python.o 519
643 LIB_OBJS += $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o 520 ifdef NO_LIBPYTHON
644 endif 521 $(call disable-python)
522 else
523
524 override PYTHON_CONFIG := \
525 $(call get-executable-or-default,PYTHON_CONFIG,$(PYTHON)-config)
526
527 ifndef PYTHON_CONFIG
528 $(call disable-python,python-config tool)
529 else
530
531 PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG))
532
533 PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null)
534 PYTHON_EMBED_LDFLAGS := $(call strip-libs,$(PYTHON_EMBED_LDOPTS))
535 PYTHON_EMBED_LIBADD := $(call grep-libs,$(PYTHON_EMBED_LDOPTS))
536 PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
537 FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
538
539 ifneq ($(call try-cc,$(SOURCE_PYTHON_EMBED),$(FLAGS_PYTHON_EMBED)),y)
540 $(call disable-python,Python.h (for Python 2.x))
541 else
542
543 ifneq ($(call try-cc,$(SOURCE_PYTHON_VERSION),$(FLAGS_PYTHON_EMBED)),y)
544 $(warning Python 3 is not yet supported; please set)
545 $(warning PYTHON and/or PYTHON_CONFIG appropriately.)
546 $(warning If you also have Python 2 installed, then)
547 $(warning try something like:)
548 $(warning $(and ,))
549 $(warning $(and ,) make PYTHON=python2)
550 $(warning $(and ,))
551 $(warning Otherwise, disable Python support entirely:)
552 $(warning $(and ,))
553 $(warning $(and ,) make NO_LIBPYTHON=1)
554 $(warning $(and ,))
555 $(error $(and ,))
556 else
557 ALL_LDFLAGS += $(PYTHON_EMBED_LDFLAGS)
558 EXTLIBS += $(PYTHON_EMBED_LIBADD)
559 LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-python.o
560 LIB_OBJS += $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o
561 LANG_BINDINGS += $(OUTPUT)python/perf.so
562 endif
563
564 endif
565 endif
566 endif
645endif 567endif
646 568
647ifdef NO_DEMANGLE 569ifdef NO_DEMANGLE
@@ -690,201 +612,13 @@ else
690 endif 612 endif
691endif 613endif
692 614
693ifndef CC_LD_DYNPATH
694 ifdef NO_R_TO_GCC_LINKER
695 # Some gcc does not accept and pass -R to the linker to specify
696 # the runtime dynamic library path.
697 CC_LD_DYNPATH = -Wl,-rpath,
698 else
699 CC_LD_DYNPATH = -R
700 endif
701endif
702
703ifdef NEEDS_SOCKET
704 EXTLIBS += -lsocket
705endif
706ifdef NEEDS_NSL
707 EXTLIBS += -lnsl
708endif
709ifdef NO_D_TYPE_IN_DIRENT
710 BASIC_CFLAGS += -DNO_D_TYPE_IN_DIRENT
711endif
712ifdef NO_D_INO_IN_DIRENT
713 BASIC_CFLAGS += -DNO_D_INO_IN_DIRENT
714endif
715ifdef NO_ST_BLOCKS_IN_STRUCT_STAT
716 BASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT
717endif
718ifdef USE_NSEC
719 BASIC_CFLAGS += -DUSE_NSEC
720endif
721ifdef USE_ST_TIMESPEC
722 BASIC_CFLAGS += -DUSE_ST_TIMESPEC
723endif
724ifdef NO_NSEC
725 BASIC_CFLAGS += -DNO_NSEC
726endif
727ifdef NO_C99_FORMAT
728 BASIC_CFLAGS += -DNO_C99_FORMAT
729endif
730ifdef SNPRINTF_RETURNS_BOGUS
731 COMPAT_CFLAGS += -DSNPRINTF_RETURNS_BOGUS
732 COMPAT_OBJS += $(OUTPUT)compat/snprintf.o
733endif
734ifdef FREAD_READS_DIRECTORIES
735 COMPAT_CFLAGS += -DFREAD_READS_DIRECTORIES
736 COMPAT_OBJS += $(OUTPUT)compat/fopen.o
737endif
738ifdef NO_SYMLINK_HEAD
739 BASIC_CFLAGS += -DNO_SYMLINK_HEAD
740endif
741ifdef NO_STRCASESTR
742 COMPAT_CFLAGS += -DNO_STRCASESTR
743 COMPAT_OBJS += $(OUTPUT)compat/strcasestr.o
744endif
745ifdef NO_STRTOUMAX
746 COMPAT_CFLAGS += -DNO_STRTOUMAX
747 COMPAT_OBJS += $(OUTPUT)compat/strtoumax.o
748endif
749ifdef NO_STRTOULL
750 COMPAT_CFLAGS += -DNO_STRTOULL
751endif
752ifdef NO_SETENV
753 COMPAT_CFLAGS += -DNO_SETENV
754 COMPAT_OBJS += $(OUTPUT)compat/setenv.o
755endif
756ifdef NO_MKDTEMP
757 COMPAT_CFLAGS += -DNO_MKDTEMP
758 COMPAT_OBJS += $(OUTPUT)compat/mkdtemp.o
759endif
760ifdef NO_UNSETENV
761 COMPAT_CFLAGS += -DNO_UNSETENV
762 COMPAT_OBJS += $(OUTPUT)compat/unsetenv.o
763endif
764ifdef NO_SYS_SELECT_H
765 BASIC_CFLAGS += -DNO_SYS_SELECT_H
766endif
767ifdef NO_MMAP
768 COMPAT_CFLAGS += -DNO_MMAP
769 COMPAT_OBJS += $(OUTPUT)compat/mmap.o
770else
771 ifdef USE_WIN32_MMAP
772 COMPAT_CFLAGS += -DUSE_WIN32_MMAP
773 COMPAT_OBJS += $(OUTPUT)compat/win32mmap.o
774 endif
775endif
776ifdef NO_PREAD
777 COMPAT_CFLAGS += -DNO_PREAD
778 COMPAT_OBJS += $(OUTPUT)compat/pread.o
779endif
780ifdef NO_FAST_WORKING_DIRECTORY
781 BASIC_CFLAGS += -DNO_FAST_WORKING_DIRECTORY
782endif
783ifdef NO_TRUSTABLE_FILEMODE
784 BASIC_CFLAGS += -DNO_TRUSTABLE_FILEMODE
785endif
786ifdef NO_IPV6
787 BASIC_CFLAGS += -DNO_IPV6
788endif
789ifdef NO_UINTMAX_T
790 BASIC_CFLAGS += -Duintmax_t=uint32_t
791endif
792ifdef NO_SOCKADDR_STORAGE
793ifdef NO_IPV6
794 BASIC_CFLAGS += -Dsockaddr_storage=sockaddr_in
795else
796 BASIC_CFLAGS += -Dsockaddr_storage=sockaddr_in6
797endif
798endif
799ifdef NO_INET_NTOP
800 LIB_OBJS += $(OUTPUT)compat/inet_ntop.o
801endif
802ifdef NO_INET_PTON
803 LIB_OBJS += $(OUTPUT)compat/inet_pton.o
804endif
805
806ifdef NO_ICONV
807 BASIC_CFLAGS += -DNO_ICONV
808endif
809
810ifdef OLD_ICONV
811 BASIC_CFLAGS += -DOLD_ICONV
812endif
813
814ifdef NO_DEFLATE_BOUND
815 BASIC_CFLAGS += -DNO_DEFLATE_BOUND
816endif
817
818ifdef PPC_SHA1
819 SHA1_HEADER = "ppc/sha1.h"
820 LIB_OBJS += $(OUTPUT)ppc/sha1.o ppc/sha1ppc.o
821else
822ifdef ARM_SHA1
823 SHA1_HEADER = "arm/sha1.h"
824 LIB_OBJS += $(OUTPUT)arm/sha1.o $(OUTPUT)arm/sha1_arm.o
825else
826ifdef MOZILLA_SHA1
827 SHA1_HEADER = "mozilla-sha1/sha1.h"
828 LIB_OBJS += $(OUTPUT)mozilla-sha1/sha1.o
829else
830 SHA1_HEADER = <openssl/sha.h>
831 EXTLIBS += $(LIB_4_CRYPTO)
832endif
833endif
834endif
835ifdef NO_PERL_MAKEMAKER
836 export NO_PERL_MAKEMAKER
837endif
838ifdef NO_HSTRERROR
839 COMPAT_CFLAGS += -DNO_HSTRERROR
840 COMPAT_OBJS += $(OUTPUT)compat/hstrerror.o
841endif
842ifdef NO_MEMMEM
843 COMPAT_CFLAGS += -DNO_MEMMEM
844 COMPAT_OBJS += $(OUTPUT)compat/memmem.o
845endif
846ifdef INTERNAL_QSORT
847 COMPAT_CFLAGS += -DINTERNAL_QSORT
848 COMPAT_OBJS += $(OUTPUT)compat/qsort.o
849endif
850ifdef RUNTIME_PREFIX
851 COMPAT_CFLAGS += -DRUNTIME_PREFIX
852endif
853
854ifdef DIR_HAS_BSD_GROUP_SEMANTICS
855 COMPAT_CFLAGS += -DDIR_HAS_BSD_GROUP_SEMANTICS
856endif
857ifdef NO_EXTERNAL_GREP
858 BASIC_CFLAGS += -DNO_EXTERNAL_GREP
859endif
860
861ifeq ($(PERL_PATH),)
862NO_PERL=NoThanks
863endif
864
865QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir
866QUIET_SUBDIR1 =
867
868ifneq ($(findstring $(MAKEFLAGS),w),w)
869PRINT_DIR = --no-print-directory
870else # "make -w"
871NO_SUBDIR = :
872endif
873
874ifneq ($(findstring $(MAKEFLAGS),s),s) 615ifneq ($(findstring $(MAKEFLAGS),s),s)
875ifndef V 616ifndef V
876 QUIET_CC = @echo ' ' CC $@; 617 QUIET_CC = @echo ' ' CC $@;
877 QUIET_AR = @echo ' ' AR $@; 618 QUIET_AR = @echo ' ' AR $@;
878 QUIET_LINK = @echo ' ' LINK $@; 619 QUIET_LINK = @echo ' ' LINK $@;
879 QUIET_MKDIR = @echo ' ' MKDIR $@; 620 QUIET_MKDIR = @echo ' ' MKDIR $@;
880 QUIET_BUILT_IN = @echo ' ' BUILTIN $@;
881 QUIET_GEN = @echo ' ' GEN $@; 621 QUIET_GEN = @echo ' ' GEN $@;
882 QUIET_SUBDIR0 = +@subdir=
883 QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \
884 $(MAKE) $(PRINT_DIR) -C $$subdir
885 export V
886 export QUIET_GEN
887 export QUIET_BUILT_IN
888endif 622endif
889endif 623endif
890 624
@@ -894,7 +628,6 @@ endif
894 628
895# Shell quote (do not use $(call) to accommodate ancient setups); 629# Shell quote (do not use $(call) to accommodate ancient setups);
896 630
897SHA1_HEADER_SQ = $(subst ','\'',$(SHA1_HEADER))
898ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG)) 631ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG))
899 632
900DESTDIR_SQ = $(subst ','\'',$(DESTDIR)) 633DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
@@ -908,46 +641,36 @@ htmldir_SQ = $(subst ','\'',$(htmldir))
908prefix_SQ = $(subst ','\'',$(prefix)) 641prefix_SQ = $(subst ','\'',$(prefix))
909 642
910SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) 643SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
911PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH))
912
913LIBS = -Wl,--whole-archive $(PERFLIBS) -Wl,--no-whole-archive $(EXTLIBS)
914 644
915BASIC_CFLAGS += -DSHA1_HEADER='$(SHA1_HEADER_SQ)' \ 645LIBS = -Wl,--whole-archive $(PERFLIBS) -Wl,--no-whole-archive -Wl,--start-group $(EXTLIBS) -Wl,--end-group
916 $(COMPAT_CFLAGS)
917LIB_OBJS += $(COMPAT_OBJS)
918 646
919ALL_CFLAGS += $(BASIC_CFLAGS) 647ALL_CFLAGS += $(BASIC_CFLAGS)
920ALL_CFLAGS += $(ARCH_CFLAGS) 648ALL_CFLAGS += $(ARCH_CFLAGS)
921ALL_LDFLAGS += $(BASIC_LDFLAGS) 649ALL_LDFLAGS += $(BASIC_LDFLAGS)
922 650
923export TAR INSTALL DESTDIR SHELL_PATH 651export INSTALL SHELL_PATH
924 652
925 653
926### Build rules 654### Build rules
927 655
928SHELL = $(SHELL_PATH) 656SHELL = $(SHELL_PATH)
929 657
930all:: shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) $(OUTPUT)PERF-BUILD-OPTIONS 658all: shell_compatibility_test $(ALL_PROGRAMS) $(LANG_BINDINGS) $(OTHER_PROGRAMS)
931ifneq (,$X)
932 $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) perf$X)), test '$p' -ef '$p$X' || $(RM) '$p';)
933endif
934
935all::
936 659
937please_set_SHELL_PATH_to_a_more_modern_shell: 660please_set_SHELL_PATH_to_a_more_modern_shell:
938 @$$(:) 661 @$$(:)
939 662
940shell_compatibility_test: please_set_SHELL_PATH_to_a_more_modern_shell 663shell_compatibility_test: please_set_SHELL_PATH_to_a_more_modern_shell
941 664
942strip: $(PROGRAMS) $(OUTPUT)perf$X 665strip: $(PROGRAMS) $(OUTPUT)perf
943 $(STRIP) $(STRIP_OPTS) $(PROGRAMS) $(OUTPUT)perf$X 666 $(STRIP) $(STRIP_OPTS) $(PROGRAMS) $(OUTPUT)perf
944 667
945$(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS 668$(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
946 $(QUIET_CC)$(CC) -DPERF_VERSION='"$(PERF_VERSION)"' \ 669 $(QUIET_CC)$(CC) -DPERF_VERSION='"$(PERF_VERSION)"' \
947 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ 670 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
948 $(ALL_CFLAGS) -c $(filter %.c,$^) -o $@ 671 $(ALL_CFLAGS) -c $(filter %.c,$^) -o $@
949 672
950$(OUTPUT)perf$X: $(OUTPUT)perf.o $(BUILTIN_OBJS) $(PERFLIBS) 673$(OUTPUT)perf: $(OUTPUT)perf.o $(BUILTIN_OBJS) $(PERFLIBS)
951 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) $(OUTPUT)perf.o \ 674 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) $(OUTPUT)perf.o \
952 $(BUILTIN_OBJS) $(LIBS) -o $@ 675 $(BUILTIN_OBJS) $(LIBS) -o $@
953 676
@@ -963,39 +686,17 @@ $(OUTPUT)builtin-timechart.o: builtin-timechart.c $(OUTPUT)common-cmds.h $(OUTPU
963 '-DPERF_MAN_PATH="$(mandir_SQ)"' \ 686 '-DPERF_MAN_PATH="$(mandir_SQ)"' \
964 '-DPERF_INFO_PATH="$(infodir_SQ)"' $< 687 '-DPERF_INFO_PATH="$(infodir_SQ)"' $<
965 688
966$(BUILT_INS): $(OUTPUT)perf$X
967 $(QUIET_BUILT_IN)$(RM) $@ && \
968 ln perf$X $@ 2>/dev/null || \
969 ln -s perf$X $@ 2>/dev/null || \
970 cp perf$X $@
971
972$(OUTPUT)common-cmds.h: util/generate-cmdlist.sh command-list.txt 689$(OUTPUT)common-cmds.h: util/generate-cmdlist.sh command-list.txt
973 690
974$(OUTPUT)common-cmds.h: $(wildcard Documentation/perf-*.txt) 691$(OUTPUT)common-cmds.h: $(wildcard Documentation/perf-*.txt)
975 $(QUIET_GEN). util/generate-cmdlist.sh > $@+ && mv $@+ $@ 692 $(QUIET_GEN). util/generate-cmdlist.sh > $@+ && mv $@+ $@
976 693
977$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh 694$(SCRIPTS) : % : %.sh
978 $(QUIET_GEN)$(RM) $(OUTPUT)$@ $(OUTPUT)$@+ && \ 695 $(QUIET_GEN)$(INSTALL) '$@.sh' '$(OUTPUT)$@'
979 sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
980 -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \
981 -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \
982 -e 's/@@PERF_VERSION@@/$(PERF_VERSION)/g' \
983 -e 's/@@NO_CURL@@/$(NO_CURL)/g' \
984 $@.sh > $(OUTPUT)$@+ && \
985 chmod +x $(OUTPUT)$@+ && \
986 mv $(OUTPUT)$@+ $(OUTPUT)$@
987
988configure: configure.ac
989 $(QUIET_GEN)$(RM) $@ $<+ && \
990 sed -e 's/@@PERF_VERSION@@/$(PERF_VERSION)/g' \
991 $< > $<+ && \
992 autoconf -o $@ $<+ && \
993 $(RM) $<+
994 696
995# These can record PERF_VERSION 697# These can record PERF_VERSION
996$(OUTPUT)perf.o perf.spec \ 698$(OUTPUT)perf.o perf.spec \
997 $(patsubst %.sh,%,$(SCRIPT_SH)) \ 699 $(SCRIPTS) \
998 $(patsubst %.perl,%,$(SCRIPT_PERL)) \
999 : $(OUTPUT)PERF-VERSION-FILE 700 : $(OUTPUT)PERF-VERSION-FILE
1000 701
1001$(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS 702$(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS
@@ -1012,9 +713,6 @@ $(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS
1012 '-DPREFIX="$(prefix_SQ)"' \ 713 '-DPREFIX="$(prefix_SQ)"' \
1013 $< 714 $<
1014 715
1015$(OUTPUT)builtin-init-db.o: builtin-init-db.c $(OUTPUT)PERF-CFLAGS
1016 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DDEFAULT_PERF_TEMPLATE_DIR='"$(template_dir_SQ)"' $<
1017
1018$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS 716$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS
1019 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< 717 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
1020 718
@@ -1024,6 +722,9 @@ $(OUTPUT)util/ui/browser.o: util/ui/browser.c $(OUTPUT)PERF-CFLAGS
1024$(OUTPUT)util/ui/browsers/annotate.o: util/ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS 722$(OUTPUT)util/ui/browsers/annotate.o: util/ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS
1025 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 723 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
1026 724
725$(OUTPUT)util/ui/browsers/top.o: util/ui/browsers/top.c $(OUTPUT)PERF-CFLAGS
726 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
727
1027$(OUTPUT)util/ui/browsers/hists.o: util/ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS 728$(OUTPUT)util/ui/browsers/hists.o: util/ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS
1028 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 729 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
1029 730
@@ -1045,12 +746,11 @@ $(OUTPUT)util/scripting-engines/trace-event-python.o: util/scripting-engines/tra
1045$(OUTPUT)scripts/python/Perf-Trace-Util/Context.o: scripts/python/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS 746$(OUTPUT)scripts/python/Perf-Trace-Util/Context.o: scripts/python/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS
1046 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $< 747 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $<
1047 748
1048$(OUTPUT)perf-%$X: %.o $(PERFLIBS) 749$(OUTPUT)perf-%: %.o $(PERFLIBS)
1049 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) 750 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
1050 751
1051$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H) 752$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
1052$(patsubst perf-%$X,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h) 753$(patsubst perf-%,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
1053builtin-revert.o wt-status.o: wt-status.h
1054 754
1055# we compile into subdirectories. if the target directory is not the source directory, they might not exists. So 755# we compile into subdirectories. if the target directory is not the source directory, they might not exists. So
1056# we depend the various files onto their directories. 756# we depend the various files onto their directories.
@@ -1063,6 +763,36 @@ $(sort $(dir $(DIRECTORY_DEPS))):
1063$(LIB_FILE): $(LIB_OBJS) 763$(LIB_FILE): $(LIB_OBJS)
1064 $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS) 764 $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS)
1065 765
766help:
767 @echo 'Perf make targets:'
768 @echo ' doc - make *all* documentation (see below)'
769 @echo ' man - make manpage documentation (access with man <foo>)'
770 @echo ' html - make html documentation'
771 @echo ' info - make GNU info documentation (access with info <foo>)'
772 @echo ' pdf - make pdf documentation'
773 @echo ' TAGS - use etags to make tag information for source browsing'
774 @echo ' tags - use ctags to make tag information for source browsing'
775 @echo ' cscope - use cscope to make interactive browsing database'
776 @echo ''
777 @echo 'Perf install targets:'
778 @echo ' NOTE: documentation build requires asciidoc, xmlto packages to be installed'
779 @echo ' HINT: use "make prefix=<path> <install target>" to install to a particular'
780 @echo ' path like make prefix=/usr/local install install-doc'
781 @echo ' install - install compiled binaries'
782 @echo ' install-doc - install *all* documentation'
783 @echo ' install-man - install manpage documentation'
784 @echo ' install-html - install html documentation'
785 @echo ' install-info - install GNU info documentation'
786 @echo ' install-pdf - install pdf documentation'
787 @echo ''
788 @echo ' quick-install-doc - alias for quick-install-man'
789 @echo ' quick-install-man - install the documentation quickly'
790 @echo ' quick-install-html - install the html documentation quickly'
791 @echo ''
792 @echo 'Perf maintainer targets:'
793 @echo ' distclean - alias to clean'
794 @echo ' clean - clean all binary objects and build output'
795
1066doc: 796doc:
1067 $(MAKE) -C Documentation all 797 $(MAKE) -C Documentation all
1068 798
@@ -1101,30 +831,12 @@ $(OUTPUT)PERF-CFLAGS: .FORCE-PERF-CFLAGS
1101 echo "$$FLAGS" >$(OUTPUT)PERF-CFLAGS; \ 831 echo "$$FLAGS" >$(OUTPUT)PERF-CFLAGS; \
1102 fi 832 fi
1103 833
1104# We need to apply sq twice, once to protect from the shell
1105# that runs $(OUTPUT)PERF-BUILD-OPTIONS, and then again to protect it
1106# and the first level quoting from the shell that runs "echo".
1107$(OUTPUT)PERF-BUILD-OPTIONS: .FORCE-PERF-BUILD-OPTIONS
1108 @echo SHELL_PATH=\''$(subst ','\'',$(SHELL_PATH_SQ))'\' >$@
1109 @echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@
1110 @echo NO_CURL=\''$(subst ','\'',$(subst ','\'',$(NO_CURL)))'\' >>$@
1111 @echo NO_PERL=\''$(subst ','\'',$(subst ','\'',$(NO_PERL)))'\' >>$@
1112
1113### Testing rules 834### Testing rules
1114 835
1115#
1116# None right now:
1117#
1118# TEST_PROGRAMS += test-something$X
1119
1120all:: $(TEST_PROGRAMS)
1121
1122# GNU make supports exporting all variables by "export" without parameters. 836# GNU make supports exporting all variables by "export" without parameters.
1123# However, the environment gets quite big, and some programs have problems 837# However, the environment gets quite big, and some programs have problems
1124# with that. 838# with that.
1125 839
1126export NO_SVN_TESTS
1127
1128check: $(OUTPUT)common-cmds.h 840check: $(OUTPUT)common-cmds.h
1129 if sparse; \ 841 if sparse; \
1130 then \ 842 then \
@@ -1133,33 +845,21 @@ check: $(OUTPUT)common-cmds.h
1133 sparse $(ALL_CFLAGS) $(SPARSE_FLAGS) $$i || exit; \ 845 sparse $(ALL_CFLAGS) $(SPARSE_FLAGS) $$i || exit; \
1134 done; \ 846 done; \
1135 else \ 847 else \
1136 echo 2>&1 "Did you mean 'make test'?"; \
1137 exit 1; \ 848 exit 1; \
1138 fi 849 fi
1139 850
1140remove-dashes:
1141 ./fixup-builtins $(BUILT_INS) $(PROGRAMS) $(SCRIPTS)
1142
1143### Installation rules 851### Installation rules
1144 852
1145ifneq ($(filter /%,$(firstword $(template_dir))),)
1146template_instdir = $(template_dir)
1147else
1148template_instdir = $(prefix)/$(template_dir)
1149endif
1150export template_instdir
1151
1152ifneq ($(filter /%,$(firstword $(perfexecdir))),) 853ifneq ($(filter /%,$(firstword $(perfexecdir))),)
1153perfexec_instdir = $(perfexecdir) 854perfexec_instdir = $(perfexecdir)
1154else 855else
1155perfexec_instdir = $(prefix)/$(perfexecdir) 856perfexec_instdir = $(prefix)/$(perfexecdir)
1156endif 857endif
1157perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir)) 858perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir))
1158export perfexec_instdir
1159 859
1160install: all 860install: all
1161 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' 861 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
1162 $(INSTALL) $(OUTPUT)perf$X '$(DESTDIR_SQ)$(bindir_SQ)' 862 $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)'
1163 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace' 863 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
1164 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin' 864 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
1165 $(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' 865 $(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
@@ -1172,13 +872,8 @@ install: all
1172 $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python' 872 $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python'
1173 $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin' 873 $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
1174 874
1175ifdef BUILT_INS 875install-python_ext:
1176 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' 876 $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)'
1177 $(INSTALL) $(BUILT_INS) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
1178ifneq (,$X)
1179 $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) $(OUTPUT)perf$X)), $(RM) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/$p';)
1180endif
1181endif
1182 877
1183install-doc: 878install-doc:
1184 $(MAKE) -C Documentation install 879 $(MAKE) -C Documentation install
@@ -1204,104 +899,16 @@ quick-install-man:
1204quick-install-html: 899quick-install-html:
1205 $(MAKE) -C Documentation quick-install-html 900 $(MAKE) -C Documentation quick-install-html
1206 901
1207
1208### Maintainer's dist rules
1209#
1210# None right now
1211#
1212#
1213# perf.spec: perf.spec.in
1214# sed -e 's/@@VERSION@@/$(PERF_VERSION)/g' < $< > $@+
1215# mv $@+ $@
1216#
1217# PERF_TARNAME=perf-$(PERF_VERSION)
1218# dist: perf.spec perf-archive$(X) configure
1219# ./perf-archive --format=tar \
1220# --prefix=$(PERF_TARNAME)/ HEAD^{tree} > $(PERF_TARNAME).tar
1221# @mkdir -p $(PERF_TARNAME)
1222# @cp perf.spec configure $(PERF_TARNAME)
1223# @echo $(PERF_VERSION) > $(PERF_TARNAME)/version
1224# $(TAR) rf $(PERF_TARNAME).tar \
1225# $(PERF_TARNAME)/perf.spec \
1226# $(PERF_TARNAME)/configure \
1227# $(PERF_TARNAME)/version
1228# @$(RM) -r $(PERF_TARNAME)
1229# gzip -f -9 $(PERF_TARNAME).tar
1230#
1231# htmldocs = perf-htmldocs-$(PERF_VERSION)
1232# manpages = perf-manpages-$(PERF_VERSION)
1233# dist-doc:
1234# $(RM) -r .doc-tmp-dir
1235# mkdir .doc-tmp-dir
1236# $(MAKE) -C Documentation WEBDOC_DEST=../.doc-tmp-dir install-webdoc
1237# cd .doc-tmp-dir && $(TAR) cf ../$(htmldocs).tar .
1238# gzip -n -9 -f $(htmldocs).tar
1239# :
1240# $(RM) -r .doc-tmp-dir
1241# mkdir -p .doc-tmp-dir/man1 .doc-tmp-dir/man5 .doc-tmp-dir/man7
1242# $(MAKE) -C Documentation DESTDIR=./ \
1243# man1dir=../.doc-tmp-dir/man1 \
1244# man5dir=../.doc-tmp-dir/man5 \
1245# man7dir=../.doc-tmp-dir/man7 \
1246# install
1247# cd .doc-tmp-dir && $(TAR) cf ../$(manpages).tar .
1248# gzip -n -9 -f $(manpages).tar
1249# $(RM) -r .doc-tmp-dir
1250#
1251# rpm: dist
1252# $(RPMBUILD) -ta $(PERF_TARNAME).tar.gz
1253
1254### Cleaning rules 902### Cleaning rules
1255 903
1256distclean: clean
1257# $(RM) configure
1258
1259clean: 904clean:
1260 $(RM) *.o */*.o */*/*.o */*/*/*.o $(LIB_FILE) 905 $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS)
1261 $(RM) $(ALL_PROGRAMS) $(BUILT_INS) perf$X 906 $(RM) $(ALL_PROGRAMS) perf
1262 $(RM) $(TEST_PROGRAMS)
1263 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* 907 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope*
1264 $(RM) -r autom4te.cache
1265 $(RM) config.log config.mak.autogen config.mak.append config.status config.cache
1266 $(RM) -r $(PERF_TARNAME) .doc-tmp-dir
1267 $(RM) $(PERF_TARNAME).tar.gz perf-core_$(PERF_VERSION)-*.tar.gz
1268 $(RM) $(htmldocs).tar.gz $(manpages).tar.gz
1269 $(MAKE) -C Documentation/ clean 908 $(MAKE) -C Documentation/ clean
1270 $(RM) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS $(OUTPUT)PERF-BUILD-OPTIONS 909 $(RM) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS
910 $(python-clean)
1271 911
1272.PHONY: all install clean strip 912.PHONY: all install clean strip
1273.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell 913.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
1274.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS 914.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS
1275.PHONY: .FORCE-PERF-BUILD-OPTIONS
1276
1277### Make sure built-ins do not have dups and listed in perf.c
1278#
1279check-builtins::
1280 ./check-builtins.sh
1281
1282### Test suite coverage testing
1283#
1284# None right now
1285#
1286# .PHONY: coverage coverage-clean coverage-build coverage-report
1287#
1288# coverage:
1289# $(MAKE) coverage-build
1290# $(MAKE) coverage-report
1291#
1292# coverage-clean:
1293# rm -f *.gcda *.gcno
1294#
1295# COVERAGE_CFLAGS = $(CFLAGS) -O0 -ftest-coverage -fprofile-arcs
1296# COVERAGE_LDFLAGS = $(CFLAGS) -O0 -lgcov
1297#
1298# coverage-build: coverage-clean
1299# $(MAKE) CFLAGS="$(COVERAGE_CFLAGS)" LDFLAGS="$(COVERAGE_LDFLAGS)" all
1300# $(MAKE) CFLAGS="$(COVERAGE_CFLAGS)" LDFLAGS="$(COVERAGE_LDFLAGS)" \
1301# -j1 test
1302#
1303# coverage-report:
1304# gcov -b *.c */*.c
1305# grep '^function.*called 0 ' *.c.gcov */*.c.gcov \
1306# | sed -e 's/\([^:]*\)\.gcov: *function \([^ ]*\) called.*/\1: \2/' \
1307# | tee coverage-untested-functions
diff --git a/tools/perf/bench/sched-pipe.c b/tools/perf/bench/sched-pipe.c
index d9ab3ce446ac..0c7454f8b8a9 100644
--- a/tools/perf/bench/sched-pipe.c
+++ b/tools/perf/bench/sched-pipe.c
@@ -55,7 +55,7 @@ int bench_sched_pipe(int argc, const char **argv,
55 * discarding returned value of read(), write() 55 * discarding returned value of read(), write()
56 * causes error in building environment for perf 56 * causes error in building environment for perf
57 */ 57 */
58 int ret, wait_stat; 58 int __used ret, wait_stat;
59 pid_t pid, retpid; 59 pid_t pid, retpid;
60 60
61 argc = parse_options(argc, argv, options, 61 argc = parse_options(argc, argv, options,
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 8879463807e4..555aefd7fe01 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -8,7 +8,6 @@
8#include "builtin.h" 8#include "builtin.h"
9 9
10#include "util/util.h" 10#include "util/util.h"
11
12#include "util/color.h" 11#include "util/color.h"
13#include <linux/list.h> 12#include <linux/list.h>
14#include "util/cache.h" 13#include "util/cache.h"
@@ -18,6 +17,9 @@
18#include "perf.h" 17#include "perf.h"
19#include "util/debug.h" 18#include "util/debug.h"
20 19
20#include "util/evlist.h"
21#include "util/evsel.h"
22#include "util/annotate.h"
21#include "util/event.h" 23#include "util/event.h"
22#include "util/parse-options.h" 24#include "util/parse-options.h"
23#include "util/parse-events.h" 25#include "util/parse-events.h"
@@ -26,6 +28,8 @@
26#include "util/hist.h" 28#include "util/hist.h"
27#include "util/session.h" 29#include "util/session.h"
28 30
31#include <linux/bitmap.h>
32
29static char const *input_name = "perf.data"; 33static char const *input_name = "perf.data";
30 34
31static bool force, use_tui, use_stdio; 35static bool force, use_tui, use_stdio;
@@ -36,9 +40,16 @@ 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 const char *cpu_list;
44static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
45
46static int perf_evlist__add_sample(struct perf_evlist *evlist,
47 struct perf_sample *sample,
48 struct perf_evsel *evsel,
49 struct addr_location *al)
40{ 50{
41 struct hist_entry *he; 51 struct hist_entry *he;
52 int ret;
42 53
43 if (sym_hist_filter != NULL && 54 if (sym_hist_filter != NULL &&
44 (al->sym == NULL || strcmp(sym_hist_filter, al->sym->name) != 0)) { 55 (al->sym == NULL || strcmp(sym_hist_filter, al->sym->name) != 0)) {
@@ -51,25 +62,44 @@ static int hists__add_entry(struct hists *self, struct addr_location *al)
51 return 0; 62 return 0;
52 } 63 }
53 64
54 he = __hists__add_entry(self, al, NULL, 1); 65 he = __hists__add_entry(&evsel->hists, al, NULL, 1);
55 if (he == NULL) 66 if (he == NULL)
56 return -ENOMEM; 67 return -ENOMEM;
57 68
58 return hist_entry__inc_addr_samples(he, al->addr); 69 ret = 0;
70 if (he->ms.sym != NULL) {
71 struct annotation *notes = symbol__annotation(he->ms.sym);
72 if (notes->src == NULL &&
73 symbol__alloc_hist(he->ms.sym, evlist->nr_entries) < 0)
74 return -ENOMEM;
75
76 ret = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
77 }
78
79 evsel->hists.stats.total_period += sample->period;
80 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
81 return ret;
59} 82}
60 83
61static int process_sample_event(event_t *event, struct sample_data *sample, 84static int process_sample_event(union perf_event *event,
85 struct perf_sample *sample,
86 struct perf_evsel *evsel,
62 struct perf_session *session) 87 struct perf_session *session)
63{ 88{
64 struct addr_location al; 89 struct addr_location al;
65 90
66 if (event__preprocess_sample(event, session, &al, sample, NULL) < 0) { 91 if (perf_event__preprocess_sample(event, session, &al, sample,
92 symbol__annotate_init) < 0) {
67 pr_warning("problem processing %d event, skipping it.\n", 93 pr_warning("problem processing %d event, skipping it.\n",
68 event->header.type); 94 event->header.type);
69 return -1; 95 return -1;
70 } 96 }
71 97
72 if (!al.filtered && hists__add_entry(&session->hists, &al)) { 98 if (cpu_list && !test_bit(sample->cpu, cpu_bitmap))
99 return 0;
100
101 if (!al.filtered &&
102 perf_evlist__add_sample(session->evlist, sample, evsel, &al)) {
73 pr_warning("problem incrementing symbol count, " 103 pr_warning("problem incrementing symbol count, "
74 "skipping event\n"); 104 "skipping event\n");
75 return -1; 105 return -1;
@@ -78,261 +108,26 @@ static int process_sample_event(event_t *event, struct sample_data *sample,
78 return 0; 108 return 0;
79} 109}
80 110
81static int objdump_line__print(struct objdump_line *self, 111static int hist_entry__tty_annotate(struct hist_entry *he, int evidx)
82 struct list_head *head,
83 struct hist_entry *he, u64 len)
84{
85 struct symbol *sym = he->ms.sym;
86 static const char *prev_line;
87 static const char *prev_color;
88
89 if (self->offset != -1) {
90 const char *path = NULL;
91 unsigned int hits = 0;
92 double percent = 0.0;
93 const char *color;
94 struct sym_priv *priv = symbol__priv(sym);
95 struct sym_ext *sym_ext = priv->ext;
96 struct sym_hist *h = priv->hist;
97 s64 offset = self->offset;
98 struct objdump_line *next = objdump__get_next_ip_line(head, self);
99
100 while (offset < (s64)len &&
101 (next == NULL || offset < next->offset)) {
102 if (sym_ext) {
103 if (path == NULL)
104 path = sym_ext[offset].path;
105 percent += sym_ext[offset].percent;
106 } else
107 hits += h->ip[offset];
108
109 ++offset;
110 }
111
112 if (sym_ext == NULL && h->sum)
113 percent = 100.0 * hits / h->sum;
114
115 color = get_percent_color(percent);
116
117 /*
118 * Also color the filename and line if needed, with
119 * the same color than the percentage. Don't print it
120 * twice for close colored ip with the same filename:line
121 */
122 if (path) {
123 if (!prev_line || strcmp(prev_line, path)
124 || color != prev_color) {
125 color_fprintf(stdout, color, " %s", path);
126 prev_line = path;
127 prev_color = color;
128 }
129 }
130
131 color_fprintf(stdout, color, " %7.2f", percent);
132 printf(" : ");
133 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", self->line);
134 } else {
135 if (!*self->line)
136 printf(" :\n");
137 else
138 printf(" : %s\n", self->line);
139 }
140
141 return 0;
142}
143
144static struct rb_root root_sym_ext;
145
146static void insert_source_line(struct sym_ext *sym_ext)
147{
148 struct sym_ext *iter;
149 struct rb_node **p = &root_sym_ext.rb_node;
150 struct rb_node *parent = NULL;
151
152 while (*p != NULL) {
153 parent = *p;
154 iter = rb_entry(parent, struct sym_ext, node);
155
156 if (sym_ext->percent > iter->percent)
157 p = &(*p)->rb_left;
158 else
159 p = &(*p)->rb_right;
160 }
161
162 rb_link_node(&sym_ext->node, parent, p);
163 rb_insert_color(&sym_ext->node, &root_sym_ext);
164}
165
166static void free_source_line(struct hist_entry *he, int len)
167{
168 struct sym_priv *priv = symbol__priv(he->ms.sym);
169 struct sym_ext *sym_ext = priv->ext;
170 int i;
171
172 if (!sym_ext)
173 return;
174
175 for (i = 0; i < len; i++)
176 free(sym_ext[i].path);
177 free(sym_ext);
178
179 priv->ext = NULL;
180 root_sym_ext = RB_ROOT;
181}
182
183/* Get the filename:line for the colored entries */
184static void
185get_source_line(struct hist_entry *he, int len, const char *filename)
186{
187 struct symbol *sym = he->ms.sym;
188 u64 start;
189 int i;
190 char cmd[PATH_MAX * 2];
191 struct sym_ext *sym_ext;
192 struct sym_priv *priv = symbol__priv(sym);
193 struct sym_hist *h = priv->hist;
194
195 if (!h->sum)
196 return;
197
198 sym_ext = priv->ext = calloc(len, sizeof(struct sym_ext));
199 if (!priv->ext)
200 return;
201
202 start = he->ms.map->unmap_ip(he->ms.map, sym->start);
203
204 for (i = 0; i < len; i++) {
205 char *path = NULL;
206 size_t line_len;
207 u64 offset;
208 FILE *fp;
209
210 sym_ext[i].percent = 100.0 * h->ip[i] / h->sum;
211 if (sym_ext[i].percent <= 0.5)
212 continue;
213
214 offset = start + i;
215 sprintf(cmd, "addr2line -e %s %016" PRIx64, filename, offset);
216 fp = popen(cmd, "r");
217 if (!fp)
218 continue;
219
220 if (getline(&path, &line_len, fp) < 0 || !line_len)
221 goto next;
222
223 sym_ext[i].path = malloc(sizeof(char) * line_len + 1);
224 if (!sym_ext[i].path)
225 goto next;
226
227 strcpy(sym_ext[i].path, path);
228 insert_source_line(&sym_ext[i]);
229
230 next:
231 pclose(fp);
232 }
233}
234
235static void print_summary(const char *filename)
236{ 112{
237 struct sym_ext *sym_ext; 113 return symbol__tty_annotate(he->ms.sym, he->ms.map, evidx,
238 struct rb_node *node; 114 print_line, full_paths, 0, 0);
239
240 printf("\nSorted summary for file %s\n", filename);
241 printf("----------------------------------------------\n\n");
242
243 if (RB_EMPTY_ROOT(&root_sym_ext)) {
244 printf(" Nothing higher than %1.1f%%\n", MIN_GREEN);
245 return;
246 }
247
248 node = rb_first(&root_sym_ext);
249 while (node) {
250 double percent;
251 const char *color;
252 char *path;
253
254 sym_ext = rb_entry(node, struct sym_ext, node);
255 percent = sym_ext->percent;
256 color = get_percent_color(percent);
257 path = sym_ext->path;
258
259 color_fprintf(stdout, color, " %7.2f %s", percent, path);
260 node = rb_next(node);
261 }
262}
263
264static void hist_entry__print_hits(struct hist_entry *self)
265{
266 struct symbol *sym = self->ms.sym;
267 struct sym_priv *priv = symbol__priv(sym);
268 struct sym_hist *h = priv->hist;
269 u64 len = sym->end - sym->start, offset;
270
271 for (offset = 0; offset < len; ++offset)
272 if (h->ip[offset] != 0)
273 printf("%*" PRIx64 ": %" PRIu64 "\n", BITS_PER_LONG / 2,
274 sym->start + offset, h->ip[offset]);
275 printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum);
276} 115}
277 116
278static int hist_entry__tty_annotate(struct hist_entry *he) 117static void hists__find_annotations(struct hists *self, int evidx)
279{
280 struct map *map = he->ms.map;
281 struct dso *dso = map->dso;
282 struct symbol *sym = he->ms.sym;
283 const char *filename = dso->long_name, *d_filename;
284 u64 len;
285 LIST_HEAD(head);
286 struct objdump_line *pos, *n;
287
288 if (hist_entry__annotate(he, &head, 0) < 0)
289 return -1;
290
291 if (full_paths)
292 d_filename = filename;
293 else
294 d_filename = basename(filename);
295
296 len = sym->end - sym->start;
297
298 if (print_line) {
299 get_source_line(he, len, filename);
300 print_summary(filename);
301 }
302
303 printf("\n\n------------------------------------------------\n");
304 printf(" Percent | Source code & Disassembly of %s\n", d_filename);
305 printf("------------------------------------------------\n");
306
307 if (verbose)
308 hist_entry__print_hits(he);
309
310 list_for_each_entry_safe(pos, n, &head, node) {
311 objdump_line__print(pos, &head, he, len);
312 list_del(&pos->node);
313 objdump_line__free(pos);
314 }
315
316 if (print_line)
317 free_source_line(he, len);
318
319 return 0;
320}
321
322static void hists__find_annotations(struct hists *self)
323{ 118{
324 struct rb_node *nd = rb_first(&self->entries), *next; 119 struct rb_node *nd = rb_first(&self->entries), *next;
325 int key = KEY_RIGHT; 120 int key = KEY_RIGHT;
326 121
327 while (nd) { 122 while (nd) {
328 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); 123 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
329 struct sym_priv *priv; 124 struct annotation *notes;
330 125
331 if (he->ms.sym == NULL || he->ms.map->dso->annotate_warned) 126 if (he->ms.sym == NULL || he->ms.map->dso->annotate_warned)
332 goto find_next; 127 goto find_next;
333 128
334 priv = symbol__priv(he->ms.sym); 129 notes = symbol__annotation(he->ms.sym);
335 if (priv->hist == NULL) { 130 if (notes->src == NULL) {
336find_next: 131find_next:
337 if (key == KEY_LEFT) 132 if (key == KEY_LEFT)
338 nd = rb_prev(nd); 133 nd = rb_prev(nd);
@@ -342,7 +137,7 @@ find_next:
342 } 137 }
343 138
344 if (use_browser > 0) { 139 if (use_browser > 0) {
345 key = hist_entry__tui_annotate(he); 140 key = hist_entry__tui_annotate(he, evidx);
346 switch (key) { 141 switch (key) {
347 case KEY_RIGHT: 142 case KEY_RIGHT:
348 next = rb_next(nd); 143 next = rb_next(nd);
@@ -357,24 +152,24 @@ find_next:
357 if (next != NULL) 152 if (next != NULL)
358 nd = next; 153 nd = next;
359 } else { 154 } else {
360 hist_entry__tty_annotate(he); 155 hist_entry__tty_annotate(he, evidx);
361 nd = rb_next(nd); 156 nd = rb_next(nd);
362 /* 157 /*
363 * Since we have a hist_entry per IP for the same 158 * Since we have a hist_entry per IP for the same
364 * symbol, free he->ms.sym->hist to signal we already 159 * symbol, free he->ms.sym->src to signal we already
365 * processed this symbol. 160 * processed this symbol.
366 */ 161 */
367 free(priv->hist); 162 free(notes->src);
368 priv->hist = NULL; 163 notes->src = NULL;
369 } 164 }
370 } 165 }
371} 166}
372 167
373static struct perf_event_ops event_ops = { 168static struct perf_event_ops event_ops = {
374 .sample = process_sample_event, 169 .sample = process_sample_event,
375 .mmap = event__process_mmap, 170 .mmap = perf_event__process_mmap,
376 .comm = event__process_comm, 171 .comm = perf_event__process_comm,
377 .fork = event__process_task, 172 .fork = perf_event__process_task,
378 .ordered_samples = true, 173 .ordered_samples = true,
379 .ordering_requires_timestamps = true, 174 .ordering_requires_timestamps = true,
380}; 175};
@@ -383,11 +178,19 @@ static int __cmd_annotate(void)
383{ 178{
384 int ret; 179 int ret;
385 struct perf_session *session; 180 struct perf_session *session;
181 struct perf_evsel *pos;
182 u64 total_nr_samples;
386 183
387 session = perf_session__new(input_name, O_RDONLY, force, false, &event_ops); 184 session = perf_session__new(input_name, O_RDONLY, force, false, &event_ops);
388 if (session == NULL) 185 if (session == NULL)
389 return -ENOMEM; 186 return -ENOMEM;
390 187
188 if (cpu_list) {
189 ret = perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap);
190 if (ret)
191 goto out_delete;
192 }
193
391 ret = perf_session__process_events(session, &event_ops); 194 ret = perf_session__process_events(session, &event_ops);
392 if (ret) 195 if (ret)
393 goto out_delete; 196 goto out_delete;
@@ -403,12 +206,36 @@ static int __cmd_annotate(void)
403 if (verbose > 2) 206 if (verbose > 2)
404 perf_session__fprintf_dsos(session, stdout); 207 perf_session__fprintf_dsos(session, stdout);
405 208
406 hists__collapse_resort(&session->hists); 209 total_nr_samples = 0;
407 hists__output_resort(&session->hists); 210 list_for_each_entry(pos, &session->evlist->entries, node) {
408 hists__find_annotations(&session->hists); 211 struct hists *hists = &pos->hists;
409out_delete: 212 u32 nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
410 perf_session__delete(session); 213
214 if (nr_samples > 0) {
215 total_nr_samples += nr_samples;
216 hists__collapse_resort(hists);
217 hists__output_resort(hists);
218 hists__find_annotations(hists, pos->idx);
219 }
220 }
411 221
222 if (total_nr_samples == 0) {
223 ui__warning("The %s file has no samples!\n", input_name);
224 goto out_delete;
225 }
226out_delete:
227 /*
228 * Speed up the exit process, for large files this can
229 * take quite a while.
230 *
231 * XXX Enable this when using valgrind or if we ever
232 * librarize this command.
233 *
234 * Also experiment with obstacks to see how much speed
235 * up we'll get here.
236 *
237 * perf_session__delete(session);
238 */
412 return ret; 239 return ret;
413} 240}
414 241
@@ -439,6 +266,7 @@ static const struct option options[] = {
439 "print matching source lines (may be slow)"), 266 "print matching source lines (may be slow)"),
440 OPT_BOOLEAN('P', "full-paths", &full_paths, 267 OPT_BOOLEAN('P', "full-paths", &full_paths,
441 "Don't shorten the displayed pathnames"), 268 "Don't shorten the displayed pathnames"),
269 OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"),
442 OPT_END() 270 OPT_END()
443}; 271};
444 272
@@ -451,9 +279,9 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used)
451 else if (use_tui) 279 else if (use_tui)
452 use_browser = 1; 280 use_browser = 1;
453 281
454 setup_browser(); 282 setup_browser(true);
455 283
456 symbol_conf.priv_size = sizeof(struct sym_priv); 284 symbol_conf.priv_size = sizeof(struct annotation);
457 symbol_conf.try_vmlinux_path = true; 285 symbol_conf.try_vmlinux_path = true;
458 286
459 if (symbol__init() < 0) 287 if (symbol__init() < 0)
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 3153e492dbcc..e8219990f8b8 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -30,13 +30,14 @@ static int hists__add_entry(struct hists *self,
30 return -ENOMEM; 30 return -ENOMEM;
31} 31}
32 32
33static int diff__process_sample_event(event_t *event, 33static int diff__process_sample_event(union perf_event *event,
34 struct sample_data *sample, 34 struct perf_sample *sample,
35 struct perf_evsel *evsel __used,
35 struct perf_session *session) 36 struct perf_session *session)
36{ 37{
37 struct addr_location al; 38 struct addr_location al;
38 39
39 if (event__preprocess_sample(event, session, &al, sample, NULL) < 0) { 40 if (perf_event__preprocess_sample(event, session, &al, sample, NULL) < 0) {
40 pr_warning("problem processing %d event, skipping it.\n", 41 pr_warning("problem processing %d event, skipping it.\n",
41 event->header.type); 42 event->header.type);
42 return -1; 43 return -1;
@@ -56,11 +57,11 @@ static int diff__process_sample_event(event_t *event,
56 57
57static struct perf_event_ops event_ops = { 58static struct perf_event_ops event_ops = {
58 .sample = diff__process_sample_event, 59 .sample = diff__process_sample_event,
59 .mmap = event__process_mmap, 60 .mmap = perf_event__process_mmap,
60 .comm = event__process_comm, 61 .comm = perf_event__process_comm,
61 .exit = event__process_task, 62 .exit = perf_event__process_task,
62 .fork = event__process_task, 63 .fork = perf_event__process_task,
63 .lost = event__process_lost, 64 .lost = perf_event__process_lost,
64 .ordered_samples = true, 65 .ordered_samples = true,
65 .ordering_requires_timestamps = true, 66 .ordering_requires_timestamps = true,
66}; 67};
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c
new file mode 100644
index 000000000000..4c5e9e04a41f
--- /dev/null
+++ b/tools/perf/builtin-evlist.c
@@ -0,0 +1,54 @@
1/*
2 * Builtin evlist command: Show the list of event selectors present
3 * in a perf.data file.
4 */
5#include "builtin.h"
6
7#include "util/util.h"
8
9#include <linux/list.h>
10
11#include "perf.h"
12#include "util/evlist.h"
13#include "util/evsel.h"
14#include "util/parse-events.h"
15#include "util/parse-options.h"
16#include "util/session.h"
17
18static char const *input_name = "perf.data";
19
20static int __cmd_evlist(void)
21{
22 struct perf_session *session;
23 struct perf_evsel *pos;
24
25 session = perf_session__new(input_name, O_RDONLY, 0, false, NULL);
26 if (session == NULL)
27 return -ENOMEM;
28
29 list_for_each_entry(pos, &session->evlist->entries, node)
30 printf("%s\n", event_name(pos));
31
32 perf_session__delete(session);
33 return 0;
34}
35
36static const char * const evlist_usage[] = {
37 "perf evlist [<options>]",
38 NULL
39};
40
41static const struct option options[] = {
42 OPT_STRING('i', "input", &input_name, "file",
43 "input file name"),
44 OPT_END()
45};
46
47int cmd_evlist(int argc, const char **argv, const char *prefix __used)
48{
49 argc = parse_options(argc, argv, options, evlist_usage, 0);
50 if (argc)
51 usage_with_options(evlist_usage, options);
52
53 return __cmd_evlist();
54}
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 0c78ffa7bf67..8dfc12bb119b 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -16,8 +16,8 @@
16static char const *input_name = "-"; 16static char const *input_name = "-";
17static bool inject_build_ids; 17static bool inject_build_ids;
18 18
19static int event__repipe_synth(event_t *event, 19static int perf_event__repipe_synth(union perf_event *event,
20 struct perf_session *session __used) 20 struct perf_session *session __used)
21{ 21{
22 uint32_t size; 22 uint32_t size;
23 void *buf = event; 23 void *buf = event;
@@ -36,41 +36,52 @@ static int event__repipe_synth(event_t *event,
36 return 0; 36 return 0;
37} 37}
38 38
39static int event__repipe(event_t *event, struct sample_data *sample __used, 39static int perf_event__repipe(union perf_event *event,
40 struct perf_session *session) 40 struct perf_sample *sample __used,
41 struct perf_session *session)
41{ 42{
42 return event__repipe_synth(event, session); 43 return perf_event__repipe_synth(event, session);
43} 44}
44 45
45static int event__repipe_mmap(event_t *self, struct sample_data *sample, 46static int perf_event__repipe_sample(union perf_event *event,
47 struct perf_sample *sample __used,
48 struct perf_evsel *evsel __used,
46 struct perf_session *session) 49 struct perf_session *session)
47{ 50{
51 return perf_event__repipe_synth(event, session);
52}
53
54static int perf_event__repipe_mmap(union perf_event *event,
55 struct perf_sample *sample,
56 struct perf_session *session)
57{
48 int err; 58 int err;
49 59
50 err = event__process_mmap(self, sample, session); 60 err = perf_event__process_mmap(event, sample, session);
51 event__repipe(self, sample, session); 61 perf_event__repipe(event, sample, session);
52 62
53 return err; 63 return err;
54} 64}
55 65
56static int event__repipe_task(event_t *self, struct sample_data *sample, 66static int perf_event__repipe_task(union perf_event *event,
57 struct perf_session *session) 67 struct perf_sample *sample,
68 struct perf_session *session)
58{ 69{
59 int err; 70 int err;
60 71
61 err = event__process_task(self, sample, session); 72 err = perf_event__process_task(event, sample, session);
62 event__repipe(self, sample, session); 73 perf_event__repipe(event, sample, session);
63 74
64 return err; 75 return err;
65} 76}
66 77
67static int event__repipe_tracing_data(event_t *self, 78static int perf_event__repipe_tracing_data(union perf_event *event,
68 struct perf_session *session) 79 struct perf_session *session)
69{ 80{
70 int err; 81 int err;
71 82
72 event__repipe_synth(self, session); 83 perf_event__repipe_synth(event, session);
73 err = event__process_tracing_data(self, session); 84 err = perf_event__process_tracing_data(event, session);
74 85
75 return err; 86 return err;
76} 87}
@@ -109,8 +120,8 @@ static int dso__inject_build_id(struct dso *self, struct perf_session *session)
109 if (self->kernel) 120 if (self->kernel)
110 misc = PERF_RECORD_MISC_KERNEL; 121 misc = PERF_RECORD_MISC_KERNEL;
111 122
112 err = event__synthesize_build_id(self, misc, event__repipe, 123 err = perf_event__synthesize_build_id(self, misc, perf_event__repipe,
113 machine, session); 124 machine, session);
114 if (err) { 125 if (err) {
115 pr_err("Can't synthesize build_id event for %s\n", self->long_name); 126 pr_err("Can't synthesize build_id event for %s\n", self->long_name);
116 return -1; 127 return -1;
@@ -119,8 +130,10 @@ static int dso__inject_build_id(struct dso *self, struct perf_session *session)
119 return 0; 130 return 0;
120} 131}
121 132
122static int event__inject_buildid(event_t *event, struct sample_data *sample, 133static int perf_event__inject_buildid(union perf_event *event,
123 struct perf_session *session) 134 struct perf_sample *sample,
135 struct perf_evsel *evsel __used,
136 struct perf_session *session)
124{ 137{
125 struct addr_location al; 138 struct addr_location al;
126 struct thread *thread; 139 struct thread *thread;
@@ -155,24 +168,24 @@ static int event__inject_buildid(event_t *event, struct sample_data *sample,
155 } 168 }
156 169
157repipe: 170repipe:
158 event__repipe(event, sample, session); 171 perf_event__repipe(event, sample, session);
159 return 0; 172 return 0;
160} 173}
161 174
162struct perf_event_ops inject_ops = { 175struct perf_event_ops inject_ops = {
163 .sample = event__repipe, 176 .sample = perf_event__repipe_sample,
164 .mmap = event__repipe, 177 .mmap = perf_event__repipe,
165 .comm = event__repipe, 178 .comm = perf_event__repipe,
166 .fork = event__repipe, 179 .fork = perf_event__repipe,
167 .exit = event__repipe, 180 .exit = perf_event__repipe,
168 .lost = event__repipe, 181 .lost = perf_event__repipe,
169 .read = event__repipe, 182 .read = perf_event__repipe,
170 .throttle = event__repipe, 183 .throttle = perf_event__repipe,
171 .unthrottle = event__repipe, 184 .unthrottle = perf_event__repipe,
172 .attr = event__repipe_synth, 185 .attr = perf_event__repipe_synth,
173 .event_type = event__repipe_synth, 186 .event_type = perf_event__repipe_synth,
174 .tracing_data = event__repipe_synth, 187 .tracing_data = perf_event__repipe_synth,
175 .build_id = event__repipe_synth, 188 .build_id = perf_event__repipe_synth,
176}; 189};
177 190
178extern volatile int session_done; 191extern volatile int session_done;
@@ -190,10 +203,10 @@ static int __cmd_inject(void)
190 signal(SIGINT, sig_handler); 203 signal(SIGINT, sig_handler);
191 204
192 if (inject_build_ids) { 205 if (inject_build_ids) {
193 inject_ops.sample = event__inject_buildid; 206 inject_ops.sample = perf_event__inject_buildid;
194 inject_ops.mmap = event__repipe_mmap; 207 inject_ops.mmap = perf_event__repipe_mmap;
195 inject_ops.fork = event__repipe_task; 208 inject_ops.fork = perf_event__repipe_task;
196 inject_ops.tracing_data = event__repipe_tracing_data; 209 inject_ops.tracing_data = perf_event__repipe_tracing_data;
197 } 210 }
198 211
199 session = perf_session__new(input_name, O_RDONLY, false, true, &inject_ops); 212 session = perf_session__new(input_name, O_RDONLY, false, true, &inject_ops);
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index d97256d65980..225e963df105 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -275,9 +275,8 @@ static void process_free_event(void *data,
275 s_alloc->alloc_cpu = -1; 275 s_alloc->alloc_cpu = -1;
276} 276}
277 277
278static void 278static void process_raw_event(union perf_event *raw_event __used, void *data,
279process_raw_event(event_t *raw_event __used, void *data, 279 int cpu, u64 timestamp, struct thread *thread)
280 int cpu, u64 timestamp, struct thread *thread)
281{ 280{
282 struct event *event; 281 struct event *event;
283 int type; 282 int type;
@@ -304,7 +303,9 @@ process_raw_event(event_t *raw_event __used, void *data,
304 } 303 }
305} 304}
306 305
307static int process_sample_event(event_t *event, struct sample_data *sample, 306static int process_sample_event(union perf_event *event,
307 struct perf_sample *sample,
308 struct perf_evsel *evsel __used,
308 struct perf_session *session) 309 struct perf_session *session)
309{ 310{
310 struct thread *thread = perf_session__findnew(session, event->ip.pid); 311 struct thread *thread = perf_session__findnew(session, event->ip.pid);
@@ -325,7 +326,7 @@ static int process_sample_event(event_t *event, struct sample_data *sample,
325 326
326static struct perf_event_ops event_ops = { 327static struct perf_event_ops event_ops = {
327 .sample = process_sample_event, 328 .sample = process_sample_event,
328 .comm = event__process_comm, 329 .comm = perf_event__process_comm,
329 .ordered_samples = true, 330 .ordered_samples = true,
330}; 331};
331 332
diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c
index d88c6961274c..6313b6eb3ebb 100644
--- a/tools/perf/builtin-list.c
+++ b/tools/perf/builtin-list.c
@@ -5,6 +5,7 @@
5 * 5 *
6 * Copyright (C) 2009, Thomas Gleixner <tglx@linutronix.de> 6 * Copyright (C) 2009, Thomas Gleixner <tglx@linutronix.de>
7 * Copyright (C) 2008-2009, Red Hat Inc, Ingo Molnar <mingo@redhat.com> 7 * Copyright (C) 2008-2009, Red Hat Inc, Ingo Molnar <mingo@redhat.com>
8 * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
8 */ 9 */
9#include "builtin.h" 10#include "builtin.h"
10 11
@@ -13,9 +14,47 @@
13#include "util/parse-events.h" 14#include "util/parse-events.h"
14#include "util/cache.h" 15#include "util/cache.h"
15 16
16int cmd_list(int argc __used, const char **argv __used, const char *prefix __used) 17int cmd_list(int argc, const char **argv, const char *prefix __used)
17{ 18{
18 setup_pager(); 19 setup_pager();
19 print_events(); 20
21 if (argc == 1)
22 print_events(NULL);
23 else {
24 int i;
25
26 for (i = 1; i < argc; ++i) {
27 if (i > 1)
28 putchar('\n');
29 if (strncmp(argv[i], "tracepoint", 10) == 0)
30 print_tracepoint_events(NULL, NULL);
31 else if (strcmp(argv[i], "hw") == 0 ||
32 strcmp(argv[i], "hardware") == 0)
33 print_events_type(PERF_TYPE_HARDWARE);
34 else if (strcmp(argv[i], "sw") == 0 ||
35 strcmp(argv[i], "software") == 0)
36 print_events_type(PERF_TYPE_SOFTWARE);
37 else if (strcmp(argv[i], "cache") == 0 ||
38 strcmp(argv[i], "hwcache") == 0)
39 print_hwcache_events(NULL);
40 else {
41 char *sep = strchr(argv[i], ':'), *s;
42 int sep_idx;
43
44 if (sep == NULL) {
45 print_events(argv[i]);
46 continue;
47 }
48 sep_idx = sep - argv[i];
49 s = strdup(argv[i]);
50 if (s == NULL)
51 return -1;
52
53 s[sep_idx] = '\0';
54 print_tracepoint_events(s, s + sep_idx + 1);
55 free(s);
56 }
57 }
58 }
20 return 0; 59 return 0;
21} 60}
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index 2b36defc5d73..899080ace267 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -202,9 +202,20 @@ static struct thread_stat *thread_stat_findnew_first(u32 tid)
202SINGLE_KEY(nr_acquired) 202SINGLE_KEY(nr_acquired)
203SINGLE_KEY(nr_contended) 203SINGLE_KEY(nr_contended)
204SINGLE_KEY(wait_time_total) 204SINGLE_KEY(wait_time_total)
205SINGLE_KEY(wait_time_min)
206SINGLE_KEY(wait_time_max) 205SINGLE_KEY(wait_time_max)
207 206
207static int lock_stat_key_wait_time_min(struct lock_stat *one,
208 struct lock_stat *two)
209{
210 u64 s1 = one->wait_time_min;
211 u64 s2 = two->wait_time_min;
212 if (s1 == ULLONG_MAX)
213 s1 = 0;
214 if (s2 == ULLONG_MAX)
215 s2 = 0;
216 return s1 > s2;
217}
218
208struct lock_key { 219struct lock_key {
209 /* 220 /*
210 * name: the value for specify by user 221 * name: the value for specify by user
@@ -834,14 +845,16 @@ static void dump_info(void)
834 die("Unknown type of information\n"); 845 die("Unknown type of information\n");
835} 846}
836 847
837static int process_sample_event(event_t *self, struct sample_data *sample, 848static int process_sample_event(union perf_event *event,
849 struct perf_sample *sample,
850 struct perf_evsel *evsel __used,
838 struct perf_session *s) 851 struct perf_session *s)
839{ 852{
840 struct thread *thread = perf_session__findnew(s, sample->tid); 853 struct thread *thread = perf_session__findnew(s, sample->tid);
841 854
842 if (thread == NULL) { 855 if (thread == NULL) {
843 pr_debug("problem processing %d event, skipping it.\n", 856 pr_debug("problem processing %d event, skipping it.\n",
844 self->header.type); 857 event->header.type);
845 return -1; 858 return -1;
846 } 859 }
847 860
@@ -852,7 +865,7 @@ static int process_sample_event(event_t *self, struct sample_data *sample,
852 865
853static struct perf_event_ops eops = { 866static struct perf_event_ops eops = {
854 .sample = process_sample_event, 867 .sample = process_sample_event,
855 .comm = event__process_comm, 868 .comm = perf_event__process_comm,
856 .ordered_samples = true, 869 .ordered_samples = true,
857}; 870};
858 871
@@ -893,7 +906,7 @@ static const char * const report_usage[] = {
893 906
894static const struct option report_options[] = { 907static const struct option report_options[] = {
895 OPT_STRING('k', "key", &sort_key, "acquired", 908 OPT_STRING('k', "key", &sort_key, "acquired",
896 "key for sorting"), 909 "key for sorting (acquired / contended / wait_total / wait_max / wait_min)"),
897 /* TODO: type */ 910 /* TODO: type */
898 OPT_END() 911 OPT_END()
899}; 912};
@@ -929,10 +942,10 @@ static const char *record_args[] = {
929 "-f", 942 "-f",
930 "-m", "1024", 943 "-m", "1024",
931 "-c", "1", 944 "-c", "1",
932 "-e", "lock:lock_acquire:r", 945 "-e", "lock:lock_acquire",
933 "-e", "lock:lock_acquired:r", 946 "-e", "lock:lock_acquired",
934 "-e", "lock:lock_contended:r", 947 "-e", "lock:lock_contended",
935 "-e", "lock:lock_release:r", 948 "-e", "lock:lock_release",
936}; 949};
937 950
938static int __cmd_record(int argc, const char **argv) 951static int __cmd_record(int argc, const char **argv)
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index add163c9f0e7..5f2a5c7046df 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' ...]",
@@ -216,11 +242,19 @@ static const struct option options[] = {
216 OPT_STRING('s', "source", &symbol_conf.source_prefix, 242 OPT_STRING('s', "source", &symbol_conf.source_prefix,
217 "directory", "path to kernel source"), 243 "directory", "path to kernel source"),
218 OPT_STRING('m', "module", &params.target_module, 244 OPT_STRING('m', "module", &params.target_module,
219 "modname", "target module name"), 245 "modname|path",
246 "target module name (for online) or path (for offline)"),
220#endif 247#endif
221 OPT__DRY_RUN(&probe_event_dry_run), 248 OPT__DRY_RUN(&probe_event_dry_run),
222 OPT_INTEGER('\0', "max-probes", &params.max_probe_points, 249 OPT_INTEGER('\0', "max-probes", &params.max_probe_points,
223 "Set how many probe points can be found for a probe."), 250 "Set how many probe points can be found for a probe."),
251 OPT_BOOLEAN('F', "funcs", &params.show_funcs,
252 "Show potential probe-able functions."),
253 OPT_CALLBACK('\0', "filter", NULL,
254 "[!]FILTER", "Set a filter (with --vars/funcs only)\n"
255 "\t\t\t(default: \"" DEFAULT_VAR_FILTER "\" for --vars,\n"
256 "\t\t\t \"" DEFAULT_FUNC_FILTER "\" for --funcs)",
257 opt_set_filter),
224 OPT_END() 258 OPT_END()
225}; 259};
226 260
@@ -246,7 +280,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
246 params.max_probe_points = MAX_PROBES; 280 params.max_probe_points = MAX_PROBES;
247 281
248 if ((!params.nevents && !params.dellist && !params.list_events && 282 if ((!params.nevents && !params.dellist && !params.list_events &&
249 !params.show_lines)) 283 !params.show_lines && !params.show_funcs))
250 usage_with_options(probe_usage, options); 284 usage_with_options(probe_usage, options);
251 285
252 /* 286 /*
@@ -267,12 +301,41 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
267 pr_err(" Error: Don't use --list with --vars.\n"); 301 pr_err(" Error: Don't use --list with --vars.\n");
268 usage_with_options(probe_usage, options); 302 usage_with_options(probe_usage, options);
269 } 303 }
304 if (params.show_funcs) {
305 pr_err(" Error: Don't use --list with --funcs.\n");
306 usage_with_options(probe_usage, options);
307 }
270 ret = show_perf_probe_events(); 308 ret = show_perf_probe_events();
271 if (ret < 0) 309 if (ret < 0)
272 pr_err(" Error: Failed to show event list. (%d)\n", 310 pr_err(" Error: Failed to show event list. (%d)\n",
273 ret); 311 ret);
274 return ret; 312 return ret;
275 } 313 }
314 if (params.show_funcs) {
315 if (params.nevents != 0 || params.dellist) {
316 pr_err(" Error: Don't use --funcs with"
317 " --add/--del.\n");
318 usage_with_options(probe_usage, options);
319 }
320 if (params.show_lines) {
321 pr_err(" Error: Don't use --funcs with --line.\n");
322 usage_with_options(probe_usage, options);
323 }
324 if (params.show_vars) {
325 pr_err(" Error: Don't use --funcs with --vars.\n");
326 usage_with_options(probe_usage, options);
327 }
328 if (!params.filter)
329 params.filter = strfilter__new(DEFAULT_FUNC_FILTER,
330 NULL);
331 ret = show_available_funcs(params.target_module,
332 params.filter);
333 strfilter__delete(params.filter);
334 if (ret < 0)
335 pr_err(" Error: Failed to show functions."
336 " (%d)\n", ret);
337 return ret;
338 }
276 339
277#ifdef DWARF_SUPPORT 340#ifdef DWARF_SUPPORT
278 if (params.show_lines) { 341 if (params.show_lines) {
@@ -297,10 +360,16 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
297 " --add/--del.\n"); 360 " --add/--del.\n");
298 usage_with_options(probe_usage, options); 361 usage_with_options(probe_usage, options);
299 } 362 }
363 if (!params.filter)
364 params.filter = strfilter__new(DEFAULT_VAR_FILTER,
365 NULL);
366
300 ret = show_available_vars(params.events, params.nevents, 367 ret = show_available_vars(params.events, params.nevents,
301 params.max_probe_points, 368 params.max_probe_points,
302 params.target_module, 369 params.target_module,
370 params.filter,
303 params.show_ext_vars); 371 params.show_ext_vars);
372 strfilter__delete(params.filter);
304 if (ret < 0) 373 if (ret < 0)
305 pr_err(" Error: Failed to show vars. (%d)\n", ret); 374 pr_err(" Error: Failed to show vars. (%d)\n", ret);
306 return ret; 375 return ret;
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 60cac6f92e8b..f6426b496f4a 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -18,18 +18,18 @@
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>
29#include <sys/mman.h> 31#include <sys/mman.h>
30 32
31#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
32
33enum write_mode_t { 33enum write_mode_t {
34 WRITE_FORCE, 34 WRITE_FORCE,
35 WRITE_APPEND 35 WRITE_APPEND
@@ -37,16 +37,14 @@ enum write_mode_t {
37 37
38static u64 user_interval = ULLONG_MAX; 38static u64 user_interval = ULLONG_MAX;
39static u64 default_interval = 0; 39static u64 default_interval = 0;
40static u64 sample_type;
41 40
42static struct cpu_map *cpus;
43static unsigned int page_size; 41static unsigned int page_size;
44static unsigned int mmap_pages = 128; 42static unsigned int mmap_pages = UINT_MAX;
45static unsigned int user_freq = UINT_MAX; 43static unsigned int user_freq = UINT_MAX;
46static int freq = 1000; 44static int freq = 1000;
47static int output; 45static int output;
48static int pipe_output = 0; 46static int pipe_output = 0;
49static const char *output_name = "perf.data"; 47static const char *output_name = NULL;
50static int group = 0; 48static int group = 0;
51static int realtime_prio = 0; 49static int realtime_prio = 0;
52static bool nodelay = false; 50static bool nodelay = false;
@@ -55,7 +53,6 @@ static bool sample_id_all_avail = true;
55static bool system_wide = false; 53static bool system_wide = false;
56static pid_t target_pid = -1; 54static pid_t target_pid = -1;
57static pid_t target_tid = -1; 55static pid_t target_tid = -1;
58static struct thread_map *threads;
59static pid_t child_pid = -1; 56static pid_t child_pid = -1;
60static bool no_inherit = false; 57static bool no_inherit = false;
61static enum write_mode_t write_mode = WRITE_FORCE; 58static enum write_mode_t write_mode = WRITE_FORCE;
@@ -66,51 +63,17 @@ static bool sample_address = false;
66static bool sample_time = false; 63static bool sample_time = false;
67static bool no_buildid = false; 64static bool no_buildid = false;
68static bool no_buildid_cache = false; 65static bool no_buildid_cache = false;
66static struct perf_evlist *evsel_list;
69 67
70static long samples = 0; 68static long samples = 0;
71static u64 bytes_written = 0; 69static u64 bytes_written = 0;
72 70
73static struct pollfd *event_array;
74
75static int nr_poll = 0;
76static int nr_cpu = 0;
77
78static int file_new = 1; 71static int file_new = 1;
79static off_t post_processing_offset; 72static off_t post_processing_offset;
80 73
81static struct perf_session *session; 74static struct perf_session *session;
82static const char *cpu_list; 75static const char *cpu_list;
83 76
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) 77static void advance_output(size_t size)
115{ 78{
116 bytes_written += size; 79 bytes_written += size;
@@ -131,42 +94,26 @@ static void write_output(void *buf, size_t size)
131 } 94 }
132} 95}
133 96
134static int process_synthesized_event(event_t *event, 97static int process_synthesized_event(union perf_event *event,
135 struct sample_data *sample __used, 98 struct perf_sample *sample __used,
136 struct perf_session *self __used) 99 struct perf_session *self __used)
137{ 100{
138 write_output(event, event->header.size); 101 write_output(event, event->header.size);
139 return 0; 102 return 0;
140} 103}
141 104
142static void mmap_read(struct mmap_data *md) 105static void mmap_read(struct perf_mmap *md)
143{ 106{
144 unsigned int head = mmap_read_head(md); 107 unsigned int head = perf_mmap__read_head(md);
145 unsigned int old = md->prev; 108 unsigned int old = md->prev;
146 unsigned char *data = md->base + page_size; 109 unsigned char *data = md->base + page_size;
147 unsigned long size; 110 unsigned long size;
148 void *buf; 111 void *buf;
149 int diff;
150 112
151 /* 113 if (old == head)
152 * If we're further behind than half the buffer, there's a chance 114 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 115
168 if (old != head) 116 samples++;
169 samples++;
170 117
171 size = head - old; 118 size = head - old;
172 119
@@ -185,7 +132,7 @@ static void mmap_read(struct mmap_data *md)
185 write_output(buf, size); 132 write_output(buf, size);
186 133
187 md->prev = old; 134 md->prev = old;
188 mmap_write_tail(md, old); 135 perf_mmap__write_tail(md, old);
189} 136}
190 137
191static volatile int done = 0; 138static volatile int done = 0;
@@ -209,61 +156,19 @@ static void sig_atexit(void)
209 kill(getpid(), signr); 156 kill(getpid(), signr);
210} 157}
211 158
212static int group_fd; 159static 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{ 160{
216 struct perf_header_attr *h_attr;
217
218 if (nr < session->header.attrs) {
219 h_attr = session->header.attr[nr];
220 } else {
221 h_attr = perf_header_attr__new(a);
222 if (h_attr != NULL)
223 if (perf_header__add_attr(&session->header, h_attr) < 0) {
224 perf_header_attr__delete(h_attr);
225 h_attr = NULL;
226 }
227 }
228
229 return h_attr;
230}
231
232static void create_counter(struct perf_evsel *evsel, int cpu)
233{
234 char *filter = evsel->filter;
235 struct perf_event_attr *attr = &evsel->attr; 161 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 */ 162 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 163
164 attr->inherit = !no_inherit;
260 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | 165 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
261 PERF_FORMAT_TOTAL_TIME_RUNNING | 166 PERF_FORMAT_TOTAL_TIME_RUNNING |
262 PERF_FORMAT_ID; 167 PERF_FORMAT_ID;
263 168
264 attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID; 169 attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID;
265 170
266 if (nr_counters > 1) 171 if (evlist->nr_entries > 1)
267 attr->sample_type |= PERF_SAMPLE_ID; 172 attr->sample_type |= PERF_SAMPLE_ID;
268 173
269 /* 174 /*
@@ -315,26 +220,66 @@ static void create_counter(struct perf_evsel *evsel, int cpu)
315 220
316 attr->mmap = track; 221 attr->mmap = track;
317 attr->comm = track; 222 attr->comm = track;
318 attr->inherit = !no_inherit; 223
319 if (target_pid == -1 && target_tid == -1 && !system_wide) { 224 if (target_pid == -1 && target_tid == -1 && !system_wide) {
320 attr->disabled = 1; 225 attr->disabled = 1;
321 attr->enable_on_exec = 1; 226 attr->enable_on_exec = 1;
322 } 227 }
323retry_sample_id: 228}
324 attr->sample_id_all = sample_id_all_avail ? 1 : 0;
325 229
326 for (thread_index = 0; thread_index < threads->nr; thread_index++) { 230static bool perf_evlist__equal(struct perf_evlist *evlist,
327try_again: 231 struct perf_evlist *other)
328 FD(evsel, nr_cpu, thread_index) = sys_perf_event_open(attr, threads->map[thread_index], cpu, group_fd, 0); 232{
233 struct perf_evsel *pos, *pair;
234
235 if (evlist->nr_entries != other->nr_entries)
236 return false;
237
238 pair = list_entry(other->entries.next, struct perf_evsel, node);
239
240 list_for_each_entry(pos, &evlist->entries, node) {
241 if (memcmp(&pos->attr, &pair->attr, sizeof(pos->attr) != 0))
242 return false;
243 pair = list_entry(pair->node.next, struct perf_evsel, node);
244 }
245
246 return true;
247}
248
249static void open_counters(struct perf_evlist *evlist)
250{
251 struct perf_evsel *pos;
252
253 if (evlist->cpus->map[0] < 0)
254 no_inherit = true;
329 255
330 if (FD(evsel, nr_cpu, thread_index) < 0) { 256 list_for_each_entry(pos, &evlist->entries, node) {
257 struct perf_event_attr *attr = &pos->attr;
258 /*
259 * Check if parse_single_tracepoint_event has already asked for
260 * PERF_SAMPLE_TIME.
261 *
262 * XXX this is kludgy but short term fix for problems introduced by
263 * eac23d1c that broke 'perf script' by having different sample_types
264 * when using multiple tracepoint events when we use a perf binary
265 * that tries to use sample_id_all on an older kernel.
266 *
267 * We need to move counter creation to perf_session, support
268 * different sample_types, etc.
269 */
270 bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
271
272 config_attr(pos, evlist);
273retry_sample_id:
274 attr->sample_id_all = sample_id_all_avail ? 1 : 0;
275try_again:
276 if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group) < 0) {
331 int err = errno; 277 int err = errno;
332 278
333 if (err == EPERM || err == EACCES) 279 if (err == EPERM || err == EACCES) {
334 die("Permission error - are you root?\n" 280 ui__warning_paranoid();
335 "\t Consider tweaking" 281 exit(EXIT_FAILURE);
336 " /proc/sys/kernel/perf_event_paranoid.\n"); 282 } else if (err == ENODEV && cpu_list) {
337 else if (err == ENODEV && cpu_list) {
338 die("No such device - did you specify" 283 die("No such device - did you specify"
339 " an out-of-range profile CPU?\n"); 284 " an out-of-range profile CPU?\n");
340 } else if (err == EINVAL && sample_id_all_avail) { 285 } else if (err == EINVAL && sample_id_all_avail) {
@@ -357,14 +302,22 @@ try_again:
357 && attr->config == PERF_COUNT_HW_CPU_CYCLES) { 302 && attr->config == PERF_COUNT_HW_CPU_CYCLES) {
358 303
359 if (verbose) 304 if (verbose)
360 warning(" ... trying to fall back to cpu-clock-ticks\n"); 305 ui__warning("The cycles event is not supported, "
306 "trying to fall back to cpu-clock-ticks\n");
361 attr->type = PERF_TYPE_SOFTWARE; 307 attr->type = PERF_TYPE_SOFTWARE;
362 attr->config = PERF_COUNT_SW_CPU_CLOCK; 308 attr->config = PERF_COUNT_SW_CPU_CLOCK;
363 goto try_again; 309 goto try_again;
364 } 310 }
311
312 if (err == ENOENT) {
313 ui__warning("The %s event is not supported.\n",
314 event_name(pos));
315 exit(EXIT_FAILURE);
316 }
317
365 printf("\n"); 318 printf("\n");
366 error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n", 319 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)); 320 err, strerror(err));
368 321
369#if defined(__i386__) || defined(__x86_64__) 322#if defined(__i386__) || defined(__x86_64__)
370 if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP) 323 if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP)
@@ -375,90 +328,28 @@ try_again:
375#endif 328#endif
376 329
377 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); 330 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
378 exit(-1);
379 } 331 }
332 }
380 333
381 h_attr = get_header_attr(attr, evsel->idx); 334 if (perf_evlist__set_filters(evlist)) {
382 if (h_attr == NULL) 335 error("failed to set filter with %d (%s)\n", errno,
383 die("nomem\n"); 336 strerror(errno));
337 exit(-1);
338 }
384 339
385 if (!file_new) { 340 if (perf_evlist__mmap(evlist, mmap_pages, false) < 0)
386 if (memcmp(&h_attr->attr, attr, sizeof(*attr))) { 341 die("failed to mmap with %d (%s)\n", errno, strerror(errno));
387 fprintf(stderr, "incompatible append\n");
388 exit(-1);
389 }
390 }
391 342
392 if (read(FD(evsel, nr_cpu, thread_index), &read_data, sizeof(read_data)) == -1) { 343 if (file_new)
393 perror("Unable to read perf file descriptor"); 344 session->evlist = evlist;
345 else {
346 if (!perf_evlist__equal(session->evlist, evlist)) {
347 fprintf(stderr, "incompatible append\n");
394 exit(-1); 348 exit(-1);
395 } 349 }
350 }
396 351
397 if (perf_header_attr__add_id(h_attr, read_data.id) < 0) { 352 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} 353}
463 354
464static int process_buildids(void) 355static int process_buildids(void)
@@ -481,14 +372,14 @@ static void atexit_header(void)
481 372
482 if (!no_buildid) 373 if (!no_buildid)
483 process_buildids(); 374 process_buildids();
484 perf_header__write(&session->header, output, true); 375 perf_session__write_header(session, evsel_list, output, true);
485 perf_session__delete(session); 376 perf_session__delete(session);
486 perf_evsel_list__delete(); 377 perf_evlist__delete(evsel_list);
487 symbol__exit(); 378 symbol__exit();
488 } 379 }
489} 380}
490 381
491static void event__synthesize_guest_os(struct machine *machine, void *data) 382static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
492{ 383{
493 int err; 384 int err;
494 struct perf_session *psession = data; 385 struct perf_session *psession = data;
@@ -504,8 +395,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 395 *method is used to avoid symbol missing when the first addr is
505 *in module instead of in guest kernel. 396 *in module instead of in guest kernel.
506 */ 397 */
507 err = event__synthesize_modules(process_synthesized_event, 398 err = perf_event__synthesize_modules(process_synthesized_event,
508 psession, machine); 399 psession, machine);
509 if (err < 0) 400 if (err < 0)
510 pr_err("Couldn't record guest kernel [%d]'s reference" 401 pr_err("Couldn't record guest kernel [%d]'s reference"
511 " relocation symbol.\n", machine->pid); 402 " relocation symbol.\n", machine->pid);
@@ -514,11 +405,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 405 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
515 * have no _text sometimes. 406 * have no _text sometimes.
516 */ 407 */
517 err = event__synthesize_kernel_mmap(process_synthesized_event, 408 err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
518 psession, machine, "_text"); 409 psession, machine, "_text");
519 if (err < 0) 410 if (err < 0)
520 err = event__synthesize_kernel_mmap(process_synthesized_event, 411 err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
521 psession, machine, "_stext"); 412 psession, machine,
413 "_stext");
522 if (err < 0) 414 if (err < 0)
523 pr_err("Couldn't record guest kernel [%d]'s reference" 415 pr_err("Couldn't record guest kernel [%d]'s reference"
524 " relocation symbol.\n", machine->pid); 416 " relocation symbol.\n", machine->pid);
@@ -533,9 +425,9 @@ static void mmap_read_all(void)
533{ 425{
534 int i; 426 int i;
535 427
536 for (i = 0; i < nr_cpu; i++) { 428 for (i = 0; i < evsel_list->nr_mmaps; i++) {
537 if (mmap_array[i].base) 429 if (evsel_list->mmap[i].base)
538 mmap_read(&mmap_array[i]); 430 mmap_read(&evsel_list->mmap[i]);
539 } 431 }
540 432
541 if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO)) 433 if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO))
@@ -544,7 +436,6 @@ static void mmap_read_all(void)
544 436
545static int __cmd_record(int argc, const char **argv) 437static int __cmd_record(int argc, const char **argv)
546{ 438{
547 int i;
548 struct stat st; 439 struct stat st;
549 int flags; 440 int flags;
550 int err; 441 int err;
@@ -566,18 +457,26 @@ static int __cmd_record(int argc, const char **argv)
566 exit(-1); 457 exit(-1);
567 } 458 }
568 459
569 if (!strcmp(output_name, "-")) 460 if (!output_name) {
570 pipe_output = 1; 461 if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
571 else if (!stat(output_name, &st) && st.st_size) { 462 pipe_output = 1;
572 if (write_mode == WRITE_FORCE) { 463 else
573 char oldname[PATH_MAX]; 464 output_name = "perf.data";
574 snprintf(oldname, sizeof(oldname), "%s.old", 465 }
575 output_name); 466 if (output_name) {
576 unlink(oldname); 467 if (!strcmp(output_name, "-"))
577 rename(output_name, oldname); 468 pipe_output = 1;
469 else if (!stat(output_name, &st) && st.st_size) {
470 if (write_mode == WRITE_FORCE) {
471 char oldname[PATH_MAX];
472 snprintf(oldname, sizeof(oldname), "%s.old",
473 output_name);
474 unlink(oldname);
475 rename(output_name, oldname);
476 }
477 } else if (write_mode == WRITE_APPEND) {
478 write_mode = WRITE_FORCE;
578 } 479 }
579 } else if (write_mode == WRITE_APPEND) {
580 write_mode = WRITE_FORCE;
581 } 480 }
582 481
583 flags = O_CREAT|O_RDWR; 482 flags = O_CREAT|O_RDWR;
@@ -606,18 +505,17 @@ static int __cmd_record(int argc, const char **argv)
606 perf_header__set_feat(&session->header, HEADER_BUILD_ID); 505 perf_header__set_feat(&session->header, HEADER_BUILD_ID);
607 506
608 if (!file_new) { 507 if (!file_new) {
609 err = perf_header__read(session, output); 508 err = perf_session__read_header(session, output);
610 if (err < 0) 509 if (err < 0)
611 goto out_delete_session; 510 goto out_delete_session;
612 } 511 }
613 512
614 if (have_tracepoints(&evsel_list)) 513 if (have_tracepoints(&evsel_list->entries))
615 perf_header__set_feat(&session->header, HEADER_TRACE_INFO); 514 perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
616 515
617 /* 516 /* 512 kiB: default amount of unprivileged mlocked memory */
618 * perf_session__delete(session) will be called at atexit_header() 517 if (mmap_pages == UINT_MAX)
619 */ 518 mmap_pages = (512 * 1024) / page_size;
620 atexit(atexit_header);
621 519
622 if (forks) { 520 if (forks) {
623 child_pid = fork(); 521 child_pid = fork();
@@ -659,7 +557,7 @@ static int __cmd_record(int argc, const char **argv)
659 } 557 }
660 558
661 if (!system_wide && target_tid == -1 && target_pid == -1) 559 if (!system_wide && target_tid == -1 && target_pid == -1)
662 threads->map[0] = child_pid; 560 evsel_list->threads->map[0] = child_pid;
663 561
664 close(child_ready_pipe[1]); 562 close(child_ready_pipe[1]);
665 close(go_pipe[0]); 563 close(go_pipe[0]);
@@ -673,46 +571,42 @@ static int __cmd_record(int argc, const char **argv)
673 close(child_ready_pipe[0]); 571 close(child_ready_pipe[0]);
674 } 572 }
675 573
676 if (!system_wide && no_inherit && !cpu_list) { 574 open_counters(evsel_list);
677 open_counters(-1);
678 } else {
679 for (i = 0; i < cpus->nr; i++)
680 open_counters(cpus->map[i]);
681 }
682 575
683 perf_session__set_sample_type(session, sample_type); 576 /*
577 * perf_session__delete(session) will be called at atexit_header()
578 */
579 atexit(atexit_header);
684 580
685 if (pipe_output) { 581 if (pipe_output) {
686 err = perf_header__write_pipe(output); 582 err = perf_header__write_pipe(output);
687 if (err < 0) 583 if (err < 0)
688 return err; 584 return err;
689 } else if (file_new) { 585 } else if (file_new) {
690 err = perf_header__write(&session->header, output, false); 586 err = perf_session__write_header(session, evsel_list,
587 output, false);
691 if (err < 0) 588 if (err < 0)
692 return err; 589 return err;
693 } 590 }
694 591
695 post_processing_offset = lseek(output, 0, SEEK_CUR); 592 post_processing_offset = lseek(output, 0, SEEK_CUR);
696 593
697 perf_session__set_sample_id_all(session, sample_id_all_avail);
698
699 if (pipe_output) { 594 if (pipe_output) {
700 err = event__synthesize_attrs(&session->header, 595 err = perf_session__synthesize_attrs(session,
701 process_synthesized_event, 596 process_synthesized_event);
702 session);
703 if (err < 0) { 597 if (err < 0) {
704 pr_err("Couldn't synthesize attrs.\n"); 598 pr_err("Couldn't synthesize attrs.\n");
705 return err; 599 return err;
706 } 600 }
707 601
708 err = event__synthesize_event_types(process_synthesized_event, 602 err = perf_event__synthesize_event_types(process_synthesized_event,
709 session); 603 session);
710 if (err < 0) { 604 if (err < 0) {
711 pr_err("Couldn't synthesize event_types.\n"); 605 pr_err("Couldn't synthesize event_types.\n");
712 return err; 606 return err;
713 } 607 }
714 608
715 if (have_tracepoints(&evsel_list)) { 609 if (have_tracepoints(&evsel_list->entries)) {
716 /* 610 /*
717 * FIXME err <= 0 here actually means that 611 * FIXME err <= 0 here actually means that
718 * there were no tracepoints so its not really 612 * there were no tracepoints so its not really
@@ -721,9 +615,9 @@ static int __cmd_record(int argc, const char **argv)
721 * return this more properly and also 615 * return this more properly and also
722 * propagate errors that now are calling die() 616 * propagate errors that now are calling die()
723 */ 617 */
724 err = event__synthesize_tracing_data(output, &evsel_list, 618 err = perf_event__synthesize_tracing_data(output, evsel_list,
725 process_synthesized_event, 619 process_synthesized_event,
726 session); 620 session);
727 if (err <= 0) { 621 if (err <= 0) {
728 pr_err("Couldn't record tracing data.\n"); 622 pr_err("Couldn't record tracing data.\n");
729 return err; 623 return err;
@@ -738,31 +632,34 @@ static int __cmd_record(int argc, const char **argv)
738 return -1; 632 return -1;
739 } 633 }
740 634
741 err = event__synthesize_kernel_mmap(process_synthesized_event, 635 err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
742 session, machine, "_text"); 636 session, machine, "_text");
743 if (err < 0) 637 if (err < 0)
744 err = event__synthesize_kernel_mmap(process_synthesized_event, 638 err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
745 session, machine, "_stext"); 639 session, machine, "_stext");
746 if (err < 0) 640 if (err < 0)
747 pr_err("Couldn't record kernel reference relocation symbol\n" 641 pr_err("Couldn't record kernel reference relocation symbol\n"
748 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" 642 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
749 "Check /proc/kallsyms permission or run as root.\n"); 643 "Check /proc/kallsyms permission or run as root.\n");
750 644
751 err = event__synthesize_modules(process_synthesized_event, 645 err = perf_event__synthesize_modules(process_synthesized_event,
752 session, machine); 646 session, machine);
753 if (err < 0) 647 if (err < 0)
754 pr_err("Couldn't record kernel module information.\n" 648 pr_err("Couldn't record kernel module information.\n"
755 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" 649 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
756 "Check /proc/modules permission or run as root.\n"); 650 "Check /proc/modules permission or run as root.\n");
757 651
758 if (perf_guest) 652 if (perf_guest)
759 perf_session__process_machines(session, event__synthesize_guest_os); 653 perf_session__process_machines(session,
654 perf_event__synthesize_guest_os);
760 655
761 if (!system_wide) 656 if (!system_wide)
762 event__synthesize_thread_map(threads, process_synthesized_event, 657 perf_event__synthesize_thread_map(evsel_list->threads,
763 session); 658 process_synthesized_event,
659 session);
764 else 660 else
765 event__synthesize_threads(process_synthesized_event, session); 661 perf_event__synthesize_threads(process_synthesized_event,
662 session);
766 663
767 if (realtime_prio) { 664 if (realtime_prio) {
768 struct sched_param param; 665 struct sched_param param;
@@ -782,30 +679,18 @@ static int __cmd_record(int argc, const char **argv)
782 679
783 for (;;) { 680 for (;;) {
784 int hits = samples; 681 int hits = samples;
785 int thread;
786 682
787 mmap_read_all(); 683 mmap_read_all();
788 684
789 if (hits == samples) { 685 if (hits == samples) {
790 if (done) 686 if (done)
791 break; 687 break;
792 err = poll(event_array, nr_poll, -1); 688 err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
793 waking++; 689 waking++;
794 } 690 }
795 691
796 if (done) { 692 if (done)
797 for (i = 0; i < nr_cpu; i++) { 693 perf_evlist__disable(evsel_list);
798 struct perf_evsel *pos;
799
800 list_for_each_entry(pos, &evsel_list, node) {
801 for (thread = 0;
802 thread < threads->nr;
803 thread++)
804 ioctl(FD(pos, i, thread),
805 PERF_EVENT_IOC_DISABLE);
806 }
807 }
808 }
809 } 694 }
810 695
811 if (quiet || signr == SIGUSR1) 696 if (quiet || signr == SIGUSR1)
@@ -838,10 +723,10 @@ static const char * const record_usage[] = {
838static bool force, append_file; 723static bool force, append_file;
839 724
840const struct option record_options[] = { 725const struct option record_options[] = {
841 OPT_CALLBACK('e', "event", NULL, "event", 726 OPT_CALLBACK('e', "event", &evsel_list, "event",
842 "event selector. use 'perf list' to list available events", 727 "event selector. use 'perf list' to list available events",
843 parse_events), 728 parse_events_option),
844 OPT_CALLBACK(0, "filter", NULL, "filter", 729 OPT_CALLBACK(0, "filter", &evsel_list, "filter",
845 "event filter", parse_filter), 730 "event filter", parse_filter),
846 OPT_INTEGER('p', "pid", &target_pid, 731 OPT_INTEGER('p', "pid", &target_pid,
847 "record events on existing process id"), 732 "record events on existing process id"),
@@ -884,6 +769,9 @@ const struct option record_options[] = {
884 "do not update the buildid cache"), 769 "do not update the buildid cache"),
885 OPT_BOOLEAN('B', "no-buildid", &no_buildid, 770 OPT_BOOLEAN('B', "no-buildid", &no_buildid,
886 "do not collect buildids in perf.data"), 771 "do not collect buildids in perf.data"),
772 OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
773 "monitor event in cgroup name only",
774 parse_cgroups),
887 OPT_END() 775 OPT_END()
888}; 776};
889 777
@@ -892,6 +780,10 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
892 int err = -ENOMEM; 780 int err = -ENOMEM;
893 struct perf_evsel *pos; 781 struct perf_evsel *pos;
894 782
783 evsel_list = perf_evlist__new(NULL, NULL);
784 if (evsel_list == NULL)
785 return -ENOMEM;
786
895 argc = parse_options(argc, argv, record_options, record_usage, 787 argc = parse_options(argc, argv, record_options, record_usage,
896 PARSE_OPT_STOP_AT_NON_OPTION); 788 PARSE_OPT_STOP_AT_NON_OPTION);
897 if (!argc && target_pid == -1 && target_tid == -1 && 789 if (!argc && target_pid == -1 && target_tid == -1 &&
@@ -908,12 +800,29 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
908 write_mode = WRITE_FORCE; 800 write_mode = WRITE_FORCE;
909 } 801 }
910 802
803 if (nr_cgroups && !system_wide) {
804 fprintf(stderr, "cgroup monitoring only available in"
805 " system-wide mode\n");
806 usage_with_options(record_usage, record_options);
807 }
808
911 symbol__init(); 809 symbol__init();
912 810
811 if (symbol_conf.kptr_restrict)
812 pr_warning(
813"WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
814"check /proc/sys/kernel/kptr_restrict.\n\n"
815"Samples in kernel functions may not be resolved if a suitable vmlinux\n"
816"file is not found in the buildid cache or in the vmlinux path.\n\n"
817"Samples in kernel modules won't be resolved at all.\n\n"
818"If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
819"even with a suitable vmlinux or kallsyms file.\n\n");
820
913 if (no_buildid_cache || no_buildid) 821 if (no_buildid_cache || no_buildid)
914 disable_buildid_cache(); 822 disable_buildid_cache();
915 823
916 if (list_empty(&evsel_list) && perf_evsel_list__create_default() < 0) { 824 if (evsel_list->nr_entries == 0 &&
825 perf_evlist__add_default(evsel_list) < 0) {
917 pr_err("Not enough memory for event selector list\n"); 826 pr_err("Not enough memory for event selector list\n");
918 goto out_symbol_exit; 827 goto out_symbol_exit;
919 } 828 }
@@ -921,27 +830,19 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
921 if (target_pid != -1) 830 if (target_pid != -1)
922 target_tid = target_pid; 831 target_tid = target_pid;
923 832
924 threads = thread_map__new(target_pid, target_tid); 833 if (perf_evlist__create_maps(evsel_list, target_pid,
925 if (threads == NULL) { 834 target_tid, cpu_list) < 0)
926 pr_err("Problems finding threads of monitor\n");
927 usage_with_options(record_usage, record_options); 835 usage_with_options(record_usage, record_options);
928 }
929
930 cpus = cpu_map__new(cpu_list);
931 if (cpus == NULL) {
932 perror("failed to parse CPUs map");
933 return -1;
934 }
935 836
936 list_for_each_entry(pos, &evsel_list, node) { 837 list_for_each_entry(pos, &evsel_list->entries, node) {
937 if (perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0) 838 if (perf_evsel__alloc_fd(pos, evsel_list->cpus->nr,
839 evsel_list->threads->nr) < 0)
938 goto out_free_fd; 840 goto out_free_fd;
939 if (perf_header__push_event(pos->attr.config, event_name(pos))) 841 if (perf_header__push_event(pos->attr.config, event_name(pos)))
940 goto out_free_fd; 842 goto out_free_fd;
941 } 843 }
942 event_array = malloc((sizeof(struct pollfd) * MAX_NR_CPUS * 844
943 MAX_COUNTERS * threads->nr)); 845 if (perf_evlist__alloc_pollfd(evsel_list) < 0)
944 if (!event_array)
945 goto out_free_fd; 846 goto out_free_fd;
946 847
947 if (user_interval != ULLONG_MAX) 848 if (user_interval != ULLONG_MAX)
@@ -959,16 +860,12 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
959 } else { 860 } else {
960 fprintf(stderr, "frequency and count are zero, aborting\n"); 861 fprintf(stderr, "frequency and count are zero, aborting\n");
961 err = -EINVAL; 862 err = -EINVAL;
962 goto out_free_event_array; 863 goto out_free_fd;
963 } 864 }
964 865
965 err = __cmd_record(argc, argv); 866 err = __cmd_record(argc, argv);
966
967out_free_event_array:
968 free(event_array);
969out_free_fd: 867out_free_fd:
970 thread_map__delete(threads); 868 perf_evlist__delete_maps(evsel_list);
971 threads = NULL;
972out_symbol_exit: 869out_symbol_exit:
973 symbol__exit(); 870 symbol__exit();
974 return err; 871 return err;
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index c27e31f289e6..d7ff277bdb78 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
@@ -30,6 +33,8 @@
30#include "util/sort.h" 33#include "util/sort.h"
31#include "util/hist.h" 34#include "util/hist.h"
32 35
36#include <linux/bitmap.h>
37
33static char const *input_name = "perf.data"; 38static char const *input_name = "perf.data";
34 39
35static bool force, use_tui, use_stdio; 40static bool force, use_tui, use_stdio;
@@ -42,121 +47,73 @@ static struct perf_read_values show_threads_values;
42static const char default_pretty_printing_style[] = "normal"; 47static const char default_pretty_printing_style[] = "normal";
43static const char *pretty_printing_style = default_pretty_printing_style; 48static const char *pretty_printing_style = default_pretty_printing_style;
44 49
45static char callchain_default_opt[] = "fractal,0.5"; 50static char callchain_default_opt[] = "fractal,0.5,callee";
46 51static bool inverted_callchain;
47static struct hists *perf_session__hists_findnew(struct perf_session *self, 52static symbol_filter_t annotate_init;
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 53
54static const char *cpu_list;
55static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
61 56
62 if (config > iter->config) 57static int perf_session__add_hist_entry(struct perf_session *session,
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, 58 struct addr_location *al,
82 struct sample_data *data) 59 struct perf_sample *sample,
60 struct perf_evsel *evsel)
83{ 61{
84 struct map_symbol *syms = NULL;
85 struct symbol *parent = NULL; 62 struct symbol *parent = NULL;
86 int err = -ENOMEM; 63 int err = 0;
87 struct hist_entry *he; 64 struct hist_entry *he;
88 struct hists *hists; 65
89 struct perf_event_attr *attr; 66 if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) {
90 67 err = perf_session__resolve_callchain(session, al->thread,
91 if ((sort__has_parent || symbol_conf.use_callchain) && data->callchain) { 68 sample->callchain, &parent);
92 syms = perf_session__resolve_callchain(self, al->thread, 69 if (err)
93 data->callchain, &parent); 70 return err;
94 if (syms == NULL)
95 return -ENOMEM;
96 } 71 }
97 72
98 attr = perf_header__find_attr(data->id, &self->header); 73 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) 74 if (he == NULL)
107 goto out_free_syms; 75 return -ENOMEM;
108 err = 0; 76
109 if (symbol_conf.use_callchain) { 77 if (symbol_conf.use_callchain) {
110 err = callchain_append(he->callchain, data->callchain, syms, 78 err = callchain_append(he->callchain, &session->callchain_cursor,
111 data->period); 79 sample->period);
112 if (err) 80 if (err)
113 goto out_free_syms; 81 return err;
114 } 82 }
115 /* 83 /*
116 * Only in the newt browser we are doing integrated annotation, 84 * Only in the newt browser we are doing integrated annotation,
117 * so we don't allocated the extra space needed because the stdio 85 * so we don't allocated the extra space needed because the stdio
118 * code will not use it. 86 * code will not use it.
119 */ 87 */
120 if (use_browser > 0) 88 if (al->sym != NULL && use_browser > 0) {
121 err = hist_entry__inc_addr_samples(he, al->addr); 89 struct annotation *notes = symbol__annotation(he->ms.sym);
122out_free_syms:
123 free(syms);
124 return err;
125}
126 90
127static int add_event_total(struct perf_session *session, 91 assert(evsel != NULL);
128 struct sample_data *data,
129 struct perf_event_attr *attr)
130{
131 struct hists *hists;
132 92
133 if (attr) 93 err = -ENOMEM;
134 hists = perf_session__hists_findnew(session, data->id, 94 if (notes->src == NULL &&
135 attr->type, attr->config); 95 symbol__alloc_hist(he->ms.sym, session->evlist->nr_entries) < 0)
136 else 96 goto out;
137 hists = perf_session__hists_findnew(session, data->id, 0, 0);
138 97
139 if (!hists) 98 err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
140 return -ENOMEM; 99 }
141 100
142 hists->stats.total_period += data->period; 101 evsel->hists.stats.total_period += sample->period;
143 /* 102 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
144 * FIXME: add_event_total should be moved from here to 103out:
145 * perf_session__process_event so that the proper hist is passed to 104 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} 105}
152 106
153static int process_sample_event(event_t *event, struct sample_data *sample, 107
108static int process_sample_event(union perf_event *event,
109 struct perf_sample *sample,
110 struct perf_evsel *evsel,
154 struct perf_session *session) 111 struct perf_session *session)
155{ 112{
156 struct addr_location al; 113 struct addr_location al;
157 struct perf_event_attr *attr;
158 114
159 if (event__preprocess_sample(event, session, &al, sample, NULL) < 0) { 115 if (perf_event__preprocess_sample(event, session, &al, sample,
116 annotate_init) < 0) {
160 fprintf(stderr, "problem processing %d event, skipping it.\n", 117 fprintf(stderr, "problem processing %d event, skipping it.\n",
161 event->header.type); 118 event->header.type);
162 return -1; 119 return -1;
@@ -165,31 +122,28 @@ static int process_sample_event(event_t *event, struct sample_data *sample,
165 if (al.filtered || (hide_unresolved && al.sym == NULL)) 122 if (al.filtered || (hide_unresolved && al.sym == NULL))
166 return 0; 123 return 0;
167 124
168 if (perf_session__add_hist_entry(session, &al, sample)) { 125 if (cpu_list && !test_bit(sample->cpu, cpu_bitmap))
169 pr_debug("problem incrementing symbol period, skipping event\n"); 126 return 0;
170 return -1;
171 }
172 127
173 attr = perf_header__find_attr(sample->id, &session->header); 128 if (al.map != NULL)
129 al.map->dso->hit = 1;
174 130
175 if (add_event_total(session, sample, attr)) { 131 if (perf_session__add_hist_entry(session, &al, sample, evsel)) {
176 pr_debug("problem adding event period\n"); 132 pr_debug("problem incrementing symbol period, skipping event\n");
177 return -1; 133 return -1;
178 } 134 }
179 135
180 return 0; 136 return 0;
181} 137}
182 138
183static int process_read_event(event_t *event, struct sample_data *sample __used, 139static int process_read_event(union perf_event *event,
184 struct perf_session *session __used) 140 struct perf_sample *sample __used,
141 struct perf_session *session)
185{ 142{
186 struct perf_event_attr *attr; 143 struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist,
187 144 event->read.id);
188 attr = perf_header__find_attr(event->read.id, &session->header);
189
190 if (show_threads) { 145 if (show_threads) {
191 const char *name = attr ? __event_name(attr->type, attr->config) 146 const char *name = evsel ? event_name(evsel) : "unknown";
192 : "unknown";
193 perf_read_values_add_value(&show_threads_values, 147 perf_read_values_add_value(&show_threads_values,
194 event->read.pid, event->read.tid, 148 event->read.pid, event->read.tid,
195 event->read.id, 149 event->read.id,
@@ -198,7 +152,7 @@ static int process_read_event(event_t *event, struct sample_data *sample __used,
198 } 152 }
199 153
200 dump_printf(": %d %d %s %" PRIu64 "\n", event->read.pid, event->read.tid, 154 dump_printf(": %d %d %s %" PRIu64 "\n", event->read.pid, event->read.tid,
201 attr ? __event_name(attr->type, attr->config) : "FAIL", 155 evsel ? event_name(evsel) : "FAIL",
202 event->read.value); 156 event->read.value);
203 157
204 return 0; 158 return 0;
@@ -208,23 +162,22 @@ static int perf_session__setup_sample_type(struct perf_session *self)
208{ 162{
209 if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) { 163 if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) {
210 if (sort__has_parent) { 164 if (sort__has_parent) {
211 fprintf(stderr, "selected --sort parent, but no" 165 ui__warning("Selected --sort parent, but no "
212 " callchain data. Did you call" 166 "callchain data. Did you call "
213 " perf record without -g?\n"); 167 "'perf record' without -g?\n");
214 return -EINVAL; 168 return -EINVAL;
215 } 169 }
216 if (symbol_conf.use_callchain) { 170 if (symbol_conf.use_callchain) {
217 fprintf(stderr, "selected -g but no callchain data." 171 ui__warning("Selected -g but no callchain data. Did "
218 " Did you call perf record without" 172 "you call 'perf record' without -g?\n");
219 " -g?\n");
220 return -1; 173 return -1;
221 } 174 }
222 } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE && 175 } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE &&
223 !symbol_conf.use_callchain) { 176 !symbol_conf.use_callchain) {
224 symbol_conf.use_callchain = true; 177 symbol_conf.use_callchain = true;
225 if (register_callchain_param(&callchain_param) < 0) { 178 if (callchain_register_param(&callchain_param) < 0) {
226 fprintf(stderr, "Can't register callchain" 179 ui__warning("Can't register callchain "
227 " params\n"); 180 "params.\n");
228 return -EINVAL; 181 return -EINVAL;
229 } 182 }
230 } 183 }
@@ -233,17 +186,17 @@ static int perf_session__setup_sample_type(struct perf_session *self)
233} 186}
234 187
235static struct perf_event_ops event_ops = { 188static struct perf_event_ops event_ops = {
236 .sample = process_sample_event, 189 .sample = process_sample_event,
237 .mmap = event__process_mmap, 190 .mmap = perf_event__process_mmap,
238 .comm = event__process_comm, 191 .comm = perf_event__process_comm,
239 .exit = event__process_task, 192 .exit = perf_event__process_task,
240 .fork = event__process_task, 193 .fork = perf_event__process_task,
241 .lost = event__process_lost, 194 .lost = perf_event__process_lost,
242 .read = process_read_event, 195 .read = process_read_event,
243 .attr = event__process_attr, 196 .attr = perf_event__process_attr,
244 .event_type = event__process_event_type, 197 .event_type = perf_event__process_event_type,
245 .tracing_data = event__process_tracing_data, 198 .tracing_data = perf_event__process_tracing_data,
246 .build_id = event__process_build_id, 199 .build_id = perf_event__process_build_id,
247 .ordered_samples = true, 200 .ordered_samples = true,
248 .ordering_requires_timestamps = true, 201 .ordering_requires_timestamps = true,
249}; 202};
@@ -269,21 +222,21 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self,
269 return ret + fprintf(fp, "\n#\n"); 222 return ret + fprintf(fp, "\n#\n");
270} 223}
271 224
272static int hists__tty_browse_tree(struct rb_root *tree, const char *help) 225static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
226 const char *help)
273{ 227{
274 struct rb_node *next = rb_first(tree); 228 struct perf_evsel *pos;
275 229
276 while (next) { 230 list_for_each_entry(pos, &evlist->entries, node) {
277 struct hists *hists = rb_entry(next, struct hists, rb_node); 231 struct hists *hists = &pos->hists;
278 const char *evname = NULL; 232 const char *evname = NULL;
279 233
280 if (rb_first(&hists->entries) != rb_last(&hists->entries)) 234 if (rb_first(&hists->entries) != rb_last(&hists->entries))
281 evname = __event_name(hists->type, hists->config); 235 evname = event_name(pos);
282 236
283 hists__fprintf_nr_sample_events(hists, evname, stdout); 237 hists__fprintf_nr_sample_events(hists, evname, stdout);
284 hists__fprintf(hists, NULL, false, stdout); 238 hists__fprintf(hists, NULL, false, stdout);
285 fprintf(stdout, "\n\n"); 239 fprintf(stdout, "\n\n");
286 next = rb_next(&hists->rb_node);
287 } 240 }
288 241
289 if (sort_order == default_sort_order && 242 if (sort_order == default_sort_order &&
@@ -304,8 +257,11 @@ static int hists__tty_browse_tree(struct rb_root *tree, const char *help)
304static int __cmd_report(void) 257static int __cmd_report(void)
305{ 258{
306 int ret = -EINVAL; 259 int ret = -EINVAL;
260 u64 nr_samples;
307 struct perf_session *session; 261 struct perf_session *session;
308 struct rb_node *next; 262 struct perf_evsel *pos;
263 struct map *kernel_map;
264 struct kmap *kernel_kmap;
309 const char *help = "For a higher level overview, try: perf report --sort comm,dso"; 265 const char *help = "For a higher level overview, try: perf report --sort comm,dso";
310 266
311 signal(SIGINT, sig_handler); 267 signal(SIGINT, sig_handler);
@@ -314,6 +270,12 @@ static int __cmd_report(void)
314 if (session == NULL) 270 if (session == NULL)
315 return -ENOMEM; 271 return -ENOMEM;
316 272
273 if (cpu_list) {
274 ret = perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap);
275 if (ret)
276 goto out_delete;
277 }
278
317 if (show_threads) 279 if (show_threads)
318 perf_read_values_init(&show_threads_values); 280 perf_read_values_init(&show_threads_values);
319 281
@@ -325,6 +287,24 @@ static int __cmd_report(void)
325 if (ret) 287 if (ret)
326 goto out_delete; 288 goto out_delete;
327 289
290 kernel_map = session->host_machine.vmlinux_maps[MAP__FUNCTION];
291 kernel_kmap = map__kmap(kernel_map);
292 if (kernel_map == NULL ||
293 (kernel_map->dso->hit &&
294 (kernel_kmap->ref_reloc_sym == NULL ||
295 kernel_kmap->ref_reloc_sym->addr == 0))) {
296 const struct dso *kdso = kernel_map->dso;
297
298 ui__warning(
299"Kernel address maps (/proc/{kallsyms,modules}) were restricted.\n\n"
300"Check /proc/sys/kernel/kptr_restrict before running 'perf record'.\n\n%s\n\n"
301"Samples in kernel modules can't be resolved as well.\n\n",
302 RB_EMPTY_ROOT(&kdso->symbols[MAP__FUNCTION]) ?
303"As no suitable kallsyms nor vmlinux was found, kernel samples\n"
304"can't be resolved." :
305"If some relocation was applied (e.g. kexec) symbols may be misresolved.");
306 }
307
328 if (dump_trace) { 308 if (dump_trace) {
329 perf_session__fprintf_nr_events(session, stdout); 309 perf_session__fprintf_nr_events(session, stdout);
330 goto out_delete; 310 goto out_delete;
@@ -336,20 +316,24 @@ static int __cmd_report(void)
336 if (verbose > 2) 316 if (verbose > 2)
337 perf_session__fprintf_dsos(session, stdout); 317 perf_session__fprintf_dsos(session, stdout);
338 318
339 next = rb_first(&session->hists_tree); 319 nr_samples = 0;
340 while (next) { 320 list_for_each_entry(pos, &session->evlist->entries, node) {
341 struct hists *hists; 321 struct hists *hists = &pos->hists;
342 322
343 hists = rb_entry(next, struct hists, rb_node);
344 hists__collapse_resort(hists); 323 hists__collapse_resort(hists);
345 hists__output_resort(hists); 324 hists__output_resort(hists);
346 next = rb_next(&hists->rb_node); 325 nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE];
326 }
327
328 if (nr_samples == 0) {
329 ui__warning("The %s file has no samples!\n", input_name);
330 goto out_delete;
347 } 331 }
348 332
349 if (use_browser > 0) 333 if (use_browser > 0)
350 hists__tui_browse_tree(&session->hists_tree, help); 334 perf_evlist__tui_browse_hists(session->evlist, help);
351 else 335 else
352 hists__tty_browse_tree(&session->hists_tree, help); 336 perf_evlist__tty_browse_hists(session->evlist, help);
353 337
354out_delete: 338out_delete:
355 /* 339 /*
@@ -416,15 +400,31 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
416 if (!tok) 400 if (!tok)
417 goto setup; 401 goto setup;
418 402
419 tok2 = strtok(NULL, ",");
420 callchain_param.min_percent = strtod(tok, &endptr); 403 callchain_param.min_percent = strtod(tok, &endptr);
421 if (tok == endptr) 404 if (tok == endptr)
422 return -1; 405 return -1;
423 406
424 if (tok2) 407 /* get the print limit */
408 tok2 = strtok(NULL, ",");
409 if (!tok2)
410 goto setup;
411
412 if (tok2[0] != 'c') {
425 callchain_param.print_limit = strtod(tok2, &endptr); 413 callchain_param.print_limit = strtod(tok2, &endptr);
414 tok2 = strtok(NULL, ",");
415 if (!tok2)
416 goto setup;
417 }
418
419 /* get the call chain order */
420 if (!strcmp(tok2, "caller"))
421 callchain_param.order = ORDER_CALLER;
422 else if (!strcmp(tok2, "callee"))
423 callchain_param.order = ORDER_CALLEE;
424 else
425 return -1;
426setup: 426setup:
427 if (register_callchain_param(&callchain_param) < 0) { 427 if (callchain_register_param(&callchain_param) < 0) {
428 fprintf(stderr, "Can't register callchain params\n"); 428 fprintf(stderr, "Can't register callchain params\n");
429 return -1; 429 return -1;
430 } 430 }
@@ -466,9 +466,10 @@ static const struct option options[] = {
466 "regex filter to identify parent, see: '--sort parent'"), 466 "regex filter to identify parent, see: '--sort parent'"),
467 OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other, 467 OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other,
468 "Only display entries with parent-match"), 468 "Only display entries with parent-match"),
469 OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent", 469 OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent, call_order",
470 "Display callchains using output_type (graph, flat, fractal, or none) and min percent threshold. " 470 "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold and callchain order. "
471 "Default: fractal,0.5", &parse_callchain_opt, callchain_default_opt), 471 "Default: fractal,0.5,callee", &parse_callchain_opt, callchain_default_opt),
472 OPT_BOOLEAN('G', "inverted", &inverted_callchain, "alias for inverted call graph"),
472 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", 473 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
473 "only consider symbols in these dsos"), 474 "only consider symbols in these dsos"),
474 OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]", 475 OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
@@ -485,6 +486,7 @@ static const struct option options[] = {
485 "Only display entries resolved to a symbol"), 486 "Only display entries resolved to a symbol"),
486 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", 487 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
487 "Look for files with symbols relative to this directory"), 488 "Look for files with symbols relative to this directory"),
489 OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"),
488 OPT_END() 490 OPT_END()
489}; 491};
490 492
@@ -497,8 +499,11 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
497 else if (use_tui) 499 else if (use_tui)
498 use_browser = 1; 500 use_browser = 1;
499 501
502 if (inverted_callchain)
503 callchain_param.order = ORDER_CALLER;
504
500 if (strcmp(input_name, "-") != 0) 505 if (strcmp(input_name, "-") != 0)
501 setup_browser(); 506 setup_browser(true);
502 else 507 else
503 use_browser = 0; 508 use_browser = 0;
504 /* 509 /*
@@ -507,7 +512,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
507 * implementation. 512 * implementation.
508 */ 513 */
509 if (use_browser > 0) { 514 if (use_browser > 0) {
510 symbol_conf.priv_size = sizeof(struct sym_priv); 515 symbol_conf.priv_size = sizeof(struct annotation);
516 annotate_init = symbol__annotate_init;
511 /* 517 /*
512 * For searching by name on the "Browse map details". 518 * For searching by name on the "Browse map details".
513 * providing it only in verbose mode not to bloat too 519 * providing it only in verbose mode not to bloat too
@@ -533,7 +539,14 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
533 if (parent_pattern != default_parent_pattern) { 539 if (parent_pattern != default_parent_pattern) {
534 if (sort_dimension__add("parent") < 0) 540 if (sort_dimension__add("parent") < 0)
535 return -1; 541 return -1;
536 sort_parent.elide = 1; 542
543 /*
544 * Only show the parent fields if we explicitly
545 * sort that way. If we only use parent machinery
546 * for filtering, we don't want it.
547 */
548 if (!strstr(sort_order, "parent"))
549 sort_parent.elide = 1;
537 } else 550 } else
538 symbol_conf.exclude_other = false; 551 symbol_conf.exclude_other = false;
539 552
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 29acb894e035..5177964943e7 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -369,11 +369,6 @@ static void
369process_sched_event(struct task_desc *this_task __used, struct sched_atom *atom) 369process_sched_event(struct task_desc *this_task __used, struct sched_atom *atom)
370{ 370{
371 int ret = 0; 371 int ret = 0;
372 u64 now;
373 long long delta;
374
375 now = get_nsecs();
376 delta = start_time + atom->timestamp - now;
377 372
378 switch (atom->type) { 373 switch (atom->type) {
379 case SCHED_EVENT_RUN: 374 case SCHED_EVENT_RUN:
@@ -562,7 +557,7 @@ static void wait_for_tasks(void)
562 557
563static void run_one_test(void) 558static void run_one_test(void)
564{ 559{
565 u64 T0, T1, delta, avg_delta, fluct, std_dev; 560 u64 T0, T1, delta, avg_delta, fluct;
566 561
567 T0 = get_nsecs(); 562 T0 = get_nsecs();
568 wait_for_tasks(); 563 wait_for_tasks();
@@ -578,7 +573,6 @@ static void run_one_test(void)
578 else 573 else
579 fluct = delta - avg_delta; 574 fluct = delta - avg_delta;
580 sum_fluct += fluct; 575 sum_fluct += fluct;
581 std_dev = sum_fluct / nr_runs / sqrt(nr_runs);
582 if (!run_avg) 576 if (!run_avg)
583 run_avg = delta; 577 run_avg = delta;
584 run_avg = (run_avg*9 + delta)/10; 578 run_avg = (run_avg*9 + delta)/10;
@@ -799,7 +793,7 @@ replay_switch_event(struct trace_switch_event *switch_event,
799 u64 timestamp, 793 u64 timestamp,
800 struct thread *thread __used) 794 struct thread *thread __used)
801{ 795{
802 struct task_desc *prev, *next; 796 struct task_desc *prev, __used *next;
803 u64 timestamp0; 797 u64 timestamp0;
804 s64 delta; 798 s64 delta;
805 799
@@ -1404,7 +1398,7 @@ map_switch_event(struct trace_switch_event *switch_event,
1404 u64 timestamp, 1398 u64 timestamp,
1405 struct thread *thread __used) 1399 struct thread *thread __used)
1406{ 1400{
1407 struct thread *sched_out, *sched_in; 1401 struct thread *sched_out __used, *sched_in;
1408 int new_shortname; 1402 int new_shortname;
1409 u64 timestamp0; 1403 u64 timestamp0;
1410 s64 delta; 1404 s64 delta;
@@ -1580,9 +1574,9 @@ process_sched_migrate_task_event(void *data, struct perf_session *session,
1580 event, cpu, timestamp, thread); 1574 event, cpu, timestamp, thread);
1581} 1575}
1582 1576
1583static void 1577static void process_raw_event(union perf_event *raw_event __used,
1584process_raw_event(event_t *raw_event __used, struct perf_session *session, 1578 struct perf_session *session, void *data, int cpu,
1585 void *data, int cpu, u64 timestamp, struct thread *thread) 1579 u64 timestamp, struct thread *thread)
1586{ 1580{
1587 struct event *event; 1581 struct event *event;
1588 int type; 1582 int type;
@@ -1607,7 +1601,9 @@ process_raw_event(event_t *raw_event __used, struct perf_session *session,
1607 process_sched_migrate_task_event(data, session, event, cpu, timestamp, thread); 1601 process_sched_migrate_task_event(data, session, event, cpu, timestamp, thread);
1608} 1602}
1609 1603
1610static int process_sample_event(event_t *event, struct sample_data *sample, 1604static int process_sample_event(union perf_event *event,
1605 struct perf_sample *sample,
1606 struct perf_evsel *evsel __used,
1611 struct perf_session *session) 1607 struct perf_session *session)
1612{ 1608{
1613 struct thread *thread; 1609 struct thread *thread;
@@ -1635,29 +1631,35 @@ 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
1644static int read_events(void) 1640static void read_events(bool destroy, struct perf_session **psession)
1645{ 1641{
1646 int err = -EINVAL; 1642 int err = -EINVAL;
1647 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 1643 struct perf_session *session = perf_session__new(input_name, O_RDONLY,
1648 0, false, &event_ops); 1644 0, false, &event_ops);
1649 if (session == NULL) 1645 if (session == NULL)
1650 return -ENOMEM; 1646 die("No Memory");
1651 1647
1652 if (perf_session__has_traces(session, "record -R")) { 1648 if (perf_session__has_traces(session, "record -R")) {
1653 err = perf_session__process_events(session, &event_ops); 1649 err = perf_session__process_events(session, &event_ops);
1650 if (err)
1651 die("Failed to process events, error %d", err);
1652
1654 nr_events = session->hists.stats.nr_events[0]; 1653 nr_events = session->hists.stats.nr_events[0];
1655 nr_lost_events = session->hists.stats.total_lost; 1654 nr_lost_events = session->hists.stats.total_lost;
1656 nr_lost_chunks = session->hists.stats.nr_events[PERF_RECORD_LOST]; 1655 nr_lost_chunks = session->hists.stats.nr_events[PERF_RECORD_LOST];
1657 } 1656 }
1658 1657
1659 perf_session__delete(session); 1658 if (destroy)
1660 return err; 1659 perf_session__delete(session);
1660
1661 if (psession)
1662 *psession = session;
1661} 1663}
1662 1664
1663static void print_bad_events(void) 1665static void print_bad_events(void)
@@ -1693,9 +1695,10 @@ static void print_bad_events(void)
1693static void __cmd_lat(void) 1695static void __cmd_lat(void)
1694{ 1696{
1695 struct rb_node *next; 1697 struct rb_node *next;
1698 struct perf_session *session;
1696 1699
1697 setup_pager(); 1700 setup_pager();
1698 read_events(); 1701 read_events(false, &session);
1699 sort_lat(); 1702 sort_lat();
1700 1703
1701 printf("\n ---------------------------------------------------------------------------------------------------------------\n"); 1704 printf("\n ---------------------------------------------------------------------------------------------------------------\n");
@@ -1721,6 +1724,7 @@ static void __cmd_lat(void)
1721 print_bad_events(); 1724 print_bad_events();
1722 printf("\n"); 1725 printf("\n");
1723 1726
1727 perf_session__delete(session);
1724} 1728}
1725 1729
1726static struct trace_sched_handler map_ops = { 1730static struct trace_sched_handler map_ops = {
@@ -1735,7 +1739,7 @@ static void __cmd_map(void)
1735 max_cpu = sysconf(_SC_NPROCESSORS_CONF); 1739 max_cpu = sysconf(_SC_NPROCESSORS_CONF);
1736 1740
1737 setup_pager(); 1741 setup_pager();
1738 read_events(); 1742 read_events(true, NULL);
1739 print_bad_events(); 1743 print_bad_events();
1740} 1744}
1741 1745
@@ -1748,7 +1752,7 @@ static void __cmd_replay(void)
1748 1752
1749 test_calibrations(); 1753 test_calibrations();
1750 1754
1751 read_events(); 1755 read_events(true, NULL);
1752 1756
1753 printf("nr_run_events: %ld\n", nr_run_events); 1757 printf("nr_run_events: %ld\n", nr_run_events);
1754 printf("nr_sleep_events: %ld\n", nr_sleep_events); 1758 printf("nr_sleep_events: %ld\n", nr_sleep_events);
@@ -1773,7 +1777,7 @@ static void __cmd_replay(void)
1773 1777
1774 1778
1775static const char * const sched_usage[] = { 1779static const char * const sched_usage[] = {
1776 "perf sched [<options>] {record|latency|map|replay|trace}", 1780 "perf sched [<options>] {record|latency|map|replay|script}",
1777 NULL 1781 NULL
1778}; 1782};
1779 1783
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index b766c2a9ac97..09024ec2ab2e 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -10,8 +10,10 @@
10#include "util/symbol.h" 10#include "util/symbol.h"
11#include "util/thread.h" 11#include "util/thread.h"
12#include "util/trace-event.h" 12#include "util/trace-event.h"
13#include "util/parse-options.h"
14#include "util/util.h" 13#include "util/util.h"
14#include "util/evlist.h"
15#include "util/evsel.h"
16#include <linux/bitmap.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,374 @@ 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;
25static const char *cpu_list;
26static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
27
28enum perf_output_field {
29 PERF_OUTPUT_COMM = 1U << 0,
30 PERF_OUTPUT_TID = 1U << 1,
31 PERF_OUTPUT_PID = 1U << 2,
32 PERF_OUTPUT_TIME = 1U << 3,
33 PERF_OUTPUT_CPU = 1U << 4,
34 PERF_OUTPUT_EVNAME = 1U << 5,
35 PERF_OUTPUT_TRACE = 1U << 6,
36 PERF_OUTPUT_IP = 1U << 7,
37 PERF_OUTPUT_SYM = 1U << 8,
38 PERF_OUTPUT_DSO = 1U << 9,
39 PERF_OUTPUT_ADDR = 1U << 10,
40};
41
42struct output_option {
43 const char *str;
44 enum perf_output_field field;
45} all_output_options[] = {
46 {.str = "comm", .field = PERF_OUTPUT_COMM},
47 {.str = "tid", .field = PERF_OUTPUT_TID},
48 {.str = "pid", .field = PERF_OUTPUT_PID},
49 {.str = "time", .field = PERF_OUTPUT_TIME},
50 {.str = "cpu", .field = PERF_OUTPUT_CPU},
51 {.str = "event", .field = PERF_OUTPUT_EVNAME},
52 {.str = "trace", .field = PERF_OUTPUT_TRACE},
53 {.str = "ip", .field = PERF_OUTPUT_IP},
54 {.str = "sym", .field = PERF_OUTPUT_SYM},
55 {.str = "dso", .field = PERF_OUTPUT_DSO},
56 {.str = "addr", .field = PERF_OUTPUT_ADDR},
57};
58
59/* default set to maintain compatibility with current format */
60static struct {
61 bool user_set;
62 bool wildcard_set;
63 u64 fields;
64 u64 invalid_fields;
65} output[PERF_TYPE_MAX] = {
66
67 [PERF_TYPE_HARDWARE] = {
68 .user_set = false,
69
70 .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
71 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
72 PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
73 PERF_OUTPUT_SYM | PERF_OUTPUT_DSO,
74
75 .invalid_fields = PERF_OUTPUT_TRACE,
76 },
77
78 [PERF_TYPE_SOFTWARE] = {
79 .user_set = false,
80
81 .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
82 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
83 PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
84 PERF_OUTPUT_SYM | PERF_OUTPUT_DSO,
85
86 .invalid_fields = PERF_OUTPUT_TRACE,
87 },
88
89 [PERF_TYPE_TRACEPOINT] = {
90 .user_set = false,
91
92 .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
93 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
94 PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE,
95 },
96
97 [PERF_TYPE_RAW] = {
98 .user_set = false,
99
100 .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
101 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
102 PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
103 PERF_OUTPUT_SYM | PERF_OUTPUT_DSO,
104
105 .invalid_fields = PERF_OUTPUT_TRACE,
106 },
107};
108
109static bool output_set_by_user(void)
110{
111 int j;
112 for (j = 0; j < PERF_TYPE_MAX; ++j) {
113 if (output[j].user_set)
114 return true;
115 }
116 return false;
117}
118
119static const char *output_field2str(enum perf_output_field field)
120{
121 int i, imax = ARRAY_SIZE(all_output_options);
122 const char *str = "";
123
124 for (i = 0; i < imax; ++i) {
125 if (all_output_options[i].field == field) {
126 str = all_output_options[i].str;
127 break;
128 }
129 }
130 return str;
131}
132
133#define PRINT_FIELD(x) (output[attr->type].fields & PERF_OUTPUT_##x)
134
135static int perf_event_attr__check_stype(struct perf_event_attr *attr,
136 u64 sample_type, const char *sample_msg,
137 enum perf_output_field field)
138{
139 int type = attr->type;
140 const char *evname;
141
142 if (attr->sample_type & sample_type)
143 return 0;
144
145 if (output[type].user_set) {
146 evname = __event_name(attr->type, attr->config);
147 pr_err("Samples for '%s' event do not have %s attribute set. "
148 "Cannot print '%s' field.\n",
149 evname, sample_msg, output_field2str(field));
150 return -1;
151 }
152
153 /* user did not ask for it explicitly so remove from the default list */
154 output[type].fields &= ~field;
155 evname = __event_name(attr->type, attr->config);
156 pr_debug("Samples for '%s' event do not have %s attribute set. "
157 "Skipping '%s' field.\n",
158 evname, sample_msg, output_field2str(field));
159
160 return 0;
161}
162
163static int perf_evsel__check_attr(struct perf_evsel *evsel,
164 struct perf_session *session)
165{
166 struct perf_event_attr *attr = &evsel->attr;
167
168 if (PRINT_FIELD(TRACE) &&
169 !perf_session__has_traces(session, "record -R"))
170 return -EINVAL;
171
172 if (PRINT_FIELD(IP)) {
173 if (perf_event_attr__check_stype(attr, PERF_SAMPLE_IP, "IP",
174 PERF_OUTPUT_IP))
175 return -EINVAL;
176
177 if (!no_callchain &&
178 !(attr->sample_type & PERF_SAMPLE_CALLCHAIN))
179 symbol_conf.use_callchain = false;
180 }
181
182 if (PRINT_FIELD(ADDR) &&
183 perf_event_attr__check_stype(attr, PERF_SAMPLE_ADDR, "ADDR",
184 PERF_OUTPUT_ADDR))
185 return -EINVAL;
186
187 if (PRINT_FIELD(SYM) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) {
188 pr_err("Display of symbols requested but neither sample IP nor "
189 "sample address\nis selected. Hence, no addresses to convert "
190 "to symbols.\n");
191 return -EINVAL;
192 }
193 if (PRINT_FIELD(DSO) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) {
194 pr_err("Display of DSO requested but neither sample IP nor "
195 "sample address\nis selected. Hence, no addresses to convert "
196 "to DSO.\n");
197 return -EINVAL;
198 }
199
200 if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) &&
201 perf_event_attr__check_stype(attr, PERF_SAMPLE_TID, "TID",
202 PERF_OUTPUT_TID|PERF_OUTPUT_PID))
203 return -EINVAL;
204
205 if (PRINT_FIELD(TIME) &&
206 perf_event_attr__check_stype(attr, PERF_SAMPLE_TIME, "TIME",
207 PERF_OUTPUT_TIME))
208 return -EINVAL;
209
210 if (PRINT_FIELD(CPU) &&
211 perf_event_attr__check_stype(attr, PERF_SAMPLE_CPU, "CPU",
212 PERF_OUTPUT_CPU))
213 return -EINVAL;
214
215 return 0;
216}
217
218/*
219 * verify all user requested events exist and the samples
220 * have the expected data
221 */
222static int perf_session__check_output_opt(struct perf_session *session)
223{
224 int j;
225 struct perf_evsel *evsel;
226
227 for (j = 0; j < PERF_TYPE_MAX; ++j) {
228 evsel = perf_session__find_first_evtype(session, j);
229
230 /*
231 * even if fields is set to 0 (ie., show nothing) event must
232 * exist if user explicitly includes it on the command line
233 */
234 if (!evsel && output[j].user_set && !output[j].wildcard_set) {
235 pr_err("%s events do not exist. "
236 "Remove corresponding -f option to proceed.\n",
237 event_type(j));
238 return -1;
239 }
240
241 if (evsel && output[j].fields &&
242 perf_evsel__check_attr(evsel, session))
243 return -1;
244 }
245
246 return 0;
247}
248
249static void print_sample_start(struct perf_sample *sample,
250 struct thread *thread,
251 struct perf_event_attr *attr)
252{
253 int type;
254 struct event *event;
255 const char *evname = NULL;
256 unsigned long secs;
257 unsigned long usecs;
258 unsigned long long nsecs;
259
260 if (PRINT_FIELD(COMM)) {
261 if (latency_format)
262 printf("%8.8s ", thread->comm);
263 else if (PRINT_FIELD(IP) && symbol_conf.use_callchain)
264 printf("%s ", thread->comm);
265 else
266 printf("%16s ", thread->comm);
267 }
268
269 if (PRINT_FIELD(PID) && PRINT_FIELD(TID))
270 printf("%5d/%-5d ", sample->pid, sample->tid);
271 else if (PRINT_FIELD(PID))
272 printf("%5d ", sample->pid);
273 else if (PRINT_FIELD(TID))
274 printf("%5d ", sample->tid);
275
276 if (PRINT_FIELD(CPU)) {
277 if (latency_format)
278 printf("%3d ", sample->cpu);
279 else
280 printf("[%03d] ", sample->cpu);
281 }
282
283 if (PRINT_FIELD(TIME)) {
284 nsecs = sample->time;
285 secs = nsecs / NSECS_PER_SEC;
286 nsecs -= secs * NSECS_PER_SEC;
287 usecs = nsecs / NSECS_PER_USEC;
288 printf("%5lu.%06lu: ", secs, usecs);
289 }
290
291 if (PRINT_FIELD(EVNAME)) {
292 if (attr->type == PERF_TYPE_TRACEPOINT) {
293 type = trace_parse_common_type(sample->raw_data);
294 event = trace_find_event(type);
295 if (event)
296 evname = event->name;
297 } else
298 evname = __event_name(attr->type, attr->config);
299
300 printf("%s: ", evname ? evname : "(unknown)");
301 }
302}
303
304static bool sample_addr_correlates_sym(struct perf_event_attr *attr)
305{
306 if ((attr->type == PERF_TYPE_SOFTWARE) &&
307 ((attr->config == PERF_COUNT_SW_PAGE_FAULTS) ||
308 (attr->config == PERF_COUNT_SW_PAGE_FAULTS_MIN) ||
309 (attr->config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)))
310 return true;
311
312 return false;
313}
314
315static void print_sample_addr(union perf_event *event,
316 struct perf_sample *sample,
317 struct perf_session *session,
318 struct thread *thread,
319 struct perf_event_attr *attr)
320{
321 struct addr_location al;
322 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
323 const char *symname, *dsoname;
324
325 printf("%16" PRIx64, sample->addr);
326
327 if (!sample_addr_correlates_sym(attr))
328 return;
329
330 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION,
331 event->ip.pid, sample->addr, &al);
332 if (!al.map)
333 thread__find_addr_map(thread, session, cpumode, MAP__VARIABLE,
334 event->ip.pid, sample->addr, &al);
335
336 al.cpu = sample->cpu;
337 al.sym = NULL;
338
339 if (al.map)
340 al.sym = map__find_symbol(al.map, al.addr, NULL);
341
342 if (PRINT_FIELD(SYM)) {
343 if (al.sym && al.sym->name)
344 symname = al.sym->name;
345 else
346 symname = "";
347
348 printf(" %16s", symname);
349 }
350
351 if (PRINT_FIELD(DSO)) {
352 if (al.map && al.map->dso && al.map->dso->name)
353 dsoname = al.map->dso->name;
354 else
355 dsoname = "";
356
357 printf(" (%s)", dsoname);
358 }
359}
360
361static void process_event(union perf_event *event __unused,
362 struct perf_sample *sample,
363 struct perf_evsel *evsel,
364 struct perf_session *session,
365 struct thread *thread)
366{
367 struct perf_event_attr *attr = &evsel->attr;
368
369 if (output[attr->type].fields == 0)
370 return;
371
372 print_sample_start(sample, thread, attr);
373
374 if (PRINT_FIELD(TRACE))
375 print_trace_event(sample->cpu, sample->raw_data,
376 sample->raw_size);
377
378 if (PRINT_FIELD(ADDR))
379 print_sample_addr(event, sample, session, thread, attr);
380
381 if (PRINT_FIELD(IP)) {
382 if (!symbol_conf.use_callchain)
383 printf(" ");
384 else
385 printf("\n");
386 perf_session__print_ip(event, sample, session,
387 PRINT_FIELD(SYM), PRINT_FIELD(DSO));
388 }
389
390 printf("\n");
391}
22 392
23static int default_start_script(const char *script __unused, 393static int default_start_script(const char *script __unused,
24 int argc __unused, 394 int argc __unused,
@@ -40,7 +410,7 @@ static int default_generate_script(const char *outfile __unused)
40static struct scripting_ops default_scripting_ops = { 410static struct scripting_ops default_scripting_ops = {
41 .start_script = default_start_script, 411 .start_script = default_start_script,
42 .stop_script = default_stop_script, 412 .stop_script = default_stop_script,
43 .process_event = print_event, 413 .process_event = process_event,
44 .generate_script = default_generate_script, 414 .generate_script = default_generate_script,
45}; 415};
46 416
@@ -63,7 +433,9 @@ static int cleanup_scripting(void)
63 433
64static char const *input_name = "perf.data"; 434static char const *input_name = "perf.data";
65 435
66static int process_sample_event(event_t *event, struct sample_data *sample, 436static int process_sample_event(union perf_event *event,
437 struct perf_sample *sample,
438 struct perf_evsel *evsel,
67 struct perf_session *session) 439 struct perf_session *session)
68{ 440{
69 struct thread *thread = perf_session__findnew(session, event->ip.pid); 441 struct thread *thread = perf_session__findnew(session, event->ip.pid);
@@ -74,40 +446,38 @@ static int process_sample_event(event_t *event, struct sample_data *sample,
74 return -1; 446 return -1;
75 } 447 }
76 448
77 if (session->sample_type & PERF_SAMPLE_RAW) { 449 if (debug_mode) {
78 if (debug_mode) { 450 if (sample->time < last_timestamp) {
79 if (sample->time < last_timestamp) { 451 pr_err("Samples misordered, previous: %" PRIu64
80 pr_err("Samples misordered, previous: %" PRIu64 452 " this: %" PRIu64 "\n", last_timestamp,
81 " this: %" PRIu64 "\n", last_timestamp, 453 sample->time);
82 sample->time); 454 nr_unordered++;
83 nr_unordered++;
84 }
85 last_timestamp = sample->time;
86 return 0;
87 } 455 }
88 /* 456 last_timestamp = sample->time;
89 * FIXME: better resolve from pid from the struct trace_entry 457 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 } 458 }
97 459
460 if (cpu_list && !test_bit(sample->cpu, cpu_bitmap))
461 return 0;
462
463 scripting_ops->process_event(event, sample, evsel, session, thread);
464
98 session->hists.stats.total_period += sample->period; 465 session->hists.stats.total_period += sample->period;
99 return 0; 466 return 0;
100} 467}
101 468
102static struct perf_event_ops event_ops = { 469static struct perf_event_ops event_ops = {
103 .sample = process_sample_event, 470 .sample = process_sample_event,
104 .comm = event__process_comm, 471 .mmap = perf_event__process_mmap,
105 .attr = event__process_attr, 472 .comm = perf_event__process_comm,
106 .event_type = event__process_event_type, 473 .exit = perf_event__process_task,
107 .tracing_data = event__process_tracing_data, 474 .fork = perf_event__process_task,
108 .build_id = event__process_build_id, 475 .attr = perf_event__process_attr,
109 .ordering_requires_timestamps = true, 476 .event_type = perf_event__process_event_type,
477 .tracing_data = perf_event__process_tracing_data,
478 .build_id = perf_event__process_build_id,
110 .ordered_samples = true, 479 .ordered_samples = true,
480 .ordering_requires_timestamps = true,
111}; 481};
112 482
113extern volatile int session_done; 483extern volatile int session_done;
@@ -279,6 +649,116 @@ static int parse_scriptname(const struct option *opt __used,
279 return 0; 649 return 0;
280} 650}
281 651
652static int parse_output_fields(const struct option *opt __used,
653 const char *arg, int unset __used)
654{
655 char *tok;
656 int i, imax = sizeof(all_output_options) / sizeof(struct output_option);
657 int j;
658 int rc = 0;
659 char *str = strdup(arg);
660 int type = -1;
661
662 if (!str)
663 return -ENOMEM;
664
665 /* first word can state for which event type the user is specifying
666 * the fields. If no type exists, the specified fields apply to all
667 * event types found in the file minus the invalid fields for a type.
668 */
669 tok = strchr(str, ':');
670 if (tok) {
671 *tok = '\0';
672 tok++;
673 if (!strcmp(str, "hw"))
674 type = PERF_TYPE_HARDWARE;
675 else if (!strcmp(str, "sw"))
676 type = PERF_TYPE_SOFTWARE;
677 else if (!strcmp(str, "trace"))
678 type = PERF_TYPE_TRACEPOINT;
679 else if (!strcmp(str, "raw"))
680 type = PERF_TYPE_RAW;
681 else {
682 fprintf(stderr, "Invalid event type in field string.\n");
683 return -EINVAL;
684 }
685
686 if (output[type].user_set)
687 pr_warning("Overriding previous field request for %s events.\n",
688 event_type(type));
689
690 output[type].fields = 0;
691 output[type].user_set = true;
692 output[type].wildcard_set = false;
693
694 } else {
695 tok = str;
696 if (strlen(str) == 0) {
697 fprintf(stderr,
698 "Cannot set fields to 'none' for all event types.\n");
699 rc = -EINVAL;
700 goto out;
701 }
702
703 if (output_set_by_user())
704 pr_warning("Overriding previous field request for all events.\n");
705
706 for (j = 0; j < PERF_TYPE_MAX; ++j) {
707 output[j].fields = 0;
708 output[j].user_set = true;
709 output[j].wildcard_set = true;
710 }
711 }
712
713 tok = strtok(tok, ",");
714 while (tok) {
715 for (i = 0; i < imax; ++i) {
716 if (strcmp(tok, all_output_options[i].str) == 0)
717 break;
718 }
719 if (i == imax) {
720 fprintf(stderr, "Invalid field requested.\n");
721 rc = -EINVAL;
722 goto out;
723 }
724
725 if (type == -1) {
726 /* add user option to all events types for
727 * which it is valid
728 */
729 for (j = 0; j < PERF_TYPE_MAX; ++j) {
730 if (output[j].invalid_fields & all_output_options[i].field) {
731 pr_warning("\'%s\' not valid for %s events. Ignoring.\n",
732 all_output_options[i].str, event_type(j));
733 } else
734 output[j].fields |= all_output_options[i].field;
735 }
736 } else {
737 if (output[type].invalid_fields & all_output_options[i].field) {
738 fprintf(stderr, "\'%s\' not valid for %s events.\n",
739 all_output_options[i].str, event_type(type));
740
741 rc = -EINVAL;
742 goto out;
743 }
744 output[type].fields |= all_output_options[i].field;
745 }
746
747 tok = strtok(NULL, ",");
748 }
749
750 if (type >= 0) {
751 if (output[type].fields == 0) {
752 pr_debug("No fields requested for %s type. "
753 "Events will not be displayed.\n", event_type(type));
754 }
755 }
756
757out:
758 free(str);
759 return rc;
760}
761
282/* Helper function for filesystems that return a dent->d_type DT_UNKNOWN */ 762/* Helper function for filesystems that return a dent->d_type DT_UNKNOWN */
283static int is_directory(const char *base_path, const struct dirent *dent) 763static int is_directory(const char *base_path, const struct dirent *dent)
284{ 764{
@@ -591,6 +1071,18 @@ static const struct option options[] = {
591 "input file name"), 1071 "input file name"),
592 OPT_BOOLEAN('d', "debug-mode", &debug_mode, 1072 OPT_BOOLEAN('d', "debug-mode", &debug_mode,
593 "do various checks like samples ordering and lost events"), 1073 "do various checks like samples ordering and lost events"),
1074 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
1075 "file", "vmlinux pathname"),
1076 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
1077 "file", "kallsyms pathname"),
1078 OPT_BOOLEAN('G', "hide-call-graph", &no_callchain,
1079 "When printing symbols do not display call chain"),
1080 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
1081 "Look for files with symbols relative to this directory"),
1082 OPT_CALLBACK('f', "fields", NULL, "str",
1083 "comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace,raw. Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,addr",
1084 parse_output_fields),
1085 OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"),
594 1086
595 OPT_END() 1087 OPT_END()
596}; 1088};
@@ -771,14 +1263,27 @@ int cmd_script(int argc, const char **argv, const char *prefix __used)
771 if (session == NULL) 1263 if (session == NULL)
772 return -ENOMEM; 1264 return -ENOMEM;
773 1265
774 if (strcmp(input_name, "-") && 1266 if (cpu_list) {
775 !perf_session__has_traces(session, "record -R")) 1267 if (perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap))
776 return -EINVAL; 1268 return -1;
1269 }
1270
1271 if (!no_callchain)
1272 symbol_conf.use_callchain = true;
1273 else
1274 symbol_conf.use_callchain = false;
777 1275
778 if (generate_script_lang) { 1276 if (generate_script_lang) {
779 struct stat perf_stat; 1277 struct stat perf_stat;
1278 int input;
1279
1280 if (output_set_by_user()) {
1281 fprintf(stderr,
1282 "custom fields not supported for generated scripts");
1283 return -1;
1284 }
780 1285
781 int input = open(input_name, O_RDONLY); 1286 input = open(input_name, O_RDONLY);
782 if (input < 0) { 1287 if (input < 0) {
783 perror("failed to open file"); 1288 perror("failed to open file");
784 exit(-1); 1289 exit(-1);
@@ -812,6 +1317,11 @@ int cmd_script(int argc, const char **argv, const char *prefix __used)
812 pr_debug("perf script started with script %s\n\n", script_name); 1317 pr_debug("perf script started with script %s\n\n", script_name);
813 } 1318 }
814 1319
1320
1321 err = perf_session__check_output_opt(session);
1322 if (err < 0)
1323 goto out;
1324
815 err = __cmd_script(session); 1325 err = __cmd_script(session);
816 1326
817 perf_session__delete(session); 1327 perf_session__delete(session);
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index a482a191a0ca..1ad04ce29c34 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -6,24 +6,28 @@
6 * 6 *
7 * Sample output: 7 * Sample output:
8 8
9 $ perf stat ~/hackbench 10 9 $ perf stat ./hackbench 10
10 Time: 0.104
11 10
12 Performance counter stats for '/home/mingo/hackbench': 11 Time: 0.118
13 12
14 1255.538611 task clock ticks # 10.143 CPU utilization factor 13 Performance counter stats for './hackbench 10':
15 54011 context switches # 0.043 M/sec
16 385 CPU migrations # 0.000 M/sec
17 17755 pagefaults # 0.014 M/sec
18 3808323185 CPU cycles # 3033.219 M/sec
19 1575111190 instructions # 1254.530 M/sec
20 17367895 cache references # 13.833 M/sec
21 7674421 cache misses # 6.112 M/sec
22 14
23 Wall-clock time elapsed: 123.786620 msecs 15 1708.761321 task-clock # 11.037 CPUs utilized
16 41,190 context-switches # 0.024 M/sec
17 6,735 CPU-migrations # 0.004 M/sec
18 17,318 page-faults # 0.010 M/sec
19 5,205,202,243 cycles # 3.046 GHz
20 3,856,436,920 stalled-cycles-frontend # 74.09% frontend cycles idle
21 1,600,790,871 stalled-cycles-backend # 30.75% backend cycles idle
22 2,603,501,247 instructions # 0.50 insns per cycle
23 # 1.48 stalled cycles per insn
24 484,357,498 branches # 283.455 M/sec
25 6,388,934 branch-misses # 1.32% of all branches
26
27 0.154822978 seconds time elapsed
24 28
25 * 29 *
26 * Copyright (C) 2008, Red Hat Inc, Ingo Molnar <mingo@redhat.com> 30 * Copyright (C) 2008-2011, Red Hat Inc, Ingo Molnar <mingo@redhat.com>
27 * 31 *
28 * Improvements and fixes by: 32 * Improvements and fixes by:
29 * 33 *
@@ -43,17 +47,22 @@
43#include "util/parse-options.h" 47#include "util/parse-options.h"
44#include "util/parse-events.h" 48#include "util/parse-events.h"
45#include "util/event.h" 49#include "util/event.h"
50#include "util/evlist.h"
46#include "util/evsel.h" 51#include "util/evsel.h"
47#include "util/debug.h" 52#include "util/debug.h"
53#include "util/color.h"
48#include "util/header.h" 54#include "util/header.h"
49#include "util/cpumap.h" 55#include "util/cpumap.h"
50#include "util/thread.h" 56#include "util/thread.h"
57#include "util/thread_map.h"
51 58
52#include <sys/prctl.h> 59#include <sys/prctl.h>
53#include <math.h> 60#include <math.h>
54#include <locale.h> 61#include <locale.h>
55 62
56#define DEFAULT_SEPARATOR " " 63#define DEFAULT_SEPARATOR " "
64#define CNTR_NOT_SUPPORTED "<not supported>"
65#define CNTR_NOT_COUNTED "<not counted>"
57 66
58static struct perf_event_attr default_attrs[] = { 67static struct perf_event_attr default_attrs[] = {
59 68
@@ -63,16 +72,110 @@ static struct perf_event_attr default_attrs[] = {
63 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS }, 72 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS },
64 73
65 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES }, 74 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES },
75 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_FRONTEND },
76 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_BACKEND },
66 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS }, 77 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS },
67 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS }, 78 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS },
68 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES }, 79 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES },
69 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_REFERENCES },
70 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_MISSES },
71 80
72}; 81};
73 82
83/*
84 * Detailed stats (-d), covering the L1 and last level data caches:
85 */
86static struct perf_event_attr detailed_attrs[] = {
87
88 { .type = PERF_TYPE_HW_CACHE,
89 .config =
90 PERF_COUNT_HW_CACHE_L1D << 0 |
91 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
92 (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) },
93
94 { .type = PERF_TYPE_HW_CACHE,
95 .config =
96 PERF_COUNT_HW_CACHE_L1D << 0 |
97 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
98 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) },
99
100 { .type = PERF_TYPE_HW_CACHE,
101 .config =
102 PERF_COUNT_HW_CACHE_LL << 0 |
103 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
104 (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) },
105
106 { .type = PERF_TYPE_HW_CACHE,
107 .config =
108 PERF_COUNT_HW_CACHE_LL << 0 |
109 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
110 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) },
111};
112
113/*
114 * Very detailed stats (-d -d), covering the instruction cache and the TLB caches:
115 */
116static struct perf_event_attr very_detailed_attrs[] = {
117
118 { .type = PERF_TYPE_HW_CACHE,
119 .config =
120 PERF_COUNT_HW_CACHE_L1I << 0 |
121 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
122 (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) },
123
124 { .type = PERF_TYPE_HW_CACHE,
125 .config =
126 PERF_COUNT_HW_CACHE_L1I << 0 |
127 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
128 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) },
129
130 { .type = PERF_TYPE_HW_CACHE,
131 .config =
132 PERF_COUNT_HW_CACHE_DTLB << 0 |
133 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
134 (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) },
135
136 { .type = PERF_TYPE_HW_CACHE,
137 .config =
138 PERF_COUNT_HW_CACHE_DTLB << 0 |
139 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
140 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) },
141
142 { .type = PERF_TYPE_HW_CACHE,
143 .config =
144 PERF_COUNT_HW_CACHE_ITLB << 0 |
145 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
146 (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) },
147
148 { .type = PERF_TYPE_HW_CACHE,
149 .config =
150 PERF_COUNT_HW_CACHE_ITLB << 0 |
151 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
152 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) },
153
154};
155
156/*
157 * Very, very detailed stats (-d -d -d), adding prefetch events:
158 */
159static struct perf_event_attr very_very_detailed_attrs[] = {
160
161 { .type = PERF_TYPE_HW_CACHE,
162 .config =
163 PERF_COUNT_HW_CACHE_L1D << 0 |
164 (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) |
165 (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) },
166
167 { .type = PERF_TYPE_HW_CACHE,
168 .config =
169 PERF_COUNT_HW_CACHE_L1D << 0 |
170 (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) |
171 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) },
172};
173
174
175
176struct perf_evlist *evsel_list;
177
74static bool system_wide = false; 178static bool system_wide = false;
75static struct cpu_map *cpus;
76static int run_idx = 0; 179static int run_idx = 0;
77 180
78static int run_count = 1; 181static int run_count = 1;
@@ -81,9 +184,10 @@ static bool scale = true;
81static bool no_aggr = false; 184static bool no_aggr = false;
82static pid_t target_pid = -1; 185static pid_t target_pid = -1;
83static pid_t target_tid = -1; 186static pid_t target_tid = -1;
84static struct thread_map *threads;
85static pid_t child_pid = -1; 187static pid_t child_pid = -1;
86static bool null_run = false; 188static bool null_run = false;
189static int detailed_run = 0;
190static bool sync_run = false;
87static bool big_num = true; 191static bool big_num = true;
88static int big_num_opt = -1; 192static int big_num_opt = -1;
89static const char *cpu_list; 193static const char *cpu_list;
@@ -154,7 +258,15 @@ static double stddev_stats(struct stats *stats)
154 258
155struct stats runtime_nsecs_stats[MAX_NR_CPUS]; 259struct stats runtime_nsecs_stats[MAX_NR_CPUS];
156struct stats runtime_cycles_stats[MAX_NR_CPUS]; 260struct stats runtime_cycles_stats[MAX_NR_CPUS];
261struct stats runtime_stalled_cycles_front_stats[MAX_NR_CPUS];
262struct stats runtime_stalled_cycles_back_stats[MAX_NR_CPUS];
157struct stats runtime_branches_stats[MAX_NR_CPUS]; 263struct stats runtime_branches_stats[MAX_NR_CPUS];
264struct stats runtime_cacherefs_stats[MAX_NR_CPUS];
265struct stats runtime_l1_dcache_stats[MAX_NR_CPUS];
266struct stats runtime_l1_icache_stats[MAX_NR_CPUS];
267struct stats runtime_ll_cache_stats[MAX_NR_CPUS];
268struct stats runtime_itlb_cache_stats[MAX_NR_CPUS];
269struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS];
158struct stats walltime_nsecs_stats; 270struct stats walltime_nsecs_stats;
159 271
160static int create_perf_stat_counter(struct perf_evsel *evsel) 272static int create_perf_stat_counter(struct perf_evsel *evsel)
@@ -165,16 +277,17 @@ static int create_perf_stat_counter(struct perf_evsel *evsel)
165 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | 277 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
166 PERF_FORMAT_TOTAL_TIME_RUNNING; 278 PERF_FORMAT_TOTAL_TIME_RUNNING;
167 279
280 attr->inherit = !no_inherit;
281
168 if (system_wide) 282 if (system_wide)
169 return perf_evsel__open_per_cpu(evsel, cpus); 283 return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, false);
170 284
171 attr->inherit = !no_inherit;
172 if (target_pid == -1 && target_tid == -1) { 285 if (target_pid == -1 && target_tid == -1) {
173 attr->disabled = 1; 286 attr->disabled = 1;
174 attr->enable_on_exec = 1; 287 attr->enable_on_exec = 1;
175 } 288 }
176 289
177 return perf_evsel__open_per_thread(evsel, threads); 290 return perf_evsel__open_per_thread(evsel, evsel_list->threads, false);
178} 291}
179 292
180/* 293/*
@@ -190,6 +303,37 @@ static inline int nsec_counter(struct perf_evsel *evsel)
190} 303}
191 304
192/* 305/*
306 * Update various tracking values we maintain to print
307 * more semantic information such as miss/hit ratios,
308 * instruction rates, etc:
309 */
310static void update_shadow_stats(struct perf_evsel *counter, u64 *count)
311{
312 if (perf_evsel__match(counter, SOFTWARE, SW_TASK_CLOCK))
313 update_stats(&runtime_nsecs_stats[0], count[0]);
314 else if (perf_evsel__match(counter, HARDWARE, HW_CPU_CYCLES))
315 update_stats(&runtime_cycles_stats[0], count[0]);
316 else if (perf_evsel__match(counter, HARDWARE, HW_STALLED_CYCLES_FRONTEND))
317 update_stats(&runtime_stalled_cycles_front_stats[0], count[0]);
318 else if (perf_evsel__match(counter, HARDWARE, HW_STALLED_CYCLES_BACKEND))
319 update_stats(&runtime_stalled_cycles_back_stats[0], count[0]);
320 else if (perf_evsel__match(counter, HARDWARE, HW_BRANCH_INSTRUCTIONS))
321 update_stats(&runtime_branches_stats[0], count[0]);
322 else if (perf_evsel__match(counter, HARDWARE, HW_CACHE_REFERENCES))
323 update_stats(&runtime_cacherefs_stats[0], count[0]);
324 else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_L1D))
325 update_stats(&runtime_l1_dcache_stats[0], count[0]);
326 else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_L1I))
327 update_stats(&runtime_l1_icache_stats[0], count[0]);
328 else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_LL))
329 update_stats(&runtime_ll_cache_stats[0], count[0]);
330 else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_DTLB))
331 update_stats(&runtime_dtlb_cache_stats[0], count[0]);
332 else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_ITLB))
333 update_stats(&runtime_itlb_cache_stats[0], count[0]);
334}
335
336/*
193 * Read out the results of a single counter: 337 * Read out the results of a single counter:
194 * aggregate counts across CPUs in system-wide mode 338 * aggregate counts across CPUs in system-wide mode
195 */ 339 */
@@ -199,7 +343,8 @@ static int read_counter_aggr(struct perf_evsel *counter)
199 u64 *count = counter->counts->aggr.values; 343 u64 *count = counter->counts->aggr.values;
200 int i; 344 int i;
201 345
202 if (__perf_evsel__read(counter, cpus->nr, threads->nr, scale) < 0) 346 if (__perf_evsel__read(counter, evsel_list->cpus->nr,
347 evsel_list->threads->nr, scale) < 0)
203 return -1; 348 return -1;
204 349
205 for (i = 0; i < 3; i++) 350 for (i = 0; i < 3; i++)
@@ -213,12 +358,7 @@ static int read_counter_aggr(struct perf_evsel *counter)
213 /* 358 /*
214 * Save the full runtime - to allow normalization during printout: 359 * Save the full runtime - to allow normalization during printout:
215 */ 360 */
216 if (perf_evsel__match(counter, SOFTWARE, SW_TASK_CLOCK)) 361 update_shadow_stats(counter, count);
217 update_stats(&runtime_nsecs_stats[0], count[0]);
218 if (perf_evsel__match(counter, HARDWARE, HW_CPU_CYCLES))
219 update_stats(&runtime_cycles_stats[0], count[0]);
220 if (perf_evsel__match(counter, HARDWARE, HW_BRANCH_INSTRUCTIONS))
221 update_stats(&runtime_branches_stats[0], count[0]);
222 362
223 return 0; 363 return 0;
224} 364}
@@ -232,18 +372,13 @@ static int read_counter(struct perf_evsel *counter)
232 u64 *count; 372 u64 *count;
233 int cpu; 373 int cpu;
234 374
235 for (cpu = 0; cpu < cpus->nr; cpu++) { 375 for (cpu = 0; cpu < evsel_list->cpus->nr; cpu++) {
236 if (__perf_evsel__read_on_cpu(counter, cpu, 0, scale) < 0) 376 if (__perf_evsel__read_on_cpu(counter, cpu, 0, scale) < 0)
237 return -1; 377 return -1;
238 378
239 count = counter->counts->cpu[cpu].values; 379 count = counter->counts->cpu[cpu].values;
240 380
241 if (perf_evsel__match(counter, SOFTWARE, SW_TASK_CLOCK)) 381 update_shadow_stats(counter, count);
242 update_stats(&runtime_nsecs_stats[cpu], count[0]);
243 if (perf_evsel__match(counter, HARDWARE, HW_CPU_CYCLES))
244 update_stats(&runtime_cycles_stats[cpu], count[0]);
245 if (perf_evsel__match(counter, HARDWARE, HW_BRANCH_INSTRUCTIONS))
246 update_stats(&runtime_branches_stats[cpu], count[0]);
247 } 382 }
248 383
249 return 0; 384 return 0;
@@ -297,7 +432,7 @@ static int run_perf_stat(int argc __used, const char **argv)
297 } 432 }
298 433
299 if (target_tid == -1 && target_pid == -1 && !system_wide) 434 if (target_tid == -1 && target_pid == -1 && !system_wide)
300 threads->map[0] = child_pid; 435 evsel_list->threads->map[0] = child_pid;
301 436
302 /* 437 /*
303 * Wait for the child to be ready to exec. 438 * Wait for the child to be ready to exec.
@@ -309,15 +444,21 @@ static int run_perf_stat(int argc __used, const char **argv)
309 close(child_ready_pipe[0]); 444 close(child_ready_pipe[0]);
310 } 445 }
311 446
312 list_for_each_entry(counter, &evsel_list, node) { 447 list_for_each_entry(counter, &evsel_list->entries, node) {
313 if (create_perf_stat_counter(counter) < 0) { 448 if (create_perf_stat_counter(counter) < 0) {
314 if (errno == -EPERM || errno == -EACCES) { 449 if (errno == EINVAL || errno == ENOSYS || errno == ENOENT) {
450 if (verbose)
451 ui__warning("%s event is not supported by the kernel.\n",
452 event_name(counter));
453 counter->supported = false;
454 continue;
455 }
456
457 if (errno == EPERM || errno == EACCES) {
315 error("You may not have permission to collect %sstats.\n" 458 error("You may not have permission to collect %sstats.\n"
316 "\t Consider tweaking" 459 "\t Consider tweaking"
317 " /proc/sys/kernel/perf_event_paranoid or running as root.", 460 " /proc/sys/kernel/perf_event_paranoid or running as root.",
318 system_wide ? "system-wide " : ""); 461 system_wide ? "system-wide " : "");
319 } else if (errno == ENOENT) {
320 error("%s event is not supported. ", event_name(counter));
321 } else { 462 } else {
322 error("open_counter returned with %d (%s). " 463 error("open_counter returned with %d (%s). "
323 "/bin/dmesg may provide additional information.\n", 464 "/bin/dmesg may provide additional information.\n",
@@ -328,6 +469,13 @@ static int run_perf_stat(int argc __used, const char **argv)
328 die("Not all events could be opened.\n"); 469 die("Not all events could be opened.\n");
329 return -1; 470 return -1;
330 } 471 }
472 counter->supported = true;
473 }
474
475 if (perf_evlist__set_filters(evsel_list)) {
476 error("failed to set filter with %d (%s)\n", errno,
477 strerror(errno));
478 return -1;
331 } 479 }
332 480
333 /* 481 /*
@@ -347,20 +495,34 @@ static int run_perf_stat(int argc __used, const char **argv)
347 update_stats(&walltime_nsecs_stats, t1 - t0); 495 update_stats(&walltime_nsecs_stats, t1 - t0);
348 496
349 if (no_aggr) { 497 if (no_aggr) {
350 list_for_each_entry(counter, &evsel_list, node) { 498 list_for_each_entry(counter, &evsel_list->entries, node) {
351 read_counter(counter); 499 read_counter(counter);
352 perf_evsel__close_fd(counter, cpus->nr, 1); 500 perf_evsel__close_fd(counter, evsel_list->cpus->nr, 1);
353 } 501 }
354 } else { 502 } else {
355 list_for_each_entry(counter, &evsel_list, node) { 503 list_for_each_entry(counter, &evsel_list->entries, node) {
356 read_counter_aggr(counter); 504 read_counter_aggr(counter);
357 perf_evsel__close_fd(counter, cpus->nr, threads->nr); 505 perf_evsel__close_fd(counter, evsel_list->cpus->nr,
506 evsel_list->threads->nr);
358 } 507 }
359 } 508 }
360 509
361 return WEXITSTATUS(status); 510 return WEXITSTATUS(status);
362} 511}
363 512
513static void print_noise_pct(double total, double avg)
514{
515 double pct = 0.0;
516
517 if (avg)
518 pct = 100.0*total/avg;
519
520 if (csv_output)
521 fprintf(stderr, "%s%.2f%%", csv_sep, pct);
522 else
523 fprintf(stderr, " ( +-%6.2f%% )", pct);
524}
525
364static void print_noise(struct perf_evsel *evsel, double avg) 526static void print_noise(struct perf_evsel *evsel, double avg)
365{ 527{
366 struct perf_stat *ps; 528 struct perf_stat *ps;
@@ -369,29 +531,214 @@ static void print_noise(struct perf_evsel *evsel, double avg)
369 return; 531 return;
370 532
371 ps = evsel->priv; 533 ps = evsel->priv;
372 fprintf(stderr, " ( +- %7.3f%% )", 534 print_noise_pct(stddev_stats(&ps->res_stats[0]), avg);
373 100 * stddev_stats(&ps->res_stats[0]) / avg);
374} 535}
375 536
376static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg) 537static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg)
377{ 538{
378 double msecs = avg / 1e6; 539 double msecs = avg / 1e6;
379 char cpustr[16] = { '\0', }; 540 char cpustr[16] = { '\0', };
380 const char *fmt = csv_output ? "%s%.6f%s%s" : "%s%18.6f%s%-24s"; 541 const char *fmt = csv_output ? "%s%.6f%s%s" : "%s%18.6f%s%-25s";
381 542
382 if (no_aggr) 543 if (no_aggr)
383 sprintf(cpustr, "CPU%*d%s", 544 sprintf(cpustr, "CPU%*d%s",
384 csv_output ? 0 : -4, 545 csv_output ? 0 : -4,
385 cpus->map[cpu], csv_sep); 546 evsel_list->cpus->map[cpu], csv_sep);
386 547
387 fprintf(stderr, fmt, cpustr, msecs, csv_sep, event_name(evsel)); 548 fprintf(stderr, fmt, cpustr, msecs, csv_sep, event_name(evsel));
388 549
550 if (evsel->cgrp)
551 fprintf(stderr, "%s%s", csv_sep, evsel->cgrp->name);
552
389 if (csv_output) 553 if (csv_output)
390 return; 554 return;
391 555
392 if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK)) 556 if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK))
393 fprintf(stderr, " # %10.3f CPUs ", 557 fprintf(stderr, " # %8.3f CPUs utilized ", avg / avg_stats(&walltime_nsecs_stats));
394 avg / avg_stats(&walltime_nsecs_stats)); 558}
559
560static void print_stalled_cycles_frontend(int cpu, struct perf_evsel *evsel __used, double avg)
561{
562 double total, ratio = 0.0;
563 const char *color;
564
565 total = avg_stats(&runtime_cycles_stats[cpu]);
566
567 if (total)
568 ratio = avg / total * 100.0;
569
570 color = PERF_COLOR_NORMAL;
571 if (ratio > 50.0)
572 color = PERF_COLOR_RED;
573 else if (ratio > 30.0)
574 color = PERF_COLOR_MAGENTA;
575 else if (ratio > 10.0)
576 color = PERF_COLOR_YELLOW;
577
578 fprintf(stderr, " # ");
579 color_fprintf(stderr, color, "%6.2f%%", ratio);
580 fprintf(stderr, " frontend cycles idle ");
581}
582
583static void print_stalled_cycles_backend(int cpu, struct perf_evsel *evsel __used, double avg)
584{
585 double total, ratio = 0.0;
586 const char *color;
587
588 total = avg_stats(&runtime_cycles_stats[cpu]);
589
590 if (total)
591 ratio = avg / total * 100.0;
592
593 color = PERF_COLOR_NORMAL;
594 if (ratio > 75.0)
595 color = PERF_COLOR_RED;
596 else if (ratio > 50.0)
597 color = PERF_COLOR_MAGENTA;
598 else if (ratio > 20.0)
599 color = PERF_COLOR_YELLOW;
600
601 fprintf(stderr, " # ");
602 color_fprintf(stderr, color, "%6.2f%%", ratio);
603 fprintf(stderr, " backend cycles idle ");
604}
605
606static void print_branch_misses(int cpu, struct perf_evsel *evsel __used, double avg)
607{
608 double total, ratio = 0.0;
609 const char *color;
610
611 total = avg_stats(&runtime_branches_stats[cpu]);
612
613 if (total)
614 ratio = avg / total * 100.0;
615
616 color = PERF_COLOR_NORMAL;
617 if (ratio > 20.0)
618 color = PERF_COLOR_RED;
619 else if (ratio > 10.0)
620 color = PERF_COLOR_MAGENTA;
621 else if (ratio > 5.0)
622 color = PERF_COLOR_YELLOW;
623
624 fprintf(stderr, " # ");
625 color_fprintf(stderr, color, "%6.2f%%", ratio);
626 fprintf(stderr, " of all branches ");
627}
628
629static void print_l1_dcache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
630{
631 double total, ratio = 0.0;
632 const char *color;
633
634 total = avg_stats(&runtime_l1_dcache_stats[cpu]);
635
636 if (total)
637 ratio = avg / total * 100.0;
638
639 color = PERF_COLOR_NORMAL;
640 if (ratio > 20.0)
641 color = PERF_COLOR_RED;
642 else if (ratio > 10.0)
643 color = PERF_COLOR_MAGENTA;
644 else if (ratio > 5.0)
645 color = PERF_COLOR_YELLOW;
646
647 fprintf(stderr, " # ");
648 color_fprintf(stderr, color, "%6.2f%%", ratio);
649 fprintf(stderr, " of all L1-dcache hits ");
650}
651
652static void print_l1_icache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
653{
654 double total, ratio = 0.0;
655 const char *color;
656
657 total = avg_stats(&runtime_l1_icache_stats[cpu]);
658
659 if (total)
660 ratio = avg / total * 100.0;
661
662 color = PERF_COLOR_NORMAL;
663 if (ratio > 20.0)
664 color = PERF_COLOR_RED;
665 else if (ratio > 10.0)
666 color = PERF_COLOR_MAGENTA;
667 else if (ratio > 5.0)
668 color = PERF_COLOR_YELLOW;
669
670 fprintf(stderr, " # ");
671 color_fprintf(stderr, color, "%6.2f%%", ratio);
672 fprintf(stderr, " of all L1-icache hits ");
673}
674
675static void print_dtlb_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
676{
677 double total, ratio = 0.0;
678 const char *color;
679
680 total = avg_stats(&runtime_dtlb_cache_stats[cpu]);
681
682 if (total)
683 ratio = avg / total * 100.0;
684
685 color = PERF_COLOR_NORMAL;
686 if (ratio > 20.0)
687 color = PERF_COLOR_RED;
688 else if (ratio > 10.0)
689 color = PERF_COLOR_MAGENTA;
690 else if (ratio > 5.0)
691 color = PERF_COLOR_YELLOW;
692
693 fprintf(stderr, " # ");
694 color_fprintf(stderr, color, "%6.2f%%", ratio);
695 fprintf(stderr, " of all dTLB cache hits ");
696}
697
698static void print_itlb_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
699{
700 double total, ratio = 0.0;
701 const char *color;
702
703 total = avg_stats(&runtime_itlb_cache_stats[cpu]);
704
705 if (total)
706 ratio = avg / total * 100.0;
707
708 color = PERF_COLOR_NORMAL;
709 if (ratio > 20.0)
710 color = PERF_COLOR_RED;
711 else if (ratio > 10.0)
712 color = PERF_COLOR_MAGENTA;
713 else if (ratio > 5.0)
714 color = PERF_COLOR_YELLOW;
715
716 fprintf(stderr, " # ");
717 color_fprintf(stderr, color, "%6.2f%%", ratio);
718 fprintf(stderr, " of all iTLB cache hits ");
719}
720
721static void print_ll_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
722{
723 double total, ratio = 0.0;
724 const char *color;
725
726 total = avg_stats(&runtime_ll_cache_stats[cpu]);
727
728 if (total)
729 ratio = avg / total * 100.0;
730
731 color = PERF_COLOR_NORMAL;
732 if (ratio > 20.0)
733 color = PERF_COLOR_RED;
734 else if (ratio > 10.0)
735 color = PERF_COLOR_MAGENTA;
736 else if (ratio > 5.0)
737 color = PERF_COLOR_YELLOW;
738
739 fprintf(stderr, " # ");
740 color_fprintf(stderr, color, "%6.2f%%", ratio);
741 fprintf(stderr, " of all LL-cache hits ");
395} 742}
396 743
397static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) 744static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
@@ -403,19 +750,22 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
403 if (csv_output) 750 if (csv_output)
404 fmt = "%s%.0f%s%s"; 751 fmt = "%s%.0f%s%s";
405 else if (big_num) 752 else if (big_num)
406 fmt = "%s%'18.0f%s%-24s"; 753 fmt = "%s%'18.0f%s%-25s";
407 else 754 else
408 fmt = "%s%18.0f%s%-24s"; 755 fmt = "%s%18.0f%s%-25s";
409 756
410 if (no_aggr) 757 if (no_aggr)
411 sprintf(cpustr, "CPU%*d%s", 758 sprintf(cpustr, "CPU%*d%s",
412 csv_output ? 0 : -4, 759 csv_output ? 0 : -4,
413 cpus->map[cpu], csv_sep); 760 evsel_list->cpus->map[cpu], csv_sep);
414 else 761 else
415 cpu = 0; 762 cpu = 0;
416 763
417 fprintf(stderr, fmt, cpustr, avg, csv_sep, event_name(evsel)); 764 fprintf(stderr, fmt, cpustr, avg, csv_sep, event_name(evsel));
418 765
766 if (evsel->cgrp)
767 fprintf(stderr, "%s%s", csv_sep, evsel->cgrp->name);
768
419 if (csv_output) 769 if (csv_output)
420 return; 770 return;
421 771
@@ -425,23 +775,83 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
425 if (total) 775 if (total)
426 ratio = avg / total; 776 ratio = avg / total;
427 777
428 fprintf(stderr, " # %10.3f IPC ", ratio); 778 fprintf(stderr, " # %5.2f insns per cycle ", ratio);
779
780 total = avg_stats(&runtime_stalled_cycles_front_stats[cpu]);
781 total = max(total, avg_stats(&runtime_stalled_cycles_back_stats[cpu]));
782
783 if (total && avg) {
784 ratio = total / avg;
785 fprintf(stderr, "\n # %5.2f stalled cycles per insn", ratio);
786 }
787
429 } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) && 788 } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) &&
430 runtime_branches_stats[cpu].n != 0) { 789 runtime_branches_stats[cpu].n != 0) {
431 total = avg_stats(&runtime_branches_stats[cpu]); 790 print_branch_misses(cpu, evsel, avg);
791 } else if (
792 evsel->attr.type == PERF_TYPE_HW_CACHE &&
793 evsel->attr.config == ( PERF_COUNT_HW_CACHE_L1D |
794 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
795 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) &&
796 runtime_l1_dcache_stats[cpu].n != 0) {
797 print_l1_dcache_misses(cpu, evsel, avg);
798 } else if (
799 evsel->attr.type == PERF_TYPE_HW_CACHE &&
800 evsel->attr.config == ( PERF_COUNT_HW_CACHE_L1I |
801 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
802 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) &&
803 runtime_l1_icache_stats[cpu].n != 0) {
804 print_l1_icache_misses(cpu, evsel, avg);
805 } else if (
806 evsel->attr.type == PERF_TYPE_HW_CACHE &&
807 evsel->attr.config == ( PERF_COUNT_HW_CACHE_DTLB |
808 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
809 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) &&
810 runtime_dtlb_cache_stats[cpu].n != 0) {
811 print_dtlb_cache_misses(cpu, evsel, avg);
812 } else if (
813 evsel->attr.type == PERF_TYPE_HW_CACHE &&
814 evsel->attr.config == ( PERF_COUNT_HW_CACHE_ITLB |
815 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
816 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) &&
817 runtime_itlb_cache_stats[cpu].n != 0) {
818 print_itlb_cache_misses(cpu, evsel, avg);
819 } else if (
820 evsel->attr.type == PERF_TYPE_HW_CACHE &&
821 evsel->attr.config == ( PERF_COUNT_HW_CACHE_LL |
822 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
823 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) &&
824 runtime_ll_cache_stats[cpu].n != 0) {
825 print_ll_cache_misses(cpu, evsel, avg);
826 } else if (perf_evsel__match(evsel, HARDWARE, HW_CACHE_MISSES) &&
827 runtime_cacherefs_stats[cpu].n != 0) {
828 total = avg_stats(&runtime_cacherefs_stats[cpu]);
432 829
433 if (total) 830 if (total)
434 ratio = avg * 100 / total; 831 ratio = avg * 100 / total;
435 832
436 fprintf(stderr, " # %10.3f %% ", ratio); 833 fprintf(stderr, " # %8.3f %% of all cache refs ", ratio);
834
835 } else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_FRONTEND)) {
836 print_stalled_cycles_frontend(cpu, evsel, avg);
837 } else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_BACKEND)) {
838 print_stalled_cycles_backend(cpu, evsel, avg);
839 } else if (perf_evsel__match(evsel, HARDWARE, HW_CPU_CYCLES)) {
840 total = avg_stats(&runtime_nsecs_stats[cpu]);
841
842 if (total)
843 ratio = 1.0 * avg / total;
437 844
845 fprintf(stderr, " # %8.3f GHz ", ratio);
438 } else if (runtime_nsecs_stats[cpu].n != 0) { 846 } else if (runtime_nsecs_stats[cpu].n != 0) {
439 total = avg_stats(&runtime_nsecs_stats[cpu]); 847 total = avg_stats(&runtime_nsecs_stats[cpu]);
440 848
441 if (total) 849 if (total)
442 ratio = 1000.0 * avg / total; 850 ratio = 1000.0 * avg / total;
443 851
444 fprintf(stderr, " # %10.3f M/sec", ratio); 852 fprintf(stderr, " # %8.3f M/sec ", ratio);
853 } else {
854 fprintf(stderr, " ");
445 } 855 }
446} 856}
447 857
@@ -456,9 +866,17 @@ static void print_counter_aggr(struct perf_evsel *counter)
456 int scaled = counter->counts->scaled; 866 int scaled = counter->counts->scaled;
457 867
458 if (scaled == -1) { 868 if (scaled == -1) {
459 fprintf(stderr, "%*s%s%-24s\n", 869 fprintf(stderr, "%*s%s%*s",
460 csv_output ? 0 : 18, 870 csv_output ? 0 : 18,
461 "<not counted>", csv_sep, event_name(counter)); 871 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
872 csv_sep,
873 csv_output ? 0 : -24,
874 event_name(counter));
875
876 if (counter->cgrp)
877 fprintf(stderr, "%s%s", csv_sep, counter->cgrp->name);
878
879 fputc('\n', stderr);
462 return; 880 return;
463 } 881 }
464 882
@@ -467,23 +885,21 @@ static void print_counter_aggr(struct perf_evsel *counter)
467 else 885 else
468 abs_printout(-1, counter, avg); 886 abs_printout(-1, counter, avg);
469 887
888 print_noise(counter, avg);
889
470 if (csv_output) { 890 if (csv_output) {
471 fputc('\n', stderr); 891 fputc('\n', stderr);
472 return; 892 return;
473 } 893 }
474 894
475 print_noise(counter, avg);
476
477 if (scaled) { 895 if (scaled) {
478 double avg_enabled, avg_running; 896 double avg_enabled, avg_running;
479 897
480 avg_enabled = avg_stats(&ps->res_stats[1]); 898 avg_enabled = avg_stats(&ps->res_stats[1]);
481 avg_running = avg_stats(&ps->res_stats[2]); 899 avg_running = avg_stats(&ps->res_stats[2]);
482 900
483 fprintf(stderr, " (scaled from %.2f%%)", 901 fprintf(stderr, " [%5.2f%%]", 100 * avg_running / avg_enabled);
484 100 * avg_running / avg_enabled);
485 } 902 }
486
487 fprintf(stderr, "\n"); 903 fprintf(stderr, "\n");
488} 904}
489 905
@@ -496,19 +912,24 @@ static void print_counter(struct perf_evsel *counter)
496 u64 ena, run, val; 912 u64 ena, run, val;
497 int cpu; 913 int cpu;
498 914
499 for (cpu = 0; cpu < cpus->nr; cpu++) { 915 for (cpu = 0; cpu < evsel_list->cpus->nr; cpu++) {
500 val = counter->counts->cpu[cpu].val; 916 val = counter->counts->cpu[cpu].val;
501 ena = counter->counts->cpu[cpu].ena; 917 ena = counter->counts->cpu[cpu].ena;
502 run = counter->counts->cpu[cpu].run; 918 run = counter->counts->cpu[cpu].run;
503 if (run == 0 || ena == 0) { 919 if (run == 0 || ena == 0) {
504 fprintf(stderr, "CPU%*d%s%*s%s%-24s", 920 fprintf(stderr, "CPU%*d%s%*s%s%*s",
505 csv_output ? 0 : -4, 921 csv_output ? 0 : -4,
506 cpus->map[cpu], csv_sep, 922 evsel_list->cpus->map[cpu], csv_sep,
507 csv_output ? 0 : 18, 923 csv_output ? 0 : 18,
508 "<not counted>", csv_sep, 924 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
925 csv_sep,
926 csv_output ? 0 : -24,
509 event_name(counter)); 927 event_name(counter));
510 928
511 fprintf(stderr, "\n"); 929 if (counter->cgrp)
930 fprintf(stderr, "%s%s", csv_sep, counter->cgrp->name);
931
932 fputc('\n', stderr);
512 continue; 933 continue;
513 } 934 }
514 935
@@ -520,12 +941,10 @@ static void print_counter(struct perf_evsel *counter)
520 if (!csv_output) { 941 if (!csv_output) {
521 print_noise(counter, 1.0); 942 print_noise(counter, 1.0);
522 943
523 if (run != ena) { 944 if (run != ena)
524 fprintf(stderr, " (scaled from %.2f%%)", 945 fprintf(stderr, " (%.2f%%)", 100.0 * run / ena);
525 100.0 * run / ena);
526 }
527 } 946 }
528 fprintf(stderr, "\n"); 947 fputc('\n', stderr);
529 } 948 }
530} 949}
531 950
@@ -555,21 +974,22 @@ static void print_stat(int argc, const char **argv)
555 } 974 }
556 975
557 if (no_aggr) { 976 if (no_aggr) {
558 list_for_each_entry(counter, &evsel_list, node) 977 list_for_each_entry(counter, &evsel_list->entries, node)
559 print_counter(counter); 978 print_counter(counter);
560 } else { 979 } else {
561 list_for_each_entry(counter, &evsel_list, node) 980 list_for_each_entry(counter, &evsel_list->entries, node)
562 print_counter_aggr(counter); 981 print_counter_aggr(counter);
563 } 982 }
564 983
565 if (!csv_output) { 984 if (!csv_output) {
566 fprintf(stderr, "\n"); 985 if (!null_run)
567 fprintf(stderr, " %18.9f seconds time elapsed", 986 fprintf(stderr, "\n");
987 fprintf(stderr, " %17.9f seconds time elapsed",
568 avg_stats(&walltime_nsecs_stats)/1e9); 988 avg_stats(&walltime_nsecs_stats)/1e9);
569 if (run_count > 1) { 989 if (run_count > 1) {
570 fprintf(stderr, " ( +- %7.3f%% )", 990 fprintf(stderr, " ");
571 100*stddev_stats(&walltime_nsecs_stats) / 991 print_noise_pct(stddev_stats(&walltime_nsecs_stats),
572 avg_stats(&walltime_nsecs_stats)); 992 avg_stats(&walltime_nsecs_stats));
573 } 993 }
574 fprintf(stderr, "\n\n"); 994 fprintf(stderr, "\n\n");
575 } 995 }
@@ -610,9 +1030,11 @@ static int stat__set_big_num(const struct option *opt __used,
610} 1030}
611 1031
612static const struct option options[] = { 1032static const struct option options[] = {
613 OPT_CALLBACK('e', "event", NULL, "event", 1033 OPT_CALLBACK('e', "event", &evsel_list, "event",
614 "event selector. use 'perf list' to list available events", 1034 "event selector. use 'perf list' to list available events",
615 parse_events), 1035 parse_events_option),
1036 OPT_CALLBACK(0, "filter", &evsel_list, "filter",
1037 "event filter", parse_filter),
616 OPT_BOOLEAN('i', "no-inherit", &no_inherit, 1038 OPT_BOOLEAN('i', "no-inherit", &no_inherit,
617 "child tasks do not inherit counters"), 1039 "child tasks do not inherit counters"),
618 OPT_INTEGER('p', "pid", &target_pid, 1040 OPT_INTEGER('p', "pid", &target_pid,
@@ -629,6 +1051,10 @@ static const struct option options[] = {
629 "repeat command and print average + stddev (max: 100)"), 1051 "repeat command and print average + stddev (max: 100)"),
630 OPT_BOOLEAN('n', "null", &null_run, 1052 OPT_BOOLEAN('n', "null", &null_run,
631 "null run - dont start any counters"), 1053 "null run - dont start any counters"),
1054 OPT_INCR('d', "detailed", &detailed_run,
1055 "detailed run - start a lot of events"),
1056 OPT_BOOLEAN('S', "sync", &sync_run,
1057 "call sync() before starting a run"),
632 OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL, 1058 OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL,
633 "print large numbers with thousands\' separators", 1059 "print large numbers with thousands\' separators",
634 stat__set_big_num), 1060 stat__set_big_num),
@@ -638,9 +1064,76 @@ static const struct option options[] = {
638 "disable CPU count aggregation"), 1064 "disable CPU count aggregation"),
639 OPT_STRING('x', "field-separator", &csv_sep, "separator", 1065 OPT_STRING('x', "field-separator", &csv_sep, "separator",
640 "print counts with custom separator"), 1066 "print counts with custom separator"),
1067 OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
1068 "monitor event in cgroup name only",
1069 parse_cgroups),
641 OPT_END() 1070 OPT_END()
642}; 1071};
643 1072
1073/*
1074 * Add default attributes, if there were no attributes specified or
1075 * if -d/--detailed, -d -d or -d -d -d is used:
1076 */
1077static int add_default_attributes(void)
1078{
1079 struct perf_evsel *pos;
1080 size_t attr_nr = 0;
1081 size_t c;
1082
1083 /* Set attrs if no event is selected and !null_run: */
1084 if (null_run)
1085 return 0;
1086
1087 if (!evsel_list->nr_entries) {
1088 for (c = 0; c < ARRAY_SIZE(default_attrs); c++) {
1089 pos = perf_evsel__new(default_attrs + c, c + attr_nr);
1090 if (pos == NULL)
1091 return -1;
1092 perf_evlist__add(evsel_list, pos);
1093 }
1094 attr_nr += c;
1095 }
1096
1097 /* Detailed events get appended to the event list: */
1098
1099 if (detailed_run < 1)
1100 return 0;
1101
1102 /* Append detailed run extra attributes: */
1103 for (c = 0; c < ARRAY_SIZE(detailed_attrs); c++) {
1104 pos = perf_evsel__new(detailed_attrs + c, c + attr_nr);
1105 if (pos == NULL)
1106 return -1;
1107 perf_evlist__add(evsel_list, pos);
1108 }
1109 attr_nr += c;
1110
1111 if (detailed_run < 2)
1112 return 0;
1113
1114 /* Append very detailed run extra attributes: */
1115 for (c = 0; c < ARRAY_SIZE(very_detailed_attrs); c++) {
1116 pos = perf_evsel__new(very_detailed_attrs + c, c + attr_nr);
1117 if (pos == NULL)
1118 return -1;
1119 perf_evlist__add(evsel_list, pos);
1120 }
1121
1122 if (detailed_run < 3)
1123 return 0;
1124
1125 /* Append very, very detailed run extra attributes: */
1126 for (c = 0; c < ARRAY_SIZE(very_very_detailed_attrs); c++) {
1127 pos = perf_evsel__new(very_very_detailed_attrs + c, c + attr_nr);
1128 if (pos == NULL)
1129 return -1;
1130 perf_evlist__add(evsel_list, pos);
1131 }
1132
1133
1134 return 0;
1135}
1136
644int cmd_stat(int argc, const char **argv, const char *prefix __used) 1137int cmd_stat(int argc, const char **argv, const char *prefix __used)
645{ 1138{
646 struct perf_evsel *pos; 1139 struct perf_evsel *pos;
@@ -648,6 +1141,10 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
648 1141
649 setlocale(LC_ALL, ""); 1142 setlocale(LC_ALL, "");
650 1143
1144 evsel_list = perf_evlist__new(NULL, NULL);
1145 if (evsel_list == NULL)
1146 return -ENOMEM;
1147
651 argc = parse_options(argc, argv, options, stat_usage, 1148 argc = parse_options(argc, argv, options, stat_usage,
652 PARSE_OPT_STOP_AT_NON_OPTION); 1149 PARSE_OPT_STOP_AT_NON_OPTION);
653 1150
@@ -674,49 +1171,41 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
674 if (run_count <= 0) 1171 if (run_count <= 0)
675 usage_with_options(stat_usage, options); 1172 usage_with_options(stat_usage, options);
676 1173
677 /* no_aggr is for system-wide only */ 1174 /* no_aggr, cgroup are for system-wide only */
678 if (no_aggr && !system_wide) 1175 if ((no_aggr || nr_cgroups) && !system_wide) {
679 usage_with_options(stat_usage, options); 1176 fprintf(stderr, "both cgroup and no-aggregation "
680 1177 "modes only available in system-wide mode\n");
681 /* Set attrs and nr_counters if no event is selected and !null_run */
682 if (!null_run && !nr_counters) {
683 size_t c;
684 1178
685 nr_counters = ARRAY_SIZE(default_attrs); 1179 usage_with_options(stat_usage, options);
686
687 for (c = 0; c < ARRAY_SIZE(default_attrs); ++c) {
688 pos = perf_evsel__new(&default_attrs[c],
689 nr_counters);
690 if (pos == NULL)
691 goto out;
692 list_add(&pos->node, &evsel_list);
693 }
694 } 1180 }
695 1181
1182 if (add_default_attributes())
1183 goto out;
1184
696 if (target_pid != -1) 1185 if (target_pid != -1)
697 target_tid = target_pid; 1186 target_tid = target_pid;
698 1187
699 threads = thread_map__new(target_pid, target_tid); 1188 evsel_list->threads = thread_map__new(target_pid, target_tid);
700 if (threads == NULL) { 1189 if (evsel_list->threads == NULL) {
701 pr_err("Problems finding threads of monitor\n"); 1190 pr_err("Problems finding threads of monitor\n");
702 usage_with_options(stat_usage, options); 1191 usage_with_options(stat_usage, options);
703 } 1192 }
704 1193
705 if (system_wide) 1194 if (system_wide)
706 cpus = cpu_map__new(cpu_list); 1195 evsel_list->cpus = cpu_map__new(cpu_list);
707 else 1196 else
708 cpus = cpu_map__dummy_new(); 1197 evsel_list->cpus = cpu_map__dummy_new();
709 1198
710 if (cpus == NULL) { 1199 if (evsel_list->cpus == NULL) {
711 perror("failed to parse CPUs map"); 1200 perror("failed to parse CPUs map");
712 usage_with_options(stat_usage, options); 1201 usage_with_options(stat_usage, options);
713 return -1; 1202 return -1;
714 } 1203 }
715 1204
716 list_for_each_entry(pos, &evsel_list, node) { 1205 list_for_each_entry(pos, &evsel_list->entries, node) {
717 if (perf_evsel__alloc_stat_priv(pos) < 0 || 1206 if (perf_evsel__alloc_stat_priv(pos) < 0 ||
718 perf_evsel__alloc_counts(pos, cpus->nr) < 0 || 1207 perf_evsel__alloc_counts(pos, evsel_list->cpus->nr) < 0 ||
719 perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0) 1208 perf_evsel__alloc_fd(pos, evsel_list->cpus->nr, evsel_list->threads->nr) < 0)
720 goto out_free_fd; 1209 goto out_free_fd;
721 } 1210 }
722 1211
@@ -735,17 +1224,20 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
735 for (run_idx = 0; run_idx < run_count; run_idx++) { 1224 for (run_idx = 0; run_idx < run_count; run_idx++) {
736 if (run_count != 1 && verbose) 1225 if (run_count != 1 && verbose)
737 fprintf(stderr, "[ perf stat: executing run #%d ... ]\n", run_idx + 1); 1226 fprintf(stderr, "[ perf stat: executing run #%d ... ]\n", run_idx + 1);
1227
1228 if (sync_run)
1229 sync();
1230
738 status = run_perf_stat(argc, argv); 1231 status = run_perf_stat(argc, argv);
739 } 1232 }
740 1233
741 if (status != -1) 1234 if (status != -1)
742 print_stat(argc, argv); 1235 print_stat(argc, argv);
743out_free_fd: 1236out_free_fd:
744 list_for_each_entry(pos, &evsel_list, node) 1237 list_for_each_entry(pos, &evsel_list->entries, node)
745 perf_evsel__free_stat_priv(pos); 1238 perf_evsel__free_stat_priv(pos);
746 perf_evsel_list__delete(); 1239 perf_evlist__delete_maps(evsel_list);
747out: 1240out:
748 thread_map__delete(threads); 1241 perf_evlist__delete(evsel_list);
749 threads = NULL;
750 return status; 1242 return status;
751} 1243}
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 5dcdba653d70..55f4c76f2821 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -7,10 +7,12 @@
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"
15#include "../../include/linux/hw_breakpoint.h"
14 16
15static long page_size; 17static long page_size;
16 18
@@ -238,14 +240,14 @@ out:
238#include "util/evsel.h" 240#include "util/evsel.h"
239#include <sys/types.h> 241#include <sys/types.h>
240 242
241static int trace_event__id(const char *event_name) 243static int trace_event__id(const char *evname)
242{ 244{
243 char *filename; 245 char *filename;
244 int err = -1, fd; 246 int err = -1, fd;
245 247
246 if (asprintf(&filename, 248 if (asprintf(&filename,
247 "/sys/kernel/debug/tracing/events/syscalls/%s/id", 249 "%s/syscalls/%s/id",
248 event_name) < 0) 250 debugfs_path, evname) < 0)
249 return -1; 251 return -1;
250 252
251 fd = open(filename, O_RDONLY); 253 fd = open(filename, O_RDONLY);
@@ -289,7 +291,7 @@ static int test__open_syscall_event(void)
289 goto out_thread_map_delete; 291 goto out_thread_map_delete;
290 } 292 }
291 293
292 if (perf_evsel__open_per_thread(evsel, threads) < 0) { 294 if (perf_evsel__open_per_thread(evsel, threads, false) < 0) {
293 pr_debug("failed to open counter: %s, " 295 pr_debug("failed to open counter: %s, "
294 "tweak /proc/sys/kernel/perf_event_paranoid?\n", 296 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
295 strerror(errno)); 297 strerror(errno));
@@ -302,7 +304,7 @@ static int test__open_syscall_event(void)
302 } 304 }
303 305
304 if (perf_evsel__read_on_cpu(evsel, 0, 0) < 0) { 306 if (perf_evsel__read_on_cpu(evsel, 0, 0) < 0) {
305 pr_debug("perf_evsel__open_read_on_cpu\n"); 307 pr_debug("perf_evsel__read_on_cpu\n");
306 goto out_close_fd; 308 goto out_close_fd;
307 } 309 }
308 310
@@ -347,9 +349,9 @@ static int test__open_syscall_event_on_all_cpus(void)
347 } 349 }
348 350
349 cpus = cpu_map__new(NULL); 351 cpus = cpu_map__new(NULL);
350 if (threads == NULL) { 352 if (cpus == NULL) {
351 pr_debug("thread_map__new\n"); 353 pr_debug("cpu_map__new\n");
352 return -1; 354 goto out_thread_map_delete;
353 } 355 }
354 356
355 357
@@ -364,7 +366,7 @@ static int test__open_syscall_event_on_all_cpus(void)
364 goto out_thread_map_delete; 366 goto out_thread_map_delete;
365 } 367 }
366 368
367 if (perf_evsel__open(evsel, cpus, threads) < 0) { 369 if (perf_evsel__open(evsel, cpus, threads, false) < 0) {
368 pr_debug("failed to open counter: %s, " 370 pr_debug("failed to open counter: %s, "
369 "tweak /proc/sys/kernel/perf_event_paranoid?\n", 371 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
370 strerror(errno)); 372 strerror(errno));
@@ -408,6 +410,8 @@ static int test__open_syscall_event_on_all_cpus(void)
408 goto out_close_fd; 410 goto out_close_fd;
409 } 411 }
410 412
413 err = 0;
414
411 for (cpu = 0; cpu < cpus->nr; ++cpu) { 415 for (cpu = 0; cpu < cpus->nr; ++cpu) {
412 unsigned int expected; 416 unsigned int expected;
413 417
@@ -415,19 +419,19 @@ static int test__open_syscall_event_on_all_cpus(void)
415 continue; 419 continue;
416 420
417 if (perf_evsel__read_on_cpu(evsel, cpu, 0) < 0) { 421 if (perf_evsel__read_on_cpu(evsel, cpu, 0) < 0) {
418 pr_debug("perf_evsel__open_read_on_cpu\n"); 422 pr_debug("perf_evsel__read_on_cpu\n");
419 goto out_close_fd; 423 err = -1;
424 break;
420 } 425 }
421 426
422 expected = nr_open_calls + cpu; 427 expected = nr_open_calls + cpu;
423 if (evsel->counts->cpu[cpu].val != expected) { 428 if (evsel->counts->cpu[cpu].val != expected) {
424 pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls on cpu %d, got %" PRIu64 "\n", 429 pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls on cpu %d, got %" PRIu64 "\n",
425 expected, cpus->map[cpu], evsel->counts->cpu[cpu].val); 430 expected, cpus->map[cpu], evsel->counts->cpu[cpu].val);
426 goto out_close_fd; 431 err = -1;
427 } 432 }
428 } 433 }
429 434
430 err = 0;
431out_close_fd: 435out_close_fd:
432 perf_evsel__close_fd(evsel, 1, threads->nr); 436 perf_evsel__close_fd(evsel, 1, threads->nr);
433out_evsel_delete: 437out_evsel_delete:
@@ -437,6 +441,406 @@ out_thread_map_delete:
437 return err; 441 return err;
438} 442}
439 443
444/*
445 * This test will generate random numbers of calls to some getpid syscalls,
446 * then establish an mmap for a group of events that are created to monitor
447 * the syscalls.
448 *
449 * It will receive the events, using mmap, use its PERF_SAMPLE_ID generated
450 * sample.id field to map back to its respective perf_evsel instance.
451 *
452 * Then it checks if the number of syscalls reported as perf events by
453 * the kernel corresponds to the number of syscalls made.
454 */
455static int test__basic_mmap(void)
456{
457 int err = -1;
458 union perf_event *event;
459 struct thread_map *threads;
460 struct cpu_map *cpus;
461 struct perf_evlist *evlist;
462 struct perf_event_attr attr = {
463 .type = PERF_TYPE_TRACEPOINT,
464 .read_format = PERF_FORMAT_ID,
465 .sample_type = PERF_SAMPLE_ID,
466 .watermark = 0,
467 };
468 cpu_set_t cpu_set;
469 const char *syscall_names[] = { "getsid", "getppid", "getpgrp",
470 "getpgid", };
471 pid_t (*syscalls[])(void) = { (void *)getsid, getppid, getpgrp,
472 (void*)getpgid };
473#define nsyscalls ARRAY_SIZE(syscall_names)
474 int ids[nsyscalls];
475 unsigned int nr_events[nsyscalls],
476 expected_nr_events[nsyscalls], i, j;
477 struct perf_evsel *evsels[nsyscalls], *evsel;
478 int sample_size = __perf_evsel__sample_size(attr.sample_type);
479
480 for (i = 0; i < nsyscalls; ++i) {
481 char name[64];
482
483 snprintf(name, sizeof(name), "sys_enter_%s", syscall_names[i]);
484 ids[i] = trace_event__id(name);
485 if (ids[i] < 0) {
486 pr_debug("Is debugfs mounted on /sys/kernel/debug?\n");
487 return -1;
488 }
489 nr_events[i] = 0;
490 expected_nr_events[i] = random() % 257;
491 }
492
493 threads = thread_map__new(-1, getpid());
494 if (threads == NULL) {
495 pr_debug("thread_map__new\n");
496 return -1;
497 }
498
499 cpus = cpu_map__new(NULL);
500 if (cpus == NULL) {
501 pr_debug("cpu_map__new\n");
502 goto out_free_threads;
503 }
504
505 CPU_ZERO(&cpu_set);
506 CPU_SET(cpus->map[0], &cpu_set);
507 sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
508 if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) {
509 pr_debug("sched_setaffinity() failed on CPU %d: %s ",
510 cpus->map[0], strerror(errno));
511 goto out_free_cpus;
512 }
513
514 evlist = perf_evlist__new(cpus, threads);
515 if (evlist == NULL) {
516 pr_debug("perf_evlist__new\n");
517 goto out_free_cpus;
518 }
519
520 /* anonymous union fields, can't be initialized above */
521 attr.wakeup_events = 1;
522 attr.sample_period = 1;
523
524 for (i = 0; i < nsyscalls; ++i) {
525 attr.config = ids[i];
526 evsels[i] = perf_evsel__new(&attr, i);
527 if (evsels[i] == NULL) {
528 pr_debug("perf_evsel__new\n");
529 goto out_free_evlist;
530 }
531
532 perf_evlist__add(evlist, evsels[i]);
533
534 if (perf_evsel__open(evsels[i], cpus, threads, false) < 0) {
535 pr_debug("failed to open counter: %s, "
536 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
537 strerror(errno));
538 goto out_close_fd;
539 }
540 }
541
542 if (perf_evlist__mmap(evlist, 128, true) < 0) {
543 pr_debug("failed to mmap events: %d (%s)\n", errno,
544 strerror(errno));
545 goto out_close_fd;
546 }
547
548 for (i = 0; i < nsyscalls; ++i)
549 for (j = 0; j < expected_nr_events[i]; ++j) {
550 int foo = syscalls[i]();
551 ++foo;
552 }
553
554 while ((event = perf_evlist__mmap_read(evlist, 0)) != NULL) {
555 struct perf_sample sample;
556
557 if (event->header.type != PERF_RECORD_SAMPLE) {
558 pr_debug("unexpected %s event\n",
559 perf_event__name(event->header.type));
560 goto out_munmap;
561 }
562
563 err = perf_event__parse_sample(event, attr.sample_type, sample_size,
564 false, &sample);
565 if (err) {
566 pr_err("Can't parse sample, err = %d\n", err);
567 goto out_munmap;
568 }
569
570 evsel = perf_evlist__id2evsel(evlist, sample.id);
571 if (evsel == NULL) {
572 pr_debug("event with id %" PRIu64
573 " doesn't map to an evsel\n", sample.id);
574 goto out_munmap;
575 }
576 nr_events[evsel->idx]++;
577 }
578
579 list_for_each_entry(evsel, &evlist->entries, node) {
580 if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) {
581 pr_debug("expected %d %s events, got %d\n",
582 expected_nr_events[evsel->idx],
583 event_name(evsel), nr_events[evsel->idx]);
584 goto out_munmap;
585 }
586 }
587
588 err = 0;
589out_munmap:
590 perf_evlist__munmap(evlist);
591out_close_fd:
592 for (i = 0; i < nsyscalls; ++i)
593 perf_evsel__close_fd(evsels[i], 1, threads->nr);
594out_free_evlist:
595 perf_evlist__delete(evlist);
596out_free_cpus:
597 cpu_map__delete(cpus);
598out_free_threads:
599 thread_map__delete(threads);
600 return err;
601#undef nsyscalls
602}
603
604#define TEST_ASSERT_VAL(text, cond) \
605do { \
606 if (!cond) { \
607 pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
608 return -1; \
609 } \
610} while (0)
611
612static int test__checkevent_tracepoint(struct perf_evlist *evlist)
613{
614 struct perf_evsel *evsel = list_entry(evlist->entries.next,
615 struct perf_evsel, node);
616
617 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
618 TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
619 TEST_ASSERT_VAL("wrong sample_type",
620 (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) ==
621 evsel->attr.sample_type);
622 TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
623 return 0;
624}
625
626static int test__checkevent_tracepoint_multi(struct perf_evlist *evlist)
627{
628 struct perf_evsel *evsel;
629
630 TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1);
631
632 list_for_each_entry(evsel, &evlist->entries, node) {
633 TEST_ASSERT_VAL("wrong type",
634 PERF_TYPE_TRACEPOINT == evsel->attr.type);
635 TEST_ASSERT_VAL("wrong sample_type",
636 (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU)
637 == evsel->attr.sample_type);
638 TEST_ASSERT_VAL("wrong sample_period",
639 1 == evsel->attr.sample_period);
640 }
641 return 0;
642}
643
644static int test__checkevent_raw(struct perf_evlist *evlist)
645{
646 struct perf_evsel *evsel = list_entry(evlist->entries.next,
647 struct perf_evsel, node);
648
649 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
650 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
651 TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
652 return 0;
653}
654
655static int test__checkevent_numeric(struct perf_evlist *evlist)
656{
657 struct perf_evsel *evsel = list_entry(evlist->entries.next,
658 struct perf_evsel, node);
659
660 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
661 TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type);
662 TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
663 return 0;
664}
665
666static int test__checkevent_symbolic_name(struct perf_evlist *evlist)
667{
668 struct perf_evsel *evsel = list_entry(evlist->entries.next,
669 struct perf_evsel, node);
670
671 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
672 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
673 TEST_ASSERT_VAL("wrong config",
674 PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config);
675 return 0;
676}
677
678static int test__checkevent_symbolic_alias(struct perf_evlist *evlist)
679{
680 struct perf_evsel *evsel = list_entry(evlist->entries.next,
681 struct perf_evsel, node);
682
683 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
684 TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->attr.type);
685 TEST_ASSERT_VAL("wrong config",
686 PERF_COUNT_SW_PAGE_FAULTS == evsel->attr.config);
687 return 0;
688}
689
690static int test__checkevent_genhw(struct perf_evlist *evlist)
691{
692 struct perf_evsel *evsel = list_entry(evlist->entries.next,
693 struct perf_evsel, node);
694
695 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
696 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HW_CACHE == evsel->attr.type);
697 TEST_ASSERT_VAL("wrong config", (1 << 16) == evsel->attr.config);
698 return 0;
699}
700
701static int test__checkevent_breakpoint(struct perf_evlist *evlist)
702{
703 struct perf_evsel *evsel = list_entry(evlist->entries.next,
704 struct perf_evsel, node);
705
706 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
707 TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
708 TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
709 TEST_ASSERT_VAL("wrong bp_type", (HW_BREAKPOINT_R | HW_BREAKPOINT_W) ==
710 evsel->attr.bp_type);
711 TEST_ASSERT_VAL("wrong bp_len", HW_BREAKPOINT_LEN_4 ==
712 evsel->attr.bp_len);
713 return 0;
714}
715
716static int test__checkevent_breakpoint_x(struct perf_evlist *evlist)
717{
718 struct perf_evsel *evsel = list_entry(evlist->entries.next,
719 struct perf_evsel, node);
720
721 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
722 TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
723 TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
724 TEST_ASSERT_VAL("wrong bp_type",
725 HW_BREAKPOINT_X == evsel->attr.bp_type);
726 TEST_ASSERT_VAL("wrong bp_len", sizeof(long) == evsel->attr.bp_len);
727 return 0;
728}
729
730static int test__checkevent_breakpoint_r(struct perf_evlist *evlist)
731{
732 struct perf_evsel *evsel = list_entry(evlist->entries.next,
733 struct perf_evsel, node);
734
735 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
736 TEST_ASSERT_VAL("wrong type",
737 PERF_TYPE_BREAKPOINT == evsel->attr.type);
738 TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
739 TEST_ASSERT_VAL("wrong bp_type",
740 HW_BREAKPOINT_R == evsel->attr.bp_type);
741 TEST_ASSERT_VAL("wrong bp_len",
742 HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len);
743 return 0;
744}
745
746static int test__checkevent_breakpoint_w(struct perf_evlist *evlist)
747{
748 struct perf_evsel *evsel = list_entry(evlist->entries.next,
749 struct perf_evsel, node);
750
751 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
752 TEST_ASSERT_VAL("wrong type",
753 PERF_TYPE_BREAKPOINT == evsel->attr.type);
754 TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
755 TEST_ASSERT_VAL("wrong bp_type",
756 HW_BREAKPOINT_W == evsel->attr.bp_type);
757 TEST_ASSERT_VAL("wrong bp_len",
758 HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len);
759 return 0;
760}
761
762static struct test__event_st {
763 const char *name;
764 __u32 type;
765 int (*check)(struct perf_evlist *evlist);
766} test__events[] = {
767 {
768 .name = "syscalls:sys_enter_open",
769 .check = test__checkevent_tracepoint,
770 },
771 {
772 .name = "syscalls:*",
773 .check = test__checkevent_tracepoint_multi,
774 },
775 {
776 .name = "r1",
777 .check = test__checkevent_raw,
778 },
779 {
780 .name = "1:1",
781 .check = test__checkevent_numeric,
782 },
783 {
784 .name = "instructions",
785 .check = test__checkevent_symbolic_name,
786 },
787 {
788 .name = "faults",
789 .check = test__checkevent_symbolic_alias,
790 },
791 {
792 .name = "L1-dcache-load-miss",
793 .check = test__checkevent_genhw,
794 },
795 {
796 .name = "mem:0",
797 .check = test__checkevent_breakpoint,
798 },
799 {
800 .name = "mem:0:x",
801 .check = test__checkevent_breakpoint_x,
802 },
803 {
804 .name = "mem:0:r",
805 .check = test__checkevent_breakpoint_r,
806 },
807 {
808 .name = "mem:0:w",
809 .check = test__checkevent_breakpoint_w,
810 },
811};
812
813#define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st))
814
815static int test__parse_events(void)
816{
817 struct perf_evlist *evlist;
818 u_int i;
819 int ret = 0;
820
821 for (i = 0; i < TEST__EVENTS_CNT; i++) {
822 struct test__event_st *e = &test__events[i];
823
824 evlist = perf_evlist__new(NULL, NULL);
825 if (evlist == NULL)
826 break;
827
828 ret = parse_events(evlist, e->name, 0);
829 if (ret) {
830 pr_debug("failed to parse event '%s', err %d\n",
831 e->name, ret);
832 break;
833 }
834
835 ret = e->check(evlist);
836 if (ret)
837 break;
838
839 perf_evlist__delete(evlist);
840 }
841
842 return ret;
843}
440static struct test { 844static struct test {
441 const char *desc; 845 const char *desc;
442 int (*func)(void); 846 int (*func)(void);
@@ -454,6 +858,14 @@ static struct test {
454 .func = test__open_syscall_event_on_all_cpus, 858 .func = test__open_syscall_event_on_all_cpus,
455 }, 859 },
456 { 860 {
861 .desc = "read samples using the mmap interface",
862 .func = test__basic_mmap,
863 },
864 {
865 .desc = "parse events tests",
866 .func = test__parse_events,
867 },
868 {
457 .func = NULL, 869 .func = NULL,
458 }, 870 },
459}; 871};
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 0ace786e83e0..aa26f4d66d10 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -273,21 +273,24 @@ static int cpus_cstate_state[MAX_CPUS];
273static u64 cpus_pstate_start_times[MAX_CPUS]; 273static u64 cpus_pstate_start_times[MAX_CPUS];
274static u64 cpus_pstate_state[MAX_CPUS]; 274static u64 cpus_pstate_state[MAX_CPUS];
275 275
276static 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,
277 struct perf_session *session __used) 278 struct perf_session *session __used)
278{ 279{
279 pid_set_comm(event->comm.tid, event->comm.comm); 280 pid_set_comm(event->comm.tid, event->comm.comm);
280 return 0; 281 return 0;
281} 282}
282 283
283static 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,
284 struct perf_session *session __used) 286 struct perf_session *session __used)
285{ 287{
286 pid_fork(event->fork.pid, event->fork.ppid, event->fork.time); 288 pid_fork(event->fork.pid, event->fork.ppid, event->fork.time);
287 return 0; 289 return 0;
288} 290}
289 291
290static 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,
291 struct perf_session *session __used) 294 struct perf_session *session __used)
292{ 295{
293 pid_exit(event->fork.pid, event->fork.time); 296 pid_exit(event->fork.pid, event->fork.time);
@@ -483,8 +486,9 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te)
483} 486}
484 487
485 488
486static int process_sample_event(event_t *event __used, 489static int process_sample_event(union perf_event *event __used,
487 struct sample_data *sample, 490 struct perf_sample *sample,
491 struct perf_evsel *evsel __used,
488 struct perf_session *session) 492 struct perf_session *session)
489{ 493{
490 struct trace_entry *te; 494 struct trace_entry *te;
@@ -503,6 +507,16 @@ static int process_sample_event(event_t *event __used,
503 struct power_entry_old *peo; 507 struct power_entry_old *peo;
504 peo = (void *)te; 508 peo = (void *)te;
505#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 */
506 event_str = perf_header__find_event(te->type); 520 event_str = perf_header__find_event(te->type);
507 521
508 if (!event_str) 522 if (!event_str)
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 5a29d9cd9486..a43433f08300 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -20,11 +20,16 @@
20 20
21#include "perf.h" 21#include "perf.h"
22 22
23#include "util/annotate.h"
24#include "util/cache.h"
23#include "util/color.h" 25#include "util/color.h"
26#include "util/evlist.h"
24#include "util/evsel.h" 27#include "util/evsel.h"
25#include "util/session.h" 28#include "util/session.h"
26#include "util/symbol.h" 29#include "util/symbol.h"
27#include "util/thread.h" 30#include "util/thread.h"
31#include "util/thread_map.h"
32#include "util/top.h"
28#include "util/util.h" 33#include "util/util.h"
29#include <linux/rbtree.h> 34#include <linux/rbtree.h>
30#include "util/parse-options.h" 35#include "util/parse-options.h"
@@ -45,7 +50,6 @@
45#include <errno.h> 50#include <errno.h>
46#include <time.h> 51#include <time.h>
47#include <sched.h> 52#include <sched.h>
48#include <pthread.h>
49 53
50#include <sys/syscall.h> 54#include <sys/syscall.h>
51#include <sys/ioctl.h> 55#include <sys/ioctl.h>
@@ -58,87 +62,44 @@
58#include <linux/unistd.h> 62#include <linux/unistd.h>
59#include <linux/types.h> 63#include <linux/types.h>
60 64
61#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) 65static struct perf_top top = {
66 .count_filter = 5,
67 .delay_secs = 2,
68 .display_weighted = -1,
69 .target_pid = -1,
70 .target_tid = -1,
71 .active_symbols = LIST_HEAD_INIT(top.active_symbols),
72 .active_symbols_lock = PTHREAD_MUTEX_INITIALIZER,
73 .active_symbols_cond = PTHREAD_COND_INITIALIZER,
74 .freq = 1000, /* 1 KHz */
75};
62 76
63static bool system_wide = false; 77static bool system_wide = false;
64 78
65static int default_interval = 0; 79static bool use_tui, use_stdio;
66 80
67static int count_filter = 5; 81static int default_interval = 0;
68static int print_entries;
69 82
70static int target_pid = -1; 83static bool kptr_restrict_warned;
71static int target_tid = -1; 84static bool vmlinux_warned;
72static struct thread_map *threads;
73static bool inherit = false; 85static bool inherit = false;
74static struct cpu_map *cpus;
75static int realtime_prio = 0; 86static int realtime_prio = 0;
76static bool group = false; 87static bool group = false;
77static unsigned int page_size; 88static unsigned int page_size;
78static unsigned int mmap_pages = 16; 89static unsigned int mmap_pages = 128;
79static int freq = 1000; /* 1 KHz */
80 90
81static int delay_secs = 2;
82static bool zero = false;
83static bool dump_symtab = false; 91static bool dump_symtab = false;
84 92
85static bool hide_kernel_symbols = false;
86static bool hide_user_symbols = false;
87static struct winsize winsize; 93static struct winsize winsize;
88 94
89/*
90 * Source
91 */
92
93struct source_line {
94 u64 eip;
95 unsigned long count[MAX_COUNTERS];
96 char *line;
97 struct source_line *next;
98};
99
100static const char *sym_filter = NULL; 95static const char *sym_filter = NULL;
101struct sym_entry *sym_filter_entry = NULL;
102struct sym_entry *sym_filter_entry_sched = NULL; 96struct sym_entry *sym_filter_entry_sched = NULL;
103static int sym_pcnt_filter = 5; 97static int sym_pcnt_filter = 5;
104static int sym_counter = 0;
105static struct perf_evsel *sym_evsel = NULL;
106static int display_weighted = -1;
107static const char *cpu_list;
108
109/*
110 * Symbols
111 */
112
113struct sym_entry_source {
114 struct source_line *source;
115 struct source_line *lines;
116 struct source_line **lines_tail;
117 pthread_mutex_t lock;
118};
119
120struct sym_entry {
121 struct rb_node rb_node;
122 struct list_head node;
123 unsigned long snap_count;
124 double weight;
125 int skip;
126 u16 name_len;
127 u8 origin;
128 struct map *map;
129 struct sym_entry_source *src;
130 unsigned long count[0];
131};
132 98
133/* 99/*
134 * Source functions 100 * Source functions
135 */ 101 */
136 102
137static inline struct symbol *sym_entry__symbol(struct sym_entry *self)
138{
139 return ((void *)self) + symbol_conf.priv_size;
140}
141
142void get_term_dimensions(struct winsize *ws) 103void get_term_dimensions(struct winsize *ws)
143{ 104{
144 char *s = getenv("LINES"); 105 char *s = getenv("LINES");
@@ -163,10 +124,10 @@ void get_term_dimensions(struct winsize *ws)
163 124
164static void update_print_entries(struct winsize *ws) 125static void update_print_entries(struct winsize *ws)
165{ 126{
166 print_entries = ws->ws_row; 127 top.print_entries = ws->ws_row;
167 128
168 if (print_entries > 9) 129 if (top.print_entries > 9)
169 print_entries -= 9; 130 top.print_entries -= 9;
170} 131}
171 132
172static void sig_winch_handler(int sig __used) 133static void sig_winch_handler(int sig __used)
@@ -178,12 +139,9 @@ static void sig_winch_handler(int sig __used)
178static int parse_source(struct sym_entry *syme) 139static int parse_source(struct sym_entry *syme)
179{ 140{
180 struct symbol *sym; 141 struct symbol *sym;
181 struct sym_entry_source *source; 142 struct annotation *notes;
182 struct map *map; 143 struct map *map;
183 FILE *file; 144 int err = -1;
184 char command[PATH_MAX*2];
185 const char *path;
186 u64 len;
187 145
188 if (!syme) 146 if (!syme)
189 return -1; 147 return -1;
@@ -194,411 +152,137 @@ static int parse_source(struct sym_entry *syme)
194 /* 152 /*
195 * We can't annotate with just /proc/kallsyms 153 * We can't annotate with just /proc/kallsyms
196 */ 154 */
197 if (map->dso->origin == DSO__ORIG_KERNEL) 155 if (map->dso->symtab_type == SYMTAB__KALLSYMS) {
156 pr_err("Can't annotate %s: No vmlinux file was found in the "
157 "path\n", sym->name);
158 sleep(1);
198 return -1; 159 return -1;
199
200 if (syme->src == NULL) {
201 syme->src = zalloc(sizeof(*source));
202 if (syme->src == NULL)
203 return -1;
204 pthread_mutex_init(&syme->src->lock, NULL);
205 } 160 }
206 161
207 source = syme->src; 162 notes = symbol__annotation(sym);
208 163 if (notes->src != NULL) {
209 if (source->lines) { 164 pthread_mutex_lock(&notes->lock);
210 pthread_mutex_lock(&source->lock);
211 goto out_assign; 165 goto out_assign;
212 } 166 }
213 path = map->dso->long_name;
214
215 len = sym->end - sym->start;
216
217 sprintf(command,
218 "objdump --start-address=%#0*" PRIx64 " --stop-address=%#0*" PRIx64 " -dS %s",
219 BITS_PER_LONG / 4, map__rip_2objdump(map, sym->start),
220 BITS_PER_LONG / 4, map__rip_2objdump(map, sym->end), path);
221
222 file = popen(command, "r");
223 if (!file)
224 return -1;
225
226 pthread_mutex_lock(&source->lock);
227 source->lines_tail = &source->lines;
228 while (!feof(file)) {
229 struct source_line *src;
230 size_t dummy = 0;
231 char *c, *sep;
232
233 src = malloc(sizeof(struct source_line));
234 assert(src != NULL);
235 memset(src, 0, sizeof(struct source_line));
236
237 if (getline(&src->line, &dummy, file) < 0)
238 break;
239 if (!src->line)
240 break;
241 167
242 c = strchr(src->line, '\n'); 168 pthread_mutex_lock(&notes->lock);
243 if (c)
244 *c = 0;
245 169
246 src->next = NULL; 170 if (symbol__alloc_hist(sym, top.evlist->nr_entries) < 0) {
247 *source->lines_tail = src; 171 pthread_mutex_unlock(&notes->lock);
248 source->lines_tail = &src->next; 172 pr_err("Not enough memory for annotating '%s' symbol!\n",
249 173 sym->name);
250 src->eip = strtoull(src->line, &sep, 16); 174 sleep(1);
251 if (*sep == ':') 175 return err;
252 src->eip = map__objdump_2ip(map, src->eip);
253 else /* this line has no ip info (e.g. source line) */
254 src->eip = 0;
255 } 176 }
256 pclose(file); 177
178 err = symbol__annotate(sym, syme->map, 0);
179 if (err == 0) {
257out_assign: 180out_assign:
258 sym_filter_entry = syme; 181 top.sym_filter_entry = syme;
259 pthread_mutex_unlock(&source->lock); 182 }
260 return 0; 183
184 pthread_mutex_unlock(&notes->lock);
185 return err;
261} 186}
262 187
263static void __zero_source_counters(struct sym_entry *syme) 188static void __zero_source_counters(struct sym_entry *syme)
264{ 189{
265 int i; 190 struct symbol *sym = sym_entry__symbol(syme);
266 struct source_line *line; 191 symbol__annotate_zero_histograms(sym);
267
268 line = syme->src->lines;
269 while (line) {
270 for (i = 0; i < nr_counters; i++)
271 line->count[i] = 0;
272 line = line->next;
273 }
274} 192}
275 193
276static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip) 194static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip)
277{ 195{
278 struct source_line *line; 196 struct annotation *notes;
279 197 struct symbol *sym;
280 if (syme != sym_filter_entry)
281 return;
282 198
283 if (pthread_mutex_trylock(&syme->src->lock)) 199 if (syme != top.sym_filter_entry)
284 return; 200 return;
285 201
286 if (syme->src == NULL || syme->src->source == NULL) 202 sym = sym_entry__symbol(syme);
287 goto out_unlock; 203 notes = symbol__annotation(sym);
288
289 for (line = syme->src->lines; line; line = line->next) {
290 /* skip lines without IP info */
291 if (line->eip == 0)
292 continue;
293 if (line->eip == ip) {
294 line->count[counter]++;
295 break;
296 }
297 if (line->eip > ip)
298 break;
299 }
300out_unlock:
301 pthread_mutex_unlock(&syme->src->lock);
302}
303
304#define PATTERN_LEN (BITS_PER_LONG / 4 + 2)
305
306static void lookup_sym_source(struct sym_entry *syme)
307{
308 struct symbol *symbol = sym_entry__symbol(syme);
309 struct source_line *line;
310 char pattern[PATTERN_LEN + 1];
311
312 sprintf(pattern, "%0*" PRIx64 " <", BITS_PER_LONG / 4,
313 map__rip_2objdump(syme->map, symbol->start));
314
315 pthread_mutex_lock(&syme->src->lock);
316 for (line = syme->src->lines; line; line = line->next) {
317 if (memcmp(line->line, pattern, PATTERN_LEN) == 0) {
318 syme->src->source = line;
319 break;
320 }
321 }
322 pthread_mutex_unlock(&syme->src->lock);
323}
324 204
325static void show_lines(struct source_line *queue, int count, int total) 205 if (pthread_mutex_trylock(&notes->lock))
326{ 206 return;
327 int i;
328 struct source_line *line;
329 207
330 line = queue; 208 ip = syme->map->map_ip(syme->map, ip);
331 for (i = 0; i < count; i++) { 209 symbol__inc_addr_samples(sym, syme->map, counter, ip);
332 float pcnt = 100.0*(float)line->count[sym_counter]/(float)total;
333 210
334 printf("%8li %4.1f%%\t%s\n", line->count[sym_counter], pcnt, line->line); 211 pthread_mutex_unlock(&notes->lock);
335 line = line->next;
336 }
337} 212}
338 213
339#define TRACE_COUNT 3
340
341static void show_details(struct sym_entry *syme) 214static void show_details(struct sym_entry *syme)
342{ 215{
216 struct annotation *notes;
343 struct symbol *symbol; 217 struct symbol *symbol;
344 struct source_line *line; 218 int more;
345 struct source_line *line_queue = NULL;
346 int displayed = 0;
347 int line_queue_count = 0, total = 0, more = 0;
348 219
349 if (!syme) 220 if (!syme)
350 return; 221 return;
351 222
352 if (!syme->src->source)
353 lookup_sym_source(syme);
354
355 if (!syme->src->source)
356 return;
357
358 symbol = sym_entry__symbol(syme); 223 symbol = sym_entry__symbol(syme);
359 printf("Showing %s for %s\n", event_name(sym_evsel), symbol->name); 224 notes = symbol__annotation(symbol);
360 printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter);
361 225
362 pthread_mutex_lock(&syme->src->lock); 226 pthread_mutex_lock(&notes->lock);
363 line = syme->src->source;
364 while (line) {
365 total += line->count[sym_counter];
366 line = line->next;
367 }
368
369 line = syme->src->source;
370 while (line) {
371 float pcnt = 0.0;
372
373 if (!line_queue_count)
374 line_queue = line;
375 line_queue_count++;
376
377 if (line->count[sym_counter])
378 pcnt = 100.0 * line->count[sym_counter] / (float)total;
379 if (pcnt >= (float)sym_pcnt_filter) {
380 if (displayed <= print_entries)
381 show_lines(line_queue, line_queue_count, total);
382 else more++;
383 displayed += line_queue_count;
384 line_queue_count = 0;
385 line_queue = NULL;
386 } else if (line_queue_count > TRACE_COUNT) {
387 line_queue = line_queue->next;
388 line_queue_count--;
389 }
390
391 line->count[sym_counter] = zero ? 0 : line->count[sym_counter] * 7 / 8;
392 line = line->next;
393 }
394 pthread_mutex_unlock(&syme->src->lock);
395 if (more)
396 printf("%d lines not displayed, maybe increase display entries [e]\n", more);
397}
398
399/*
400 * Symbols will be added here in event__process_sample and will get out
401 * after decayed.
402 */
403static LIST_HEAD(active_symbols);
404static pthread_mutex_t active_symbols_lock = PTHREAD_MUTEX_INITIALIZER;
405
406/*
407 * Ordering weight: count-1 * count-2 * ... / count-n
408 */
409static double sym_weight(const struct sym_entry *sym)
410{
411 double weight = sym->snap_count;
412 int counter;
413 227
414 if (!display_weighted) 228 if (notes->src == NULL)
415 return weight; 229 goto out_unlock;
416
417 for (counter = 1; counter < nr_counters-1; counter++)
418 weight *= sym->count[counter];
419 230
420 weight /= (sym->count[counter] + 1); 231 printf("Showing %s for %s\n", event_name(top.sym_evsel), symbol->name);
232 printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter);
421 233
422 return weight; 234 more = symbol__annotate_printf(symbol, syme->map, top.sym_evsel->idx,
235 0, sym_pcnt_filter, top.print_entries, 4);
236 if (top.zero)
237 symbol__annotate_zero_histogram(symbol, top.sym_evsel->idx);
238 else
239 symbol__annotate_decay_histogram(symbol, top.sym_evsel->idx);
240 if (more != 0)
241 printf("%d lines not displayed, maybe increase display entries [e]\n", more);
242out_unlock:
243 pthread_mutex_unlock(&notes->lock);
423} 244}
424 245
425static long samples;
426static long kernel_samples, us_samples;
427static long exact_samples;
428static long guest_us_samples, guest_kernel_samples;
429static const char CONSOLE_CLEAR[] = ""; 246static const char CONSOLE_CLEAR[] = "";
430 247
431static void __list_insert_active_sym(struct sym_entry *syme) 248static void __list_insert_active_sym(struct sym_entry *syme)
432{ 249{
433 list_add(&syme->node, &active_symbols); 250 list_add(&syme->node, &top.active_symbols);
434}
435
436static void list_remove_active_sym(struct sym_entry *syme)
437{
438 pthread_mutex_lock(&active_symbols_lock);
439 list_del_init(&syme->node);
440 pthread_mutex_unlock(&active_symbols_lock);
441} 251}
442 252
443static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se) 253static void print_sym_table(struct perf_session *session)
444{ 254{
445 struct rb_node **p = &tree->rb_node; 255 char bf[160];
446 struct rb_node *parent = NULL; 256 int printed = 0;
447 struct sym_entry *iter;
448
449 while (*p != NULL) {
450 parent = *p;
451 iter = rb_entry(parent, struct sym_entry, rb_node);
452
453 if (se->weight > iter->weight)
454 p = &(*p)->rb_left;
455 else
456 p = &(*p)->rb_right;
457 }
458
459 rb_link_node(&se->rb_node, parent, p);
460 rb_insert_color(&se->rb_node, tree);
461}
462
463static void print_sym_table(void)
464{
465 int printed = 0, j;
466 struct perf_evsel *counter;
467 int snap = !display_weighted ? sym_counter : 0;
468 float samples_per_sec = samples/delay_secs;
469 float ksamples_per_sec = kernel_samples/delay_secs;
470 float us_samples_per_sec = (us_samples)/delay_secs;
471 float guest_kernel_samples_per_sec = (guest_kernel_samples)/delay_secs;
472 float guest_us_samples_per_sec = (guest_us_samples)/delay_secs;
473 float esamples_percent = (100.0*exact_samples)/samples;
474 float sum_ksamples = 0.0;
475 struct sym_entry *syme, *n;
476 struct rb_root tmp = RB_ROOT;
477 struct rb_node *nd; 257 struct rb_node *nd;
478 int sym_width = 0, dso_width = 0, dso_short_width = 0; 258 struct sym_entry *syme;
259 struct rb_root tmp = RB_ROOT;
479 const int win_width = winsize.ws_col - 1; 260 const int win_width = winsize.ws_col - 1;
480 261 int sym_width, dso_width, dso_short_width;
481 samples = us_samples = kernel_samples = exact_samples = 0; 262 float sum_ksamples = perf_top__decay_samples(&top, &tmp);
482 guest_kernel_samples = guest_us_samples = 0;
483
484 /* Sort the active symbols */
485 pthread_mutex_lock(&active_symbols_lock);
486 syme = list_entry(active_symbols.next, struct sym_entry, node);
487 pthread_mutex_unlock(&active_symbols_lock);
488
489 list_for_each_entry_safe_from(syme, n, &active_symbols, node) {
490 syme->snap_count = syme->count[snap];
491 if (syme->snap_count != 0) {
492
493 if ((hide_user_symbols &&
494 syme->origin == PERF_RECORD_MISC_USER) ||
495 (hide_kernel_symbols &&
496 syme->origin == PERF_RECORD_MISC_KERNEL)) {
497 list_remove_active_sym(syme);
498 continue;
499 }
500 syme->weight = sym_weight(syme);
501 rb_insert_active_sym(&tmp, syme);
502 sum_ksamples += syme->snap_count;
503
504 for (j = 0; j < nr_counters; j++)
505 syme->count[j] = zero ? 0 : syme->count[j] * 7 / 8;
506 } else
507 list_remove_active_sym(syme);
508 }
509 263
510 puts(CONSOLE_CLEAR); 264 puts(CONSOLE_CLEAR);
511 265
512 printf("%-*.*s\n", win_width, win_width, graph_dotted_line); 266 perf_top__header_snprintf(&top, bf, sizeof(bf));
513 if (!perf_guest) { 267 printf("%s\n", bf);
514 printf(" PerfTop:%8.0f irqs/sec kernel:%4.1f%%"
515 " exact: %4.1f%% [",
516 samples_per_sec,
517 100.0 - (100.0 * ((samples_per_sec - ksamples_per_sec) /
518 samples_per_sec)),
519 esamples_percent);
520 } else {
521 printf(" PerfTop:%8.0f irqs/sec kernel:%4.1f%% us:%4.1f%%"
522 " guest kernel:%4.1f%% guest us:%4.1f%%"
523 " exact: %4.1f%% [",
524 samples_per_sec,
525 100.0 - (100.0 * ((samples_per_sec-ksamples_per_sec) /
526 samples_per_sec)),
527 100.0 - (100.0 * ((samples_per_sec-us_samples_per_sec) /
528 samples_per_sec)),
529 100.0 - (100.0 * ((samples_per_sec -
530 guest_kernel_samples_per_sec) /
531 samples_per_sec)),
532 100.0 - (100.0 * ((samples_per_sec -
533 guest_us_samples_per_sec) /
534 samples_per_sec)),
535 esamples_percent);
536 }
537
538 if (nr_counters == 1 || !display_weighted) {
539 struct perf_evsel *first;
540 first = list_entry(evsel_list.next, struct perf_evsel, node);
541 printf("%" PRIu64, (uint64_t)first->attr.sample_period);
542 if (freq)
543 printf("Hz ");
544 else
545 printf(" ");
546 }
547
548 if (!display_weighted)
549 printf("%s", event_name(sym_evsel));
550 else list_for_each_entry(counter, &evsel_list, node) {
551 if (counter->idx)
552 printf("/");
553 268
554 printf("%s", event_name(counter)); 269 perf_top__reset_sample_counters(&top);
555 }
556
557 printf( "], ");
558
559 if (target_pid != -1)
560 printf(" (target_pid: %d", target_pid);
561 else if (target_tid != -1)
562 printf(" (target_tid: %d", target_tid);
563 else
564 printf(" (all");
565
566 if (cpu_list)
567 printf(", CPU%s: %s)\n", cpus->nr > 1 ? "s" : "", cpu_list);
568 else {
569 if (target_tid != -1)
570 printf(")\n");
571 else
572 printf(", %d CPU%s)\n", cpus->nr, cpus->nr > 1 ? "s" : "");
573 }
574 270
575 printf("%-*.*s\n", win_width, win_width, graph_dotted_line); 271 printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
576 272
577 if (sym_filter_entry) { 273 if (session->hists.stats.total_lost != 0) {
578 show_details(sym_filter_entry); 274 color_fprintf(stdout, PERF_COLOR_RED, "WARNING:");
579 return; 275 printf(" LOST %" PRIu64 " events, Check IO/CPU overload\n",
276 session->hists.stats.total_lost);
580 } 277 }
581 278
582 /* 279 if (top.sym_filter_entry) {
583 * Find the longest symbol name that will be displayed 280 show_details(top.sym_filter_entry);
584 */ 281 return;
585 for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
586 syme = rb_entry(nd, struct sym_entry, rb_node);
587 if (++printed > print_entries ||
588 (int)syme->snap_count < count_filter)
589 continue;
590
591 if (syme->map->dso->long_name_len > dso_width)
592 dso_width = syme->map->dso->long_name_len;
593
594 if (syme->map->dso->short_name_len > dso_short_width)
595 dso_short_width = syme->map->dso->short_name_len;
596
597 if (syme->name_len > sym_width)
598 sym_width = syme->name_len;
599 } 282 }
600 283
601 printed = 0; 284 perf_top__find_widths(&top, &tmp, &dso_width, &dso_short_width,
285 &sym_width);
602 286
603 if (sym_width + dso_width > winsize.ws_col - 29) { 287 if (sym_width + dso_width > winsize.ws_col - 29) {
604 dso_width = dso_short_width; 288 dso_width = dso_short_width;
@@ -606,7 +290,7 @@ static void print_sym_table(void)
606 sym_width = winsize.ws_col - dso_width - 29; 290 sym_width = winsize.ws_col - dso_width - 29;
607 } 291 }
608 putchar('\n'); 292 putchar('\n');
609 if (nr_counters == 1) 293 if (top.evlist->nr_entries == 1)
610 printf(" samples pcnt"); 294 printf(" samples pcnt");
611 else 295 else
612 printf(" weight samples pcnt"); 296 printf(" weight samples pcnt");
@@ -615,7 +299,7 @@ static void print_sym_table(void)
615 printf(" RIP "); 299 printf(" RIP ");
616 printf(" %-*.*s DSO\n", sym_width, sym_width, "function"); 300 printf(" %-*.*s DSO\n", sym_width, sym_width, "function");
617 printf(" %s _______ _____", 301 printf(" %s _______ _____",
618 nr_counters == 1 ? " " : "______"); 302 top.evlist->nr_entries == 1 ? " " : "______");
619 if (verbose) 303 if (verbose)
620 printf(" ________________"); 304 printf(" ________________");
621 printf(" %-*.*s", sym_width, sym_width, graph_line); 305 printf(" %-*.*s", sym_width, sym_width, graph_line);
@@ -628,13 +312,14 @@ static void print_sym_table(void)
628 312
629 syme = rb_entry(nd, struct sym_entry, rb_node); 313 syme = rb_entry(nd, struct sym_entry, rb_node);
630 sym = sym_entry__symbol(syme); 314 sym = sym_entry__symbol(syme);
631 if (++printed > print_entries || (int)syme->snap_count < count_filter) 315 if (++printed > top.print_entries ||
316 (int)syme->snap_count < top.count_filter)
632 continue; 317 continue;
633 318
634 pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) / 319 pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) /
635 sum_ksamples)); 320 sum_ksamples));
636 321
637 if (nr_counters == 1 || !display_weighted) 322 if (top.evlist->nr_entries == 1 || !top.display_weighted)
638 printf("%20.2f ", syme->weight); 323 printf("%20.2f ", syme->weight);
639 else 324 else
640 printf("%9.1f %10ld ", syme->weight, syme->snap_count); 325 printf("%9.1f %10ld ", syme->weight, syme->snap_count);
@@ -693,10 +378,8 @@ static void prompt_symbol(struct sym_entry **target, const char *msg)
693 378
694 /* zero counters of active symbol */ 379 /* zero counters of active symbol */
695 if (syme) { 380 if (syme) {
696 pthread_mutex_lock(&syme->src->lock);
697 __zero_source_counters(syme); 381 __zero_source_counters(syme);
698 *target = NULL; 382 *target = NULL;
699 pthread_mutex_unlock(&syme->src->lock);
700 } 383 }
701 384
702 fprintf(stdout, "\n%s: ", msg); 385 fprintf(stdout, "\n%s: ", msg);
@@ -707,11 +390,11 @@ static void prompt_symbol(struct sym_entry **target, const char *msg)
707 if (p) 390 if (p)
708 *p = 0; 391 *p = 0;
709 392
710 pthread_mutex_lock(&active_symbols_lock); 393 pthread_mutex_lock(&top.active_symbols_lock);
711 syme = list_entry(active_symbols.next, struct sym_entry, node); 394 syme = list_entry(top.active_symbols.next, struct sym_entry, node);
712 pthread_mutex_unlock(&active_symbols_lock); 395 pthread_mutex_unlock(&top.active_symbols_lock);
713 396
714 list_for_each_entry_safe_from(syme, n, &active_symbols, node) { 397 list_for_each_entry_safe_from(syme, n, &top.active_symbols, node) {
715 struct symbol *sym = sym_entry__symbol(syme); 398 struct symbol *sym = sym_entry__symbol(syme);
716 399
717 if (!strcmp(buf, sym->name)) { 400 if (!strcmp(buf, sym->name)) {
@@ -735,34 +418,34 @@ static void print_mapped_keys(void)
735{ 418{
736 char *name = NULL; 419 char *name = NULL;
737 420
738 if (sym_filter_entry) { 421 if (top.sym_filter_entry) {
739 struct symbol *sym = sym_entry__symbol(sym_filter_entry); 422 struct symbol *sym = sym_entry__symbol(top.sym_filter_entry);
740 name = sym->name; 423 name = sym->name;
741 } 424 }
742 425
743 fprintf(stdout, "\nMapped keys:\n"); 426 fprintf(stdout, "\nMapped keys:\n");
744 fprintf(stdout, "\t[d] display refresh delay. \t(%d)\n", delay_secs); 427 fprintf(stdout, "\t[d] display refresh delay. \t(%d)\n", top.delay_secs);
745 fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", print_entries); 428 fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", top.print_entries);
746 429
747 if (nr_counters > 1) 430 if (top.evlist->nr_entries > 1)
748 fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(sym_evsel)); 431 fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(top.sym_evsel));
749 432
750 fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter); 433 fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", top.count_filter);
751 434
752 fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter); 435 fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter);
753 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); 436 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL");
754 fprintf(stdout, "\t[S] stop annotation.\n"); 437 fprintf(stdout, "\t[S] stop annotation.\n");
755 438
756 if (nr_counters > 1) 439 if (top.evlist->nr_entries > 1)
757 fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0); 440 fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", top.display_weighted ? 1 : 0);
758 441
759 fprintf(stdout, 442 fprintf(stdout,
760 "\t[K] hide kernel_symbols symbols. \t(%s)\n", 443 "\t[K] hide kernel_symbols symbols. \t(%s)\n",
761 hide_kernel_symbols ? "yes" : "no"); 444 top.hide_kernel_symbols ? "yes" : "no");
762 fprintf(stdout, 445 fprintf(stdout,
763 "\t[U] hide user symbols. \t(%s)\n", 446 "\t[U] hide user symbols. \t(%s)\n",
764 hide_user_symbols ? "yes" : "no"); 447 top.hide_user_symbols ? "yes" : "no");
765 fprintf(stdout, "\t[z] toggle sample zeroing. \t(%d)\n", zero ? 1 : 0); 448 fprintf(stdout, "\t[z] toggle sample zeroing. \t(%d)\n", top.zero ? 1 : 0);
766 fprintf(stdout, "\t[qQ] quit.\n"); 449 fprintf(stdout, "\t[qQ] quit.\n");
767} 450}
768 451
@@ -783,7 +466,7 @@ static int key_mapped(int c)
783 return 1; 466 return 1;
784 case 'E': 467 case 'E':
785 case 'w': 468 case 'w':
786 return nr_counters > 1 ? 1 : 0; 469 return top.evlist->nr_entries > 1 ? 1 : 0;
787 default: 470 default:
788 break; 471 break;
789 } 472 }
@@ -818,47 +501,50 @@ static void handle_keypress(struct perf_session *session, int c)
818 501
819 switch (c) { 502 switch (c) {
820 case 'd': 503 case 'd':
821 prompt_integer(&delay_secs, "Enter display delay"); 504 prompt_integer(&top.delay_secs, "Enter display delay");
822 if (delay_secs < 1) 505 if (top.delay_secs < 1)
823 delay_secs = 1; 506 top.delay_secs = 1;
824 break; 507 break;
825 case 'e': 508 case 'e':
826 prompt_integer(&print_entries, "Enter display entries (lines)"); 509 prompt_integer(&top.print_entries, "Enter display entries (lines)");
827 if (print_entries == 0) { 510 if (top.print_entries == 0) {
828 sig_winch_handler(SIGWINCH); 511 sig_winch_handler(SIGWINCH);
829 signal(SIGWINCH, sig_winch_handler); 512 signal(SIGWINCH, sig_winch_handler);
830 } else 513 } else
831 signal(SIGWINCH, SIG_DFL); 514 signal(SIGWINCH, SIG_DFL);
832 break; 515 break;
833 case 'E': 516 case 'E':
834 if (nr_counters > 1) { 517 if (top.evlist->nr_entries > 1) {
518 /* Select 0 as the default event: */
519 int counter = 0;
520
835 fprintf(stderr, "\nAvailable events:"); 521 fprintf(stderr, "\nAvailable events:");
836 522
837 list_for_each_entry(sym_evsel, &evsel_list, node) 523 list_for_each_entry(top.sym_evsel, &top.evlist->entries, node)
838 fprintf(stderr, "\n\t%d %s", sym_evsel->idx, event_name(sym_evsel)); 524 fprintf(stderr, "\n\t%d %s", top.sym_evsel->idx, event_name(top.sym_evsel));
839 525
840 prompt_integer(&sym_counter, "Enter details event counter"); 526 prompt_integer(&counter, "Enter details event counter");
841 527
842 if (sym_counter >= nr_counters) { 528 if (counter >= top.evlist->nr_entries) {
843 sym_evsel = list_entry(evsel_list.next, struct perf_evsel, node); 529 top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node);
844 sym_counter = 0; 530 fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(top.sym_evsel));
845 fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(sym_evsel));
846 sleep(1); 531 sleep(1);
847 break; 532 break;
848 } 533 }
849 list_for_each_entry(sym_evsel, &evsel_list, node) 534 list_for_each_entry(top.sym_evsel, &top.evlist->entries, node)
850 if (sym_evsel->idx == sym_counter) 535 if (top.sym_evsel->idx == counter)
851 break; 536 break;
852 } else sym_counter = 0; 537 } else
538 top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node);
853 break; 539 break;
854 case 'f': 540 case 'f':
855 prompt_integer(&count_filter, "Enter display event count filter"); 541 prompt_integer(&top.count_filter, "Enter display event count filter");
856 break; 542 break;
857 case 'F': 543 case 'F':
858 prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)"); 544 prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)");
859 break; 545 break;
860 case 'K': 546 case 'K':
861 hide_kernel_symbols = !hide_kernel_symbols; 547 top.hide_kernel_symbols = !top.hide_kernel_symbols;
862 break; 548 break;
863 case 'q': 549 case 'q':
864 case 'Q': 550 case 'Q':
@@ -867,34 +553,50 @@ static void handle_keypress(struct perf_session *session, int c)
867 perf_session__fprintf_dsos(session, stderr); 553 perf_session__fprintf_dsos(session, stderr);
868 exit(0); 554 exit(0);
869 case 's': 555 case 's':
870 prompt_symbol(&sym_filter_entry, "Enter details symbol"); 556 prompt_symbol(&top.sym_filter_entry, "Enter details symbol");
871 break; 557 break;
872 case 'S': 558 case 'S':
873 if (!sym_filter_entry) 559 if (!top.sym_filter_entry)
874 break; 560 break;
875 else { 561 else {
876 struct sym_entry *syme = sym_filter_entry; 562 struct sym_entry *syme = top.sym_filter_entry;
877 563
878 pthread_mutex_lock(&syme->src->lock); 564 top.sym_filter_entry = NULL;
879 sym_filter_entry = NULL;
880 __zero_source_counters(syme); 565 __zero_source_counters(syme);
881 pthread_mutex_unlock(&syme->src->lock);
882 } 566 }
883 break; 567 break;
884 case 'U': 568 case 'U':
885 hide_user_symbols = !hide_user_symbols; 569 top.hide_user_symbols = !top.hide_user_symbols;
886 break; 570 break;
887 case 'w': 571 case 'w':
888 display_weighted = ~display_weighted; 572 top.display_weighted = ~top.display_weighted;
889 break; 573 break;
890 case 'z': 574 case 'z':
891 zero = !zero; 575 top.zero = !top.zero;
892 break; 576 break;
893 default: 577 default:
894 break; 578 break;
895 } 579 }
896} 580}
897 581
582static void *display_thread_tui(void *arg __used)
583{
584 int err = 0;
585 pthread_mutex_lock(&top.active_symbols_lock);
586 while (list_empty(&top.active_symbols)) {
587 err = pthread_cond_wait(&top.active_symbols_cond,
588 &top.active_symbols_lock);
589 if (err)
590 break;
591 }
592 pthread_mutex_unlock(&top.active_symbols_lock);
593 if (!err)
594 perf_top__tui_browser(&top);
595 exit_browser(0);
596 exit(0);
597 return NULL;
598}
599
898static void *display_thread(void *arg __used) 600static void *display_thread(void *arg __used)
899{ 601{
900 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; 602 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
@@ -909,13 +611,13 @@ static void *display_thread(void *arg __used)
909 tc.c_cc[VTIME] = 0; 611 tc.c_cc[VTIME] = 0;
910 612
911repeat: 613repeat:
912 delay_msecs = delay_secs * 1000; 614 delay_msecs = top.delay_secs * 1000;
913 tcsetattr(0, TCSANOW, &tc); 615 tcsetattr(0, TCSANOW, &tc);
914 /* trash return*/ 616 /* trash return*/
915 getc(stdin); 617 getc(stdin);
916 618
917 do { 619 do {
918 print_sym_table(); 620 print_sym_table(session);
919 } while (!poll(&stdin_poll, 1, delay_msecs) == 1); 621 } while (!poll(&stdin_poll, 1, delay_msecs) == 1);
920 622
921 c = getc(stdin); 623 c = getc(stdin);
@@ -930,6 +632,7 @@ repeat:
930/* Tag samples to be skipped. */ 632/* Tag samples to be skipped. */
931static const char *skip_symbols[] = { 633static const char *skip_symbols[] = {
932 "default_idle", 634 "default_idle",
635 "native_safe_halt",
933 "cpu_idle", 636 "cpu_idle",
934 "enter_idle", 637 "enter_idle",
935 "exit_idle", 638 "exit_idle",
@@ -965,9 +668,9 @@ static int symbol_filter(struct map *map, struct symbol *sym)
965 668
966 syme = symbol__priv(sym); 669 syme = symbol__priv(sym);
967 syme->map = map; 670 syme->map = map;
968 syme->src = NULL; 671 symbol__annotate_init(map, sym);
969 672
970 if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) { 673 if (!top.sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) {
971 /* schedule initial sym_filter_entry setup */ 674 /* schedule initial sym_filter_entry setup */
972 sym_filter_entry_sched = syme; 675 sym_filter_entry_sched = syme;
973 sym_filter = NULL; 676 sym_filter = NULL;
@@ -975,49 +678,45 @@ static int symbol_filter(struct map *map, struct symbol *sym)
975 678
976 for (i = 0; skip_symbols[i]; i++) { 679 for (i = 0; skip_symbols[i]; i++) {
977 if (!strcmp(skip_symbols[i], name)) { 680 if (!strcmp(skip_symbols[i], name)) {
978 syme->skip = 1; 681 sym->ignore = true;
979 break; 682 break;
980 } 683 }
981 } 684 }
982 685
983 if (!syme->skip)
984 syme->name_len = strlen(sym->name);
985
986 return 0; 686 return 0;
987} 687}
988 688
989static void event__process_sample(const event_t *self, 689static void perf_event__process_sample(const union perf_event *event,
990 struct sample_data *sample, 690 struct perf_sample *sample,
991 struct perf_session *session, 691 struct perf_session *session)
992 struct perf_evsel *evsel)
993{ 692{
994 u64 ip = self->ip.ip; 693 u64 ip = event->ip.ip;
995 struct sym_entry *syme; 694 struct sym_entry *syme;
996 struct addr_location al; 695 struct addr_location al;
997 struct machine *machine; 696 struct machine *machine;
998 u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 697 u8 origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
999 698
1000 ++samples; 699 ++top.samples;
1001 700
1002 switch (origin) { 701 switch (origin) {
1003 case PERF_RECORD_MISC_USER: 702 case PERF_RECORD_MISC_USER:
1004 ++us_samples; 703 ++top.us_samples;
1005 if (hide_user_symbols) 704 if (top.hide_user_symbols)
1006 return; 705 return;
1007 machine = perf_session__find_host_machine(session); 706 machine = perf_session__find_host_machine(session);
1008 break; 707 break;
1009 case PERF_RECORD_MISC_KERNEL: 708 case PERF_RECORD_MISC_KERNEL:
1010 ++kernel_samples; 709 ++top.kernel_samples;
1011 if (hide_kernel_symbols) 710 if (top.hide_kernel_symbols)
1012 return; 711 return;
1013 machine = perf_session__find_host_machine(session); 712 machine = perf_session__find_host_machine(session);
1014 break; 713 break;
1015 case PERF_RECORD_MISC_GUEST_KERNEL: 714 case PERF_RECORD_MISC_GUEST_KERNEL:
1016 ++guest_kernel_samples; 715 ++top.guest_kernel_samples;
1017 machine = perf_session__find_machine(session, self->ip.pid); 716 machine = perf_session__find_machine(session, event->ip.pid);
1018 break; 717 break;
1019 case PERF_RECORD_MISC_GUEST_USER: 718 case PERF_RECORD_MISC_GUEST_USER:
1020 ++guest_us_samples; 719 ++top.guest_us_samples;
1021 /* 720 /*
1022 * TODO: we don't process guest user from host side 721 * TODO: we don't process guest user from host side
1023 * except simple counting. 722 * except simple counting.
@@ -1029,19 +728,34 @@ static void event__process_sample(const event_t *self,
1029 728
1030 if (!machine && perf_guest) { 729 if (!machine && perf_guest) {
1031 pr_err("Can't find guest [%d]'s kernel information\n", 730 pr_err("Can't find guest [%d]'s kernel information\n",
1032 self->ip.pid); 731 event->ip.pid);
1033 return; 732 return;
1034 } 733 }
1035 734
1036 if (self->header.misc & PERF_RECORD_MISC_EXACT_IP) 735 if (event->header.misc & PERF_RECORD_MISC_EXACT_IP)
1037 exact_samples++; 736 top.exact_samples++;
1038 737
1039 if (event__preprocess_sample(self, session, &al, sample, 738 if (perf_event__preprocess_sample(event, session, &al, sample,
1040 symbol_filter) < 0 || 739 symbol_filter) < 0 ||
1041 al.filtered) 740 al.filtered)
1042 return; 741 return;
1043 742
743 if (!kptr_restrict_warned &&
744 symbol_conf.kptr_restrict &&
745 al.cpumode == PERF_RECORD_MISC_KERNEL) {
746 ui__warning(
747"Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
748"Check /proc/sys/kernel/kptr_restrict.\n\n"
749"Kernel%s samples will not be resolved.\n",
750 !RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION]) ?
751 " modules" : "");
752 if (use_browser <= 0)
753 sleep(5);
754 kptr_restrict_warned = true;
755 }
756
1044 if (al.sym == NULL) { 757 if (al.sym == NULL) {
758 const char *msg = "Kernel samples will not be resolved.\n";
1045 /* 759 /*
1046 * As we do lazy loading of symtabs we only will know if the 760 * As we do lazy loading of symtabs we only will know if the
1047 * specified vmlinux file is invalid when we actually have a 761 * specified vmlinux file is invalid when we actually have a
@@ -1053,11 +767,20 @@ static void event__process_sample(const event_t *self,
1053 * --hide-kernel-symbols, even if the user specifies an 767 * --hide-kernel-symbols, even if the user specifies an
1054 * invalid --vmlinux ;-) 768 * invalid --vmlinux ;-)
1055 */ 769 */
1056 if (al.map == machine->vmlinux_maps[MAP__FUNCTION] && 770 if (!kptr_restrict_warned && !vmlinux_warned &&
771 al.map == machine->vmlinux_maps[MAP__FUNCTION] &&
1057 RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) { 772 RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) {
1058 pr_err("The %s file can't be used\n", 773 if (symbol_conf.vmlinux_name) {
1059 symbol_conf.vmlinux_name); 774 ui__warning("The %s file can't be used.\n%s",
1060 exit(1); 775 symbol_conf.vmlinux_name, msg);
776 } else {
777 ui__warning("A vmlinux file was not found.\n%s",
778 msg);
779 }
780
781 if (use_browser <= 0)
782 sleep(5);
783 vmlinux_warned = true;
1061 } 784 }
1062 785
1063 return; 786 return;
@@ -1065,13 +788,13 @@ static void event__process_sample(const event_t *self,
1065 788
1066 /* let's see, whether we need to install initial sym_filter_entry */ 789 /* let's see, whether we need to install initial sym_filter_entry */
1067 if (sym_filter_entry_sched) { 790 if (sym_filter_entry_sched) {
1068 sym_filter_entry = sym_filter_entry_sched; 791 top.sym_filter_entry = sym_filter_entry_sched;
1069 sym_filter_entry_sched = NULL; 792 sym_filter_entry_sched = NULL;
1070 if (parse_source(sym_filter_entry) < 0) { 793 if (parse_source(top.sym_filter_entry) < 0) {
1071 struct symbol *sym = sym_entry__symbol(sym_filter_entry); 794 struct symbol *sym = sym_entry__symbol(top.sym_filter_entry);
1072 795
1073 pr_err("Can't annotate %s", sym->name); 796 pr_err("Can't annotate %s", sym->name);
1074 if (sym_filter_entry->map->dso->origin == DSO__ORIG_KERNEL) { 797 if (top.sym_filter_entry->map->dso->symtab_type == SYMTAB__KALLSYMS) {
1075 pr_err(": No vmlinux file was found in the path:\n"); 798 pr_err(": No vmlinux file was found in the path:\n");
1076 machine__fprintf_vmlinux_path(machine, stderr); 799 machine__fprintf_vmlinux_path(machine, stderr);
1077 } else 800 } else
@@ -1081,222 +804,133 @@ static void event__process_sample(const event_t *self,
1081 } 804 }
1082 805
1083 syme = symbol__priv(al.sym); 806 syme = symbol__priv(al.sym);
1084 if (!syme->skip) { 807 if (!al.sym->ignore) {
808 struct perf_evsel *evsel;
809
810 evsel = perf_evlist__id2evsel(top.evlist, sample->id);
811 assert(evsel != NULL);
1085 syme->count[evsel->idx]++; 812 syme->count[evsel->idx]++;
1086 syme->origin = origin;
1087 record_precise_ip(syme, evsel->idx, ip); 813 record_precise_ip(syme, evsel->idx, ip);
1088 pthread_mutex_lock(&active_symbols_lock); 814 pthread_mutex_lock(&top.active_symbols_lock);
1089 if (list_empty(&syme->node) || !syme->node.next) 815 if (list_empty(&syme->node) || !syme->node.next) {
816 static bool first = true;
1090 __list_insert_active_sym(syme); 817 __list_insert_active_sym(syme);
1091 pthread_mutex_unlock(&active_symbols_lock); 818 if (first) {
819 pthread_cond_broadcast(&top.active_symbols_cond);
820 first = false;
821 }
822 }
823 pthread_mutex_unlock(&top.active_symbols_lock);
1092 } 824 }
1093} 825}
1094 826
1095struct mmap_data { 827static void perf_session__mmap_read_idx(struct perf_session *self, int idx)
1096 void *base;
1097 int mask;
1098 unsigned int prev;
1099};
1100
1101static int perf_evsel__alloc_mmap_per_thread(struct perf_evsel *evsel,
1102 int ncpus, int nthreads)
1103{
1104 evsel->priv = xyarray__new(ncpus, nthreads, sizeof(struct mmap_data));
1105 return evsel->priv != NULL ? 0 : -ENOMEM;
1106}
1107
1108static void perf_evsel__free_mmap(struct perf_evsel *evsel)
1109{
1110 xyarray__delete(evsel->priv);
1111 evsel->priv = NULL;
1112}
1113
1114static unsigned int mmap_read_head(struct mmap_data *md)
1115{ 828{
1116 struct perf_event_mmap_page *pc = md->base; 829 struct perf_sample sample;
1117 int head; 830 union perf_event *event;
1118 831 int ret;
1119 head = pc->data_head; 832
1120 rmb(); 833 while ((event = perf_evlist__mmap_read(top.evlist, idx)) != NULL) {
1121 834 ret = perf_session__parse_sample(self, event, &sample);
1122 return head; 835 if (ret) {
1123} 836 pr_err("Can't parse sample, err = %d\n", ret);
1124 837 continue;
1125static void perf_session__mmap_read_counter(struct perf_session *self,
1126 struct perf_evsel *evsel,
1127 int cpu, int thread_idx)
1128{
1129 struct xyarray *mmap_array = evsel->priv;
1130 struct mmap_data *md = xyarray__entry(mmap_array, cpu, thread_idx);
1131 unsigned int head = mmap_read_head(md);
1132 unsigned int old = md->prev;
1133 unsigned char *data = md->base + page_size;
1134 struct sample_data sample;
1135 int diff;
1136
1137 /*
1138 * If we're further behind than half the buffer, there's a chance
1139 * the writer will bite our tail and mess up the samples under us.
1140 *
1141 * If we somehow ended up ahead of the head, we got messed up.
1142 *
1143 * In either case, truncate and restart at head.
1144 */
1145 diff = head - old;
1146 if (diff > md->mask / 2 || diff < 0) {
1147 fprintf(stderr, "WARNING: failed to keep up with mmap data.\n");
1148
1149 /*
1150 * head points to a known good entry, start there.
1151 */
1152 old = head;
1153 }
1154
1155 for (; old != head;) {
1156 event_t *event = (event_t *)&data[old & md->mask];
1157
1158 event_t event_copy;
1159
1160 size_t size = event->header.size;
1161
1162 /*
1163 * Event straddles the mmap boundary -- header should always
1164 * be inside due to u64 alignment of output.
1165 */
1166 if ((old & md->mask) + size != ((old + size) & md->mask)) {
1167 unsigned int offset = old;
1168 unsigned int len = min(sizeof(*event), size), cpy;
1169 void *dst = &event_copy;
1170
1171 do {
1172 cpy = min(md->mask + 1 - (offset & md->mask), len);
1173 memcpy(dst, &data[offset & md->mask], cpy);
1174 offset += cpy;
1175 dst += cpy;
1176 len -= cpy;
1177 } while (len);
1178
1179 event = &event_copy;
1180 } 838 }
1181 839
1182 event__parse_sample(event, self, &sample);
1183 if (event->header.type == PERF_RECORD_SAMPLE) 840 if (event->header.type == PERF_RECORD_SAMPLE)
1184 event__process_sample(event, &sample, self, evsel); 841 perf_event__process_sample(event, &sample, self);
1185 else 842 else
1186 event__process(event, &sample, self); 843 perf_event__process(event, &sample, self);
1187 old += size;
1188 } 844 }
1189
1190 md->prev = old;
1191} 845}
1192 846
1193static struct pollfd *event_array;
1194
1195static void perf_session__mmap_read(struct perf_session *self) 847static void perf_session__mmap_read(struct perf_session *self)
1196{ 848{
1197 struct perf_evsel *counter; 849 int i;
1198 int i, thread_index;
1199
1200 for (i = 0; i < cpus->nr; i++) {
1201 list_for_each_entry(counter, &evsel_list, node) {
1202 for (thread_index = 0;
1203 thread_index < threads->nr;
1204 thread_index++) {
1205 perf_session__mmap_read_counter(self,
1206 counter, i, thread_index);
1207 }
1208 }
1209 }
1210}
1211 850
1212int nr_poll; 851 for (i = 0; i < top.evlist->nr_mmaps; i++)
1213int group_fd; 852 perf_session__mmap_read_idx(self, i);
853}
1214 854
1215static void start_counter(int i, struct perf_evsel *evsel) 855static void start_counters(struct perf_evlist *evlist)
1216{ 856{
1217 struct xyarray *mmap_array = evsel->priv; 857 struct perf_evsel *counter;
1218 struct mmap_data *mm;
1219 struct perf_event_attr *attr;
1220 int cpu = -1;
1221 int thread_index;
1222
1223 if (target_tid == -1)
1224 cpu = cpus->map[i];
1225 858
1226 attr = &evsel->attr; 859 list_for_each_entry(counter, &evlist->entries, node) {
860 struct perf_event_attr *attr = &counter->attr;
1227 861
1228 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; 862 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
1229 863
1230 if (freq) { 864 if (top.freq) {
1231 attr->sample_type |= PERF_SAMPLE_PERIOD; 865 attr->sample_type |= PERF_SAMPLE_PERIOD;
1232 attr->freq = 1; 866 attr->freq = 1;
1233 attr->sample_freq = freq; 867 attr->sample_freq = top.freq;
1234 } 868 }
1235 869
1236 attr->inherit = (cpu < 0) && inherit; 870 if (evlist->nr_entries > 1) {
1237 attr->mmap = 1; 871 attr->sample_type |= PERF_SAMPLE_ID;
872 attr->read_format |= PERF_FORMAT_ID;
873 }
1238 874
1239 for (thread_index = 0; thread_index < threads->nr; thread_index++) { 875 attr->mmap = 1;
876 attr->inherit = inherit;
1240try_again: 877try_again:
1241 FD(evsel, i, thread_index) = sys_perf_event_open(attr, 878 if (perf_evsel__open(counter, top.evlist->cpus,
1242 threads->map[thread_index], cpu, group_fd, 0); 879 top.evlist->threads, group) < 0) {
1243
1244 if (FD(evsel, i, thread_index) < 0) {
1245 int err = errno; 880 int err = errno;
1246 881
1247 if (err == EPERM || err == EACCES) 882 if (err == EPERM || err == EACCES) {
1248 die("Permission error - are you root?\n" 883 ui__warning_paranoid();
1249 "\t Consider tweaking" 884 goto out_err;
1250 " /proc/sys/kernel/perf_event_paranoid.\n"); 885 }
1251 /* 886 /*
1252 * If it's cycles then fall back to hrtimer 887 * If it's cycles then fall back to hrtimer
1253 * based cpu-clock-tick sw counter, which 888 * based cpu-clock-tick sw counter, which
1254 * is always available even if no PMU support: 889 * is always available even if no PMU support:
1255 */ 890 */
1256 if (attr->type == PERF_TYPE_HARDWARE 891 if (attr->type == PERF_TYPE_HARDWARE &&
1257 && attr->config == PERF_COUNT_HW_CPU_CYCLES) { 892 attr->config == PERF_COUNT_HW_CPU_CYCLES) {
1258
1259 if (verbose) 893 if (verbose)
1260 warning(" ... trying to fall back to cpu-clock-ticks\n"); 894 ui__warning("Cycles event not supported,\n"
895 "trying to fall back to cpu-clock-ticks\n");
1261 896
1262 attr->type = PERF_TYPE_SOFTWARE; 897 attr->type = PERF_TYPE_SOFTWARE;
1263 attr->config = PERF_COUNT_SW_CPU_CLOCK; 898 attr->config = PERF_COUNT_SW_CPU_CLOCK;
1264 goto try_again; 899 goto try_again;
1265 } 900 }
1266 printf("\n"); 901
1267 error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n", 902 if (err == ENOENT) {
1268 FD(evsel, i, thread_index), strerror(err)); 903 ui__warning("The %s event is not supported.\n",
1269 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); 904 event_name(counter));
1270 exit(-1); 905 goto out_err;
906 }
907
908 ui__warning("The sys_perf_event_open() syscall "
909 "returned with %d (%s). /bin/dmesg "
910 "may provide additional information.\n"
911 "No CONFIG_PERF_EVENTS=y kernel support "
912 "configured?\n", err, strerror(err));
913 goto out_err;
1271 } 914 }
1272 assert(FD(evsel, i, thread_index) >= 0); 915 }
1273 fcntl(FD(evsel, i, thread_index), F_SETFL, O_NONBLOCK);
1274 916
1275 /* 917 if (perf_evlist__mmap(evlist, mmap_pages, false) < 0) {
1276 * First counter acts as the group leader: 918 ui__warning("Failed to mmap with %d (%s)\n",
1277 */ 919 errno, strerror(errno));
1278 if (group && group_fd == -1) 920 goto out_err;
1279 group_fd = FD(evsel, i, thread_index);
1280
1281 event_array[nr_poll].fd = FD(evsel, i, thread_index);
1282 event_array[nr_poll].events = POLLIN;
1283 nr_poll++;
1284
1285 mm = xyarray__entry(mmap_array, i, thread_index);
1286 mm->prev = 0;
1287 mm->mask = mmap_pages*page_size - 1;
1288 mm->base = mmap(NULL, (mmap_pages+1)*page_size,
1289 PROT_READ, MAP_SHARED, FD(evsel, i, thread_index), 0);
1290 if (mm->base == MAP_FAILED)
1291 die("failed to mmap with %d (%s)\n", errno, strerror(errno));
1292 } 921 }
922
923 return;
924
925out_err:
926 exit_browser(0);
927 exit(0);
1293} 928}
1294 929
1295static int __cmd_top(void) 930static int __cmd_top(void)
1296{ 931{
1297 pthread_t thread; 932 pthread_t thread;
1298 struct perf_evsel *counter; 933 int ret __used;
1299 int i, ret;
1300 /* 934 /*
1301 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this 935 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this
1302 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now. 936 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now.
@@ -1305,23 +939,23 @@ static int __cmd_top(void)
1305 if (session == NULL) 939 if (session == NULL)
1306 return -ENOMEM; 940 return -ENOMEM;
1307 941
1308 if (target_tid != -1) 942 if (top.target_tid != -1)
1309 event__synthesize_thread_map(threads, event__process, session); 943 perf_event__synthesize_thread_map(top.evlist->threads,
944 perf_event__process, session);
1310 else 945 else
1311 event__synthesize_threads(event__process, session); 946 perf_event__synthesize_threads(perf_event__process, session);
1312 947
1313 for (i = 0; i < cpus->nr; i++) { 948 start_counters(top.evlist);
1314 group_fd = -1; 949 session->evlist = top.evlist;
1315 list_for_each_entry(counter, &evsel_list, node) 950 perf_session__update_sample_type(session);
1316 start_counter(i, counter);
1317 }
1318 951
1319 /* Wait for a minimal set of events before starting the snapshot */ 952 /* Wait for a minimal set of events before starting the snapshot */
1320 poll(&event_array[0], nr_poll, 100); 953 poll(top.evlist->pollfd, top.evlist->nr_fds, 100);
1321 954
1322 perf_session__mmap_read(session); 955 perf_session__mmap_read(session);
1323 956
1324 if (pthread_create(&thread, NULL, display_thread, session)) { 957 if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui :
958 display_thread), session)) {
1325 printf("Could not create display thread.\n"); 959 printf("Could not create display thread.\n");
1326 exit(-1); 960 exit(-1);
1327 } 961 }
@@ -1337,12 +971,12 @@ static int __cmd_top(void)
1337 } 971 }
1338 972
1339 while (1) { 973 while (1) {
1340 int hits = samples; 974 u64 hits = top.samples;
1341 975
1342 perf_session__mmap_read(session); 976 perf_session__mmap_read(session);
1343 977
1344 if (hits == samples) 978 if (hits == top.samples)
1345 ret = poll(event_array, nr_poll, 100); 979 ret = poll(top.evlist->pollfd, top.evlist->nr_fds, 100);
1346 } 980 }
1347 981
1348 return 0; 982 return 0;
@@ -1354,31 +988,31 @@ static const char * const top_usage[] = {
1354}; 988};
1355 989
1356static const struct option options[] = { 990static const struct option options[] = {
1357 OPT_CALLBACK('e', "event", NULL, "event", 991 OPT_CALLBACK('e', "event", &top.evlist, "event",
1358 "event selector. use 'perf list' to list available events", 992 "event selector. use 'perf list' to list available events",
1359 parse_events), 993 parse_events_option),
1360 OPT_INTEGER('c', "count", &default_interval, 994 OPT_INTEGER('c', "count", &default_interval,
1361 "event period to sample"), 995 "event period to sample"),
1362 OPT_INTEGER('p', "pid", &target_pid, 996 OPT_INTEGER('p', "pid", &top.target_pid,
1363 "profile events on existing process id"), 997 "profile events on existing process id"),
1364 OPT_INTEGER('t', "tid", &target_tid, 998 OPT_INTEGER('t', "tid", &top.target_tid,
1365 "profile events on existing thread id"), 999 "profile events on existing thread id"),
1366 OPT_BOOLEAN('a', "all-cpus", &system_wide, 1000 OPT_BOOLEAN('a', "all-cpus", &system_wide,
1367 "system-wide collection from all CPUs"), 1001 "system-wide collection from all CPUs"),
1368 OPT_STRING('C', "cpu", &cpu_list, "cpu", 1002 OPT_STRING('C', "cpu", &top.cpu_list, "cpu",
1369 "list of cpus to monitor"), 1003 "list of cpus to monitor"),
1370 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 1004 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
1371 "file", "vmlinux pathname"), 1005 "file", "vmlinux pathname"),
1372 OPT_BOOLEAN('K', "hide_kernel_symbols", &hide_kernel_symbols, 1006 OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols,
1373 "hide kernel symbols"), 1007 "hide kernel symbols"),
1374 OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"), 1008 OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"),
1375 OPT_INTEGER('r', "realtime", &realtime_prio, 1009 OPT_INTEGER('r', "realtime", &realtime_prio,
1376 "collect data with this RT SCHED_FIFO priority"), 1010 "collect data with this RT SCHED_FIFO priority"),
1377 OPT_INTEGER('d', "delay", &delay_secs, 1011 OPT_INTEGER('d', "delay", &top.delay_secs,
1378 "number of seconds to delay between refreshes"), 1012 "number of seconds to delay between refreshes"),
1379 OPT_BOOLEAN('D', "dump-symtab", &dump_symtab, 1013 OPT_BOOLEAN('D', "dump-symtab", &dump_symtab,
1380 "dump the symbol table used for profiling"), 1014 "dump the symbol table used for profiling"),
1381 OPT_INTEGER('f', "count-filter", &count_filter, 1015 OPT_INTEGER('f', "count-filter", &top.count_filter,
1382 "only display functions with more events than this"), 1016 "only display functions with more events than this"),
1383 OPT_BOOLEAN('g', "group", &group, 1017 OPT_BOOLEAN('g', "group", &group,
1384 "put the counters into a counter group"), 1018 "put the counters into a counter group"),
@@ -1386,14 +1020,16 @@ static const struct option options[] = {
1386 "child tasks inherit counters"), 1020 "child tasks inherit counters"),
1387 OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name", 1021 OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name",
1388 "symbol to annotate"), 1022 "symbol to annotate"),
1389 OPT_BOOLEAN('z', "zero", &zero, 1023 OPT_BOOLEAN('z', "zero", &top.zero,
1390 "zero history across updates"), 1024 "zero history across updates"),
1391 OPT_INTEGER('F', "freq", &freq, 1025 OPT_INTEGER('F', "freq", &top.freq,
1392 "profile at this frequency"), 1026 "profile at this frequency"),
1393 OPT_INTEGER('E', "entries", &print_entries, 1027 OPT_INTEGER('E', "entries", &top.print_entries,
1394 "display this many functions"), 1028 "display this many functions"),
1395 OPT_BOOLEAN('U', "hide_user_symbols", &hide_user_symbols, 1029 OPT_BOOLEAN('U', "hide_user_symbols", &top.hide_user_symbols,
1396 "hide user symbols"), 1030 "hide user symbols"),
1031 OPT_BOOLEAN(0, "tui", &use_tui, "Use the TUI interface"),
1032 OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"),
1397 OPT_INCR('v', "verbose", &verbose, 1033 OPT_INCR('v', "verbose", &verbose,
1398 "be more verbose (show counter open errors, etc)"), 1034 "be more verbose (show counter open errors, etc)"),
1399 OPT_END() 1035 OPT_END()
@@ -1404,64 +1040,68 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1404 struct perf_evsel *pos; 1040 struct perf_evsel *pos;
1405 int status = -ENOMEM; 1041 int status = -ENOMEM;
1406 1042
1043 top.evlist = perf_evlist__new(NULL, NULL);
1044 if (top.evlist == NULL)
1045 return -ENOMEM;
1046
1407 page_size = sysconf(_SC_PAGE_SIZE); 1047 page_size = sysconf(_SC_PAGE_SIZE);
1408 1048
1409 argc = parse_options(argc, argv, options, top_usage, 0); 1049 argc = parse_options(argc, argv, options, top_usage, 0);
1410 if (argc) 1050 if (argc)
1411 usage_with_options(top_usage, options); 1051 usage_with_options(top_usage, options);
1412 1052
1413 if (target_pid != -1) 1053 /*
1414 target_tid = target_pid; 1054 * XXX For now start disabled, only using TUI if explicitely asked for.
1055 * Change that when handle_keys equivalent gets written, live annotation
1056 * done, etc.
1057 */
1058 use_browser = 0;
1415 1059
1416 threads = thread_map__new(target_pid, target_tid); 1060 if (use_stdio)
1417 if (threads == NULL) { 1061 use_browser = 0;
1418 pr_err("Problems finding threads of monitor\n"); 1062 else if (use_tui)
1419 usage_with_options(top_usage, options); 1063 use_browser = 1;
1420 }
1421 1064
1422 event_array = malloc((sizeof(struct pollfd) * 1065 setup_browser(false);
1423 MAX_NR_CPUS * MAX_COUNTERS * threads->nr));
1424 if (!event_array)
1425 return -ENOMEM;
1426 1066
1427 /* CPU and PID are mutually exclusive */ 1067 /* CPU and PID are mutually exclusive */
1428 if (target_tid > 0 && cpu_list) { 1068 if (top.target_tid > 0 && top.cpu_list) {
1429 printf("WARNING: PID switch overriding CPU\n"); 1069 printf("WARNING: PID switch overriding CPU\n");
1430 sleep(1); 1070 sleep(1);
1431 cpu_list = NULL; 1071 top.cpu_list = NULL;
1432 } 1072 }
1433 1073
1434 if (!nr_counters && perf_evsel_list__create_default() < 0) { 1074 if (top.target_pid != -1)
1075 top.target_tid = top.target_pid;
1076
1077 if (perf_evlist__create_maps(top.evlist, top.target_pid,
1078 top.target_tid, top.cpu_list) < 0)
1079 usage_with_options(top_usage, options);
1080
1081 if (!top.evlist->nr_entries &&
1082 perf_evlist__add_default(top.evlist) < 0) {
1435 pr_err("Not enough memory for event selector list\n"); 1083 pr_err("Not enough memory for event selector list\n");
1436 return -ENOMEM; 1084 return -ENOMEM;
1437 } 1085 }
1438 1086
1439 if (delay_secs < 1) 1087 if (top.delay_secs < 1)
1440 delay_secs = 1; 1088 top.delay_secs = 1;
1441 1089
1442 /* 1090 /*
1443 * User specified count overrides default frequency. 1091 * User specified count overrides default frequency.
1444 */ 1092 */
1445 if (default_interval) 1093 if (default_interval)
1446 freq = 0; 1094 top.freq = 0;
1447 else if (freq) { 1095 else if (top.freq) {
1448 default_interval = freq; 1096 default_interval = top.freq;
1449 } else { 1097 } else {
1450 fprintf(stderr, "frequency and count are zero, aborting\n"); 1098 fprintf(stderr, "frequency and count are zero, aborting\n");
1451 exit(EXIT_FAILURE); 1099 exit(EXIT_FAILURE);
1452 } 1100 }
1453 1101
1454 if (target_tid != -1) 1102 list_for_each_entry(pos, &top.evlist->entries, node) {
1455 cpus = cpu_map__dummy_new(); 1103 if (perf_evsel__alloc_fd(pos, top.evlist->cpus->nr,
1456 else 1104 top.evlist->threads->nr) < 0)
1457 cpus = cpu_map__new(cpu_list);
1458
1459 if (cpus == NULL)
1460 usage_with_options(top_usage, options);
1461
1462 list_for_each_entry(pos, &evsel_list, node) {
1463 if (perf_evsel__alloc_mmap_per_thread(pos, cpus->nr, threads->nr) < 0 ||
1464 perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0)
1465 goto out_free_fd; 1105 goto out_free_fd;
1466 /* 1106 /*
1467 * Fill in the ones not specifically initialized via -c: 1107 * Fill in the ones not specifically initialized via -c:
@@ -1472,26 +1112,28 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1472 pos->attr.sample_period = default_interval; 1112 pos->attr.sample_period = default_interval;
1473 } 1113 }
1474 1114
1475 sym_evsel = list_entry(evsel_list.next, struct perf_evsel, node); 1115 if (perf_evlist__alloc_pollfd(top.evlist) < 0 ||
1116 perf_evlist__alloc_mmap(top.evlist) < 0)
1117 goto out_free_fd;
1118
1119 top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node);
1476 1120
1477 symbol_conf.priv_size = (sizeof(struct sym_entry) + 1121 symbol_conf.priv_size = (sizeof(struct sym_entry) + sizeof(struct annotation) +
1478 (nr_counters + 1) * sizeof(unsigned long)); 1122 (top.evlist->nr_entries + 1) * sizeof(unsigned long));
1479 1123
1480 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); 1124 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
1481 if (symbol__init() < 0) 1125 if (symbol__init() < 0)
1482 return -1; 1126 return -1;
1483 1127
1484 get_term_dimensions(&winsize); 1128 get_term_dimensions(&winsize);
1485 if (print_entries == 0) { 1129 if (top.print_entries == 0) {
1486 update_print_entries(&winsize); 1130 update_print_entries(&winsize);
1487 signal(SIGWINCH, sig_winch_handler); 1131 signal(SIGWINCH, sig_winch_handler);
1488 } 1132 }
1489 1133
1490 status = __cmd_top(); 1134 status = __cmd_top();
1491out_free_fd: 1135out_free_fd:
1492 list_for_each_entry(pos, &evsel_list, node) 1136 perf_evlist__delete(top.evlist);
1493 perf_evsel__free_mmap(pos);
1494 perf_evsel_list__delete();
1495 1137
1496 return status; 1138 return status;
1497} 1139}
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/feature-tests.mak b/tools/perf/config/feature-tests.mak
index b041ca67a2cb..6170fd2531b5 100644
--- a/tools/perf/feature-tests.mak
+++ b/tools/perf/config/feature-tests.mak
@@ -79,9 +79,15 @@ endef
79endif 79endif
80 80
81ifndef NO_LIBPYTHON 81ifndef NO_LIBPYTHON
82define SOURCE_PYTHON_VERSION
83#include <Python.h>
84#if PY_VERSION_HEX >= 0x03000000
85 #error
86#endif
87int main(void){}
88endef
82define SOURCE_PYTHON_EMBED 89define SOURCE_PYTHON_EMBED
83#include <Python.h> 90#include <Python.h>
84
85int main(void) 91int main(void)
86{ 92{
87 Py_Initialize(); 93 Py_Initialize();
@@ -120,11 +126,3 @@ int main(void)
120 return 0; 126 return 0;
121} 127}
122endef 128endef
123
124# try-cc
125# Usage: option = $(call try-cc, source-to-build, cc-options)
126try-cc = $(shell sh -c \
127 'TMP="$(OUTPUT)$(TMPOUT).$$$$"; \
128 echo "$(1)" | \
129 $(CC) -x c - $(2) -o "$$TMP" > /dev/null 2>&1 && echo y; \
130 rm -f "$$TMP"')
diff --git a/tools/perf/config/utilities.mak b/tools/perf/config/utilities.mak
new file mode 100644
index 000000000000..8046182a19eb
--- /dev/null
+++ b/tools/perf/config/utilities.mak
@@ -0,0 +1,188 @@
1# This allows us to work with the newline character:
2define newline
3
4
5endef
6newline := $(newline)
7
8# nl-escape
9#
10# Usage: escape = $(call nl-escape[,escape])
11#
12# This is used as the common way to specify
13# what should replace a newline when escaping
14# newlines; the default is a bizarre string.
15#
16nl-escape = $(or $(1),m822df3020w6a44id34bt574ctac44eb9f4n)
17
18# escape-nl
19#
20# Usage: escaped-text = $(call escape-nl,text[,escape])
21#
22# GNU make's $(shell ...) function converts to a
23# single space each newline character in the output
24# produced during the expansion; this may not be
25# desirable.
26#
27# The only solution is to change each newline into
28# something that won't be converted, so that the
29# information can be recovered later with
30# $(call unescape-nl...)
31#
32escape-nl = $(subst $(newline),$(call nl-escape,$(2)),$(1))
33
34# unescape-nl
35#
36# Usage: text = $(call unescape-nl,escaped-text[,escape])
37#
38# See escape-nl.
39#
40unescape-nl = $(subst $(call nl-escape,$(2)),$(newline),$(1))
41
42# shell-escape-nl
43#
44# Usage: $(shell some-command | $(call shell-escape-nl[,escape]))
45#
46# Use this to escape newlines from within a shell call;
47# the default escape is a bizarre string.
48#
49# NOTE: The escape is used directly as a string constant
50# in an `awk' program that is delimited by shell
51# single-quotes, so be wary of the characters
52# that are chosen.
53#
54define shell-escape-nl
55awk 'NR==1 {t=$$0} NR>1 {t=t "$(nl-escape)" $$0} END {printf t}'
56endef
57
58# shell-unescape-nl
59#
60# Usage: $(shell some-command | $(call shell-unescape-nl[,escape]))
61#
62# Use this to unescape newlines from within a shell call;
63# the default escape is a bizarre string.
64#
65# NOTE: The escape is used directly as an extended regular
66# expression constant in an `awk' program that is
67# delimited by shell single-quotes, so be wary
68# of the characters that are chosen.
69#
70# (The bash shell has a bug where `{gsub(...),...}' is
71# misinterpreted as a brace expansion; this can be
72# overcome by putting a space between `{' and `gsub').
73#
74define shell-unescape-nl
75awk 'NR==1 {t=$$0} NR>1 {t=t "\n" $$0} END { gsub(/$(nl-escape)/,"\n",t); printf t }'
76endef
77
78# escape-for-shell-sq
79#
80# Usage: embeddable-text = $(call escape-for-shell-sq,text)
81#
82# This function produces text that is suitable for
83# embedding in a shell string that is delimited by
84# single-quotes.
85#
86escape-for-shell-sq = $(subst ','\'',$(1))
87
88# shell-sq
89#
90# Usage: single-quoted-and-escaped-text = $(call shell-sq,text)
91#
92shell-sq = '$(escape-for-shell-sq)'
93
94# shell-wordify
95#
96# Usage: wordified-text = $(call shell-wordify,text)
97#
98# For instance:
99#
100# |define text
101# |hello
102# |world
103# |endef
104# |
105# |target:
106# | echo $(call shell-wordify,$(text))
107#
108# At least GNU make gets confused by expanding a newline
109# within the context of a command line of a makefile rule
110# (this is in constrast to a `$(shell ...)' function call,
111# which can handle it just fine).
112#
113# This function avoids the problem by producing a string
114# that works as a shell word, regardless of whether or
115# not it contains a newline.
116#
117# If the text to be wordified contains a newline, then
118# an intrictate shell command substitution is constructed
119# to render the text as a single line; when the shell
120# processes the resulting escaped text, it transforms
121# it into the original unescaped text.
122#
123# If the text does not contain a newline, then this function
124# produces the same results as the `$(shell-sq)' function.
125#
126shell-wordify = $(if $(findstring $(newline),$(1)),$(_sw-esc-nl),$(shell-sq))
127define _sw-esc-nl
128"$$(echo $(call escape-nl,$(shell-sq),$(2)) | $(call shell-unescape-nl,$(2)))"
129endef
130
131# is-absolute
132#
133# Usage: bool-value = $(call is-absolute,path)
134#
135is-absolute = $(shell echo $(shell-sq) | grep ^/ -q && echo y)
136
137# lookup
138#
139# Usage: absolute-executable-path-or-empty = $(call lookup,path)
140#
141# (It's necessary to use `sh -c' because GNU make messes up by
142# trying too hard and getting things wrong).
143#
144lookup = $(call unescape-nl,$(shell sh -c $(_l-sh)))
145_l-sh = $(call shell-sq,command -v $(shell-sq) | $(call shell-escape-nl,))
146
147# is-executable
148#
149# Usage: bool-value = $(call is-executable,path)
150#
151# (It's necessary to use `sh -c' because GNU make messes up by
152# trying too hard and getting things wrong).
153#
154is-executable = $(call _is-executable-helper,$(shell-sq))
155_is-executable-helper = $(shell sh -c $(_is-executable-sh))
156_is-executable-sh = $(call shell-sq,test -f $(1) -a -x $(1) && echo y)
157
158# get-executable
159#
160# Usage: absolute-executable-path-or-empty = $(call get-executable,path)
161#
162# The goal is to get an absolute path for an executable;
163# the `command -v' is defined by POSIX, but it's not
164# necessarily very portable, so it's only used if
165# relative path resolution is requested, as determined
166# by the presence of a leading `/'.
167#
168get-executable = $(if $(1),$(if $(is-absolute),$(_ge-abspath),$(lookup)))
169_ge-abspath = $(if $(is-executable),$(1))
170
171# get-supplied-or-default-executable
172#
173# Usage: absolute-executable-path-or-empty = $(call get-executable-or-default,variable,default)
174#
175define get-executable-or-default
176$(if $($(1)),$(call _ge_attempt,$($(1)),$(1)),$(call _ge_attempt,$(2)))
177endef
178_ge_attempt = $(or $(get-executable),$(_gea_warn),$(call _gea_err,$(2)))
179_gea_warn = $(warning The path '$(1)' is not executable.)
180_gea_err = $(if $(1),$(error Please set '$(1)' appropriately))
181
182# try-cc
183# Usage: option = $(call try-cc, source-to-build, cc-options)
184try-cc = $(shell sh -c \
185 'TMP="$(OUTPUT)$(TMPOUT).$$$$"; \
186 echo "$(1)" | \
187 $(CC) -x c - $(2) -o "$$TMP" > /dev/null 2>&1 && echo y; \
188 rm -f "$$TMP"')
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 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..ad73300f7bac 100755
--- a/tools/perf/util/PERF-VERSION-GEN
+++ b/tools/perf/util/PERF-VERSION-GEN
@@ -23,12 +23,7 @@ if test -d ../../.git -o -f ../../.git &&
23then 23then
24 VN=$(echo "$VN" | sed -e 's/-/./g'); 24 VN=$(echo "$VN" | sed -e 's/-/./g');
25else 25else
26 eval `grep '^VERSION\s*=' ../../Makefile|tr -d ' '` 26 VN=$(MAKEFLAGS= make -sC ../.. kernelversion)
27 eval `grep '^PATCHLEVEL\s*=' ../../Makefile|tr -d ' '`
28 eval `grep '^SUBLEVEL\s*=' ../../Makefile|tr -d ' '`
29 eval `grep '^EXTRAVERSION\s*=' ../../Makefile|tr -d ' '`
30
31 VN="${VERSION}.${PATCHLEVEL}.${SUBLEVEL}${EXTRAVERSION}"
32fi 27fi
33 28
34VN=$(expr "$VN" : v*'\(.*\)') 29VN=$(expr "$VN" : v*'\(.*\)')
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
new file mode 100644
index 000000000000..e01af2b1a469
--- /dev/null
+++ b/tools/perf/util/annotate.c
@@ -0,0 +1,605 @@
1/*
2 * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
3 *
4 * Parts came from builtin-annotate.c, see those files for further
5 * copyright notes.
6 *
7 * Released under the GPL v2. (and only v2, not any later version)
8 */
9
10#include "util.h"
11#include "build-id.h"
12#include "color.h"
13#include "cache.h"
14#include "symbol.h"
15#include "debug.h"
16#include "annotate.h"
17#include <pthread.h>
18
19int symbol__annotate_init(struct map *map __used, struct symbol *sym)
20{
21 struct annotation *notes = symbol__annotation(sym);
22 pthread_mutex_init(&notes->lock, NULL);
23 return 0;
24}
25
26int symbol__alloc_hist(struct symbol *sym, int nevents)
27{
28 struct annotation *notes = symbol__annotation(sym);
29 size_t sizeof_sym_hist = (sizeof(struct sym_hist) +
30 (sym->end - sym->start) * sizeof(u64));
31
32 notes->src = zalloc(sizeof(*notes->src) + nevents * sizeof_sym_hist);
33 if (notes->src == NULL)
34 return -1;
35 notes->src->sizeof_sym_hist = sizeof_sym_hist;
36 notes->src->nr_histograms = nevents;
37 INIT_LIST_HEAD(&notes->src->source);
38 return 0;
39}
40
41void symbol__annotate_zero_histograms(struct symbol *sym)
42{
43 struct annotation *notes = symbol__annotation(sym);
44
45 pthread_mutex_lock(&notes->lock);
46 if (notes->src != NULL)
47 memset(notes->src->histograms, 0,
48 notes->src->nr_histograms * notes->src->sizeof_sym_hist);
49 pthread_mutex_unlock(&notes->lock);
50}
51
52int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
53 int evidx, u64 addr)
54{
55 unsigned offset;
56 struct annotation *notes;
57 struct sym_hist *h;
58
59 notes = symbol__annotation(sym);
60 if (notes->src == NULL)
61 return -ENOMEM;
62
63 pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr));
64
65 if (addr >= sym->end)
66 return 0;
67
68 offset = addr - sym->start;
69 h = annotation__histogram(notes, evidx);
70 h->sum++;
71 h->addr[offset]++;
72
73 pr_debug3("%#" PRIx64 " %s: period++ [addr: %#" PRIx64 ", %#" PRIx64
74 ", evidx=%d] => %" PRIu64 "\n", sym->start, sym->name,
75 addr, addr - sym->start, evidx, h->addr[offset]);
76 return 0;
77}
78
79static struct objdump_line *objdump_line__new(s64 offset, char *line, size_t privsize)
80{
81 struct objdump_line *self = malloc(sizeof(*self) + privsize);
82
83 if (self != NULL) {
84 self->offset = offset;
85 self->line = line;
86 }
87
88 return self;
89}
90
91void objdump_line__free(struct objdump_line *self)
92{
93 free(self->line);
94 free(self);
95}
96
97static void objdump__add_line(struct list_head *head, struct objdump_line *line)
98{
99 list_add_tail(&line->node, head);
100}
101
102struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
103 struct objdump_line *pos)
104{
105 list_for_each_entry_continue(pos, head, node)
106 if (pos->offset >= 0)
107 return pos;
108
109 return NULL;
110}
111
112static int objdump_line__print(struct objdump_line *oline, struct symbol *sym,
113 int evidx, u64 len, int min_pcnt,
114 int printed, int max_lines,
115 struct objdump_line *queue)
116{
117 static const char *prev_line;
118 static const char *prev_color;
119
120 if (oline->offset != -1) {
121 const char *path = NULL;
122 unsigned int hits = 0;
123 double percent = 0.0;
124 const char *color;
125 struct annotation *notes = symbol__annotation(sym);
126 struct source_line *src_line = notes->src->lines;
127 struct sym_hist *h = annotation__histogram(notes, evidx);
128 s64 offset = oline->offset;
129 struct objdump_line *next;
130
131 next = objdump__get_next_ip_line(&notes->src->source, oline);
132
133 while (offset < (s64)len &&
134 (next == NULL || offset < next->offset)) {
135 if (src_line) {
136 if (path == NULL)
137 path = src_line[offset].path;
138 percent += src_line[offset].percent;
139 } else
140 hits += h->addr[offset];
141
142 ++offset;
143 }
144
145 if (src_line == NULL && h->sum)
146 percent = 100.0 * hits / h->sum;
147
148 if (percent < min_pcnt)
149 return -1;
150
151 if (max_lines && printed >= max_lines)
152 return 1;
153
154 if (queue != NULL) {
155 list_for_each_entry_from(queue, &notes->src->source, node) {
156 if (queue == oline)
157 break;
158 objdump_line__print(queue, sym, evidx, len,
159 0, 0, 1, NULL);
160 }
161 }
162
163 color = get_percent_color(percent);
164
165 /*
166 * Also color the filename and line if needed, with
167 * the same color than the percentage. Don't print it
168 * twice for close colored addr with the same filename:line
169 */
170 if (path) {
171 if (!prev_line || strcmp(prev_line, path)
172 || color != prev_color) {
173 color_fprintf(stdout, color, " %s", path);
174 prev_line = path;
175 prev_color = color;
176 }
177 }
178
179 color_fprintf(stdout, color, " %7.2f", percent);
180 printf(" : ");
181 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", oline->line);
182 } else if (max_lines && printed >= max_lines)
183 return 1;
184 else {
185 if (queue)
186 return -1;
187
188 if (!*oline->line)
189 printf(" :\n");
190 else
191 printf(" : %s\n", oline->line);
192 }
193
194 return 0;
195}
196
197static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
198 FILE *file, size_t privsize)
199{
200 struct annotation *notes = symbol__annotation(sym);
201 struct objdump_line *objdump_line;
202 char *line = NULL, *tmp, *tmp2, *c;
203 size_t line_len;
204 s64 line_ip, offset = -1;
205
206 if (getline(&line, &line_len, file) < 0)
207 return -1;
208
209 if (!line)
210 return -1;
211
212 while (line_len != 0 && isspace(line[line_len - 1]))
213 line[--line_len] = '\0';
214
215 c = strchr(line, '\n');
216 if (c)
217 *c = 0;
218
219 line_ip = -1;
220
221 /*
222 * Strip leading spaces:
223 */
224 tmp = line;
225 while (*tmp) {
226 if (*tmp != ' ')
227 break;
228 tmp++;
229 }
230
231 if (*tmp) {
232 /*
233 * Parse hexa addresses followed by ':'
234 */
235 line_ip = strtoull(tmp, &tmp2, 16);
236 if (*tmp2 != ':' || tmp == tmp2 || tmp2[1] == '\0')
237 line_ip = -1;
238 }
239
240 if (line_ip != -1) {
241 u64 start = map__rip_2objdump(map, sym->start),
242 end = map__rip_2objdump(map, sym->end);
243
244 offset = line_ip - start;
245 if (offset < 0 || (u64)line_ip > end)
246 offset = -1;
247 }
248
249 objdump_line = objdump_line__new(offset, line, privsize);
250 if (objdump_line == NULL) {
251 free(line);
252 return -1;
253 }
254 objdump__add_line(&notes->src->source, objdump_line);
255
256 return 0;
257}
258
259int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
260{
261 struct dso *dso = map->dso;
262 char *filename = dso__build_id_filename(dso, NULL, 0);
263 bool free_filename = true;
264 char command[PATH_MAX * 2];
265 FILE *file;
266 int err = 0;
267 char symfs_filename[PATH_MAX];
268
269 if (filename) {
270 snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
271 symbol_conf.symfs, filename);
272 }
273
274 if (filename == NULL) {
275 if (dso->has_build_id) {
276 pr_err("Can't annotate %s: not enough memory\n",
277 sym->name);
278 return -ENOMEM;
279 }
280 goto fallback;
281 } else if (readlink(symfs_filename, command, sizeof(command)) < 0 ||
282 strstr(command, "[kernel.kallsyms]") ||
283 access(symfs_filename, R_OK)) {
284 free(filename);
285fallback:
286 /*
287 * If we don't have build-ids or the build-id file isn't in the
288 * cache, or is just a kallsyms file, well, lets hope that this
289 * DSO is the same as when 'perf record' ran.
290 */
291 filename = dso->long_name;
292 snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
293 symbol_conf.symfs, filename);
294 free_filename = false;
295 }
296
297 if (dso->symtab_type == SYMTAB__KALLSYMS) {
298 char bf[BUILD_ID_SIZE * 2 + 16] = " with build id ";
299 char *build_id_msg = NULL;
300
301 if (dso->annotate_warned)
302 goto out_free_filename;
303
304 if (dso->has_build_id) {
305 build_id__sprintf(dso->build_id,
306 sizeof(dso->build_id), bf + 15);
307 build_id_msg = bf;
308 }
309 err = -ENOENT;
310 dso->annotate_warned = 1;
311 pr_err("Can't annotate %s: No vmlinux file%s was found in the "
312 "path.\nPlease use 'perf buildid-cache -av vmlinux' or "
313 "--vmlinux vmlinux.\n",
314 sym->name, build_id_msg ?: "");
315 goto out_free_filename;
316 }
317
318 pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__,
319 filename, sym->name, map->unmap_ip(map, sym->start),
320 map->unmap_ip(map, sym->end));
321
322 pr_debug("annotating [%p] %30s : [%p] %30s\n",
323 dso, dso->long_name, sym, sym->name);
324
325 snprintf(command, sizeof(command),
326 "objdump --start-address=0x%016" PRIx64
327 " --stop-address=0x%016" PRIx64 " -dS -C %s|grep -v %s|expand",
328 map__rip_2objdump(map, sym->start),
329 map__rip_2objdump(map, sym->end),
330 symfs_filename, filename);
331
332 pr_debug("Executing: %s\n", command);
333
334 file = popen(command, "r");
335 if (!file)
336 goto out_free_filename;
337
338 while (!feof(file))
339 if (symbol__parse_objdump_line(sym, map, file, privsize) < 0)
340 break;
341
342 pclose(file);
343out_free_filename:
344 if (free_filename)
345 free(filename);
346 return err;
347}
348
349static void insert_source_line(struct rb_root *root, struct source_line *src_line)
350{
351 struct source_line *iter;
352 struct rb_node **p = &root->rb_node;
353 struct rb_node *parent = NULL;
354
355 while (*p != NULL) {
356 parent = *p;
357 iter = rb_entry(parent, struct source_line, node);
358
359 if (src_line->percent > iter->percent)
360 p = &(*p)->rb_left;
361 else
362 p = &(*p)->rb_right;
363 }
364
365 rb_link_node(&src_line->node, parent, p);
366 rb_insert_color(&src_line->node, root);
367}
368
369static void symbol__free_source_line(struct symbol *sym, int len)
370{
371 struct annotation *notes = symbol__annotation(sym);
372 struct source_line *src_line = notes->src->lines;
373 int i;
374
375 for (i = 0; i < len; i++)
376 free(src_line[i].path);
377
378 free(src_line);
379 notes->src->lines = NULL;
380}
381
382/* Get the filename:line for the colored entries */
383static int symbol__get_source_line(struct symbol *sym, struct map *map,
384 int evidx, struct rb_root *root, int len,
385 const char *filename)
386{
387 u64 start;
388 int i;
389 char cmd[PATH_MAX * 2];
390 struct source_line *src_line;
391 struct annotation *notes = symbol__annotation(sym);
392 struct sym_hist *h = annotation__histogram(notes, evidx);
393
394 if (!h->sum)
395 return 0;
396
397 src_line = notes->src->lines = calloc(len, sizeof(struct source_line));
398 if (!notes->src->lines)
399 return -1;
400
401 start = map->unmap_ip(map, sym->start);
402
403 for (i = 0; i < len; i++) {
404 char *path = NULL;
405 size_t line_len;
406 u64 offset;
407 FILE *fp;
408
409 src_line[i].percent = 100.0 * h->addr[i] / h->sum;
410 if (src_line[i].percent <= 0.5)
411 continue;
412
413 offset = start + i;
414 sprintf(cmd, "addr2line -e %s %016" PRIx64, filename, offset);
415 fp = popen(cmd, "r");
416 if (!fp)
417 continue;
418
419 if (getline(&path, &line_len, fp) < 0 || !line_len)
420 goto next;
421
422 src_line[i].path = malloc(sizeof(char) * line_len + 1);
423 if (!src_line[i].path)
424 goto next;
425
426 strcpy(src_line[i].path, path);
427 insert_source_line(root, &src_line[i]);
428
429 next:
430 pclose(fp);
431 }
432
433 return 0;
434}
435
436static void print_summary(struct rb_root *root, const char *filename)
437{
438 struct source_line *src_line;
439 struct rb_node *node;
440
441 printf("\nSorted summary for file %s\n", filename);
442 printf("----------------------------------------------\n\n");
443
444 if (RB_EMPTY_ROOT(root)) {
445 printf(" Nothing higher than %1.1f%%\n", MIN_GREEN);
446 return;
447 }
448
449 node = rb_first(root);
450 while (node) {
451 double percent;
452 const char *color;
453 char *path;
454
455 src_line = rb_entry(node, struct source_line, node);
456 percent = src_line->percent;
457 color = get_percent_color(percent);
458 path = src_line->path;
459
460 color_fprintf(stdout, color, " %7.2f %s", percent, path);
461 node = rb_next(node);
462 }
463}
464
465static void symbol__annotate_hits(struct symbol *sym, int evidx)
466{
467 struct annotation *notes = symbol__annotation(sym);
468 struct sym_hist *h = annotation__histogram(notes, evidx);
469 u64 len = sym->end - sym->start, offset;
470
471 for (offset = 0; offset < len; ++offset)
472 if (h->addr[offset] != 0)
473 printf("%*" PRIx64 ": %" PRIu64 "\n", BITS_PER_LONG / 2,
474 sym->start + offset, h->addr[offset]);
475 printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum);
476}
477
478int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
479 bool full_paths, int min_pcnt, int max_lines,
480 int context)
481{
482 struct dso *dso = map->dso;
483 const char *filename = dso->long_name, *d_filename;
484 struct annotation *notes = symbol__annotation(sym);
485 struct objdump_line *pos, *queue = NULL;
486 int printed = 2, queue_len = 0;
487 int more = 0;
488 u64 len;
489
490 if (full_paths)
491 d_filename = filename;
492 else
493 d_filename = basename(filename);
494
495 len = sym->end - sym->start;
496
497 printf(" Percent | Source code & Disassembly of %s\n", d_filename);
498 printf("------------------------------------------------\n");
499
500 if (verbose)
501 symbol__annotate_hits(sym, evidx);
502
503 list_for_each_entry(pos, &notes->src->source, node) {
504 if (context && queue == NULL) {
505 queue = pos;
506 queue_len = 0;
507 }
508
509 switch (objdump_line__print(pos, sym, evidx, len, min_pcnt,
510 printed, max_lines, queue)) {
511 case 0:
512 ++printed;
513 if (context) {
514 printed += queue_len;
515 queue = NULL;
516 queue_len = 0;
517 }
518 break;
519 case 1:
520 /* filtered by max_lines */
521 ++more;
522 break;
523 case -1:
524 default:
525 /*
526 * Filtered by min_pcnt or non IP lines when
527 * context != 0
528 */
529 if (!context)
530 break;
531 if (queue_len == context)
532 queue = list_entry(queue->node.next, typeof(*queue), node);
533 else
534 ++queue_len;
535 break;
536 }
537 }
538
539 return more;
540}
541
542void symbol__annotate_zero_histogram(struct symbol *sym, int evidx)
543{
544 struct annotation *notes = symbol__annotation(sym);
545 struct sym_hist *h = annotation__histogram(notes, evidx);
546
547 memset(h, 0, notes->src->sizeof_sym_hist);
548}
549
550void symbol__annotate_decay_histogram(struct symbol *sym, int evidx)
551{
552 struct annotation *notes = symbol__annotation(sym);
553 struct sym_hist *h = annotation__histogram(notes, evidx);
554 struct objdump_line *pos;
555 int len = sym->end - sym->start;
556
557 h->sum = 0;
558
559 list_for_each_entry(pos, &notes->src->source, node) {
560 if (pos->offset != -1 && pos->offset < len) {
561 h->addr[pos->offset] = h->addr[pos->offset] * 7 / 8;
562 h->sum += h->addr[pos->offset];
563 }
564 }
565}
566
567void objdump_line_list__purge(struct list_head *head)
568{
569 struct objdump_line *pos, *n;
570
571 list_for_each_entry_safe(pos, n, head, node) {
572 list_del(&pos->node);
573 objdump_line__free(pos);
574 }
575}
576
577int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
578 bool print_lines, bool full_paths, int min_pcnt,
579 int max_lines)
580{
581 struct dso *dso = map->dso;
582 const char *filename = dso->long_name;
583 struct rb_root source_line = RB_ROOT;
584 u64 len;
585
586 if (symbol__annotate(sym, map, 0) < 0)
587 return -1;
588
589 len = sym->end - sym->start;
590
591 if (print_lines) {
592 symbol__get_source_line(sym, map, evidx, &source_line,
593 len, filename);
594 print_summary(&source_line, filename);
595 }
596
597 symbol__annotate_printf(sym, map, evidx, full_paths,
598 min_pcnt, max_lines, 0);
599 if (print_lines)
600 symbol__free_source_line(sym, len);
601
602 objdump_line_list__purge(&symbol__annotation(sym)->src->source);
603
604 return 0;
605}
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
new file mode 100644
index 000000000000..c2c286896801
--- /dev/null
+++ b/tools/perf/util/annotate.h
@@ -0,0 +1,103 @@
1#ifndef __PERF_ANNOTATE_H
2#define __PERF_ANNOTATE_H
3
4#include <stdbool.h>
5#include "types.h"
6#include "symbol.h"
7#include <linux/list.h>
8#include <linux/rbtree.h>
9
10struct objdump_line {
11 struct list_head node;
12 s64 offset;
13 char *line;
14};
15
16void objdump_line__free(struct objdump_line *self);
17struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
18 struct objdump_line *pos);
19
20struct sym_hist {
21 u64 sum;
22 u64 addr[0];
23};
24
25struct source_line {
26 struct rb_node node;
27 double percent;
28 char *path;
29};
30
31/** struct annotated_source - symbols with hits have this attached as in sannotation
32 *
33 * @histogram: Array of addr hit histograms per event being monitored
34 * @lines: If 'print_lines' is specified, per source code line percentages
35 * @source: source parsed from objdump -dS
36 *
37 * lines is allocated, percentages calculated and all sorted by percentage
38 * when the annotation is about to be presented, so the percentages are for
39 * one of the entries in the histogram array, i.e. for the event/counter being
40 * presented. It is deallocated right after symbol__{tui,tty,etc}_annotate
41 * returns.
42 */
43struct annotated_source {
44 struct list_head source;
45 struct source_line *lines;
46 int nr_histograms;
47 int sizeof_sym_hist;
48 struct sym_hist histograms[0];
49};
50
51struct annotation {
52 pthread_mutex_t lock;
53 struct annotated_source *src;
54};
55
56struct sannotation {
57 struct annotation annotation;
58 struct symbol symbol;
59};
60
61static inline struct sym_hist *annotation__histogram(struct annotation *notes, int idx)
62{
63 return (((void *)&notes->src->histograms) +
64 (notes->src->sizeof_sym_hist * idx));
65}
66
67static inline struct annotation *symbol__annotation(struct symbol *sym)
68{
69 struct sannotation *a = container_of(sym, struct sannotation, symbol);
70 return &a->annotation;
71}
72
73int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
74 int evidx, u64 addr);
75int symbol__alloc_hist(struct symbol *sym, int nevents);
76void symbol__annotate_zero_histograms(struct symbol *sym);
77
78int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize);
79int symbol__annotate_init(struct map *map __used, struct symbol *sym);
80int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
81 bool full_paths, int min_pcnt, int max_lines,
82 int context);
83void symbol__annotate_zero_histogram(struct symbol *sym, int evidx);
84void symbol__annotate_decay_histogram(struct symbol *sym, int evidx);
85void objdump_line_list__purge(struct list_head *head);
86
87int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
88 bool print_lines, bool full_paths, int min_pcnt,
89 int max_lines);
90
91#ifdef NO_NEWT_SUPPORT
92static inline int symbol__tui_annotate(struct symbol *sym __used,
93 struct map *map __used,
94 int evidx __used, int refresh __used)
95{
96 return 0;
97}
98#else
99int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
100 int refresh);
101#endif
102
103#endif /* __PERF_ANNOTATE_H */
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 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..9b4ff16cac96 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -14,9 +14,14 @@ enum chain_mode {
14 CHAIN_GRAPH_REL 14 CHAIN_GRAPH_REL
15}; 15};
16 16
17enum chain_order {
18 ORDER_CALLER,
19 ORDER_CALLEE
20};
21
17struct callchain_node { 22struct callchain_node {
18 struct callchain_node *parent; 23 struct callchain_node *parent;
19 struct list_head brothers; 24 struct list_head siblings;
20 struct list_head children; 25 struct list_head children;
21 struct list_head val; 26 struct list_head val;
22 struct rb_node rb_node; /* to sort nodes in an rbtree */ 27 struct rb_node rb_node; /* to sort nodes in an rbtree */
@@ -41,6 +46,7 @@ struct callchain_param {
41 u32 print_limit; 46 u32 print_limit;
42 double min_percent; 47 double min_percent;
43 sort_chain_func_t sort; 48 sort_chain_func_t sort;
49 enum chain_order order;
44}; 50};
45 51
46struct callchain_list { 52struct callchain_list {
@@ -49,9 +55,30 @@ struct callchain_list {
49 struct list_head list; 55 struct list_head list;
50}; 56};
51 57
58/*
59 * A callchain cursor is a single linked list that
60 * let one feed a callchain progressively.
61 * It keeps persitent allocated entries to minimize
62 * allocations.
63 */
64struct callchain_cursor_node {
65 u64 ip;
66 struct map *map;
67 struct symbol *sym;
68 struct callchain_cursor_node *next;
69};
70
71struct callchain_cursor {
72 u64 nr;
73 struct callchain_cursor_node *first;
74 struct callchain_cursor_node **last;
75 u64 pos;
76 struct callchain_cursor_node *curr;
77};
78
52static inline void callchain_init(struct callchain_root *root) 79static inline void callchain_init(struct callchain_root *root)
53{ 80{
54 INIT_LIST_HEAD(&root->node.brothers); 81 INIT_LIST_HEAD(&root->node.siblings);
55 INIT_LIST_HEAD(&root->node.children); 82 INIT_LIST_HEAD(&root->node.children);
56 INIT_LIST_HEAD(&root->node.val); 83 INIT_LIST_HEAD(&root->node.val);
57 84
@@ -61,15 +88,54 @@ static inline void callchain_init(struct callchain_root *root)
61 root->max_depth = 0; 88 root->max_depth = 0;
62} 89}
63 90
64static inline u64 cumul_hits(struct callchain_node *node) 91static inline u64 callchain_cumul_hits(struct callchain_node *node)
65{ 92{
66 return node->hit + node->children_hit; 93 return node->hit + node->children_hit;
67} 94}
68 95
69int register_callchain_param(struct callchain_param *param); 96int callchain_register_param(struct callchain_param *param);
70int callchain_append(struct callchain_root *root, struct ip_callchain *chain, 97int callchain_append(struct callchain_root *root,
71 struct map_symbol *syms, u64 period); 98 struct callchain_cursor *cursor,
72int callchain_merge(struct callchain_root *dst, struct callchain_root *src); 99 u64 period);
100
101int callchain_merge(struct callchain_cursor *cursor,
102 struct callchain_root *dst, struct callchain_root *src);
103
104bool ip_callchain__valid(struct ip_callchain *chain,
105 const union perf_event *event);
106/*
107 * Initialize a cursor before adding entries inside, but keep
108 * the previously allocated entries as a cache.
109 */
110static inline void callchain_cursor_reset(struct callchain_cursor *cursor)
111{
112 cursor->nr = 0;
113 cursor->last = &cursor->first;
114}
115
116int callchain_cursor_append(struct callchain_cursor *cursor, u64 ip,
117 struct map *map, struct symbol *sym);
118
119/* Close a cursor writing session. Initialize for the reader */
120static inline void callchain_cursor_commit(struct callchain_cursor *cursor)
121{
122 cursor->curr = cursor->first;
123 cursor->pos = 0;
124}
125
126/* Cursor reading iteration helpers */
127static inline struct callchain_cursor_node *
128callchain_cursor_current(struct callchain_cursor *cursor)
129{
130 if (cursor->pos == cursor->nr)
131 return NULL;
132
133 return cursor->curr;
134}
73 135
74bool ip_callchain__valid(struct ip_callchain *chain, const event_t *event); 136static inline void callchain_cursor_advance(struct callchain_cursor *cursor)
137{
138 cursor->curr = cursor->curr->next;
139 cursor->pos++;
140}
75#endif /* __PERF_CALLCHAIN_H */ 141#endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c
new file mode 100644
index 000000000000..96bee5c46008
--- /dev/null
+++ b/tools/perf/util/cgroup.c
@@ -0,0 +1,178 @@
1#include "util.h"
2#include "../perf.h"
3#include "parse-options.h"
4#include "evsel.h"
5#include "cgroup.h"
6#include "debugfs.h" /* MAX_PATH, STR() */
7#include "evlist.h"
8
9int nr_cgroups;
10
11static int
12cgroupfs_find_mountpoint(char *buf, size_t maxlen)
13{
14 FILE *fp;
15 char mountpoint[MAX_PATH+1], tokens[MAX_PATH+1], type[MAX_PATH+1];
16 char *token, *saved_ptr = NULL;
17 int found = 0;
18
19 fp = fopen("/proc/mounts", "r");
20 if (!fp)
21 return -1;
22
23 /*
24 * in order to handle split hierarchy, we need to scan /proc/mounts
25 * and inspect every cgroupfs mount point to find one that has
26 * perf_event subsystem
27 */
28 while (fscanf(fp, "%*s %"STR(MAX_PATH)"s %"STR(MAX_PATH)"s %"
29 STR(MAX_PATH)"s %*d %*d\n",
30 mountpoint, type, tokens) == 3) {
31
32 if (!strcmp(type, "cgroup")) {
33
34 token = strtok_r(tokens, ",", &saved_ptr);
35
36 while (token != NULL) {
37 if (!strcmp(token, "perf_event")) {
38 found = 1;
39 break;
40 }
41 token = strtok_r(NULL, ",", &saved_ptr);
42 }
43 }
44 if (found)
45 break;
46 }
47 fclose(fp);
48 if (!found)
49 return -1;
50
51 if (strlen(mountpoint) < maxlen) {
52 strcpy(buf, mountpoint);
53 return 0;
54 }
55 return -1;
56}
57
58static int open_cgroup(char *name)
59{
60 char path[MAX_PATH+1];
61 char mnt[MAX_PATH+1];
62 int fd;
63
64
65 if (cgroupfs_find_mountpoint(mnt, MAX_PATH+1))
66 return -1;
67
68 snprintf(path, MAX_PATH, "%s/%s", mnt, name);
69
70 fd = open(path, O_RDONLY);
71 if (fd == -1)
72 fprintf(stderr, "no access to cgroup %s\n", path);
73
74 return fd;
75}
76
77static int add_cgroup(struct perf_evlist *evlist, char *str)
78{
79 struct perf_evsel *counter;
80 struct cgroup_sel *cgrp = NULL;
81 int n;
82 /*
83 * check if cgrp is already defined, if so we reuse it
84 */
85 list_for_each_entry(counter, &evlist->entries, node) {
86 cgrp = counter->cgrp;
87 if (!cgrp)
88 continue;
89 if (!strcmp(cgrp->name, str))
90 break;
91
92 cgrp = NULL;
93 }
94
95 if (!cgrp) {
96 cgrp = zalloc(sizeof(*cgrp));
97 if (!cgrp)
98 return -1;
99
100 cgrp->name = str;
101
102 cgrp->fd = open_cgroup(str);
103 if (cgrp->fd == -1) {
104 free(cgrp);
105 return -1;
106 }
107 }
108
109 /*
110 * find corresponding event
111 * if add cgroup N, then need to find event N
112 */
113 n = 0;
114 list_for_each_entry(counter, &evlist->entries, node) {
115 if (n == nr_cgroups)
116 goto found;
117 n++;
118 }
119 if (cgrp->refcnt == 0)
120 free(cgrp);
121
122 return -1;
123found:
124 cgrp->refcnt++;
125 counter->cgrp = cgrp;
126 return 0;
127}
128
129void close_cgroup(struct cgroup_sel *cgrp)
130{
131 if (!cgrp)
132 return;
133
134 /* XXX: not reentrant */
135 if (--cgrp->refcnt == 0) {
136 close(cgrp->fd);
137 free(cgrp->name);
138 free(cgrp);
139 }
140}
141
142int parse_cgroups(const struct option *opt __used, const char *str,
143 int unset __used)
144{
145 struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
146 const char *p, *e, *eos = str + strlen(str);
147 char *s;
148 int ret;
149
150 if (list_empty(&evlist->entries)) {
151 fprintf(stderr, "must define events before cgroups\n");
152 return -1;
153 }
154
155 for (;;) {
156 p = strchr(str, ',');
157 e = p ? p : eos;
158
159 /* allow empty cgroups, i.e., skip */
160 if (e - str) {
161 /* termination added */
162 s = strndup(str, e - str);
163 if (!s)
164 return -1;
165 ret = add_cgroup(evlist, s);
166 if (ret) {
167 free(s);
168 return -1;
169 }
170 }
171 /* nr_cgroups is increased een for empty cgroups */
172 nr_cgroups++;
173 if (!p)
174 break;
175 str = p+1;
176 }
177 return 0;
178}
diff --git a/tools/perf/util/cgroup.h b/tools/perf/util/cgroup.h
new file mode 100644
index 000000000000..89acd6debdc5
--- /dev/null
+++ b/tools/perf/util/cgroup.h
@@ -0,0 +1,17 @@
1#ifndef __CGROUP_H__
2#define __CGROUP_H__
3
4struct option;
5
6struct cgroup_sel {
7 char *name;
8 int fd;
9 int refcnt;
10};
11
12
13extern int nr_cgroups; /* number of explicit cgroups defined */
14extern void close_cgroup(struct cgroup_sel *cgrp);
15extern int parse_cgroups(const struct option *opt, const char *str, int unset);
16
17#endif /* __CGROUP_H__ */
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index e02d78cae70f..fe02903f7d0f 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -399,7 +399,6 @@ static int perf_config_global(void)
399int perf_config(config_fn_t fn, void *data) 399int perf_config(config_fn_t fn, void *data)
400{ 400{
401 int ret = 0, found = 0; 401 int ret = 0, found = 0;
402 char *repo_config = NULL;
403 const char *home = NULL; 402 const char *home = NULL;
404 403
405 /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */ 404 /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */
@@ -414,19 +413,32 @@ int perf_config(config_fn_t fn, void *data)
414 home = getenv("HOME"); 413 home = getenv("HOME");
415 if (perf_config_global() && home) { 414 if (perf_config_global() && home) {
416 char *user_config = strdup(mkpath("%s/.perfconfig", home)); 415 char *user_config = strdup(mkpath("%s/.perfconfig", home));
417 if (!access(user_config, R_OK)) { 416 struct stat st;
418 ret += perf_config_from_file(fn, user_config, data); 417
419 found += 1; 418 if (user_config == NULL) {
419 warning("Not enough memory to process %s/.perfconfig, "
420 "ignoring it.", home);
421 goto out;
420 } 422 }
421 free(user_config);
422 }
423 423
424 repo_config = perf_pathdup("config"); 424 if (stat(user_config, &st) < 0)
425 if (!access(repo_config, R_OK)) { 425 goto out_free;
426 ret += perf_config_from_file(fn, repo_config, data); 426
427 if (st.st_uid && (st.st_uid != geteuid())) {
428 warning("File %s not owned by current user or root, "
429 "ignoring it.", user_config);
430 goto out_free;
431 }
432
433 if (!st.st_size)
434 goto out_free;
435
436 ret += perf_config_from_file(fn, user_config, data);
427 found += 1; 437 found += 1;
438out_free:
439 free(user_config);
428 } 440 }
429 free(repo_config); 441out:
430 if (found == 0) 442 if (found == 0)
431 return -1; 443 return -1;
432 return ret; 444 return ret;
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
index 3ccaa1043383..6893eec693ab 100644
--- a/tools/perf/util/cpumap.c
+++ b/tools/perf/util/cpumap.c
@@ -177,3 +177,8 @@ struct cpu_map *cpu_map__dummy_new(void)
177 177
178 return cpus; 178 return cpus;
179} 179}
180
181void cpu_map__delete(struct cpu_map *map)
182{
183 free(map);
184}
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
index f7a4f42f6307..072c0a374794 100644
--- a/tools/perf/util/cpumap.h
+++ b/tools/perf/util/cpumap.h
@@ -8,6 +8,6 @@ struct cpu_map {
8 8
9struct cpu_map *cpu_map__new(const char *cpu_list); 9struct cpu_map *cpu_map__new(const char *cpu_list);
10struct cpu_map *cpu_map__dummy_new(void); 10struct cpu_map *cpu_map__dummy_new(void);
11void *cpu_map__delete(struct cpu_map *map); 11void cpu_map__delete(struct cpu_map *map);
12 12
13#endif /* __PERF_CPUMAP_H */ 13#endif /* __PERF_CPUMAP_H */
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index 01bbe8ecec3f..155749d74350 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -57,7 +57,17 @@ void ui__warning(const char *format, ...)
57} 57}
58#endif 58#endif
59 59
60void trace_event(event_t *event) 60void ui__warning_paranoid(void)
61{
62 ui__warning("Permission error - are you root?\n"
63 "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n"
64 " -1 - Not paranoid at all\n"
65 " 0 - Disallow raw tracepoint access for unpriv\n"
66 " 1 - Disallow cpu events for unpriv\n"
67 " 2 - Disallow kernel profiling for unpriv\n");
68}
69
70void trace_event(union perf_event *event)
61{ 71{
62 unsigned char *raw_event = (void *)event; 72 unsigned char *raw_event = (void *)event;
63 const char *color = PERF_COLOR_BLUE; 73 const char *color = PERF_COLOR_BLUE;
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index ca35fd66b5df..fd53db47e3de 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -9,7 +9,7 @@ extern int verbose;
9extern bool quiet, dump_trace; 9extern bool quiet, dump_trace;
10 10
11int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); 11int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
12void trace_event(event_t *event); 12void trace_event(union perf_event *event);
13 13
14struct ui_progress; 14struct ui_progress;
15 15
@@ -36,5 +36,6 @@ int ui_helpline__show_help(const char *format, va_list ap);
36#endif 36#endif
37 37
38void ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); 38void ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2)));
39void ui__warning_paranoid(void);
39 40
40#endif /* __PERF_DEBUG_H */ 41#endif /* __PERF_DEBUG_H */
diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c
new file mode 100644
index 000000000000..fddf40f30d3e
--- /dev/null
+++ b/tools/perf/util/dwarf-aux.c
@@ -0,0 +1,663 @@
1/*
2 * dwarf-aux.c : libdw auxiliary interfaces
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 *
18 */
19
20#include <stdbool.h>
21#include "util.h"
22#include "debug.h"
23#include "dwarf-aux.h"
24
25/**
26 * cu_find_realpath - Find the realpath of the target file
27 * @cu_die: A DIE(dwarf information entry) of CU(compilation Unit)
28 * @fname: The tail filename of the target file
29 *
30 * Find the real(long) path of @fname in @cu_die.
31 */
32const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname)
33{
34 Dwarf_Files *files;
35 size_t nfiles, i;
36 const char *src = NULL;
37 int ret;
38
39 if (!fname)
40 return NULL;
41
42 ret = dwarf_getsrcfiles(cu_die, &files, &nfiles);
43 if (ret != 0)
44 return NULL;
45
46 for (i = 0; i < nfiles; i++) {
47 src = dwarf_filesrc(files, i, NULL, NULL);
48 if (strtailcmp(src, fname) == 0)
49 break;
50 }
51 if (i == nfiles)
52 return NULL;
53 return src;
54}
55
56/**
57 * cu_get_comp_dir - Get the path of compilation directory
58 * @cu_die: a CU DIE
59 *
60 * Get the path of compilation directory of given @cu_die.
61 * Since this depends on DW_AT_comp_dir, older gcc will not
62 * embedded it. In that case, this returns NULL.
63 */
64const char *cu_get_comp_dir(Dwarf_Die *cu_die)
65{
66 Dwarf_Attribute attr;
67 if (dwarf_attr(cu_die, DW_AT_comp_dir, &attr) == NULL)
68 return NULL;
69 return dwarf_formstring(&attr);
70}
71
72/**
73 * cu_find_lineinfo - Get a line number and file name for given address
74 * @cu_die: a CU DIE
75 * @addr: An address
76 * @fname: a pointer which returns the file name string
77 * @lineno: a pointer which returns the line number
78 *
79 * Find a line number and file name for @addr in @cu_die.
80 */
81int cu_find_lineinfo(Dwarf_Die *cu_die, unsigned long addr,
82 const char **fname, int *lineno)
83{
84 Dwarf_Line *line;
85 Dwarf_Addr laddr;
86
87 line = dwarf_getsrc_die(cu_die, (Dwarf_Addr)addr);
88 if (line && dwarf_lineaddr(line, &laddr) == 0 &&
89 addr == (unsigned long)laddr && dwarf_lineno(line, lineno) == 0) {
90 *fname = dwarf_linesrc(line, NULL, NULL);
91 if (!*fname)
92 /* line number is useless without filename */
93 *lineno = 0;
94 }
95
96 return *lineno ?: -ENOENT;
97}
98
99/**
100 * die_compare_name - Compare diename and tname
101 * @dw_die: a DIE
102 * @tname: a string of target name
103 *
104 * Compare the name of @dw_die and @tname. Return false if @dw_die has no name.
105 */
106bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
107{
108 const char *name;
109 name = dwarf_diename(dw_die);
110 return name ? (strcmp(tname, name) == 0) : false;
111}
112
113/**
114 * die_get_call_lineno - Get callsite line number of inline-function instance
115 * @in_die: a DIE of an inlined function instance
116 *
117 * Get call-site line number of @in_die. This means from where the inline
118 * function is called.
119 */
120int die_get_call_lineno(Dwarf_Die *in_die)
121{
122 Dwarf_Attribute attr;
123 Dwarf_Word ret;
124
125 if (!dwarf_attr(in_die, DW_AT_call_line, &attr))
126 return -ENOENT;
127
128 dwarf_formudata(&attr, &ret);
129 return (int)ret;
130}
131
132/**
133 * die_get_type - Get type DIE
134 * @vr_die: a DIE of a variable
135 * @die_mem: where to store a type DIE
136 *
137 * Get a DIE of the type of given variable (@vr_die), and store
138 * it to die_mem. Return NULL if fails to get a type DIE.
139 */
140Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
141{
142 Dwarf_Attribute attr;
143
144 if (dwarf_attr_integrate(vr_die, DW_AT_type, &attr) &&
145 dwarf_formref_die(&attr, die_mem))
146 return die_mem;
147 else
148 return NULL;
149}
150
151/* Get a type die, but skip qualifiers */
152static Dwarf_Die *__die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
153{
154 int tag;
155
156 do {
157 vr_die = die_get_type(vr_die, die_mem);
158 if (!vr_die)
159 break;
160 tag = dwarf_tag(vr_die);
161 } while (tag == DW_TAG_const_type ||
162 tag == DW_TAG_restrict_type ||
163 tag == DW_TAG_volatile_type ||
164 tag == DW_TAG_shared_type);
165
166 return vr_die;
167}
168
169/**
170 * die_get_real_type - Get a type die, but skip qualifiers and typedef
171 * @vr_die: a DIE of a variable
172 * @die_mem: where to store a type DIE
173 *
174 * Get a DIE of the type of given variable (@vr_die), and store
175 * it to die_mem. Return NULL if fails to get a type DIE.
176 * If the type is qualifiers (e.g. const) or typedef, this skips it
177 * and tries to find real type (structure or basic types, e.g. int).
178 */
179Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
180{
181 do {
182 vr_die = __die_get_real_type(vr_die, die_mem);
183 } while (vr_die && dwarf_tag(vr_die) == DW_TAG_typedef);
184
185 return vr_die;
186}
187
188/* Get attribute and translate it as a udata */
189static int die_get_attr_udata(Dwarf_Die *tp_die, unsigned int attr_name,
190 Dwarf_Word *result)
191{
192 Dwarf_Attribute attr;
193
194 if (dwarf_attr(tp_die, attr_name, &attr) == NULL ||
195 dwarf_formudata(&attr, result) != 0)
196 return -ENOENT;
197
198 return 0;
199}
200
201/**
202 * die_is_signed_type - Check whether a type DIE is signed or not
203 * @tp_die: a DIE of a type
204 *
205 * Get the encoding of @tp_die and return true if the encoding
206 * is signed.
207 */
208bool die_is_signed_type(Dwarf_Die *tp_die)
209{
210 Dwarf_Word ret;
211
212 if (die_get_attr_udata(tp_die, DW_AT_encoding, &ret))
213 return false;
214
215 return (ret == DW_ATE_signed_char || ret == DW_ATE_signed ||
216 ret == DW_ATE_signed_fixed);
217}
218
219/**
220 * die_get_data_member_location - Get the data-member offset
221 * @mb_die: a DIE of a member of a data structure
222 * @offs: The offset of the member in the data structure
223 *
224 * Get the offset of @mb_die in the data structure including @mb_die, and
225 * stores result offset to @offs. If any error occurs this returns errno.
226 */
227int die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs)
228{
229 Dwarf_Attribute attr;
230 Dwarf_Op *expr;
231 size_t nexpr;
232 int ret;
233
234 if (dwarf_attr(mb_die, DW_AT_data_member_location, &attr) == NULL)
235 return -ENOENT;
236
237 if (dwarf_formudata(&attr, offs) != 0) {
238 /* DW_AT_data_member_location should be DW_OP_plus_uconst */
239 ret = dwarf_getlocation(&attr, &expr, &nexpr);
240 if (ret < 0 || nexpr == 0)
241 return -ENOENT;
242
243 if (expr[0].atom != DW_OP_plus_uconst || nexpr != 1) {
244 pr_debug("Unable to get offset:Unexpected OP %x (%zd)\n",
245 expr[0].atom, nexpr);
246 return -ENOTSUP;
247 }
248 *offs = (Dwarf_Word)expr[0].number;
249 }
250 return 0;
251}
252
253/**
254 * die_find_child - Generic DIE search function in DIE tree
255 * @rt_die: a root DIE
256 * @callback: a callback function
257 * @data: a user data passed to the callback function
258 * @die_mem: a buffer for result DIE
259 *
260 * Trace DIE tree from @rt_die and call @callback for each child DIE.
261 * If @callback returns DIE_FIND_CB_END, this stores the DIE into
262 * @die_mem and returns it. If @callback returns DIE_FIND_CB_CONTINUE,
263 * this continues to trace the tree. Optionally, @callback can return
264 * DIE_FIND_CB_CHILD and DIE_FIND_CB_SIBLING, those means trace only
265 * the children and trace only the siblings respectively.
266 * Returns NULL if @callback can't find any appropriate DIE.
267 */
268Dwarf_Die *die_find_child(Dwarf_Die *rt_die,
269 int (*callback)(Dwarf_Die *, void *),
270 void *data, Dwarf_Die *die_mem)
271{
272 Dwarf_Die child_die;
273 int ret;
274
275 ret = dwarf_child(rt_die, die_mem);
276 if (ret != 0)
277 return NULL;
278
279 do {
280 ret = callback(die_mem, data);
281 if (ret == DIE_FIND_CB_END)
282 return die_mem;
283
284 if ((ret & DIE_FIND_CB_CHILD) &&
285 die_find_child(die_mem, callback, data, &child_die)) {
286 memcpy(die_mem, &child_die, sizeof(Dwarf_Die));
287 return die_mem;
288 }
289 } while ((ret & DIE_FIND_CB_SIBLING) &&
290 dwarf_siblingof(die_mem, die_mem) == 0);
291
292 return NULL;
293}
294
295struct __addr_die_search_param {
296 Dwarf_Addr addr;
297 Dwarf_Die *die_mem;
298};
299
300/* die_find callback for non-inlined function search */
301static int __die_search_func_cb(Dwarf_Die *fn_die, void *data)
302{
303 struct __addr_die_search_param *ad = data;
304
305 if (dwarf_tag(fn_die) == DW_TAG_subprogram &&
306 dwarf_haspc(fn_die, ad->addr)) {
307 memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die));
308 return DWARF_CB_ABORT;
309 }
310 return DWARF_CB_OK;
311}
312
313/**
314 * die_find_realfunc - Search a non-inlined function at given address
315 * @cu_die: a CU DIE which including @addr
316 * @addr: target address
317 * @die_mem: a buffer for result DIE
318 *
319 * Search a non-inlined function DIE which includes @addr. Stores the
320 * DIE to @die_mem and returns it if found. Returns NULl if failed.
321 */
322Dwarf_Die *die_find_realfunc(Dwarf_Die *cu_die, Dwarf_Addr addr,
323 Dwarf_Die *die_mem)
324{
325 struct __addr_die_search_param ad;
326 ad.addr = addr;
327 ad.die_mem = die_mem;
328 /* dwarf_getscopes can't find subprogram. */
329 if (!dwarf_getfuncs(cu_die, __die_search_func_cb, &ad, 0))
330 return NULL;
331 else
332 return die_mem;
333}
334
335/* die_find callback for inline function search */
336static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data)
337{
338 Dwarf_Addr *addr = data;
339
340 if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine &&
341 dwarf_haspc(die_mem, *addr))
342 return DIE_FIND_CB_END;
343
344 return DIE_FIND_CB_CONTINUE;
345}
346
347/**
348 * die_find_inlinefunc - Search an inlined function at given address
349 * @cu_die: a CU DIE which including @addr
350 * @addr: target address
351 * @die_mem: a buffer for result DIE
352 *
353 * Search an inlined function DIE which includes @addr. Stores the
354 * DIE to @die_mem and returns it if found. Returns NULl if failed.
355 * If several inlined functions are expanded recursively, this trace
356 * it and returns deepest one.
357 */
358Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
359 Dwarf_Die *die_mem)
360{
361 Dwarf_Die tmp_die;
362
363 sp_die = die_find_child(sp_die, __die_find_inline_cb, &addr, &tmp_die);
364 if (!sp_die)
365 return NULL;
366
367 /* Inlined function could be recursive. Trace it until fail */
368 while (sp_die) {
369 memcpy(die_mem, sp_die, sizeof(Dwarf_Die));
370 sp_die = die_find_child(sp_die, __die_find_inline_cb, &addr,
371 &tmp_die);
372 }
373
374 return die_mem;
375}
376
377/* Line walker internal parameters */
378struct __line_walk_param {
379 const char *fname;
380 line_walk_callback_t callback;
381 void *data;
382 int retval;
383};
384
385static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data)
386{
387 struct __line_walk_param *lw = data;
388 Dwarf_Addr addr;
389 int lineno;
390
391 if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) {
392 lineno = die_get_call_lineno(in_die);
393 if (lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) {
394 lw->retval = lw->callback(lw->fname, lineno, addr,
395 lw->data);
396 if (lw->retval != 0)
397 return DIE_FIND_CB_END;
398 }
399 }
400 return DIE_FIND_CB_SIBLING;
401}
402
403/* Walk on lines of blocks included in given DIE */
404static int __die_walk_funclines(Dwarf_Die *sp_die,
405 line_walk_callback_t callback, void *data)
406{
407 struct __line_walk_param lw = {
408 .callback = callback,
409 .data = data,
410 .retval = 0,
411 };
412 Dwarf_Die die_mem;
413 Dwarf_Addr addr;
414 int lineno;
415
416 /* Handle function declaration line */
417 lw.fname = dwarf_decl_file(sp_die);
418 if (lw.fname && dwarf_decl_line(sp_die, &lineno) == 0 &&
419 dwarf_entrypc(sp_die, &addr) == 0) {
420 lw.retval = callback(lw.fname, lineno, addr, data);
421 if (lw.retval != 0)
422 goto done;
423 }
424 die_find_child(sp_die, __die_walk_funclines_cb, &lw, &die_mem);
425done:
426 return lw.retval;
427}
428
429static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data)
430{
431 struct __line_walk_param *lw = data;
432
433 lw->retval = __die_walk_funclines(sp_die, lw->callback, lw->data);
434 if (lw->retval != 0)
435 return DWARF_CB_ABORT;
436
437 return DWARF_CB_OK;
438}
439
440/**
441 * die_walk_lines - Walk on lines inside given DIE
442 * @rt_die: a root DIE (CU or subprogram)
443 * @callback: callback routine
444 * @data: user data
445 *
446 * Walk on all lines inside given @rt_die and call @callback on each line.
447 * If the @rt_die is a function, walk only on the lines inside the function,
448 * otherwise @rt_die must be a CU DIE.
449 * Note that this walks not only dwarf line list, but also function entries
450 * and inline call-site.
451 */
452int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data)
453{
454 Dwarf_Lines *lines;
455 Dwarf_Line *line;
456 Dwarf_Addr addr;
457 const char *fname;
458 int lineno, ret = 0;
459 Dwarf_Die die_mem, *cu_die;
460 size_t nlines, i;
461
462 /* Get the CU die */
463 if (dwarf_tag(rt_die) == DW_TAG_subprogram)
464 cu_die = dwarf_diecu(rt_die, &die_mem, NULL, NULL);
465 else
466 cu_die = rt_die;
467 if (!cu_die) {
468 pr_debug2("Failed to get CU from subprogram\n");
469 return -EINVAL;
470 }
471
472 /* Get lines list in the CU */
473 if (dwarf_getsrclines(cu_die, &lines, &nlines) != 0) {
474 pr_debug2("Failed to get source lines on this CU.\n");
475 return -ENOENT;
476 }
477 pr_debug2("Get %zd lines from this CU\n", nlines);
478
479 /* Walk on the lines on lines list */
480 for (i = 0; i < nlines; i++) {
481 line = dwarf_onesrcline(lines, i);
482 if (line == NULL ||
483 dwarf_lineno(line, &lineno) != 0 ||
484 dwarf_lineaddr(line, &addr) != 0) {
485 pr_debug2("Failed to get line info. "
486 "Possible error in debuginfo.\n");
487 continue;
488 }
489 /* Filter lines based on address */
490 if (rt_die != cu_die)
491 /*
492 * Address filtering
493 * The line is included in given function, and
494 * no inline block includes it.
495 */
496 if (!dwarf_haspc(rt_die, addr) ||
497 die_find_inlinefunc(rt_die, addr, &die_mem))
498 continue;
499 /* Get source line */
500 fname = dwarf_linesrc(line, NULL, NULL);
501
502 ret = callback(fname, lineno, addr, data);
503 if (ret != 0)
504 return ret;
505 }
506
507 /*
508 * Dwarf lines doesn't include function declarations and inlined
509 * subroutines. We have to check functions list or given function.
510 */
511 if (rt_die != cu_die)
512 ret = __die_walk_funclines(rt_die, callback, data);
513 else {
514 struct __line_walk_param param = {
515 .callback = callback,
516 .data = data,
517 .retval = 0,
518 };
519 dwarf_getfuncs(cu_die, __die_walk_culines_cb, &param, 0);
520 ret = param.retval;
521 }
522
523 return ret;
524}
525
526struct __find_variable_param {
527 const char *name;
528 Dwarf_Addr addr;
529};
530
531static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data)
532{
533 struct __find_variable_param *fvp = data;
534 int tag;
535
536 tag = dwarf_tag(die_mem);
537 if ((tag == DW_TAG_formal_parameter ||
538 tag == DW_TAG_variable) &&
539 die_compare_name(die_mem, fvp->name))
540 return DIE_FIND_CB_END;
541
542 if (dwarf_haspc(die_mem, fvp->addr))
543 return DIE_FIND_CB_CONTINUE;
544 else
545 return DIE_FIND_CB_SIBLING;
546}
547
548/**
549 * die_find_variable_at - Find a given name variable at given address
550 * @sp_die: a function DIE
551 * @name: variable name
552 * @addr: address
553 * @die_mem: a buffer for result DIE
554 *
555 * Find a variable DIE called @name at @addr in @sp_die.
556 */
557Dwarf_Die *die_find_variable_at(Dwarf_Die *sp_die, const char *name,
558 Dwarf_Addr addr, Dwarf_Die *die_mem)
559{
560 struct __find_variable_param fvp = { .name = name, .addr = addr};
561
562 return die_find_child(sp_die, __die_find_variable_cb, (void *)&fvp,
563 die_mem);
564}
565
566static int __die_find_member_cb(Dwarf_Die *die_mem, void *data)
567{
568 const char *name = data;
569
570 if ((dwarf_tag(die_mem) == DW_TAG_member) &&
571 die_compare_name(die_mem, name))
572 return DIE_FIND_CB_END;
573
574 return DIE_FIND_CB_SIBLING;
575}
576
577/**
578 * die_find_member - Find a given name member in a data structure
579 * @st_die: a data structure type DIE
580 * @name: member name
581 * @die_mem: a buffer for result DIE
582 *
583 * Find a member DIE called @name in @st_die.
584 */
585Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name,
586 Dwarf_Die *die_mem)
587{
588 return die_find_child(st_die, __die_find_member_cb, (void *)name,
589 die_mem);
590}
591
592/**
593 * die_get_typename - Get the name of given variable DIE
594 * @vr_die: a variable DIE
595 * @buf: a buffer for result type name
596 * @len: a max-length of @buf
597 *
598 * Get the name of @vr_die and stores it to @buf. Return the actual length
599 * of type name if succeeded. Return -E2BIG if @len is not enough long, and
600 * Return -ENOENT if failed to find type name.
601 * Note that the result will stores typedef name if possible, and stores
602 * "*(function_type)" if the type is a function pointer.
603 */
604int die_get_typename(Dwarf_Die *vr_die, char *buf, int len)
605{
606 Dwarf_Die type;
607 int tag, ret, ret2;
608 const char *tmp = "";
609
610 if (__die_get_real_type(vr_die, &type) == NULL)
611 return -ENOENT;
612
613 tag = dwarf_tag(&type);
614 if (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)
615 tmp = "*";
616 else if (tag == DW_TAG_subroutine_type) {
617 /* Function pointer */
618 ret = snprintf(buf, len, "(function_type)");
619 return (ret >= len) ? -E2BIG : ret;
620 } else {
621 if (!dwarf_diename(&type))
622 return -ENOENT;
623 if (tag == DW_TAG_union_type)
624 tmp = "union ";
625 else if (tag == DW_TAG_structure_type)
626 tmp = "struct ";
627 /* Write a base name */
628 ret = snprintf(buf, len, "%s%s", tmp, dwarf_diename(&type));
629 return (ret >= len) ? -E2BIG : ret;
630 }
631 ret = die_get_typename(&type, buf, len);
632 if (ret > 0) {
633 ret2 = snprintf(buf + ret, len - ret, "%s", tmp);
634 ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret;
635 }
636 return ret;
637}
638
639/**
640 * die_get_varname - Get the name and type of given variable DIE
641 * @vr_die: a variable DIE
642 * @buf: a buffer for type and variable name
643 * @len: the max-length of @buf
644 *
645 * Get the name and type of @vr_die and stores it in @buf as "type\tname".
646 */
647int die_get_varname(Dwarf_Die *vr_die, char *buf, int len)
648{
649 int ret, ret2;
650
651 ret = die_get_typename(vr_die, buf, len);
652 if (ret < 0) {
653 pr_debug("Failed to get type, make it unknown.\n");
654 ret = snprintf(buf, len, "(unknown_type)");
655 }
656 if (ret > 0) {
657 ret2 = snprintf(buf + ret, len - ret, "\t%s",
658 dwarf_diename(vr_die));
659 ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret;
660 }
661 return ret;
662}
663
diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h
new file mode 100644
index 000000000000..bc3b21167e70
--- /dev/null
+++ b/tools/perf/util/dwarf-aux.h
@@ -0,0 +1,100 @@
1#ifndef _DWARF_AUX_H
2#define _DWARF_AUX_H
3/*
4 * dwarf-aux.h : libdw auxiliary interfaces
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program 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
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 *
20 */
21
22#include <dwarf.h>
23#include <elfutils/libdw.h>
24#include <elfutils/libdwfl.h>
25#include <elfutils/version.h>
26
27/* Find the realpath of the target file */
28extern const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname);
29
30/* Get DW_AT_comp_dir (should be NULL with older gcc) */
31extern const char *cu_get_comp_dir(Dwarf_Die *cu_die);
32
33/* Get a line number and file name for given address */
34extern int cu_find_lineinfo(Dwarf_Die *cudie, unsigned long addr,
35 const char **fname, int *lineno);
36
37/* Compare diename and tname */
38extern bool die_compare_name(Dwarf_Die *dw_die, const char *tname);
39
40/* Get callsite line number of inline-function instance */
41extern int die_get_call_lineno(Dwarf_Die *in_die);
42
43/* Get type die */
44extern Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem);
45
46/* Get a type die, but skip qualifiers and typedef */
47extern Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem);
48
49/* Check whether the DIE is signed or not */
50extern bool die_is_signed_type(Dwarf_Die *tp_die);
51
52/* Get data_member_location offset */
53extern int die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs);
54
55/* Return values for die_find_child() callbacks */
56enum {
57 DIE_FIND_CB_END = 0, /* End of Search */
58 DIE_FIND_CB_CHILD = 1, /* Search only children */
59 DIE_FIND_CB_SIBLING = 2, /* Search only siblings */
60 DIE_FIND_CB_CONTINUE = 3, /* Search children and siblings */
61};
62
63/* Search child DIEs */
64extern Dwarf_Die *die_find_child(Dwarf_Die *rt_die,
65 int (*callback)(Dwarf_Die *, void *),
66 void *data, Dwarf_Die *die_mem);
67
68/* Search a non-inlined function including given address */
69extern Dwarf_Die *die_find_realfunc(Dwarf_Die *cu_die, Dwarf_Addr addr,
70 Dwarf_Die *die_mem);
71
72/* Search an inlined function including given address */
73extern Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
74 Dwarf_Die *die_mem);
75
76/* Walker on lines (Note: line number will not be sorted) */
77typedef int (* line_walk_callback_t) (const char *fname, int lineno,
78 Dwarf_Addr addr, void *data);
79
80/*
81 * Walk on lines inside given DIE. If the DIE is a subprogram, walk only on
82 * the lines inside the subprogram, otherwise the DIE must be a CU DIE.
83 */
84extern int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback,
85 void *data);
86
87/* Find a variable called 'name' at given address */
88extern Dwarf_Die *die_find_variable_at(Dwarf_Die *sp_die, const char *name,
89 Dwarf_Addr addr, Dwarf_Die *die_mem);
90
91/* Find a member called 'name' */
92extern Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name,
93 Dwarf_Die *die_mem);
94
95/* Get the name of given variable DIE */
96extern int die_get_typename(Dwarf_Die *vr_die, char *buf, int len);
97
98/* Get the name and type of given variable DIE, stored as "type\tname" */
99extern int die_get_varname(Dwarf_Die *vr_die, char *buf, int len);
100#endif
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 50d0a931497a..3c1b8a632101 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -6,35 +6,36 @@
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 9#include "thread_map.h"
10static const char *event__name[] = { 10
11 [0] = "TOTAL", 11static const char *perf_event__names[] = {
12 [PERF_RECORD_MMAP] = "MMAP", 12 [0] = "TOTAL",
13 [PERF_RECORD_LOST] = "LOST", 13 [PERF_RECORD_MMAP] = "MMAP",
14 [PERF_RECORD_COMM] = "COMM", 14 [PERF_RECORD_LOST] = "LOST",
15 [PERF_RECORD_EXIT] = "EXIT", 15 [PERF_RECORD_COMM] = "COMM",
16 [PERF_RECORD_THROTTLE] = "THROTTLE", 16 [PERF_RECORD_EXIT] = "EXIT",
17 [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE", 17 [PERF_RECORD_THROTTLE] = "THROTTLE",
18 [PERF_RECORD_FORK] = "FORK", 18 [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE",
19 [PERF_RECORD_READ] = "READ", 19 [PERF_RECORD_FORK] = "FORK",
20 [PERF_RECORD_SAMPLE] = "SAMPLE", 20 [PERF_RECORD_READ] = "READ",
21 [PERF_RECORD_HEADER_ATTR] = "ATTR", 21 [PERF_RECORD_SAMPLE] = "SAMPLE",
22 [PERF_RECORD_HEADER_EVENT_TYPE] = "EVENT_TYPE", 22 [PERF_RECORD_HEADER_ATTR] = "ATTR",
23 [PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA", 23 [PERF_RECORD_HEADER_EVENT_TYPE] = "EVENT_TYPE",
24 [PERF_RECORD_HEADER_BUILD_ID] = "BUILD_ID", 24 [PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA",
25 [PERF_RECORD_FINISHED_ROUND] = "FINISHED_ROUND", 25 [PERF_RECORD_HEADER_BUILD_ID] = "BUILD_ID",
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,24 @@ 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_map(struct thread_map *threads, 269int perf_event__synthesize_thread_map(struct thread_map *threads,
267 event__handler_t process, 270 perf_event__handler_t process,
268 struct perf_session *session) 271 struct perf_session *session)
269{ 272{
270 event_t *comm_event, *mmap_event; 273 union perf_event *comm_event, *mmap_event;
271 int err = -1, thread; 274 int err = -1, thread;
272 275
273 comm_event = malloc(sizeof(comm_event->comm) + session->id_hdr_size); 276 comm_event = malloc(sizeof(comm_event->comm) + session->id_hdr_size);
@@ -294,12 +297,12 @@ out:
294 return err; 297 return err;
295} 298}
296 299
297int event__synthesize_threads(event__handler_t process, 300int perf_event__synthesize_threads(perf_event__handler_t process,
298 struct perf_session *session) 301 struct perf_session *session)
299{ 302{
300 DIR *proc; 303 DIR *proc;
301 struct dirent dirent, *next; 304 struct dirent dirent, *next;
302 event_t *comm_event, *mmap_event; 305 union perf_event *comm_event, *mmap_event;
303 int err = -1; 306 int err = -1;
304 307
305 comm_event = malloc(sizeof(comm_event->comm) + session->id_hdr_size); 308 comm_event = malloc(sizeof(comm_event->comm) + session->id_hdr_size);
@@ -357,10 +360,10 @@ static int find_symbol_cb(void *arg, const char *name, char type,
357 return 1; 360 return 1;
358} 361}
359 362
360int event__synthesize_kernel_mmap(event__handler_t process, 363int perf_event__synthesize_kernel_mmap(perf_event__handler_t process,
361 struct perf_session *session, 364 struct perf_session *session,
362 struct machine *machine, 365 struct machine *machine,
363 const char *symbol_name) 366 const char *symbol_name)
364{ 367{
365 size_t size; 368 size_t size;
366 const char *filename, *mmap_name; 369 const char *filename, *mmap_name;
@@ -374,8 +377,8 @@ int event__synthesize_kernel_mmap(event__handler_t process,
374 * kernels. 377 * kernels.
375 */ 378 */
376 struct process_symbol_args args = { .name = symbol_name, }; 379 struct process_symbol_args args = { .name = symbol_name, };
377 event_t *event = zalloc(sizeof(event->mmap) + session->id_hdr_size); 380 union perf_event *event = zalloc((sizeof(event->mmap) +
378 381 session->id_hdr_size));
379 if (event == NULL) { 382 if (event == NULL) {
380 pr_debug("Not enough memory synthesizing mmap event " 383 pr_debug("Not enough memory synthesizing mmap event "
381 "for kernel modules\n"); 384 "for kernel modules\n");
@@ -421,42 +424,15 @@ int event__synthesize_kernel_mmap(event__handler_t process,
421 return err; 424 return err;
422} 425}
423 426
424static void thread__comm_adjust(struct thread *self, struct hists *hists) 427int perf_event__process_comm(union perf_event *event,
428 struct perf_sample *sample __used,
429 struct perf_session *session)
425{ 430{
426 char *comm = self->comm; 431 struct thread *thread = perf_session__findnew(session, event->comm.tid);
427
428 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
429 (!symbol_conf.comm_list ||
430 strlist__has_entry(symbol_conf.comm_list, comm))) {
431 u16 slen = strlen(comm);
432
433 if (hists__new_col_len(hists, HISTC_COMM, slen))
434 hists__set_col_len(hists, HISTC_THREAD, slen + 6);
435 }
436}
437 432
438static int thread__set_comm_adjust(struct thread *self, const char *comm, 433 dump_printf(": %s:%d\n", event->comm.comm, event->comm.tid);
439 struct hists *hists)
440{
441 int ret = thread__set_comm(self, comm);
442 434
443 if (ret) 435 if (thread == NULL || thread__set_comm(thread, event->comm.comm)) {
444 return ret;
445
446 thread__comm_adjust(self, hists);
447
448 return 0;
449}
450
451int event__process_comm(event_t *self, struct sample_data *sample __used,
452 struct perf_session *session)
453{
454 struct thread *thread = perf_session__findnew(session, self->comm.tid);
455
456 dump_printf(": %s:%d\n", self->comm.comm, self->comm.tid);
457
458 if (thread == NULL || thread__set_comm_adjust(thread, self->comm.comm,
459 &session->hists)) {
460 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); 436 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
461 return -1; 437 return -1;
462 } 438 }
@@ -464,19 +440,21 @@ int event__process_comm(event_t *self, struct sample_data *sample __used,
464 return 0; 440 return 0;
465} 441}
466 442
467int event__process_lost(event_t *self, struct sample_data *sample __used, 443int perf_event__process_lost(union perf_event *event,
468 struct perf_session *session) 444 struct perf_sample *sample __used,
445 struct perf_session *session)
469{ 446{
470 dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n", 447 dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n",
471 self->lost.id, self->lost.lost); 448 event->lost.id, event->lost.lost);
472 session->hists.stats.total_lost += self->lost.lost; 449 session->hists.stats.total_lost += event->lost.lost;
473 return 0; 450 return 0;
474} 451}
475 452
476static 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)
477{ 455{
478 maps[MAP__FUNCTION]->start = self->mmap.start; 456 maps[MAP__FUNCTION]->start = event->mmap.start;
479 maps[MAP__FUNCTION]->end = self->mmap.start + self->mmap.len; 457 maps[MAP__FUNCTION]->end = event->mmap.start + event->mmap.len;
480 /* 458 /*
481 * Be a bit paranoid here, some perf.data file came with 459 * Be a bit paranoid here, some perf.data file came with
482 * a zero sized synthesized MMAP event for the kernel. 460 * a zero sized synthesized MMAP event for the kernel.
@@ -485,8 +463,8 @@ static void event_set_kernel_mmap_len(struct map **maps, event_t *self)
485 maps[MAP__FUNCTION]->end = ~0ULL; 463 maps[MAP__FUNCTION]->end = ~0ULL;
486} 464}
487 465
488static int event__process_kernel_mmap(event_t *self, 466static int perf_event__process_kernel_mmap(union perf_event *event,
489 struct perf_session *session) 467 struct perf_session *session)
490{ 468{
491 struct map *map; 469 struct map *map;
492 char kmmap_prefix[PATH_MAX]; 470 char kmmap_prefix[PATH_MAX];
@@ -494,9 +472,9 @@ static int event__process_kernel_mmap(event_t *self,
494 enum dso_kernel_type kernel_type; 472 enum dso_kernel_type kernel_type;
495 bool is_kernel_mmap; 473 bool is_kernel_mmap;
496 474
497 machine = perf_session__findnew_machine(session, self->mmap.pid); 475 machine = perf_session__findnew_machine(session, event->mmap.pid);
498 if (!machine) { 476 if (!machine) {
499 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);
500 goto out_problem; 478 goto out_problem;
501 } 479 }
502 480
@@ -506,17 +484,17 @@ static int event__process_kernel_mmap(event_t *self,
506 else 484 else
507 kernel_type = DSO_TYPE_GUEST_KERNEL; 485 kernel_type = DSO_TYPE_GUEST_KERNEL;
508 486
509 is_kernel_mmap = memcmp(self->mmap.filename, 487 is_kernel_mmap = memcmp(event->mmap.filename,
510 kmmap_prefix, 488 kmmap_prefix,
511 strlen(kmmap_prefix)) == 0; 489 strlen(kmmap_prefix)) == 0;
512 if (self->mmap.filename[0] == '/' || 490 if (event->mmap.filename[0] == '/' ||
513 (!is_kernel_mmap && self->mmap.filename[0] == '[')) { 491 (!is_kernel_mmap && event->mmap.filename[0] == '[')) {
514 492
515 char short_module_name[1024]; 493 char short_module_name[1024];
516 char *name, *dot; 494 char *name, *dot;
517 495
518 if (self->mmap.filename[0] == '/') { 496 if (event->mmap.filename[0] == '/') {
519 name = strrchr(self->mmap.filename, '/'); 497 name = strrchr(event->mmap.filename, '/');
520 if (name == NULL) 498 if (name == NULL)
521 goto out_problem; 499 goto out_problem;
522 500
@@ -528,10 +506,10 @@ static int event__process_kernel_mmap(event_t *self,
528 "[%.*s]", (int)(dot - name), name); 506 "[%.*s]", (int)(dot - name), name);
529 strxfrchar(short_module_name, '-', '_'); 507 strxfrchar(short_module_name, '-', '_');
530 } else 508 } else
531 strcpy(short_module_name, self->mmap.filename); 509 strcpy(short_module_name, event->mmap.filename);
532 510
533 map = machine__new_module(machine, self->mmap.start, 511 map = machine__new_module(machine, event->mmap.start,
534 self->mmap.filename); 512 event->mmap.filename);
535 if (map == NULL) 513 if (map == NULL)
536 goto out_problem; 514 goto out_problem;
537 515
@@ -541,9 +519,9 @@ static int event__process_kernel_mmap(event_t *self,
541 519
542 map->dso->short_name = name; 520 map->dso->short_name = name;
543 map->dso->sname_alloc = 1; 521 map->dso->sname_alloc = 1;
544 map->end = map->start + self->mmap.len; 522 map->end = map->start + event->mmap.len;
545 } else if (is_kernel_mmap) { 523 } else if (is_kernel_mmap) {
546 const char *symbol_name = (self->mmap.filename + 524 const char *symbol_name = (event->mmap.filename +
547 strlen(kmmap_prefix)); 525 strlen(kmmap_prefix));
548 /* 526 /*
549 * Should be there already, from the build-id table in 527 * Should be there already, from the build-id table in
@@ -558,10 +536,19 @@ static int event__process_kernel_mmap(event_t *self,
558 if (__machine__create_kernel_maps(machine, kernel) < 0) 536 if (__machine__create_kernel_maps(machine, kernel) < 0)
559 goto out_problem; 537 goto out_problem;
560 538
561 event_set_kernel_mmap_len(machine->vmlinux_maps, self); 539 perf_event__set_kernel_mmap_len(event, machine->vmlinux_maps);
562 perf_session__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps, 540
563 symbol_name, 541 /*
564 self->mmap.pgoff); 542 * Avoid using a zero address (kptr_restrict) for the ref reloc
543 * symbol. Effectively having zero here means that at record
544 * time /proc/sys/kernel/kptr_restrict was non zero.
545 */
546 if (event->mmap.pgoff != 0) {
547 perf_session__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps,
548 symbol_name,
549 event->mmap.pgoff);
550 }
551
565 if (machine__is_default_guest(machine)) { 552 if (machine__is_default_guest(machine)) {
566 /* 553 /*
567 * preload dso of guest kernel and modules 554 * preload dso of guest kernel and modules
@@ -575,22 +562,23 @@ out_problem:
575 return -1; 562 return -1;
576} 563}
577 564
578int event__process_mmap(event_t *self, struct sample_data *sample __used, 565int perf_event__process_mmap(union perf_event *event,
579 struct perf_session *session) 566 struct perf_sample *sample __used,
567 struct perf_session *session)
580{ 568{
581 struct machine *machine; 569 struct machine *machine;
582 struct thread *thread; 570 struct thread *thread;
583 struct map *map; 571 struct map *map;
584 u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 572 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
585 int ret = 0; 573 int ret = 0;
586 574
587 dump_printf(" %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %s\n", 575 dump_printf(" %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %s\n",
588 self->mmap.pid, self->mmap.tid, self->mmap.start, 576 event->mmap.pid, event->mmap.tid, event->mmap.start,
589 self->mmap.len, self->mmap.pgoff, self->mmap.filename); 577 event->mmap.len, event->mmap.pgoff, event->mmap.filename);
590 578
591 if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL || 579 if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
592 cpumode == PERF_RECORD_MISC_KERNEL) { 580 cpumode == PERF_RECORD_MISC_KERNEL) {
593 ret = event__process_kernel_mmap(self, session); 581 ret = perf_event__process_kernel_mmap(event, session);
594 if (ret < 0) 582 if (ret < 0)
595 goto out_problem; 583 goto out_problem;
596 return 0; 584 return 0;
@@ -599,12 +587,12 @@ int event__process_mmap(event_t *self, struct sample_data *sample __used,
599 machine = perf_session__find_host_machine(session); 587 machine = perf_session__find_host_machine(session);
600 if (machine == NULL) 588 if (machine == NULL)
601 goto out_problem; 589 goto out_problem;
602 thread = perf_session__findnew(session, self->mmap.pid); 590 thread = perf_session__findnew(session, event->mmap.pid);
603 if (thread == NULL) 591 if (thread == NULL)
604 goto out_problem; 592 goto out_problem;
605 map = map__new(&machine->user_dsos, self->mmap.start, 593 map = map__new(&machine->user_dsos, event->mmap.start,
606 self->mmap.len, self->mmap.pgoff, 594 event->mmap.len, event->mmap.pgoff,
607 self->mmap.pid, self->mmap.filename, 595 event->mmap.pid, event->mmap.filename,
608 MAP__FUNCTION); 596 MAP__FUNCTION);
609 if (map == NULL) 597 if (map == NULL)
610 goto out_problem; 598 goto out_problem;
@@ -617,16 +605,17 @@ out_problem:
617 return 0; 605 return 0;
618} 606}
619 607
620int event__process_task(event_t *self, struct sample_data *sample __used, 608int perf_event__process_task(union perf_event *event,
621 struct perf_session *session) 609 struct perf_sample *sample __used,
610 struct perf_session *session)
622{ 611{
623 struct thread *thread = perf_session__findnew(session, self->fork.tid); 612 struct thread *thread = perf_session__findnew(session, event->fork.tid);
624 struct thread *parent = perf_session__findnew(session, self->fork.ptid); 613 struct thread *parent = perf_session__findnew(session, event->fork.ptid);
625 614
626 dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid, 615 dump_printf("(%d:%d):(%d:%d)\n", event->fork.pid, event->fork.tid,
627 self->fork.ppid, self->fork.ptid); 616 event->fork.ppid, event->fork.ptid);
628 617
629 if (self->header.type == PERF_RECORD_EXIT) { 618 if (event->header.type == PERF_RECORD_EXIT) {
630 perf_session__remove_thread(session, thread); 619 perf_session__remove_thread(session, thread);
631 return 0; 620 return 0;
632 } 621 }
@@ -640,20 +629,22 @@ int event__process_task(event_t *self, struct sample_data *sample __used,
640 return 0; 629 return 0;
641} 630}
642 631
643int event__process(event_t *event, struct sample_data *sample, 632int perf_event__process(union perf_event *event, struct perf_sample *sample,
644 struct perf_session *session) 633 struct perf_session *session)
645{ 634{
646 switch (event->header.type) { 635 switch (event->header.type) {
647 case PERF_RECORD_COMM: 636 case PERF_RECORD_COMM:
648 event__process_comm(event, sample, session); 637 perf_event__process_comm(event, sample, session);
649 break; 638 break;
650 case PERF_RECORD_MMAP: 639 case PERF_RECORD_MMAP:
651 event__process_mmap(event, sample, session); 640 perf_event__process_mmap(event, sample, session);
652 break; 641 break;
653 case PERF_RECORD_FORK: 642 case PERF_RECORD_FORK:
654 case PERF_RECORD_EXIT: 643 case PERF_RECORD_EXIT:
655 event__process_task(event, sample, session); 644 perf_event__process_task(event, sample, session);
656 break; 645 break;
646 case PERF_RECORD_LOST:
647 perf_event__process_lost(event, sample, session);
657 default: 648 default:
658 break; 649 break;
659 } 650 }
@@ -728,7 +719,7 @@ try_again:
728 * in the whole kernel symbol list. 719 * in the whole kernel symbol list.
729 */ 720 */
730 if ((long long)al->addr < 0 && 721 if ((long long)al->addr < 0 &&
731 cpumode == PERF_RECORD_MISC_KERNEL && 722 cpumode == PERF_RECORD_MISC_USER &&
732 machine && mg != &machine->kmaps) { 723 machine && mg != &machine->kmaps) {
733 mg = &machine->kmaps; 724 mg = &machine->kmaps;
734 goto try_again; 725 goto try_again;
@@ -750,24 +741,14 @@ void thread__find_addr_location(struct thread *self,
750 al->sym = NULL; 741 al->sym = NULL;
751} 742}
752 743
753static void dso__calc_col_width(struct dso *self, struct hists *hists) 744int perf_event__preprocess_sample(const union perf_event *event,
754{ 745 struct perf_session *session,
755 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep && 746 struct addr_location *al,
756 (!symbol_conf.dso_list || 747 struct perf_sample *sample,
757 strlist__has_entry(symbol_conf.dso_list, self->name))) { 748 symbol_filter_t filter)
758 u16 slen = dso__name_len(self);
759 hists__new_col_len(hists, HISTC_DSO, slen);
760 }
761
762 self->slen_calculated = 1;
763}
764
765int event__preprocess_sample(const event_t *self, struct perf_session *session,
766 struct addr_location *al, struct sample_data *data,
767 symbol_filter_t filter)
768{ 749{
769 u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 750 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
770 struct thread *thread = perf_session__findnew(session, self->ip.pid); 751 struct thread *thread = perf_session__findnew(session, event->ip.pid);
771 752
772 if (thread == NULL) 753 if (thread == NULL)
773 return -1; 754 return -1;
@@ -789,12 +770,12 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session,
789 machine__create_kernel_maps(&session->host_machine); 770 machine__create_kernel_maps(&session->host_machine);
790 771
791 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION, 772 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION,
792 self->ip.pid, self->ip.ip, al); 773 event->ip.pid, event->ip.ip, al);
793 dump_printf(" ...... dso: %s\n", 774 dump_printf(" ...... dso: %s\n",
794 al->map ? al->map->dso->long_name : 775 al->map ? al->map->dso->long_name :
795 al->level == 'H' ? "[hypervisor]" : "<not found>"); 776 al->level == 'H' ? "[hypervisor]" : "<not found>");
796 al->sym = NULL; 777 al->sym = NULL;
797 al->cpu = data->cpu; 778 al->cpu = sample->cpu;
798 779
799 if (al->map) { 780 if (al->map) {
800 if (symbol_conf.dso_list && 781 if (symbol_conf.dso_list &&
@@ -805,23 +786,8 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session,
805 strlist__has_entry(symbol_conf.dso_list, 786 strlist__has_entry(symbol_conf.dso_list,
806 al->map->dso->long_name))))) 787 al->map->dso->long_name)))))
807 goto out_filtered; 788 goto out_filtered;
808 /*
809 * We have to do this here as we may have a dso with no symbol
810 * hit that has a name longer than the ones with symbols
811 * sampled.
812 */
813 if (!sort_dso.elide && !al->map->dso->slen_calculated)
814 dso__calc_col_width(al->map->dso, &session->hists);
815 789
816 al->sym = map__find_symbol(al->map, al->addr, filter); 790 al->sym = map__find_symbol(al->map, al->addr, filter);
817 } else {
818 const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
819
820 if (hists__col_len(&session->hists, HISTC_DSO) < unresolved_col_width &&
821 !symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
822 !symbol_conf.dso_list)
823 hists__set_col_len(&session->hists, HISTC_DSO,
824 unresolved_col_width);
825 } 791 }
826 792
827 if (symbol_conf.sym_list && al->sym && 793 if (symbol_conf.sym_list && al->sym &&
@@ -834,128 +800,3 @@ out_filtered:
834 al->filtered = true; 800 al->filtered = true;
835 return 0; 801 return 0;
836} 802}
837
838static int event__parse_id_sample(const event_t *event,
839 struct perf_session *session,
840 struct sample_data *sample)
841{
842 const u64 *array;
843 u64 type;
844
845 sample->cpu = sample->pid = sample->tid = -1;
846 sample->stream_id = sample->id = sample->time = -1ULL;
847
848 if (!session->sample_id_all)
849 return 0;
850
851 array = event->sample.array;
852 array += ((event->header.size -
853 sizeof(event->header)) / sizeof(u64)) - 1;
854 type = session->sample_type;
855
856 if (type & PERF_SAMPLE_CPU) {
857 u32 *p = (u32 *)array;
858 sample->cpu = *p;
859 array--;
860 }
861
862 if (type & PERF_SAMPLE_STREAM_ID) {
863 sample->stream_id = *array;
864 array--;
865 }
866
867 if (type & PERF_SAMPLE_ID) {
868 sample->id = *array;
869 array--;
870 }
871
872 if (type & PERF_SAMPLE_TIME) {
873 sample->time = *array;
874 array--;
875 }
876
877 if (type & PERF_SAMPLE_TID) {
878 u32 *p = (u32 *)array;
879 sample->pid = p[0];
880 sample->tid = p[1];
881 }
882
883 return 0;
884}
885
886int event__parse_sample(const event_t *event, struct perf_session *session,
887 struct sample_data *data)
888{
889 const u64 *array;
890 u64 type;
891
892 if (event->header.type != PERF_RECORD_SAMPLE)
893 return event__parse_id_sample(event, session, data);
894
895 array = event->sample.array;
896 type = session->sample_type;
897
898 if (type & PERF_SAMPLE_IP) {
899 data->ip = event->ip.ip;
900 array++;
901 }
902
903 if (type & PERF_SAMPLE_TID) {
904 u32 *p = (u32 *)array;
905 data->pid = p[0];
906 data->tid = p[1];
907 array++;
908 }
909
910 if (type & PERF_SAMPLE_TIME) {
911 data->time = *array;
912 array++;
913 }
914
915 if (type & PERF_SAMPLE_ADDR) {
916 data->addr = *array;
917 array++;
918 }
919
920 data->id = -1ULL;
921 if (type & PERF_SAMPLE_ID) {
922 data->id = *array;
923 array++;
924 }
925
926 if (type & PERF_SAMPLE_STREAM_ID) {
927 data->stream_id = *array;
928 array++;
929 }
930
931 if (type & PERF_SAMPLE_CPU) {
932 u32 *p = (u32 *)array;
933 data->cpu = *p;
934 array++;
935 } else
936 data->cpu = -1;
937
938 if (type & PERF_SAMPLE_PERIOD) {
939 data->period = *array;
940 array++;
941 }
942
943 if (type & PERF_SAMPLE_READ) {
944 pr_debug("PERF_SAMPLE_READ is unsuported for now\n");
945 return -1;
946 }
947
948 if (type & PERF_SAMPLE_CALLCHAIN) {
949 data->callchain = (struct ip_callchain *)array;
950 array += 1 + data->callchain->nr;
951 }
952
953 if (type & PERF_SAMPLE_RAW) {
954 u32 *p = (u32 *)array;
955 data->raw_size = *p;
956 p++;
957 data->raw_data = p;
958 }
959
960 return 0;
961}
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index cc7b52f9b492..1d7f66488a88 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -56,12 +56,19 @@ struct read_event {
56 u64 id; 56 u64 id;
57}; 57};
58 58
59
60#define PERF_SAMPLE_MASK \
61 (PERF_SAMPLE_IP | PERF_SAMPLE_TID | \
62 PERF_SAMPLE_TIME | PERF_SAMPLE_ADDR | \
63 PERF_SAMPLE_ID | PERF_SAMPLE_STREAM_ID | \
64 PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD)
65
59struct sample_event { 66struct sample_event {
60 struct perf_event_header header; 67 struct perf_event_header header;
61 u64 array[]; 68 u64 array[];
62}; 69};
63 70
64struct sample_data { 71struct perf_sample {
65 u64 ip; 72 u64 ip;
66 u32 pid, tid; 73 u32 pid, tid;
67 u64 time; 74 u64 time;
@@ -117,7 +124,7 @@ struct tracing_data_event {
117 u32 size; 124 u32 size;
118}; 125};
119 126
120typedef union event_union { 127union perf_event {
121 struct perf_event_header header; 128 struct perf_event_header header;
122 struct ip_event ip; 129 struct ip_event ip;
123 struct mmap_event mmap; 130 struct mmap_event mmap;
@@ -130,50 +137,55 @@ typedef union event_union {
130 struct event_type_event event_type; 137 struct event_type_event event_type;
131 struct tracing_data_event tracing_data; 138 struct tracing_data_event tracing_data;
132 struct build_id_event build_id; 139 struct build_id_event build_id;
133} event_t; 140};
134 141
135void event__print_totals(void); 142void perf_event__print_totals(void);
136 143
137struct perf_session; 144struct perf_session;
138struct thread_map; 145struct thread_map;
139 146
140typedef int (*event__handler_synth_t)(event_t *event, 147typedef int (*perf_event__handler_synth_t)(union perf_event *event,
148 struct perf_session *session);
149typedef int (*perf_event__handler_t)(union perf_event *event,
150 struct perf_sample *sample,
141 struct perf_session *session); 151 struct perf_session *session);
142typedef int (*event__handler_t)(event_t *event, struct sample_data *sample, 152
143 struct perf_session *session); 153int perf_event__synthesize_thread_map(struct thread_map *threads,
144 154 perf_event__handler_t process,
145int event__synthesize_thread_map(struct thread_map *threads, 155 struct perf_session *session);
146 event__handler_t process, 156int perf_event__synthesize_threads(perf_event__handler_t process,
147 struct perf_session *session); 157 struct perf_session *session);
148int event__synthesize_threads(event__handler_t process, 158int perf_event__synthesize_kernel_mmap(perf_event__handler_t process,
149 struct perf_session *session); 159 struct perf_session *session,
150int event__synthesize_kernel_mmap(event__handler_t process, 160 struct machine *machine,
151 struct perf_session *session, 161 const char *symbol_name);
152 struct machine *machine, 162
153 const char *symbol_name); 163int perf_event__synthesize_modules(perf_event__handler_t process,
154 164 struct perf_session *session,
155int event__synthesize_modules(event__handler_t process, 165 struct machine *machine);
156 struct perf_session *session, 166
157 struct machine *machine); 167int perf_event__process_comm(union perf_event *event, struct perf_sample *sample,
158 168 struct perf_session *session);
159int event__process_comm(event_t *self, struct sample_data *sample, 169int perf_event__process_lost(union perf_event *event, struct perf_sample *sample,
160 struct perf_session *session); 170 struct perf_session *session);
161int event__process_lost(event_t *self, struct sample_data *sample, 171int perf_event__process_mmap(union perf_event *event, struct perf_sample *sample,
162 struct perf_session *session); 172 struct perf_session *session);
163int event__process_mmap(event_t *self, struct sample_data *sample, 173int perf_event__process_task(union perf_event *event, struct perf_sample *sample,
164 struct perf_session *session); 174 struct perf_session *session);
165int event__process_task(event_t *self, struct sample_data *sample, 175int perf_event__process(union perf_event *event, struct perf_sample *sample,
166 struct perf_session *session); 176 struct perf_session *session);
167int event__process(event_t *event, struct sample_data *sample,
168 struct perf_session *session);
169 177
170struct addr_location; 178struct addr_location;
171int event__preprocess_sample(const event_t *self, struct perf_session *session, 179int perf_event__preprocess_sample(const union perf_event *self,
172 struct addr_location *al, struct sample_data *data, 180 struct perf_session *session,
173 symbol_filter_t filter); 181 struct addr_location *al,
174int event__parse_sample(const event_t *event, struct perf_session *session, 182 struct perf_sample *sample,
175 struct sample_data *sample); 183 symbol_filter_t filter);
184
185const char *perf_event__name(unsigned int id);
176 186
177const char *event__get_event_name(unsigned int id); 187int perf_event__parse_sample(const union perf_event *event, u64 type,
188 int sample_size, bool sample_id_all,
189 struct perf_sample *sample);
178 190
179#endif /* __PERF_RECORD_H */ 191#endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
new file mode 100644
index 000000000000..e03e7bc8205e
--- /dev/null
+++ b/tools/perf/util/evlist.c
@@ -0,0 +1,513 @@
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
94void perf_evlist__disable(struct perf_evlist *evlist)
95{
96 int cpu, thread;
97 struct perf_evsel *pos;
98
99 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
100 list_for_each_entry(pos, &evlist->entries, node) {
101 for (thread = 0; thread < evlist->threads->nr; thread++)
102 ioctl(FD(pos, cpu, thread), PERF_EVENT_IOC_DISABLE);
103 }
104 }
105}
106
107int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
108{
109 int nfds = evlist->cpus->nr * evlist->threads->nr * evlist->nr_entries;
110 evlist->pollfd = malloc(sizeof(struct pollfd) * nfds);
111 return evlist->pollfd != NULL ? 0 : -ENOMEM;
112}
113
114void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd)
115{
116 fcntl(fd, F_SETFL, O_NONBLOCK);
117 evlist->pollfd[evlist->nr_fds].fd = fd;
118 evlist->pollfd[evlist->nr_fds].events = POLLIN;
119 evlist->nr_fds++;
120}
121
122static void perf_evlist__id_hash(struct perf_evlist *evlist,
123 struct perf_evsel *evsel,
124 int cpu, int thread, u64 id)
125{
126 int hash;
127 struct perf_sample_id *sid = SID(evsel, cpu, thread);
128
129 sid->id = id;
130 sid->evsel = evsel;
131 hash = hash_64(sid->id, PERF_EVLIST__HLIST_BITS);
132 hlist_add_head(&sid->node, &evlist->heads[hash]);
133}
134
135void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel,
136 int cpu, int thread, u64 id)
137{
138 perf_evlist__id_hash(evlist, evsel, cpu, thread, id);
139 evsel->id[evsel->ids++] = id;
140}
141
142static int perf_evlist__id_add_fd(struct perf_evlist *evlist,
143 struct perf_evsel *evsel,
144 int cpu, int thread, int fd)
145{
146 u64 read_data[4] = { 0, };
147 int id_idx = 1; /* The first entry is the counter value */
148
149 if (!(evsel->attr.read_format & PERF_FORMAT_ID) ||
150 read(fd, &read_data, sizeof(read_data)) == -1)
151 return -1;
152
153 if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
154 ++id_idx;
155 if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
156 ++id_idx;
157
158 perf_evlist__id_add(evlist, evsel, cpu, thread, read_data[id_idx]);
159 return 0;
160}
161
162struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id)
163{
164 struct hlist_head *head;
165 struct hlist_node *pos;
166 struct perf_sample_id *sid;
167 int hash;
168
169 if (evlist->nr_entries == 1)
170 return list_entry(evlist->entries.next, struct perf_evsel, node);
171
172 hash = hash_64(id, PERF_EVLIST__HLIST_BITS);
173 head = &evlist->heads[hash];
174
175 hlist_for_each_entry(sid, pos, head, node)
176 if (sid->id == id)
177 return sid->evsel;
178 return NULL;
179}
180
181union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
182{
183 /* XXX Move this to perf.c, making it generally available */
184 unsigned int page_size = sysconf(_SC_PAGE_SIZE);
185 struct perf_mmap *md = &evlist->mmap[idx];
186 unsigned int head = perf_mmap__read_head(md);
187 unsigned int old = md->prev;
188 unsigned char *data = md->base + page_size;
189 union perf_event *event = NULL;
190
191 if (evlist->overwrite) {
192 /*
193 * If we're further behind than half the buffer, there's a chance
194 * the writer will bite our tail and mess up the samples under us.
195 *
196 * If we somehow ended up ahead of the head, we got messed up.
197 *
198 * In either case, truncate and restart at head.
199 */
200 int diff = head - old;
201 if (diff > md->mask / 2 || diff < 0) {
202 fprintf(stderr, "WARNING: failed to keep up with mmap data.\n");
203
204 /*
205 * head points to a known good entry, start there.
206 */
207 old = head;
208 }
209 }
210
211 if (old != head) {
212 size_t size;
213
214 event = (union perf_event *)&data[old & md->mask];
215 size = event->header.size;
216
217 /*
218 * Event straddles the mmap boundary -- header should always
219 * be inside due to u64 alignment of output.
220 */
221 if ((old & md->mask) + size != ((old + size) & md->mask)) {
222 unsigned int offset = old;
223 unsigned int len = min(sizeof(*event), size), cpy;
224 void *dst = &evlist->event_copy;
225
226 do {
227 cpy = min(md->mask + 1 - (offset & md->mask), len);
228 memcpy(dst, &data[offset & md->mask], cpy);
229 offset += cpy;
230 dst += cpy;
231 len -= cpy;
232 } while (len);
233
234 event = &evlist->event_copy;
235 }
236
237 old += size;
238 }
239
240 md->prev = old;
241
242 if (!evlist->overwrite)
243 perf_mmap__write_tail(md, old);
244
245 return event;
246}
247
248void perf_evlist__munmap(struct perf_evlist *evlist)
249{
250 int i;
251
252 for (i = 0; i < evlist->nr_mmaps; i++) {
253 if (evlist->mmap[i].base != NULL) {
254 munmap(evlist->mmap[i].base, evlist->mmap_len);
255 evlist->mmap[i].base = NULL;
256 }
257 }
258
259 free(evlist->mmap);
260 evlist->mmap = NULL;
261}
262
263int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
264{
265 evlist->nr_mmaps = evlist->cpus->nr;
266 if (evlist->cpus->map[0] == -1)
267 evlist->nr_mmaps = evlist->threads->nr;
268 evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap));
269 return evlist->mmap != NULL ? 0 : -ENOMEM;
270}
271
272static int __perf_evlist__mmap(struct perf_evlist *evlist,
273 int idx, int prot, int mask, int fd)
274{
275 evlist->mmap[idx].prev = 0;
276 evlist->mmap[idx].mask = mask;
277 evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, prot,
278 MAP_SHARED, fd, 0);
279 if (evlist->mmap[idx].base == MAP_FAILED)
280 return -1;
281
282 perf_evlist__add_pollfd(evlist, fd);
283 return 0;
284}
285
286static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int mask)
287{
288 struct perf_evsel *evsel;
289 int cpu, thread;
290
291 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
292 int output = -1;
293
294 for (thread = 0; thread < evlist->threads->nr; thread++) {
295 list_for_each_entry(evsel, &evlist->entries, node) {
296 int fd = FD(evsel, cpu, thread);
297
298 if (output == -1) {
299 output = fd;
300 if (__perf_evlist__mmap(evlist, cpu,
301 prot, mask, output) < 0)
302 goto out_unmap;
303 } else {
304 if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, output) != 0)
305 goto out_unmap;
306 }
307
308 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
309 perf_evlist__id_add_fd(evlist, evsel, cpu, thread, fd) < 0)
310 goto out_unmap;
311 }
312 }
313 }
314
315 return 0;
316
317out_unmap:
318 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
319 if (evlist->mmap[cpu].base != NULL) {
320 munmap(evlist->mmap[cpu].base, evlist->mmap_len);
321 evlist->mmap[cpu].base = NULL;
322 }
323 }
324 return -1;
325}
326
327static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, int mask)
328{
329 struct perf_evsel *evsel;
330 int thread;
331
332 for (thread = 0; thread < evlist->threads->nr; thread++) {
333 int output = -1;
334
335 list_for_each_entry(evsel, &evlist->entries, node) {
336 int fd = FD(evsel, 0, thread);
337
338 if (output == -1) {
339 output = fd;
340 if (__perf_evlist__mmap(evlist, thread,
341 prot, mask, output) < 0)
342 goto out_unmap;
343 } else {
344 if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, output) != 0)
345 goto out_unmap;
346 }
347
348 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
349 perf_evlist__id_add_fd(evlist, evsel, 0, thread, fd) < 0)
350 goto out_unmap;
351 }
352 }
353
354 return 0;
355
356out_unmap:
357 for (thread = 0; thread < evlist->threads->nr; thread++) {
358 if (evlist->mmap[thread].base != NULL) {
359 munmap(evlist->mmap[thread].base, evlist->mmap_len);
360 evlist->mmap[thread].base = NULL;
361 }
362 }
363 return -1;
364}
365
366/** perf_evlist__mmap - Create per cpu maps to receive events
367 *
368 * @evlist - list of events
369 * @pages - map length in pages
370 * @overwrite - overwrite older events?
371 *
372 * If overwrite is false the user needs to signal event consuption using:
373 *
374 * struct perf_mmap *m = &evlist->mmap[cpu];
375 * unsigned int head = perf_mmap__read_head(m);
376 *
377 * perf_mmap__write_tail(m, head)
378 *
379 * Using perf_evlist__read_on_cpu does this automatically.
380 */
381int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite)
382{
383 unsigned int page_size = sysconf(_SC_PAGE_SIZE);
384 int mask = pages * page_size - 1;
385 struct perf_evsel *evsel;
386 const struct cpu_map *cpus = evlist->cpus;
387 const struct thread_map *threads = evlist->threads;
388 int prot = PROT_READ | (overwrite ? 0 : PROT_WRITE);
389
390 if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0)
391 return -ENOMEM;
392
393 if (evlist->pollfd == NULL && perf_evlist__alloc_pollfd(evlist) < 0)
394 return -ENOMEM;
395
396 evlist->overwrite = overwrite;
397 evlist->mmap_len = (pages + 1) * page_size;
398
399 list_for_each_entry(evsel, &evlist->entries, node) {
400 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
401 evsel->sample_id == NULL &&
402 perf_evsel__alloc_id(evsel, cpus->nr, threads->nr) < 0)
403 return -ENOMEM;
404 }
405
406 if (evlist->cpus->map[0] == -1)
407 return perf_evlist__mmap_per_thread(evlist, prot, mask);
408
409 return perf_evlist__mmap_per_cpu(evlist, prot, mask);
410}
411
412int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid,
413 pid_t target_tid, const char *cpu_list)
414{
415 evlist->threads = thread_map__new(target_pid, target_tid);
416
417 if (evlist->threads == NULL)
418 return -1;
419
420 if (cpu_list == NULL && target_tid != -1)
421 evlist->cpus = cpu_map__dummy_new();
422 else
423 evlist->cpus = cpu_map__new(cpu_list);
424
425 if (evlist->cpus == NULL)
426 goto out_delete_threads;
427
428 return 0;
429
430out_delete_threads:
431 thread_map__delete(evlist->threads);
432 return -1;
433}
434
435void perf_evlist__delete_maps(struct perf_evlist *evlist)
436{
437 cpu_map__delete(evlist->cpus);
438 thread_map__delete(evlist->threads);
439 evlist->cpus = NULL;
440 evlist->threads = NULL;
441}
442
443int perf_evlist__set_filters(struct perf_evlist *evlist)
444{
445 const struct thread_map *threads = evlist->threads;
446 const struct cpu_map *cpus = evlist->cpus;
447 struct perf_evsel *evsel;
448 char *filter;
449 int thread;
450 int cpu;
451 int err;
452 int fd;
453
454 list_for_each_entry(evsel, &evlist->entries, node) {
455 filter = evsel->filter;
456 if (!filter)
457 continue;
458 for (cpu = 0; cpu < cpus->nr; cpu++) {
459 for (thread = 0; thread < threads->nr; thread++) {
460 fd = FD(evsel, cpu, thread);
461 err = ioctl(fd, PERF_EVENT_IOC_SET_FILTER, filter);
462 if (err)
463 return err;
464 }
465 }
466 }
467
468 return 0;
469}
470
471bool perf_evlist__valid_sample_type(const struct perf_evlist *evlist)
472{
473 struct perf_evsel *pos, *first;
474
475 pos = first = list_entry(evlist->entries.next, struct perf_evsel, node);
476
477 list_for_each_entry_continue(pos, &evlist->entries, node) {
478 if (first->attr.sample_type != pos->attr.sample_type)
479 return false;
480 }
481
482 return true;
483}
484
485u64 perf_evlist__sample_type(const struct perf_evlist *evlist)
486{
487 struct perf_evsel *first;
488
489 first = list_entry(evlist->entries.next, struct perf_evsel, node);
490 return first->attr.sample_type;
491}
492
493bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist)
494{
495 struct perf_evsel *pos, *first;
496
497 pos = first = list_entry(evlist->entries.next, struct perf_evsel, node);
498
499 list_for_each_entry_continue(pos, &evlist->entries, node) {
500 if (first->attr.sample_id_all != pos->attr.sample_id_all)
501 return false;
502 }
503
504 return true;
505}
506
507bool perf_evlist__sample_id_all(const struct perf_evlist *evlist)
508{
509 struct perf_evsel *first;
510
511 first = list_entry(evlist->entries.next, struct perf_evsel, node);
512 return first->attr.sample_id_all;
513}
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
new file mode 100644
index 000000000000..ce85ae9ae57a
--- /dev/null
+++ b/tools/perf/util/evlist.h
@@ -0,0 +1,76 @@
1#ifndef __PERF_EVLIST_H
2#define __PERF_EVLIST_H 1
3
4#include <linux/list.h>
5#include "../perf.h"
6#include "event.h"
7
8struct pollfd;
9struct thread_map;
10struct cpu_map;
11
12#define PERF_EVLIST__HLIST_BITS 8
13#define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS)
14
15struct perf_evlist {
16 struct list_head entries;
17 struct hlist_head heads[PERF_EVLIST__HLIST_SIZE];
18 int nr_entries;
19 int nr_fds;
20 int nr_mmaps;
21 int mmap_len;
22 bool overwrite;
23 union perf_event event_copy;
24 struct perf_mmap *mmap;
25 struct pollfd *pollfd;
26 struct thread_map *threads;
27 struct cpu_map *cpus;
28};
29
30struct perf_evsel;
31
32struct perf_evlist *perf_evlist__new(struct cpu_map *cpus,
33 struct thread_map *threads);
34void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
35 struct thread_map *threads);
36void perf_evlist__exit(struct perf_evlist *evlist);
37void perf_evlist__delete(struct perf_evlist *evlist);
38
39void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry);
40int perf_evlist__add_default(struct perf_evlist *evlist);
41
42void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel,
43 int cpu, int thread, u64 id);
44
45int perf_evlist__alloc_pollfd(struct perf_evlist *evlist);
46void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd);
47
48struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id);
49
50union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx);
51
52int perf_evlist__alloc_mmap(struct perf_evlist *evlist);
53int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite);
54void perf_evlist__munmap(struct perf_evlist *evlist);
55
56void perf_evlist__disable(struct perf_evlist *evlist);
57
58static inline void perf_evlist__set_maps(struct perf_evlist *evlist,
59 struct cpu_map *cpus,
60 struct thread_map *threads)
61{
62 evlist->cpus = cpus;
63 evlist->threads = threads;
64}
65
66int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid,
67 pid_t target_tid, const char *cpu_list);
68void perf_evlist__delete_maps(struct perf_evlist *evlist);
69int perf_evlist__set_filters(struct perf_evlist *evlist);
70
71u64 perf_evlist__sample_type(const struct perf_evlist *evlist);
72bool perf_evlist__sample_id_all(const const struct perf_evlist *evlist);
73
74bool perf_evlist__valid_sample_type(const struct perf_evlist *evlist);
75bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist);
76#endif /* __PERF_EVLIST_H */
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index d8575d31ee6c..a03a36b7908a 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -1,30 +1,86 @@
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
18int __perf_evsel__sample_size(u64 sample_type)
19{
20 u64 mask = sample_type & PERF_SAMPLE_MASK;
21 int size = 0;
22 int i;
23
24 for (i = 0; i < 64; i++) {
25 if (mask & (1ULL << i))
26 size++;
27 }
28
29 size *= sizeof(u64);
30
31 return size;
32}
33
34void perf_evsel__init(struct perf_evsel *evsel,
35 struct perf_event_attr *attr, int idx)
36{
37 evsel->idx = idx;
38 evsel->attr = *attr;
39 INIT_LIST_HEAD(&evsel->node);
40}
41
9struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) 42struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
10{ 43{
11 struct perf_evsel *evsel = zalloc(sizeof(*evsel)); 44 struct perf_evsel *evsel = zalloc(sizeof(*evsel));
12 45
13 if (evsel != NULL) { 46 if (evsel != NULL)
14 evsel->idx = idx; 47 perf_evsel__init(evsel, attr, idx);
15 evsel->attr = *attr;
16 INIT_LIST_HEAD(&evsel->node);
17 }
18 48
19 return evsel; 49 return evsel;
20} 50}
21 51
22int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) 52int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
23{ 53{
54 int cpu, thread;
24 evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int)); 55 evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int));
56
57 if (evsel->fd) {
58 for (cpu = 0; cpu < ncpus; cpu++) {
59 for (thread = 0; thread < nthreads; thread++) {
60 FD(evsel, cpu, thread) = -1;
61 }
62 }
63 }
64
25 return evsel->fd != NULL ? 0 : -ENOMEM; 65 return evsel->fd != NULL ? 0 : -ENOMEM;
26} 66}
27 67
68int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
69{
70 evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id));
71 if (evsel->sample_id == NULL)
72 return -ENOMEM;
73
74 evsel->id = zalloc(ncpus * nthreads * sizeof(u64));
75 if (evsel->id == NULL) {
76 xyarray__delete(evsel->sample_id);
77 evsel->sample_id = NULL;
78 return -ENOMEM;
79 }
80
81 return 0;
82}
83
28int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus) 84int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus)
29{ 85{
30 evsel->counts = zalloc((sizeof(*evsel->counts) + 86 evsel->counts = zalloc((sizeof(*evsel->counts) +
@@ -38,6 +94,14 @@ void perf_evsel__free_fd(struct perf_evsel *evsel)
38 evsel->fd = NULL; 94 evsel->fd = NULL;
39} 95}
40 96
97void perf_evsel__free_id(struct perf_evsel *evsel)
98{
99 xyarray__delete(evsel->sample_id);
100 evsel->sample_id = NULL;
101 free(evsel->id);
102 evsel->id = NULL;
103}
104
41void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads) 105void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
42{ 106{
43 int cpu, thread; 107 int cpu, thread;
@@ -49,10 +113,19 @@ void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
49 } 113 }
50} 114}
51 115
52void perf_evsel__delete(struct perf_evsel *evsel) 116void perf_evsel__exit(struct perf_evsel *evsel)
53{ 117{
54 assert(list_empty(&evsel->node)); 118 assert(list_empty(&evsel->node));
55 xyarray__delete(evsel->fd); 119 xyarray__delete(evsel->fd);
120 xyarray__delete(evsel->sample_id);
121 free(evsel->id);
122}
123
124void perf_evsel__delete(struct perf_evsel *evsel)
125{
126 perf_evsel__exit(evsel);
127 close_cgroup(evsel->cgrp);
128 free(evsel->name);
56 free(evsel); 129 free(evsel);
57} 130}
58 131
@@ -128,21 +201,38 @@ int __perf_evsel__read(struct perf_evsel *evsel,
128} 201}
129 202
130static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, 203static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
131 struct thread_map *threads) 204 struct thread_map *threads, bool group)
132{ 205{
133 int cpu, thread; 206 int cpu, thread;
207 unsigned long flags = 0;
208 int pid = -1;
134 209
135 if (evsel->fd == NULL && 210 if (evsel->fd == NULL &&
136 perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0) 211 perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0)
137 return -1; 212 return -1;
138 213
214 if (evsel->cgrp) {
215 flags = PERF_FLAG_PID_CGROUP;
216 pid = evsel->cgrp->fd;
217 }
218
139 for (cpu = 0; cpu < cpus->nr; cpu++) { 219 for (cpu = 0; cpu < cpus->nr; cpu++) {
220 int group_fd = -1;
221
140 for (thread = 0; thread < threads->nr; thread++) { 222 for (thread = 0; thread < threads->nr; thread++) {
223
224 if (!evsel->cgrp)
225 pid = threads->map[thread];
226
141 FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr, 227 FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr,
142 threads->map[thread], 228 pid,
143 cpus->map[cpu], -1, 0); 229 cpus->map[cpu],
230 group_fd, flags);
144 if (FD(evsel, cpu, thread) < 0) 231 if (FD(evsel, cpu, thread) < 0)
145 goto out_close; 232 goto out_close;
233
234 if (group && group_fd == -1)
235 group_fd = FD(evsel, cpu, thread);
146 } 236 }
147 } 237 }
148 238
@@ -175,10 +265,9 @@ static struct {
175 .threads = { -1, }, 265 .threads = { -1, },
176}; 266};
177 267
178int perf_evsel__open(struct perf_evsel *evsel, 268int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
179 struct cpu_map *cpus, struct thread_map *threads) 269 struct thread_map *threads, bool group)
180{ 270{
181
182 if (cpus == NULL) { 271 if (cpus == NULL) {
183 /* Work around old compiler warnings about strict aliasing */ 272 /* Work around old compiler warnings about strict aliasing */
184 cpus = &empty_cpu_map.map; 273 cpus = &empty_cpu_map.map;
@@ -187,15 +276,166 @@ int perf_evsel__open(struct perf_evsel *evsel,
187 if (threads == NULL) 276 if (threads == NULL)
188 threads = &empty_thread_map.map; 277 threads = &empty_thread_map.map;
189 278
190 return __perf_evsel__open(evsel, cpus, threads); 279 return __perf_evsel__open(evsel, cpus, threads, group);
280}
281
282int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
283 struct cpu_map *cpus, bool group)
284{
285 return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group);
286}
287
288int perf_evsel__open_per_thread(struct perf_evsel *evsel,
289 struct thread_map *threads, bool group)
290{
291 return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group);
292}
293
294static int perf_event__parse_id_sample(const union perf_event *event, u64 type,
295 struct perf_sample *sample)
296{
297 const u64 *array = event->sample.array;
298
299 array += ((event->header.size -
300 sizeof(event->header)) / sizeof(u64)) - 1;
301
302 if (type & PERF_SAMPLE_CPU) {
303 u32 *p = (u32 *)array;
304 sample->cpu = *p;
305 array--;
306 }
307
308 if (type & PERF_SAMPLE_STREAM_ID) {
309 sample->stream_id = *array;
310 array--;
311 }
312
313 if (type & PERF_SAMPLE_ID) {
314 sample->id = *array;
315 array--;
316 }
317
318 if (type & PERF_SAMPLE_TIME) {
319 sample->time = *array;
320 array--;
321 }
322
323 if (type & PERF_SAMPLE_TID) {
324 u32 *p = (u32 *)array;
325 sample->pid = p[0];
326 sample->tid = p[1];
327 }
328
329 return 0;
191} 330}
192 331
193int perf_evsel__open_per_cpu(struct perf_evsel *evsel, struct cpu_map *cpus) 332static bool sample_overlap(const union perf_event *event,
333 const void *offset, u64 size)
194{ 334{
195 return __perf_evsel__open(evsel, cpus, &empty_thread_map.map); 335 const void *base = event;
336
337 if (offset + size > base + event->header.size)
338 return true;
339
340 return false;
196} 341}
197 342
198int perf_evsel__open_per_thread(struct perf_evsel *evsel, struct thread_map *threads) 343int perf_event__parse_sample(const union perf_event *event, u64 type,
344 int sample_size, bool sample_id_all,
345 struct perf_sample *data)
199{ 346{
200 return __perf_evsel__open(evsel, &empty_cpu_map.map, threads); 347 const u64 *array;
348
349 data->cpu = data->pid = data->tid = -1;
350 data->stream_id = data->id = data->time = -1ULL;
351
352 if (event->header.type != PERF_RECORD_SAMPLE) {
353 if (!sample_id_all)
354 return 0;
355 return perf_event__parse_id_sample(event, type, data);
356 }
357
358 array = event->sample.array;
359
360 if (sample_size + sizeof(event->header) > event->header.size)
361 return -EFAULT;
362
363 if (type & PERF_SAMPLE_IP) {
364 data->ip = event->ip.ip;
365 array++;
366 }
367
368 if (type & PERF_SAMPLE_TID) {
369 u32 *p = (u32 *)array;
370 data->pid = p[0];
371 data->tid = p[1];
372 array++;
373 }
374
375 if (type & PERF_SAMPLE_TIME) {
376 data->time = *array;
377 array++;
378 }
379
380 data->addr = 0;
381 if (type & PERF_SAMPLE_ADDR) {
382 data->addr = *array;
383 array++;
384 }
385
386 data->id = -1ULL;
387 if (type & PERF_SAMPLE_ID) {
388 data->id = *array;
389 array++;
390 }
391
392 if (type & PERF_SAMPLE_STREAM_ID) {
393 data->stream_id = *array;
394 array++;
395 }
396
397 if (type & PERF_SAMPLE_CPU) {
398 u32 *p = (u32 *)array;
399 data->cpu = *p;
400 array++;
401 }
402
403 if (type & PERF_SAMPLE_PERIOD) {
404 data->period = *array;
405 array++;
406 }
407
408 if (type & PERF_SAMPLE_READ) {
409 fprintf(stderr, "PERF_SAMPLE_READ is unsuported for now\n");
410 return -1;
411 }
412
413 if (type & PERF_SAMPLE_CALLCHAIN) {
414 if (sample_overlap(event, array, sizeof(data->callchain->nr)))
415 return -EFAULT;
416
417 data->callchain = (struct ip_callchain *)array;
418
419 if (sample_overlap(event, array, data->callchain->nr))
420 return -EFAULT;
421
422 array += 1 + data->callchain->nr;
423 }
424
425 if (type & PERF_SAMPLE_RAW) {
426 u32 *p = (u32 *)array;
427
428 if (sample_overlap(event, array, sizeof(u32)))
429 return -EFAULT;
430
431 data->raw_size = *p;
432 p++;
433
434 if (sample_overlap(event, p, data->raw_size))
435 return -EFAULT;
436
437 data->raw_data = p;
438 }
439
440 return 0;
201} 441}
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index b2d755fe88a5..e9a31554e265 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,67 @@ 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;
64 bool supported;
35}; 65};
36 66
37struct cpu_map; 67struct cpu_map;
38struct thread_map; 68struct thread_map;
69struct perf_evlist;
39 70
40struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx); 71struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx);
72void perf_evsel__init(struct perf_evsel *evsel,
73 struct perf_event_attr *attr, int idx);
74void perf_evsel__exit(struct perf_evsel *evsel);
41void perf_evsel__delete(struct perf_evsel *evsel); 75void perf_evsel__delete(struct perf_evsel *evsel);
42 76
43int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); 77int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
78int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads);
44int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); 79int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus);
45void perf_evsel__free_fd(struct perf_evsel *evsel); 80void perf_evsel__free_fd(struct perf_evsel *evsel);
81void perf_evsel__free_id(struct perf_evsel *evsel);
46void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); 82void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
47 83
48int perf_evsel__open_per_cpu(struct perf_evsel *evsel, struct cpu_map *cpus); 84int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
49int perf_evsel__open_per_thread(struct perf_evsel *evsel, struct thread_map *threads); 85 struct cpu_map *cpus, bool group);
50int perf_evsel__open(struct perf_evsel *evsel, 86int perf_evsel__open_per_thread(struct perf_evsel *evsel,
51 struct cpu_map *cpus, struct thread_map *threads); 87 struct thread_map *threads, bool group);
88int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
89 struct thread_map *threads, bool group);
52 90
53#define perf_evsel__match(evsel, t, c) \ 91#define perf_evsel__match(evsel, t, c) \
54 (evsel->attr.type == PERF_TYPE_##t && \ 92 (evsel->attr.type == PERF_TYPE_##t && \
@@ -112,4 +150,11 @@ static inline int perf_evsel__read_scaled(struct perf_evsel *evsel,
112 return __perf_evsel__read(evsel, ncpus, nthreads, true); 150 return __perf_evsel__read(evsel, ncpus, nthreads, true);
113} 151}
114 152
153int __perf_evsel__sample_size(u64 sample_type);
154
155static inline int perf_evsel__sample_size(struct perf_evsel *evsel)
156{
157 return __perf_evsel__sample_size(evsel->attr.sample_type);
158}
159
115#endif /* __PERF_EVSEL_H */ 160#endif /* __PERF_EVSEL_H */
diff --git a/tools/perf/util/exec_cmd.c b/tools/perf/util/exec_cmd.c
index 67eeff571568..7adf4ad15d8f 100644
--- a/tools/perf/util/exec_cmd.c
+++ b/tools/perf/util/exec_cmd.c
@@ -11,31 +11,12 @@ static const char *argv0_path;
11 11
12const char *system_path(const char *path) 12const char *system_path(const char *path)
13{ 13{
14#ifdef RUNTIME_PREFIX
15 static const char *prefix;
16#else
17 static const char *prefix = PREFIX; 14 static const char *prefix = PREFIX;
18#endif
19 struct strbuf d = STRBUF_INIT; 15 struct strbuf d = STRBUF_INIT;
20 16
21 if (is_absolute_path(path)) 17 if (is_absolute_path(path))
22 return path; 18 return path;
23 19
24#ifdef RUNTIME_PREFIX
25 assert(argv0_path);
26 assert(is_absolute_path(argv0_path));
27
28 if (!prefix &&
29 !(prefix = strip_path_suffix(argv0_path, PERF_EXEC_PATH)) &&
30 !(prefix = strip_path_suffix(argv0_path, BINDIR)) &&
31 !(prefix = strip_path_suffix(argv0_path, "perf"))) {
32 prefix = PREFIX;
33 fprintf(stderr, "RUNTIME_PREFIX requested, "
34 "but prefix computation failed. "
35 "Using static fallback '%s'.\n", prefix);
36 }
37#endif
38
39 strbuf_addf(&d, "%s/%s", prefix, path); 20 strbuf_addf(&d, "%s/%s", prefix, path);
40 path = strbuf_detach(&d, NULL); 21 path = strbuf_detach(&d, NULL);
41 return path; 22 return path;
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index f6a929e74981..d4f3101773db 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,19 @@ 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 = zalloc(size),
274 *filename = malloc(size), 193 *linkname = zalloc(size), *targetname;
275 *linkname = malloc(size), *targetname;
276 int len, err = -1; 194 int len, err = -1;
277 195
196 if (is_kallsyms) {
197 if (symbol_conf.kptr_restrict) {
198 pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n");
199 return 0;
200 }
201 realname = (char *)name;
202 } else
203 realname = realpath(name, NULL);
204
278 if (realname == NULL || filename == NULL || linkname == NULL) 205 if (realname == NULL || filename == NULL || linkname == NULL)
279 goto out_free; 206 goto out_free;
280 207
@@ -306,7 +233,8 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
306 if (symlink(targetname, linkname) == 0) 233 if (symlink(targetname, linkname) == 0)
307 err = 0; 234 err = 0;
308out_free: 235out_free:
309 free(realname); 236 if (!is_kallsyms)
237 free(realname);
310 free(filename); 238 free(filename);
311 free(linkname); 239 free(linkname);
312 return err; 240 return err;
@@ -326,8 +254,8 @@ static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,
326int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir) 254int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir)
327{ 255{
328 const size_t size = PATH_MAX; 256 const size_t size = PATH_MAX;
329 char *filename = malloc(size), 257 char *filename = zalloc(size),
330 *linkname = malloc(size); 258 *linkname = zalloc(size);
331 int err = -1; 259 int err = -1;
332 260
333 if (filename == NULL || linkname == NULL) 261 if (filename == NULL || linkname == NULL)
@@ -361,12 +289,12 @@ out_free:
361 return err; 289 return err;
362} 290}
363 291
364static int dso__cache_build_id(struct dso *self, const char *debugdir) 292static int dso__cache_build_id(struct dso *dso, const char *debugdir)
365{ 293{
366 bool is_kallsyms = self->kernel && self->long_name[0] != '/'; 294 bool is_kallsyms = dso->kernel && dso->long_name[0] != '/';
367 295
368 return build_id_cache__add_b(self->build_id, sizeof(self->build_id), 296 return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id),
369 self->long_name, debugdir, is_kallsyms); 297 dso->long_name, debugdir, is_kallsyms);
370} 298}
371 299
372static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir) 300static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir)
@@ -381,14 +309,14 @@ static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir)
381 return err; 309 return err;
382} 310}
383 311
384static int machine__cache_build_ids(struct machine *self, const char *debugdir) 312static int machine__cache_build_ids(struct machine *machine, const char *debugdir)
385{ 313{
386 int ret = __dsos__cache_build_ids(&self->kernel_dsos, debugdir); 314 int ret = __dsos__cache_build_ids(&machine->kernel_dsos, debugdir);
387 ret |= __dsos__cache_build_ids(&self->user_dsos, debugdir); 315 ret |= __dsos__cache_build_ids(&machine->user_dsos, debugdir);
388 return ret; 316 return ret;
389} 317}
390 318
391static int perf_session__cache_build_ids(struct perf_session *self) 319static int perf_session__cache_build_ids(struct perf_session *session)
392{ 320{
393 struct rb_node *nd; 321 struct rb_node *nd;
394 int ret; 322 int ret;
@@ -399,28 +327,28 @@ static int perf_session__cache_build_ids(struct perf_session *self)
399 if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) 327 if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
400 return -1; 328 return -1;
401 329
402 ret = machine__cache_build_ids(&self->host_machine, debugdir); 330 ret = machine__cache_build_ids(&session->host_machine, debugdir);
403 331
404 for (nd = rb_first(&self->machines); nd; nd = rb_next(nd)) { 332 for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) {
405 struct machine *pos = rb_entry(nd, struct machine, rb_node); 333 struct machine *pos = rb_entry(nd, struct machine, rb_node);
406 ret |= machine__cache_build_ids(pos, debugdir); 334 ret |= machine__cache_build_ids(pos, debugdir);
407 } 335 }
408 return ret ? -1 : 0; 336 return ret ? -1 : 0;
409} 337}
410 338
411static bool machine__read_build_ids(struct machine *self, bool with_hits) 339static bool machine__read_build_ids(struct machine *machine, bool with_hits)
412{ 340{
413 bool ret = __dsos__read_build_ids(&self->kernel_dsos, with_hits); 341 bool ret = __dsos__read_build_ids(&machine->kernel_dsos, with_hits);
414 ret |= __dsos__read_build_ids(&self->user_dsos, with_hits); 342 ret |= __dsos__read_build_ids(&machine->user_dsos, with_hits);
415 return ret; 343 return ret;
416} 344}
417 345
418static bool perf_session__read_build_ids(struct perf_session *self, bool with_hits) 346static bool perf_session__read_build_ids(struct perf_session *session, bool with_hits)
419{ 347{
420 struct rb_node *nd; 348 struct rb_node *nd;
421 bool ret = machine__read_build_ids(&self->host_machine, with_hits); 349 bool ret = machine__read_build_ids(&session->host_machine, with_hits);
422 350
423 for (nd = rb_first(&self->machines); nd; nd = rb_next(nd)) { 351 for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) {
424 struct machine *pos = rb_entry(nd, struct machine, rb_node); 352 struct machine *pos = rb_entry(nd, struct machine, rb_node);
425 ret |= machine__read_build_ids(pos, with_hits); 353 ret |= machine__read_build_ids(pos, with_hits);
426 } 354 }
@@ -428,7 +356,8 @@ static bool perf_session__read_build_ids(struct perf_session *self, bool with_hi
428 return ret; 356 return ret;
429} 357}
430 358
431static int perf_header__adds_write(struct perf_header *self, int fd) 359static int perf_header__adds_write(struct perf_header *header,
360 struct perf_evlist *evlist, int fd)
432{ 361{
433 int nr_sections; 362 int nr_sections;
434 struct perf_session *session; 363 struct perf_session *session;
@@ -437,13 +366,13 @@ static int perf_header__adds_write(struct perf_header *self, int fd)
437 u64 sec_start; 366 u64 sec_start;
438 int idx = 0, err; 367 int idx = 0, err;
439 368
440 session = container_of(self, struct perf_session, header); 369 session = container_of(header, struct perf_session, header);
441 370
442 if (perf_header__has_feat(self, HEADER_BUILD_ID && 371 if (perf_header__has_feat(header, HEADER_BUILD_ID &&
443 !perf_session__read_build_ids(session, true))) 372 !perf_session__read_build_ids(session, true)))
444 perf_header__clear_feat(self, HEADER_BUILD_ID); 373 perf_header__clear_feat(header, HEADER_BUILD_ID);
445 374
446 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); 375 nr_sections = bitmap_weight(header->adds_features, HEADER_FEAT_BITS);
447 if (!nr_sections) 376 if (!nr_sections)
448 return 0; 377 return 0;
449 378
@@ -453,28 +382,28 @@ static int perf_header__adds_write(struct perf_header *self, int fd)
453 382
454 sec_size = sizeof(*feat_sec) * nr_sections; 383 sec_size = sizeof(*feat_sec) * nr_sections;
455 384
456 sec_start = self->data_offset + self->data_size; 385 sec_start = header->data_offset + header->data_size;
457 lseek(fd, sec_start + sec_size, SEEK_SET); 386 lseek(fd, sec_start + sec_size, SEEK_SET);
458 387
459 if (perf_header__has_feat(self, HEADER_TRACE_INFO)) { 388 if (perf_header__has_feat(header, HEADER_TRACE_INFO)) {
460 struct perf_file_section *trace_sec; 389 struct perf_file_section *trace_sec;
461 390
462 trace_sec = &feat_sec[idx++]; 391 trace_sec = &feat_sec[idx++];
463 392
464 /* Write trace info */ 393 /* Write trace info */
465 trace_sec->offset = lseek(fd, 0, SEEK_CUR); 394 trace_sec->offset = lseek(fd, 0, SEEK_CUR);
466 read_tracing_data(fd, &evsel_list); 395 read_tracing_data(fd, &evlist->entries);
467 trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset; 396 trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset;
468 } 397 }
469 398
470 if (perf_header__has_feat(self, HEADER_BUILD_ID)) { 399 if (perf_header__has_feat(header, HEADER_BUILD_ID)) {
471 struct perf_file_section *buildid_sec; 400 struct perf_file_section *buildid_sec;
472 401
473 buildid_sec = &feat_sec[idx++]; 402 buildid_sec = &feat_sec[idx++];
474 403
475 /* Write build-ids */ 404 /* Write build-ids */
476 buildid_sec->offset = lseek(fd, 0, SEEK_CUR); 405 buildid_sec->offset = lseek(fd, 0, SEEK_CUR);
477 err = dsos__write_buildid_table(self, fd); 406 err = dsos__write_buildid_table(header, fd);
478 if (err < 0) { 407 if (err < 0) {
479 pr_debug("failed to write buildid table\n"); 408 pr_debug("failed to write buildid table\n");
480 goto out_free; 409 goto out_free;
@@ -513,32 +442,41 @@ int perf_header__write_pipe(int fd)
513 return 0; 442 return 0;
514} 443}
515 444
516int perf_header__write(struct perf_header *self, int fd, bool at_exit) 445int perf_session__write_header(struct perf_session *session,
446 struct perf_evlist *evlist,
447 int fd, bool at_exit)
517{ 448{
518 struct perf_file_header f_header; 449 struct perf_file_header f_header;
519 struct perf_file_attr f_attr; 450 struct perf_file_attr f_attr;
520 struct perf_header_attr *attr; 451 struct perf_header *header = &session->header;
521 int i, err; 452 struct perf_evsel *attr, *pair = NULL;
453 int err;
522 454
523 lseek(fd, sizeof(f_header), SEEK_SET); 455 lseek(fd, sizeof(f_header), SEEK_SET);
524 456
525 for (i = 0; i < self->attrs; i++) { 457 if (session->evlist != evlist)
526 attr = self->attr[i]; 458 pair = list_entry(session->evlist->entries.next, struct perf_evsel, node);
527 459
460 list_for_each_entry(attr, &evlist->entries, node) {
528 attr->id_offset = lseek(fd, 0, SEEK_CUR); 461 attr->id_offset = lseek(fd, 0, SEEK_CUR);
529 err = do_write(fd, attr->id, attr->ids * sizeof(u64)); 462 err = do_write(fd, attr->id, attr->ids * sizeof(u64));
530 if (err < 0) { 463 if (err < 0) {
464out_err_write:
531 pr_debug("failed to write perf header\n"); 465 pr_debug("failed to write perf header\n");
532 return err; 466 return err;
533 } 467 }
468 if (session->evlist != evlist) {
469 err = do_write(fd, pair->id, pair->ids * sizeof(u64));
470 if (err < 0)
471 goto out_err_write;
472 attr->ids += pair->ids;
473 pair = list_entry(pair->node.next, struct perf_evsel, node);
474 }
534 } 475 }
535 476
477 header->attr_offset = lseek(fd, 0, SEEK_CUR);
536 478
537 self->attr_offset = lseek(fd, 0, SEEK_CUR); 479 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){ 480 f_attr = (struct perf_file_attr){
543 .attr = attr->attr, 481 .attr = attr->attr,
544 .ids = { 482 .ids = {
@@ -553,20 +491,20 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit)
553 } 491 }
554 } 492 }
555 493
556 self->event_offset = lseek(fd, 0, SEEK_CUR); 494 header->event_offset = lseek(fd, 0, SEEK_CUR);
557 self->event_size = event_count * sizeof(struct perf_trace_event_type); 495 header->event_size = event_count * sizeof(struct perf_trace_event_type);
558 if (events) { 496 if (events) {
559 err = do_write(fd, events, self->event_size); 497 err = do_write(fd, events, header->event_size);
560 if (err < 0) { 498 if (err < 0) {
561 pr_debug("failed to write perf header events\n"); 499 pr_debug("failed to write perf header events\n");
562 return err; 500 return err;
563 } 501 }
564 } 502 }
565 503
566 self->data_offset = lseek(fd, 0, SEEK_CUR); 504 header->data_offset = lseek(fd, 0, SEEK_CUR);
567 505
568 if (at_exit) { 506 if (at_exit) {
569 err = perf_header__adds_write(self, fd); 507 err = perf_header__adds_write(header, evlist, fd);
570 if (err < 0) 508 if (err < 0)
571 return err; 509 return err;
572 } 510 }
@@ -576,20 +514,20 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit)
576 .size = sizeof(f_header), 514 .size = sizeof(f_header),
577 .attr_size = sizeof(f_attr), 515 .attr_size = sizeof(f_attr),
578 .attrs = { 516 .attrs = {
579 .offset = self->attr_offset, 517 .offset = header->attr_offset,
580 .size = self->attrs * sizeof(f_attr), 518 .size = evlist->nr_entries * sizeof(f_attr),
581 }, 519 },
582 .data = { 520 .data = {
583 .offset = self->data_offset, 521 .offset = header->data_offset,
584 .size = self->data_size, 522 .size = header->data_size,
585 }, 523 },
586 .event_types = { 524 .event_types = {
587 .offset = self->event_offset, 525 .offset = header->event_offset,
588 .size = self->event_size, 526 .size = header->event_size,
589 }, 527 },
590 }; 528 };
591 529
592 memcpy(&f_header.adds_features, &self->adds_features, sizeof(self->adds_features)); 530 memcpy(&f_header.adds_features, &header->adds_features, sizeof(header->adds_features));
593 531
594 lseek(fd, 0, SEEK_SET); 532 lseek(fd, 0, SEEK_SET);
595 err = do_write(fd, &f_header, sizeof(f_header)); 533 err = do_write(fd, &f_header, sizeof(f_header));
@@ -597,26 +535,26 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit)
597 pr_debug("failed to write perf header\n"); 535 pr_debug("failed to write perf header\n");
598 return err; 536 return err;
599 } 537 }
600 lseek(fd, self->data_offset + self->data_size, SEEK_SET); 538 lseek(fd, header->data_offset + header->data_size, SEEK_SET);
601 539
602 self->frozen = 1; 540 header->frozen = 1;
603 return 0; 541 return 0;
604} 542}
605 543
606static int perf_header__getbuffer64(struct perf_header *self, 544static int perf_header__getbuffer64(struct perf_header *header,
607 int fd, void *buf, size_t size) 545 int fd, void *buf, size_t size)
608{ 546{
609 if (readn(fd, buf, size) <= 0) 547 if (readn(fd, buf, size) <= 0)
610 return -1; 548 return -1;
611 549
612 if (self->needs_swap) 550 if (header->needs_swap)
613 mem_bswap_64(buf, size); 551 mem_bswap_64(buf, size);
614 552
615 return 0; 553 return 0;
616} 554}
617 555
618int perf_header__process_sections(struct perf_header *self, int fd, 556int perf_header__process_sections(struct perf_header *header, int fd,
619 int (*process)(struct perf_file_section *self, 557 int (*process)(struct perf_file_section *section,
620 struct perf_header *ph, 558 struct perf_header *ph,
621 int feat, int fd)) 559 int feat, int fd))
622{ 560{
@@ -626,7 +564,7 @@ int perf_header__process_sections(struct perf_header *self, int fd,
626 int idx = 0; 564 int idx = 0;
627 int err = -1, feat = 1; 565 int err = -1, feat = 1;
628 566
629 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); 567 nr_sections = bitmap_weight(header->adds_features, HEADER_FEAT_BITS);
630 if (!nr_sections) 568 if (!nr_sections)
631 return 0; 569 return 0;
632 570
@@ -636,17 +574,17 @@ int perf_header__process_sections(struct perf_header *self, int fd,
636 574
637 sec_size = sizeof(*feat_sec) * nr_sections; 575 sec_size = sizeof(*feat_sec) * nr_sections;
638 576
639 lseek(fd, self->data_offset + self->data_size, SEEK_SET); 577 lseek(fd, header->data_offset + header->data_size, SEEK_SET);
640 578
641 if (perf_header__getbuffer64(self, fd, feat_sec, sec_size)) 579 if (perf_header__getbuffer64(header, fd, feat_sec, sec_size))
642 goto out_free; 580 goto out_free;
643 581
644 err = 0; 582 err = 0;
645 while (idx < nr_sections && feat < HEADER_LAST_FEATURE) { 583 while (idx < nr_sections && feat < HEADER_LAST_FEATURE) {
646 if (perf_header__has_feat(self, feat)) { 584 if (perf_header__has_feat(header, feat)) {
647 struct perf_file_section *sec = &feat_sec[idx++]; 585 struct perf_file_section *sec = &feat_sec[idx++];
648 586
649 err = process(sec, self, feat, fd); 587 err = process(sec, header, feat, fd);
650 if (err < 0) 588 if (err < 0)
651 break; 589 break;
652 } 590 }
@@ -657,35 +595,35 @@ out_free:
657 return err; 595 return err;
658} 596}
659 597
660int perf_file_header__read(struct perf_file_header *self, 598int perf_file_header__read(struct perf_file_header *header,
661 struct perf_header *ph, int fd) 599 struct perf_header *ph, int fd)
662{ 600{
663 lseek(fd, 0, SEEK_SET); 601 lseek(fd, 0, SEEK_SET);
664 602
665 if (readn(fd, self, sizeof(*self)) <= 0 || 603 if (readn(fd, header, sizeof(*header)) <= 0 ||
666 memcmp(&self->magic, __perf_magic, sizeof(self->magic))) 604 memcmp(&header->magic, __perf_magic, sizeof(header->magic)))
667 return -1; 605 return -1;
668 606
669 if (self->attr_size != sizeof(struct perf_file_attr)) { 607 if (header->attr_size != sizeof(struct perf_file_attr)) {
670 u64 attr_size = bswap_64(self->attr_size); 608 u64 attr_size = bswap_64(header->attr_size);
671 609
672 if (attr_size != sizeof(struct perf_file_attr)) 610 if (attr_size != sizeof(struct perf_file_attr))
673 return -1; 611 return -1;
674 612
675 mem_bswap_64(self, offsetof(struct perf_file_header, 613 mem_bswap_64(header, offsetof(struct perf_file_header,
676 adds_features)); 614 adds_features));
677 ph->needs_swap = true; 615 ph->needs_swap = true;
678 } 616 }
679 617
680 if (self->size != sizeof(*self)) { 618 if (header->size != sizeof(*header)) {
681 /* Support the previous format */ 619 /* Support the previous format */
682 if (self->size == offsetof(typeof(*self), adds_features)) 620 if (header->size == offsetof(typeof(*header), adds_features))
683 bitmap_zero(self->adds_features, HEADER_FEAT_BITS); 621 bitmap_zero(header->adds_features, HEADER_FEAT_BITS);
684 else 622 else
685 return -1; 623 return -1;
686 } 624 }
687 625
688 memcpy(&ph->adds_features, &self->adds_features, 626 memcpy(&ph->adds_features, &header->adds_features,
689 sizeof(ph->adds_features)); 627 sizeof(ph->adds_features));
690 /* 628 /*
691 * FIXME: hack that assumes that if we need swap the perf.data file 629 * FIXME: hack that assumes that if we need swap the perf.data file
@@ -699,10 +637,10 @@ int perf_file_header__read(struct perf_file_header *self,
699 perf_header__set_feat(ph, HEADER_BUILD_ID); 637 perf_header__set_feat(ph, HEADER_BUILD_ID);
700 } 638 }
701 639
702 ph->event_offset = self->event_types.offset; 640 ph->event_offset = header->event_types.offset;
703 ph->event_size = self->event_types.size; 641 ph->event_size = header->event_types.size;
704 ph->data_offset = self->data.offset; 642 ph->data_offset = header->data.offset;
705 ph->data_size = self->data.size; 643 ph->data_size = header->data.size;
706 return 0; 644 return 0;
707} 645}
708 646
@@ -761,14 +699,50 @@ out:
761 return err; 699 return err;
762} 700}
763 701
764static int perf_header__read_build_ids(struct perf_header *self, 702static int perf_header__read_build_ids_abi_quirk(struct perf_header *header,
765 int input, u64 offset, u64 size) 703 int input, u64 offset, u64 size)
766{ 704{
767 struct perf_session *session = container_of(self, 705 struct perf_session *session = container_of(header, struct perf_session, header);
768 struct perf_session, header); 706 struct {
707 struct perf_event_header header;
708 u8 build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))];
709 char filename[0];
710 } old_bev;
769 struct build_id_event bev; 711 struct build_id_event bev;
770 char filename[PATH_MAX]; 712 char filename[PATH_MAX];
771 u64 limit = offset + size; 713 u64 limit = offset + size;
714
715 while (offset < limit) {
716 ssize_t len;
717
718 if (read(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev))
719 return -1;
720
721 if (header->needs_swap)
722 perf_event_header__bswap(&old_bev.header);
723
724 len = old_bev.header.size - sizeof(old_bev);
725 if (read(input, filename, len) != len)
726 return -1;
727
728 bev.header = old_bev.header;
729 bev.pid = 0;
730 memcpy(bev.build_id, old_bev.build_id, sizeof(bev.build_id));
731 __event_process_build_id(&bev, filename, session);
732
733 offset += bev.header.size;
734 }
735
736 return 0;
737}
738
739static int perf_header__read_build_ids(struct perf_header *header,
740 int input, u64 offset, u64 size)
741{
742 struct perf_session *session = container_of(header, struct perf_session, header);
743 struct build_id_event bev;
744 char filename[PATH_MAX];
745 u64 limit = offset + size, orig_offset = offset;
772 int err = -1; 746 int err = -1;
773 747
774 while (offset < limit) { 748 while (offset < limit) {
@@ -777,12 +751,30 @@ static int perf_header__read_build_ids(struct perf_header *self,
777 if (read(input, &bev, sizeof(bev)) != sizeof(bev)) 751 if (read(input, &bev, sizeof(bev)) != sizeof(bev))
778 goto out; 752 goto out;
779 753
780 if (self->needs_swap) 754 if (header->needs_swap)
781 perf_event_header__bswap(&bev.header); 755 perf_event_header__bswap(&bev.header);
782 756
783 len = bev.header.size - sizeof(bev); 757 len = bev.header.size - sizeof(bev);
784 if (read(input, filename, len) != len) 758 if (read(input, filename, len) != len)
785 goto out; 759 goto out;
760 /*
761 * The a1645ce1 changeset:
762 *
763 * "perf: 'perf kvm' tool for monitoring guest performance from host"
764 *
765 * Added a field to struct build_id_event that broke the file
766 * format.
767 *
768 * Since the kernel build-id is the first entry, process the
769 * table using the old format if the well known
770 * '[kernel.kallsyms]' string for the kernel build-id has the
771 * first 4 characters chopped off (where the pid_t sits).
772 */
773 if (memcmp(filename, "nel.kallsyms]", 13) == 0) {
774 if (lseek(input, orig_offset, SEEK_SET) == (off_t)-1)
775 return -1;
776 return perf_header__read_build_ids_abi_quirk(header, input, offset, size);
777 }
786 778
787 __event_process_build_id(&bev, filename, session); 779 __event_process_build_id(&bev, filename, session);
788 780
@@ -793,13 +785,13 @@ out:
793 return err; 785 return err;
794} 786}
795 787
796static int perf_file_section__process(struct perf_file_section *self, 788static int perf_file_section__process(struct perf_file_section *section,
797 struct perf_header *ph, 789 struct perf_header *ph,
798 int feat, int fd) 790 int feat, int fd)
799{ 791{
800 if (lseek(fd, self->offset, SEEK_SET) == (off_t)-1) { 792 if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) {
801 pr_debug("Failed to lseek to %" PRIu64 " offset for feature " 793 pr_debug("Failed to lseek to %" PRIu64 " offset for feature "
802 "%d, continuing...\n", self->offset, feat); 794 "%d, continuing...\n", section->offset, feat);
803 return 0; 795 return 0;
804 } 796 }
805 797
@@ -809,7 +801,7 @@ static int perf_file_section__process(struct perf_file_section *self,
809 break; 801 break;
810 802
811 case HEADER_BUILD_ID: 803 case HEADER_BUILD_ID:
812 if (perf_header__read_build_ids(ph, fd, self->offset, self->size)) 804 if (perf_header__read_build_ids(ph, fd, section->offset, section->size))
813 pr_debug("Failed to read buildids, continuing...\n"); 805 pr_debug("Failed to read buildids, continuing...\n");
814 break; 806 break;
815 default: 807 default:
@@ -819,21 +811,21 @@ static int perf_file_section__process(struct perf_file_section *self,
819 return 0; 811 return 0;
820} 812}
821 813
822static int perf_file_header__read_pipe(struct perf_pipe_file_header *self, 814static int perf_file_header__read_pipe(struct perf_pipe_file_header *header,
823 struct perf_header *ph, int fd, 815 struct perf_header *ph, int fd,
824 bool repipe) 816 bool repipe)
825{ 817{
826 if (readn(fd, self, sizeof(*self)) <= 0 || 818 if (readn(fd, header, sizeof(*header)) <= 0 ||
827 memcmp(&self->magic, __perf_magic, sizeof(self->magic))) 819 memcmp(&header->magic, __perf_magic, sizeof(header->magic)))
828 return -1; 820 return -1;
829 821
830 if (repipe && do_write(STDOUT_FILENO, self, sizeof(*self)) < 0) 822 if (repipe && do_write(STDOUT_FILENO, header, sizeof(*header)) < 0)
831 return -1; 823 return -1;
832 824
833 if (self->size != sizeof(*self)) { 825 if (header->size != sizeof(*header)) {
834 u64 size = bswap_64(self->size); 826 u64 size = bswap_64(header->size);
835 827
836 if (size != sizeof(*self)) 828 if (size != sizeof(*header))
837 return -1; 829 return -1;
838 830
839 ph->needs_swap = true; 831 ph->needs_swap = true;
@@ -844,10 +836,10 @@ static int perf_file_header__read_pipe(struct perf_pipe_file_header *self,
844 836
845static int perf_header__read_pipe(struct perf_session *session, int fd) 837static int perf_header__read_pipe(struct perf_session *session, int fd)
846{ 838{
847 struct perf_header *self = &session->header; 839 struct perf_header *header = &session->header;
848 struct perf_pipe_file_header f_header; 840 struct perf_pipe_file_header f_header;
849 841
850 if (perf_file_header__read_pipe(&f_header, self, fd, 842 if (perf_file_header__read_pipe(&f_header, header, fd,
851 session->repipe) < 0) { 843 session->repipe) < 0) {
852 pr_debug("incompatible file format\n"); 844 pr_debug("incompatible file format\n");
853 return -EINVAL; 845 return -EINVAL;
@@ -858,18 +850,22 @@ static int perf_header__read_pipe(struct perf_session *session, int fd)
858 return 0; 850 return 0;
859} 851}
860 852
861int perf_header__read(struct perf_session *session, int fd) 853int perf_session__read_header(struct perf_session *session, int fd)
862{ 854{
863 struct perf_header *self = &session->header; 855 struct perf_header *header = &session->header;
864 struct perf_file_header f_header; 856 struct perf_file_header f_header;
865 struct perf_file_attr f_attr; 857 struct perf_file_attr f_attr;
866 u64 f_id; 858 u64 f_id;
867 int nr_attrs, nr_ids, i, j; 859 int nr_attrs, nr_ids, i, j;
868 860
861 session->evlist = perf_evlist__new(NULL, NULL);
862 if (session->evlist == NULL)
863 return -ENOMEM;
864
869 if (session->fd_pipe) 865 if (session->fd_pipe)
870 return perf_header__read_pipe(session, fd); 866 return perf_header__read_pipe(session, fd);
871 867
872 if (perf_file_header__read(&f_header, self, fd) < 0) { 868 if (perf_file_header__read(&f_header, header, fd) < 0) {
873 pr_debug("incompatible file format\n"); 869 pr_debug("incompatible file format\n");
874 return -EINVAL; 870 return -EINVAL;
875 } 871 }
@@ -878,33 +874,42 @@ int perf_header__read(struct perf_session *session, int fd)
878 lseek(fd, f_header.attrs.offset, SEEK_SET); 874 lseek(fd, f_header.attrs.offset, SEEK_SET);
879 875
880 for (i = 0; i < nr_attrs; i++) { 876 for (i = 0; i < nr_attrs; i++) {
881 struct perf_header_attr *attr; 877 struct perf_evsel *evsel;
882 off_t tmp; 878 off_t tmp;
883 879
884 if (perf_header__getbuffer64(self, fd, &f_attr, sizeof(f_attr))) 880 if (readn(fd, &f_attr, sizeof(f_attr)) <= 0)
885 goto out_errno; 881 goto out_errno;
886 882
883 if (header->needs_swap)
884 perf_event__attr_swap(&f_attr.attr);
885
887 tmp = lseek(fd, 0, SEEK_CUR); 886 tmp = lseek(fd, 0, SEEK_CUR);
887 evsel = perf_evsel__new(&f_attr.attr, i);
888 888
889 attr = perf_header_attr__new(&f_attr.attr); 889 if (evsel == NULL)
890 if (attr == NULL) 890 goto out_delete_evlist;
891 return -ENOMEM; 891 /*
892 * Do it before so that if perf_evsel__alloc_id fails, this
893 * entry gets purged too at perf_evlist__delete().
894 */
895 perf_evlist__add(session->evlist, evsel);
892 896
893 nr_ids = f_attr.ids.size / sizeof(u64); 897 nr_ids = f_attr.ids.size / sizeof(u64);
898 /*
899 * We don't have the cpu and thread maps on the header, so
900 * for allocating the perf_sample_id table we fake 1 cpu and
901 * hattr->ids threads.
902 */
903 if (perf_evsel__alloc_id(evsel, 1, nr_ids))
904 goto out_delete_evlist;
905
894 lseek(fd, f_attr.ids.offset, SEEK_SET); 906 lseek(fd, f_attr.ids.offset, SEEK_SET);
895 907
896 for (j = 0; j < nr_ids; j++) { 908 for (j = 0; j < nr_ids; j++) {
897 if (perf_header__getbuffer64(self, fd, &f_id, sizeof(f_id))) 909 if (perf_header__getbuffer64(header, fd, &f_id, sizeof(f_id)))
898 goto out_errno; 910 goto out_errno;
899 911
900 if (perf_header_attr__add_id(attr, f_id) < 0) { 912 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 } 913 }
909 914
910 lseek(fd, tmp, SEEK_SET); 915 lseek(fd, tmp, SEEK_SET);
@@ -915,93 +920,32 @@ int perf_header__read(struct perf_session *session, int fd)
915 events = malloc(f_header.event_types.size); 920 events = malloc(f_header.event_types.size);
916 if (events == NULL) 921 if (events == NULL)
917 return -ENOMEM; 922 return -ENOMEM;
918 if (perf_header__getbuffer64(self, fd, events, 923 if (perf_header__getbuffer64(header, fd, events,
919 f_header.event_types.size)) 924 f_header.event_types.size))
920 goto out_errno; 925 goto out_errno;
921 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); 926 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
922 } 927 }
923 928
924 perf_header__process_sections(self, fd, perf_file_section__process); 929 perf_header__process_sections(header, fd, perf_file_section__process);
925 930
926 lseek(fd, self->data_offset, SEEK_SET); 931 lseek(fd, header->data_offset, SEEK_SET);
927 932
928 self->frozen = 1; 933 header->frozen = 1;
929 return 0; 934 return 0;
930out_errno: 935out_errno:
931 return -errno; 936 return -errno;
932}
933
934u64 perf_header__sample_type(struct perf_header *header)
935{
936 u64 type = 0;
937 int i;
938 937
939 for (i = 0; i < header->attrs; i++) { 938out_delete_evlist:
940 struct perf_header_attr *attr = header->attr[i]; 939 perf_evlist__delete(session->evlist);
941 940 session->evlist = NULL;
942 if (!type) 941 return -ENOMEM;
943 type = attr->attr.sample_type;
944 else if (type != attr->attr.sample_type)
945 die("non matching sample_type");
946 }
947
948 return type;
949}
950
951bool perf_header__sample_id_all(const struct perf_header *header)
952{
953 bool value = false, first = true;
954 int i;
955
956 for (i = 0; i < header->attrs; i++) {
957 struct perf_header_attr *attr = header->attr[i];
958
959 if (first) {
960 value = attr->attr.sample_id_all;
961 first = false;
962 } else if (value != attr->attr.sample_id_all)
963 die("non matching sample_id_all");
964 }
965
966 return value;
967} 942}
968 943
969struct perf_event_attr * 944int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id,
970perf_header__find_attr(u64 id, struct perf_header *header) 945 perf_event__handler_t process,
971{ 946 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{ 947{
1004 event_t *ev; 948 union perf_event *ev;
1005 size_t size; 949 size_t size;
1006 int err; 950 int err;
1007 951
@@ -1028,17 +972,15 @@ int event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id,
1028 return err; 972 return err;
1029} 973}
1030 974
1031int event__synthesize_attrs(struct perf_header *self, event__handler_t process, 975int perf_session__synthesize_attrs(struct perf_session *session,
1032 struct perf_session *session) 976 perf_event__handler_t process)
1033{ 977{
1034 struct perf_header_attr *attr; 978 struct perf_evsel *attr;
1035 int i, err = 0; 979 int err = 0;
1036
1037 for (i = 0; i < self->attrs; i++) {
1038 attr = self->attr[i];
1039 980
1040 err = event__synthesize_attr(&attr->attr, attr->ids, attr->id, 981 list_for_each_entry(attr, &session->evlist->entries, node) {
1041 process, session); 982 err = perf_event__synthesize_attr(&attr->attr, attr->ids,
983 attr->id, process, session);
1042 if (err) { 984 if (err) {
1043 pr_debug("failed to create perf header attribute\n"); 985 pr_debug("failed to create perf header attribute\n");
1044 return err; 986 return err;
@@ -1048,29 +990,39 @@ int event__synthesize_attrs(struct perf_header *self, event__handler_t process,
1048 return err; 990 return err;
1049} 991}
1050 992
1051int event__process_attr(event_t *self, struct perf_session *session) 993int perf_event__process_attr(union perf_event *event,
994 struct perf_session *session)
1052{ 995{
1053 struct perf_header_attr *attr;
1054 unsigned int i, ids, n_ids; 996 unsigned int i, ids, n_ids;
997 struct perf_evsel *evsel;
998
999 if (session->evlist == NULL) {
1000 session->evlist = perf_evlist__new(NULL, NULL);
1001 if (session->evlist == NULL)
1002 return -ENOMEM;
1003 }
1055 1004
1056 attr = perf_header_attr__new(&self->attr.attr); 1005 evsel = perf_evsel__new(&event->attr.attr,
1057 if (attr == NULL) 1006 session->evlist->nr_entries);
1007 if (evsel == NULL)
1058 return -ENOMEM; 1008 return -ENOMEM;
1059 1009
1060 ids = self->header.size; 1010 perf_evlist__add(session->evlist, evsel);
1061 ids -= (void *)&self->attr.id - (void *)self; 1011
1012 ids = event->header.size;
1013 ids -= (void *)&event->attr.id - (void *)event;
1062 n_ids = ids / sizeof(u64); 1014 n_ids = ids / sizeof(u64);
1015 /*
1016 * We don't have the cpu and thread maps on the header, so
1017 * for allocating the perf_sample_id table we fake 1 cpu and
1018 * hattr->ids threads.
1019 */
1020 if (perf_evsel__alloc_id(evsel, 1, n_ids))
1021 return -ENOMEM;
1063 1022
1064 for (i = 0; i < n_ids; i++) { 1023 for (i = 0; i < n_ids; i++) {
1065 if (perf_header_attr__add_id(attr, self->attr.id[i]) < 0) { 1024 perf_evlist__id_add(session->evlist, evsel, 0, i,
1066 perf_header_attr__delete(attr); 1025 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 } 1026 }
1075 1027
1076 perf_session__update_sample_type(session); 1028 perf_session__update_sample_type(session);
@@ -1078,11 +1030,11 @@ int event__process_attr(event_t *self, struct perf_session *session)
1078 return 0; 1030 return 0;
1079} 1031}
1080 1032
1081int event__synthesize_event_type(u64 event_id, char *name, 1033int perf_event__synthesize_event_type(u64 event_id, char *name,
1082 event__handler_t process, 1034 perf_event__handler_t process,
1083 struct perf_session *session) 1035 struct perf_session *session)
1084{ 1036{
1085 event_t ev; 1037 union perf_event ev;
1086 size_t size = 0; 1038 size_t size = 0;
1087 int err = 0; 1039 int err = 0;
1088 1040
@@ -1103,8 +1055,8 @@ int event__synthesize_event_type(u64 event_id, char *name,
1103 return err; 1055 return err;
1104} 1056}
1105 1057
1106int event__synthesize_event_types(event__handler_t process, 1058int perf_event__synthesize_event_types(perf_event__handler_t process,
1107 struct perf_session *session) 1059 struct perf_session *session)
1108{ 1060{
1109 struct perf_trace_event_type *type; 1061 struct perf_trace_event_type *type;
1110 int i, err = 0; 1062 int i, err = 0;
@@ -1112,8 +1064,9 @@ int event__synthesize_event_types(event__handler_t process,
1112 for (i = 0; i < event_count; i++) { 1064 for (i = 0; i < event_count; i++) {
1113 type = &events[i]; 1065 type = &events[i];
1114 1066
1115 err = event__synthesize_event_type(type->event_id, type->name, 1067 err = perf_event__synthesize_event_type(type->event_id,
1116 process, session); 1068 type->name, process,
1069 session);
1117 if (err) { 1070 if (err) {
1118 pr_debug("failed to create perf header event type\n"); 1071 pr_debug("failed to create perf header event type\n");
1119 return err; 1072 return err;
@@ -1123,28 +1076,28 @@ int event__synthesize_event_types(event__handler_t process,
1123 return err; 1076 return err;
1124} 1077}
1125 1078
1126int event__process_event_type(event_t *self, 1079int perf_event__process_event_type(union perf_event *event,
1127 struct perf_session *session __unused) 1080 struct perf_session *session __unused)
1128{ 1081{
1129 if (perf_header__push_event(self->event_type.event_type.event_id, 1082 if (perf_header__push_event(event->event_type.event_type.event_id,
1130 self->event_type.event_type.name) < 0) 1083 event->event_type.event_type.name) < 0)
1131 return -ENOMEM; 1084 return -ENOMEM;
1132 1085
1133 return 0; 1086 return 0;
1134} 1087}
1135 1088
1136int event__synthesize_tracing_data(int fd, struct list_head *pattrs, 1089int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist,
1137 event__handler_t process, 1090 perf_event__handler_t process,
1138 struct perf_session *session __unused) 1091 struct perf_session *session __unused)
1139{ 1092{
1140 event_t ev; 1093 union perf_event ev;
1141 ssize_t size = 0, aligned_size = 0, padding; 1094 ssize_t size = 0, aligned_size = 0, padding;
1142 int err = 0; 1095 int err __used = 0;
1143 1096
1144 memset(&ev, 0, sizeof(ev)); 1097 memset(&ev, 0, sizeof(ev));
1145 1098
1146 ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA; 1099 ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA;
1147 size = read_tracing_data_size(fd, pattrs); 1100 size = read_tracing_data_size(fd, &evlist->entries);
1148 if (size <= 0) 1101 if (size <= 0)
1149 return size; 1102 return size;
1150 aligned_size = ALIGN(size, sizeof(u64)); 1103 aligned_size = ALIGN(size, sizeof(u64));
@@ -1154,16 +1107,16 @@ int event__synthesize_tracing_data(int fd, struct list_head *pattrs,
1154 1107
1155 process(&ev, NULL, session); 1108 process(&ev, NULL, session);
1156 1109
1157 err = read_tracing_data(fd, pattrs); 1110 err = read_tracing_data(fd, &evlist->entries);
1158 write_padded(fd, NULL, 0, padding); 1111 write_padded(fd, NULL, 0, padding);
1159 1112
1160 return aligned_size; 1113 return aligned_size;
1161} 1114}
1162 1115
1163int event__process_tracing_data(event_t *self, 1116int perf_event__process_tracing_data(union perf_event *event,
1164 struct perf_session *session) 1117 struct perf_session *session)
1165{ 1118{
1166 ssize_t size_read, padding, size = self->tracing_data.size; 1119 ssize_t size_read, padding, size = event->tracing_data.size;
1167 off_t offset = lseek(session->fd, 0, SEEK_CUR); 1120 off_t offset = lseek(session->fd, 0, SEEK_CUR);
1168 char buf[BUFSIZ]; 1121 char buf[BUFSIZ];
1169 1122
@@ -1189,12 +1142,12 @@ int event__process_tracing_data(event_t *self,
1189 return size_read + padding; 1142 return size_read + padding;
1190} 1143}
1191 1144
1192int event__synthesize_build_id(struct dso *pos, u16 misc, 1145int perf_event__synthesize_build_id(struct dso *pos, u16 misc,
1193 event__handler_t process, 1146 perf_event__handler_t process,
1194 struct machine *machine, 1147 struct machine *machine,
1195 struct perf_session *session) 1148 struct perf_session *session)
1196{ 1149{
1197 event_t ev; 1150 union perf_event ev;
1198 size_t len; 1151 size_t len;
1199 int err = 0; 1152 int err = 0;
1200 1153
@@ -1217,11 +1170,11 @@ int event__synthesize_build_id(struct dso *pos, u16 misc,
1217 return err; 1170 return err;
1218} 1171}
1219 1172
1220int event__process_build_id(event_t *self, 1173int perf_event__process_build_id(union perf_event *event,
1221 struct perf_session *session) 1174 struct perf_session *session)
1222{ 1175{
1223 __event_process_build_id(&self->build_id, 1176 __event_process_build_id(&event->build_id,
1224 self->build_id.filename, 1177 event->build_id.filename,
1225 session); 1178 session);
1226 return 0; 1179 return 0;
1227} 1180}
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 33f16be7b72f..1886256768a1 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -9,13 +9,6 @@
9 9
10#include <linux/bitmap.h> 10#include <linux/bitmap.h>
11 11
12struct perf_header_attr {
13 struct perf_event_attr attr;
14 int ids, size;
15 u64 *id;
16 off_t id_offset;
17};
18
19enum { 12enum {
20 HEADER_TRACE_INFO = 1, 13 HEADER_TRACE_INFO = 1,
21 HEADER_BUILD_ID, 14 HEADER_BUILD_ID,
@@ -46,14 +39,12 @@ struct perf_pipe_file_header {
46 39
47struct perf_header; 40struct perf_header;
48 41
49int perf_file_header__read(struct perf_file_header *self, 42int perf_file_header__read(struct perf_file_header *header,
50 struct perf_header *ph, int fd); 43 struct perf_header *ph, int fd);
51 44
52struct perf_header { 45struct perf_header {
53 int frozen; 46 int frozen;
54 int attrs, size;
55 bool needs_swap; 47 bool needs_swap;
56 struct perf_header_attr **attr;
57 s64 attr_offset; 48 s64 attr_offset;
58 u64 data_offset; 49 u64 data_offset;
59 u64 data_size; 50 u64 data_size;
@@ -62,34 +53,23 @@ struct perf_header {
62 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS); 53 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
63}; 54};
64 55
65int perf_header__init(struct perf_header *self); 56struct perf_evlist;
66void perf_header__exit(struct perf_header *self);
67 57
68int perf_header__read(struct perf_session *session, int fd); 58int perf_session__read_header(struct perf_session *session, int fd);
69int perf_header__write(struct perf_header *self, int fd, bool at_exit); 59int perf_session__write_header(struct perf_session *session,
60 struct perf_evlist *evlist,
61 int fd, bool at_exit);
70int perf_header__write_pipe(int fd); 62int perf_header__write_pipe(int fd);
71 63
72int perf_header__add_attr(struct perf_header *self,
73 struct perf_header_attr *attr);
74
75int perf_header__push_event(u64 id, const char *name); 64int perf_header__push_event(u64 id, const char *name);
76char *perf_header__find_event(u64 id); 65char *perf_header__find_event(u64 id);
77 66
78struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr); 67void perf_header__set_feat(struct perf_header *header, int feat);
79void perf_header_attr__delete(struct perf_header_attr *self); 68void perf_header__clear_feat(struct perf_header *header, int feat);
69bool perf_header__has_feat(const struct perf_header *header, int feat);
80 70
81int perf_header_attr__add_id(struct perf_header_attr *self, u64 id); 71int perf_header__process_sections(struct perf_header *header, int fd,
82 72 int (*process)(struct perf_file_section *section,
83u64 perf_header__sample_type(struct perf_header *header);
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, 73 struct perf_header *ph,
94 int feat, int fd)); 74 int feat, int fd));
95 75
@@ -97,32 +77,31 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
97 const char *name, bool is_kallsyms); 77 const char *name, bool is_kallsyms);
98int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir); 78int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir);
99 79
100int event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, 80int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id,
101 event__handler_t process, 81 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); 82 struct perf_session *session);
83int perf_session__synthesize_attrs(struct perf_session *session,
84 perf_event__handler_t process);
85int perf_event__process_attr(union perf_event *event, struct perf_session *session);
86
87int perf_event__synthesize_event_type(u64 event_id, char *name,
88 perf_event__handler_t process,
89 struct perf_session *session);
90int perf_event__synthesize_event_types(perf_event__handler_t process,
91 struct perf_session *session);
92int perf_event__process_event_type(union perf_event *event,
93 struct perf_session *session);
121 94
122int event__synthesize_build_id(struct dso *pos, u16 misc, 95int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist,
123 event__handler_t process, 96 perf_event__handler_t process,
124 struct machine *machine, 97 struct perf_session *session);
125 struct perf_session *session); 98int perf_event__process_tracing_data(union perf_event *event,
126int event__process_build_id(event_t *self, struct perf_session *session); 99 struct perf_session *session);
127 100
101int perf_event__synthesize_build_id(struct dso *pos, u16 misc,
102 perf_event__handler_t process,
103 struct machine *machine,
104 struct perf_session *session);
105int perf_event__process_build_id(union perf_event *event,
106 struct perf_session *session);
128#endif /* __PERF_HEADER_H */ 107#endif /* __PERF_HEADER_H */
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index df51560f16f7..677e1da6bb3e 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"
@@ -13,7 +14,8 @@ enum hist_filter {
13 14
14struct callchain_param callchain_param = { 15struct callchain_param callchain_param = {
15 .mode = CHAIN_GRAPH_REL, 16 .mode = CHAIN_GRAPH_REL,
16 .min_percent = 0.5 17 .min_percent = 0.5,
18 .order = ORDER_CALLEE
17}; 19};
18 20
19u16 hists__col_len(struct hists *self, enum hist_column col) 21u16 hists__col_len(struct hists *self, enum hist_column col)
@@ -49,6 +51,15 @@ static void hists__calc_col_len(struct hists *self, struct hist_entry *h)
49 51
50 if (h->ms.sym) 52 if (h->ms.sym)
51 hists__new_col_len(self, HISTC_SYMBOL, h->ms.sym->namelen); 53 hists__new_col_len(self, HISTC_SYMBOL, h->ms.sym->namelen);
54 else {
55 const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
56
57 if (hists__col_len(self, HISTC_DSO) < unresolved_col_width &&
58 !symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
59 !symbol_conf.dso_list)
60 hists__set_col_len(self, HISTC_DSO,
61 unresolved_col_width);
62 }
52 63
53 len = thread__comm_len(h->thread); 64 len = thread__comm_len(h->thread);
54 if (hists__new_col_len(self, HISTC_COMM, len)) 65 if (hists__new_col_len(self, HISTC_COMM, len))
@@ -211,7 +222,9 @@ void hist_entry__free(struct hist_entry *he)
211 * collapse the histogram 222 * collapse the histogram
212 */ 223 */
213 224
214static bool collapse__insert_entry(struct rb_root *root, struct hist_entry *he) 225static bool hists__collapse_insert_entry(struct hists *self,
226 struct rb_root *root,
227 struct hist_entry *he)
215{ 228{
216 struct rb_node **p = &root->rb_node; 229 struct rb_node **p = &root->rb_node;
217 struct rb_node *parent = NULL; 230 struct rb_node *parent = NULL;
@@ -226,8 +239,11 @@ static bool collapse__insert_entry(struct rb_root *root, struct hist_entry *he)
226 239
227 if (!cmp) { 240 if (!cmp) {
228 iter->period += he->period; 241 iter->period += he->period;
229 if (symbol_conf.use_callchain) 242 if (symbol_conf.use_callchain) {
230 callchain_merge(iter->callchain, he->callchain); 243 callchain_cursor_reset(&self->callchain_cursor);
244 callchain_merge(&self->callchain_cursor, iter->callchain,
245 he->callchain);
246 }
231 hist_entry__free(he); 247 hist_entry__free(he);
232 return false; 248 return false;
233 } 249 }
@@ -262,7 +278,7 @@ void hists__collapse_resort(struct hists *self)
262 next = rb_next(&n->rb_node); 278 next = rb_next(&n->rb_node);
263 279
264 rb_erase(&n->rb_node, &self->entries); 280 rb_erase(&n->rb_node, &self->entries);
265 if (collapse__insert_entry(&tmp, n)) 281 if (hists__collapse_insert_entry(self, &tmp, n))
266 hists__inc_nr_entries(self, n); 282 hists__inc_nr_entries(self, n);
267 } 283 }
268 284
@@ -425,7 +441,7 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
425 u64 cumul; 441 u64 cumul;
426 442
427 child = rb_entry(node, struct callchain_node, rb_node); 443 child = rb_entry(node, struct callchain_node, rb_node);
428 cumul = cumul_hits(child); 444 cumul = callchain_cumul_hits(child);
429 remaining -= cumul; 445 remaining -= cumul;
430 446
431 /* 447 /*
@@ -831,6 +847,9 @@ print_entries:
831 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { 847 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
832 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 848 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
833 849
850 if (h->filtered)
851 continue;
852
834 if (show_displacement) { 853 if (show_displacement) {
835 if (h->pair != NULL) 854 if (h->pair != NULL)
836 displacement = ((long)h->pair->position - 855 displacement = ((long)h->pair->position -
@@ -947,225 +966,14 @@ void hists__filter_by_thread(struct hists *self, const struct thread *thread)
947 } 966 }
948} 967}
949 968
950static int symbol__alloc_hist(struct symbol *self) 969int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip)
951{
952 struct sym_priv *priv = symbol__priv(self);
953 const int size = (sizeof(*priv->hist) +
954 (self->end - self->start) * sizeof(u64));
955
956 priv->hist = zalloc(size);
957 return priv->hist == NULL ? -1 : 0;
958}
959
960int hist_entry__inc_addr_samples(struct hist_entry *self, u64 ip)
961{
962 unsigned int sym_size, offset;
963 struct symbol *sym = self->ms.sym;
964 struct sym_priv *priv;
965 struct sym_hist *h;
966
967 if (!sym || !self->ms.map)
968 return 0;
969
970 priv = symbol__priv(sym);
971 if (priv->hist == NULL && symbol__alloc_hist(sym) < 0)
972 return -ENOMEM;
973
974 sym_size = sym->end - sym->start;
975 offset = ip - sym->start;
976
977 pr_debug3("%s: ip=%#" PRIx64 "\n", __func__, self->ms.map->unmap_ip(self->ms.map, ip));
978
979 if (offset >= sym_size)
980 return 0;
981
982 h = priv->hist;
983 h->sum++;
984 h->ip[offset]++;
985
986 pr_debug3("%#" PRIx64 " %s: period++ [ip: %#" PRIx64 ", %#" PRIx64
987 "] => %" PRIu64 "\n", self->ms.sym->start, self->ms.sym->name,
988 ip, ip - self->ms.sym->start, h->ip[offset]);
989 return 0;
990}
991
992static struct objdump_line *objdump_line__new(s64 offset, char *line, size_t privsize)
993{
994 struct objdump_line *self = malloc(sizeof(*self) + privsize);
995
996 if (self != NULL) {
997 self->offset = offset;
998 self->line = line;
999 }
1000
1001 return self;
1002}
1003
1004void objdump_line__free(struct objdump_line *self)
1005{
1006 free(self->line);
1007 free(self);
1008}
1009
1010static void objdump__add_line(struct list_head *head, struct objdump_line *line)
1011{
1012 list_add_tail(&line->node, head);
1013}
1014
1015struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
1016 struct objdump_line *pos)
1017{
1018 list_for_each_entry_continue(pos, head, node)
1019 if (pos->offset >= 0)
1020 return pos;
1021
1022 return NULL;
1023}
1024
1025static int hist_entry__parse_objdump_line(struct hist_entry *self, FILE *file,
1026 struct list_head *head, size_t privsize)
1027{ 970{
1028 struct symbol *sym = self->ms.sym; 971 return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip);
1029 struct objdump_line *objdump_line;
1030 char *line = NULL, *tmp, *tmp2, *c;
1031 size_t line_len;
1032 s64 line_ip, offset = -1;
1033
1034 if (getline(&line, &line_len, file) < 0)
1035 return -1;
1036
1037 if (!line)
1038 return -1;
1039
1040 while (line_len != 0 && isspace(line[line_len - 1]))
1041 line[--line_len] = '\0';
1042
1043 c = strchr(line, '\n');
1044 if (c)
1045 *c = 0;
1046
1047 line_ip = -1;
1048
1049 /*
1050 * Strip leading spaces:
1051 */
1052 tmp = line;
1053 while (*tmp) {
1054 if (*tmp != ' ')
1055 break;
1056 tmp++;
1057 }
1058
1059 if (*tmp) {
1060 /*
1061 * Parse hexa addresses followed by ':'
1062 */
1063 line_ip = strtoull(tmp, &tmp2, 16);
1064 if (*tmp2 != ':' || tmp == tmp2 || tmp2[1] == '\0')
1065 line_ip = -1;
1066 }
1067
1068 if (line_ip != -1) {
1069 u64 start = map__rip_2objdump(self->ms.map, sym->start),
1070 end = map__rip_2objdump(self->ms.map, sym->end);
1071
1072 offset = line_ip - start;
1073 if (offset < 0 || (u64)line_ip > end)
1074 offset = -1;
1075 }
1076
1077 objdump_line = objdump_line__new(offset, line, privsize);
1078 if (objdump_line == NULL) {
1079 free(line);
1080 return -1;
1081 }
1082 objdump__add_line(head, objdump_line);
1083
1084 return 0;
1085} 972}
1086 973
1087int hist_entry__annotate(struct hist_entry *self, struct list_head *head, 974int hist_entry__annotate(struct hist_entry *he, size_t privsize)
1088 size_t privsize)
1089{ 975{
1090 struct symbol *sym = self->ms.sym; 976 return symbol__annotate(he->ms.sym, he->ms.map, privsize);
1091 struct map *map = self->ms.map;
1092 struct dso *dso = map->dso;
1093 char *filename = dso__build_id_filename(dso, NULL, 0);
1094 bool free_filename = true;
1095 char command[PATH_MAX * 2];
1096 FILE *file;
1097 int err = 0;
1098 u64 len;
1099 char symfs_filename[PATH_MAX];
1100
1101 if (filename) {
1102 snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
1103 symbol_conf.symfs, filename);
1104 }
1105
1106 if (filename == NULL) {
1107 if (dso->has_build_id) {
1108 pr_err("Can't annotate %s: not enough memory\n",
1109 sym->name);
1110 return -ENOMEM;
1111 }
1112 goto fallback;
1113 } else if (readlink(symfs_filename, command, sizeof(command)) < 0 ||
1114 strstr(command, "[kernel.kallsyms]") ||
1115 access(symfs_filename, R_OK)) {
1116 free(filename);
1117fallback:
1118 /*
1119 * If we don't have build-ids or the build-id file isn't in the
1120 * cache, or is just a kallsyms file, well, lets hope that this
1121 * DSO is the same as when 'perf record' ran.
1122 */
1123 filename = dso->long_name;
1124 snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
1125 symbol_conf.symfs, filename);
1126 free_filename = false;
1127 }
1128
1129 if (dso->origin == DSO__ORIG_KERNEL) {
1130 if (dso->annotate_warned)
1131 goto out_free_filename;
1132 err = -ENOENT;
1133 dso->annotate_warned = 1;
1134 pr_err("Can't annotate %s: No vmlinux file was found in the "
1135 "path\n", sym->name);
1136 goto out_free_filename;
1137 }
1138
1139 pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__,
1140 filename, sym->name, map->unmap_ip(map, sym->start),
1141 map->unmap_ip(map, sym->end));
1142
1143 len = sym->end - sym->start;
1144
1145 pr_debug("annotating [%p] %30s : [%p] %30s\n",
1146 dso, dso->long_name, sym, sym->name);
1147
1148 snprintf(command, sizeof(command),
1149 "objdump --start-address=0x%016" PRIx64 " --stop-address=0x%016" PRIx64 " -dS -C %s|grep -v %s|expand",
1150 map__rip_2objdump(map, sym->start),
1151 map__rip_2objdump(map, sym->end),
1152 symfs_filename, filename);
1153
1154 pr_debug("Executing: %s\n", command);
1155
1156 file = popen(command, "r");
1157 if (!file)
1158 goto out_free_filename;
1159
1160 while (!feof(file))
1161 if (hist_entry__parse_objdump_line(self, file, head, privsize) < 0)
1162 break;
1163
1164 pclose(file);
1165out_free_filename:
1166 if (free_filename)
1167 free(filename);
1168 return err;
1169} 977}
1170 978
1171void hists__inc_nr_events(struct hists *self, u32 type) 979void hists__inc_nr_events(struct hists *self, u32 type)
@@ -1180,8 +988,12 @@ size_t hists__fprintf_nr_events(struct hists *self, FILE *fp)
1180 size_t ret = 0; 988 size_t ret = 0;
1181 989
1182 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) { 990 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
1183 const char *name = event__get_event_name(i); 991 const char *name;
992
993 if (self->stats.nr_events[i] == 0)
994 continue;
1184 995
996 name = perf_event__name(i);
1185 if (!strcmp(name, "UNKNOWN")) 997 if (!strcmp(name, "UNKNOWN"))
1186 continue; 998 continue;
1187 999
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/asm/alternative-asm.h b/tools/perf/util/include/asm/alternative-asm.h
new file mode 100644
index 000000000000..6789d788d494
--- /dev/null
+++ b/tools/perf/util/include/asm/alternative-asm.h
@@ -0,0 +1,8 @@
1#ifndef _PERF_ASM_ALTERNATIVE_ASM_H
2#define _PERF_ASM_ALTERNATIVE_ASM_H
3
4/* Just disable it so we can build arch/x86/lib/memcpy_64.S for perf bench: */
5
6#define altinstruction_entry #
7
8#endif
diff --git a/tools/perf/util/include/linux/const.h b/tools/perf/util/include/linux/const.h
new file mode 100644
index 000000000000..1b476c9ae649
--- /dev/null
+++ b/tools/perf/util/include/linux/const.h
@@ -0,0 +1 @@
#include "../../../../include/linux/const.h"
diff --git a/tools/perf/util/include/linux/list.h b/tools/perf/util/include/linux/list.h
index f5ca26e53fbb..1d928a0ce997 100644
--- a/tools/perf/util/include/linux/list.h
+++ b/tools/perf/util/include/linux/list.h
@@ -1,3 +1,6 @@
1#include <linux/kernel.h>
2#include <linux/prefetch.h>
3
1#include "../../../../include/linux/list.h" 4#include "../../../../include/linux/list.h"
2 5
3#ifndef PERF_LIST_H 6#ifndef PERF_LIST_H
@@ -22,5 +25,5 @@ static inline void list_del_range(struct list_head *begin,
22 * @head: the head for your list. 25 * @head: the head for your list.
23 */ 26 */
24#define list_for_each_from(pos, head) \ 27#define list_for_each_from(pos, head) \
25 for (; prefetch(pos->next), pos != (head); pos = pos->next) 28 for (; pos != (head); pos = pos->next)
26#endif 29#endif
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 135f69baf966..4ea7e19f5251 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;
@@ -34,34 +31,36 @@ char debugfs_path[MAXPATHLEN];
34#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x 31#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
35 32
36static struct event_symbol event_symbols[] = { 33static struct event_symbol event_symbols[] = {
37 { CHW(CPU_CYCLES), "cpu-cycles", "cycles" }, 34 { CHW(CPU_CYCLES), "cpu-cycles", "cycles" },
38 { CHW(INSTRUCTIONS), "instructions", "" }, 35 { CHW(STALLED_CYCLES_FRONTEND), "stalled-cycles-frontend", "idle-cycles-frontend" },
39 { CHW(CACHE_REFERENCES), "cache-references", "" }, 36 { CHW(STALLED_CYCLES_BACKEND), "stalled-cycles-backend", "idle-cycles-backend" },
40 { CHW(CACHE_MISSES), "cache-misses", "" }, 37 { CHW(INSTRUCTIONS), "instructions", "" },
41 { CHW(BRANCH_INSTRUCTIONS), "branch-instructions", "branches" }, 38 { CHW(CACHE_REFERENCES), "cache-references", "" },
42 { CHW(BRANCH_MISSES), "branch-misses", "" }, 39 { CHW(CACHE_MISSES), "cache-misses", "" },
43 { CHW(BUS_CYCLES), "bus-cycles", "" }, 40 { CHW(BRANCH_INSTRUCTIONS), "branch-instructions", "branches" },
44 41 { CHW(BRANCH_MISSES), "branch-misses", "" },
45 { CSW(CPU_CLOCK), "cpu-clock", "" }, 42 { CHW(BUS_CYCLES), "bus-cycles", "" },
46 { CSW(TASK_CLOCK), "task-clock", "" }, 43
47 { CSW(PAGE_FAULTS), "page-faults", "faults" }, 44 { CSW(CPU_CLOCK), "cpu-clock", "" },
48 { CSW(PAGE_FAULTS_MIN), "minor-faults", "" }, 45 { CSW(TASK_CLOCK), "task-clock", "" },
49 { CSW(PAGE_FAULTS_MAJ), "major-faults", "" }, 46 { CSW(PAGE_FAULTS), "page-faults", "faults" },
50 { CSW(CONTEXT_SWITCHES), "context-switches", "cs" }, 47 { CSW(PAGE_FAULTS_MIN), "minor-faults", "" },
51 { CSW(CPU_MIGRATIONS), "cpu-migrations", "migrations" }, 48 { CSW(PAGE_FAULTS_MAJ), "major-faults", "" },
52 { CSW(ALIGNMENT_FAULTS), "alignment-faults", "" }, 49 { CSW(CONTEXT_SWITCHES), "context-switches", "cs" },
53 { CSW(EMULATION_FAULTS), "emulation-faults", "" }, 50 { CSW(CPU_MIGRATIONS), "cpu-migrations", "migrations" },
51 { CSW(ALIGNMENT_FAULTS), "alignment-faults", "" },
52 { CSW(EMULATION_FAULTS), "emulation-faults", "" },
54}; 53};
55 54
56#define __PERF_EVENT_FIELD(config, name) \ 55#define __PERF_EVENT_FIELD(config, name) \
57 ((config & PERF_EVENT_##name##_MASK) >> PERF_EVENT_##name##_SHIFT) 56 ((config & PERF_EVENT_##name##_MASK) >> PERF_EVENT_##name##_SHIFT)
58 57
59#define PERF_EVENT_RAW(config) __PERF_EVENT_FIELD(config, RAW) 58#define PERF_EVENT_RAW(config) __PERF_EVENT_FIELD(config, RAW)
60#define PERF_EVENT_CONFIG(config) __PERF_EVENT_FIELD(config, CONFIG) 59#define PERF_EVENT_CONFIG(config) __PERF_EVENT_FIELD(config, CONFIG)
61#define PERF_EVENT_TYPE(config) __PERF_EVENT_FIELD(config, TYPE) 60#define PERF_EVENT_TYPE(config) __PERF_EVENT_FIELD(config, TYPE)
62#define PERF_EVENT_ID(config) __PERF_EVENT_FIELD(config, EVENT) 61#define PERF_EVENT_ID(config) __PERF_EVENT_FIELD(config, EVENT)
63 62
64static const char *hw_event_names[] = { 63static const char *hw_event_names[PERF_COUNT_HW_MAX] = {
65 "cycles", 64 "cycles",
66 "instructions", 65 "instructions",
67 "cache-references", 66 "cache-references",
@@ -69,11 +68,13 @@ static const char *hw_event_names[] = {
69 "branches", 68 "branches",
70 "branch-misses", 69 "branch-misses",
71 "bus-cycles", 70 "bus-cycles",
71 "stalled-cycles-frontend",
72 "stalled-cycles-backend",
72}; 73};
73 74
74static const char *sw_event_names[] = { 75static const char *sw_event_names[PERF_COUNT_SW_MAX] = {
75 "cpu-clock-msecs", 76 "cpu-clock",
76 "task-clock-msecs", 77 "task-clock",
77 "page-faults", 78 "page-faults",
78 "context-switches", 79 "context-switches",
79 "CPU-migrations", 80 "CPU-migrations",
@@ -85,22 +86,24 @@ static const char *sw_event_names[] = {
85 86
86#define MAX_ALIASES 8 87#define MAX_ALIASES 8
87 88
88static const char *hw_cache[][MAX_ALIASES] = { 89static const char *hw_cache[PERF_COUNT_HW_CACHE_MAX][MAX_ALIASES] = {
89 { "L1-dcache", "l1-d", "l1d", "L1-data", }, 90 { "L1-dcache", "l1-d", "l1d", "L1-data", },
90 { "L1-icache", "l1-i", "l1i", "L1-instruction", }, 91 { "L1-icache", "l1-i", "l1i", "L1-instruction", },
91 { "LLC", "L2" }, 92 { "LLC", "L2", },
92 { "dTLB", "d-tlb", "Data-TLB", }, 93 { "dTLB", "d-tlb", "Data-TLB", },
93 { "iTLB", "i-tlb", "Instruction-TLB", }, 94 { "iTLB", "i-tlb", "Instruction-TLB", },
94 { "branch", "branches", "bpu", "btb", "bpc", }, 95 { "branch", "branches", "bpu", "btb", "bpc", },
96 { "node", },
95}; 97};
96 98
97static const char *hw_cache_op[][MAX_ALIASES] = { 99static const char *hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX][MAX_ALIASES] = {
98 { "load", "loads", "read", }, 100 { "load", "loads", "read", },
99 { "store", "stores", "write", }, 101 { "store", "stores", "write", },
100 { "prefetch", "prefetches", "speculative-read", "speculative-load", }, 102 { "prefetch", "prefetches", "speculative-read", "speculative-load", },
101}; 103};
102 104
103static const char *hw_cache_result[][MAX_ALIASES] = { 105static const char *hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX]
106 [MAX_ALIASES] = {
104 { "refs", "Reference", "ops", "access", }, 107 { "refs", "Reference", "ops", "access", },
105 { "misses", "miss", }, 108 { "misses", "miss", },
106}; 109};
@@ -123,6 +126,7 @@ static unsigned long hw_cache_stat[C(MAX)] = {
123 [C(DTLB)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH), 126 [C(DTLB)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
124 [C(ITLB)] = (CACHE_READ), 127 [C(ITLB)] = (CACHE_READ),
125 [C(BPU)] = (CACHE_READ), 128 [C(BPU)] = (CACHE_READ),
129 [C(NODE)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
126}; 130};
127 131
128#define for_each_subsystem(sys_dir, sys_dirent, sys_next) \ 132#define for_each_subsystem(sys_dir, sys_dirent, sys_next) \
@@ -266,11 +270,36 @@ static char *event_cache_name(u8 cache_type, u8 cache_op, u8 cache_result)
266 return name; 270 return name;
267} 271}
268 272
273const char *event_type(int type)
274{
275 switch (type) {
276 case PERF_TYPE_HARDWARE:
277 return "hardware";
278
279 case PERF_TYPE_SOFTWARE:
280 return "software";
281
282 case PERF_TYPE_TRACEPOINT:
283 return "tracepoint";
284
285 case PERF_TYPE_HW_CACHE:
286 return "hardware-cache";
287
288 default:
289 break;
290 }
291
292 return "unknown";
293}
294
269const char *event_name(struct perf_evsel *evsel) 295const char *event_name(struct perf_evsel *evsel)
270{ 296{
271 u64 config = evsel->attr.config; 297 u64 config = evsel->attr.config;
272 int type = evsel->attr.type; 298 int type = evsel->attr.type;
273 299
300 if (evsel->name)
301 return evsel->name;
302
274 return __event_name(type, config); 303 return __event_name(type, config);
275} 304}
276 305
@@ -285,7 +314,7 @@ const char *__event_name(int type, u64 config)
285 314
286 switch (type) { 315 switch (type) {
287 case PERF_TYPE_HARDWARE: 316 case PERF_TYPE_HARDWARE:
288 if (config < PERF_COUNT_HW_MAX) 317 if (config < PERF_COUNT_HW_MAX && hw_event_names[config])
289 return hw_event_names[config]; 318 return hw_event_names[config];
290 return "unknown-hardware"; 319 return "unknown-hardware";
291 320
@@ -311,7 +340,7 @@ const char *__event_name(int type, u64 config)
311 } 340 }
312 341
313 case PERF_TYPE_SOFTWARE: 342 case PERF_TYPE_SOFTWARE:
314 if (config < PERF_COUNT_SW_MAX) 343 if (config < PERF_COUNT_SW_MAX && sw_event_names[config])
315 return sw_event_names[config]; 344 return sw_event_names[config];
316 return "unknown-software"; 345 return "unknown-software";
317 346
@@ -367,7 +396,7 @@ parse_generic_hw_event(const char **str, struct perf_event_attr *attr)
367 PERF_COUNT_HW_CACHE_OP_MAX); 396 PERF_COUNT_HW_CACHE_OP_MAX);
368 if (cache_op >= 0) { 397 if (cache_op >= 0) {
369 if (!is_cache_op_valid(cache_type, cache_op)) 398 if (!is_cache_op_valid(cache_type, cache_op))
370 return 0; 399 return EVT_FAILED;
371 continue; 400 continue;
372 } 401 }
373 } 402 }
@@ -449,8 +478,8 @@ parse_single_tracepoint_event(char *sys_name,
449/* sys + ':' + event + ':' + flags*/ 478/* sys + ':' + event + ':' + flags*/
450#define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128) 479#define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128)
451static enum event_result 480static enum event_result
452parse_multiple_tracepoint_event(char *sys_name, const char *evt_exp, 481parse_multiple_tracepoint_event(struct perf_evlist *evlist, char *sys_name,
453 char *flags) 482 const char *evt_exp, char *flags)
454{ 483{
455 char evt_path[MAXPATHLEN]; 484 char evt_path[MAXPATHLEN];
456 struct dirent *evt_ent; 485 struct dirent *evt_ent;
@@ -483,15 +512,16 @@ parse_multiple_tracepoint_event(char *sys_name, const char *evt_exp,
483 if (len < 0) 512 if (len < 0)
484 return EVT_FAILED; 513 return EVT_FAILED;
485 514
486 if (parse_events(NULL, event_opt, 0)) 515 if (parse_events(evlist, event_opt, 0))
487 return EVT_FAILED; 516 return EVT_FAILED;
488 } 517 }
489 518
490 return EVT_HANDLED_ALL; 519 return EVT_HANDLED_ALL;
491} 520}
492 521
493static enum event_result parse_tracepoint_event(const char **strp, 522static enum event_result
494 struct perf_event_attr *attr) 523parse_tracepoint_event(struct perf_evlist *evlist, const char **strp,
524 struct perf_event_attr *attr)
495{ 525{
496 const char *evt_name; 526 const char *evt_name;
497 char *flags = NULL, *comma_loc; 527 char *flags = NULL, *comma_loc;
@@ -530,8 +560,8 @@ static enum event_result parse_tracepoint_event(const char **strp,
530 return EVT_FAILED; 560 return EVT_FAILED;
531 if (strpbrk(evt_name, "*?")) { 561 if (strpbrk(evt_name, "*?")) {
532 *strp += strlen(sys_name) + evt_length + 1; /* 1 == the ':' */ 562 *strp += strlen(sys_name) + evt_length + 1; /* 1 == the ':' */
533 return parse_multiple_tracepoint_event(sys_name, evt_name, 563 return parse_multiple_tracepoint_event(evlist, sys_name,
534 flags); 564 evt_name, flags);
535 } else { 565 } else {
536 return parse_single_tracepoint_event(sys_name, evt_name, 566 return parse_single_tracepoint_event(sys_name, evt_name,
537 evt_length, attr, strp); 567 evt_length, attr, strp);
@@ -625,13 +655,15 @@ static int check_events(const char *str, unsigned int i)
625 int n; 655 int n;
626 656
627 n = strlen(event_symbols[i].symbol); 657 n = strlen(event_symbols[i].symbol);
628 if (!strncmp(str, event_symbols[i].symbol, n)) 658 if (!strncasecmp(str, event_symbols[i].symbol, n))
629 return n; 659 return n;
630 660
631 n = strlen(event_symbols[i].alias); 661 n = strlen(event_symbols[i].alias);
632 if (n) 662 if (n) {
633 if (!strncmp(str, event_symbols[i].alias, n)) 663 if (!strncasecmp(str, event_symbols[i].alias, n))
634 return n; 664 return n;
665 }
666
635 return 0; 667 return 0;
636} 668}
637 669
@@ -695,15 +727,22 @@ parse_numeric_event(const char **strp, struct perf_event_attr *attr)
695 return EVT_FAILED; 727 return EVT_FAILED;
696} 728}
697 729
698static enum event_result 730static int
699parse_event_modifier(const char **strp, struct perf_event_attr *attr) 731parse_event_modifier(const char **strp, struct perf_event_attr *attr)
700{ 732{
701 const char *str = *strp; 733 const char *str = *strp;
702 int exclude = 0; 734 int exclude = 0;
703 int eu = 0, ek = 0, eh = 0, precise = 0; 735 int eu = 0, ek = 0, eh = 0, precise = 0;
704 736
705 if (*str++ != ':') 737 if (!*str)
706 return 0; 738 return 0;
739
740 if (*str == ',')
741 return 0;
742
743 if (*str++ != ':')
744 return -1;
745
707 while (*str) { 746 while (*str) {
708 if (*str == 'u') { 747 if (*str == 'u') {
709 if (!exclude) 748 if (!exclude)
@@ -724,14 +763,16 @@ parse_event_modifier(const char **strp, struct perf_event_attr *attr)
724 763
725 ++str; 764 ++str;
726 } 765 }
727 if (str >= *strp + 2) { 766 if (str < *strp + 2)
728 *strp = str; 767 return -1;
729 attr->exclude_user = eu; 768
730 attr->exclude_kernel = ek; 769 *strp = str;
731 attr->exclude_hv = eh; 770
732 attr->precise_ip = precise; 771 attr->exclude_user = eu;
733 return 1; 772 attr->exclude_kernel = ek;
734 } 773 attr->exclude_hv = eh;
774 attr->precise_ip = precise;
775
735 return 0; 776 return 0;
736} 777}
737 778
@@ -740,11 +781,12 @@ parse_event_modifier(const char **strp, struct perf_event_attr *attr)
740 * Symbolic names are (almost) exactly matched. 781 * Symbolic names are (almost) exactly matched.
741 */ 782 */
742static enum event_result 783static enum event_result
743parse_event_symbols(const char **str, struct perf_event_attr *attr) 784parse_event_symbols(struct perf_evlist *evlist, const char **str,
785 struct perf_event_attr *attr)
744{ 786{
745 enum event_result ret; 787 enum event_result ret;
746 788
747 ret = parse_tracepoint_event(str, attr); 789 ret = parse_tracepoint_event(evlist, str, attr);
748 if (ret != EVT_FAILED) 790 if (ret != EVT_FAILED)
749 goto modifier; 791 goto modifier;
750 792
@@ -773,19 +815,26 @@ parse_event_symbols(const char **str, struct perf_event_attr *attr)
773 return EVT_FAILED; 815 return EVT_FAILED;
774 816
775modifier: 817modifier:
776 parse_event_modifier(str, attr); 818 if (parse_event_modifier(str, attr) < 0) {
819 fprintf(stderr, "invalid event modifier: '%s'\n", *str);
820 fprintf(stderr, "Run 'perf list' for a list of valid events and modifiers\n");
821
822 return EVT_FAILED;
823 }
777 824
778 return ret; 825 return ret;
779} 826}
780 827
781int parse_events(const struct option *opt __used, const char *str, int unset __used) 828int parse_events(struct perf_evlist *evlist , const char *str, int unset __used)
782{ 829{
783 struct perf_event_attr attr; 830 struct perf_event_attr attr;
784 enum event_result ret; 831 enum event_result ret;
832 const char *ostr;
785 833
786 for (;;) { 834 for (;;) {
835 ostr = str;
787 memset(&attr, 0, sizeof(attr)); 836 memset(&attr, 0, sizeof(attr));
788 ret = parse_event_symbols(&str, &attr); 837 ret = parse_event_symbols(evlist, &str, &attr);
789 if (ret == EVT_FAILED) 838 if (ret == EVT_FAILED)
790 return -1; 839 return -1;
791 840
@@ -794,12 +843,15 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u
794 843
795 if (ret != EVT_HANDLED_ALL) { 844 if (ret != EVT_HANDLED_ALL) {
796 struct perf_evsel *evsel; 845 struct perf_evsel *evsel;
797 evsel = perf_evsel__new(&attr, 846 evsel = perf_evsel__new(&attr, evlist->nr_entries);
798 nr_counters);
799 if (evsel == NULL) 847 if (evsel == NULL)
800 return -1; 848 return -1;
801 list_add_tail(&evsel->node, &evsel_list); 849 perf_evlist__add(evlist, evsel);
802 ++nr_counters; 850
851 evsel->name = calloc(str - ostr + 1, 1);
852 if (!evsel->name)
853 return -1;
854 strncpy(evsel->name, ostr, str - ostr);
803 } 855 }
804 856
805 if (*str == 0) 857 if (*str == 0)
@@ -813,13 +865,21 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u
813 return 0; 865 return 0;
814} 866}
815 867
816int parse_filter(const struct option *opt __used, const char *str, 868int parse_events_option(const struct option *opt, const char *str,
869 int unset __used)
870{
871 struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
872 return parse_events(evlist, str, unset);
873}
874
875int parse_filter(const struct option *opt, const char *str,
817 int unset __used) 876 int unset __used)
818{ 877{
878 struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
819 struct perf_evsel *last = NULL; 879 struct perf_evsel *last = NULL;
820 880
821 if (!list_empty(&evsel_list)) 881 if (evlist->nr_entries > 0)
822 last = list_entry(evsel_list.prev, struct perf_evsel, node); 882 last = list_entry(evlist->entries.prev, struct perf_evsel, node);
823 883
824 if (last == NULL || last->attr.type != PERF_TYPE_TRACEPOINT) { 884 if (last == NULL || last->attr.type != PERF_TYPE_TRACEPOINT) {
825 fprintf(stderr, 885 fprintf(stderr,
@@ -849,7 +909,7 @@ static const char * const event_type_descriptors[] = {
849 * Print the events from <debugfs_mount_point>/tracing/events 909 * Print the events from <debugfs_mount_point>/tracing/events
850 */ 910 */
851 911
852static void print_tracepoint_events(void) 912void print_tracepoint_events(const char *subsys_glob, const char *event_glob)
853{ 913{
854 DIR *sys_dir, *evt_dir; 914 DIR *sys_dir, *evt_dir;
855 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; 915 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
@@ -864,6 +924,9 @@ static void print_tracepoint_events(void)
864 return; 924 return;
865 925
866 for_each_subsystem(sys_dir, sys_dirent, sys_next) { 926 for_each_subsystem(sys_dir, sys_dirent, sys_next) {
927 if (subsys_glob != NULL &&
928 !strglobmatch(sys_dirent.d_name, subsys_glob))
929 continue;
867 930
868 snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path, 931 snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path,
869 sys_dirent.d_name); 932 sys_dirent.d_name);
@@ -872,9 +935,13 @@ static void print_tracepoint_events(void)
872 continue; 935 continue;
873 936
874 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { 937 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) {
938 if (event_glob != NULL &&
939 !strglobmatch(evt_dirent.d_name, event_glob))
940 continue;
941
875 snprintf(evt_path, MAXPATHLEN, "%s:%s", 942 snprintf(evt_path, MAXPATHLEN, "%s:%s",
876 sys_dirent.d_name, evt_dirent.d_name); 943 sys_dirent.d_name, evt_dirent.d_name);
877 printf(" %-42s [%s]\n", evt_path, 944 printf(" %-50s [%s]\n", evt_path,
878 event_type_descriptors[PERF_TYPE_TRACEPOINT]); 945 event_type_descriptors[PERF_TYPE_TRACEPOINT]);
879 } 946 }
880 closedir(evt_dir); 947 closedir(evt_dir);
@@ -923,14 +990,63 @@ int is_valid_tracepoint(const char *event_string)
923 return 0; 990 return 0;
924} 991}
925 992
993void print_events_type(u8 type)
994{
995 struct event_symbol *syms = event_symbols;
996 unsigned int i;
997 char name[64];
998
999 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
1000 if (type != syms->type)
1001 continue;
1002
1003 if (strlen(syms->alias))
1004 snprintf(name, sizeof(name), "%s OR %s",
1005 syms->symbol, syms->alias);
1006 else
1007 snprintf(name, sizeof(name), "%s", syms->symbol);
1008
1009 printf(" %-50s [%s]\n", name,
1010 event_type_descriptors[type]);
1011 }
1012}
1013
1014int print_hwcache_events(const char *event_glob)
1015{
1016 unsigned int type, op, i, printed = 0;
1017
1018 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
1019 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
1020 /* skip invalid cache type */
1021 if (!is_cache_op_valid(type, op))
1022 continue;
1023
1024 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
1025 char *name = event_cache_name(type, op, i);
1026
1027 if (event_glob != NULL && !strglobmatch(name, event_glob))
1028 continue;
1029
1030 printf(" %-50s [%s]\n", name,
1031 event_type_descriptors[PERF_TYPE_HW_CACHE]);
1032 ++printed;
1033 }
1034 }
1035 }
1036
1037 return printed;
1038}
1039
1040#define MAX_NAME_LEN 100
1041
926/* 1042/*
927 * Print the help text for the event symbols: 1043 * Print the help text for the event symbols:
928 */ 1044 */
929void print_events(void) 1045void print_events(const char *event_glob)
930{ 1046{
1047 unsigned int i, type, prev_type = -1, printed = 0, ntypes_printed = 0;
931 struct event_symbol *syms = event_symbols; 1048 struct event_symbol *syms = event_symbols;
932 unsigned int i, type, op, prev_type = -1; 1049 char name[MAX_NAME_LEN];
933 char name[40];
934 1050
935 printf("\n"); 1051 printf("\n");
936 printf("List of pre-defined events (to be used in -e):\n"); 1052 printf("List of pre-defined events (to be used in -e):\n");
@@ -938,76 +1054,49 @@ void print_events(void)
938 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { 1054 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
939 type = syms->type; 1055 type = syms->type;
940 1056
941 if (type != prev_type) 1057 if (type != prev_type && printed) {
942 printf("\n"); 1058 printf("\n");
1059 printed = 0;
1060 ntypes_printed++;
1061 }
1062
1063 if (event_glob != NULL &&
1064 !(strglobmatch(syms->symbol, event_glob) ||
1065 (syms->alias && strglobmatch(syms->alias, event_glob))))
1066 continue;
943 1067
944 if (strlen(syms->alias)) 1068 if (strlen(syms->alias))
945 sprintf(name, "%s OR %s", syms->symbol, syms->alias); 1069 snprintf(name, MAX_NAME_LEN, "%s OR %s", syms->symbol, syms->alias);
946 else 1070 else
947 strcpy(name, syms->symbol); 1071 strncpy(name, syms->symbol, MAX_NAME_LEN);
948 printf(" %-42s [%s]\n", name, 1072 printf(" %-50s [%s]\n", name,
949 event_type_descriptors[type]); 1073 event_type_descriptors[type]);
950 1074
951 prev_type = type; 1075 prev_type = type;
1076 ++printed;
952 } 1077 }
953 1078
954 printf("\n"); 1079 if (ntypes_printed) {
955 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { 1080 printed = 0;
956 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { 1081 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 } 1082 }
1083 print_hwcache_events(event_glob);
1084
1085 if (event_glob != NULL)
1086 return;
968 1087
969 printf("\n"); 1088 printf("\n");
970 printf(" %-42s [%s]\n", 1089 printf(" %-50s [%s]\n",
971 "rNNN (see 'perf list --help' on how to encode it)", 1090 "rNNN (see 'perf list --help' on how to encode it)",
972 event_type_descriptors[PERF_TYPE_RAW]); 1091 event_type_descriptors[PERF_TYPE_RAW]);
973 printf("\n"); 1092 printf("\n");
974 1093
975 printf(" %-42s [%s]\n", 1094 printf(" %-50s [%s]\n",
976 "mem:<addr>[:access]", 1095 "mem:<addr>[:access]",
977 event_type_descriptors[PERF_TYPE_BREAKPOINT]); 1096 event_type_descriptors[PERF_TYPE_BREAKPOINT]);
978 printf("\n"); 1097 printf("\n");
979 1098
980 print_tracepoint_events(); 1099 print_tracepoint_events(NULL, NULL);
981 1100
982 exit(129); 1101 exit(129);
983} 1102}
984
985int perf_evsel_list__create_default(void)
986{
987 struct perf_evsel *evsel;
988 struct perf_event_attr attr;
989
990 memset(&attr, 0, sizeof(attr));
991 attr.type = PERF_TYPE_HARDWARE;
992 attr.config = PERF_COUNT_HW_CPU_CYCLES;
993
994 evsel = perf_evsel__new(&attr, 0);
995
996 if (evsel == NULL)
997 return -ENOMEM;
998
999 list_add(&evsel->node, &evsel_list);
1000 ++nr_counters;
1001 return 0;
1002}
1003
1004void perf_evsel_list__delete(void)
1005{
1006 struct perf_evsel *pos, *n;
1007
1008 list_for_each_entry_safe(pos, n, &evsel_list, node) {
1009 list_del_init(&pos->node);
1010 perf_evsel__delete(pos);
1011 }
1012 nr_counters = 0;
1013}
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 458e3ecf17af..2f8e375e038d 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -8,11 +8,7 @@
8 8
9struct list_head; 9struct list_head;
10struct perf_evsel; 10struct perf_evsel;
11 11struct perf_evlist;
12extern struct list_head evsel_list;
13
14int perf_evsel_list__create_default(void);
15void perf_evsel_list__delete(void);
16 12
17struct option; 13struct option;
18 14
@@ -25,17 +21,22 @@ struct tracepoint_path {
25extern struct tracepoint_path *tracepoint_id_to_path(u64 config); 21extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
26extern bool have_tracepoints(struct list_head *evlist); 22extern bool have_tracepoints(struct list_head *evlist);
27 23
28extern int nr_counters; 24const char *event_type(int type);
29
30const char *event_name(struct perf_evsel *event); 25const char *event_name(struct perf_evsel *event);
31extern const char *__event_name(int type, u64 config); 26extern const char *__event_name(int type, u64 config);
32 27
33extern int parse_events(const struct option *opt, const char *str, int unset); 28extern int parse_events_option(const struct option *opt, const char *str,
29 int unset);
30extern int parse_events(struct perf_evlist *evlist, const char *str,
31 int unset);
34extern int parse_filter(const struct option *opt, const char *str, int unset); 32extern int parse_filter(const struct option *opt, const char *str, int unset);
35 33
36#define EVENTS_HELP_MAX (128*1024) 34#define EVENTS_HELP_MAX (128*1024)
37 35
38extern void print_events(void); 36void print_events(const char *event_glob);
37void print_events_type(u8 type);
38void print_tracepoint_events(const char *subsys_glob, const char *event_glob);
39int print_hwcache_events(const char *event_glob);
39extern int is_valid_tracepoint(const char *event_string); 40extern int is_valid_tracepoint(const char *event_string);
40 41
41extern char debugfs_path[]; 42extern char debugfs_path[];
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 6e29d9c9dccc..1c7bfa5fe0a8 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,29 @@ static struct symbol *__find_kernel_function_by_name(const char *name,
111 NULL); 112 NULL);
112} 113}
113 114
114const char *kernel_get_module_path(const char *module) 115static struct map *kernel_get_module_map(const char *module)
116{
117 struct rb_node *nd;
118 struct map_groups *grp = &machine.kmaps;
119
120 /* A file path -- this is an offline module */
121 if (module && strchr(module, '/'))
122 return machine__new_module(&machine, 0, module);
123
124 if (!module)
125 module = "kernel";
126
127 for (nd = rb_first(&grp->maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) {
128 struct map *pos = rb_entry(nd, struct map, rb_node);
129 if (strncmp(pos->dso->short_name + 1, module,
130 pos->dso->short_name_len - 2) == 0) {
131 return pos;
132 }
133 }
134 return NULL;
135}
136
137static struct dso *kernel_get_module_dso(const char *module)
115{ 138{
116 struct dso *dso; 139 struct dso *dso;
117 struct map *map; 140 struct map *map;
@@ -141,20 +164,34 @@ const char *kernel_get_module_path(const char *module)
141 } 164 }
142 } 165 }
143found: 166found:
144 return dso->long_name; 167 return dso;
168}
169
170const char *kernel_get_module_path(const char *module)
171{
172 struct dso *dso = kernel_get_module_dso(module);
173 return (dso) ? dso->long_name : NULL;
145} 174}
146 175
147#ifdef DWARF_SUPPORT 176#ifdef DWARF_SUPPORT
148static int open_vmlinux(const char *module) 177/* Open new debuginfo of given module */
178static struct debuginfo *open_debuginfo(const char *module)
149{ 179{
150 const char *path = kernel_get_module_path(module); 180 const char *path;
151 if (!path) { 181
152 pr_err("Failed to find path of %s module.\n", 182 /* A file path -- this is an offline module */
153 module ?: "kernel"); 183 if (module && strchr(module, '/'))
154 return -ENOENT; 184 path = module;
185 else {
186 path = kernel_get_module_path(module);
187
188 if (!path) {
189 pr_err("Failed to find path of %s module.\n",
190 module ?: "kernel");
191 return NULL;
192 }
155 } 193 }
156 pr_debug("Try to open %s\n", path); 194 return debuginfo__new(path);
157 return open(path, O_RDONLY);
158} 195}
159 196
160/* 197/*
@@ -168,13 +205,24 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
168 struct map *map; 205 struct map *map;
169 u64 addr; 206 u64 addr;
170 int ret = -ENOENT; 207 int ret = -ENOENT;
208 struct debuginfo *dinfo;
171 209
172 sym = __find_kernel_function_by_name(tp->symbol, &map); 210 sym = __find_kernel_function_by_name(tp->symbol, &map);
173 if (sym) { 211 if (sym) {
174 addr = map->unmap_ip(map, sym->start + tp->offset); 212 addr = map->unmap_ip(map, sym->start + tp->offset);
175 pr_debug("try to find %s+%ld@%" PRIx64 "\n", tp->symbol, 213 pr_debug("try to find %s+%ld@%" PRIx64 "\n", tp->symbol,
176 tp->offset, addr); 214 tp->offset, addr);
177 ret = find_perf_probe_point((unsigned long)addr, pp); 215
216 dinfo = debuginfo__new_online_kernel(addr);
217 if (dinfo) {
218 ret = debuginfo__find_probe_point(dinfo,
219 (unsigned long)addr, pp);
220 debuginfo__delete(dinfo);
221 } else {
222 pr_debug("Failed to open debuginfo at 0x%" PRIx64 "\n",
223 addr);
224 ret = -ENOENT;
225 }
178 } 226 }
179 if (ret <= 0) { 227 if (ret <= 0) {
180 pr_debug("Failed to find corresponding probes from " 228 pr_debug("Failed to find corresponding probes from "
@@ -189,31 +237,70 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
189 return 0; 237 return 0;
190} 238}
191 239
240static int add_module_to_probe_trace_events(struct probe_trace_event *tevs,
241 int ntevs, const char *module)
242{
243 int i, ret = 0;
244 char *tmp;
245
246 if (!module)
247 return 0;
248
249 tmp = strrchr(module, '/');
250 if (tmp) {
251 /* This is a module path -- get the module name */
252 module = strdup(tmp + 1);
253 if (!module)
254 return -ENOMEM;
255 tmp = strchr(module, '.');
256 if (tmp)
257 *tmp = '\0';
258 tmp = (char *)module; /* For free() */
259 }
260
261 for (i = 0; i < ntevs; i++) {
262 tevs[i].point.module = strdup(module);
263 if (!tevs[i].point.module) {
264 ret = -ENOMEM;
265 break;
266 }
267 }
268
269 if (tmp)
270 free(tmp);
271
272 return ret;
273}
274
192/* Try to find perf_probe_event with debuginfo */ 275/* Try to find perf_probe_event with debuginfo */
193static int try_to_find_probe_trace_events(struct perf_probe_event *pev, 276static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
194 struct probe_trace_event **tevs, 277 struct probe_trace_event **tevs,
195 int max_tevs, const char *module) 278 int max_tevs, const char *module)
196{ 279{
197 bool need_dwarf = perf_probe_event_need_dwarf(pev); 280 bool need_dwarf = perf_probe_event_need_dwarf(pev);
198 int fd, ntevs; 281 struct debuginfo *dinfo = open_debuginfo(module);
282 int ntevs, ret = 0;
199 283
200 fd = open_vmlinux(module); 284 if (!dinfo) {
201 if (fd < 0) {
202 if (need_dwarf) { 285 if (need_dwarf) {
203 pr_warning("Failed to open debuginfo file.\n"); 286 pr_warning("Failed to open debuginfo file.\n");
204 return fd; 287 return -ENOENT;
205 } 288 }
206 pr_debug("Could not open vmlinux. Try to use symbols.\n"); 289 pr_debug("Could not open debuginfo. Try to use symbols.\n");
207 return 0; 290 return 0;
208 } 291 }
209 292
210 /* Searching trace events corresponding to probe event */ 293 /* Searching trace events corresponding to a probe event */
211 ntevs = find_probe_trace_events(fd, pev, tevs, max_tevs); 294 ntevs = debuginfo__find_trace_events(dinfo, pev, tevs, max_tevs);
212 close(fd); 295
296 debuginfo__delete(dinfo);
213 297
214 if (ntevs > 0) { /* Succeeded to find trace events */ 298 if (ntevs > 0) { /* Succeeded to find trace events */
215 pr_debug("find %d probe_trace_events.\n", ntevs); 299 pr_debug("find %d probe_trace_events.\n", ntevs);
216 return ntevs; 300 if (module)
301 ret = add_module_to_probe_trace_events(*tevs, ntevs,
302 module);
303 return ret < 0 ? ret : ntevs;
217 } 304 }
218 305
219 if (ntevs == 0) { /* No error but failed to find probe point. */ 306 if (ntevs == 0) { /* No error but failed to find probe point. */
@@ -347,8 +434,9 @@ int show_line_range(struct line_range *lr, const char *module)
347{ 434{
348 int l = 1; 435 int l = 1;
349 struct line_node *ln; 436 struct line_node *ln;
437 struct debuginfo *dinfo;
350 FILE *fp; 438 FILE *fp;
351 int fd, ret; 439 int ret;
352 char *tmp; 440 char *tmp;
353 441
354 /* Search a line range */ 442 /* Search a line range */
@@ -356,14 +444,14 @@ int show_line_range(struct line_range *lr, const char *module)
356 if (ret < 0) 444 if (ret < 0)
357 return ret; 445 return ret;
358 446
359 fd = open_vmlinux(module); 447 dinfo = open_debuginfo(module);
360 if (fd < 0) { 448 if (!dinfo) {
361 pr_warning("Failed to open debuginfo file.\n"); 449 pr_warning("Failed to open debuginfo file.\n");
362 return fd; 450 return -ENOENT;
363 } 451 }
364 452
365 ret = find_line_range(fd, lr); 453 ret = debuginfo__find_line_range(dinfo, lr);
366 close(fd); 454 debuginfo__delete(dinfo);
367 if (ret == 0) { 455 if (ret == 0) {
368 pr_warning("Specified source line is not found.\n"); 456 pr_warning("Specified source line is not found.\n");
369 return -ENOENT; 457 return -ENOENT;
@@ -384,7 +472,7 @@ int show_line_range(struct line_range *lr, const char *module)
384 setup_pager(); 472 setup_pager();
385 473
386 if (lr->function) 474 if (lr->function)
387 fprintf(stdout, "<%s:%d>\n", lr->function, 475 fprintf(stdout, "<%s@%s:%d>\n", lr->function, lr->path,
388 lr->start - lr->offset); 476 lr->start - lr->offset);
389 else 477 else
390 fprintf(stdout, "<%s:%d>\n", lr->path, lr->start); 478 fprintf(stdout, "<%s:%d>\n", lr->path, lr->start);
@@ -425,69 +513,84 @@ end:
425 return ret; 513 return ret;
426} 514}
427 515
428static int show_available_vars_at(int fd, struct perf_probe_event *pev, 516static int show_available_vars_at(struct debuginfo *dinfo,
429 int max_vls, bool externs) 517 struct perf_probe_event *pev,
518 int max_vls, struct strfilter *_filter,
519 bool externs)
430{ 520{
431 char *buf; 521 char *buf;
432 int ret, i; 522 int ret, i, nvars;
433 struct str_node *node; 523 struct str_node *node;
434 struct variable_list *vls = NULL, *vl; 524 struct variable_list *vls = NULL, *vl;
525 const char *var;
435 526
436 buf = synthesize_perf_probe_point(&pev->point); 527 buf = synthesize_perf_probe_point(&pev->point);
437 if (!buf) 528 if (!buf)
438 return -EINVAL; 529 return -EINVAL;
439 pr_debug("Searching variables at %s\n", buf); 530 pr_debug("Searching variables at %s\n", buf);
440 531
441 ret = find_available_vars_at(fd, pev, &vls, max_vls, externs); 532 ret = debuginfo__find_available_vars_at(dinfo, pev, &vls,
442 if (ret > 0) { 533 max_vls, externs);
443 /* Some variables were found */ 534 if (ret <= 0) {
444 fprintf(stdout, "Available variables at %s\n", buf); 535 pr_err("Failed to find variables at %s (%d)\n", buf, ret);
445 for (i = 0; i < ret; i++) { 536 goto end;
446 vl = &vls[i]; 537 }
447 /* 538 /* Some variables are found */
448 * A probe point might be converted to 539 fprintf(stdout, "Available variables at %s\n", buf);
449 * several trace points. 540 for (i = 0; i < ret; i++) {
450 */ 541 vl = &vls[i];
451 fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol, 542 /*
452 vl->point.offset); 543 * A probe point might be converted to
453 free(vl->point.symbol); 544 * several trace points.
454 if (vl->vars) { 545 */
455 strlist__for_each(node, vl->vars) 546 fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol,
547 vl->point.offset);
548 free(vl->point.symbol);
549 nvars = 0;
550 if (vl->vars) {
551 strlist__for_each(node, vl->vars) {
552 var = strchr(node->s, '\t') + 1;
553 if (strfilter__compare(_filter, var)) {
456 fprintf(stdout, "\t\t%s\n", node->s); 554 fprintf(stdout, "\t\t%s\n", node->s);
457 strlist__delete(vl->vars); 555 nvars++;
458 } else 556 }
459 fprintf(stdout, "(No variables)\n"); 557 }
558 strlist__delete(vl->vars);
460 } 559 }
461 free(vls); 560 if (nvars == 0)
462 } else 561 fprintf(stdout, "\t\t(No matched variables)\n");
463 pr_err("Failed to find variables at %s (%d)\n", buf, ret); 562 }
464 563 free(vls);
564end:
465 free(buf); 565 free(buf);
466 return ret; 566 return ret;
467} 567}
468 568
469/* Show available variables on given probe point */ 569/* Show available variables on given probe point */
470int show_available_vars(struct perf_probe_event *pevs, int npevs, 570int show_available_vars(struct perf_probe_event *pevs, int npevs,
471 int max_vls, const char *module, bool externs) 571 int max_vls, const char *module,
572 struct strfilter *_filter, bool externs)
472{ 573{
473 int i, fd, ret = 0; 574 int i, ret = 0;
575 struct debuginfo *dinfo;
474 576
475 ret = init_vmlinux(); 577 ret = init_vmlinux();
476 if (ret < 0) 578 if (ret < 0)
477 return ret; 579 return ret;
478 580
479 fd = open_vmlinux(module); 581 dinfo = open_debuginfo(module);
480 if (fd < 0) { 582 if (!dinfo) {
481 pr_warning("Failed to open debug information file.\n"); 583 pr_warning("Failed to open debuginfo file.\n");
482 return fd; 584 return -ENOENT;
483 } 585 }
484 586
485 setup_pager(); 587 setup_pager();
486 588
487 for (i = 0; i < npevs && ret >= 0; i++) 589 for (i = 0; i < npevs && ret >= 0; i++)
488 ret = show_available_vars_at(fd, &pevs[i], max_vls, externs); 590 ret = show_available_vars_at(dinfo, &pevs[i], max_vls, _filter,
591 externs);
489 592
490 close(fd); 593 debuginfo__delete(dinfo);
491 return ret; 594 return ret;
492} 595}
493 596
@@ -531,7 +634,9 @@ int show_line_range(struct line_range *lr __unused, const char *module __unused)
531 634
532int show_available_vars(struct perf_probe_event *pevs __unused, 635int show_available_vars(struct perf_probe_event *pevs __unused,
533 int npevs __unused, int max_vls __unused, 636 int npevs __unused, int max_vls __unused,
534 const char *module __unused, bool externs __unused) 637 const char *module __unused,
638 struct strfilter *filter __unused,
639 bool externs __unused)
535{ 640{
536 pr_warning("Debuginfo-analysis is not supported.\n"); 641 pr_warning("Debuginfo-analysis is not supported.\n");
537 return -ENOSYS; 642 return -ENOSYS;
@@ -556,11 +661,11 @@ static int parse_line_num(char **ptr, int *val, const char *what)
556 * The line range syntax is described by: 661 * The line range syntax is described by:
557 * 662 *
558 * SRC[:SLN[+NUM|-ELN]] 663 * SRC[:SLN[+NUM|-ELN]]
559 * FNC[:SLN[+NUM|-ELN]] 664 * FNC[@SRC][:SLN[+NUM|-ELN]]
560 */ 665 */
561int parse_line_range_desc(const char *arg, struct line_range *lr) 666int parse_line_range_desc(const char *arg, struct line_range *lr)
562{ 667{
563 char *range, *name = strdup(arg); 668 char *range, *file, *name = strdup(arg);
564 int err; 669 int err;
565 670
566 if (!name) 671 if (!name)
@@ -610,7 +715,16 @@ int parse_line_range_desc(const char *arg, struct line_range *lr)
610 } 715 }
611 } 716 }
612 717
613 if (strchr(name, '.')) 718 file = strchr(name, '@');
719 if (file) {
720 *file = '\0';
721 lr->file = strdup(++file);
722 if (lr->file == NULL) {
723 err = -ENOMEM;
724 goto err;
725 }
726 lr->function = name;
727 } else if (strchr(name, '.'))
614 lr->file = name; 728 lr->file = name;
615 else 729 else
616 lr->function = name; 730 lr->function = name;
@@ -945,7 +1059,7 @@ bool perf_probe_event_need_dwarf(struct perf_probe_event *pev)
945 1059
946/* Parse probe_events event into struct probe_point */ 1060/* Parse probe_events event into struct probe_point */
947static int parse_probe_trace_command(const char *cmd, 1061static int parse_probe_trace_command(const char *cmd,
948 struct probe_trace_event *tev) 1062 struct probe_trace_event *tev)
949{ 1063{
950 struct probe_trace_point *tp = &tev->point; 1064 struct probe_trace_point *tp = &tev->point;
951 char pr; 1065 char pr;
@@ -978,8 +1092,14 @@ static int parse_probe_trace_command(const char *cmd,
978 1092
979 tp->retprobe = (pr == 'r'); 1093 tp->retprobe = (pr == 'r');
980 1094
981 /* Scan function name and offset */ 1095 /* Scan module name(if there), function name and offset */
982 ret = sscanf(argv[1], "%a[^+]+%lu", (float *)(void *)&tp->symbol, 1096 p = strchr(argv[1], ':');
1097 if (p) {
1098 tp->module = strndup(argv[1], p - argv[1]);
1099 p++;
1100 } else
1101 p = argv[1];
1102 ret = sscanf(p, "%a[^+]+%lu", (float *)(void *)&tp->symbol,
983 &tp->offset); 1103 &tp->offset);
984 if (ret == 1) 1104 if (ret == 1)
985 tp->offset = 0; 1105 tp->offset = 0;
@@ -1224,9 +1344,10 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev)
1224 if (buf == NULL) 1344 if (buf == NULL)
1225 return NULL; 1345 return NULL;
1226 1346
1227 len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s+%lu", 1347 len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu",
1228 tp->retprobe ? 'r' : 'p', 1348 tp->retprobe ? 'r' : 'p',
1229 tev->group, tev->event, 1349 tev->group, tev->event,
1350 tp->module ?: "", tp->module ? ":" : "",
1230 tp->symbol, tp->offset); 1351 tp->symbol, tp->offset);
1231 if (len <= 0) 1352 if (len <= 0)
1232 goto error; 1353 goto error;
@@ -1333,6 +1454,8 @@ static void clear_probe_trace_event(struct probe_trace_event *tev)
1333 free(tev->group); 1454 free(tev->group);
1334 if (tev->point.symbol) 1455 if (tev->point.symbol)
1335 free(tev->point.symbol); 1456 free(tev->point.symbol);
1457 if (tev->point.module)
1458 free(tev->point.module);
1336 for (i = 0; i < tev->nargs; i++) { 1459 for (i = 0; i < tev->nargs; i++) {
1337 if (tev->args[i].name) 1460 if (tev->args[i].name)
1338 free(tev->args[i].name); 1461 free(tev->args[i].name);
@@ -1684,7 +1807,7 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
1684 /* Convert perf_probe_event with debuginfo */ 1807 /* Convert perf_probe_event with debuginfo */
1685 ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, module); 1808 ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, module);
1686 if (ret != 0) 1809 if (ret != 0)
1687 return ret; 1810 return ret; /* Found in debuginfo or got an error */
1688 1811
1689 /* Allocate trace event buffer */ 1812 /* Allocate trace event buffer */
1690 tev = *tevs = zalloc(sizeof(struct probe_trace_event)); 1813 tev = *tevs = zalloc(sizeof(struct probe_trace_event));
@@ -1697,6 +1820,15 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
1697 ret = -ENOMEM; 1820 ret = -ENOMEM;
1698 goto error; 1821 goto error;
1699 } 1822 }
1823
1824 if (module) {
1825 tev->point.module = strdup(module);
1826 if (tev->point.module == NULL) {
1827 ret = -ENOMEM;
1828 goto error;
1829 }
1830 }
1831
1700 tev->point.offset = pev->point.offset; 1832 tev->point.offset = pev->point.offset;
1701 tev->point.retprobe = pev->point.retprobe; 1833 tev->point.retprobe = pev->point.retprobe;
1702 tev->nargs = pev->nargs; 1834 tev->nargs = pev->nargs;
@@ -1784,9 +1916,12 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
1784 } 1916 }
1785 1917
1786 /* Loop 2: add all events */ 1918 /* Loop 2: add all events */
1787 for (i = 0; i < npevs && ret >= 0; i++) 1919 for (i = 0; i < npevs; i++) {
1788 ret = __add_probe_trace_events(pkgs[i].pev, pkgs[i].tevs, 1920 ret = __add_probe_trace_events(pkgs[i].pev, pkgs[i].tevs,
1789 pkgs[i].ntevs, force_add); 1921 pkgs[i].ntevs, force_add);
1922 if (ret < 0)
1923 break;
1924 }
1790end: 1925end:
1791 /* Loop 3: cleanup and free trace events */ 1926 /* Loop 3: cleanup and free trace events */
1792 for (i = 0; i < npevs; i++) { 1927 for (i = 0; i < npevs; i++) {
@@ -1912,4 +2047,46 @@ int del_perf_probe_events(struct strlist *dellist)
1912 2047
1913 return ret; 2048 return ret;
1914} 2049}
2050/* TODO: don't use a global variable for filter ... */
2051static struct strfilter *available_func_filter;
2052
2053/*
2054 * If a symbol corresponds to a function with global binding and
2055 * matches filter return 0. For all others return 1.
2056 */
2057static int filter_available_functions(struct map *map __unused,
2058 struct symbol *sym)
2059{
2060 if (sym->binding == STB_GLOBAL &&
2061 strfilter__compare(available_func_filter, sym->name))
2062 return 0;
2063 return 1;
2064}
2065
2066int show_available_funcs(const char *module, struct strfilter *_filter)
2067{
2068 struct map *map;
2069 int ret;
1915 2070
2071 setup_pager();
2072
2073 ret = init_vmlinux();
2074 if (ret < 0)
2075 return ret;
2076
2077 map = kernel_get_module_map(module);
2078 if (!map) {
2079 pr_err("Failed to find %s map.\n", (module) ? : "kernel");
2080 return -EINVAL;
2081 }
2082 available_func_filter = _filter;
2083 if (map__load(map, filter_available_functions)) {
2084 pr_err("Failed to load map.\n");
2085 return -EINVAL;
2086 }
2087 if (!dso__sorted_by_name(map->dso, map->type))
2088 dso__sort_by_name(map->dso, map->type);
2089
2090 dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
2091 return 0;
2092}
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 5accbedfea37..a7dee835f49c 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -3,12 +3,14 @@
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
9/* kprobe-tracer tracing point */ 10/* kprobe-tracer tracing point */
10struct probe_trace_point { 11struct probe_trace_point {
11 char *symbol; /* Base symbol */ 12 char *symbol; /* Base symbol */
13 char *module; /* Module name */
12 unsigned long offset; /* Offset from symbol */ 14 unsigned long offset; /* Offset from symbol */
13 bool retprobe; /* Return probe flag */ 15 bool retprobe; /* Return probe flag */
14}; 16};
@@ -126,7 +128,8 @@ extern int show_perf_probe_events(void);
126extern int show_line_range(struct line_range *lr, const char *module); 128extern int show_line_range(struct line_range *lr, const char *module);
127extern int show_available_vars(struct perf_probe_event *pevs, int npevs, 129extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
128 int max_probe_points, const char *module, 130 int max_probe_points, const char *module,
129 bool externs); 131 struct strfilter *filter, bool externs);
132extern int show_available_funcs(const char *module, struct strfilter *filter);
130 133
131 134
132/* Maximum index number of event-name postfix */ 135/* 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..3e44a3e36519 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"
@@ -42,21 +43,6 @@
42/* Kprobe tracer basic type is up to u64 */ 43/* Kprobe tracer basic type is up to u64 */
43#define MAX_BASIC_TYPE_BITS 64 44#define MAX_BASIC_TYPE_BITS 64
44 45
45/*
46 * Compare the tail of two strings.
47 * Return 0 if whole of either string is same as another's tail part.
48 */
49static int strtailcmp(const char *s1, const char *s2)
50{
51 int i1 = strlen(s1);
52 int i2 = strlen(s2);
53 while (--i1 >= 0 && --i2 >= 0) {
54 if (s1[i1] != s2[i2])
55 return s1[i1] - s2[i2];
56 }
57 return 0;
58}
59
60/* Line number list operations */ 46/* Line number list operations */
61 47
62/* Add a line to line number list */ 48/* Add a line to line number list */
@@ -130,29 +116,37 @@ static const Dwfl_Callbacks offline_callbacks = {
130}; 116};
131 117
132/* Get a Dwarf from offline image */ 118/* Get a Dwarf from offline image */
133static Dwarf *dwfl_init_offline_dwarf(int fd, Dwfl **dwflp, Dwarf_Addr *bias) 119static int debuginfo__init_offline_dwarf(struct debuginfo *self,
120 const char *path)
134{ 121{
135 Dwfl_Module *mod; 122 Dwfl_Module *mod;
136 Dwarf *dbg = NULL; 123 int fd;
137 124
138 if (!dwflp) 125 fd = open(path, O_RDONLY);
139 return NULL; 126 if (fd < 0)
127 return fd;
140 128
141 *dwflp = dwfl_begin(&offline_callbacks); 129 self->dwfl = dwfl_begin(&offline_callbacks);
142 if (!*dwflp) 130 if (!self->dwfl)
143 return NULL; 131 goto error;
144 132
145 mod = dwfl_report_offline(*dwflp, "", "", fd); 133 mod = dwfl_report_offline(self->dwfl, "", "", fd);
146 if (!mod) 134 if (!mod)
147 goto error; 135 goto error;
148 136
149 dbg = dwfl_module_getdwarf(mod, bias); 137 self->dbg = dwfl_module_getdwarf(mod, &self->bias);
150 if (!dbg) { 138 if (!self->dbg)
139 goto error;
140
141 return 0;
151error: 142error:
152 dwfl_end(*dwflp); 143 if (self->dwfl)
153 *dwflp = NULL; 144 dwfl_end(self->dwfl);
154 } 145 else
155 return dbg; 146 close(fd);
147 memset(self, 0, sizeof(*self));
148
149 return -ENOENT;
156} 150}
157 151
158#if _ELFUTILS_PREREQ(0, 148) 152#if _ELFUTILS_PREREQ(0, 148)
@@ -188,379 +182,81 @@ static const Dwfl_Callbacks kernel_callbacks = {
188}; 182};
189 183
190/* Get a Dwarf from live kernel image */ 184/* Get a Dwarf from live kernel image */
191static Dwarf *dwfl_init_live_kernel_dwarf(Dwarf_Addr addr, Dwfl **dwflp, 185static int debuginfo__init_online_kernel_dwarf(struct debuginfo *self,
192 Dwarf_Addr *bias) 186 Dwarf_Addr addr)
193{ 187{
194 Dwarf *dbg; 188 self->dwfl = dwfl_begin(&kernel_callbacks);
195 189 if (!self->dwfl)
196 if (!dwflp) 190 return -EINVAL;
197 return NULL;
198
199 *dwflp = dwfl_begin(&kernel_callbacks);
200 if (!*dwflp)
201 return NULL;
202 191
203 /* Load the kernel dwarves: Don't care the result here */ 192 /* Load the kernel dwarves: Don't care the result here */
204 dwfl_linux_kernel_report_kernel(*dwflp); 193 dwfl_linux_kernel_report_kernel(self->dwfl);
205 dwfl_linux_kernel_report_modules(*dwflp); 194 dwfl_linux_kernel_report_modules(self->dwfl);
206 195
207 dbg = dwfl_addrdwarf(*dwflp, addr, bias); 196 self->dbg = dwfl_addrdwarf(self->dwfl, addr, &self->bias);
208 /* Here, check whether we could get a real dwarf */ 197 /* Here, check whether we could get a real dwarf */
209 if (!dbg) { 198 if (!self->dbg) {
210 pr_debug("Failed to find kernel dwarf at %lx\n", 199 pr_debug("Failed to find kernel dwarf at %lx\n",
211 (unsigned long)addr); 200 (unsigned long)addr);
212 dwfl_end(*dwflp); 201 dwfl_end(self->dwfl);
213 *dwflp = NULL; 202 memset(self, 0, sizeof(*self));
203 return -ENOENT;
214 } 204 }
215 return dbg; 205
206 return 0;
216} 207}
217#else 208#else
218/* With older elfutils, this just support kernel module... */ 209/* With older elfutils, this just support kernel module... */
219static Dwarf *dwfl_init_live_kernel_dwarf(Dwarf_Addr addr __used, Dwfl **dwflp, 210static int debuginfo__init_online_kernel_dwarf(struct debuginfo *self,
220 Dwarf_Addr *bias) 211 Dwarf_Addr addr __used)
221{ 212{
222 int fd;
223 const char *path = kernel_get_module_path("kernel"); 213 const char *path = kernel_get_module_path("kernel");
224 214
225 if (!path) { 215 if (!path) {
226 pr_err("Failed to find vmlinux path\n"); 216 pr_err("Failed to find vmlinux path\n");
227 return NULL; 217 return -ENOENT;
228 } 218 }
229 219
230 pr_debug2("Use file %s for debuginfo\n", path); 220 pr_debug2("Use file %s for debuginfo\n", path);
231 fd = open(path, O_RDONLY); 221 return debuginfo__init_offline_dwarf(self, path);
232 if (fd < 0)
233 return NULL;
234
235 return dwfl_init_offline_dwarf(fd, dwflp, bias);
236} 222}
237#endif 223#endif
238 224
239/* Dwarf wrappers */ 225struct debuginfo *debuginfo__new(const char *path)
240
241/* Find the realpath of the target file. */
242static const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname)
243{ 226{
244 Dwarf_Files *files; 227 struct debuginfo *self = zalloc(sizeof(struct debuginfo));
245 size_t nfiles, i; 228 if (!self)
246 const char *src = NULL;
247 int ret;
248
249 if (!fname)
250 return NULL; 229 return NULL;
251 230
252 ret = dwarf_getsrcfiles(cu_die, &files, &nfiles); 231 if (debuginfo__init_offline_dwarf(self, path) < 0) {
253 if (ret != 0) 232 free(self);
254 return NULL; 233 self = NULL;
255
256 for (i = 0; i < nfiles; i++) {
257 src = dwarf_filesrc(files, i, NULL, NULL);
258 if (strtailcmp(src, fname) == 0)
259 break;
260 } 234 }
261 if (i == nfiles)
262 return NULL;
263 return src;
264}
265
266/* Get DW_AT_comp_dir (should be NULL with older gcc) */
267static const char *cu_get_comp_dir(Dwarf_Die *cu_die)
268{
269 Dwarf_Attribute attr;
270 if (dwarf_attr(cu_die, DW_AT_comp_dir, &attr) == NULL)
271 return NULL;
272 return dwarf_formstring(&attr);
273}
274 235
275/* Compare diename and tname */ 236 return self;
276static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
277{
278 const char *name;
279 name = dwarf_diename(dw_die);
280 return name ? (strcmp(tname, name) == 0) : false;
281} 237}
282 238
283/* Get type die */ 239struct debuginfo *debuginfo__new_online_kernel(unsigned long addr)
284static Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
285{ 240{
286 Dwarf_Attribute attr; 241 struct debuginfo *self = zalloc(sizeof(struct debuginfo));
287 242 if (!self)
288 if (dwarf_attr_integrate(vr_die, DW_AT_type, &attr) &&
289 dwarf_formref_die(&attr, die_mem))
290 return die_mem;
291 else
292 return NULL; 243 return NULL;
293}
294
295/* Get a type die, but skip qualifiers */
296static Dwarf_Die *__die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
297{
298 int tag;
299
300 do {
301 vr_die = die_get_type(vr_die, die_mem);
302 if (!vr_die)
303 break;
304 tag = dwarf_tag(vr_die);
305 } while (tag == DW_TAG_const_type ||
306 tag == DW_TAG_restrict_type ||
307 tag == DW_TAG_volatile_type ||
308 tag == DW_TAG_shared_type);
309
310 return vr_die;
311}
312
313/* Get a type die, but skip qualifiers and typedef */
314static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
315{
316 do {
317 vr_die = __die_get_real_type(vr_die, die_mem);
318 } while (vr_die && dwarf_tag(vr_die) == DW_TAG_typedef);
319
320 return vr_die;
321}
322
323static bool die_is_signed_type(Dwarf_Die *tp_die)
324{
325 Dwarf_Attribute attr;
326 Dwarf_Word ret;
327
328 if (dwarf_attr(tp_die, DW_AT_encoding, &attr) == NULL ||
329 dwarf_formudata(&attr, &ret) != 0)
330 return false;
331
332 return (ret == DW_ATE_signed_char || ret == DW_ATE_signed ||
333 ret == DW_ATE_signed_fixed);
334}
335
336static int die_get_byte_size(Dwarf_Die *tp_die)
337{
338 Dwarf_Attribute attr;
339 Dwarf_Word ret;
340
341 if (dwarf_attr(tp_die, DW_AT_byte_size, &attr) == NULL ||
342 dwarf_formudata(&attr, &ret) != 0)
343 return 0;
344
345 return (int)ret;
346}
347
348/* Get data_member_location offset */
349static int die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs)
350{
351 Dwarf_Attribute attr;
352 Dwarf_Op *expr;
353 size_t nexpr;
354 int ret;
355 244
356 if (dwarf_attr(mb_die, DW_AT_data_member_location, &attr) == NULL) 245 if (debuginfo__init_online_kernel_dwarf(self, (Dwarf_Addr)addr) < 0) {
357 return -ENOENT; 246 free(self);
358 247 self = NULL;
359 if (dwarf_formudata(&attr, offs) != 0) {
360 /* DW_AT_data_member_location should be DW_OP_plus_uconst */
361 ret = dwarf_getlocation(&attr, &expr, &nexpr);
362 if (ret < 0 || nexpr == 0)
363 return -ENOENT;
364
365 if (expr[0].atom != DW_OP_plus_uconst || nexpr != 1) {
366 pr_debug("Unable to get offset:Unexpected OP %x (%zd)\n",
367 expr[0].atom, nexpr);
368 return -ENOTSUP;
369 }
370 *offs = (Dwarf_Word)expr[0].number;
371 } 248 }
372 return 0;
373}
374
375/* Return values for die_find callbacks */
376enum {
377 DIE_FIND_CB_FOUND = 0, /* End of Search */
378 DIE_FIND_CB_CHILD = 1, /* Search only children */
379 DIE_FIND_CB_SIBLING = 2, /* Search only siblings */
380 DIE_FIND_CB_CONTINUE = 3, /* Search children and siblings */
381};
382 249
383/* Search a child die */ 250 return self;
384static Dwarf_Die *die_find_child(Dwarf_Die *rt_die,
385 int (*callback)(Dwarf_Die *, void *),
386 void *data, Dwarf_Die *die_mem)
387{
388 Dwarf_Die child_die;
389 int ret;
390
391 ret = dwarf_child(rt_die, die_mem);
392 if (ret != 0)
393 return NULL;
394
395 do {
396 ret = callback(die_mem, data);
397 if (ret == DIE_FIND_CB_FOUND)
398 return die_mem;
399
400 if ((ret & DIE_FIND_CB_CHILD) &&
401 die_find_child(die_mem, callback, data, &child_die)) {
402 memcpy(die_mem, &child_die, sizeof(Dwarf_Die));
403 return die_mem;
404 }
405 } while ((ret & DIE_FIND_CB_SIBLING) &&
406 dwarf_siblingof(die_mem, die_mem) == 0);
407
408 return NULL;
409} 251}
410 252
411struct __addr_die_search_param { 253void debuginfo__delete(struct debuginfo *self)
412 Dwarf_Addr addr;
413 Dwarf_Die *die_mem;
414};
415
416static int __die_search_func_cb(Dwarf_Die *fn_die, void *data)
417{ 254{
418 struct __addr_die_search_param *ad = data; 255 if (self) {
419 256 if (self->dwfl)
420 if (dwarf_tag(fn_die) == DW_TAG_subprogram && 257 dwfl_end(self->dwfl);
421 dwarf_haspc(fn_die, ad->addr)) { 258 free(self);
422 memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die));
423 return DWARF_CB_ABORT;
424 } 259 }
425 return DWARF_CB_OK;
426}
427
428/* Search a real subprogram including this line, */
429static Dwarf_Die *die_find_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr,
430 Dwarf_Die *die_mem)
431{
432 struct __addr_die_search_param ad;
433 ad.addr = addr;
434 ad.die_mem = die_mem;
435 /* dwarf_getscopes can't find subprogram. */
436 if (!dwarf_getfuncs(cu_die, __die_search_func_cb, &ad, 0))
437 return NULL;
438 else
439 return die_mem;
440}
441
442/* die_find callback for inline function search */
443static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data)
444{
445 Dwarf_Addr *addr = data;
446
447 if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine &&
448 dwarf_haspc(die_mem, *addr))
449 return DIE_FIND_CB_FOUND;
450
451 return DIE_FIND_CB_CONTINUE;
452}
453
454/* Similar to dwarf_getfuncs, but returns inlined_subroutine if exists. */
455static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
456 Dwarf_Die *die_mem)
457{
458 return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem);
459}
460
461struct __find_variable_param {
462 const char *name;
463 Dwarf_Addr addr;
464};
465
466static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data)
467{
468 struct __find_variable_param *fvp = data;
469 int tag;
470
471 tag = dwarf_tag(die_mem);
472 if ((tag == DW_TAG_formal_parameter ||
473 tag == DW_TAG_variable) &&
474 die_compare_name(die_mem, fvp->name))
475 return DIE_FIND_CB_FOUND;
476
477 if (dwarf_haspc(die_mem, fvp->addr))
478 return DIE_FIND_CB_CONTINUE;
479 else
480 return DIE_FIND_CB_SIBLING;
481}
482
483/* Find a variable called 'name' at given address */
484static Dwarf_Die *die_find_variable_at(Dwarf_Die *sp_die, const char *name,
485 Dwarf_Addr addr, Dwarf_Die *die_mem)
486{
487 struct __find_variable_param fvp = { .name = name, .addr = addr};
488
489 return die_find_child(sp_die, __die_find_variable_cb, (void *)&fvp,
490 die_mem);
491}
492
493static int __die_find_member_cb(Dwarf_Die *die_mem, void *data)
494{
495 const char *name = data;
496
497 if ((dwarf_tag(die_mem) == DW_TAG_member) &&
498 die_compare_name(die_mem, name))
499 return DIE_FIND_CB_FOUND;
500
501 return DIE_FIND_CB_SIBLING;
502}
503
504/* Find a member called 'name' */
505static Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name,
506 Dwarf_Die *die_mem)
507{
508 return die_find_child(st_die, __die_find_member_cb, (void *)name,
509 die_mem);
510}
511
512/* Get the name of given variable DIE */
513static int die_get_typename(Dwarf_Die *vr_die, char *buf, int len)
514{
515 Dwarf_Die type;
516 int tag, ret, ret2;
517 const char *tmp = "";
518
519 if (__die_get_real_type(vr_die, &type) == NULL)
520 return -ENOENT;
521
522 tag = dwarf_tag(&type);
523 if (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)
524 tmp = "*";
525 else if (tag == DW_TAG_subroutine_type) {
526 /* Function pointer */
527 ret = snprintf(buf, len, "(function_type)");
528 return (ret >= len) ? -E2BIG : ret;
529 } else {
530 if (!dwarf_diename(&type))
531 return -ENOENT;
532 if (tag == DW_TAG_union_type)
533 tmp = "union ";
534 else if (tag == DW_TAG_structure_type)
535 tmp = "struct ";
536 /* Write a base name */
537 ret = snprintf(buf, len, "%s%s", tmp, dwarf_diename(&type));
538 return (ret >= len) ? -E2BIG : ret;
539 }
540 ret = die_get_typename(&type, buf, len);
541 if (ret > 0) {
542 ret2 = snprintf(buf + ret, len - ret, "%s", tmp);
543 ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret;
544 }
545 return ret;
546}
547
548/* Get the name and type of given variable DIE, stored as "type\tname" */
549static int die_get_varname(Dwarf_Die *vr_die, char *buf, int len)
550{
551 int ret, ret2;
552
553 ret = die_get_typename(vr_die, buf, len);
554 if (ret < 0) {
555 pr_debug("Failed to get type, make it unknown.\n");
556 ret = snprintf(buf, len, "(unknown_type)");
557 }
558 if (ret > 0) {
559 ret2 = snprintf(buf + ret, len - ret, "\t%s",
560 dwarf_diename(vr_die));
561 ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret;
562 }
563 return ret;
564} 260}
565 261
566/* 262/*
@@ -669,6 +365,8 @@ static_var:
669 return 0; 365 return 0;
670} 366}
671 367
368#define BYTES_TO_BITS(nb) ((nb) * BITS_PER_LONG / sizeof(long))
369
672static int convert_variable_type(Dwarf_Die *vr_die, 370static int convert_variable_type(Dwarf_Die *vr_die,
673 struct probe_trace_arg *tvar, 371 struct probe_trace_arg *tvar,
674 const char *cast) 372 const char *cast)
@@ -676,6 +374,7 @@ static int convert_variable_type(Dwarf_Die *vr_die,
676 struct probe_trace_arg_ref **ref_ptr = &tvar->ref; 374 struct probe_trace_arg_ref **ref_ptr = &tvar->ref;
677 Dwarf_Die type; 375 Dwarf_Die type;
678 char buf[16]; 376 char buf[16];
377 int bsize, boffs, total;
679 int ret; 378 int ret;
680 379
681 /* TODO: check all types */ 380 /* TODO: check all types */
@@ -685,6 +384,18 @@ static int convert_variable_type(Dwarf_Die *vr_die,
685 return (tvar->type == NULL) ? -ENOMEM : 0; 384 return (tvar->type == NULL) ? -ENOMEM : 0;
686 } 385 }
687 386
387 bsize = dwarf_bitsize(vr_die);
388 if (bsize > 0) {
389 /* This is a bitfield */
390 boffs = dwarf_bitoffset(vr_die);
391 total = dwarf_bytesize(vr_die);
392 if (boffs < 0 || total < 0)
393 return -ENOENT;
394 ret = snprintf(buf, 16, "b%d@%d/%zd", bsize, boffs,
395 BYTES_TO_BITS(total));
396 goto formatted;
397 }
398
688 if (die_get_real_type(vr_die, &type) == NULL) { 399 if (die_get_real_type(vr_die, &type) == NULL) {
689 pr_warning("Failed to get a type information of %s.\n", 400 pr_warning("Failed to get a type information of %s.\n",
690 dwarf_diename(vr_die)); 401 dwarf_diename(vr_die));
@@ -729,29 +440,32 @@ static int convert_variable_type(Dwarf_Die *vr_die,
729 return (tvar->type == NULL) ? -ENOMEM : 0; 440 return (tvar->type == NULL) ? -ENOMEM : 0;
730 } 441 }
731 442
732 ret = die_get_byte_size(&type) * 8; 443 ret = dwarf_bytesize(&type);
733 if (ret) { 444 if (ret <= 0)
734 /* Check the bitwidth */ 445 /* No size ... try to use default type */
735 if (ret > MAX_BASIC_TYPE_BITS) { 446 return 0;
736 pr_info("%s exceeds max-bitwidth." 447 ret = BYTES_TO_BITS(ret);
737 " Cut down to %d bits.\n", 448
738 dwarf_diename(&type), MAX_BASIC_TYPE_BITS); 449 /* Check the bitwidth */
739 ret = MAX_BASIC_TYPE_BITS; 450 if (ret > MAX_BASIC_TYPE_BITS) {
740 } 451 pr_info("%s exceeds max-bitwidth. Cut down to %d bits.\n",
741 452 dwarf_diename(&type), MAX_BASIC_TYPE_BITS);
742 ret = snprintf(buf, 16, "%c%d", 453 ret = MAX_BASIC_TYPE_BITS;
743 die_is_signed_type(&type) ? 's' : 'u', ret); 454 }
744 if (ret < 0 || ret >= 16) { 455 ret = snprintf(buf, 16, "%c%d",
745 if (ret >= 16) 456 die_is_signed_type(&type) ? 's' : 'u', ret);
746 ret = -E2BIG; 457
747 pr_warning("Failed to convert variable type: %s\n", 458formatted:
748 strerror(-ret)); 459 if (ret < 0 || ret >= 16) {
749 return ret; 460 if (ret >= 16)
750 } 461 ret = -E2BIG;
751 tvar->type = strdup(buf); 462 pr_warning("Failed to convert variable type: %s\n",
752 if (tvar->type == NULL) 463 strerror(-ret));
753 return -ENOMEM; 464 return ret;
754 } 465 }
466 tvar->type = strdup(buf);
467 if (tvar->type == NULL)
468 return -ENOMEM;
755 return 0; 469 return 0;
756} 470}
757 471
@@ -794,7 +508,7 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
794 else 508 else
795 *ref_ptr = ref; 509 *ref_ptr = ref;
796 } 510 }
797 ref->offset += die_get_byte_size(&type) * field->index; 511 ref->offset += dwarf_bytesize(&type) * field->index;
798 if (!field->next) 512 if (!field->next)
799 /* Save vr_die for converting types */ 513 /* Save vr_die for converting types */
800 memcpy(die_mem, vr_die, sizeof(*die_mem)); 514 memcpy(die_mem, vr_die, sizeof(*die_mem));
@@ -1014,8 +728,7 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf)
1014 728
1015 /* If no real subprogram, find a real one */ 729 /* If no real subprogram, find a real one */
1016 if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) { 730 if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) {
1017 sp_die = die_find_real_subprogram(&pf->cu_die, 731 sp_die = die_find_realfunc(&pf->cu_die, pf->addr, &die_mem);
1018 pf->addr, &die_mem);
1019 if (!sp_die) { 732 if (!sp_die) {
1020 pr_warning("Failed to find probe point in any " 733 pr_warning("Failed to find probe point in any "
1021 "functions.\n"); 734 "functions.\n");
@@ -1050,157 +763,102 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf)
1050 return ret; 763 return ret;
1051} 764}
1052 765
1053/* Find probe point from its line number */ 766static int probe_point_line_walker(const char *fname, int lineno,
1054static int find_probe_point_by_line(struct probe_finder *pf) 767 Dwarf_Addr addr, void *data)
1055{ 768{
1056 Dwarf_Lines *lines; 769 struct probe_finder *pf = data;
1057 Dwarf_Line *line; 770 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 771
1068 for (i = 0; i < nlines && ret == 0; i++) { 772 if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0)
1069 line = dwarf_onesrcline(lines, i); 773 return 0;
1070 if (dwarf_lineno(line, &lineno) != 0 ||
1071 lineno != pf->lno)
1072 continue;
1073 774
1074 /* TODO: Get fileno from line, but how? */ 775 pf->addr = addr;
1075 if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0) 776 ret = call_probe_finder(NULL, pf);
1076 continue;
1077 777
1078 if (dwarf_lineaddr(line, &addr) != 0) { 778 /* Continue if no error, because the line will be in inline function */
1079 pr_warning("Failed to get the address of the line.\n"); 779 return ret < 0 ? ret : 0;
1080 return -ENOENT; 780}
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 781
1086 ret = call_probe_finder(NULL, pf); 782/* Find probe point from its line number */
1087 /* Continuing, because target line might be inlined. */ 783static int find_probe_point_by_line(struct probe_finder *pf)
1088 } 784{
1089 return ret; 785 return die_walk_lines(&pf->cu_die, probe_point_line_walker, pf);
1090} 786}
1091 787
1092/* Find lines which match lazy pattern */ 788/* Find lines which match lazy pattern */
1093static int find_lazy_match_lines(struct list_head *head, 789static int find_lazy_match_lines(struct list_head *head,
1094 const char *fname, const char *pat) 790 const char *fname, const char *pat)
1095{ 791{
1096 char *fbuf, *p1, *p2; 792 FILE *fp;
1097 int fd, line, nlines = -1; 793 char *line = NULL;
1098 struct stat st; 794 size_t line_len;
1099 795 ssize_t len;
1100 fd = open(fname, O_RDONLY); 796 int count = 0, linenum = 1;
1101 if (fd < 0) { 797
1102 pr_warning("Failed to open %s: %s\n", fname, strerror(-fd)); 798 fp = fopen(fname, "r");
799 if (!fp) {
800 pr_warning("Failed to open %s: %s\n", fname, strerror(errno));
1103 return -errno; 801 return -errno;
1104 } 802 }
1105 803
1106 if (fstat(fd, &st) < 0) { 804 while ((len = getline(&line, &line_len, fp)) > 0) {
1107 pr_warning("Failed to get the size of %s: %s\n",
1108 fname, strerror(errno));
1109 nlines = -errno;
1110 goto out_close;
1111 }
1112 805
1113 nlines = -ENOMEM; 806 if (line[len - 1] == '\n')
1114 fbuf = malloc(st.st_size + 2); 807 line[len - 1] = '\0';
1115 if (fbuf == NULL) 808
1116 goto out_close; 809 if (strlazymatch(line, pat)) {
1117 if (read(fd, fbuf, st.st_size) < 0) { 810 line_list__add_line(head, linenum);
1118 pr_warning("Failed to read %s: %s\n", fname, strerror(errno)); 811 count++;
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 } 812 }
1133 line++; 813 linenum++;
1134 p1 = p2 + 1;
1135 } 814 }
1136out_free_fbuf: 815
1137 free(fbuf); 816 if (ferror(fp))
1138out_close: 817 count = -errno;
1139 close(fd); 818 free(line);
1140 return nlines; 819 fclose(fp);
820
821 if (count == 0)
822 pr_debug("No matched lines found in %s.\n", fname);
823 return count;
824}
825
826static int probe_point_lazy_walker(const char *fname, int lineno,
827 Dwarf_Addr addr, void *data)
828{
829 struct probe_finder *pf = data;
830 int ret;
831
832 if (!line_list__has_line(&pf->lcache, lineno) ||
833 strtailcmp(fname, pf->fname) != 0)
834 return 0;
835
836 pr_debug("Probe line found: line:%d addr:0x%llx\n",
837 lineno, (unsigned long long)addr);
838 pf->addr = addr;
839 ret = call_probe_finder(NULL, pf);
840
841 /*
842 * Continue if no error, because the lazy pattern will match
843 * to other lines
844 */
845 return ret < 0 ? ret : 0;
1141} 846}
1142 847
1143/* Find probe points from lazy pattern */ 848/* Find probe points from lazy pattern */
1144static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) 849static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
1145{ 850{
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; 851 int ret = 0;
1153 852
1154 if (list_empty(&pf->lcache)) { 853 if (list_empty(&pf->lcache)) {
1155 /* Matching lazy line pattern */ 854 /* Matching lazy line pattern */
1156 ret = find_lazy_match_lines(&pf->lcache, pf->fname, 855 ret = find_lazy_match_lines(&pf->lcache, pf->fname,
1157 pf->pev->point.lazy_line); 856 pf->pev->point.lazy_line);
1158 if (ret == 0) { 857 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; 858 return ret;
1163 } 859 }
1164 860
1165 if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) { 861 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} 862}
1205 863
1206/* Callback parameter with return value */ 864/* Callback parameter with return value */
@@ -1251,6 +909,10 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
1251 !die_compare_name(sp_die, pp->function)) 909 !die_compare_name(sp_die, pp->function))
1252 return DWARF_CB_OK; 910 return DWARF_CB_OK;
1253 911
912 /* Check declared file */
913 if (pp->file && strtailcmp(pp->file, dwarf_decl_file(sp_die)))
914 return DWARF_CB_OK;
915
1254 pf->fname = dwarf_decl_file(sp_die); 916 pf->fname = dwarf_decl_file(sp_die);
1255 if (pp->line) { /* Function relative line */ 917 if (pp->line) { /* Function relative line */
1256 dwarf_decl_line(sp_die, &pf->lno); 918 dwarf_decl_line(sp_die, &pf->lno);
@@ -1291,37 +953,82 @@ static int find_probe_point_by_func(struct probe_finder *pf)
1291 return _param.retval; 953 return _param.retval;
1292} 954}
1293 955
956struct pubname_callback_param {
957 char *function;
958 char *file;
959 Dwarf_Die *cu_die;
960 Dwarf_Die *sp_die;
961 int found;
962};
963
964static int pubname_search_cb(Dwarf *dbg, Dwarf_Global *gl, void *data)
965{
966 struct pubname_callback_param *param = data;
967
968 if (dwarf_offdie(dbg, gl->die_offset, param->sp_die)) {
969 if (dwarf_tag(param->sp_die) != DW_TAG_subprogram)
970 return DWARF_CB_OK;
971
972 if (die_compare_name(param->sp_die, param->function)) {
973 if (!dwarf_offdie(dbg, gl->cu_offset, param->cu_die))
974 return DWARF_CB_OK;
975
976 if (param->file &&
977 strtailcmp(param->file, dwarf_decl_file(param->sp_die)))
978 return DWARF_CB_OK;
979
980 param->found = 1;
981 return DWARF_CB_ABORT;
982 }
983 }
984
985 return DWARF_CB_OK;
986}
987
1294/* Find probe points from debuginfo */ 988/* Find probe points from debuginfo */
1295static int find_probes(int fd, struct probe_finder *pf) 989static int debuginfo__find_probes(struct debuginfo *self,
990 struct probe_finder *pf)
1296{ 991{
1297 struct perf_probe_point *pp = &pf->pev->point; 992 struct perf_probe_point *pp = &pf->pev->point;
1298 Dwarf_Off off, noff; 993 Dwarf_Off off, noff;
1299 size_t cuhl; 994 size_t cuhl;
1300 Dwarf_Die *diep; 995 Dwarf_Die *diep;
1301 Dwarf *dbg = NULL;
1302 Dwfl *dwfl;
1303 Dwarf_Addr bias; /* Currently ignored */
1304 int ret = 0; 996 int ret = 0;
1305 997
1306 dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias);
1307 if (!dbg) {
1308 pr_warning("No debug information found in the vmlinux - "
1309 "please rebuild with CONFIG_DEBUG_INFO=y.\n");
1310 return -EBADF;
1311 }
1312
1313#if _ELFUTILS_PREREQ(0, 142) 998#if _ELFUTILS_PREREQ(0, 142)
1314 /* Get the call frame information from this dwarf */ 999 /* Get the call frame information from this dwarf */
1315 pf->cfi = dwarf_getcfi(dbg); 1000 pf->cfi = dwarf_getcfi(self->dbg);
1316#endif 1001#endif
1317 1002
1318 off = 0; 1003 off = 0;
1319 line_list__init(&pf->lcache); 1004 line_list__init(&pf->lcache);
1005
1006 /* Fastpath: lookup by function name from .debug_pubnames section */
1007 if (pp->function) {
1008 struct pubname_callback_param pubname_param = {
1009 .function = pp->function,
1010 .file = pp->file,
1011 .cu_die = &pf->cu_die,
1012 .sp_die = &pf->sp_die,
1013 .found = 0,
1014 };
1015 struct dwarf_callback_param probe_param = {
1016 .data = pf,
1017 };
1018
1019 dwarf_getpubnames(self->dbg, pubname_search_cb,
1020 &pubname_param, 0);
1021 if (pubname_param.found) {
1022 ret = probe_point_search_cb(&pf->sp_die, &probe_param);
1023 if (ret)
1024 goto found;
1025 }
1026 }
1027
1320 /* Loop on CUs (Compilation Unit) */ 1028 /* Loop on CUs (Compilation Unit) */
1321 while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) && 1029 while (!dwarf_nextcu(self->dbg, off, &noff, &cuhl, NULL, NULL, NULL)) {
1322 ret >= 0) {
1323 /* Get the DIE(Debugging Information Entry) of this CU */ 1030 /* Get the DIE(Debugging Information Entry) of this CU */
1324 diep = dwarf_offdie(dbg, off + cuhl, &pf->cu_die); 1031 diep = dwarf_offdie(self->dbg, off + cuhl, &pf->cu_die);
1325 if (!diep) 1032 if (!diep)
1326 continue; 1033 continue;
1327 1034
@@ -1340,12 +1047,14 @@ static int find_probes(int fd, struct probe_finder *pf)
1340 pf->lno = pp->line; 1047 pf->lno = pp->line;
1341 ret = find_probe_point_by_line(pf); 1048 ret = find_probe_point_by_line(pf);
1342 } 1049 }
1050 if (ret < 0)
1051 break;
1343 } 1052 }
1344 off = noff; 1053 off = noff;
1345 } 1054 }
1055
1056found:
1346 line_list__free(&pf->lcache); 1057 line_list__free(&pf->lcache);
1347 if (dwfl)
1348 dwfl_end(dwfl);
1349 1058
1350 return ret; 1059 return ret;
1351} 1060}
@@ -1391,8 +1100,9 @@ static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf)
1391} 1100}
1392 1101
1393/* Find probe_trace_events specified by perf_probe_event from debuginfo */ 1102/* Find probe_trace_events specified by perf_probe_event from debuginfo */
1394int find_probe_trace_events(int fd, struct perf_probe_event *pev, 1103int debuginfo__find_trace_events(struct debuginfo *self,
1395 struct probe_trace_event **tevs, int max_tevs) 1104 struct perf_probe_event *pev,
1105 struct probe_trace_event **tevs, int max_tevs)
1396{ 1106{
1397 struct trace_event_finder tf = { 1107 struct trace_event_finder tf = {
1398 .pf = {.pev = pev, .callback = add_probe_trace_event}, 1108 .pf = {.pev = pev, .callback = add_probe_trace_event},
@@ -1407,7 +1117,7 @@ int find_probe_trace_events(int fd, struct perf_probe_event *pev,
1407 tf.tevs = *tevs; 1117 tf.tevs = *tevs;
1408 tf.ntevs = 0; 1118 tf.ntevs = 0;
1409 1119
1410 ret = find_probes(fd, &tf.pf); 1120 ret = debuginfo__find_probes(self, &tf.pf);
1411 if (ret < 0) { 1121 if (ret < 0) {
1412 free(*tevs); 1122 free(*tevs);
1413 *tevs = NULL; 1123 *tevs = NULL;
@@ -1501,9 +1211,10 @@ out:
1501} 1211}
1502 1212
1503/* Find available variables at given probe point */ 1213/* Find available variables at given probe point */
1504int find_available_vars_at(int fd, struct perf_probe_event *pev, 1214int debuginfo__find_available_vars_at(struct debuginfo *self,
1505 struct variable_list **vls, int max_vls, 1215 struct perf_probe_event *pev,
1506 bool externs) 1216 struct variable_list **vls,
1217 int max_vls, bool externs)
1507{ 1218{
1508 struct available_var_finder af = { 1219 struct available_var_finder af = {
1509 .pf = {.pev = pev, .callback = add_available_vars}, 1220 .pf = {.pev = pev, .callback = add_available_vars},
@@ -1518,7 +1229,7 @@ int find_available_vars_at(int fd, struct perf_probe_event *pev,
1518 af.vls = *vls; 1229 af.vls = *vls;
1519 af.nvls = 0; 1230 af.nvls = 0;
1520 1231
1521 ret = find_probes(fd, &af.pf); 1232 ret = debuginfo__find_probes(self, &af.pf);
1522 if (ret < 0) { 1233 if (ret < 0) {
1523 /* Free vlist for error */ 1234 /* Free vlist for error */
1524 while (af.nvls--) { 1235 while (af.nvls--) {
@@ -1536,98 +1247,96 @@ int find_available_vars_at(int fd, struct perf_probe_event *pev,
1536} 1247}
1537 1248
1538/* Reverse search */ 1249/* Reverse search */
1539int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt) 1250int debuginfo__find_probe_point(struct debuginfo *self, unsigned long addr,
1251 struct perf_probe_point *ppt)
1540{ 1252{
1541 Dwarf_Die cudie, spdie, indie; 1253 Dwarf_Die cudie, spdie, indie;
1542 Dwarf *dbg = NULL; 1254 Dwarf_Addr _addr, baseaddr;
1543 Dwfl *dwfl = NULL; 1255 const char *fname = NULL, *func = NULL, *tmp;
1544 Dwarf_Line *line; 1256 int baseline = 0, lineno = 0, ret = 0;
1545 Dwarf_Addr laddr, eaddr, bias = 0;
1546 const char *tmp;
1547 int lineno, ret = 0;
1548 bool found = false;
1549
1550 /* Open the live linux kernel */
1551 dbg = dwfl_init_live_kernel_dwarf(addr, &dwfl, &bias);
1552 if (!dbg) {
1553 pr_warning("No debug information found in the vmlinux - "
1554 "please rebuild with CONFIG_DEBUG_INFO=y.\n");
1555 ret = -EINVAL;
1556 goto end;
1557 }
1558 1257
1559 /* Adjust address with bias */ 1258 /* Adjust address with bias */
1560 addr += bias; 1259 addr += self->bias;
1260
1561 /* Find cu die */ 1261 /* Find cu die */
1562 if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr - bias, &cudie)) { 1262 if (!dwarf_addrdie(self->dbg, (Dwarf_Addr)addr - self->bias, &cudie)) {
1563 pr_warning("Failed to find debug information for address %lx\n", 1263 pr_warning("Failed to find debug information for address %lx\n",
1564 addr); 1264 addr);
1565 ret = -EINVAL; 1265 ret = -EINVAL;
1566 goto end; 1266 goto end;
1567 } 1267 }
1568 1268
1569 /* Find a corresponding line */ 1269 /* Find a corresponding line (filename and lineno) */
1570 line = dwarf_getsrc_die(&cudie, (Dwarf_Addr)addr); 1270 cu_find_lineinfo(&cudie, addr, &fname, &lineno);
1571 if (line) { 1271 /* Don't care whether it failed or not */
1572 if (dwarf_lineaddr(line, &laddr) == 0 &&
1573 (Dwarf_Addr)addr == laddr &&
1574 dwarf_lineno(line, &lineno) == 0) {
1575 tmp = dwarf_linesrc(line, NULL, NULL);
1576 if (tmp) {
1577 ppt->line = lineno;
1578 ppt->file = strdup(tmp);
1579 if (ppt->file == NULL) {
1580 ret = -ENOMEM;
1581 goto end;
1582 }
1583 found = true;
1584 }
1585 }
1586 }
1587 1272
1588 /* Find a corresponding function */ 1273 /* Find a corresponding function (name, baseline and baseaddr) */
1589 if (die_find_real_subprogram(&cudie, (Dwarf_Addr)addr, &spdie)) { 1274 if (die_find_realfunc(&cudie, (Dwarf_Addr)addr, &spdie)) {
1275 /* Get function entry information */
1590 tmp = dwarf_diename(&spdie); 1276 tmp = dwarf_diename(&spdie);
1591 if (!tmp || dwarf_entrypc(&spdie, &eaddr) != 0) 1277 if (!tmp ||
1592 goto end; 1278 dwarf_entrypc(&spdie, &baseaddr) != 0 ||
1593 1279 dwarf_decl_line(&spdie, &baseline) != 0)
1594 if (ppt->line) { 1280 goto post;
1595 if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr, 1281 func = tmp;
1596 &indie)) { 1282
1597 /* addr in an inline function */ 1283 if (addr == (unsigned long)baseaddr)
1284 /* Function entry - Relative line number is 0 */
1285 lineno = baseline;
1286 else if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr,
1287 &indie)) {
1288 if (dwarf_entrypc(&indie, &_addr) == 0 &&
1289 _addr == addr)
1290 /*
1291 * addr is at an inline function entry.
1292 * In this case, lineno should be the call-site
1293 * line number.
1294 */
1295 lineno = die_get_call_lineno(&indie);
1296 else {
1297 /*
1298 * addr is in an inline function body.
1299 * Since lineno points one of the lines
1300 * of the inline function, baseline should
1301 * be the entry line of the inline function.
1302 */
1598 tmp = dwarf_diename(&indie); 1303 tmp = dwarf_diename(&indie);
1599 if (!tmp) 1304 if (tmp &&
1600 goto end; 1305 dwarf_decl_line(&spdie, &baseline) == 0)
1601 ret = dwarf_decl_line(&indie, &lineno); 1306 func = tmp;
1602 } else {
1603 if (eaddr == addr) { /* Function entry */
1604 lineno = ppt->line;
1605 ret = 0;
1606 } else
1607 ret = dwarf_decl_line(&spdie, &lineno);
1608 }
1609 if (ret == 0) {
1610 /* Make a relative line number */
1611 ppt->line -= lineno;
1612 goto found;
1613 } 1307 }
1614 } 1308 }
1615 /* We don't have a line number, let's use offset */ 1309 }
1616 ppt->offset = addr - (unsigned long)eaddr; 1310
1617found: 1311post:
1618 ppt->function = strdup(tmp); 1312 /* Make a relative line number or an offset */
1313 if (lineno)
1314 ppt->line = lineno - baseline;
1315 else if (func)
1316 ppt->offset = addr - (unsigned long)baseaddr;
1317
1318 /* Duplicate strings */
1319 if (func) {
1320 ppt->function = strdup(func);
1619 if (ppt->function == NULL) { 1321 if (ppt->function == NULL) {
1620 ret = -ENOMEM; 1322 ret = -ENOMEM;
1621 goto end; 1323 goto end;
1622 } 1324 }
1623 found = true;
1624 } 1325 }
1625 1326 if (fname) {
1327 ppt->file = strdup(fname);
1328 if (ppt->file == NULL) {
1329 if (ppt->function) {
1330 free(ppt->function);
1331 ppt->function = NULL;
1332 }
1333 ret = -ENOMEM;
1334 goto end;
1335 }
1336 }
1626end: 1337end:
1627 if (dwfl) 1338 if (ret == 0 && (fname || func))
1628 dwfl_end(dwfl); 1339 ret = 1; /* Found a point */
1629 if (ret >= 0)
1630 ret = found ? 1 : 0;
1631 return ret; 1340 return ret;
1632} 1341}
1633 1342
@@ -1644,91 +1353,28 @@ static int line_range_add_line(const char *src, unsigned int lineno,
1644 return line_list__add_line(&lr->line_list, lineno); 1353 return line_list__add_line(&lr->line_list, lineno);
1645} 1354}
1646 1355
1647/* Search function declaration lines */ 1356static int line_range_walk_cb(const char *fname, int lineno,
1648static int line_range_funcdecl_cb(Dwarf_Die *sp_die, void *data) 1357 Dwarf_Addr addr __used,
1358 void *data)
1649{ 1359{
1650 struct dwarf_callback_param *param = data; 1360 struct line_finder *lf = data;
1651 struct line_finder *lf = param->data;
1652 const char *src;
1653 int lineno;
1654 1361
1655 src = dwarf_decl_file(sp_die); 1362 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)) 1363 (lf->lno_s > lineno || lf->lno_e < lineno))
1661 return DWARF_CB_OK; 1364 return 0;
1662 1365
1663 param->retval = line_range_add_line(src, lineno, lf->lr); 1366 if (line_range_add_line(fname, lineno, lf->lr) < 0)
1664 if (param->retval < 0) 1367 return -EINVAL;
1665 return DWARF_CB_ABORT;
1666 return DWARF_CB_OK;
1667}
1668 1368
1669static int find_line_range_func_decl_lines(struct line_finder *lf) 1369 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} 1370}
1675 1371
1676/* Find line range from its line number */ 1372/* Find line range from its line number */
1677static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) 1373static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
1678{ 1374{
1679 Dwarf_Lines *lines; 1375 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 1376
1721 /* 1377 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 1378
1733 /* Update status */ 1379 /* Update status */
1734 if (ret >= 0) 1380 if (ret >= 0)
@@ -1758,9 +1404,10 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
1758 struct line_finder *lf = param->data; 1404 struct line_finder *lf = param->data;
1759 struct line_range *lr = lf->lr; 1405 struct line_range *lr = lf->lr;
1760 1406
1761 pr_debug("find (%llx) %s\n", 1407 /* Check declared file */
1762 (unsigned long long)dwarf_dieoffset(sp_die), 1408 if (lr->file && strtailcmp(lr->file, dwarf_decl_file(sp_die)))
1763 dwarf_diename(sp_die)); 1409 return DWARF_CB_OK;
1410
1764 if (dwarf_tag(sp_die) == DW_TAG_subprogram && 1411 if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
1765 die_compare_name(sp_die, lr->function)) { 1412 die_compare_name(sp_die, lr->function)) {
1766 lf->fname = dwarf_decl_file(sp_die); 1413 lf->fname = dwarf_decl_file(sp_die);
@@ -1797,32 +1444,40 @@ static int find_line_range_by_func(struct line_finder *lf)
1797 return param.retval; 1444 return param.retval;
1798} 1445}
1799 1446
1800int find_line_range(int fd, struct line_range *lr) 1447int debuginfo__find_line_range(struct debuginfo *self, struct line_range *lr)
1801{ 1448{
1802 struct line_finder lf = {.lr = lr, .found = 0}; 1449 struct line_finder lf = {.lr = lr, .found = 0};
1803 int ret = 0; 1450 int ret = 0;
1804 Dwarf_Off off = 0, noff; 1451 Dwarf_Off off = 0, noff;
1805 size_t cuhl; 1452 size_t cuhl;
1806 Dwarf_Die *diep; 1453 Dwarf_Die *diep;
1807 Dwarf *dbg = NULL;
1808 Dwfl *dwfl;
1809 Dwarf_Addr bias; /* Currently ignored */
1810 const char *comp_dir; 1454 const char *comp_dir;
1811 1455
1812 dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias); 1456 /* Fastpath: lookup by function name from .debug_pubnames section */
1813 if (!dbg) { 1457 if (lr->function) {
1814 pr_warning("No debug information found in the vmlinux - " 1458 struct pubname_callback_param pubname_param = {
1815 "please rebuild with CONFIG_DEBUG_INFO=y.\n"); 1459 .function = lr->function, .file = lr->file,
1816 return -EBADF; 1460 .cu_die = &lf.cu_die, .sp_die = &lf.sp_die, .found = 0};
1461 struct dwarf_callback_param line_range_param = {
1462 .data = (void *)&lf, .retval = 0};
1463
1464 dwarf_getpubnames(self->dbg, pubname_search_cb,
1465 &pubname_param, 0);
1466 if (pubname_param.found) {
1467 line_range_search_cb(&lf.sp_die, &line_range_param);
1468 if (lf.found)
1469 goto found;
1470 }
1817 } 1471 }
1818 1472
1819 /* Loop on CUs (Compilation Unit) */ 1473 /* Loop on CUs (Compilation Unit) */
1820 while (!lf.found && ret >= 0) { 1474 while (!lf.found && ret >= 0) {
1821 if (dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) != 0) 1475 if (dwarf_nextcu(self->dbg, off, &noff, &cuhl,
1476 NULL, NULL, NULL) != 0)
1822 break; 1477 break;
1823 1478
1824 /* Get the DIE(Debugging Information Entry) of this CU */ 1479 /* Get the DIE(Debugging Information Entry) of this CU */
1825 diep = dwarf_offdie(dbg, off + cuhl, &lf.cu_die); 1480 diep = dwarf_offdie(self->dbg, off + cuhl, &lf.cu_die);
1826 if (!diep) 1481 if (!diep)
1827 continue; 1482 continue;
1828 1483
@@ -1844,6 +1499,7 @@ int find_line_range(int fd, struct line_range *lr)
1844 off = noff; 1499 off = noff;
1845 } 1500 }
1846 1501
1502found:
1847 /* Store comp_dir */ 1503 /* Store comp_dir */
1848 if (lf.found) { 1504 if (lf.found) {
1849 comp_dir = cu_get_comp_dir(&lf.cu_die); 1505 comp_dir = cu_get_comp_dir(&lf.cu_die);
@@ -1855,7 +1511,6 @@ int find_line_range(int fd, struct line_range *lr)
1855 } 1511 }
1856 1512
1857 pr_debug("path: %s\n", lr->path); 1513 pr_debug("path: %s\n", lr->path);
1858 dwfl_end(dwfl);
1859 return (ret < 0) ? ret : lf.found; 1514 return (ret < 0) ? ret : lf.found;
1860} 1515}
1861 1516
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index beaefc3c1223..c478b42a2473 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -16,27 +16,42 @@ static inline int is_c_varname(const char *name)
16} 16}
17 17
18#ifdef DWARF_SUPPORT 18#ifdef DWARF_SUPPORT
19
20#include "dwarf-aux.h"
21
22/* TODO: export debuginfo data structure even if no dwarf support */
23
24/* debug information structure */
25struct debuginfo {
26 Dwarf *dbg;
27 Dwfl *dwfl;
28 Dwarf_Addr bias;
29};
30
31extern struct debuginfo *debuginfo__new(const char *path);
32extern struct debuginfo *debuginfo__new_online_kernel(unsigned long addr);
33extern void debuginfo__delete(struct debuginfo *self);
34
19/* Find probe_trace_events specified by perf_probe_event from debuginfo */ 35/* Find probe_trace_events specified by perf_probe_event from debuginfo */
20extern int find_probe_trace_events(int fd, struct perf_probe_event *pev, 36extern int debuginfo__find_trace_events(struct debuginfo *self,
21 struct probe_trace_event **tevs, 37 struct perf_probe_event *pev,
22 int max_tevs); 38 struct probe_trace_event **tevs,
39 int max_tevs);
23 40
24/* Find a perf_probe_point from debuginfo */ 41/* Find a perf_probe_point from debuginfo */
25extern int find_perf_probe_point(unsigned long addr, 42extern int debuginfo__find_probe_point(struct debuginfo *self,
26 struct perf_probe_point *ppt); 43 unsigned long addr,
44 struct perf_probe_point *ppt);
27 45
28/* Find a line range */ 46/* Find a line range */
29extern int find_line_range(int fd, struct line_range *lr); 47extern int debuginfo__find_line_range(struct debuginfo *self,
48 struct line_range *lr);
30 49
31/* Find available variables */ 50/* Find available variables */
32extern int find_available_vars_at(int fd, struct perf_probe_event *pev, 51extern int debuginfo__find_available_vars_at(struct debuginfo *self,
33 struct variable_list **vls, int max_points, 52 struct perf_probe_event *pev,
34 bool externs); 53 struct variable_list **vls,
35 54 int max_points, bool externs);
36#include <dwarf.h>
37#include <elfutils/libdw.h>
38#include <elfutils/libdwfl.h>
39#include <elfutils/version.h>
40 55
41struct probe_finder { 56struct probe_finder {
42 struct perf_probe_event *pev; /* Target probe event */ 57 struct perf_probe_event *pev; /* Target probe event */
@@ -49,6 +64,7 @@ struct probe_finder {
49 Dwarf_Addr addr; /* Address */ 64 Dwarf_Addr addr; /* Address */
50 const char *fname; /* Real file name */ 65 const char *fname; /* Real file name */
51 Dwarf_Die cu_die; /* Current CU */ 66 Dwarf_Die cu_die; /* Current CU */
67 Dwarf_Die sp_die;
52 struct list_head lcache; /* Line cache for lazy match */ 68 struct list_head lcache; /* Line cache for lazy match */
53 69
54 /* For variable searching */ 70 /* For variable searching */
@@ -83,6 +99,7 @@ struct line_finder {
83 int lno_s; /* Start line number */ 99 int lno_s; /* Start line number */
84 int lno_e; /* End line number */ 100 int lno_e; /* End line number */
85 Dwarf_Die cu_die; /* Current CU */ 101 Dwarf_Die cu_die; /* Current CU */
102 Dwarf_Die sp_die;
86 int found; 103 int found;
87}; 104};
88 105
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
new file mode 100644
index 000000000000..cbc8f215d4b7
--- /dev/null
+++ b/tools/perf/util/python.c
@@ -0,0 +1,1015 @@
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 char pyrf_lost_event__doc[] = PyDoc_STR("perf lost event object.");
191
192static PyMemberDef pyrf_lost_event__members[] = {
193 sample_members
194 member_def(lost_event, id, T_ULONGLONG, "event id"),
195 member_def(lost_event, lost, T_ULONGLONG, "number of lost events"),
196 { .name = NULL, },
197};
198
199static PyObject *pyrf_lost_event__repr(struct pyrf_event *pevent)
200{
201 PyObject *ret;
202 char *s;
203
204 if (asprintf(&s, "{ type: lost, id: %#" PRIx64 ", "
205 "lost: %#" PRIx64 " }",
206 pevent->event.lost.id, pevent->event.lost.lost) < 0) {
207 ret = PyErr_NoMemory();
208 } else {
209 ret = PyString_FromString(s);
210 free(s);
211 }
212 return ret;
213}
214
215static PyTypeObject pyrf_lost_event__type = {
216 PyVarObject_HEAD_INIT(NULL, 0)
217 .tp_name = "perf.lost_event",
218 .tp_basicsize = sizeof(struct pyrf_event),
219 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
220 .tp_doc = pyrf_lost_event__doc,
221 .tp_members = pyrf_lost_event__members,
222 .tp_repr = (reprfunc)pyrf_lost_event__repr,
223};
224
225static char pyrf_read_event__doc[] = PyDoc_STR("perf read event object.");
226
227static PyMemberDef pyrf_read_event__members[] = {
228 sample_members
229 member_def(read_event, pid, T_UINT, "event pid"),
230 member_def(read_event, tid, T_UINT, "event tid"),
231 { .name = NULL, },
232};
233
234static PyObject *pyrf_read_event__repr(struct pyrf_event *pevent)
235{
236 return PyString_FromFormat("{ type: read, pid: %u, tid: %u }",
237 pevent->event.read.pid,
238 pevent->event.read.tid);
239 /*
240 * FIXME: return the array of read values,
241 * making this method useful ;-)
242 */
243}
244
245static PyTypeObject pyrf_read_event__type = {
246 PyVarObject_HEAD_INIT(NULL, 0)
247 .tp_name = "perf.read_event",
248 .tp_basicsize = sizeof(struct pyrf_event),
249 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
250 .tp_doc = pyrf_read_event__doc,
251 .tp_members = pyrf_read_event__members,
252 .tp_repr = (reprfunc)pyrf_read_event__repr,
253};
254
255static char pyrf_sample_event__doc[] = PyDoc_STR("perf sample event object.");
256
257static PyMemberDef pyrf_sample_event__members[] = {
258 sample_members
259 member_def(perf_event_header, type, T_UINT, "event type"),
260 { .name = NULL, },
261};
262
263static PyObject *pyrf_sample_event__repr(struct pyrf_event *pevent)
264{
265 PyObject *ret;
266 char *s;
267
268 if (asprintf(&s, "{ type: sample }") < 0) {
269 ret = PyErr_NoMemory();
270 } else {
271 ret = PyString_FromString(s);
272 free(s);
273 }
274 return ret;
275}
276
277static PyTypeObject pyrf_sample_event__type = {
278 PyVarObject_HEAD_INIT(NULL, 0)
279 .tp_name = "perf.sample_event",
280 .tp_basicsize = sizeof(struct pyrf_event),
281 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
282 .tp_doc = pyrf_sample_event__doc,
283 .tp_members = pyrf_sample_event__members,
284 .tp_repr = (reprfunc)pyrf_sample_event__repr,
285};
286
287static int pyrf_event__setup_types(void)
288{
289 int err;
290 pyrf_mmap_event__type.tp_new =
291 pyrf_task_event__type.tp_new =
292 pyrf_comm_event__type.tp_new =
293 pyrf_lost_event__type.tp_new =
294 pyrf_read_event__type.tp_new =
295 pyrf_sample_event__type.tp_new =
296 pyrf_throttle_event__type.tp_new = PyType_GenericNew;
297 err = PyType_Ready(&pyrf_mmap_event__type);
298 if (err < 0)
299 goto out;
300 err = PyType_Ready(&pyrf_lost_event__type);
301 if (err < 0)
302 goto out;
303 err = PyType_Ready(&pyrf_task_event__type);
304 if (err < 0)
305 goto out;
306 err = PyType_Ready(&pyrf_comm_event__type);
307 if (err < 0)
308 goto out;
309 err = PyType_Ready(&pyrf_throttle_event__type);
310 if (err < 0)
311 goto out;
312 err = PyType_Ready(&pyrf_read_event__type);
313 if (err < 0)
314 goto out;
315 err = PyType_Ready(&pyrf_sample_event__type);
316 if (err < 0)
317 goto out;
318out:
319 return err;
320}
321
322static PyTypeObject *pyrf_event__type[] = {
323 [PERF_RECORD_MMAP] = &pyrf_mmap_event__type,
324 [PERF_RECORD_LOST] = &pyrf_lost_event__type,
325 [PERF_RECORD_COMM] = &pyrf_comm_event__type,
326 [PERF_RECORD_EXIT] = &pyrf_task_event__type,
327 [PERF_RECORD_THROTTLE] = &pyrf_throttle_event__type,
328 [PERF_RECORD_UNTHROTTLE] = &pyrf_throttle_event__type,
329 [PERF_RECORD_FORK] = &pyrf_task_event__type,
330 [PERF_RECORD_READ] = &pyrf_read_event__type,
331 [PERF_RECORD_SAMPLE] = &pyrf_sample_event__type,
332};
333
334static PyObject *pyrf_event__new(union perf_event *event)
335{
336 struct pyrf_event *pevent;
337 PyTypeObject *ptype;
338
339 if (event->header.type < PERF_RECORD_MMAP ||
340 event->header.type > PERF_RECORD_SAMPLE)
341 return NULL;
342
343 ptype = pyrf_event__type[event->header.type];
344 pevent = PyObject_New(struct pyrf_event, ptype);
345 if (pevent != NULL)
346 memcpy(&pevent->event, event, event->header.size);
347 return (PyObject *)pevent;
348}
349
350struct pyrf_cpu_map {
351 PyObject_HEAD
352
353 struct cpu_map *cpus;
354};
355
356static int pyrf_cpu_map__init(struct pyrf_cpu_map *pcpus,
357 PyObject *args, PyObject *kwargs)
358{
359 static char *kwlist[] = { "cpustr", NULL };
360 char *cpustr = NULL;
361
362 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|s",
363 kwlist, &cpustr))
364 return -1;
365
366 pcpus->cpus = cpu_map__new(cpustr);
367 if (pcpus->cpus == NULL)
368 return -1;
369 return 0;
370}
371
372static void pyrf_cpu_map__delete(struct pyrf_cpu_map *pcpus)
373{
374 cpu_map__delete(pcpus->cpus);
375 pcpus->ob_type->tp_free((PyObject*)pcpus);
376}
377
378static Py_ssize_t pyrf_cpu_map__length(PyObject *obj)
379{
380 struct pyrf_cpu_map *pcpus = (void *)obj;
381
382 return pcpus->cpus->nr;
383}
384
385static PyObject *pyrf_cpu_map__item(PyObject *obj, Py_ssize_t i)
386{
387 struct pyrf_cpu_map *pcpus = (void *)obj;
388
389 if (i >= pcpus->cpus->nr)
390 return NULL;
391
392 return Py_BuildValue("i", pcpus->cpus->map[i]);
393}
394
395static PySequenceMethods pyrf_cpu_map__sequence_methods = {
396 .sq_length = pyrf_cpu_map__length,
397 .sq_item = pyrf_cpu_map__item,
398};
399
400static char pyrf_cpu_map__doc[] = PyDoc_STR("cpu map object.");
401
402static PyTypeObject pyrf_cpu_map__type = {
403 PyVarObject_HEAD_INIT(NULL, 0)
404 .tp_name = "perf.cpu_map",
405 .tp_basicsize = sizeof(struct pyrf_cpu_map),
406 .tp_dealloc = (destructor)pyrf_cpu_map__delete,
407 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
408 .tp_doc = pyrf_cpu_map__doc,
409 .tp_as_sequence = &pyrf_cpu_map__sequence_methods,
410 .tp_init = (initproc)pyrf_cpu_map__init,
411};
412
413static int pyrf_cpu_map__setup_types(void)
414{
415 pyrf_cpu_map__type.tp_new = PyType_GenericNew;
416 return PyType_Ready(&pyrf_cpu_map__type);
417}
418
419struct pyrf_thread_map {
420 PyObject_HEAD
421
422 struct thread_map *threads;
423};
424
425static int pyrf_thread_map__init(struct pyrf_thread_map *pthreads,
426 PyObject *args, PyObject *kwargs)
427{
428 static char *kwlist[] = { "pid", "tid", NULL };
429 int pid = -1, tid = -1;
430
431 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii",
432 kwlist, &pid, &tid))
433 return -1;
434
435 pthreads->threads = thread_map__new(pid, tid);
436 if (pthreads->threads == NULL)
437 return -1;
438 return 0;
439}
440
441static void pyrf_thread_map__delete(struct pyrf_thread_map *pthreads)
442{
443 thread_map__delete(pthreads->threads);
444 pthreads->ob_type->tp_free((PyObject*)pthreads);
445}
446
447static Py_ssize_t pyrf_thread_map__length(PyObject *obj)
448{
449 struct pyrf_thread_map *pthreads = (void *)obj;
450
451 return pthreads->threads->nr;
452}
453
454static PyObject *pyrf_thread_map__item(PyObject *obj, Py_ssize_t i)
455{
456 struct pyrf_thread_map *pthreads = (void *)obj;
457
458 if (i >= pthreads->threads->nr)
459 return NULL;
460
461 return Py_BuildValue("i", pthreads->threads->map[i]);
462}
463
464static PySequenceMethods pyrf_thread_map__sequence_methods = {
465 .sq_length = pyrf_thread_map__length,
466 .sq_item = pyrf_thread_map__item,
467};
468
469static char pyrf_thread_map__doc[] = PyDoc_STR("thread map object.");
470
471static PyTypeObject pyrf_thread_map__type = {
472 PyVarObject_HEAD_INIT(NULL, 0)
473 .tp_name = "perf.thread_map",
474 .tp_basicsize = sizeof(struct pyrf_thread_map),
475 .tp_dealloc = (destructor)pyrf_thread_map__delete,
476 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
477 .tp_doc = pyrf_thread_map__doc,
478 .tp_as_sequence = &pyrf_thread_map__sequence_methods,
479 .tp_init = (initproc)pyrf_thread_map__init,
480};
481
482static int pyrf_thread_map__setup_types(void)
483{
484 pyrf_thread_map__type.tp_new = PyType_GenericNew;
485 return PyType_Ready(&pyrf_thread_map__type);
486}
487
488struct pyrf_evsel {
489 PyObject_HEAD
490
491 struct perf_evsel evsel;
492};
493
494static int pyrf_evsel__init(struct pyrf_evsel *pevsel,
495 PyObject *args, PyObject *kwargs)
496{
497 struct perf_event_attr attr = {
498 .type = PERF_TYPE_HARDWARE,
499 .config = PERF_COUNT_HW_CPU_CYCLES,
500 .sample_type = PERF_SAMPLE_PERIOD | PERF_SAMPLE_TID,
501 };
502 static char *kwlist[] = {
503 "type",
504 "config",
505 "sample_freq",
506 "sample_period",
507 "sample_type",
508 "read_format",
509 "disabled",
510 "inherit",
511 "pinned",
512 "exclusive",
513 "exclude_user",
514 "exclude_kernel",
515 "exclude_hv",
516 "exclude_idle",
517 "mmap",
518 "comm",
519 "freq",
520 "inherit_stat",
521 "enable_on_exec",
522 "task",
523 "watermark",
524 "precise_ip",
525 "mmap_data",
526 "sample_id_all",
527 "wakeup_events",
528 "bp_type",
529 "bp_addr",
530 "bp_len",
531 NULL
532 };
533 u64 sample_period = 0;
534 u32 disabled = 0,
535 inherit = 0,
536 pinned = 0,
537 exclusive = 0,
538 exclude_user = 0,
539 exclude_kernel = 0,
540 exclude_hv = 0,
541 exclude_idle = 0,
542 mmap = 0,
543 comm = 0,
544 freq = 1,
545 inherit_stat = 0,
546 enable_on_exec = 0,
547 task = 0,
548 watermark = 0,
549 precise_ip = 0,
550 mmap_data = 0,
551 sample_id_all = 1;
552 int idx = 0;
553
554 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
555 "|iKiKKiiiiiiiiiiiiiiiiiiiiiKK", kwlist,
556 &attr.type, &attr.config, &attr.sample_freq,
557 &sample_period, &attr.sample_type,
558 &attr.read_format, &disabled, &inherit,
559 &pinned, &exclusive, &exclude_user,
560 &exclude_kernel, &exclude_hv, &exclude_idle,
561 &mmap, &comm, &freq, &inherit_stat,
562 &enable_on_exec, &task, &watermark,
563 &precise_ip, &mmap_data, &sample_id_all,
564 &attr.wakeup_events, &attr.bp_type,
565 &attr.bp_addr, &attr.bp_len, &idx))
566 return -1;
567
568 /* union... */
569 if (sample_period != 0) {
570 if (attr.sample_freq != 0)
571 return -1; /* FIXME: throw right exception */
572 attr.sample_period = sample_period;
573 }
574
575 /* Bitfields */
576 attr.disabled = disabled;
577 attr.inherit = inherit;
578 attr.pinned = pinned;
579 attr.exclusive = exclusive;
580 attr.exclude_user = exclude_user;
581 attr.exclude_kernel = exclude_kernel;
582 attr.exclude_hv = exclude_hv;
583 attr.exclude_idle = exclude_idle;
584 attr.mmap = mmap;
585 attr.comm = comm;
586 attr.freq = freq;
587 attr.inherit_stat = inherit_stat;
588 attr.enable_on_exec = enable_on_exec;
589 attr.task = task;
590 attr.watermark = watermark;
591 attr.precise_ip = precise_ip;
592 attr.mmap_data = mmap_data;
593 attr.sample_id_all = sample_id_all;
594
595 perf_evsel__init(&pevsel->evsel, &attr, idx);
596 return 0;
597}
598
599static void pyrf_evsel__delete(struct pyrf_evsel *pevsel)
600{
601 perf_evsel__exit(&pevsel->evsel);
602 pevsel->ob_type->tp_free((PyObject*)pevsel);
603}
604
605static PyObject *pyrf_evsel__open(struct pyrf_evsel *pevsel,
606 PyObject *args, PyObject *kwargs)
607{
608 struct perf_evsel *evsel = &pevsel->evsel;
609 struct cpu_map *cpus = NULL;
610 struct thread_map *threads = NULL;
611 PyObject *pcpus = NULL, *pthreads = NULL;
612 int group = 0, inherit = 0;
613 static char *kwlist[] = { "cpus", "threads", "group", "inherit", NULL };
614
615 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOii", kwlist,
616 &pcpus, &pthreads, &group, &inherit))
617 return NULL;
618
619 if (pthreads != NULL)
620 threads = ((struct pyrf_thread_map *)pthreads)->threads;
621
622 if (pcpus != NULL)
623 cpus = ((struct pyrf_cpu_map *)pcpus)->cpus;
624
625 evsel->attr.inherit = inherit;
626 if (perf_evsel__open(evsel, cpus, threads, group) < 0) {
627 PyErr_SetFromErrno(PyExc_OSError);
628 return NULL;
629 }
630
631 Py_INCREF(Py_None);
632 return Py_None;
633}
634
635static PyMethodDef pyrf_evsel__methods[] = {
636 {
637 .ml_name = "open",
638 .ml_meth = (PyCFunction)pyrf_evsel__open,
639 .ml_flags = METH_VARARGS | METH_KEYWORDS,
640 .ml_doc = PyDoc_STR("open the event selector file descriptor table.")
641 },
642 { .ml_name = NULL, }
643};
644
645static char pyrf_evsel__doc[] = PyDoc_STR("perf event selector list object.");
646
647static PyTypeObject pyrf_evsel__type = {
648 PyVarObject_HEAD_INIT(NULL, 0)
649 .tp_name = "perf.evsel",
650 .tp_basicsize = sizeof(struct pyrf_evsel),
651 .tp_dealloc = (destructor)pyrf_evsel__delete,
652 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
653 .tp_doc = pyrf_evsel__doc,
654 .tp_methods = pyrf_evsel__methods,
655 .tp_init = (initproc)pyrf_evsel__init,
656};
657
658static int pyrf_evsel__setup_types(void)
659{
660 pyrf_evsel__type.tp_new = PyType_GenericNew;
661 return PyType_Ready(&pyrf_evsel__type);
662}
663
664struct pyrf_evlist {
665 PyObject_HEAD
666
667 struct perf_evlist evlist;
668};
669
670static int pyrf_evlist__init(struct pyrf_evlist *pevlist,
671 PyObject *args, PyObject *kwargs __used)
672{
673 PyObject *pcpus = NULL, *pthreads = NULL;
674 struct cpu_map *cpus;
675 struct thread_map *threads;
676
677 if (!PyArg_ParseTuple(args, "OO", &pcpus, &pthreads))
678 return -1;
679
680 threads = ((struct pyrf_thread_map *)pthreads)->threads;
681 cpus = ((struct pyrf_cpu_map *)pcpus)->cpus;
682 perf_evlist__init(&pevlist->evlist, cpus, threads);
683 return 0;
684}
685
686static void pyrf_evlist__delete(struct pyrf_evlist *pevlist)
687{
688 perf_evlist__exit(&pevlist->evlist);
689 pevlist->ob_type->tp_free((PyObject*)pevlist);
690}
691
692static PyObject *pyrf_evlist__mmap(struct pyrf_evlist *pevlist,
693 PyObject *args, PyObject *kwargs)
694{
695 struct perf_evlist *evlist = &pevlist->evlist;
696 static char *kwlist[] = { "pages", "overwrite", NULL };
697 int pages = 128, overwrite = false;
698
699 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii", kwlist,
700 &pages, &overwrite))
701 return NULL;
702
703 if (perf_evlist__mmap(evlist, pages, overwrite) < 0) {
704 PyErr_SetFromErrno(PyExc_OSError);
705 return NULL;
706 }
707
708 Py_INCREF(Py_None);
709 return Py_None;
710}
711
712static PyObject *pyrf_evlist__poll(struct pyrf_evlist *pevlist,
713 PyObject *args, PyObject *kwargs)
714{
715 struct perf_evlist *evlist = &pevlist->evlist;
716 static char *kwlist[] = { "timeout", NULL };
717 int timeout = -1, n;
718
719 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i", kwlist, &timeout))
720 return NULL;
721
722 n = poll(evlist->pollfd, evlist->nr_fds, timeout);
723 if (n < 0) {
724 PyErr_SetFromErrno(PyExc_OSError);
725 return NULL;
726 }
727
728 return Py_BuildValue("i", n);
729}
730
731static PyObject *pyrf_evlist__get_pollfd(struct pyrf_evlist *pevlist,
732 PyObject *args __used, PyObject *kwargs __used)
733{
734 struct perf_evlist *evlist = &pevlist->evlist;
735 PyObject *list = PyList_New(0);
736 int i;
737
738 for (i = 0; i < evlist->nr_fds; ++i) {
739 PyObject *file;
740 FILE *fp = fdopen(evlist->pollfd[i].fd, "r");
741
742 if (fp == NULL)
743 goto free_list;
744
745 file = PyFile_FromFile(fp, "perf", "r", NULL);
746 if (file == NULL)
747 goto free_list;
748
749 if (PyList_Append(list, file) != 0) {
750 Py_DECREF(file);
751 goto free_list;
752 }
753
754 Py_DECREF(file);
755 }
756
757 return list;
758free_list:
759 return PyErr_NoMemory();
760}
761
762
763static PyObject *pyrf_evlist__add(struct pyrf_evlist *pevlist,
764 PyObject *args, PyObject *kwargs __used)
765{
766 struct perf_evlist *evlist = &pevlist->evlist;
767 PyObject *pevsel;
768 struct perf_evsel *evsel;
769
770 if (!PyArg_ParseTuple(args, "O", &pevsel))
771 return NULL;
772
773 Py_INCREF(pevsel);
774 evsel = &((struct pyrf_evsel *)pevsel)->evsel;
775 evsel->idx = evlist->nr_entries;
776 perf_evlist__add(evlist, evsel);
777
778 return Py_BuildValue("i", evlist->nr_entries);
779}
780
781static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
782 PyObject *args, PyObject *kwargs)
783{
784 struct perf_evlist *evlist = &pevlist->evlist;
785 union perf_event *event;
786 int sample_id_all = 1, cpu;
787 static char *kwlist[] = { "cpu", "sample_id_all", NULL };
788 int err;
789
790 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|i", kwlist,
791 &cpu, &sample_id_all))
792 return NULL;
793
794 event = perf_evlist__mmap_read(evlist, cpu);
795 if (event != NULL) {
796 struct perf_evsel *first;
797 PyObject *pyevent = pyrf_event__new(event);
798 struct pyrf_event *pevent = (struct pyrf_event *)pyevent;
799
800 if (pyevent == NULL)
801 return PyErr_NoMemory();
802
803 first = list_entry(evlist->entries.next, struct perf_evsel, node);
804 err = perf_event__parse_sample(event, first->attr.sample_type,
805 perf_evsel__sample_size(first),
806 sample_id_all, &pevent->sample);
807 if (err)
808 return PyErr_Format(PyExc_OSError,
809 "perf: can't parse sample, err=%d", err);
810 return pyevent;
811 }
812
813 Py_INCREF(Py_None);
814 return Py_None;
815}
816
817static PyMethodDef pyrf_evlist__methods[] = {
818 {
819 .ml_name = "mmap",
820 .ml_meth = (PyCFunction)pyrf_evlist__mmap,
821 .ml_flags = METH_VARARGS | METH_KEYWORDS,
822 .ml_doc = PyDoc_STR("mmap the file descriptor table.")
823 },
824 {
825 .ml_name = "poll",
826 .ml_meth = (PyCFunction)pyrf_evlist__poll,
827 .ml_flags = METH_VARARGS | METH_KEYWORDS,
828 .ml_doc = PyDoc_STR("poll the file descriptor table.")
829 },
830 {
831 .ml_name = "get_pollfd",
832 .ml_meth = (PyCFunction)pyrf_evlist__get_pollfd,
833 .ml_flags = METH_VARARGS | METH_KEYWORDS,
834 .ml_doc = PyDoc_STR("get the poll file descriptor table.")
835 },
836 {
837 .ml_name = "add",
838 .ml_meth = (PyCFunction)pyrf_evlist__add,
839 .ml_flags = METH_VARARGS | METH_KEYWORDS,
840 .ml_doc = PyDoc_STR("adds an event selector to the list.")
841 },
842 {
843 .ml_name = "read_on_cpu",
844 .ml_meth = (PyCFunction)pyrf_evlist__read_on_cpu,
845 .ml_flags = METH_VARARGS | METH_KEYWORDS,
846 .ml_doc = PyDoc_STR("reads an event.")
847 },
848 { .ml_name = NULL, }
849};
850
851static Py_ssize_t pyrf_evlist__length(PyObject *obj)
852{
853 struct pyrf_evlist *pevlist = (void *)obj;
854
855 return pevlist->evlist.nr_entries;
856}
857
858static PyObject *pyrf_evlist__item(PyObject *obj, Py_ssize_t i)
859{
860 struct pyrf_evlist *pevlist = (void *)obj;
861 struct perf_evsel *pos;
862
863 if (i >= pevlist->evlist.nr_entries)
864 return NULL;
865
866 list_for_each_entry(pos, &pevlist->evlist.entries, node)
867 if (i-- == 0)
868 break;
869
870 return Py_BuildValue("O", container_of(pos, struct pyrf_evsel, evsel));
871}
872
873static PySequenceMethods pyrf_evlist__sequence_methods = {
874 .sq_length = pyrf_evlist__length,
875 .sq_item = pyrf_evlist__item,
876};
877
878static char pyrf_evlist__doc[] = PyDoc_STR("perf event selector list object.");
879
880static PyTypeObject pyrf_evlist__type = {
881 PyVarObject_HEAD_INIT(NULL, 0)
882 .tp_name = "perf.evlist",
883 .tp_basicsize = sizeof(struct pyrf_evlist),
884 .tp_dealloc = (destructor)pyrf_evlist__delete,
885 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
886 .tp_as_sequence = &pyrf_evlist__sequence_methods,
887 .tp_doc = pyrf_evlist__doc,
888 .tp_methods = pyrf_evlist__methods,
889 .tp_init = (initproc)pyrf_evlist__init,
890};
891
892static int pyrf_evlist__setup_types(void)
893{
894 pyrf_evlist__type.tp_new = PyType_GenericNew;
895 return PyType_Ready(&pyrf_evlist__type);
896}
897
898static struct {
899 const char *name;
900 int value;
901} perf__constants[] = {
902 { "TYPE_HARDWARE", PERF_TYPE_HARDWARE },
903 { "TYPE_SOFTWARE", PERF_TYPE_SOFTWARE },
904 { "TYPE_TRACEPOINT", PERF_TYPE_TRACEPOINT },
905 { "TYPE_HW_CACHE", PERF_TYPE_HW_CACHE },
906 { "TYPE_RAW", PERF_TYPE_RAW },
907 { "TYPE_BREAKPOINT", PERF_TYPE_BREAKPOINT },
908
909 { "COUNT_HW_CPU_CYCLES", PERF_COUNT_HW_CPU_CYCLES },
910 { "COUNT_HW_INSTRUCTIONS", PERF_COUNT_HW_INSTRUCTIONS },
911 { "COUNT_HW_CACHE_REFERENCES", PERF_COUNT_HW_CACHE_REFERENCES },
912 { "COUNT_HW_CACHE_MISSES", PERF_COUNT_HW_CACHE_MISSES },
913 { "COUNT_HW_BRANCH_INSTRUCTIONS", PERF_COUNT_HW_BRANCH_INSTRUCTIONS },
914 { "COUNT_HW_BRANCH_MISSES", PERF_COUNT_HW_BRANCH_MISSES },
915 { "COUNT_HW_BUS_CYCLES", PERF_COUNT_HW_BUS_CYCLES },
916 { "COUNT_HW_CACHE_L1D", PERF_COUNT_HW_CACHE_L1D },
917 { "COUNT_HW_CACHE_L1I", PERF_COUNT_HW_CACHE_L1I },
918 { "COUNT_HW_CACHE_LL", PERF_COUNT_HW_CACHE_LL },
919 { "COUNT_HW_CACHE_DTLB", PERF_COUNT_HW_CACHE_DTLB },
920 { "COUNT_HW_CACHE_ITLB", PERF_COUNT_HW_CACHE_ITLB },
921 { "COUNT_HW_CACHE_BPU", PERF_COUNT_HW_CACHE_BPU },
922 { "COUNT_HW_CACHE_OP_READ", PERF_COUNT_HW_CACHE_OP_READ },
923 { "COUNT_HW_CACHE_OP_WRITE", PERF_COUNT_HW_CACHE_OP_WRITE },
924 { "COUNT_HW_CACHE_OP_PREFETCH", PERF_COUNT_HW_CACHE_OP_PREFETCH },
925 { "COUNT_HW_CACHE_RESULT_ACCESS", PERF_COUNT_HW_CACHE_RESULT_ACCESS },
926 { "COUNT_HW_CACHE_RESULT_MISS", PERF_COUNT_HW_CACHE_RESULT_MISS },
927
928 { "COUNT_HW_STALLED_CYCLES_FRONTEND", PERF_COUNT_HW_STALLED_CYCLES_FRONTEND },
929 { "COUNT_HW_STALLED_CYCLES_BACKEND", PERF_COUNT_HW_STALLED_CYCLES_BACKEND },
930
931 { "COUNT_SW_CPU_CLOCK", PERF_COUNT_SW_CPU_CLOCK },
932 { "COUNT_SW_TASK_CLOCK", PERF_COUNT_SW_TASK_CLOCK },
933 { "COUNT_SW_PAGE_FAULTS", PERF_COUNT_SW_PAGE_FAULTS },
934 { "COUNT_SW_CONTEXT_SWITCHES", PERF_COUNT_SW_CONTEXT_SWITCHES },
935 { "COUNT_SW_CPU_MIGRATIONS", PERF_COUNT_SW_CPU_MIGRATIONS },
936 { "COUNT_SW_PAGE_FAULTS_MIN", PERF_COUNT_SW_PAGE_FAULTS_MIN },
937 { "COUNT_SW_PAGE_FAULTS_MAJ", PERF_COUNT_SW_PAGE_FAULTS_MAJ },
938 { "COUNT_SW_ALIGNMENT_FAULTS", PERF_COUNT_SW_ALIGNMENT_FAULTS },
939 { "COUNT_SW_EMULATION_FAULTS", PERF_COUNT_SW_EMULATION_FAULTS },
940
941 { "SAMPLE_IP", PERF_SAMPLE_IP },
942 { "SAMPLE_TID", PERF_SAMPLE_TID },
943 { "SAMPLE_TIME", PERF_SAMPLE_TIME },
944 { "SAMPLE_ADDR", PERF_SAMPLE_ADDR },
945 { "SAMPLE_READ", PERF_SAMPLE_READ },
946 { "SAMPLE_CALLCHAIN", PERF_SAMPLE_CALLCHAIN },
947 { "SAMPLE_ID", PERF_SAMPLE_ID },
948 { "SAMPLE_CPU", PERF_SAMPLE_CPU },
949 { "SAMPLE_PERIOD", PERF_SAMPLE_PERIOD },
950 { "SAMPLE_STREAM_ID", PERF_SAMPLE_STREAM_ID },
951 { "SAMPLE_RAW", PERF_SAMPLE_RAW },
952
953 { "FORMAT_TOTAL_TIME_ENABLED", PERF_FORMAT_TOTAL_TIME_ENABLED },
954 { "FORMAT_TOTAL_TIME_RUNNING", PERF_FORMAT_TOTAL_TIME_RUNNING },
955 { "FORMAT_ID", PERF_FORMAT_ID },
956 { "FORMAT_GROUP", PERF_FORMAT_GROUP },
957
958 { "RECORD_MMAP", PERF_RECORD_MMAP },
959 { "RECORD_LOST", PERF_RECORD_LOST },
960 { "RECORD_COMM", PERF_RECORD_COMM },
961 { "RECORD_EXIT", PERF_RECORD_EXIT },
962 { "RECORD_THROTTLE", PERF_RECORD_THROTTLE },
963 { "RECORD_UNTHROTTLE", PERF_RECORD_UNTHROTTLE },
964 { "RECORD_FORK", PERF_RECORD_FORK },
965 { "RECORD_READ", PERF_RECORD_READ },
966 { "RECORD_SAMPLE", PERF_RECORD_SAMPLE },
967 { .name = NULL, },
968};
969
970static PyMethodDef perf__methods[] = {
971 { .ml_name = NULL, }
972};
973
974PyMODINIT_FUNC initperf(void)
975{
976 PyObject *obj;
977 int i;
978 PyObject *dict, *module = Py_InitModule("perf", perf__methods);
979
980 if (module == NULL ||
981 pyrf_event__setup_types() < 0 ||
982 pyrf_evlist__setup_types() < 0 ||
983 pyrf_evsel__setup_types() < 0 ||
984 pyrf_thread_map__setup_types() < 0 ||
985 pyrf_cpu_map__setup_types() < 0)
986 return;
987
988 Py_INCREF(&pyrf_evlist__type);
989 PyModule_AddObject(module, "evlist", (PyObject*)&pyrf_evlist__type);
990
991 Py_INCREF(&pyrf_evsel__type);
992 PyModule_AddObject(module, "evsel", (PyObject*)&pyrf_evsel__type);
993
994 Py_INCREF(&pyrf_thread_map__type);
995 PyModule_AddObject(module, "thread_map", (PyObject*)&pyrf_thread_map__type);
996
997 Py_INCREF(&pyrf_cpu_map__type);
998 PyModule_AddObject(module, "cpu_map", (PyObject*)&pyrf_cpu_map__type);
999
1000 dict = PyModule_GetDict(module);
1001 if (dict == NULL)
1002 goto error;
1003
1004 for (i = 0; perf__constants[i].name != NULL; i++) {
1005 obj = PyInt_FromLong(perf__constants[i].value);
1006 if (obj == NULL)
1007 goto error;
1008 PyDict_SetItemString(dict, perf__constants[i].name, obj);
1009 Py_DECREF(obj);
1010 }
1011
1012error:
1013 if (PyErr_Occurred())
1014 PyErr_SetString(PyExc_ImportError, "perf: Init failed!");
1015}
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index 93680818e244..74350ffb57fe 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -245,9 +245,11 @@ static inline struct event *find_cache_event(int type)
245 return event; 245 return event;
246} 246}
247 247
248static void perl_process_event(int cpu, void *data, 248static void perl_process_event(union perf_event *pevent __unused,
249 int size __unused, 249 struct perf_sample *sample,
250 unsigned long long nsecs, char *comm) 250 struct perf_evsel *evsel,
251 struct perf_session *session __unused,
252 struct thread *thread)
251{ 253{
252 struct format_field *field; 254 struct format_field *field;
253 static char handler[256]; 255 static char handler[256];
@@ -256,6 +258,10 @@ static void perl_process_event(int cpu, void *data,
256 struct event *event; 258 struct event *event;
257 int type; 259 int type;
258 int pid; 260 int pid;
261 int cpu = sample->cpu;
262 void *data = sample->raw_data;
263 unsigned long long nsecs = sample->time;
264 char *comm = thread->comm;
259 265
260 dSP; 266 dSP;
261 267
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index c6d99334bdfa..6ccf70e8d8f2 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -204,9 +204,11 @@ static inline struct event *find_cache_event(int type)
204 return event; 204 return event;
205} 205}
206 206
207static void python_process_event(int cpu, void *data, 207static void python_process_event(union perf_event *pevent __unused,
208 int size __unused, 208 struct perf_sample *sample,
209 unsigned long long nsecs, char *comm) 209 struct perf_evsel *evsel __unused,
210 struct perf_session *session __unused,
211 struct thread *thread)
210{ 212{
211 PyObject *handler, *retval, *context, *t, *obj, *dict = NULL; 213 PyObject *handler, *retval, *context, *t, *obj, *dict = NULL;
212 static char handler_name[256]; 214 static char handler_name[256];
@@ -217,6 +219,10 @@ static void python_process_event(int cpu, void *data,
217 unsigned n = 0; 219 unsigned n = 0;
218 int type; 220 int type;
219 int pid; 221 int pid;
222 int cpu = sample->cpu;
223 void *data = sample->raw_data;
224 unsigned long long nsecs = sample->time;
225 char *comm = thread->comm;
220 226
221 t = PyTuple_New(MAX_FIELDS); 227 t = PyTuple_New(MAX_FIELDS);
222 if (!t) 228 if (!t)
@@ -248,8 +254,7 @@ static void python_process_event(int cpu, void *data,
248 context = PyCObject_FromVoidPtr(scripting_context, NULL); 254 context = PyCObject_FromVoidPtr(scripting_context, NULL);
249 255
250 PyTuple_SetItem(t, n++, PyString_FromString(handler_name)); 256 PyTuple_SetItem(t, n++, PyString_FromString(handler_name));
251 PyTuple_SetItem(t, n++, 257 PyTuple_SetItem(t, n++, context);
252 PyCObject_FromVoidPtr(scripting_context, NULL));
253 258
254 if (handler) { 259 if (handler) {
255 PyTuple_SetItem(t, n++, PyInt_FromLong(cpu)); 260 PyTuple_SetItem(t, n++, PyInt_FromLong(cpu));
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 105f00bfd555..72458d9da5b1 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -7,9 +7,12 @@
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"
15#include "cpumap.h"
13 16
14static int perf_session__open(struct perf_session *self, bool force) 17static int perf_session__open(struct perf_session *self, bool force)
15{ 18{
@@ -19,7 +22,7 @@ static int perf_session__open(struct perf_session *self, bool force)
19 self->fd_pipe = true; 22 self->fd_pipe = true;
20 self->fd = STDIN_FILENO; 23 self->fd = STDIN_FILENO;
21 24
22 if (perf_header__read(self, self->fd) < 0) 25 if (perf_session__read_header(self, self->fd) < 0)
23 pr_err("incompatible file format"); 26 pr_err("incompatible file format");
24 27
25 return 0; 28 return 0;
@@ -51,11 +54,21 @@ static int perf_session__open(struct perf_session *self, bool force)
51 goto out_close; 54 goto out_close;
52 } 55 }
53 56
54 if (perf_header__read(self, self->fd) < 0) { 57 if (perf_session__read_header(self, self->fd) < 0) {
55 pr_err("incompatible file format"); 58 pr_err("incompatible file format");
56 goto out_close; 59 goto out_close;
57 } 60 }
58 61
62 if (!perf_evlist__valid_sample_type(self->evlist)) {
63 pr_err("non matching sample_type");
64 goto out_close;
65 }
66
67 if (!perf_evlist__valid_sample_id_all(self->evlist)) {
68 pr_err("non matching sample_id_all");
69 goto out_close;
70 }
71
59 self->size = input_stat.st_size; 72 self->size = input_stat.st_size;
60 return 0; 73 return 0;
61 74
@@ -67,7 +80,7 @@ out_close:
67 80
68static void perf_session__id_header_size(struct perf_session *session) 81static void perf_session__id_header_size(struct perf_session *session)
69{ 82{
70 struct sample_data *data; 83 struct perf_sample *data;
71 u64 sample_type = session->sample_type; 84 u64 sample_type = session->sample_type;
72 u16 size = 0; 85 u16 size = 0;
73 86
@@ -92,21 +105,11 @@ out:
92 session->id_hdr_size = size; 105 session->id_hdr_size = size;
93} 106}
94 107
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) 108void perf_session__update_sample_type(struct perf_session *self)
107{ 109{
108 self->sample_type = perf_header__sample_type(&self->header); 110 self->sample_type = perf_evlist__sample_type(self->evlist);
109 self->sample_id_all = perf_header__sample_id_all(&self->header); 111 self->sample_size = __perf_evsel__sample_size(self->sample_type);
112 self->sample_id_all = perf_evlist__sample_id_all(self->evlist);
110 perf_session__id_header_size(self); 113 perf_session__id_header_size(self);
111} 114}
112 115
@@ -135,13 +138,9 @@ struct perf_session *perf_session__new(const char *filename, int mode,
135 if (self == NULL) 138 if (self == NULL)
136 goto out; 139 goto out;
137 140
138 if (perf_header__init(&self->header) < 0)
139 goto out_free;
140
141 memcpy(self->filename, filename, len); 141 memcpy(self->filename, filename, len);
142 self->threads = RB_ROOT; 142 self->threads = RB_ROOT;
143 INIT_LIST_HEAD(&self->dead_threads); 143 INIT_LIST_HEAD(&self->dead_threads);
144 self->hists_tree = RB_ROOT;
145 self->last_match = NULL; 144 self->last_match = NULL;
146 /* 145 /*
147 * On 64bit we can mmap the data file in one go. No need for tiny mmap 146 * On 64bit we can mmap the data file in one go. No need for tiny mmap
@@ -162,17 +161,16 @@ struct perf_session *perf_session__new(const char *filename, int mode,
162 if (mode == O_RDONLY) { 161 if (mode == O_RDONLY) {
163 if (perf_session__open(self, force) < 0) 162 if (perf_session__open(self, force) < 0)
164 goto out_delete; 163 goto out_delete;
164 perf_session__update_sample_type(self);
165 } else if (mode == O_WRONLY) { 165 } else if (mode == O_WRONLY) {
166 /* 166 /*
167 * In O_RDONLY mode this will be performed when reading the 167 * In O_RDONLY mode this will be performed when reading the
168 * kernel MMAP event, in event__process_mmap(). 168 * kernel MMAP event, in perf_event__process_mmap().
169 */ 169 */
170 if (perf_session__create_kernel_maps(self) < 0) 170 if (perf_session__create_kernel_maps(self) < 0)
171 goto out_delete; 171 goto out_delete;
172 } 172 }
173 173
174 perf_session__update_sample_type(self);
175
176 if (ops && ops->ordering_requires_timestamps && 174 if (ops && ops->ordering_requires_timestamps &&
177 ops->ordered_samples && !self->sample_id_all) { 175 ops->ordered_samples && !self->sample_id_all) {
178 dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n"); 176 dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n");
@@ -181,9 +179,6 @@ struct perf_session *perf_session__new(const char *filename, int mode,
181 179
182out: 180out:
183 return self; 181 return self;
184out_free:
185 free(self);
186 return NULL;
187out_delete: 182out_delete:
188 perf_session__delete(self); 183 perf_session__delete(self);
189 return NULL; 184 return NULL;
@@ -214,7 +209,6 @@ static void perf_session__delete_threads(struct perf_session *self)
214 209
215void perf_session__delete(struct perf_session *self) 210void perf_session__delete(struct perf_session *self)
216{ 211{
217 perf_header__exit(&self->header);
218 perf_session__destroy_kernel_maps(self); 212 perf_session__destroy_kernel_maps(self);
219 perf_session__delete_dead_threads(self); 213 perf_session__delete_dead_threads(self);
220 perf_session__delete_threads(self); 214 perf_session__delete_threads(self);
@@ -242,22 +236,26 @@ static bool symbol__match_parent_regex(struct symbol *sym)
242 return 0; 236 return 0;
243} 237}
244 238
245struct map_symbol *perf_session__resolve_callchain(struct perf_session *self, 239int perf_session__resolve_callchain(struct perf_session *self,
246 struct thread *thread, 240 struct thread *thread,
247 struct ip_callchain *chain, 241 struct ip_callchain *chain,
248 struct symbol **parent) 242 struct symbol **parent)
249{ 243{
250 u8 cpumode = PERF_RECORD_MISC_USER; 244 u8 cpumode = PERF_RECORD_MISC_USER;
251 unsigned int i; 245 unsigned int i;
252 struct map_symbol *syms = calloc(chain->nr, sizeof(*syms)); 246 int err;
253 247
254 if (!syms) 248 callchain_cursor_reset(&self->callchain_cursor);
255 return NULL;
256 249
257 for (i = 0; i < chain->nr; i++) { 250 for (i = 0; i < chain->nr; i++) {
258 u64 ip = chain->ips[i]; 251 u64 ip;
259 struct addr_location al; 252 struct addr_location al;
260 253
254 if (callchain_param.order == ORDER_CALLEE)
255 ip = chain->ips[i];
256 else
257 ip = chain->ips[chain->nr - i - 1];
258
261 if (ip >= PERF_CONTEXT_MAX) { 259 if (ip >= PERF_CONTEXT_MAX) {
262 switch (ip) { 260 switch (ip) {
263 case PERF_CONTEXT_HV: 261 case PERF_CONTEXT_HV:
@@ -281,30 +279,42 @@ struct map_symbol *perf_session__resolve_callchain(struct perf_session *self,
281 *parent = al.sym; 279 *parent = al.sym;
282 if (!symbol_conf.use_callchain) 280 if (!symbol_conf.use_callchain)
283 break; 281 break;
284 syms[i].map = al.map;
285 syms[i].sym = al.sym;
286 } 282 }
283
284 err = callchain_cursor_append(&self->callchain_cursor,
285 ip, al.map, al.sym);
286 if (err)
287 return err;
287 } 288 }
288 289
289 return syms; 290 return 0;
290} 291}
291 292
292static int process_event_synth_stub(event_t *event __used, 293static int process_event_synth_stub(union perf_event *event __used,
293 struct perf_session *session __used) 294 struct perf_session *session __used)
294{ 295{
295 dump_printf(": unhandled!\n"); 296 dump_printf(": unhandled!\n");
296 return 0; 297 return 0;
297} 298}
298 299
299static int process_event_stub(event_t *event __used, 300static int process_event_sample_stub(union perf_event *event __used,
300 struct sample_data *sample __used, 301 struct perf_sample *sample __used,
302 struct perf_evsel *evsel __used,
303 struct perf_session *session __used)
304{
305 dump_printf(": unhandled!\n");
306 return 0;
307}
308
309static int process_event_stub(union perf_event *event __used,
310 struct perf_sample *sample __used,
301 struct perf_session *session __used) 311 struct perf_session *session __used)
302{ 312{
303 dump_printf(": unhandled!\n"); 313 dump_printf(": unhandled!\n");
304 return 0; 314 return 0;
305} 315}
306 316
307static int process_finished_round_stub(event_t *event __used, 317static int process_finished_round_stub(union perf_event *event __used,
308 struct perf_session *session __used, 318 struct perf_session *session __used,
309 struct perf_event_ops *ops __used) 319 struct perf_event_ops *ops __used)
310{ 320{
@@ -312,14 +322,14 @@ static int process_finished_round_stub(event_t *event __used,
312 return 0; 322 return 0;
313} 323}
314 324
315static int process_finished_round(event_t *event, 325static int process_finished_round(union perf_event *event,
316 struct perf_session *session, 326 struct perf_session *session,
317 struct perf_event_ops *ops); 327 struct perf_event_ops *ops);
318 328
319static void perf_event_ops__fill_defaults(struct perf_event_ops *handler) 329static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
320{ 330{
321 if (handler->sample == NULL) 331 if (handler->sample == NULL)
322 handler->sample = process_event_stub; 332 handler->sample = process_event_sample_stub;
323 if (handler->mmap == NULL) 333 if (handler->mmap == NULL)
324 handler->mmap = process_event_stub; 334 handler->mmap = process_event_stub;
325 if (handler->comm == NULL) 335 if (handler->comm == NULL)
@@ -329,7 +339,7 @@ static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
329 if (handler->exit == NULL) 339 if (handler->exit == NULL)
330 handler->exit = process_event_stub; 340 handler->exit = process_event_stub;
331 if (handler->lost == NULL) 341 if (handler->lost == NULL)
332 handler->lost = event__process_lost; 342 handler->lost = perf_event__process_lost;
333 if (handler->read == NULL) 343 if (handler->read == NULL)
334 handler->read = process_event_stub; 344 handler->read = process_event_stub;
335 if (handler->throttle == NULL) 345 if (handler->throttle == NULL)
@@ -363,98 +373,104 @@ void mem_bswap_64(void *src, int byte_size)
363 } 373 }
364} 374}
365 375
366static void event__all64_swap(event_t *self) 376static void perf_event__all64_swap(union perf_event *event)
367{ 377{
368 struct perf_event_header *hdr = &self->header; 378 struct perf_event_header *hdr = &event->header;
369 mem_bswap_64(hdr + 1, self->header.size - sizeof(*hdr)); 379 mem_bswap_64(hdr + 1, event->header.size - sizeof(*hdr));
370} 380}
371 381
372static void event__comm_swap(event_t *self) 382static void perf_event__comm_swap(union perf_event *event)
373{ 383{
374 self->comm.pid = bswap_32(self->comm.pid); 384 event->comm.pid = bswap_32(event->comm.pid);
375 self->comm.tid = bswap_32(self->comm.tid); 385 event->comm.tid = bswap_32(event->comm.tid);
376} 386}
377 387
378static void event__mmap_swap(event_t *self) 388static void perf_event__mmap_swap(union perf_event *event)
379{ 389{
380 self->mmap.pid = bswap_32(self->mmap.pid); 390 event->mmap.pid = bswap_32(event->mmap.pid);
381 self->mmap.tid = bswap_32(self->mmap.tid); 391 event->mmap.tid = bswap_32(event->mmap.tid);
382 self->mmap.start = bswap_64(self->mmap.start); 392 event->mmap.start = bswap_64(event->mmap.start);
383 self->mmap.len = bswap_64(self->mmap.len); 393 event->mmap.len = bswap_64(event->mmap.len);
384 self->mmap.pgoff = bswap_64(self->mmap.pgoff); 394 event->mmap.pgoff = bswap_64(event->mmap.pgoff);
385} 395}
386 396
387static void event__task_swap(event_t *self) 397static void perf_event__task_swap(union perf_event *event)
388{ 398{
389 self->fork.pid = bswap_32(self->fork.pid); 399 event->fork.pid = bswap_32(event->fork.pid);
390 self->fork.tid = bswap_32(self->fork.tid); 400 event->fork.tid = bswap_32(event->fork.tid);
391 self->fork.ppid = bswap_32(self->fork.ppid); 401 event->fork.ppid = bswap_32(event->fork.ppid);
392 self->fork.ptid = bswap_32(self->fork.ptid); 402 event->fork.ptid = bswap_32(event->fork.ptid);
393 self->fork.time = bswap_64(self->fork.time); 403 event->fork.time = bswap_64(event->fork.time);
394} 404}
395 405
396static void event__read_swap(event_t *self) 406static void perf_event__read_swap(union perf_event *event)
397{ 407{
398 self->read.pid = bswap_32(self->read.pid); 408 event->read.pid = bswap_32(event->read.pid);
399 self->read.tid = bswap_32(self->read.tid); 409 event->read.tid = bswap_32(event->read.tid);
400 self->read.value = bswap_64(self->read.value); 410 event->read.value = bswap_64(event->read.value);
401 self->read.time_enabled = bswap_64(self->read.time_enabled); 411 event->read.time_enabled = bswap_64(event->read.time_enabled);
402 self->read.time_running = bswap_64(self->read.time_running); 412 event->read.time_running = bswap_64(event->read.time_running);
403 self->read.id = bswap_64(self->read.id); 413 event->read.id = bswap_64(event->read.id);
404} 414}
405 415
406static void event__attr_swap(event_t *self) 416/* exported for swapping attributes in file header */
417void perf_event__attr_swap(struct perf_event_attr *attr)
418{
419 attr->type = bswap_32(attr->type);
420 attr->size = bswap_32(attr->size);
421 attr->config = bswap_64(attr->config);
422 attr->sample_period = bswap_64(attr->sample_period);
423 attr->sample_type = bswap_64(attr->sample_type);
424 attr->read_format = bswap_64(attr->read_format);
425 attr->wakeup_events = bswap_32(attr->wakeup_events);
426 attr->bp_type = bswap_32(attr->bp_type);
427 attr->bp_addr = bswap_64(attr->bp_addr);
428 attr->bp_len = bswap_64(attr->bp_len);
429}
430
431static void perf_event__hdr_attr_swap(union perf_event *event)
407{ 432{
408 size_t size; 433 size_t size;
409 434
410 self->attr.attr.type = bswap_32(self->attr.attr.type); 435 perf_event__attr_swap(&event->attr.attr);
411 self->attr.attr.size = bswap_32(self->attr.attr.size); 436
412 self->attr.attr.config = bswap_64(self->attr.attr.config); 437 size = event->header.size;
413 self->attr.attr.sample_period = bswap_64(self->attr.attr.sample_period); 438 size -= (void *)&event->attr.id - (void *)event;
414 self->attr.attr.sample_type = bswap_64(self->attr.attr.sample_type); 439 mem_bswap_64(event->attr.id, size);
415 self->attr.attr.read_format = bswap_64(self->attr.attr.read_format);
416 self->attr.attr.wakeup_events = bswap_32(self->attr.attr.wakeup_events);
417 self->attr.attr.bp_type = bswap_32(self->attr.attr.bp_type);
418 self->attr.attr.bp_addr = bswap_64(self->attr.attr.bp_addr);
419 self->attr.attr.bp_len = bswap_64(self->attr.attr.bp_len);
420
421 size = self->header.size;
422 size -= (void *)&self->attr.id - (void *)self;
423 mem_bswap_64(self->attr.id, size);
424} 440}
425 441
426static void event__event_type_swap(event_t *self) 442static void perf_event__event_type_swap(union perf_event *event)
427{ 443{
428 self->event_type.event_type.event_id = 444 event->event_type.event_type.event_id =
429 bswap_64(self->event_type.event_type.event_id); 445 bswap_64(event->event_type.event_type.event_id);
430} 446}
431 447
432static void event__tracing_data_swap(event_t *self) 448static void perf_event__tracing_data_swap(union perf_event *event)
433{ 449{
434 self->tracing_data.size = bswap_32(self->tracing_data.size); 450 event->tracing_data.size = bswap_32(event->tracing_data.size);
435} 451}
436 452
437typedef void (*event__swap_op)(event_t *self); 453typedef void (*perf_event__swap_op)(union perf_event *event);
438 454
439static event__swap_op event__swap_ops[] = { 455static perf_event__swap_op perf_event__swap_ops[] = {
440 [PERF_RECORD_MMAP] = event__mmap_swap, 456 [PERF_RECORD_MMAP] = perf_event__mmap_swap,
441 [PERF_RECORD_COMM] = event__comm_swap, 457 [PERF_RECORD_COMM] = perf_event__comm_swap,
442 [PERF_RECORD_FORK] = event__task_swap, 458 [PERF_RECORD_FORK] = perf_event__task_swap,
443 [PERF_RECORD_EXIT] = event__task_swap, 459 [PERF_RECORD_EXIT] = perf_event__task_swap,
444 [PERF_RECORD_LOST] = event__all64_swap, 460 [PERF_RECORD_LOST] = perf_event__all64_swap,
445 [PERF_RECORD_READ] = event__read_swap, 461 [PERF_RECORD_READ] = perf_event__read_swap,
446 [PERF_RECORD_SAMPLE] = event__all64_swap, 462 [PERF_RECORD_SAMPLE] = perf_event__all64_swap,
447 [PERF_RECORD_HEADER_ATTR] = event__attr_swap, 463 [PERF_RECORD_HEADER_ATTR] = perf_event__hdr_attr_swap,
448 [PERF_RECORD_HEADER_EVENT_TYPE] = event__event_type_swap, 464 [PERF_RECORD_HEADER_EVENT_TYPE] = perf_event__event_type_swap,
449 [PERF_RECORD_HEADER_TRACING_DATA] = event__tracing_data_swap, 465 [PERF_RECORD_HEADER_TRACING_DATA] = perf_event__tracing_data_swap,
450 [PERF_RECORD_HEADER_BUILD_ID] = NULL, 466 [PERF_RECORD_HEADER_BUILD_ID] = NULL,
451 [PERF_RECORD_HEADER_MAX] = NULL, 467 [PERF_RECORD_HEADER_MAX] = NULL,
452}; 468};
453 469
454struct sample_queue { 470struct sample_queue {
455 u64 timestamp; 471 u64 timestamp;
456 u64 file_offset; 472 u64 file_offset;
457 event_t *event; 473 union perf_event *event;
458 struct list_head list; 474 struct list_head list;
459}; 475};
460 476
@@ -472,8 +488,8 @@ static void perf_session_free_sample_buffers(struct perf_session *session)
472} 488}
473 489
474static int perf_session_deliver_event(struct perf_session *session, 490static int perf_session_deliver_event(struct perf_session *session,
475 event_t *event, 491 union perf_event *event,
476 struct sample_data *sample, 492 struct perf_sample *sample,
477 struct perf_event_ops *ops, 493 struct perf_event_ops *ops,
478 u64 file_offset); 494 u64 file_offset);
479 495
@@ -483,9 +499,10 @@ static void flush_sample_queue(struct perf_session *s,
483 struct ordered_samples *os = &s->ordered_samples; 499 struct ordered_samples *os = &s->ordered_samples;
484 struct list_head *head = &os->samples; 500 struct list_head *head = &os->samples;
485 struct sample_queue *tmp, *iter; 501 struct sample_queue *tmp, *iter;
486 struct sample_data sample; 502 struct perf_sample sample;
487 u64 limit = os->next_flush; 503 u64 limit = os->next_flush;
488 u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL; 504 u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL;
505 int ret;
489 506
490 if (!ops->ordered_samples || !limit) 507 if (!ops->ordered_samples || !limit)
491 return; 508 return;
@@ -494,9 +511,12 @@ static void flush_sample_queue(struct perf_session *s,
494 if (iter->timestamp > limit) 511 if (iter->timestamp > limit)
495 break; 512 break;
496 513
497 event__parse_sample(iter->event, s, &sample); 514 ret = perf_session__parse_sample(s, iter->event, &sample);
498 perf_session_deliver_event(s, iter->event, &sample, ops, 515 if (ret)
499 iter->file_offset); 516 pr_err("Can't parse sample, err = %d\n", ret);
517 else
518 perf_session_deliver_event(s, iter->event, &sample, ops,
519 iter->file_offset);
500 520
501 os->last_flush = iter->timestamp; 521 os->last_flush = iter->timestamp;
502 list_del(&iter->list); 522 list_del(&iter->list);
@@ -550,7 +570,7 @@ static void flush_sample_queue(struct perf_session *s,
550 * Flush every events below timestamp 7 570 * Flush every events below timestamp 7
551 * etc... 571 * etc...
552 */ 572 */
553static int process_finished_round(event_t *event __used, 573static int process_finished_round(union perf_event *event __used,
554 struct perf_session *session, 574 struct perf_session *session,
555 struct perf_event_ops *ops) 575 struct perf_event_ops *ops)
556{ 576{
@@ -607,12 +627,12 @@ static void __queue_event(struct sample_queue *new, struct perf_session *s)
607 627
608#define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct sample_queue)) 628#define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct sample_queue))
609 629
610static int perf_session_queue_event(struct perf_session *s, event_t *event, 630static int perf_session_queue_event(struct perf_session *s, union perf_event *event,
611 struct sample_data *data, u64 file_offset) 631 struct perf_sample *sample, u64 file_offset)
612{ 632{
613 struct ordered_samples *os = &s->ordered_samples; 633 struct ordered_samples *os = &s->ordered_samples;
614 struct list_head *sc = &os->sample_cache; 634 struct list_head *sc = &os->sample_cache;
615 u64 timestamp = data->time; 635 u64 timestamp = sample->time;
616 struct sample_queue *new; 636 struct sample_queue *new;
617 637
618 if (!timestamp || timestamp == ~0ULL) 638 if (!timestamp || timestamp == ~0ULL)
@@ -648,7 +668,7 @@ static int perf_session_queue_event(struct perf_session *s, event_t *event,
648 return 0; 668 return 0;
649} 669}
650 670
651static void callchain__printf(struct sample_data *sample) 671static void callchain__printf(struct perf_sample *sample)
652{ 672{
653 unsigned int i; 673 unsigned int i;
654 674
@@ -660,8 +680,8 @@ static void callchain__printf(struct sample_data *sample)
660} 680}
661 681
662static void perf_session__print_tstamp(struct perf_session *session, 682static void perf_session__print_tstamp(struct perf_session *session,
663 event_t *event, 683 union perf_event *event,
664 struct sample_data *sample) 684 struct perf_sample *sample)
665{ 685{
666 if (event->header.type != PERF_RECORD_SAMPLE && 686 if (event->header.type != PERF_RECORD_SAMPLE &&
667 !session->sample_id_all) { 687 !session->sample_id_all) {
@@ -676,8 +696,8 @@ static void perf_session__print_tstamp(struct perf_session *session,
676 printf("%" PRIu64 " ", sample->time); 696 printf("%" PRIu64 " ", sample->time);
677} 697}
678 698
679static void dump_event(struct perf_session *session, event_t *event, 699static void dump_event(struct perf_session *session, union perf_event *event,
680 u64 file_offset, struct sample_data *sample) 700 u64 file_offset, struct perf_sample *sample)
681{ 701{
682 if (!dump_trace) 702 if (!dump_trace)
683 return; 703 return;
@@ -691,35 +711,42 @@ static void dump_event(struct perf_session *session, event_t *event,
691 perf_session__print_tstamp(session, event, sample); 711 perf_session__print_tstamp(session, event, sample);
692 712
693 printf("%#" PRIx64 " [%#x]: PERF_RECORD_%s", file_offset, 713 printf("%#" PRIx64 " [%#x]: PERF_RECORD_%s", file_offset,
694 event->header.size, event__get_event_name(event->header.type)); 714 event->header.size, perf_event__name(event->header.type));
695} 715}
696 716
697static void dump_sample(struct perf_session *session, event_t *event, 717static void dump_sample(struct perf_session *session, union perf_event *event,
698 struct sample_data *sample) 718 struct perf_sample *sample)
699{ 719{
700 if (!dump_trace) 720 if (!dump_trace)
701 return; 721 return;
702 722
703 printf("(IP, %d): %d/%d: %#" PRIx64 " period: %" PRIu64 "\n", 723 printf("(IP, %d): %d/%d: %#" PRIx64 " period: %" PRIu64 " addr: %#" PRIx64 "\n",
704 event->header.misc, sample->pid, sample->tid, sample->ip, 724 event->header.misc, sample->pid, sample->tid, sample->ip,
705 sample->period); 725 sample->period, sample->addr);
706 726
707 if (session->sample_type & PERF_SAMPLE_CALLCHAIN) 727 if (session->sample_type & PERF_SAMPLE_CALLCHAIN)
708 callchain__printf(sample); 728 callchain__printf(sample);
709} 729}
710 730
711static int perf_session_deliver_event(struct perf_session *session, 731static int perf_session_deliver_event(struct perf_session *session,
712 event_t *event, 732 union perf_event *event,
713 struct sample_data *sample, 733 struct perf_sample *sample,
714 struct perf_event_ops *ops, 734 struct perf_event_ops *ops,
715 u64 file_offset) 735 u64 file_offset)
716{ 736{
737 struct perf_evsel *evsel;
738
717 dump_event(session, event, file_offset, sample); 739 dump_event(session, event, file_offset, sample);
718 740
719 switch (event->header.type) { 741 switch (event->header.type) {
720 case PERF_RECORD_SAMPLE: 742 case PERF_RECORD_SAMPLE:
721 dump_sample(session, event, sample); 743 dump_sample(session, event, sample);
722 return ops->sample(event, sample, session); 744 evsel = perf_evlist__id2evsel(session->evlist, sample->id);
745 if (evsel == NULL) {
746 ++session->hists.stats.nr_unknown_id;
747 return -1;
748 }
749 return ops->sample(event, sample, evsel, session);
723 case PERF_RECORD_MMAP: 750 case PERF_RECORD_MMAP:
724 return ops->mmap(event, sample, session); 751 return ops->mmap(event, sample, session);
725 case PERF_RECORD_COMM: 752 case PERF_RECORD_COMM:
@@ -743,7 +770,7 @@ static int perf_session_deliver_event(struct perf_session *session,
743} 770}
744 771
745static int perf_session__preprocess_sample(struct perf_session *session, 772static int perf_session__preprocess_sample(struct perf_session *session,
746 event_t *event, struct sample_data *sample) 773 union perf_event *event, struct perf_sample *sample)
747{ 774{
748 if (event->header.type != PERF_RECORD_SAMPLE || 775 if (event->header.type != PERF_RECORD_SAMPLE ||
749 !(session->sample_type & PERF_SAMPLE_CALLCHAIN)) 776 !(session->sample_type & PERF_SAMPLE_CALLCHAIN))
@@ -758,7 +785,7 @@ static int perf_session__preprocess_sample(struct perf_session *session,
758 return 0; 785 return 0;
759} 786}
760 787
761static int perf_session__process_user_event(struct perf_session *session, event_t *event, 788static int perf_session__process_user_event(struct perf_session *session, union perf_event *event,
762 struct perf_event_ops *ops, u64 file_offset) 789 struct perf_event_ops *ops, u64 file_offset)
763{ 790{
764 dump_event(session, event, file_offset, NULL); 791 dump_event(session, event, file_offset, NULL);
@@ -783,15 +810,16 @@ static int perf_session__process_user_event(struct perf_session *session, event_
783} 810}
784 811
785static int perf_session__process_event(struct perf_session *session, 812static int perf_session__process_event(struct perf_session *session,
786 event_t *event, 813 union perf_event *event,
787 struct perf_event_ops *ops, 814 struct perf_event_ops *ops,
788 u64 file_offset) 815 u64 file_offset)
789{ 816{
790 struct sample_data sample; 817 struct perf_sample sample;
791 int ret; 818 int ret;
792 819
793 if (session->header.needs_swap && event__swap_ops[event->header.type]) 820 if (session->header.needs_swap &&
794 event__swap_ops[event->header.type](event); 821 perf_event__swap_ops[event->header.type])
822 perf_event__swap_ops[event->header.type](event);
795 823
796 if (event->header.type >= PERF_RECORD_HEADER_MAX) 824 if (event->header.type >= PERF_RECORD_HEADER_MAX)
797 return -EINVAL; 825 return -EINVAL;
@@ -804,7 +832,9 @@ static int perf_session__process_event(struct perf_session *session,
804 /* 832 /*
805 * For all kernel events we get the sample data 833 * For all kernel events we get the sample data
806 */ 834 */
807 event__parse_sample(event, session, &sample); 835 ret = perf_session__parse_sample(session, event, &sample);
836 if (ret)
837 return ret;
808 838
809 /* Preprocess sample records - precheck callchains */ 839 /* Preprocess sample records - precheck callchains */
810 if (perf_session__preprocess_sample(session, event, &sample)) 840 if (perf_session__preprocess_sample(session, event, &sample))
@@ -843,7 +873,7 @@ static struct thread *perf_session__register_idle_thread(struct perf_session *se
843static void perf_session__warn_about_errors(const struct perf_session *session, 873static void perf_session__warn_about_errors(const struct perf_session *session,
844 const struct perf_event_ops *ops) 874 const struct perf_event_ops *ops)
845{ 875{
846 if (ops->lost == event__process_lost && 876 if (ops->lost == perf_event__process_lost &&
847 session->hists.stats.total_lost != 0) { 877 session->hists.stats.total_lost != 0) {
848 ui__warning("Processed %" PRIu64 " events and LOST %" PRIu64 878 ui__warning("Processed %" PRIu64 " events and LOST %" PRIu64
849 "!\n\nCheck IO/CPU overload!\n\n", 879 "!\n\nCheck IO/CPU overload!\n\n",
@@ -860,6 +890,11 @@ static void perf_session__warn_about_errors(const struct perf_session *session,
860 session->hists.stats.nr_unknown_events); 890 session->hists.stats.nr_unknown_events);
861 } 891 }
862 892
893 if (session->hists.stats.nr_unknown_id != 0) {
894 ui__warning("%u samples with id not present in the header\n",
895 session->hists.stats.nr_unknown_id);
896 }
897
863 if (session->hists.stats.nr_invalid_chains != 0) { 898 if (session->hists.stats.nr_invalid_chains != 0) {
864 ui__warning("Found invalid callchains!\n\n" 899 ui__warning("Found invalid callchains!\n\n"
865 "%u out of %u events were discarded for this reason.\n\n" 900 "%u out of %u events were discarded for this reason.\n\n"
@@ -875,7 +910,7 @@ volatile int session_done;
875static int __perf_session__process_pipe_events(struct perf_session *self, 910static int __perf_session__process_pipe_events(struct perf_session *self,
876 struct perf_event_ops *ops) 911 struct perf_event_ops *ops)
877{ 912{
878 event_t event; 913 union perf_event event;
879 uint32_t size; 914 uint32_t size;
880 int skip = 0; 915 int skip = 0;
881 u64 head; 916 u64 head;
@@ -947,6 +982,30 @@ out_err:
947 return err; 982 return err;
948} 983}
949 984
985static union perf_event *
986fetch_mmaped_event(struct perf_session *session,
987 u64 head, size_t mmap_size, char *buf)
988{
989 union perf_event *event;
990
991 /*
992 * Ensure we have enough space remaining to read
993 * the size of the event in the headers.
994 */
995 if (head + sizeof(event->header) > mmap_size)
996 return NULL;
997
998 event = (union perf_event *)(buf + head);
999
1000 if (session->header.needs_swap)
1001 perf_event_header__bswap(&event->header);
1002
1003 if (head + event->header.size > mmap_size)
1004 return NULL;
1005
1006 return event;
1007}
1008
950int __perf_session__process_events(struct perf_session *session, 1009int __perf_session__process_events(struct perf_session *session,
951 u64 data_offset, u64 data_size, 1010 u64 data_offset, u64 data_size,
952 u64 file_size, struct perf_event_ops *ops) 1011 u64 file_size, struct perf_event_ops *ops)
@@ -956,7 +1015,7 @@ int __perf_session__process_events(struct perf_session *session,
956 struct ui_progress *progress; 1015 struct ui_progress *progress;
957 size_t page_size, mmap_size; 1016 size_t page_size, mmap_size;
958 char *buf, *mmaps[8]; 1017 char *buf, *mmaps[8];
959 event_t *event; 1018 union perf_event *event;
960 uint32_t size; 1019 uint32_t size;
961 1020
962 perf_event_ops__fill_defaults(ops); 1021 perf_event_ops__fill_defaults(ops);
@@ -1001,15 +1060,8 @@ remap:
1001 file_pos = file_offset + head; 1060 file_pos = file_offset + head;
1002 1061
1003more: 1062more:
1004 event = (event_t *)(buf + head); 1063 event = fetch_mmaped_event(session, head, mmap_size, buf);
1005 1064 if (!event) {
1006 if (session->header.needs_swap)
1007 perf_event_header__bswap(&event->header);
1008 size = event->header.size;
1009 if (size == 0)
1010 size = 8;
1011
1012 if (head + event->header.size > mmap_size) {
1013 if (mmaps[map_idx]) { 1065 if (mmaps[map_idx]) {
1014 munmap(mmaps[map_idx], mmap_size); 1066 munmap(mmaps[map_idx], mmap_size);
1015 mmaps[map_idx] = NULL; 1067 mmaps[map_idx] = NULL;
@@ -1134,3 +1186,143 @@ size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp,
1134 size_t ret = machine__fprintf_dsos_buildid(&self->host_machine, fp, with_hits); 1186 size_t ret = machine__fprintf_dsos_buildid(&self->host_machine, fp, with_hits);
1135 return ret + machines__fprintf_dsos_buildid(&self->machines, fp, with_hits); 1187 return ret + machines__fprintf_dsos_buildid(&self->machines, fp, with_hits);
1136} 1188}
1189
1190size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
1191{
1192 struct perf_evsel *pos;
1193 size_t ret = fprintf(fp, "Aggregated stats:\n");
1194
1195 ret += hists__fprintf_nr_events(&session->hists, fp);
1196
1197 list_for_each_entry(pos, &session->evlist->entries, node) {
1198 ret += fprintf(fp, "%s stats:\n", event_name(pos));
1199 ret += hists__fprintf_nr_events(&pos->hists, fp);
1200 }
1201
1202 return ret;
1203}
1204
1205struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
1206 unsigned int type)
1207{
1208 struct perf_evsel *pos;
1209
1210 list_for_each_entry(pos, &session->evlist->entries, node) {
1211 if (pos->attr.type == type)
1212 return pos;
1213 }
1214 return NULL;
1215}
1216
1217void perf_session__print_ip(union perf_event *event,
1218 struct perf_sample *sample,
1219 struct perf_session *session,
1220 int print_sym, int print_dso)
1221{
1222 struct addr_location al;
1223 const char *symname, *dsoname;
1224 struct callchain_cursor *cursor = &session->callchain_cursor;
1225 struct callchain_cursor_node *node;
1226
1227 if (perf_event__preprocess_sample(event, session, &al, sample,
1228 NULL) < 0) {
1229 error("problem processing %d event, skipping it.\n",
1230 event->header.type);
1231 return;
1232 }
1233
1234 if (symbol_conf.use_callchain && sample->callchain) {
1235
1236 if (perf_session__resolve_callchain(session, al.thread,
1237 sample->callchain, NULL) != 0) {
1238 if (verbose)
1239 error("Failed to resolve callchain. Skipping\n");
1240 return;
1241 }
1242 callchain_cursor_commit(cursor);
1243
1244 while (1) {
1245 node = callchain_cursor_current(cursor);
1246 if (!node)
1247 break;
1248
1249 printf("\t%16" PRIx64, node->ip);
1250 if (print_sym) {
1251 if (node->sym && node->sym->name)
1252 symname = node->sym->name;
1253 else
1254 symname = "";
1255
1256 printf(" %s", symname);
1257 }
1258 if (print_dso) {
1259 if (node->map && node->map->dso && node->map->dso->name)
1260 dsoname = node->map->dso->name;
1261 else
1262 dsoname = "";
1263
1264 printf(" (%s)", dsoname);
1265 }
1266 printf("\n");
1267
1268 callchain_cursor_advance(cursor);
1269 }
1270
1271 } else {
1272 printf("%16" PRIx64, sample->ip);
1273 if (print_sym) {
1274 if (al.sym && al.sym->name)
1275 symname = al.sym->name;
1276 else
1277 symname = "";
1278
1279 printf(" %s", symname);
1280 }
1281
1282 if (print_dso) {
1283 if (al.map && al.map->dso && al.map->dso->name)
1284 dsoname = al.map->dso->name;
1285 else
1286 dsoname = "";
1287
1288 printf(" (%s)", dsoname);
1289 }
1290 }
1291}
1292
1293int perf_session__cpu_bitmap(struct perf_session *session,
1294 const char *cpu_list, unsigned long *cpu_bitmap)
1295{
1296 int i;
1297 struct cpu_map *map;
1298
1299 for (i = 0; i < PERF_TYPE_MAX; ++i) {
1300 struct perf_evsel *evsel;
1301
1302 evsel = perf_session__find_first_evtype(session, i);
1303 if (!evsel)
1304 continue;
1305
1306 if (!(evsel->attr.sample_type & PERF_SAMPLE_CPU)) {
1307 pr_err("File does not contain CPU events. "
1308 "Remove -c option to proceed.\n");
1309 return -1;
1310 }
1311 }
1312
1313 map = cpu_map__new(cpu_list);
1314
1315 for (i = 0; i < map->nr; i++) {
1316 int cpu = map->map[i];
1317
1318 if (cpu >= MAX_NR_CPUS) {
1319 pr_err("Requested CPU %d too large. "
1320 "Consider raising MAX_NR_CPUS\n", cpu);
1321 return -1;
1322 }
1323
1324 set_bit(cpu, cpu_bitmap);
1325 }
1326
1327 return 0;
1328}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index decd83f274fd..170601e67d6b 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -34,15 +34,16 @@ 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;
46 int sample_size;
46 int fd; 47 int fd;
47 bool fd_pipe; 48 bool fd_pipe;
48 bool repipe; 49 bool repipe;
@@ -51,20 +52,25 @@ struct perf_session {
51 int cwdlen; 52 int cwdlen;
52 char *cwd; 53 char *cwd;
53 struct ordered_samples ordered_samples; 54 struct ordered_samples ordered_samples;
54 char filename[0]; 55 struct callchain_cursor callchain_cursor;
56 char filename[0];
55}; 57};
56 58
59struct perf_evsel;
57struct perf_event_ops; 60struct perf_event_ops;
58 61
59typedef int (*event_op)(event_t *self, struct sample_data *sample, 62typedef int (*event_sample)(union perf_event *event, struct perf_sample *sample,
63 struct perf_evsel *evsel, struct perf_session *session);
64typedef int (*event_op)(union perf_event *self, struct perf_sample *sample,
60 struct perf_session *session); 65 struct perf_session *session);
61typedef int (*event_synth_op)(event_t *self, struct perf_session *session); 66typedef int (*event_synth_op)(union perf_event *self,
62typedef int (*event_op2)(event_t *self, struct perf_session *session, 67 struct perf_session *session);
68typedef int (*event_op2)(union perf_event *self, struct perf_session *session,
63 struct perf_event_ops *ops); 69 struct perf_event_ops *ops);
64 70
65struct perf_event_ops { 71struct perf_event_ops {
66 event_op sample, 72 event_sample sample;
67 mmap, 73 event_op mmap,
68 comm, 74 comm,
69 fork, 75 fork,
70 exit, 76 exit,
@@ -94,10 +100,10 @@ int __perf_session__process_events(struct perf_session *self,
94int perf_session__process_events(struct perf_session *self, 100int perf_session__process_events(struct perf_session *self,
95 struct perf_event_ops *event_ops); 101 struct perf_event_ops *event_ops);
96 102
97struct map_symbol *perf_session__resolve_callchain(struct perf_session *self, 103int perf_session__resolve_callchain(struct perf_session *self,
98 struct thread *thread, 104 struct thread *thread,
99 struct ip_callchain *chain, 105 struct ip_callchain *chain,
100 struct symbol **parent); 106 struct symbol **parent);
101 107
102bool perf_session__has_traces(struct perf_session *self, const char *msg); 108bool perf_session__has_traces(struct perf_session *self, const char *msg);
103 109
@@ -106,12 +112,11 @@ int perf_session__set_kallsyms_ref_reloc_sym(struct map **maps,
106 u64 addr); 112 u64 addr);
107 113
108void mem_bswap_64(void *src, int byte_size); 114void mem_bswap_64(void *src, int byte_size);
115void perf_event__attr_swap(struct perf_event_attr *attr);
109 116
110int perf_session__create_kernel_maps(struct perf_session *self); 117int perf_session__create_kernel_maps(struct perf_session *self);
111 118
112void perf_session__update_sample_type(struct perf_session *self); 119void 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); 120void perf_session__remove_thread(struct perf_session *self, struct thread *th);
116 121
117static inline 122static inline
@@ -149,9 +154,26 @@ size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp);
149size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, 154size_t perf_session__fprintf_dsos_buildid(struct perf_session *self,
150 FILE *fp, bool with_hits); 155 FILE *fp, bool with_hits);
151 156
152static inline 157size_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) 158
159static inline int perf_session__parse_sample(struct perf_session *session,
160 const union perf_event *event,
161 struct perf_sample *sample)
154{ 162{
155 return hists__fprintf_nr_events(&self->hists, fp); 163 return perf_event__parse_sample(event, session->sample_type,
164 session->sample_size,
165 session->sample_id_all, sample);
156} 166}
167
168struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
169 unsigned int type);
170
171void perf_session__print_ip(union perf_event *event,
172 struct perf_sample *sample,
173 struct perf_session *session,
174 int print_sym, int print_dso);
175
176int perf_session__cpu_bitmap(struct perf_session *session,
177 const char *cpu_list, unsigned long *cpu_bitmap);
178
157#endif /* __PERF_SESSION_H */ 179#endif /* __PERF_SESSION_H */
diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py
new file mode 100644
index 000000000000..95d370074928
--- /dev/null
+++ b/tools/perf/util/setup.py
@@ -0,0 +1,43 @@
1#!/usr/bin/python2
2
3from distutils.core import setup, Extension
4from os import getenv
5
6from distutils.command.build_ext import build_ext as _build_ext
7from distutils.command.install_lib import install_lib as _install_lib
8
9class build_ext(_build_ext):
10 def finalize_options(self):
11 _build_ext.finalize_options(self)
12 self.build_lib = build_lib
13 self.build_temp = build_tmp
14
15class install_lib(_install_lib):
16 def finalize_options(self):
17 _install_lib.finalize_options(self)
18 self.build_dir = build_lib
19
20
21cflags = ['-fno-strict-aliasing', '-Wno-write-strings']
22cflags += getenv('CFLAGS', '').split()
23
24build_lib = getenv('PYTHON_EXTBUILD_LIB')
25build_tmp = getenv('PYTHON_EXTBUILD_TMP')
26
27perf = Extension('perf',
28 sources = ['util/python.c', 'util/ctype.c', 'util/evlist.c',
29 'util/evsel.c', 'util/cpumap.c', 'util/thread_map.c',
30 'util/util.c', 'util/xyarray.c', 'util/cgroup.c'],
31 include_dirs = ['util/include'],
32 extra_compile_args = cflags,
33 )
34
35setup(name='perf',
36 version='0.1',
37 description='Interface with the Linux profiling infrastructure',
38 author='Arnaldo Carvalho de Melo',
39 author_email='acme@redhat.com',
40 license='GPLv2',
41 url='http://perf.wiki.kernel.org',
42 ext_modules=[perf],
43 cmdclass={'build_ext': build_ext, 'install_lib': install_lib})
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index f44fa541d56e..401e220566fd 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -15,95 +15,6 @@ char * field_sep;
15 15
16LIST_HEAD(hist_entry__sort_list); 16LIST_HEAD(hist_entry__sort_list);
17 17
18static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf,
19 size_t size, unsigned int width);
20static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf,
21 size_t size, unsigned int width);
22static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf,
23 size_t size, unsigned int width);
24static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
25 size_t size, unsigned int width);
26static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf,
27 size_t size, unsigned int width);
28static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf,
29 size_t size, unsigned int width);
30
31struct sort_entry sort_thread = {
32 .se_header = "Command: Pid",
33 .se_cmp = sort__thread_cmp,
34 .se_snprintf = hist_entry__thread_snprintf,
35 .se_width_idx = HISTC_THREAD,
36};
37
38struct sort_entry sort_comm = {
39 .se_header = "Command",
40 .se_cmp = sort__comm_cmp,
41 .se_collapse = sort__comm_collapse,
42 .se_snprintf = hist_entry__comm_snprintf,
43 .se_width_idx = HISTC_COMM,
44};
45
46struct sort_entry sort_dso = {
47 .se_header = "Shared Object",
48 .se_cmp = sort__dso_cmp,
49 .se_snprintf = hist_entry__dso_snprintf,
50 .se_width_idx = HISTC_DSO,
51};
52
53struct sort_entry sort_sym = {
54 .se_header = "Symbol",
55 .se_cmp = sort__sym_cmp,
56 .se_snprintf = hist_entry__sym_snprintf,
57 .se_width_idx = HISTC_SYMBOL,
58};
59
60struct sort_entry sort_parent = {
61 .se_header = "Parent symbol",
62 .se_cmp = sort__parent_cmp,
63 .se_snprintf = hist_entry__parent_snprintf,
64 .se_width_idx = HISTC_PARENT,
65};
66
67struct sort_entry sort_cpu = {
68 .se_header = "CPU",
69 .se_cmp = sort__cpu_cmp,
70 .se_snprintf = hist_entry__cpu_snprintf,
71 .se_width_idx = HISTC_CPU,
72};
73
74struct sort_dimension {
75 const char *name;
76 struct sort_entry *entry;
77 int taken;
78};
79
80static struct sort_dimension sort_dimensions[] = {
81 { .name = "pid", .entry = &sort_thread, },
82 { .name = "comm", .entry = &sort_comm, },
83 { .name = "dso", .entry = &sort_dso, },
84 { .name = "symbol", .entry = &sort_sym, },
85 { .name = "parent", .entry = &sort_parent, },
86 { .name = "cpu", .entry = &sort_cpu, },
87};
88
89int64_t cmp_null(void *l, void *r)
90{
91 if (!l && !r)
92 return 0;
93 else if (!l)
94 return -1;
95 else
96 return 1;
97}
98
99/* --sort pid */
100
101int64_t
102sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
103{
104 return right->thread->pid - left->thread->pid;
105}
106
107static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...) 18static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
108{ 19{
109 int n; 20 int n;
@@ -125,6 +36,24 @@ static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
125 return n; 36 return n;
126} 37}
127 38
39static int64_t cmp_null(void *l, void *r)
40{
41 if (!l && !r)
42 return 0;
43 else if (!l)
44 return -1;
45 else
46 return 1;
47}
48
49/* --sort pid */
50
51static int64_t
52sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
53{
54 return right->thread->pid - left->thread->pid;
55}
56
128static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf, 57static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf,
129 size_t size, unsigned int width) 58 size_t size, unsigned int width)
130{ 59{
@@ -132,15 +61,50 @@ static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf,
132 self->thread->comm ?: "", self->thread->pid); 61 self->thread->comm ?: "", self->thread->pid);
133} 62}
134 63
64struct sort_entry sort_thread = {
65 .se_header = "Command: Pid",
66 .se_cmp = sort__thread_cmp,
67 .se_snprintf = hist_entry__thread_snprintf,
68 .se_width_idx = HISTC_THREAD,
69};
70
71/* --sort comm */
72
73static int64_t
74sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
75{
76 return right->thread->pid - left->thread->pid;
77}
78
79static int64_t
80sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
81{
82 char *comm_l = left->thread->comm;
83 char *comm_r = right->thread->comm;
84
85 if (!comm_l || !comm_r)
86 return cmp_null(comm_l, comm_r);
87
88 return strcmp(comm_l, comm_r);
89}
90
135static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf, 91static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf,
136 size_t size, unsigned int width) 92 size_t size, unsigned int width)
137{ 93{
138 return repsep_snprintf(bf, size, "%*s", width, self->thread->comm); 94 return repsep_snprintf(bf, size, "%*s", width, self->thread->comm);
139} 95}
140 96
97struct sort_entry sort_comm = {
98 .se_header = "Command",
99 .se_cmp = sort__comm_cmp,
100 .se_collapse = sort__comm_collapse,
101 .se_snprintf = hist_entry__comm_snprintf,
102 .se_width_idx = HISTC_COMM,
103};
104
141/* --sort dso */ 105/* --sort dso */
142 106
143int64_t 107static int64_t
144sort__dso_cmp(struct hist_entry *left, struct hist_entry *right) 108sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
145{ 109{
146 struct dso *dso_l = left->ms.map ? left->ms.map->dso : NULL; 110 struct dso *dso_l = left->ms.map ? left->ms.map->dso : NULL;
@@ -173,9 +137,16 @@ static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf,
173 return repsep_snprintf(bf, size, "%-*s", width, "[unknown]"); 137 return repsep_snprintf(bf, size, "%-*s", width, "[unknown]");
174} 138}
175 139
140struct sort_entry sort_dso = {
141 .se_header = "Shared Object",
142 .se_cmp = sort__dso_cmp,
143 .se_snprintf = hist_entry__dso_snprintf,
144 .se_width_idx = HISTC_DSO,
145};
146
176/* --sort symbol */ 147/* --sort symbol */
177 148
178int64_t 149static int64_t
179sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) 150sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
180{ 151{
181 u64 ip_l, ip_r; 152 u64 ip_l, ip_r;
@@ -211,29 +182,16 @@ static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
211 return ret; 182 return ret;
212} 183}
213 184
214/* --sort comm */ 185struct sort_entry sort_sym = {
215 186 .se_header = "Symbol",
216int64_t 187 .se_cmp = sort__sym_cmp,
217sort__comm_cmp(struct hist_entry *left, struct hist_entry *right) 188 .se_snprintf = hist_entry__sym_snprintf,
218{ 189 .se_width_idx = HISTC_SYMBOL,
219 return right->thread->pid - left->thread->pid; 190};
220}
221
222int64_t
223sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
224{
225 char *comm_l = left->thread->comm;
226 char *comm_r = right->thread->comm;
227
228 if (!comm_l || !comm_r)
229 return cmp_null(comm_l, comm_r);
230
231 return strcmp(comm_l, comm_r);
232}
233 191
234/* --sort parent */ 192/* --sort parent */
235 193
236int64_t 194static int64_t
237sort__parent_cmp(struct hist_entry *left, struct hist_entry *right) 195sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
238{ 196{
239 struct symbol *sym_l = left->parent; 197 struct symbol *sym_l = left->parent;
@@ -252,9 +210,16 @@ static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf,
252 self->parent ? self->parent->name : "[other]"); 210 self->parent ? self->parent->name : "[other]");
253} 211}
254 212
213struct sort_entry sort_parent = {
214 .se_header = "Parent symbol",
215 .se_cmp = sort__parent_cmp,
216 .se_snprintf = hist_entry__parent_snprintf,
217 .se_width_idx = HISTC_PARENT,
218};
219
255/* --sort cpu */ 220/* --sort cpu */
256 221
257int64_t 222static int64_t
258sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right) 223sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
259{ 224{
260 return right->cpu - left->cpu; 225 return right->cpu - left->cpu;
@@ -266,6 +231,28 @@ static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf,
266 return repsep_snprintf(bf, size, "%-*d", width, self->cpu); 231 return repsep_snprintf(bf, size, "%-*d", width, self->cpu);
267} 232}
268 233
234struct sort_entry sort_cpu = {
235 .se_header = "CPU",
236 .se_cmp = sort__cpu_cmp,
237 .se_snprintf = hist_entry__cpu_snprintf,
238 .se_width_idx = HISTC_CPU,
239};
240
241struct sort_dimension {
242 const char *name;
243 struct sort_entry *entry;
244 int taken;
245};
246
247static struct sort_dimension sort_dimensions[] = {
248 { .name = "pid", .entry = &sort_thread, },
249 { .name = "comm", .entry = &sort_comm, },
250 { .name = "dso", .entry = &sort_dso, },
251 { .name = "symbol", .entry = &sort_sym, },
252 { .name = "parent", .entry = &sort_parent, },
253 { .name = "cpu", .entry = &sort_cpu, },
254};
255
269int sort_dimension__add(const char *tok) 256int sort_dimension__add(const char *tok)
270{ 257{
271 unsigned int i; 258 unsigned int i;
@@ -273,15 +260,9 @@ int sort_dimension__add(const char *tok)
273 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) { 260 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
274 struct sort_dimension *sd = &sort_dimensions[i]; 261 struct sort_dimension *sd = &sort_dimensions[i];
275 262
276 if (sd->taken)
277 continue;
278
279 if (strncasecmp(tok, sd->name, strlen(tok))) 263 if (strncasecmp(tok, sd->name, strlen(tok)))
280 continue; 264 continue;
281 265
282 if (sd->entry->se_collapse)
283 sort__need_collapse = 1;
284
285 if (sd->entry == &sort_parent) { 266 if (sd->entry == &sort_parent) {
286 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED); 267 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
287 if (ret) { 268 if (ret) {
@@ -294,6 +275,12 @@ int sort_dimension__add(const char *tok)
294 sort__has_parent = 1; 275 sort__has_parent = 1;
295 } 276 }
296 277
278 if (sd->taken)
279 return 0;
280
281 if (sd->entry->se_collapse)
282 sort__need_collapse = 1;
283
297 if (list_empty(&hist_entry__sort_list)) { 284 if (list_empty(&hist_entry__sort_list)) {
298 if (!strcmp(sd->name, "pid")) 285 if (!strcmp(sd->name, "pid"))
299 sort__first_dimension = SORT_PID; 286 sort__first_dimension = SORT_PID;
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 0b91053a7d11..77d0388ad415 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -103,20 +103,6 @@ extern struct sort_entry sort_thread;
103extern struct list_head hist_entry__sort_list; 103extern struct list_head hist_entry__sort_list;
104 104
105void setup_sorting(const char * const usagestr[], const struct option *opts); 105void setup_sorting(const char * const usagestr[], const struct option *opts);
106
107extern size_t sort__thread_print(FILE *, struct hist_entry *, unsigned int);
108extern size_t sort__comm_print(FILE *, struct hist_entry *, unsigned int);
109extern size_t sort__dso_print(FILE *, struct hist_entry *, unsigned int);
110extern size_t sort__sym_print(FILE *, struct hist_entry *, unsigned int __used);
111extern int64_t cmp_null(void *, void *);
112extern int64_t sort__thread_cmp(struct hist_entry *, struct hist_entry *);
113extern int64_t sort__comm_cmp(struct hist_entry *, struct hist_entry *);
114extern int64_t sort__comm_collapse(struct hist_entry *, struct hist_entry *);
115extern int64_t sort__dso_cmp(struct hist_entry *, struct hist_entry *);
116extern int64_t sort__sym_cmp(struct hist_entry *, struct hist_entry *);
117extern int64_t sort__parent_cmp(struct hist_entry *, struct hist_entry *);
118int64_t sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right);
119extern size_t sort__parent_print(FILE *, struct hist_entry *, unsigned int);
120extern int sort_dimension__add(const char *); 106extern int sort_dimension__add(const char *);
121void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list, 107void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
122 const char *list_name, FILE *fp); 108 const char *list_name, FILE *fp);
diff --git a/tools/perf/util/strfilter.c b/tools/perf/util/strfilter.c
new file mode 100644
index 000000000000..834c8ebfe38e
--- /dev/null
+++ b/tools/perf/util/strfilter.c
@@ -0,0 +1,199 @@
1#include "util.h"
2#include "string.h"
3#include "strfilter.h"
4
5/* Operators */
6static const char *OP_and = "&"; /* Logical AND */
7static const char *OP_or = "|"; /* Logical OR */
8static const char *OP_not = "!"; /* Logical NOT */
9
10#define is_operator(c) ((c) == '|' || (c) == '&' || (c) == '!')
11#define is_separator(c) (is_operator(c) || (c) == '(' || (c) == ')')
12
13static void strfilter_node__delete(struct strfilter_node *self)
14{
15 if (self) {
16 if (self->p && !is_operator(*self->p))
17 free((char *)self->p);
18 strfilter_node__delete(self->l);
19 strfilter_node__delete(self->r);
20 free(self);
21 }
22}
23
24void strfilter__delete(struct strfilter *self)
25{
26 if (self) {
27 strfilter_node__delete(self->root);
28 free(self);
29 }
30}
31
32static const char *get_token(const char *s, const char **e)
33{
34 const char *p;
35
36 while (isspace(*s)) /* Skip spaces */
37 s++;
38
39 if (*s == '\0') {
40 p = s;
41 goto end;
42 }
43
44 p = s + 1;
45 if (!is_separator(*s)) {
46 /* End search */
47retry:
48 while (*p && !is_separator(*p) && !isspace(*p))
49 p++;
50 /* Escape and special case: '!' is also used in glob pattern */
51 if (*(p - 1) == '\\' || (*p == '!' && *(p - 1) == '[')) {
52 p++;
53 goto retry;
54 }
55 }
56end:
57 *e = p;
58 return s;
59}
60
61static struct strfilter_node *strfilter_node__alloc(const char *op,
62 struct strfilter_node *l,
63 struct strfilter_node *r)
64{
65 struct strfilter_node *ret = zalloc(sizeof(struct strfilter_node));
66
67 if (ret) {
68 ret->p = op;
69 ret->l = l;
70 ret->r = r;
71 }
72
73 return ret;
74}
75
76static struct strfilter_node *strfilter_node__new(const char *s,
77 const char **ep)
78{
79 struct strfilter_node root, *cur, *last_op;
80 const char *e;
81
82 if (!s)
83 return NULL;
84
85 memset(&root, 0, sizeof(root));
86 last_op = cur = &root;
87
88 s = get_token(s, &e);
89 while (*s != '\0' && *s != ')') {
90 switch (*s) {
91 case '&': /* Exchg last OP->r with AND */
92 if (!cur->r || !last_op->r)
93 goto error;
94 cur = strfilter_node__alloc(OP_and, last_op->r, NULL);
95 if (!cur)
96 goto nomem;
97 last_op->r = cur;
98 last_op = cur;
99 break;
100 case '|': /* Exchg the root with OR */
101 if (!cur->r || !root.r)
102 goto error;
103 cur = strfilter_node__alloc(OP_or, root.r, NULL);
104 if (!cur)
105 goto nomem;
106 root.r = cur;
107 last_op = cur;
108 break;
109 case '!': /* Add NOT as a leaf node */
110 if (cur->r)
111 goto error;
112 cur->r = strfilter_node__alloc(OP_not, NULL, NULL);
113 if (!cur->r)
114 goto nomem;
115 cur = cur->r;
116 break;
117 case '(': /* Recursively parses inside the parenthesis */
118 if (cur->r)
119 goto error;
120 cur->r = strfilter_node__new(s + 1, &s);
121 if (!s)
122 goto nomem;
123 if (!cur->r || *s != ')')
124 goto error;
125 e = s + 1;
126 break;
127 default:
128 if (cur->r)
129 goto error;
130 cur->r = strfilter_node__alloc(NULL, NULL, NULL);
131 if (!cur->r)
132 goto nomem;
133 cur->r->p = strndup(s, e - s);
134 if (!cur->r->p)
135 goto nomem;
136 }
137 s = get_token(e, &e);
138 }
139 if (!cur->r)
140 goto error;
141 *ep = s;
142 return root.r;
143nomem:
144 s = NULL;
145error:
146 *ep = s;
147 strfilter_node__delete(root.r);
148 return NULL;
149}
150
151/*
152 * Parse filter rule and return new strfilter.
153 * Return NULL if fail, and *ep == NULL if memory allocation failed.
154 */
155struct strfilter *strfilter__new(const char *rules, const char **err)
156{
157 struct strfilter *ret = zalloc(sizeof(struct strfilter));
158 const char *ep = NULL;
159
160 if (ret)
161 ret->root = strfilter_node__new(rules, &ep);
162
163 if (!ret || !ret->root || *ep != '\0') {
164 if (err)
165 *err = ep;
166 strfilter__delete(ret);
167 ret = NULL;
168 }
169
170 return ret;
171}
172
173static bool strfilter_node__compare(struct strfilter_node *self,
174 const char *str)
175{
176 if (!self || !self->p)
177 return false;
178
179 switch (*self->p) {
180 case '|': /* OR */
181 return strfilter_node__compare(self->l, str) ||
182 strfilter_node__compare(self->r, str);
183 case '&': /* AND */
184 return strfilter_node__compare(self->l, str) &&
185 strfilter_node__compare(self->r, str);
186 case '!': /* NOT */
187 return !strfilter_node__compare(self->r, str);
188 default:
189 return strglobmatch(str, self->p);
190 }
191}
192
193/* Return true if STR matches the filter rules */
194bool strfilter__compare(struct strfilter *self, const char *str)
195{
196 if (!self)
197 return false;
198 return strfilter_node__compare(self->root, str);
199}
diff --git a/tools/perf/util/strfilter.h b/tools/perf/util/strfilter.h
new file mode 100644
index 000000000000..00f58a7506de
--- /dev/null
+++ b/tools/perf/util/strfilter.h
@@ -0,0 +1,48 @@
1#ifndef __PERF_STRFILTER_H
2#define __PERF_STRFILTER_H
3/* General purpose glob matching filter */
4
5#include <linux/list.h>
6#include <stdbool.h>
7
8/* A node of string filter */
9struct strfilter_node {
10 struct strfilter_node *l; /* Tree left branche (for &,|) */
11 struct strfilter_node *r; /* Tree right branche (for !,&,|) */
12 const char *p; /* Operator or rule */
13};
14
15/* String filter */
16struct strfilter {
17 struct strfilter_node *root;
18};
19
20/**
21 * strfilter__new - Create a new string filter
22 * @rules: Filter rule, which is a combination of glob expressions.
23 * @err: Pointer which points an error detected on @rules
24 *
25 * Parse @rules and return new strfilter. Return NULL if an error detected.
26 * In that case, *@err will indicate where it is detected, and *@err is NULL
27 * if a memory allocation is failed.
28 */
29struct strfilter *strfilter__new(const char *rules, const char **err);
30
31/**
32 * strfilter__compare - compare given string and a string filter
33 * @self: String filter
34 * @str: target string
35 *
36 * Compare @str and @self. Return true if the str match the rule
37 */
38bool strfilter__compare(struct strfilter *self, const char *str);
39
40/**
41 * strfilter__delete - delete a string filter
42 * @self: String filter to delete
43 *
44 * Delete @self.
45 */
46void strfilter__delete(struct strfilter *self);
47
48#endif
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index 8fc0bd3a3a4a..d5836382ff2c 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -85,7 +85,7 @@ out:
85 85
86/* 86/*
87 * Helper function for splitting a string into an argv-like array. 87 * Helper function for splitting a string into an argv-like array.
88 * originaly copied from lib/argv_split.c 88 * originally copied from lib/argv_split.c
89 */ 89 */
90static const char *skip_sep(const char *cp) 90static const char *skip_sep(const char *cp)
91{ 91{
@@ -294,3 +294,22 @@ bool strlazymatch(const char *str, const char *pat)
294{ 294{
295 return __match_glob(str, pat, true); 295 return __match_glob(str, pat, true);
296} 296}
297
298/**
299 * strtailcmp - Compare the tail of two strings
300 * @s1: 1st string to be compared
301 * @s2: 2nd string to be compared
302 *
303 * Return 0 if whole of either string is same as another's tail part.
304 */
305int strtailcmp(const char *s1, const char *s2)
306{
307 int i1 = strlen(s1);
308 int i2 = strlen(s2);
309 while (--i1 >= 0 && --i2 >= 0) {
310 if (s1[i1] != s2[i2])
311 return s1[i1] - s2[i2];
312 }
313 return 0;
314}
315
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 7821d0e6866f..a8b53714542a 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -31,13 +31,13 @@
31#define NT_GNU_BUILD_ID 3 31#define NT_GNU_BUILD_ID 3
32#endif 32#endif
33 33
34static bool dso__build_id_equal(const struct dso *self, u8 *build_id); 34static bool dso__build_id_equal(const struct dso *dso, u8 *build_id);
35static int elf_read_build_id(Elf *elf, void *bf, size_t size); 35static int elf_read_build_id(Elf *elf, void *bf, size_t size);
36static void dsos__add(struct list_head *head, struct dso *dso); 36static void dsos__add(struct list_head *head, struct dso *dso);
37static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 37static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
38static int dso__load_kernel_sym(struct dso *self, struct map *map, 38static int dso__load_kernel_sym(struct dso *dso, struct map *map,
39 symbol_filter_t filter); 39 symbol_filter_t filter);
40static int dso__load_guest_kernel_sym(struct dso *self, struct map *map, 40static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
41 symbol_filter_t filter); 41 symbol_filter_t filter);
42static int vmlinux_path__nr_entries; 42static int vmlinux_path__nr_entries;
43static char **vmlinux_path; 43static char **vmlinux_path;
@@ -49,27 +49,27 @@ struct symbol_conf symbol_conf = {
49 .symfs = "", 49 .symfs = "",
50}; 50};
51 51
52int dso__name_len(const struct dso *self) 52int dso__name_len(const struct dso *dso)
53{ 53{
54 if (verbose) 54 if (verbose)
55 return self->long_name_len; 55 return dso->long_name_len;
56 56
57 return self->short_name_len; 57 return dso->short_name_len;
58} 58}
59 59
60bool dso__loaded(const struct dso *self, enum map_type type) 60bool dso__loaded(const struct dso *dso, enum map_type type)
61{ 61{
62 return self->loaded & (1 << type); 62 return dso->loaded & (1 << type);
63} 63}
64 64
65bool dso__sorted_by_name(const struct dso *self, enum map_type type) 65bool dso__sorted_by_name(const struct dso *dso, enum map_type type)
66{ 66{
67 return self->sorted_by_name & (1 << type); 67 return dso->sorted_by_name & (1 << type);
68} 68}
69 69
70static void dso__set_sorted_by_name(struct dso *self, enum map_type type) 70static void dso__set_sorted_by_name(struct dso *dso, enum map_type type)
71{ 71{
72 self->sorted_by_name |= (1 << type); 72 dso->sorted_by_name |= (1 << type);
73} 73}
74 74
75bool symbol_type__is_a(char symbol_type, enum map_type map_type) 75bool symbol_type__is_a(char symbol_type, enum map_type map_type)
@@ -84,9 +84,9 @@ bool symbol_type__is_a(char symbol_type, enum map_type map_type)
84 } 84 }
85} 85}
86 86
87static void symbols__fixup_end(struct rb_root *self) 87static void symbols__fixup_end(struct rb_root *symbols)
88{ 88{
89 struct rb_node *nd, *prevnd = rb_first(self); 89 struct rb_node *nd, *prevnd = rb_first(symbols);
90 struct symbol *curr, *prev; 90 struct symbol *curr, *prev;
91 91
92 if (prevnd == NULL) 92 if (prevnd == NULL)
@@ -107,10 +107,10 @@ static void symbols__fixup_end(struct rb_root *self)
107 curr->end = roundup(curr->start, 4096); 107 curr->end = roundup(curr->start, 4096);
108} 108}
109 109
110static void __map_groups__fixup_end(struct map_groups *self, enum map_type type) 110static void __map_groups__fixup_end(struct map_groups *mg, enum map_type type)
111{ 111{
112 struct map *prev, *curr; 112 struct map *prev, *curr;
113 struct rb_node *nd, *prevnd = rb_first(&self->maps[type]); 113 struct rb_node *nd, *prevnd = rb_first(&mg->maps[type]);
114 114
115 if (prevnd == NULL) 115 if (prevnd == NULL)
116 return; 116 return;
@@ -130,129 +130,128 @@ static void __map_groups__fixup_end(struct map_groups *self, enum map_type type)
130 curr->end = ~0ULL; 130 curr->end = ~0ULL;
131} 131}
132 132
133static void map_groups__fixup_end(struct map_groups *self) 133static void map_groups__fixup_end(struct map_groups *mg)
134{ 134{
135 int i; 135 int i;
136 for (i = 0; i < MAP__NR_TYPES; ++i) 136 for (i = 0; i < MAP__NR_TYPES; ++i)
137 __map_groups__fixup_end(self, i); 137 __map_groups__fixup_end(mg, i);
138} 138}
139 139
140static struct symbol *symbol__new(u64 start, u64 len, u8 binding, 140static struct symbol *symbol__new(u64 start, u64 len, u8 binding,
141 const char *name) 141 const char *name)
142{ 142{
143 size_t namelen = strlen(name) + 1; 143 size_t namelen = strlen(name) + 1;
144 struct symbol *self = calloc(1, (symbol_conf.priv_size + 144 struct symbol *sym = calloc(1, (symbol_conf.priv_size +
145 sizeof(*self) + namelen)); 145 sizeof(*sym) + namelen));
146 if (self == NULL) 146 if (sym == NULL)
147 return NULL; 147 return NULL;
148 148
149 if (symbol_conf.priv_size) 149 if (symbol_conf.priv_size)
150 self = ((void *)self) + symbol_conf.priv_size; 150 sym = ((void *)sym) + symbol_conf.priv_size;
151
152 self->start = start;
153 self->end = len ? start + len - 1 : start;
154 self->binding = binding;
155 self->namelen = namelen - 1;
156 151
157 pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n", __func__, name, start, self->end); 152 sym->start = start;
153 sym->end = len ? start + len - 1 : start;
154 sym->binding = binding;
155 sym->namelen = namelen - 1;
158 156
159 memcpy(self->name, name, namelen); 157 pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n",
158 __func__, name, start, sym->end);
159 memcpy(sym->name, name, namelen);
160 160
161 return self; 161 return sym;
162} 162}
163 163
164void symbol__delete(struct symbol *self) 164void symbol__delete(struct symbol *sym)
165{ 165{
166 free(((void *)self) - symbol_conf.priv_size); 166 free(((void *)sym) - symbol_conf.priv_size);
167} 167}
168 168
169static size_t symbol__fprintf(struct symbol *self, FILE *fp) 169static size_t symbol__fprintf(struct symbol *sym, FILE *fp)
170{ 170{
171 return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n", 171 return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n",
172 self->start, self->end, 172 sym->start, sym->end,
173 self->binding == STB_GLOBAL ? 'g' : 173 sym->binding == STB_GLOBAL ? 'g' :
174 self->binding == STB_LOCAL ? 'l' : 'w', 174 sym->binding == STB_LOCAL ? 'l' : 'w',
175 self->name); 175 sym->name);
176} 176}
177 177
178void dso__set_long_name(struct dso *self, char *name) 178void dso__set_long_name(struct dso *dso, char *name)
179{ 179{
180 if (name == NULL) 180 if (name == NULL)
181 return; 181 return;
182 self->long_name = name; 182 dso->long_name = name;
183 self->long_name_len = strlen(name); 183 dso->long_name_len = strlen(name);
184} 184}
185 185
186static void dso__set_short_name(struct dso *self, const char *name) 186static void dso__set_short_name(struct dso *dso, const char *name)
187{ 187{
188 if (name == NULL) 188 if (name == NULL)
189 return; 189 return;
190 self->short_name = name; 190 dso->short_name = name;
191 self->short_name_len = strlen(name); 191 dso->short_name_len = strlen(name);
192} 192}
193 193
194static void dso__set_basename(struct dso *self) 194static void dso__set_basename(struct dso *dso)
195{ 195{
196 dso__set_short_name(self, basename(self->long_name)); 196 dso__set_short_name(dso, basename(dso->long_name));
197} 197}
198 198
199struct dso *dso__new(const char *name) 199struct dso *dso__new(const char *name)
200{ 200{
201 struct dso *self = calloc(1, sizeof(*self) + strlen(name) + 1); 201 struct dso *dso = calloc(1, sizeof(*dso) + strlen(name) + 1);
202 202
203 if (self != NULL) { 203 if (dso != NULL) {
204 int i; 204 int i;
205 strcpy(self->name, name); 205 strcpy(dso->name, name);
206 dso__set_long_name(self, self->name); 206 dso__set_long_name(dso, dso->name);
207 dso__set_short_name(self, self->name); 207 dso__set_short_name(dso, dso->name);
208 for (i = 0; i < MAP__NR_TYPES; ++i) 208 for (i = 0; i < MAP__NR_TYPES; ++i)
209 self->symbols[i] = self->symbol_names[i] = RB_ROOT; 209 dso->symbols[i] = dso->symbol_names[i] = RB_ROOT;
210 self->slen_calculated = 0; 210 dso->symtab_type = SYMTAB__NOT_FOUND;
211 self->origin = DSO__ORIG_NOT_FOUND; 211 dso->loaded = 0;
212 self->loaded = 0; 212 dso->sorted_by_name = 0;
213 self->sorted_by_name = 0; 213 dso->has_build_id = 0;
214 self->has_build_id = 0; 214 dso->kernel = DSO_TYPE_USER;
215 self->kernel = DSO_TYPE_USER; 215 INIT_LIST_HEAD(&dso->node);
216 INIT_LIST_HEAD(&self->node);
217 } 216 }
218 217
219 return self; 218 return dso;
220} 219}
221 220
222static void symbols__delete(struct rb_root *self) 221static void symbols__delete(struct rb_root *symbols)
223{ 222{
224 struct symbol *pos; 223 struct symbol *pos;
225 struct rb_node *next = rb_first(self); 224 struct rb_node *next = rb_first(symbols);
226 225
227 while (next) { 226 while (next) {
228 pos = rb_entry(next, struct symbol, rb_node); 227 pos = rb_entry(next, struct symbol, rb_node);
229 next = rb_next(&pos->rb_node); 228 next = rb_next(&pos->rb_node);
230 rb_erase(&pos->rb_node, self); 229 rb_erase(&pos->rb_node, symbols);
231 symbol__delete(pos); 230 symbol__delete(pos);
232 } 231 }
233} 232}
234 233
235void dso__delete(struct dso *self) 234void dso__delete(struct dso *dso)
236{ 235{
237 int i; 236 int i;
238 for (i = 0; i < MAP__NR_TYPES; ++i) 237 for (i = 0; i < MAP__NR_TYPES; ++i)
239 symbols__delete(&self->symbols[i]); 238 symbols__delete(&dso->symbols[i]);
240 if (self->sname_alloc) 239 if (dso->sname_alloc)
241 free((char *)self->short_name); 240 free((char *)dso->short_name);
242 if (self->lname_alloc) 241 if (dso->lname_alloc)
243 free(self->long_name); 242 free(dso->long_name);
244 free(self); 243 free(dso);
245} 244}
246 245
247void dso__set_build_id(struct dso *self, void *build_id) 246void dso__set_build_id(struct dso *dso, void *build_id)
248{ 247{
249 memcpy(self->build_id, build_id, sizeof(self->build_id)); 248 memcpy(dso->build_id, build_id, sizeof(dso->build_id));
250 self->has_build_id = 1; 249 dso->has_build_id = 1;
251} 250}
252 251
253static void symbols__insert(struct rb_root *self, struct symbol *sym) 252static void symbols__insert(struct rb_root *symbols, struct symbol *sym)
254{ 253{
255 struct rb_node **p = &self->rb_node; 254 struct rb_node **p = &symbols->rb_node;
256 struct rb_node *parent = NULL; 255 struct rb_node *parent = NULL;
257 const u64 ip = sym->start; 256 const u64 ip = sym->start;
258 struct symbol *s; 257 struct symbol *s;
@@ -266,17 +265,17 @@ static void symbols__insert(struct rb_root *self, struct symbol *sym)
266 p = &(*p)->rb_right; 265 p = &(*p)->rb_right;
267 } 266 }
268 rb_link_node(&sym->rb_node, parent, p); 267 rb_link_node(&sym->rb_node, parent, p);
269 rb_insert_color(&sym->rb_node, self); 268 rb_insert_color(&sym->rb_node, symbols);
270} 269}
271 270
272static struct symbol *symbols__find(struct rb_root *self, u64 ip) 271static struct symbol *symbols__find(struct rb_root *symbols, u64 ip)
273{ 272{
274 struct rb_node *n; 273 struct rb_node *n;
275 274
276 if (self == NULL) 275 if (symbols == NULL)
277 return NULL; 276 return NULL;
278 277
279 n = self->rb_node; 278 n = symbols->rb_node;
280 279
281 while (n) { 280 while (n) {
282 struct symbol *s = rb_entry(n, struct symbol, rb_node); 281 struct symbol *s = rb_entry(n, struct symbol, rb_node);
@@ -297,9 +296,9 @@ struct symbol_name_rb_node {
297 struct symbol sym; 296 struct symbol sym;
298}; 297};
299 298
300static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym) 299static void symbols__insert_by_name(struct rb_root *symbols, struct symbol *sym)
301{ 300{
302 struct rb_node **p = &self->rb_node; 301 struct rb_node **p = &symbols->rb_node;
303 struct rb_node *parent = NULL; 302 struct rb_node *parent = NULL;
304 struct symbol_name_rb_node *symn, *s; 303 struct symbol_name_rb_node *symn, *s;
305 304
@@ -314,27 +313,29 @@ static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym)
314 p = &(*p)->rb_right; 313 p = &(*p)->rb_right;
315 } 314 }
316 rb_link_node(&symn->rb_node, parent, p); 315 rb_link_node(&symn->rb_node, parent, p);
317 rb_insert_color(&symn->rb_node, self); 316 rb_insert_color(&symn->rb_node, symbols);
318} 317}
319 318
320static void symbols__sort_by_name(struct rb_root *self, struct rb_root *source) 319static void symbols__sort_by_name(struct rb_root *symbols,
320 struct rb_root *source)
321{ 321{
322 struct rb_node *nd; 322 struct rb_node *nd;
323 323
324 for (nd = rb_first(source); nd; nd = rb_next(nd)) { 324 for (nd = rb_first(source); nd; nd = rb_next(nd)) {
325 struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 325 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
326 symbols__insert_by_name(self, pos); 326 symbols__insert_by_name(symbols, pos);
327 } 327 }
328} 328}
329 329
330static struct symbol *symbols__find_by_name(struct rb_root *self, const char *name) 330static struct symbol *symbols__find_by_name(struct rb_root *symbols,
331 const char *name)
331{ 332{
332 struct rb_node *n; 333 struct rb_node *n;
333 334
334 if (self == NULL) 335 if (symbols == NULL)
335 return NULL; 336 return NULL;
336 337
337 n = self->rb_node; 338 n = symbols->rb_node;
338 339
339 while (n) { 340 while (n) {
340 struct symbol_name_rb_node *s; 341 struct symbol_name_rb_node *s;
@@ -354,29 +355,29 @@ static struct symbol *symbols__find_by_name(struct rb_root *self, const char *na
354 return NULL; 355 return NULL;
355} 356}
356 357
357struct symbol *dso__find_symbol(struct dso *self, 358struct symbol *dso__find_symbol(struct dso *dso,
358 enum map_type type, u64 addr) 359 enum map_type type, u64 addr)
359{ 360{
360 return symbols__find(&self->symbols[type], addr); 361 return symbols__find(&dso->symbols[type], addr);
361} 362}
362 363
363struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type, 364struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
364 const char *name) 365 const char *name)
365{ 366{
366 return symbols__find_by_name(&self->symbol_names[type], name); 367 return symbols__find_by_name(&dso->symbol_names[type], name);
367} 368}
368 369
369void dso__sort_by_name(struct dso *self, enum map_type type) 370void dso__sort_by_name(struct dso *dso, enum map_type type)
370{ 371{
371 dso__set_sorted_by_name(self, type); 372 dso__set_sorted_by_name(dso, type);
372 return symbols__sort_by_name(&self->symbol_names[type], 373 return symbols__sort_by_name(&dso->symbol_names[type],
373 &self->symbols[type]); 374 &dso->symbols[type]);
374} 375}
375 376
376int build_id__sprintf(const u8 *self, int len, char *bf) 377int build_id__sprintf(const u8 *build_id, int len, char *bf)
377{ 378{
378 char *bid = bf; 379 char *bid = bf;
379 const u8 *raw = self; 380 const u8 *raw = build_id;
380 int i; 381 int i;
381 382
382 for (i = 0; i < len; ++i) { 383 for (i = 0; i < len; ++i) {
@@ -385,24 +386,25 @@ int build_id__sprintf(const u8 *self, int len, char *bf)
385 bid += 2; 386 bid += 2;
386 } 387 }
387 388
388 return raw - self; 389 return raw - build_id;
389} 390}
390 391
391size_t dso__fprintf_buildid(struct dso *self, FILE *fp) 392size_t dso__fprintf_buildid(struct dso *dso, FILE *fp)
392{ 393{
393 char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 394 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
394 395
395 build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id); 396 build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
396 return fprintf(fp, "%s", sbuild_id); 397 return fprintf(fp, "%s", sbuild_id);
397} 398}
398 399
399size_t dso__fprintf_symbols_by_name(struct dso *self, enum map_type type, FILE *fp) 400size_t dso__fprintf_symbols_by_name(struct dso *dso,
401 enum map_type type, FILE *fp)
400{ 402{
401 size_t ret = 0; 403 size_t ret = 0;
402 struct rb_node *nd; 404 struct rb_node *nd;
403 struct symbol_name_rb_node *pos; 405 struct symbol_name_rb_node *pos;
404 406
405 for (nd = rb_first(&self->symbol_names[type]); nd; nd = rb_next(nd)) { 407 for (nd = rb_first(&dso->symbol_names[type]); nd; nd = rb_next(nd)) {
406 pos = rb_entry(nd, struct symbol_name_rb_node, rb_node); 408 pos = rb_entry(nd, struct symbol_name_rb_node, rb_node);
407 fprintf(fp, "%s\n", pos->sym.name); 409 fprintf(fp, "%s\n", pos->sym.name);
408 } 410 }
@@ -410,18 +412,18 @@ size_t dso__fprintf_symbols_by_name(struct dso *self, enum map_type type, FILE *
410 return ret; 412 return ret;
411} 413}
412 414
413size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp) 415size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp)
414{ 416{
415 struct rb_node *nd; 417 struct rb_node *nd;
416 size_t ret = fprintf(fp, "dso: %s (", self->short_name); 418 size_t ret = fprintf(fp, "dso: %s (", dso->short_name);
417 419
418 if (self->short_name != self->long_name) 420 if (dso->short_name != dso->long_name)
419 ret += fprintf(fp, "%s, ", self->long_name); 421 ret += fprintf(fp, "%s, ", dso->long_name);
420 ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type], 422 ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type],
421 self->loaded ? "" : "NOT "); 423 dso->loaded ? "" : "NOT ");
422 ret += dso__fprintf_buildid(self, fp); 424 ret += dso__fprintf_buildid(dso, fp);
423 ret += fprintf(fp, ")\n"); 425 ret += fprintf(fp, ")\n");
424 for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) { 426 for (nd = rb_first(&dso->symbols[type]); nd; nd = rb_next(nd)) {
425 struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 427 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
426 ret += symbol__fprintf(pos, fp); 428 ret += symbol__fprintf(pos, fp);
427 } 429 }
@@ -544,10 +546,10 @@ static int map__process_kallsym_symbol(void *arg, const char *name,
544 * so that we can in the next step set the symbol ->end address and then 546 * so that we can in the next step set the symbol ->end address and then
545 * call kernel_maps__split_kallsyms. 547 * call kernel_maps__split_kallsyms.
546 */ 548 */
547static int dso__load_all_kallsyms(struct dso *self, const char *filename, 549static int dso__load_all_kallsyms(struct dso *dso, const char *filename,
548 struct map *map) 550 struct map *map)
549{ 551{
550 struct process_kallsyms_args args = { .map = map, .dso = self, }; 552 struct process_kallsyms_args args = { .map = map, .dso = dso, };
551 return kallsyms__parse(filename, &args, map__process_kallsym_symbol); 553 return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
552} 554}
553 555
@@ -556,7 +558,7 @@ static int dso__load_all_kallsyms(struct dso *self, const char *filename,
556 * kernel range is broken in several maps, named [kernel].N, as we don't have 558 * kernel range is broken in several maps, named [kernel].N, as we don't have
557 * the original ELF section names vmlinux have. 559 * the original ELF section names vmlinux have.
558 */ 560 */
559static int dso__split_kallsyms(struct dso *self, struct map *map, 561static int dso__split_kallsyms(struct dso *dso, struct map *map,
560 symbol_filter_t filter) 562 symbol_filter_t filter)
561{ 563{
562 struct map_groups *kmaps = map__kmap(map)->kmaps; 564 struct map_groups *kmaps = map__kmap(map)->kmaps;
@@ -564,7 +566,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
564 struct map *curr_map = map; 566 struct map *curr_map = map;
565 struct symbol *pos; 567 struct symbol *pos;
566 int count = 0, moved = 0; 568 int count = 0, moved = 0;
567 struct rb_root *root = &self->symbols[map->type]; 569 struct rb_root *root = &dso->symbols[map->type];
568 struct rb_node *next = rb_first(root); 570 struct rb_node *next = rb_first(root);
569 int kernel_range = 0; 571 int kernel_range = 0;
570 572
@@ -583,7 +585,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
583 585
584 if (strcmp(curr_map->dso->short_name, module)) { 586 if (strcmp(curr_map->dso->short_name, module)) {
585 if (curr_map != map && 587 if (curr_map != map &&
586 self->kernel == DSO_TYPE_GUEST_KERNEL && 588 dso->kernel == DSO_TYPE_GUEST_KERNEL &&
587 machine__is_default_guest(machine)) { 589 machine__is_default_guest(machine)) {
588 /* 590 /*
589 * We assume all symbols of a module are 591 * We assume all symbols of a module are
@@ -619,14 +621,14 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
619 pos->end = curr_map->map_ip(curr_map, pos->end); 621 pos->end = curr_map->map_ip(curr_map, pos->end);
620 } else if (curr_map != map) { 622 } else if (curr_map != map) {
621 char dso_name[PATH_MAX]; 623 char dso_name[PATH_MAX];
622 struct dso *dso; 624 struct dso *ndso;
623 625
624 if (count == 0) { 626 if (count == 0) {
625 curr_map = map; 627 curr_map = map;
626 goto filter_symbol; 628 goto filter_symbol;
627 } 629 }
628 630
629 if (self->kernel == DSO_TYPE_GUEST_KERNEL) 631 if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
630 snprintf(dso_name, sizeof(dso_name), 632 snprintf(dso_name, sizeof(dso_name),
631 "[guest.kernel].%d", 633 "[guest.kernel].%d",
632 kernel_range++); 634 kernel_range++);
@@ -635,15 +637,15 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
635 "[kernel].%d", 637 "[kernel].%d",
636 kernel_range++); 638 kernel_range++);
637 639
638 dso = dso__new(dso_name); 640 ndso = dso__new(dso_name);
639 if (dso == NULL) 641 if (ndso == NULL)
640 return -1; 642 return -1;
641 643
642 dso->kernel = self->kernel; 644 ndso->kernel = dso->kernel;
643 645
644 curr_map = map__new2(pos->start, dso, map->type); 646 curr_map = map__new2(pos->start, ndso, map->type);
645 if (curr_map == NULL) { 647 if (curr_map == NULL) {
646 dso__delete(dso); 648 dso__delete(ndso);
647 return -1; 649 return -1;
648 } 650 }
649 651
@@ -666,7 +668,7 @@ discard_symbol: rb_erase(&pos->rb_node, root);
666 } 668 }
667 669
668 if (curr_map != map && 670 if (curr_map != map &&
669 self->kernel == DSO_TYPE_GUEST_KERNEL && 671 dso->kernel == DSO_TYPE_GUEST_KERNEL &&
670 machine__is_default_guest(kmaps->machine)) { 672 machine__is_default_guest(kmaps->machine)) {
671 dso__set_loaded(curr_map->dso, curr_map->type); 673 dso__set_loaded(curr_map->dso, curr_map->type);
672 } 674 }
@@ -674,21 +676,42 @@ discard_symbol: rb_erase(&pos->rb_node, root);
674 return count + moved; 676 return count + moved;
675} 677}
676 678
677int dso__load_kallsyms(struct dso *self, const char *filename, 679static bool symbol__restricted_filename(const char *filename,
680 const char *restricted_filename)
681{
682 bool restricted = false;
683
684 if (symbol_conf.kptr_restrict) {
685 char *r = realpath(filename, NULL);
686
687 if (r != NULL) {
688 restricted = strcmp(r, restricted_filename) == 0;
689 free(r);
690 return restricted;
691 }
692 }
693
694 return restricted;
695}
696
697int dso__load_kallsyms(struct dso *dso, const char *filename,
678 struct map *map, symbol_filter_t filter) 698 struct map *map, symbol_filter_t filter)
679{ 699{
680 if (dso__load_all_kallsyms(self, filename, map) < 0) 700 if (symbol__restricted_filename(filename, "/proc/kallsyms"))
681 return -1; 701 return -1;
682 702
683 if (self->kernel == DSO_TYPE_GUEST_KERNEL) 703 if (dso__load_all_kallsyms(dso, filename, map) < 0)
684 self->origin = DSO__ORIG_GUEST_KERNEL; 704 return -1;
705
706 if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
707 dso->symtab_type = SYMTAB__GUEST_KALLSYMS;
685 else 708 else
686 self->origin = DSO__ORIG_KERNEL; 709 dso->symtab_type = SYMTAB__KALLSYMS;
687 710
688 return dso__split_kallsyms(self, map, filter); 711 return dso__split_kallsyms(dso, map, filter);
689} 712}
690 713
691static int dso__load_perf_map(struct dso *self, struct map *map, 714static int dso__load_perf_map(struct dso *dso, struct map *map,
692 symbol_filter_t filter) 715 symbol_filter_t filter)
693{ 716{
694 char *line = NULL; 717 char *line = NULL;
@@ -696,7 +719,7 @@ static int dso__load_perf_map(struct dso *self, struct map *map,
696 FILE *file; 719 FILE *file;
697 int nr_syms = 0; 720 int nr_syms = 0;
698 721
699 file = fopen(self->long_name, "r"); 722 file = fopen(dso->long_name, "r");
700 if (file == NULL) 723 if (file == NULL)
701 goto out_failure; 724 goto out_failure;
702 725
@@ -734,7 +757,7 @@ static int dso__load_perf_map(struct dso *self, struct map *map,
734 if (filter && filter(map, sym)) 757 if (filter && filter(map, sym))
735 symbol__delete(sym); 758 symbol__delete(sym);
736 else { 759 else {
737 symbols__insert(&self->symbols[map->type], sym); 760 symbols__insert(&dso->symbols[map->type], sym);
738 nr_syms++; 761 nr_syms++;
739 } 762 }
740 } 763 }
@@ -753,7 +776,7 @@ out_failure:
753/** 776/**
754 * elf_symtab__for_each_symbol - iterate thru all the symbols 777 * elf_symtab__for_each_symbol - iterate thru all the symbols
755 * 778 *
756 * @self: struct elf_symtab instance to iterate 779 * @syms: struct elf_symtab instance to iterate
757 * @idx: uint32_t idx 780 * @idx: uint32_t idx
758 * @sym: GElf_Sym iterator 781 * @sym: GElf_Sym iterator
759 */ 782 */
@@ -853,7 +876,7 @@ static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
853 * And always look at the original dso, not at debuginfo packages, that 876 * And always look at the original dso, not at debuginfo packages, that
854 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). 877 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
855 */ 878 */
856static int dso__synthesize_plt_symbols(struct dso *self, struct map *map, 879static int dso__synthesize_plt_symbols(struct dso *dso, struct map *map,
857 symbol_filter_t filter) 880 symbol_filter_t filter)
858{ 881{
859 uint32_t nr_rel_entries, idx; 882 uint32_t nr_rel_entries, idx;
@@ -872,7 +895,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, struct map *map,
872 char name[PATH_MAX]; 895 char name[PATH_MAX];
873 896
874 snprintf(name, sizeof(name), "%s%s", 897 snprintf(name, sizeof(name), "%s%s",
875 symbol_conf.symfs, self->long_name); 898 symbol_conf.symfs, dso->long_name);
876 fd = open(name, O_RDONLY); 899 fd = open(name, O_RDONLY);
877 if (fd < 0) 900 if (fd < 0)
878 goto out; 901 goto out;
@@ -948,7 +971,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, struct map *map,
948 if (filter && filter(map, f)) 971 if (filter && filter(map, f))
949 symbol__delete(f); 972 symbol__delete(f);
950 else { 973 else {
951 symbols__insert(&self->symbols[map->type], f); 974 symbols__insert(&dso->symbols[map->type], f);
952 ++nr; 975 ++nr;
953 } 976 }
954 } 977 }
@@ -970,7 +993,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, struct map *map,
970 if (filter && filter(map, f)) 993 if (filter && filter(map, f))
971 symbol__delete(f); 994 symbol__delete(f);
972 else { 995 else {
973 symbols__insert(&self->symbols[map->type], f); 996 symbols__insert(&dso->symbols[map->type], f);
974 ++nr; 997 ++nr;
975 } 998 }
976 } 999 }
@@ -986,29 +1009,30 @@ out_close:
986 return nr; 1009 return nr;
987out: 1010out:
988 pr_debug("%s: problems reading %s PLT info.\n", 1011 pr_debug("%s: problems reading %s PLT info.\n",
989 __func__, self->long_name); 1012 __func__, dso->long_name);
990 return 0; 1013 return 0;
991} 1014}
992 1015
993static bool elf_sym__is_a(GElf_Sym *self, enum map_type type) 1016static bool elf_sym__is_a(GElf_Sym *sym, enum map_type type)
994{ 1017{
995 switch (type) { 1018 switch (type) {
996 case MAP__FUNCTION: 1019 case MAP__FUNCTION:
997 return elf_sym__is_function(self); 1020 return elf_sym__is_function(sym);
998 case MAP__VARIABLE: 1021 case MAP__VARIABLE:
999 return elf_sym__is_object(self); 1022 return elf_sym__is_object(sym);
1000 default: 1023 default:
1001 return false; 1024 return false;
1002 } 1025 }
1003} 1026}
1004 1027
1005static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type) 1028static bool elf_sec__is_a(GElf_Shdr *shdr, Elf_Data *secstrs,
1029 enum map_type type)
1006{ 1030{
1007 switch (type) { 1031 switch (type) {
1008 case MAP__FUNCTION: 1032 case MAP__FUNCTION:
1009 return elf_sec__is_text(self, secstrs); 1033 return elf_sec__is_text(shdr, secstrs);
1010 case MAP__VARIABLE: 1034 case MAP__VARIABLE:
1011 return elf_sec__is_data(self, secstrs); 1035 return elf_sec__is_data(shdr, secstrs);
1012 default: 1036 default:
1013 return false; 1037 return false;
1014 } 1038 }
@@ -1033,13 +1057,13 @@ static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr)
1033 return -1; 1057 return -1;
1034} 1058}
1035 1059
1036static int dso__load_sym(struct dso *self, struct map *map, const char *name, 1060static int dso__load_sym(struct dso *dso, struct map *map, const char *name,
1037 int fd, symbol_filter_t filter, int kmodule, 1061 int fd, symbol_filter_t filter, int kmodule,
1038 int want_symtab) 1062 int want_symtab)
1039{ 1063{
1040 struct kmap *kmap = self->kernel ? map__kmap(map) : NULL; 1064 struct kmap *kmap = dso->kernel ? map__kmap(map) : NULL;
1041 struct map *curr_map = map; 1065 struct map *curr_map = map;
1042 struct dso *curr_dso = self; 1066 struct dso *curr_dso = dso;
1043 Elf_Data *symstrs, *secstrs; 1067 Elf_Data *symstrs, *secstrs;
1044 uint32_t nr_syms; 1068 uint32_t nr_syms;
1045 int err = -1; 1069 int err = -1;
@@ -1065,14 +1089,14 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
1065 } 1089 }
1066 1090
1067 /* Always reject images with a mismatched build-id: */ 1091 /* Always reject images with a mismatched build-id: */
1068 if (self->has_build_id) { 1092 if (dso->has_build_id) {
1069 u8 build_id[BUILD_ID_SIZE]; 1093 u8 build_id[BUILD_ID_SIZE];
1070 1094
1071 if (elf_read_build_id(elf, build_id, 1095 if (elf_read_build_id(elf, build_id,
1072 BUILD_ID_SIZE) != BUILD_ID_SIZE) 1096 BUILD_ID_SIZE) != BUILD_ID_SIZE)
1073 goto out_elf_end; 1097 goto out_elf_end;
1074 1098
1075 if (!dso__build_id_equal(self, build_id)) 1099 if (!dso__build_id_equal(dso, build_id))
1076 goto out_elf_end; 1100 goto out_elf_end;
1077 } 1101 }
1078 1102
@@ -1113,13 +1137,14 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
1113 nr_syms = shdr.sh_size / shdr.sh_entsize; 1137 nr_syms = shdr.sh_size / shdr.sh_entsize;
1114 1138
1115 memset(&sym, 0, sizeof(sym)); 1139 memset(&sym, 0, sizeof(sym));
1116 if (self->kernel == DSO_TYPE_USER) { 1140 if (dso->kernel == DSO_TYPE_USER) {
1117 self->adjust_symbols = (ehdr.e_type == ET_EXEC || 1141 dso->adjust_symbols = (ehdr.e_type == ET_EXEC ||
1118 elf_section_by_name(elf, &ehdr, &shdr, 1142 elf_section_by_name(elf, &ehdr, &shdr,
1119 ".gnu.prelink_undo", 1143 ".gnu.prelink_undo",
1120 NULL) != NULL); 1144 NULL) != NULL);
1121 } else self->adjust_symbols = 0; 1145 } else {
1122 1146 dso->adjust_symbols = 0;
1147 }
1123 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 1148 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
1124 struct symbol *f; 1149 struct symbol *f;
1125 const char *elf_name = elf_sym__name(&sym, symstrs); 1150 const char *elf_name = elf_sym__name(&sym, symstrs);
@@ -1169,22 +1194,22 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
1169 (sym.st_value & 1)) 1194 (sym.st_value & 1))
1170 --sym.st_value; 1195 --sym.st_value;
1171 1196
1172 if (self->kernel != DSO_TYPE_USER || kmodule) { 1197 if (dso->kernel != DSO_TYPE_USER || kmodule) {
1173 char dso_name[PATH_MAX]; 1198 char dso_name[PATH_MAX];
1174 1199
1175 if (strcmp(section_name, 1200 if (strcmp(section_name,
1176 (curr_dso->short_name + 1201 (curr_dso->short_name +
1177 self->short_name_len)) == 0) 1202 dso->short_name_len)) == 0)
1178 goto new_symbol; 1203 goto new_symbol;
1179 1204
1180 if (strcmp(section_name, ".text") == 0) { 1205 if (strcmp(section_name, ".text") == 0) {
1181 curr_map = map; 1206 curr_map = map;
1182 curr_dso = self; 1207 curr_dso = dso;
1183 goto new_symbol; 1208 goto new_symbol;
1184 } 1209 }
1185 1210
1186 snprintf(dso_name, sizeof(dso_name), 1211 snprintf(dso_name, sizeof(dso_name),
1187 "%s%s", self->short_name, section_name); 1212 "%s%s", dso->short_name, section_name);
1188 1213
1189 curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name); 1214 curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name);
1190 if (curr_map == NULL) { 1215 if (curr_map == NULL) {
@@ -1196,7 +1221,9 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
1196 curr_dso = dso__new(dso_name); 1221 curr_dso = dso__new(dso_name);
1197 if (curr_dso == NULL) 1222 if (curr_dso == NULL)
1198 goto out_elf_end; 1223 goto out_elf_end;
1199 curr_dso->kernel = self->kernel; 1224 curr_dso->kernel = dso->kernel;
1225 curr_dso->long_name = dso->long_name;
1226 curr_dso->long_name_len = dso->long_name_len;
1200 curr_map = map__new2(start, curr_dso, 1227 curr_map = map__new2(start, curr_dso,
1201 map->type); 1228 map->type);
1202 if (curr_map == NULL) { 1229 if (curr_map == NULL) {
@@ -1205,9 +1232,9 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
1205 } 1232 }
1206 curr_map->map_ip = identity__map_ip; 1233 curr_map->map_ip = identity__map_ip;
1207 curr_map->unmap_ip = identity__map_ip; 1234 curr_map->unmap_ip = identity__map_ip;
1208 curr_dso->origin = self->origin; 1235 curr_dso->symtab_type = dso->symtab_type;
1209 map_groups__insert(kmap->kmaps, curr_map); 1236 map_groups__insert(kmap->kmaps, curr_map);
1210 dsos__add(&self->node, curr_dso); 1237 dsos__add(&dso->node, curr_dso);
1211 dso__set_loaded(curr_dso, map->type); 1238 dso__set_loaded(curr_dso, map->type);
1212 } else 1239 } else
1213 curr_dso = curr_map->dso; 1240 curr_dso = curr_map->dso;
@@ -1249,7 +1276,7 @@ new_symbol:
1249 * For misannotated, zeroed, ASM function sizes. 1276 * For misannotated, zeroed, ASM function sizes.
1250 */ 1277 */
1251 if (nr > 0) { 1278 if (nr > 0) {
1252 symbols__fixup_end(&self->symbols[map->type]); 1279 symbols__fixup_end(&dso->symbols[map->type]);
1253 if (kmap) { 1280 if (kmap) {
1254 /* 1281 /*
1255 * We need to fixup this here too because we create new 1282 * We need to fixup this here too because we create new
@@ -1265,9 +1292,9 @@ out_close:
1265 return err; 1292 return err;
1266} 1293}
1267 1294
1268static bool dso__build_id_equal(const struct dso *self, u8 *build_id) 1295static bool dso__build_id_equal(const struct dso *dso, u8 *build_id)
1269{ 1296{
1270 return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0; 1297 return memcmp(dso->build_id, build_id, sizeof(dso->build_id)) == 0;
1271} 1298}
1272 1299
1273bool __dsos__read_build_ids(struct list_head *head, bool with_hits) 1300bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
@@ -1428,27 +1455,27 @@ out:
1428 return err; 1455 return err;
1429} 1456}
1430 1457
1431char dso__symtab_origin(const struct dso *self) 1458char dso__symtab_origin(const struct dso *dso)
1432{ 1459{
1433 static const char origin[] = { 1460 static const char origin[] = {
1434 [DSO__ORIG_KERNEL] = 'k', 1461 [SYMTAB__KALLSYMS] = 'k',
1435 [DSO__ORIG_JAVA_JIT] = 'j', 1462 [SYMTAB__JAVA_JIT] = 'j',
1436 [DSO__ORIG_BUILD_ID_CACHE] = 'B', 1463 [SYMTAB__BUILD_ID_CACHE] = 'B',
1437 [DSO__ORIG_FEDORA] = 'f', 1464 [SYMTAB__FEDORA_DEBUGINFO] = 'f',
1438 [DSO__ORIG_UBUNTU] = 'u', 1465 [SYMTAB__UBUNTU_DEBUGINFO] = 'u',
1439 [DSO__ORIG_BUILDID] = 'b', 1466 [SYMTAB__BUILDID_DEBUGINFO] = 'b',
1440 [DSO__ORIG_DSO] = 'd', 1467 [SYMTAB__SYSTEM_PATH_DSO] = 'd',
1441 [DSO__ORIG_KMODULE] = 'K', 1468 [SYMTAB__SYSTEM_PATH_KMODULE] = 'K',
1442 [DSO__ORIG_GUEST_KERNEL] = 'g', 1469 [SYMTAB__GUEST_KALLSYMS] = 'g',
1443 [DSO__ORIG_GUEST_KMODULE] = 'G', 1470 [SYMTAB__GUEST_KMODULE] = 'G',
1444 }; 1471 };
1445 1472
1446 if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) 1473 if (dso == NULL || dso->symtab_type == SYMTAB__NOT_FOUND)
1447 return '!'; 1474 return '!';
1448 return origin[self->origin]; 1475 return origin[dso->symtab_type];
1449} 1476}
1450 1477
1451int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) 1478int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
1452{ 1479{
1453 int size = PATH_MAX; 1480 int size = PATH_MAX;
1454 char *name; 1481 char *name;
@@ -1458,12 +1485,12 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
1458 const char *root_dir; 1485 const char *root_dir;
1459 int want_symtab; 1486 int want_symtab;
1460 1487
1461 dso__set_loaded(self, map->type); 1488 dso__set_loaded(dso, map->type);
1462 1489
1463 if (self->kernel == DSO_TYPE_KERNEL) 1490 if (dso->kernel == DSO_TYPE_KERNEL)
1464 return dso__load_kernel_sym(self, map, filter); 1491 return dso__load_kernel_sym(dso, map, filter);
1465 else if (self->kernel == DSO_TYPE_GUEST_KERNEL) 1492 else if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
1466 return dso__load_guest_kernel_sym(self, map, filter); 1493 return dso__load_guest_kernel_sym(dso, map, filter);
1467 1494
1468 if (map->groups && map->groups->machine) 1495 if (map->groups && map->groups->machine)
1469 machine = map->groups->machine; 1496 machine = map->groups->machine;
@@ -1474,12 +1501,23 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
1474 if (!name) 1501 if (!name)
1475 return -1; 1502 return -1;
1476 1503
1477 self->adjust_symbols = 0; 1504 dso->adjust_symbols = 0;
1505
1506 if (strncmp(dso->name, "/tmp/perf-", 10) == 0) {
1507 struct stat st;
1508
1509 if (stat(dso->name, &st) < 0)
1510 return -1;
1511
1512 if (st.st_uid && (st.st_uid != geteuid())) {
1513 pr_warning("File %s not owned by current user or root, "
1514 "ignoring it.\n", dso->name);
1515 return -1;
1516 }
1478 1517
1479 if (strncmp(self->name, "/tmp/perf-", 10) == 0) { 1518 ret = dso__load_perf_map(dso, map, filter);
1480 ret = dso__load_perf_map(self, map, filter); 1519 dso->symtab_type = ret > 0 ? SYMTAB__JAVA_JIT :
1481 self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : 1520 SYMTAB__NOT_FOUND;
1482 DSO__ORIG_NOT_FOUND;
1483 return ret; 1521 return ret;
1484 } 1522 }
1485 1523
@@ -1487,67 +1525,59 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
1487 * On the first pass, only load images if they have a full symtab. 1525 * On the first pass, only load images if they have a full symtab.
1488 * Failing that, do a second pass where we accept .dynsym also 1526 * Failing that, do a second pass where we accept .dynsym also
1489 */ 1527 */
1490 for (self->origin = DSO__ORIG_BUILD_ID_CACHE, want_symtab = 1; 1528 want_symtab = 1;
1491 self->origin != DSO__ORIG_NOT_FOUND; 1529restart:
1492 self->origin++) { 1530 for (dso->symtab_type = SYMTAB__BUILD_ID_CACHE;
1493 switch (self->origin) { 1531 dso->symtab_type != SYMTAB__NOT_FOUND;
1494 case DSO__ORIG_BUILD_ID_CACHE: 1532 dso->symtab_type++) {
1533 switch (dso->symtab_type) {
1534 case SYMTAB__BUILD_ID_CACHE:
1495 /* skip the locally configured cache if a symfs is given */ 1535 /* skip the locally configured cache if a symfs is given */
1496 if (symbol_conf.symfs[0] || 1536 if (symbol_conf.symfs[0] ||
1497 (dso__build_id_filename(self, name, size) == NULL)) { 1537 (dso__build_id_filename(dso, name, size) == NULL)) {
1498 continue; 1538 continue;
1499 } 1539 }
1500 break; 1540 break;
1501 case DSO__ORIG_FEDORA: 1541 case SYMTAB__FEDORA_DEBUGINFO:
1502 snprintf(name, size, "%s/usr/lib/debug%s.debug", 1542 snprintf(name, size, "%s/usr/lib/debug%s.debug",
1503 symbol_conf.symfs, self->long_name); 1543 symbol_conf.symfs, dso->long_name);
1504 break; 1544 break;
1505 case DSO__ORIG_UBUNTU: 1545 case SYMTAB__UBUNTU_DEBUGINFO:
1506 snprintf(name, size, "%s/usr/lib/debug%s", 1546 snprintf(name, size, "%s/usr/lib/debug%s",
1507 symbol_conf.symfs, self->long_name); 1547 symbol_conf.symfs, dso->long_name);
1508 break; 1548 break;
1509 case DSO__ORIG_BUILDID: { 1549 case SYMTAB__BUILDID_DEBUGINFO: {
1510 char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 1550 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
1511 1551
1512 if (!self->has_build_id) 1552 if (!dso->has_build_id)
1513 continue; 1553 continue;
1514 1554
1515 build_id__sprintf(self->build_id, 1555 build_id__sprintf(dso->build_id,
1516 sizeof(self->build_id), 1556 sizeof(dso->build_id),
1517 build_id_hex); 1557 build_id_hex);
1518 snprintf(name, size, 1558 snprintf(name, size,
1519 "%s/usr/lib/debug/.build-id/%.2s/%s.debug", 1559 "%s/usr/lib/debug/.build-id/%.2s/%s.debug",
1520 symbol_conf.symfs, build_id_hex, build_id_hex + 2); 1560 symbol_conf.symfs, build_id_hex, build_id_hex + 2);
1521 } 1561 }
1522 break; 1562 break;
1523 case DSO__ORIG_DSO: 1563 case SYMTAB__SYSTEM_PATH_DSO:
1524 snprintf(name, size, "%s%s", 1564 snprintf(name, size, "%s%s",
1525 symbol_conf.symfs, self->long_name); 1565 symbol_conf.symfs, dso->long_name);
1526 break; 1566 break;
1527 case DSO__ORIG_GUEST_KMODULE: 1567 case SYMTAB__GUEST_KMODULE:
1528 if (map->groups && map->groups->machine) 1568 if (map->groups && machine)
1529 root_dir = map->groups->machine->root_dir; 1569 root_dir = machine->root_dir;
1530 else 1570 else
1531 root_dir = ""; 1571 root_dir = "";
1532 snprintf(name, size, "%s%s%s", symbol_conf.symfs, 1572 snprintf(name, size, "%s%s%s", symbol_conf.symfs,
1533 root_dir, self->long_name); 1573 root_dir, dso->long_name);
1534 break; 1574 break;
1535 1575
1536 case DSO__ORIG_KMODULE: 1576 case SYMTAB__SYSTEM_PATH_KMODULE:
1537 snprintf(name, size, "%s%s", symbol_conf.symfs, 1577 snprintf(name, size, "%s%s", symbol_conf.symfs,
1538 self->long_name); 1578 dso->long_name);
1539 break; 1579 break;
1540 1580 default:;
1541 default:
1542 /*
1543 * If we wanted a full symtab but no image had one,
1544 * relax our requirements and repeat the search.
1545 */
1546 if (want_symtab) {
1547 want_symtab = 0;
1548 self->origin = DSO__ORIG_BUILD_ID_CACHE;
1549 } else
1550 continue;
1551 } 1581 }
1552 1582
1553 /* Name is now the name of the next image to try */ 1583 /* Name is now the name of the next image to try */
@@ -1555,7 +1585,7 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
1555 if (fd < 0) 1585 if (fd < 0)
1556 continue; 1586 continue;
1557 1587
1558 ret = dso__load_sym(self, map, name, fd, filter, 0, 1588 ret = dso__load_sym(dso, map, name, fd, filter, 0,
1559 want_symtab); 1589 want_symtab);
1560 close(fd); 1590 close(fd);
1561 1591
@@ -1567,25 +1597,35 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
1567 continue; 1597 continue;
1568 1598
1569 if (ret > 0) { 1599 if (ret > 0) {
1570 int nr_plt = dso__synthesize_plt_symbols(self, map, filter); 1600 int nr_plt = dso__synthesize_plt_symbols(dso, map,
1601 filter);
1571 if (nr_plt > 0) 1602 if (nr_plt > 0)
1572 ret += nr_plt; 1603 ret += nr_plt;
1573 break; 1604 break;
1574 } 1605 }
1575 } 1606 }
1576 1607
1608 /*
1609 * If we wanted a full symtab but no image had one,
1610 * relax our requirements and repeat the search.
1611 */
1612 if (ret <= 0 && want_symtab) {
1613 want_symtab = 0;
1614 goto restart;
1615 }
1616
1577 free(name); 1617 free(name);
1578 if (ret < 0 && strstr(self->name, " (deleted)") != NULL) 1618 if (ret < 0 && strstr(dso->name, " (deleted)") != NULL)
1579 return 0; 1619 return 0;
1580 return ret; 1620 return ret;
1581} 1621}
1582 1622
1583struct map *map_groups__find_by_name(struct map_groups *self, 1623struct map *map_groups__find_by_name(struct map_groups *mg,
1584 enum map_type type, const char *name) 1624 enum map_type type, const char *name)
1585{ 1625{
1586 struct rb_node *nd; 1626 struct rb_node *nd;
1587 1627
1588 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { 1628 for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) {
1589 struct map *map = rb_entry(nd, struct map, rb_node); 1629 struct map *map = rb_entry(nd, struct map, rb_node);
1590 1630
1591 if (map->dso && strcmp(map->dso->short_name, name) == 0) 1631 if (map->dso && strcmp(map->dso->short_name, name) == 0)
@@ -1595,28 +1635,28 @@ struct map *map_groups__find_by_name(struct map_groups *self,
1595 return NULL; 1635 return NULL;
1596} 1636}
1597 1637
1598static int dso__kernel_module_get_build_id(struct dso *self, 1638static int dso__kernel_module_get_build_id(struct dso *dso,
1599 const char *root_dir) 1639 const char *root_dir)
1600{ 1640{
1601 char filename[PATH_MAX]; 1641 char filename[PATH_MAX];
1602 /* 1642 /*
1603 * kernel module short names are of the form "[module]" and 1643 * kernel module short names are of the form "[module]" and
1604 * we need just "module" here. 1644 * we need just "module" here.
1605 */ 1645 */
1606 const char *name = self->short_name + 1; 1646 const char *name = dso->short_name + 1;
1607 1647
1608 snprintf(filename, sizeof(filename), 1648 snprintf(filename, sizeof(filename),
1609 "%s/sys/module/%.*s/notes/.note.gnu.build-id", 1649 "%s/sys/module/%.*s/notes/.note.gnu.build-id",
1610 root_dir, (int)strlen(name) - 1, name); 1650 root_dir, (int)strlen(name) - 1, name);
1611 1651
1612 if (sysfs__read_build_id(filename, self->build_id, 1652 if (sysfs__read_build_id(filename, dso->build_id,
1613 sizeof(self->build_id)) == 0) 1653 sizeof(dso->build_id)) == 0)
1614 self->has_build_id = true; 1654 dso->has_build_id = true;
1615 1655
1616 return 0; 1656 return 0;
1617} 1657}
1618 1658
1619static int map_groups__set_modules_path_dir(struct map_groups *self, 1659static int map_groups__set_modules_path_dir(struct map_groups *mg,
1620 const char *dir_name) 1660 const char *dir_name)
1621{ 1661{
1622 struct dirent *dent; 1662 struct dirent *dent;
@@ -1644,7 +1684,7 @@ static int map_groups__set_modules_path_dir(struct map_groups *self,
1644 1684
1645 snprintf(path, sizeof(path), "%s/%s", 1685 snprintf(path, sizeof(path), "%s/%s",
1646 dir_name, dent->d_name); 1686 dir_name, dent->d_name);
1647 ret = map_groups__set_modules_path_dir(self, path); 1687 ret = map_groups__set_modules_path_dir(mg, path);
1648 if (ret < 0) 1688 if (ret < 0)
1649 goto out; 1689 goto out;
1650 } else { 1690 } else {
@@ -1659,7 +1699,8 @@ static int map_groups__set_modules_path_dir(struct map_groups *self,
1659 (int)(dot - dent->d_name), dent->d_name); 1699 (int)(dot - dent->d_name), dent->d_name);
1660 1700
1661 strxfrchar(dso_name, '-', '_'); 1701 strxfrchar(dso_name, '-', '_');
1662 map = map_groups__find_by_name(self, MAP__FUNCTION, dso_name); 1702 map = map_groups__find_by_name(mg, MAP__FUNCTION,
1703 dso_name);
1663 if (map == NULL) 1704 if (map == NULL)
1664 continue; 1705 continue;
1665 1706
@@ -1709,20 +1750,20 @@ static char *get_kernel_version(const char *root_dir)
1709 return strdup(name); 1750 return strdup(name);
1710} 1751}
1711 1752
1712static int machine__set_modules_path(struct machine *self) 1753static int machine__set_modules_path(struct machine *machine)
1713{ 1754{
1714 char *version; 1755 char *version;
1715 char modules_path[PATH_MAX]; 1756 char modules_path[PATH_MAX];
1716 1757
1717 version = get_kernel_version(self->root_dir); 1758 version = get_kernel_version(machine->root_dir);
1718 if (!version) 1759 if (!version)
1719 return -1; 1760 return -1;
1720 1761
1721 snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel", 1762 snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel",
1722 self->root_dir, version); 1763 machine->root_dir, version);
1723 free(version); 1764 free(version);
1724 1765
1725 return map_groups__set_modules_path_dir(&self->kmaps, modules_path); 1766 return map_groups__set_modules_path_dir(&machine->kmaps, modules_path);
1726} 1767}
1727 1768
1728/* 1769/*
@@ -1732,23 +1773,23 @@ static int machine__set_modules_path(struct machine *self)
1732 */ 1773 */
1733static struct map *map__new2(u64 start, struct dso *dso, enum map_type type) 1774static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1734{ 1775{
1735 struct map *self = calloc(1, (sizeof(*self) + 1776 struct map *map = calloc(1, (sizeof(*map) +
1736 (dso->kernel ? sizeof(struct kmap) : 0))); 1777 (dso->kernel ? sizeof(struct kmap) : 0)));
1737 if (self != NULL) { 1778 if (map != NULL) {
1738 /* 1779 /*
1739 * ->end will be filled after we load all the symbols 1780 * ->end will be filled after we load all the symbols
1740 */ 1781 */
1741 map__init(self, type, start, 0, 0, dso); 1782 map__init(map, type, start, 0, 0, dso);
1742 } 1783 }
1743 1784
1744 return self; 1785 return map;
1745} 1786}
1746 1787
1747struct map *machine__new_module(struct machine *self, u64 start, 1788struct map *machine__new_module(struct machine *machine, u64 start,
1748 const char *filename) 1789 const char *filename)
1749{ 1790{
1750 struct map *map; 1791 struct map *map;
1751 struct dso *dso = __dsos__findnew(&self->kernel_dsos, filename); 1792 struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename);
1752 1793
1753 if (dso == NULL) 1794 if (dso == NULL)
1754 return NULL; 1795 return NULL;
@@ -1757,15 +1798,15 @@ struct map *machine__new_module(struct machine *self, u64 start,
1757 if (map == NULL) 1798 if (map == NULL)
1758 return NULL; 1799 return NULL;
1759 1800
1760 if (machine__is_host(self)) 1801 if (machine__is_host(machine))
1761 dso->origin = DSO__ORIG_KMODULE; 1802 dso->symtab_type = SYMTAB__SYSTEM_PATH_KMODULE;
1762 else 1803 else
1763 dso->origin = DSO__ORIG_GUEST_KMODULE; 1804 dso->symtab_type = SYMTAB__GUEST_KMODULE;
1764 map_groups__insert(&self->kmaps, map); 1805 map_groups__insert(&machine->kmaps, map);
1765 return map; 1806 return map;
1766} 1807}
1767 1808
1768static int machine__create_modules(struct machine *self) 1809static int machine__create_modules(struct machine *machine)
1769{ 1810{
1770 char *line = NULL; 1811 char *line = NULL;
1771 size_t n; 1812 size_t n;
@@ -1774,13 +1815,16 @@ static int machine__create_modules(struct machine *self)
1774 const char *modules; 1815 const char *modules;
1775 char path[PATH_MAX]; 1816 char path[PATH_MAX];
1776 1817
1777 if (machine__is_default_guest(self)) 1818 if (machine__is_default_guest(machine))
1778 modules = symbol_conf.default_guest_modules; 1819 modules = symbol_conf.default_guest_modules;
1779 else { 1820 else {
1780 sprintf(path, "%s/proc/modules", self->root_dir); 1821 sprintf(path, "%s/proc/modules", machine->root_dir);
1781 modules = path; 1822 modules = path;
1782 } 1823 }
1783 1824
1825 if (symbol__restricted_filename(path, "/proc/modules"))
1826 return -1;
1827
1784 file = fopen(modules, "r"); 1828 file = fopen(modules, "r");
1785 if (file == NULL) 1829 if (file == NULL)
1786 return -1; 1830 return -1;
@@ -1813,16 +1857,16 @@ static int machine__create_modules(struct machine *self)
1813 *sep = '\0'; 1857 *sep = '\0';
1814 1858
1815 snprintf(name, sizeof(name), "[%s]", line); 1859 snprintf(name, sizeof(name), "[%s]", line);
1816 map = machine__new_module(self, start, name); 1860 map = machine__new_module(machine, start, name);
1817 if (map == NULL) 1861 if (map == NULL)
1818 goto out_delete_line; 1862 goto out_delete_line;
1819 dso__kernel_module_get_build_id(map->dso, self->root_dir); 1863 dso__kernel_module_get_build_id(map->dso, machine->root_dir);
1820 } 1864 }
1821 1865
1822 free(line); 1866 free(line);
1823 fclose(file); 1867 fclose(file);
1824 1868
1825 return machine__set_modules_path(self); 1869 return machine__set_modules_path(machine);
1826 1870
1827out_delete_line: 1871out_delete_line:
1828 free(line); 1872 free(line);
@@ -1830,20 +1874,21 @@ out_failure:
1830 return -1; 1874 return -1;
1831} 1875}
1832 1876
1833int dso__load_vmlinux(struct dso *self, struct map *map, 1877int dso__load_vmlinux(struct dso *dso, struct map *map,
1834 const char *vmlinux, symbol_filter_t filter) 1878 const char *vmlinux, symbol_filter_t filter)
1835{ 1879{
1836 int err = -1, fd; 1880 int err = -1, fd;
1837 char symfs_vmlinux[PATH_MAX]; 1881 char symfs_vmlinux[PATH_MAX];
1838 1882
1839 snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s/%s", 1883 snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s",
1840 symbol_conf.symfs, vmlinux); 1884 symbol_conf.symfs, vmlinux);
1841 fd = open(symfs_vmlinux, O_RDONLY); 1885 fd = open(symfs_vmlinux, O_RDONLY);
1842 if (fd < 0) 1886 if (fd < 0)
1843 return -1; 1887 return -1;
1844 1888
1845 dso__set_loaded(self, map->type); 1889 dso__set_long_name(dso, (char *)vmlinux);
1846 err = dso__load_sym(self, map, symfs_vmlinux, fd, filter, 0, 0); 1890 dso__set_loaded(dso, map->type);
1891 err = dso__load_sym(dso, map, symfs_vmlinux, fd, filter, 0, 0);
1847 close(fd); 1892 close(fd);
1848 1893
1849 if (err > 0) 1894 if (err > 0)
@@ -1852,7 +1897,7 @@ int dso__load_vmlinux(struct dso *self, struct map *map,
1852 return err; 1897 return err;
1853} 1898}
1854 1899
1855int dso__load_vmlinux_path(struct dso *self, struct map *map, 1900int dso__load_vmlinux_path(struct dso *dso, struct map *map,
1856 symbol_filter_t filter) 1901 symbol_filter_t filter)
1857{ 1902{
1858 int i, err = 0; 1903 int i, err = 0;
@@ -1861,20 +1906,20 @@ int dso__load_vmlinux_path(struct dso *self, struct map *map,
1861 pr_debug("Looking at the vmlinux_path (%d entries long)\n", 1906 pr_debug("Looking at the vmlinux_path (%d entries long)\n",
1862 vmlinux_path__nr_entries + 1); 1907 vmlinux_path__nr_entries + 1);
1863 1908
1864 filename = dso__build_id_filename(self, NULL, 0); 1909 filename = dso__build_id_filename(dso, NULL, 0);
1865 if (filename != NULL) { 1910 if (filename != NULL) {
1866 err = dso__load_vmlinux(self, map, filename, filter); 1911 err = dso__load_vmlinux(dso, map, filename, filter);
1867 if (err > 0) { 1912 if (err > 0) {
1868 dso__set_long_name(self, filename); 1913 dso__set_long_name(dso, filename);
1869 goto out; 1914 goto out;
1870 } 1915 }
1871 free(filename); 1916 free(filename);
1872 } 1917 }
1873 1918
1874 for (i = 0; i < vmlinux_path__nr_entries; ++i) { 1919 for (i = 0; i < vmlinux_path__nr_entries; ++i) {
1875 err = dso__load_vmlinux(self, map, vmlinux_path[i], filter); 1920 err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter);
1876 if (err > 0) { 1921 if (err > 0) {
1877 dso__set_long_name(self, strdup(vmlinux_path[i])); 1922 dso__set_long_name(dso, strdup(vmlinux_path[i]));
1878 break; 1923 break;
1879 } 1924 }
1880 } 1925 }
@@ -1882,7 +1927,7 @@ out:
1882 return err; 1927 return err;
1883} 1928}
1884 1929
1885static int dso__load_kernel_sym(struct dso *self, struct map *map, 1930static int dso__load_kernel_sym(struct dso *dso, struct map *map,
1886 symbol_filter_t filter) 1931 symbol_filter_t filter)
1887{ 1932{
1888 int err; 1933 int err;
@@ -1909,10 +1954,10 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
1909 } 1954 }
1910 1955
1911 if (symbol_conf.vmlinux_name != NULL) { 1956 if (symbol_conf.vmlinux_name != NULL) {
1912 err = dso__load_vmlinux(self, map, 1957 err = dso__load_vmlinux(dso, map,
1913 symbol_conf.vmlinux_name, filter); 1958 symbol_conf.vmlinux_name, filter);
1914 if (err > 0) { 1959 if (err > 0) {
1915 dso__set_long_name(self, 1960 dso__set_long_name(dso,
1916 strdup(symbol_conf.vmlinux_name)); 1961 strdup(symbol_conf.vmlinux_name));
1917 goto out_fixup; 1962 goto out_fixup;
1918 } 1963 }
@@ -1920,7 +1965,7 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
1920 } 1965 }
1921 1966
1922 if (vmlinux_path != NULL) { 1967 if (vmlinux_path != NULL) {
1923 err = dso__load_vmlinux_path(self, map, filter); 1968 err = dso__load_vmlinux_path(dso, map, filter);
1924 if (err > 0) 1969 if (err > 0)
1925 goto out_fixup; 1970 goto out_fixup;
1926 } 1971 }
@@ -1934,13 +1979,13 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
1934 * we have a build-id, so check if it is the same as the running kernel, 1979 * we have a build-id, so check if it is the same as the running kernel,
1935 * using it if it is. 1980 * using it if it is.
1936 */ 1981 */
1937 if (self->has_build_id) { 1982 if (dso->has_build_id) {
1938 u8 kallsyms_build_id[BUILD_ID_SIZE]; 1983 u8 kallsyms_build_id[BUILD_ID_SIZE];
1939 char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 1984 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
1940 1985
1941 if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id, 1986 if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
1942 sizeof(kallsyms_build_id)) == 0) { 1987 sizeof(kallsyms_build_id)) == 0) {
1943 if (dso__build_id_equal(self, kallsyms_build_id)) { 1988 if (dso__build_id_equal(dso, kallsyms_build_id)) {
1944 kallsyms_filename = "/proc/kallsyms"; 1989 kallsyms_filename = "/proc/kallsyms";
1945 goto do_kallsyms; 1990 goto do_kallsyms;
1946 } 1991 }
@@ -1949,7 +1994,7 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
1949 * Now look if we have it on the build-id cache in 1994 * Now look if we have it on the build-id cache in
1950 * $HOME/.debug/[kernel.kallsyms]. 1995 * $HOME/.debug/[kernel.kallsyms].
1951 */ 1996 */
1952 build_id__sprintf(self->build_id, sizeof(self->build_id), 1997 build_id__sprintf(dso->build_id, sizeof(dso->build_id),
1953 sbuild_id); 1998 sbuild_id);
1954 1999
1955 if (asprintf(&kallsyms_allocated_filename, 2000 if (asprintf(&kallsyms_allocated_filename,
@@ -1976,7 +2021,7 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
1976 } 2021 }
1977 2022
1978do_kallsyms: 2023do_kallsyms:
1979 err = dso__load_kallsyms(self, kallsyms_filename, map, filter); 2024 err = dso__load_kallsyms(dso, kallsyms_filename, map, filter);
1980 if (err > 0) 2025 if (err > 0)
1981 pr_debug("Using %s for symbols\n", kallsyms_filename); 2026 pr_debug("Using %s for symbols\n", kallsyms_filename);
1982 free(kallsyms_allocated_filename); 2027 free(kallsyms_allocated_filename);
@@ -1984,7 +2029,7 @@ do_kallsyms:
1984 if (err > 0) { 2029 if (err > 0) {
1985out_fixup: 2030out_fixup:
1986 if (kallsyms_filename != NULL) 2031 if (kallsyms_filename != NULL)
1987 dso__set_long_name(self, strdup("[kernel.kallsyms]")); 2032 dso__set_long_name(dso, strdup("[kernel.kallsyms]"));
1988 map__fixup_start(map); 2033 map__fixup_start(map);
1989 map__fixup_end(map); 2034 map__fixup_end(map);
1990 } 2035 }
@@ -1992,8 +2037,8 @@ out_fixup:
1992 return err; 2037 return err;
1993} 2038}
1994 2039
1995static int dso__load_guest_kernel_sym(struct dso *self, struct map *map, 2040static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
1996 symbol_filter_t filter) 2041 symbol_filter_t filter)
1997{ 2042{
1998 int err; 2043 int err;
1999 const char *kallsyms_filename = NULL; 2044 const char *kallsyms_filename = NULL;
@@ -2013,7 +2058,7 @@ static int dso__load_guest_kernel_sym(struct dso *self, struct map *map,
2013 * Or use file guest_kallsyms inputted by user on commandline 2058 * Or use file guest_kallsyms inputted by user on commandline
2014 */ 2059 */
2015 if (symbol_conf.default_guest_vmlinux_name != NULL) { 2060 if (symbol_conf.default_guest_vmlinux_name != NULL) {
2016 err = dso__load_vmlinux(self, map, 2061 err = dso__load_vmlinux(dso, map,
2017 symbol_conf.default_guest_vmlinux_name, filter); 2062 symbol_conf.default_guest_vmlinux_name, filter);
2018 goto out_try_fixup; 2063 goto out_try_fixup;
2019 } 2064 }
@@ -2026,7 +2071,7 @@ static int dso__load_guest_kernel_sym(struct dso *self, struct map *map,
2026 kallsyms_filename = path; 2071 kallsyms_filename = path;
2027 } 2072 }
2028 2073
2029 err = dso__load_kallsyms(self, kallsyms_filename, map, filter); 2074 err = dso__load_kallsyms(dso, kallsyms_filename, map, filter);
2030 if (err > 0) 2075 if (err > 0)
2031 pr_debug("Using %s for symbols\n", kallsyms_filename); 2076 pr_debug("Using %s for symbols\n", kallsyms_filename);
2032 2077
@@ -2034,7 +2079,7 @@ out_try_fixup:
2034 if (err > 0) { 2079 if (err > 0) {
2035 if (kallsyms_filename != NULL) { 2080 if (kallsyms_filename != NULL) {
2036 machine__mmap_name(machine, path, sizeof(path)); 2081 machine__mmap_name(machine, path, sizeof(path));
2037 dso__set_long_name(self, strdup(path)); 2082 dso__set_long_name(dso, strdup(path));
2038 } 2083 }
2039 map__fixup_start(map); 2084 map__fixup_start(map);
2040 map__fixup_end(map); 2085 map__fixup_end(map);
@@ -2087,12 +2132,12 @@ size_t __dsos__fprintf(struct list_head *head, FILE *fp)
2087 return ret; 2132 return ret;
2088} 2133}
2089 2134
2090size_t machines__fprintf_dsos(struct rb_root *self, FILE *fp) 2135size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp)
2091{ 2136{
2092 struct rb_node *nd; 2137 struct rb_node *nd;
2093 size_t ret = 0; 2138 size_t ret = 0;
2094 2139
2095 for (nd = rb_first(self); nd; nd = rb_next(nd)) { 2140 for (nd = rb_first(machines); nd; nd = rb_next(nd)) {
2096 struct machine *pos = rb_entry(nd, struct machine, rb_node); 2141 struct machine *pos = rb_entry(nd, struct machine, rb_node);
2097 ret += __dsos__fprintf(&pos->kernel_dsos, fp); 2142 ret += __dsos__fprintf(&pos->kernel_dsos, fp);
2098 ret += __dsos__fprintf(&pos->user_dsos, fp); 2143 ret += __dsos__fprintf(&pos->user_dsos, fp);
@@ -2116,18 +2161,20 @@ static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
2116 return ret; 2161 return ret;
2117} 2162}
2118 2163
2119size_t machine__fprintf_dsos_buildid(struct machine *self, FILE *fp, bool with_hits) 2164size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp,
2165 bool with_hits)
2120{ 2166{
2121 return __dsos__fprintf_buildid(&self->kernel_dsos, fp, with_hits) + 2167 return __dsos__fprintf_buildid(&machine->kernel_dsos, fp, with_hits) +
2122 __dsos__fprintf_buildid(&self->user_dsos, fp, with_hits); 2168 __dsos__fprintf_buildid(&machine->user_dsos, fp, with_hits);
2123} 2169}
2124 2170
2125size_t machines__fprintf_dsos_buildid(struct rb_root *self, FILE *fp, bool with_hits) 2171size_t machines__fprintf_dsos_buildid(struct rb_root *machines,
2172 FILE *fp, bool with_hits)
2126{ 2173{
2127 struct rb_node *nd; 2174 struct rb_node *nd;
2128 size_t ret = 0; 2175 size_t ret = 0;
2129 2176
2130 for (nd = rb_first(self); nd; nd = rb_next(nd)) { 2177 for (nd = rb_first(machines); nd; nd = rb_next(nd)) {
2131 struct machine *pos = rb_entry(nd, struct machine, rb_node); 2178 struct machine *pos = rb_entry(nd, struct machine, rb_node);
2132 ret += machine__fprintf_dsos_buildid(pos, fp, with_hits); 2179 ret += machine__fprintf_dsos_buildid(pos, fp, with_hits);
2133 } 2180 }
@@ -2136,59 +2183,59 @@ size_t machines__fprintf_dsos_buildid(struct rb_root *self, FILE *fp, bool with_
2136 2183
2137struct dso *dso__new_kernel(const char *name) 2184struct dso *dso__new_kernel(const char *name)
2138{ 2185{
2139 struct dso *self = dso__new(name ?: "[kernel.kallsyms]"); 2186 struct dso *dso = dso__new(name ?: "[kernel.kallsyms]");
2140 2187
2141 if (self != NULL) { 2188 if (dso != NULL) {
2142 dso__set_short_name(self, "[kernel]"); 2189 dso__set_short_name(dso, "[kernel]");
2143 self->kernel = DSO_TYPE_KERNEL; 2190 dso->kernel = DSO_TYPE_KERNEL;
2144 } 2191 }
2145 2192
2146 return self; 2193 return dso;
2147} 2194}
2148 2195
2149static struct dso *dso__new_guest_kernel(struct machine *machine, 2196static struct dso *dso__new_guest_kernel(struct machine *machine,
2150 const char *name) 2197 const char *name)
2151{ 2198{
2152 char bf[PATH_MAX]; 2199 char bf[PATH_MAX];
2153 struct dso *self = dso__new(name ?: machine__mmap_name(machine, bf, sizeof(bf))); 2200 struct dso *dso = dso__new(name ?: machine__mmap_name(machine, bf,
2154 2201 sizeof(bf)));
2155 if (self != NULL) { 2202 if (dso != NULL) {
2156 dso__set_short_name(self, "[guest.kernel]"); 2203 dso__set_short_name(dso, "[guest.kernel]");
2157 self->kernel = DSO_TYPE_GUEST_KERNEL; 2204 dso->kernel = DSO_TYPE_GUEST_KERNEL;
2158 } 2205 }
2159 2206
2160 return self; 2207 return dso;
2161} 2208}
2162 2209
2163void dso__read_running_kernel_build_id(struct dso *self, struct machine *machine) 2210void dso__read_running_kernel_build_id(struct dso *dso, struct machine *machine)
2164{ 2211{
2165 char path[PATH_MAX]; 2212 char path[PATH_MAX];
2166 2213
2167 if (machine__is_default_guest(machine)) 2214 if (machine__is_default_guest(machine))
2168 return; 2215 return;
2169 sprintf(path, "%s/sys/kernel/notes", machine->root_dir); 2216 sprintf(path, "%s/sys/kernel/notes", machine->root_dir);
2170 if (sysfs__read_build_id(path, self->build_id, 2217 if (sysfs__read_build_id(path, dso->build_id,
2171 sizeof(self->build_id)) == 0) 2218 sizeof(dso->build_id)) == 0)
2172 self->has_build_id = true; 2219 dso->has_build_id = true;
2173} 2220}
2174 2221
2175static struct dso *machine__create_kernel(struct machine *self) 2222static struct dso *machine__create_kernel(struct machine *machine)
2176{ 2223{
2177 const char *vmlinux_name = NULL; 2224 const char *vmlinux_name = NULL;
2178 struct dso *kernel; 2225 struct dso *kernel;
2179 2226
2180 if (machine__is_host(self)) { 2227 if (machine__is_host(machine)) {
2181 vmlinux_name = symbol_conf.vmlinux_name; 2228 vmlinux_name = symbol_conf.vmlinux_name;
2182 kernel = dso__new_kernel(vmlinux_name); 2229 kernel = dso__new_kernel(vmlinux_name);
2183 } else { 2230 } else {
2184 if (machine__is_default_guest(self)) 2231 if (machine__is_default_guest(machine))
2185 vmlinux_name = symbol_conf.default_guest_vmlinux_name; 2232 vmlinux_name = symbol_conf.default_guest_vmlinux_name;
2186 kernel = dso__new_guest_kernel(self, vmlinux_name); 2233 kernel = dso__new_guest_kernel(machine, vmlinux_name);
2187 } 2234 }
2188 2235
2189 if (kernel != NULL) { 2236 if (kernel != NULL) {
2190 dso__read_running_kernel_build_id(kernel, self); 2237 dso__read_running_kernel_build_id(kernel, machine);
2191 dsos__add(&self->kernel_dsos, kernel); 2238 dsos__add(&machine->kernel_dsos, kernel);
2192 } 2239 }
2193 return kernel; 2240 return kernel;
2194} 2241}
@@ -2227,47 +2274,52 @@ static u64 machine__get_kernel_start_addr(struct machine *machine)
2227 } 2274 }
2228 } 2275 }
2229 2276
2277 if (symbol__restricted_filename(filename, "/proc/kallsyms"))
2278 return 0;
2279
2230 if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0) 2280 if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0)
2231 return 0; 2281 return 0;
2232 2282
2233 return args.start; 2283 return args.start;
2234} 2284}
2235 2285
2236int __machine__create_kernel_maps(struct machine *self, struct dso *kernel) 2286int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel)
2237{ 2287{
2238 enum map_type type; 2288 enum map_type type;
2239 u64 start = machine__get_kernel_start_addr(self); 2289 u64 start = machine__get_kernel_start_addr(machine);
2240 2290
2241 for (type = 0; type < MAP__NR_TYPES; ++type) { 2291 for (type = 0; type < MAP__NR_TYPES; ++type) {
2242 struct kmap *kmap; 2292 struct kmap *kmap;
2243 2293
2244 self->vmlinux_maps[type] = map__new2(start, kernel, type); 2294 machine->vmlinux_maps[type] = map__new2(start, kernel, type);
2245 if (self->vmlinux_maps[type] == NULL) 2295 if (machine->vmlinux_maps[type] == NULL)
2246 return -1; 2296 return -1;
2247 2297
2248 self->vmlinux_maps[type]->map_ip = 2298 machine->vmlinux_maps[type]->map_ip =
2249 self->vmlinux_maps[type]->unmap_ip = identity__map_ip; 2299 machine->vmlinux_maps[type]->unmap_ip =
2250 2300 identity__map_ip;
2251 kmap = map__kmap(self->vmlinux_maps[type]); 2301 kmap = map__kmap(machine->vmlinux_maps[type]);
2252 kmap->kmaps = &self->kmaps; 2302 kmap->kmaps = &machine->kmaps;
2253 map_groups__insert(&self->kmaps, self->vmlinux_maps[type]); 2303 map_groups__insert(&machine->kmaps,
2304 machine->vmlinux_maps[type]);
2254 } 2305 }
2255 2306
2256 return 0; 2307 return 0;
2257} 2308}
2258 2309
2259void machine__destroy_kernel_maps(struct machine *self) 2310void machine__destroy_kernel_maps(struct machine *machine)
2260{ 2311{
2261 enum map_type type; 2312 enum map_type type;
2262 2313
2263 for (type = 0; type < MAP__NR_TYPES; ++type) { 2314 for (type = 0; type < MAP__NR_TYPES; ++type) {
2264 struct kmap *kmap; 2315 struct kmap *kmap;
2265 2316
2266 if (self->vmlinux_maps[type] == NULL) 2317 if (machine->vmlinux_maps[type] == NULL)
2267 continue; 2318 continue;
2268 2319
2269 kmap = map__kmap(self->vmlinux_maps[type]); 2320 kmap = map__kmap(machine->vmlinux_maps[type]);
2270 map_groups__remove(&self->kmaps, self->vmlinux_maps[type]); 2321 map_groups__remove(&machine->kmaps,
2322 machine->vmlinux_maps[type]);
2271 if (kmap->ref_reloc_sym) { 2323 if (kmap->ref_reloc_sym) {
2272 /* 2324 /*
2273 * ref_reloc_sym is shared among all maps, so free just 2325 * ref_reloc_sym is shared among all maps, so free just
@@ -2281,25 +2333,25 @@ void machine__destroy_kernel_maps(struct machine *self)
2281 kmap->ref_reloc_sym = NULL; 2333 kmap->ref_reloc_sym = NULL;
2282 } 2334 }
2283 2335
2284 map__delete(self->vmlinux_maps[type]); 2336 map__delete(machine->vmlinux_maps[type]);
2285 self->vmlinux_maps[type] = NULL; 2337 machine->vmlinux_maps[type] = NULL;
2286 } 2338 }
2287} 2339}
2288 2340
2289int machine__create_kernel_maps(struct machine *self) 2341int machine__create_kernel_maps(struct machine *machine)
2290{ 2342{
2291 struct dso *kernel = machine__create_kernel(self); 2343 struct dso *kernel = machine__create_kernel(machine);
2292 2344
2293 if (kernel == NULL || 2345 if (kernel == NULL ||
2294 __machine__create_kernel_maps(self, kernel) < 0) 2346 __machine__create_kernel_maps(machine, kernel) < 0)
2295 return -1; 2347 return -1;
2296 2348
2297 if (symbol_conf.use_modules && machine__create_modules(self) < 0) 2349 if (symbol_conf.use_modules && machine__create_modules(machine) < 0)
2298 pr_debug("Problems creating module maps, continuing anyway...\n"); 2350 pr_debug("Problems creating module maps, continuing anyway...\n");
2299 /* 2351 /*
2300 * Now that we have all the maps created, just set the ->end of them: 2352 * Now that we have all the maps created, just set the ->end of them:
2301 */ 2353 */
2302 map_groups__fixup_end(&self->kmaps); 2354 map_groups__fixup_end(&machine->kmaps);
2303 return 0; 2355 return 0;
2304} 2356}
2305 2357
@@ -2363,11 +2415,11 @@ out_fail:
2363 return -1; 2415 return -1;
2364} 2416}
2365 2417
2366size_t machine__fprintf_vmlinux_path(struct machine *self, FILE *fp) 2418size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp)
2367{ 2419{
2368 int i; 2420 int i;
2369 size_t printed = 0; 2421 size_t printed = 0;
2370 struct dso *kdso = self->vmlinux_maps[MAP__FUNCTION]->dso; 2422 struct dso *kdso = machine->vmlinux_maps[MAP__FUNCTION]->dso;
2371 2423
2372 if (kdso->has_build_id) { 2424 if (kdso->has_build_id) {
2373 char filename[PATH_MAX]; 2425 char filename[PATH_MAX];
@@ -2396,6 +2448,25 @@ static int setup_list(struct strlist **list, const char *list_str,
2396 return 0; 2448 return 0;
2397} 2449}
2398 2450
2451static bool symbol__read_kptr_restrict(void)
2452{
2453 bool value = false;
2454
2455 if (geteuid() != 0) {
2456 FILE *fp = fopen("/proc/sys/kernel/kptr_restrict", "r");
2457 if (fp != NULL) {
2458 char line[8];
2459
2460 if (fgets(line, sizeof(line), fp) != NULL)
2461 value = atoi(line) != 0;
2462
2463 fclose(fp);
2464 }
2465 }
2466
2467 return value;
2468}
2469
2399int symbol__init(void) 2470int symbol__init(void)
2400{ 2471{
2401 const char *symfs; 2472 const char *symfs;
@@ -2403,6 +2474,8 @@ int symbol__init(void)
2403 if (symbol_conf.initialized) 2474 if (symbol_conf.initialized)
2404 return 0; 2475 return 0;
2405 2476
2477 symbol_conf.priv_size = ALIGN(symbol_conf.priv_size, sizeof(u64));
2478
2406 elf_version(EV_CURRENT); 2479 elf_version(EV_CURRENT);
2407 if (symbol_conf.sort_by_name) 2480 if (symbol_conf.sort_by_name)
2408 symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - 2481 symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
@@ -2440,6 +2513,8 @@ int symbol__init(void)
2440 if (symfs != symbol_conf.symfs) 2513 if (symfs != symbol_conf.symfs)
2441 free((void *)symfs); 2514 free((void *)symfs);
2442 2515
2516 symbol_conf.kptr_restrict = symbol__read_kptr_restrict();
2517
2443 symbol_conf.initialized = true; 2518 symbol_conf.initialized = true;
2444 return 0; 2519 return 0;
2445 2520
@@ -2462,9 +2537,9 @@ void symbol__exit(void)
2462 symbol_conf.initialized = false; 2537 symbol_conf.initialized = false;
2463} 2538}
2464 2539
2465int machines__create_kernel_maps(struct rb_root *self, pid_t pid) 2540int machines__create_kernel_maps(struct rb_root *machines, pid_t pid)
2466{ 2541{
2467 struct machine *machine = machines__findnew(self, pid); 2542 struct machine *machine = machines__findnew(machines, pid);
2468 2543
2469 if (machine == NULL) 2544 if (machine == NULL)
2470 return -1; 2545 return -1;
@@ -2515,7 +2590,7 @@ char *strxfrchar(char *s, char from, char to)
2515 return s; 2590 return s;
2516} 2591}
2517 2592
2518int machines__create_guest_kernel_maps(struct rb_root *self) 2593int machines__create_guest_kernel_maps(struct rb_root *machines)
2519{ 2594{
2520 int ret = 0; 2595 int ret = 0;
2521 struct dirent **namelist = NULL; 2596 struct dirent **namelist = NULL;
@@ -2526,7 +2601,7 @@ int machines__create_guest_kernel_maps(struct rb_root *self)
2526 if (symbol_conf.default_guest_vmlinux_name || 2601 if (symbol_conf.default_guest_vmlinux_name ||
2527 symbol_conf.default_guest_modules || 2602 symbol_conf.default_guest_modules ||
2528 symbol_conf.default_guest_kallsyms) { 2603 symbol_conf.default_guest_kallsyms) {
2529 machines__create_kernel_maps(self, DEFAULT_GUEST_KERNEL_ID); 2604 machines__create_kernel_maps(machines, DEFAULT_GUEST_KERNEL_ID);
2530 } 2605 }
2531 2606
2532 if (symbol_conf.guestmount) { 2607 if (symbol_conf.guestmount) {
@@ -2547,7 +2622,7 @@ int machines__create_guest_kernel_maps(struct rb_root *self)
2547 pr_debug("Can't access file %s\n", path); 2622 pr_debug("Can't access file %s\n", path);
2548 goto failure; 2623 goto failure;
2549 } 2624 }
2550 machines__create_kernel_maps(self, pid); 2625 machines__create_kernel_maps(machines, pid);
2551 } 2626 }
2552failure: 2627failure:
2553 free(namelist); 2628 free(namelist);
@@ -2556,23 +2631,23 @@ failure:
2556 return ret; 2631 return ret;
2557} 2632}
2558 2633
2559void machines__destroy_guest_kernel_maps(struct rb_root *self) 2634void machines__destroy_guest_kernel_maps(struct rb_root *machines)
2560{ 2635{
2561 struct rb_node *next = rb_first(self); 2636 struct rb_node *next = rb_first(machines);
2562 2637
2563 while (next) { 2638 while (next) {
2564 struct machine *pos = rb_entry(next, struct machine, rb_node); 2639 struct machine *pos = rb_entry(next, struct machine, rb_node);
2565 2640
2566 next = rb_next(&pos->rb_node); 2641 next = rb_next(&pos->rb_node);
2567 rb_erase(&pos->rb_node, self); 2642 rb_erase(&pos->rb_node, machines);
2568 machine__delete(pos); 2643 machine__delete(pos);
2569 } 2644 }
2570} 2645}
2571 2646
2572int machine__load_kallsyms(struct machine *self, const char *filename, 2647int machine__load_kallsyms(struct machine *machine, const char *filename,
2573 enum map_type type, symbol_filter_t filter) 2648 enum map_type type, symbol_filter_t filter)
2574{ 2649{
2575 struct map *map = self->vmlinux_maps[type]; 2650 struct map *map = machine->vmlinux_maps[type];
2576 int ret = dso__load_kallsyms(map->dso, filename, map, filter); 2651 int ret = dso__load_kallsyms(map->dso, filename, map, filter);
2577 2652
2578 if (ret > 0) { 2653 if (ret > 0) {
@@ -2582,16 +2657,16 @@ int machine__load_kallsyms(struct machine *self, const char *filename,
2582 * kernel, with modules between them, fixup the end of all 2657 * kernel, with modules between them, fixup the end of all
2583 * sections. 2658 * sections.
2584 */ 2659 */
2585 __map_groups__fixup_end(&self->kmaps, type); 2660 __map_groups__fixup_end(&machine->kmaps, type);
2586 } 2661 }
2587 2662
2588 return ret; 2663 return ret;
2589} 2664}
2590 2665
2591int machine__load_vmlinux_path(struct machine *self, enum map_type type, 2666int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
2592 symbol_filter_t filter) 2667 symbol_filter_t filter)
2593{ 2668{
2594 struct map *map = self->vmlinux_maps[type]; 2669 struct map *map = machine->vmlinux_maps[type];
2595 int ret = dso__load_vmlinux_path(map->dso, map, filter); 2670 int ret = dso__load_vmlinux_path(map->dso, map, filter);
2596 2671
2597 if (ret > 0) { 2672 if (ret > 0) {
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 670cd1c88f54..325ee36a9d29 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -48,16 +48,21 @@ char *strxfrchar(char *s, char from, char to);
48 48
49#define BUILD_ID_SIZE 20 49#define BUILD_ID_SIZE 20
50 50
51/** struct symbol - symtab entry
52 *
53 * @ignore - resolvable but tools ignore it (e.g. idle routines)
54 */
51struct symbol { 55struct symbol {
52 struct rb_node rb_node; 56 struct rb_node rb_node;
53 u64 start; 57 u64 start;
54 u64 end; 58 u64 end;
55 u16 namelen; 59 u16 namelen;
56 u8 binding; 60 u8 binding;
61 bool ignore;
57 char name[0]; 62 char name[0];
58}; 63};
59 64
60void symbol__delete(struct symbol *self); 65void symbol__delete(struct symbol *sym);
61 66
62struct strlist; 67struct strlist;
63 68
@@ -70,7 +75,8 @@ struct symbol_conf {
70 use_callchain, 75 use_callchain,
71 exclude_other, 76 exclude_other,
72 show_cpu_utilization, 77 show_cpu_utilization,
73 initialized; 78 initialized,
79 kptr_restrict;
74 const char *vmlinux_name, 80 const char *vmlinux_name,
75 *kallsyms_name, 81 *kallsyms_name,
76 *source_prefix, 82 *source_prefix,
@@ -91,9 +97,9 @@ struct symbol_conf {
91 97
92extern struct symbol_conf symbol_conf; 98extern struct symbol_conf symbol_conf;
93 99
94static inline void *symbol__priv(struct symbol *self) 100static inline void *symbol__priv(struct symbol *sym)
95{ 101{
96 return ((void *)self) - symbol_conf.priv_size; 102 return ((void *)sym) - symbol_conf.priv_size;
97} 103}
98 104
99struct ref_reloc_sym { 105struct ref_reloc_sym {
@@ -132,13 +138,12 @@ struct dso {
132 struct rb_root symbol_names[MAP__NR_TYPES]; 138 struct rb_root symbol_names[MAP__NR_TYPES];
133 enum dso_kernel_type kernel; 139 enum dso_kernel_type kernel;
134 u8 adjust_symbols:1; 140 u8 adjust_symbols:1;
135 u8 slen_calculated:1;
136 u8 has_build_id:1; 141 u8 has_build_id:1;
137 u8 hit:1; 142 u8 hit:1;
138 u8 annotate_warned:1; 143 u8 annotate_warned:1;
139 u8 sname_alloc:1; 144 u8 sname_alloc:1;
140 u8 lname_alloc:1; 145 u8 lname_alloc:1;
141 unsigned char origin; 146 unsigned char symtab_type;
142 u8 sorted_by_name; 147 u8 sorted_by_name;
143 u8 loaded; 148 u8 loaded;
144 u8 build_id[BUILD_ID_SIZE]; 149 u8 build_id[BUILD_ID_SIZE];
@@ -151,86 +156,90 @@ struct dso {
151 156
152struct dso *dso__new(const char *name); 157struct dso *dso__new(const char *name);
153struct dso *dso__new_kernel(const char *name); 158struct dso *dso__new_kernel(const char *name);
154void dso__delete(struct dso *self); 159void dso__delete(struct dso *dso);
155 160
156int dso__name_len(const struct dso *self); 161int dso__name_len(const struct dso *dso);
157 162
158bool dso__loaded(const struct dso *self, enum map_type type); 163bool dso__loaded(const struct dso *dso, enum map_type type);
159bool dso__sorted_by_name(const struct dso *self, enum map_type type); 164bool dso__sorted_by_name(const struct dso *dso, enum map_type type);
160 165
161static inline void dso__set_loaded(struct dso *self, enum map_type type) 166static inline void dso__set_loaded(struct dso *dso, enum map_type type)
162{ 167{
163 self->loaded |= (1 << type); 168 dso->loaded |= (1 << type);
164} 169}
165 170
166void dso__sort_by_name(struct dso *self, enum map_type type); 171void dso__sort_by_name(struct dso *dso, enum map_type type);
167 172
168struct dso *__dsos__findnew(struct list_head *head, const char *name); 173struct dso *__dsos__findnew(struct list_head *head, const char *name);
169 174
170int dso__load(struct dso *self, struct map *map, symbol_filter_t filter); 175int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter);
171int dso__load_vmlinux(struct dso *self, struct map *map, 176int dso__load_vmlinux(struct dso *dso, struct map *map,
172 const char *vmlinux, symbol_filter_t filter); 177 const char *vmlinux, symbol_filter_t filter);
173int dso__load_vmlinux_path(struct dso *self, struct map *map, 178int dso__load_vmlinux_path(struct dso *dso, struct map *map,
174 symbol_filter_t filter); 179 symbol_filter_t filter);
175int dso__load_kallsyms(struct dso *self, const char *filename, struct map *map, 180int dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map,
176 symbol_filter_t filter); 181 symbol_filter_t filter);
177int machine__load_kallsyms(struct machine *self, const char *filename, 182int machine__load_kallsyms(struct machine *machine, const char *filename,
178 enum map_type type, symbol_filter_t filter); 183 enum map_type type, symbol_filter_t filter);
179int machine__load_vmlinux_path(struct machine *self, enum map_type type, 184int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
180 symbol_filter_t filter); 185 symbol_filter_t filter);
181 186
182size_t __dsos__fprintf(struct list_head *head, FILE *fp); 187size_t __dsos__fprintf(struct list_head *head, FILE *fp);
183 188
184size_t machine__fprintf_dsos_buildid(struct machine *self, FILE *fp, bool with_hits); 189size_t machine__fprintf_dsos_buildid(struct machine *machine,
185size_t machines__fprintf_dsos(struct rb_root *self, FILE *fp); 190 FILE *fp, bool with_hits);
186size_t machines__fprintf_dsos_buildid(struct rb_root *self, FILE *fp, bool with_hits); 191size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp);
187 192size_t machines__fprintf_dsos_buildid(struct rb_root *machines,
188size_t dso__fprintf_buildid(struct dso *self, FILE *fp); 193 FILE *fp, bool with_hits);
189size_t dso__fprintf_symbols_by_name(struct dso *self, enum map_type type, FILE *fp); 194size_t dso__fprintf_buildid(struct dso *dso, FILE *fp);
190size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp); 195size_t dso__fprintf_symbols_by_name(struct dso *dso,
191 196 enum map_type type, FILE *fp);
192enum dso_origin { 197size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp);
193 DSO__ORIG_KERNEL = 0, 198
194 DSO__ORIG_GUEST_KERNEL, 199enum symtab_type {
195 DSO__ORIG_JAVA_JIT, 200 SYMTAB__KALLSYMS = 0,
196 DSO__ORIG_BUILD_ID_CACHE, 201 SYMTAB__GUEST_KALLSYMS,
197 DSO__ORIG_FEDORA, 202 SYMTAB__JAVA_JIT,
198 DSO__ORIG_UBUNTU, 203 SYMTAB__BUILD_ID_CACHE,
199 DSO__ORIG_BUILDID, 204 SYMTAB__FEDORA_DEBUGINFO,
200 DSO__ORIG_DSO, 205 SYMTAB__UBUNTU_DEBUGINFO,
201 DSO__ORIG_GUEST_KMODULE, 206 SYMTAB__BUILDID_DEBUGINFO,
202 DSO__ORIG_KMODULE, 207 SYMTAB__SYSTEM_PATH_DSO,
203 DSO__ORIG_NOT_FOUND, 208 SYMTAB__GUEST_KMODULE,
209 SYMTAB__SYSTEM_PATH_KMODULE,
210 SYMTAB__NOT_FOUND,
204}; 211};
205 212
206char dso__symtab_origin(const struct dso *self); 213char dso__symtab_origin(const struct dso *dso);
207void dso__set_long_name(struct dso *self, char *name); 214void dso__set_long_name(struct dso *dso, char *name);
208void dso__set_build_id(struct dso *self, void *build_id); 215void dso__set_build_id(struct dso *dso, void *build_id);
209void dso__read_running_kernel_build_id(struct dso *self, struct machine *machine); 216void dso__read_running_kernel_build_id(struct dso *dso,
210struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr); 217 struct machine *machine);
211struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type, 218struct symbol *dso__find_symbol(struct dso *dso, enum map_type type,
219 u64 addr);
220struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
212 const char *name); 221 const char *name);
213 222
214int filename__read_build_id(const char *filename, void *bf, size_t size); 223int filename__read_build_id(const char *filename, void *bf, size_t size);
215int sysfs__read_build_id(const char *filename, void *bf, size_t size); 224int sysfs__read_build_id(const char *filename, void *bf, size_t size);
216bool __dsos__read_build_ids(struct list_head *head, bool with_hits); 225bool __dsos__read_build_ids(struct list_head *head, bool with_hits);
217int build_id__sprintf(const u8 *self, int len, char *bf); 226int build_id__sprintf(const u8 *build_id, int len, char *bf);
218int kallsyms__parse(const char *filename, void *arg, 227int kallsyms__parse(const char *filename, void *arg,
219 int (*process_symbol)(void *arg, const char *name, 228 int (*process_symbol)(void *arg, const char *name,
220 char type, u64 start, u64 end)); 229 char type, u64 start, u64 end));
221 230
222void machine__destroy_kernel_maps(struct machine *self); 231void machine__destroy_kernel_maps(struct machine *machine);
223int __machine__create_kernel_maps(struct machine *self, struct dso *kernel); 232int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel);
224int machine__create_kernel_maps(struct machine *self); 233int machine__create_kernel_maps(struct machine *machine);
225 234
226int machines__create_kernel_maps(struct rb_root *self, pid_t pid); 235int machines__create_kernel_maps(struct rb_root *machines, pid_t pid);
227int machines__create_guest_kernel_maps(struct rb_root *self); 236int machines__create_guest_kernel_maps(struct rb_root *machines);
228void machines__destroy_guest_kernel_maps(struct rb_root *self); 237void machines__destroy_guest_kernel_maps(struct rb_root *machines);
229 238
230int symbol__init(void); 239int symbol__init(void);
231void symbol__exit(void); 240void symbol__exit(void);
232bool symbol_type__is_a(char symbol_type, enum map_type map_type); 241bool symbol_type__is_a(char symbol_type, enum map_type map_type);
233 242
234size_t machine__fprintf_vmlinux_path(struct machine *self, FILE *fp); 243size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp);
235 244
236#endif /* __PERF_SYMBOL */ 245#endif /* __PERF_SYMBOL */
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-info.c b/tools/perf/util/trace-event-info.c
index 35729f4c40cb..3403f814ad72 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -183,106 +183,59 @@ int bigendian(void)
183 return *ptr == 0x01020304; 183 return *ptr == 0x01020304;
184} 184}
185 185
186static unsigned long long copy_file_fd(int fd) 186/* unfortunately, you can not stat debugfs or proc files for size */
187static void record_file(const char *file, size_t hdr_sz)
187{ 188{
188 unsigned long long size = 0; 189 unsigned long long size = 0;
189 char buf[BUFSIZ]; 190 char buf[BUFSIZ], *sizep;
190 int r; 191 off_t hdr_pos = lseek(output_fd, 0, SEEK_CUR);
191 192 int r, fd;
192 do {
193 r = read(fd, buf, BUFSIZ);
194 if (r > 0) {
195 size += r;
196 write_or_die(buf, r);
197 }
198 } while (r > 0);
199
200 return size;
201}
202
203static unsigned long long copy_file(const char *file)
204{
205 unsigned long long size = 0;
206 int fd;
207 193
208 fd = open(file, O_RDONLY); 194 fd = open(file, O_RDONLY);
209 if (fd < 0) 195 if (fd < 0)
210 die("Can't read '%s'", file); 196 die("Can't read '%s'", file);
211 size = copy_file_fd(fd);
212 close(fd);
213 197
214 return size; 198 /* put in zeros for file size, then fill true size later */
215} 199 write_or_die(&size, hdr_sz);
216
217static unsigned long get_size_fd(int fd)
218{
219 unsigned long long size = 0;
220 char buf[BUFSIZ];
221 int r;
222 200
223 do { 201 do {
224 r = read(fd, buf, BUFSIZ); 202 r = read(fd, buf, BUFSIZ);
225 if (r > 0) 203 if (r > 0) {
226 size += r; 204 size += r;
205 write_or_die(buf, r);
206 }
227 } while (r > 0); 207 } while (r > 0);
228
229 lseek(fd, 0, SEEK_SET);
230
231 return size;
232}
233
234static unsigned long get_size(const char *file)
235{
236 unsigned long long size = 0;
237 int fd;
238
239 fd = open(file, O_RDONLY);
240 if (fd < 0)
241 die("Can't read '%s'", file);
242 size = get_size_fd(fd);
243 close(fd); 208 close(fd);
244 209
245 return size; 210 /* ugh, handle big-endian hdr_size == 4 */
211 sizep = (char*)&size;
212 if (bigendian())
213 sizep += sizeof(u64) - hdr_sz;
214
215 if (pwrite(output_fd, sizep, hdr_sz, hdr_pos) < 0)
216 die("writing to %s", output_file);
246} 217}
247 218
248static void read_header_files(void) 219static void read_header_files(void)
249{ 220{
250 unsigned long long size, check_size;
251 char *path; 221 char *path;
252 int fd; 222 struct stat st;
253 223
254 path = get_tracing_file("events/header_page"); 224 path = get_tracing_file("events/header_page");
255 fd = open(path, O_RDONLY); 225 if (stat(path, &st) < 0)
256 if (fd < 0)
257 die("can't read '%s'", path); 226 die("can't read '%s'", path);
258 227
259 /* unfortunately, you can not stat debugfs files for size */
260 size = get_size_fd(fd);
261
262 write_or_die("header_page", 12); 228 write_or_die("header_page", 12);
263 write_or_die(&size, 8); 229 record_file(path, 8);
264 check_size = copy_file_fd(fd);
265 close(fd);
266
267 if (size != check_size)
268 die("wrong size for '%s' size=%lld read=%lld",
269 path, size, check_size);
270 put_tracing_file(path); 230 put_tracing_file(path);
271 231
272 path = get_tracing_file("events/header_event"); 232 path = get_tracing_file("events/header_event");
273 fd = open(path, O_RDONLY); 233 if (stat(path, &st) < 0)
274 if (fd < 0)
275 die("can't read '%s'", path); 234 die("can't read '%s'", path);
276 235
277 size = get_size_fd(fd);
278
279 write_or_die("header_event", 13); 236 write_or_die("header_event", 13);
280 write_or_die(&size, 8); 237 record_file(path, 8);
281 check_size = copy_file_fd(fd);
282 if (size != check_size)
283 die("wrong size for '%s'", path);
284 put_tracing_file(path); 238 put_tracing_file(path);
285 close(fd);
286} 239}
287 240
288static bool name_in_tp_list(char *sys, struct tracepoint_path *tps) 241static bool name_in_tp_list(char *sys, struct tracepoint_path *tps)
@@ -298,7 +251,6 @@ static bool name_in_tp_list(char *sys, struct tracepoint_path *tps)
298 251
299static void copy_event_system(const char *sys, struct tracepoint_path *tps) 252static void copy_event_system(const char *sys, struct tracepoint_path *tps)
300{ 253{
301 unsigned long long size, check_size;
302 struct dirent *dent; 254 struct dirent *dent;
303 struct stat st; 255 struct stat st;
304 char *format; 256 char *format;
@@ -338,14 +290,8 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps)
338 sprintf(format, "%s/%s/format", sys, dent->d_name); 290 sprintf(format, "%s/%s/format", sys, dent->d_name);
339 ret = stat(format, &st); 291 ret = stat(format, &st);
340 292
341 if (ret >= 0) { 293 if (ret >= 0)
342 /* unfortunately, you can not stat debugfs files for size */ 294 record_file(format, 8);
343 size = get_size(format);
344 write_or_die(&size, 8);
345 check_size = copy_file(format);
346 if (size != check_size)
347 die("error in size of file '%s'", format);
348 }
349 295
350 free(format); 296 free(format);
351 } 297 }
@@ -426,7 +372,7 @@ static void read_event_files(struct tracepoint_path *tps)
426 372
427static void read_proc_kallsyms(void) 373static void read_proc_kallsyms(void)
428{ 374{
429 unsigned int size, check_size; 375 unsigned int size;
430 const char *path = "/proc/kallsyms"; 376 const char *path = "/proc/kallsyms";
431 struct stat st; 377 struct stat st;
432 int ret; 378 int ret;
@@ -438,17 +384,12 @@ static void read_proc_kallsyms(void)
438 write_or_die(&size, 4); 384 write_or_die(&size, 4);
439 return; 385 return;
440 } 386 }
441 size = get_size(path); 387 record_file(path, 4);
442 write_or_die(&size, 4);
443 check_size = copy_file(path);
444 if (size != check_size)
445 die("error in size of file '%s'", path);
446
447} 388}
448 389
449static void read_ftrace_printk(void) 390static void read_ftrace_printk(void)
450{ 391{
451 unsigned int size, check_size; 392 unsigned int size;
452 char *path; 393 char *path;
453 struct stat st; 394 struct stat st;
454 int ret; 395 int ret;
@@ -461,11 +402,8 @@ static void read_ftrace_printk(void)
461 write_or_die(&size, 4); 402 write_or_die(&size, 4);
462 goto out; 403 goto out;
463 } 404 }
464 size = get_size(path); 405 record_file(path, 4);
465 write_or_die(&size, 4); 406
466 check_size = copy_file(path);
467 if (size != check_size)
468 die("error in size of file '%s'", path);
469out: 407out:
470 put_tracing_file(path); 408 put_tracing_file(path);
471} 409}
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index 73a02223c629..0a7ed5b5e281 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -153,7 +153,7 @@ void parse_proc_kallsyms(char *file, unsigned int size __unused)
153 char *next = NULL; 153 char *next = NULL;
154 char *addr_str; 154 char *addr_str;
155 char ch; 155 char ch;
156 int ret; 156 int ret __used;
157 int i; 157 int i;
158 158
159 line = strtok_r(file, "\n", &next); 159 line = strtok_r(file, "\n", &next);
@@ -2643,68 +2643,13 @@ static void print_lat_fmt(void *data, int size __unused)
2643 printf("."); 2643 printf(".");
2644 2644
2645 if (lock_depth < 0) 2645 if (lock_depth < 0)
2646 printf("."); 2646 printf(". ");
2647 else 2647 else
2648 printf("%d", lock_depth); 2648 printf("%d ", lock_depth);
2649}
2650
2651/* taken from Linux, written by Frederic Weisbecker */
2652static void print_graph_cpu(int cpu)
2653{
2654 int i;
2655 int log10_this = log10_cpu(cpu);
2656 int log10_all = log10_cpu(cpus);
2657
2658
2659 /*
2660 * Start with a space character - to make it stand out
2661 * to the right a bit when trace output is pasted into
2662 * email:
2663 */
2664 printf(" ");
2665
2666 /*
2667 * Tricky - we space the CPU field according to the max
2668 * number of online CPUs. On a 2-cpu system it would take
2669 * a maximum of 1 digit - on a 128 cpu system it would
2670 * take up to 3 digits:
2671 */
2672 for (i = 0; i < log10_all - log10_this; i++)
2673 printf(" ");
2674
2675 printf("%d) ", cpu);
2676} 2649}
2677 2650
2678#define TRACE_GRAPH_PROCINFO_LENGTH 14
2679#define TRACE_GRAPH_INDENT 2 2651#define TRACE_GRAPH_INDENT 2
2680 2652
2681static void print_graph_proc(int pid, const char *comm)
2682{
2683 /* sign + log10(MAX_INT) + '\0' */
2684 char pid_str[11];
2685 int spaces = 0;
2686 int len;
2687 int i;
2688
2689 sprintf(pid_str, "%d", pid);
2690
2691 /* 1 stands for the "-" character */
2692 len = strlen(comm) + strlen(pid_str) + 1;
2693
2694 if (len < TRACE_GRAPH_PROCINFO_LENGTH)
2695 spaces = TRACE_GRAPH_PROCINFO_LENGTH - len;
2696
2697 /* First spaces to align center */
2698 for (i = 0; i < spaces / 2; i++)
2699 printf(" ");
2700
2701 printf("%s-%s", comm, pid_str);
2702
2703 /* Last spaces to align center */
2704 for (i = 0; i < spaces - (spaces / 2); i++)
2705 printf(" ");
2706}
2707
2708static struct record * 2653static struct record *
2709get_return_for_leaf(int cpu, int cur_pid, unsigned long long cur_func, 2654get_return_for_leaf(int cpu, int cur_pid, unsigned long long cur_func,
2710 struct record *next) 2655 struct record *next)
@@ -2876,21 +2821,13 @@ static void print_graph_nested(struct event *event, void *data)
2876 2821
2877static void 2822static void
2878pretty_print_func_ent(void *data, int size, struct event *event, 2823pretty_print_func_ent(void *data, int size, struct event *event,
2879 int cpu, int pid, const char *comm, 2824 int cpu, int pid)
2880 unsigned long secs, unsigned long usecs)
2881{ 2825{
2882 struct format_field *field; 2826 struct format_field *field;
2883 struct record *rec; 2827 struct record *rec;
2884 void *copy_data; 2828 void *copy_data;
2885 unsigned long val; 2829 unsigned long val;
2886 2830
2887 printf("%5lu.%06lu | ", secs, usecs);
2888
2889 print_graph_cpu(cpu);
2890 print_graph_proc(pid, comm);
2891
2892 printf(" | ");
2893
2894 if (latency_format) { 2831 if (latency_format) {
2895 print_lat_fmt(data, size); 2832 print_lat_fmt(data, size);
2896 printf(" | "); 2833 printf(" | ");
@@ -2923,22 +2860,13 @@ out_free:
2923} 2860}
2924 2861
2925static void 2862static void
2926pretty_print_func_ret(void *data, int size __unused, struct event *event, 2863pretty_print_func_ret(void *data, int size __unused, struct event *event)
2927 int cpu, int pid, const char *comm,
2928 unsigned long secs, unsigned long usecs)
2929{ 2864{
2930 unsigned long long rettime, calltime; 2865 unsigned long long rettime, calltime;
2931 unsigned long long duration, depth; 2866 unsigned long long duration, depth;
2932 struct format_field *field; 2867 struct format_field *field;
2933 int i; 2868 int i;
2934 2869
2935 printf("%5lu.%06lu | ", secs, usecs);
2936
2937 print_graph_cpu(cpu);
2938 print_graph_proc(pid, comm);
2939
2940 printf(" | ");
2941
2942 if (latency_format) { 2870 if (latency_format) {
2943 print_lat_fmt(data, size); 2871 print_lat_fmt(data, size);
2944 printf(" | "); 2872 printf(" | ");
@@ -2976,31 +2904,21 @@ pretty_print_func_ret(void *data, int size __unused, struct event *event,
2976 2904
2977static void 2905static void
2978pretty_print_func_graph(void *data, int size, struct event *event, 2906pretty_print_func_graph(void *data, int size, struct event *event,
2979 int cpu, int pid, const char *comm, 2907 int cpu, int pid)
2980 unsigned long secs, unsigned long usecs)
2981{ 2908{
2982 if (event->flags & EVENT_FL_ISFUNCENT) 2909 if (event->flags & EVENT_FL_ISFUNCENT)
2983 pretty_print_func_ent(data, size, event, 2910 pretty_print_func_ent(data, size, event, cpu, pid);
2984 cpu, pid, comm, secs, usecs);
2985 else if (event->flags & EVENT_FL_ISFUNCRET) 2911 else if (event->flags & EVENT_FL_ISFUNCRET)
2986 pretty_print_func_ret(data, size, event, 2912 pretty_print_func_ret(data, size, event);
2987 cpu, pid, comm, secs, usecs);
2988 printf("\n"); 2913 printf("\n");
2989} 2914}
2990 2915
2991void print_event(int cpu, void *data, int size, unsigned long long nsecs, 2916void print_trace_event(int cpu, void *data, int size)
2992 char *comm)
2993{ 2917{
2994 struct event *event; 2918 struct event *event;
2995 unsigned long secs;
2996 unsigned long usecs;
2997 int type; 2919 int type;
2998 int pid; 2920 int pid;
2999 2921
3000 secs = nsecs / NSECS_PER_SEC;
3001 nsecs -= secs * NSECS_PER_SEC;
3002 usecs = nsecs / NSECS_PER_USEC;
3003
3004 type = trace_parse_common_type(data); 2922 type = trace_parse_common_type(data);
3005 2923
3006 event = trace_find_event(type); 2924 event = trace_find_event(type);
@@ -3012,17 +2930,10 @@ void print_event(int cpu, void *data, int size, unsigned long long nsecs,
3012 pid = trace_parse_common_pid(data); 2930 pid = trace_parse_common_pid(data);
3013 2931
3014 if (event->flags & (EVENT_FL_ISFUNCENT | EVENT_FL_ISFUNCRET)) 2932 if (event->flags & (EVENT_FL_ISFUNCENT | EVENT_FL_ISFUNCRET))
3015 return pretty_print_func_graph(data, size, event, cpu, 2933 return pretty_print_func_graph(data, size, event, cpu, pid);
3016 pid, comm, secs, usecs);
3017 2934
3018 if (latency_format) { 2935 if (latency_format)
3019 printf("%8.8s-%-5d %3d",
3020 comm, pid, cpu);
3021 print_lat_fmt(data, size); 2936 print_lat_fmt(data, size);
3022 } else
3023 printf("%16s-%-5d [%03d]", comm, pid, cpu);
3024
3025 printf(" %5lu.%06lu: %s: ", secs, usecs, event->name);
3026 2937
3027 if (event->flags & EVENT_FL_FAILED) { 2938 if (event->flags & EVENT_FL_FAILED) {
3028 printf("EVENT '%s' FAILED TO PARSE\n", 2939 printf("EVENT '%s' FAILED TO PARSE\n",
@@ -3031,7 +2942,6 @@ void print_event(int cpu, void *data, int size, unsigned long long nsecs,
3031 } 2942 }
3032 2943
3033 pretty_print(data, size, event); 2944 pretty_print(data, size, event);
3034 printf("\n");
3035} 2945}
3036 2946
3037static void print_fields(struct print_flag_sym *field) 2947static void print_fields(struct print_flag_sym *field)
diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c
index f7af2fca965d..c9dcbec7d800 100644
--- a/tools/perf/util/trace-event-scripting.c
+++ b/tools/perf/util/trace-event-scripting.c
@@ -36,11 +36,11 @@ static int stop_script_unsupported(void)
36 return 0; 36 return 0;
37} 37}
38 38
39static void process_event_unsupported(int cpu __unused, 39static void process_event_unsupported(union perf_event *event __unused,
40 void *data __unused, 40 struct perf_sample *sample __unused,
41 int size __unused, 41 struct perf_evsel *evsel __unused,
42 unsigned long long nsecs __unused, 42 struct perf_session *session __unused,
43 char *comm __unused) 43 struct thread *thread __unused)
44{ 44{
45} 45}
46 46
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index b5f12ca24d99..f674dda3363b 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -3,6 +3,7 @@
3 3
4#include <stdbool.h> 4#include <stdbool.h>
5#include "parse-events.h" 5#include "parse-events.h"
6#include "session.h"
6 7
7#define __unused __attribute__((unused)) 8#define __unused __attribute__((unused))
8 9
@@ -176,8 +177,7 @@ void print_printk(void);
176 177
177int parse_ftrace_file(char *buf, unsigned long size); 178int parse_ftrace_file(char *buf, unsigned long size);
178int parse_event_file(char *buf, unsigned long size, char *sys); 179int parse_event_file(char *buf, unsigned long size, char *sys);
179void print_event(int cpu, void *data, int size, unsigned long long nsecs, 180void print_trace_event(int cpu, void *data, int size);
180 char *comm);
181 181
182extern int file_bigendian; 182extern int file_bigendian;
183extern int host_bigendian; 183extern int host_bigendian;
@@ -278,8 +278,11 @@ struct scripting_ops {
278 const char *name; 278 const char *name;
279 int (*start_script) (const char *script, int argc, const char **argv); 279 int (*start_script) (const char *script, int argc, const char **argv);
280 int (*stop_script) (void); 280 int (*stop_script) (void);
281 void (*process_event) (int cpu, void *data, int size, 281 void (*process_event) (union perf_event *event,
282 unsigned long long nsecs, char *comm); 282 struct perf_sample *sample,
283 struct perf_evsel *evsel,
284 struct perf_session *session,
285 struct thread *thread);
283 int (*generate_script) (const char *outfile); 286 int (*generate_script) (const char *outfile);
284}; 287};
285 288
diff --git a/tools/perf/util/ui/browser.c b/tools/perf/util/ui/browser.c
index 8bc010edca25..611219f80680 100644
--- a/tools/perf/util/ui/browser.c
+++ b/tools/perf/util/ui/browser.c
@@ -1,4 +1,5 @@
1#include "libslang.h" 1#include "libslang.h"
2#include "ui.h"
2#include <linux/compiler.h> 3#include <linux/compiler.h>
3#include <linux/list.h> 4#include <linux/list.h>
4#include <linux/rbtree.h> 5#include <linux/rbtree.h>
@@ -156,6 +157,20 @@ void ui_browser__add_exit_keys(struct ui_browser *self, int keys[])
156 } 157 }
157} 158}
158 159
160void __ui_browser__show_title(struct ui_browser *browser, const char *title)
161{
162 SLsmg_gotorc(0, 0);
163 ui_browser__set_color(browser, NEWT_COLORSET_ROOT);
164 slsmg_write_nstring(title, browser->width);
165}
166
167void ui_browser__show_title(struct ui_browser *browser, const char *title)
168{
169 pthread_mutex_lock(&ui__lock);
170 __ui_browser__show_title(browser, title);
171 pthread_mutex_unlock(&ui__lock);
172}
173
159int ui_browser__show(struct ui_browser *self, const char *title, 174int ui_browser__show(struct ui_browser *self, const char *title,
160 const char *helpline, ...) 175 const char *helpline, ...)
161{ 176{
@@ -178,9 +193,8 @@ int ui_browser__show(struct ui_browser *self, const char *title,
178 if (self->sb == NULL) 193 if (self->sb == NULL)
179 return -1; 194 return -1;
180 195
181 SLsmg_gotorc(0, 0); 196 pthread_mutex_lock(&ui__lock);
182 ui_browser__set_color(self, NEWT_COLORSET_ROOT); 197 __ui_browser__show_title(self, title);
183 slsmg_write_nstring(title, self->width);
184 198
185 ui_browser__add_exit_keys(self, keys); 199 ui_browser__add_exit_keys(self, keys);
186 newtFormAddComponent(self->form, self->sb); 200 newtFormAddComponent(self->form, self->sb);
@@ -188,25 +202,30 @@ int ui_browser__show(struct ui_browser *self, const char *title,
188 va_start(ap, helpline); 202 va_start(ap, helpline);
189 ui_helpline__vpush(helpline, ap); 203 ui_helpline__vpush(helpline, ap);
190 va_end(ap); 204 va_end(ap);
205 pthread_mutex_unlock(&ui__lock);
191 return 0; 206 return 0;
192} 207}
193 208
194void ui_browser__hide(struct ui_browser *self) 209void ui_browser__hide(struct ui_browser *self)
195{ 210{
211 pthread_mutex_lock(&ui__lock);
196 newtFormDestroy(self->form); 212 newtFormDestroy(self->form);
197 self->form = NULL; 213 self->form = NULL;
198 ui_helpline__pop(); 214 ui_helpline__pop();
215 pthread_mutex_unlock(&ui__lock);
199} 216}
200 217
201int ui_browser__refresh(struct ui_browser *self) 218int ui_browser__refresh(struct ui_browser *self)
202{ 219{
203 int row; 220 int row;
204 221
222 pthread_mutex_lock(&ui__lock);
205 newtScrollbarSet(self->sb, self->index, self->nr_entries - 1); 223 newtScrollbarSet(self->sb, self->index, self->nr_entries - 1);
206 row = self->refresh(self); 224 row = self->refresh(self);
207 ui_browser__set_color(self, HE_COLORSET_NORMAL); 225 ui_browser__set_color(self, HE_COLORSET_NORMAL);
208 SLsmg_fill_region(self->y + row, self->x, 226 SLsmg_fill_region(self->y + row, self->x,
209 self->height - row, self->width, ' '); 227 self->height - row, self->width, ' ');
228 pthread_mutex_unlock(&ui__lock);
210 229
211 return 0; 230 return 0;
212} 231}
diff --git a/tools/perf/util/ui/browser.h b/tools/perf/util/ui/browser.h
index 0dc7e4da36f5..fc63dda10910 100644
--- a/tools/perf/util/ui/browser.h
+++ b/tools/perf/util/ui/browser.h
@@ -24,7 +24,6 @@ struct ui_browser {
24 u32 nr_entries; 24 u32 nr_entries;
25}; 25};
26 26
27
28void ui_browser__set_color(struct ui_browser *self, int color); 27void ui_browser__set_color(struct ui_browser *self, int color);
29void ui_browser__set_percent_color(struct ui_browser *self, 28void ui_browser__set_percent_color(struct ui_browser *self,
30 double percent, bool current); 29 double percent, bool current);
@@ -35,6 +34,8 @@ void ui_browser__reset_index(struct ui_browser *self);
35void ui_browser__gotorc(struct ui_browser *self, int y, int x); 34void ui_browser__gotorc(struct ui_browser *self, int y, int x);
36void ui_browser__add_exit_key(struct ui_browser *self, int key); 35void ui_browser__add_exit_key(struct ui_browser *self, int key);
37void ui_browser__add_exit_keys(struct ui_browser *self, int keys[]); 36void ui_browser__add_exit_keys(struct ui_browser *self, int keys[]);
37void __ui_browser__show_title(struct ui_browser *browser, const char *title);
38void ui_browser__show_title(struct ui_browser *browser, const char *title);
38int ui_browser__show(struct ui_browser *self, const char *title, 39int ui_browser__show(struct ui_browser *self, const char *title,
39 const char *helpline, ...); 40 const char *helpline, ...);
40void ui_browser__hide(struct ui_browser *self); 41void ui_browser__hide(struct ui_browser *self);
diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c
index 82b78f99251b..0229723aceb3 100644
--- a/tools/perf/util/ui/browsers/annotate.c
+++ b/tools/perf/util/ui/browsers/annotate.c
@@ -1,9 +1,11 @@
1#include "../browser.h" 1#include "../browser.h"
2#include "../helpline.h" 2#include "../helpline.h"
3#include "../libslang.h" 3#include "../libslang.h"
4#include "../../annotate.h"
4#include "../../hist.h" 5#include "../../hist.h"
5#include "../../sort.h" 6#include "../../sort.h"
6#include "../../symbol.h" 7#include "../../symbol.h"
8#include <pthread.h>
7 9
8static void ui__error_window(const char *fmt, ...) 10static void ui__error_window(const char *fmt, ...)
9{ 11{
@@ -42,8 +44,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); 44 struct objdump_line_rb_node *olrb = objdump_line__rb(ol);
43 ui_browser__set_percent_color(self, olrb->percent, current_entry); 45 ui_browser__set_percent_color(self, olrb->percent, current_entry);
44 slsmg_printf(" %7.2f ", olrb->percent); 46 slsmg_printf(" %7.2f ", olrb->percent);
45 if (!current_entry)
46 ui_browser__set_color(self, HE_COLORSET_CODE);
47 } else { 47 } else {
48 ui_browser__set_percent_color(self, 0, current_entry); 48 ui_browser__set_percent_color(self, 0, current_entry);
49 slsmg_write_nstring(" ", 9); 49 slsmg_write_nstring(" ", 9);
@@ -55,35 +55,40 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro
55 slsmg_write_nstring(" ", width - 18); 55 slsmg_write_nstring(" ", width - 18);
56 else 56 else
57 slsmg_write_nstring(ol->line, width - 18); 57 slsmg_write_nstring(ol->line, width - 18);
58
59 if (!current_entry)
60 ui_browser__set_color(self, HE_COLORSET_CODE);
58} 61}
59 62
60static double objdump_line__calc_percent(struct objdump_line *self, 63static double objdump_line__calc_percent(struct objdump_line *self,
61 struct list_head *head, 64 struct symbol *sym, int evidx)
62 struct symbol *sym)
63{ 65{
64 double percent = 0.0; 66 double percent = 0.0;
65 67
66 if (self->offset != -1) { 68 if (self->offset != -1) {
67 int len = sym->end - sym->start; 69 int len = sym->end - sym->start;
68 unsigned int hits = 0; 70 unsigned int hits = 0;
69 struct sym_priv *priv = symbol__priv(sym); 71 struct annotation *notes = symbol__annotation(sym);
70 struct sym_ext *sym_ext = priv->ext; 72 struct source_line *src_line = notes->src->lines;
71 struct sym_hist *h = priv->hist; 73 struct sym_hist *h = annotation__histogram(notes, evidx);
72 s64 offset = self->offset; 74 s64 offset = self->offset;
73 struct objdump_line *next = objdump__get_next_ip_line(head, self); 75 struct objdump_line *next;
74
75 76
77 next = objdump__get_next_ip_line(&notes->src->source, self);
76 while (offset < (s64)len && 78 while (offset < (s64)len &&
77 (next == NULL || offset < next->offset)) { 79 (next == NULL || offset < next->offset)) {
78 if (sym_ext) { 80 if (src_line) {
79 percent += sym_ext[offset].percent; 81 percent += src_line[offset].percent;
80 } else 82 } else
81 hits += h->ip[offset]; 83 hits += h->addr[offset];
82 84
83 ++offset; 85 ++offset;
84 } 86 }
85 87 /*
86 if (sym_ext == NULL && h->sum) 88 * If the percentage wasn't already calculated in
89 * symbol__get_source_line, do it now:
90 */
91 if (src_line == NULL && h->sum)
87 percent = 100.0 * hits / h->sum; 92 percent = 100.0 * hits / h->sum;
88 } 93 }
89 94
@@ -133,103 +138,163 @@ static void annotate_browser__set_top(struct annotate_browser *self,
133 self->curr_hot = nd; 138 self->curr_hot = nd;
134} 139}
135 140
136static int annotate_browser__run(struct annotate_browser *self) 141static void annotate_browser__calc_percent(struct annotate_browser *browser,
142 int evidx)
137{ 143{
138 struct rb_node *nd; 144 struct symbol *sym = browser->b.priv;
139 struct hist_entry *he = self->b.priv; 145 struct annotation *notes = symbol__annotation(sym);
140 int key; 146 struct objdump_line *pos;
141 147
142 if (ui_browser__show(&self->b, he->ms.sym->name, 148 browser->entries = RB_ROOT;
143 "<-, -> or ESC: exit, TAB/shift+TAB: cycle thru samples") < 0) 149
144 return -1; 150 pthread_mutex_lock(&notes->lock);
151
152 list_for_each_entry(pos, &notes->src->source, node) {
153 struct objdump_line_rb_node *rbpos = objdump_line__rb(pos);
154 rbpos->percent = objdump_line__calc_percent(pos, sym, evidx);
155 if (rbpos->percent < 0.01) {
156 RB_CLEAR_NODE(&rbpos->rb_node);
157 continue;
158 }
159 objdump__insert_line(&browser->entries, rbpos);
160 }
161 pthread_mutex_unlock(&notes->lock);
162
163 browser->curr_hot = rb_last(&browser->entries);
164}
165
166static int annotate_browser__run(struct annotate_browser *self, int evidx,
167 int refresh)
168{
169 struct rb_node *nd = NULL;
170 struct symbol *sym = self->b.priv;
145 /* 171 /*
146 * To allow builtin-annotate to cycle thru multiple symbols by 172 * RIGHT To allow builtin-annotate to cycle thru multiple symbols by
147 * examining the exit key for this function. 173 * examining the exit key for this function.
148 */ 174 */
149 ui_browser__add_exit_key(&self->b, NEWT_KEY_RIGHT); 175 int exit_keys[] = { 'H', NEWT_KEY_TAB, NEWT_KEY_UNTAB,
176 NEWT_KEY_RIGHT, 0 };
177 int key;
178
179 if (ui_browser__show(&self->b, sym->name,
180 "<-, -> or ESC: exit, TAB/shift+TAB: "
181 "cycle hottest lines, H: Hottest") < 0)
182 return -1;
183
184 ui_browser__add_exit_keys(&self->b, exit_keys);
185 annotate_browser__calc_percent(self, evidx);
186
187 if (self->curr_hot)
188 annotate_browser__set_top(self, self->curr_hot);
150 189
151 nd = self->curr_hot; 190 nd = self->curr_hot;
152 if (nd) { 191
153 int tabs[] = { NEWT_KEY_TAB, NEWT_KEY_UNTAB, 0 }; 192 if (refresh != 0)
154 ui_browser__add_exit_keys(&self->b, tabs); 193 newtFormSetTimer(self->b.form, refresh);
155 }
156 194
157 while (1) { 195 while (1) {
158 key = ui_browser__run(&self->b); 196 key = ui_browser__run(&self->b);
159 197
198 if (refresh != 0) {
199 annotate_browser__calc_percent(self, evidx);
200 /*
201 * Current line focus got out of the list of most active
202 * lines, NULL it so that if TAB|UNTAB is pressed, we
203 * move to curr_hot (current hottest line).
204 */
205 if (nd != NULL && RB_EMPTY_NODE(nd))
206 nd = NULL;
207 }
208
160 switch (key) { 209 switch (key) {
210 case -1:
211 /*
212 * FIXME we need to check if it was
213 * es.reason == NEWT_EXIT_TIMER
214 */
215 if (refresh != 0)
216 symbol__annotate_decay_histogram(sym, evidx);
217 continue;
161 case NEWT_KEY_TAB: 218 case NEWT_KEY_TAB:
162 nd = rb_prev(nd); 219 if (nd != NULL) {
163 if (nd == NULL) 220 nd = rb_prev(nd);
164 nd = rb_last(&self->entries); 221 if (nd == NULL)
165 annotate_browser__set_top(self, nd); 222 nd = rb_last(&self->entries);
223 } else
224 nd = self->curr_hot;
166 break; 225 break;
167 case NEWT_KEY_UNTAB: 226 case NEWT_KEY_UNTAB:
168 nd = rb_next(nd); 227 if (nd != NULL)
169 if (nd == NULL) 228 nd = rb_next(nd);
170 nd = rb_first(&self->entries); 229 if (nd == NULL)
171 annotate_browser__set_top(self, nd); 230 nd = rb_first(&self->entries);
231 else
232 nd = self->curr_hot;
233 break;
234 case 'H':
235 nd = self->curr_hot;
172 break; 236 break;
173 default: 237 default:
174 goto out; 238 goto out;
175 } 239 }
240
241 if (nd != NULL)
242 annotate_browser__set_top(self, nd);
176 } 243 }
177out: 244out:
178 ui_browser__hide(&self->b); 245 ui_browser__hide(&self->b);
179 return key; 246 return key;
180} 247}
181 248
182int hist_entry__tui_annotate(struct hist_entry *self) 249int hist_entry__tui_annotate(struct hist_entry *he, int evidx)
250{
251 return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, 0);
252}
253
254int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
255 int refresh)
183{ 256{
184 struct objdump_line *pos, *n; 257 struct objdump_line *pos, *n;
185 struct objdump_line_rb_node *rbpos; 258 struct annotation *notes;
186 LIST_HEAD(head);
187 struct annotate_browser browser = { 259 struct annotate_browser browser = {
188 .b = { 260 .b = {
189 .entries = &head,
190 .refresh = ui_browser__list_head_refresh, 261 .refresh = ui_browser__list_head_refresh,
191 .seek = ui_browser__list_head_seek, 262 .seek = ui_browser__list_head_seek,
192 .write = annotate_browser__write, 263 .write = annotate_browser__write,
193 .priv = self, 264 .priv = sym,
194 }, 265 },
195 }; 266 };
196 int ret; 267 int ret;
197 268
198 if (self->ms.sym == NULL) 269 if (sym == NULL)
199 return -1; 270 return -1;
200 271
201 if (self->ms.map->dso->annotate_warned) 272 if (map->dso->annotate_warned)
202 return -1; 273 return -1;
203 274
204 if (hist_entry__annotate(self, &head, sizeof(*rbpos)) < 0) { 275 if (symbol__annotate(sym, map, sizeof(struct objdump_line_rb_node)) < 0) {
205 ui__error_window(ui_helpline__last_msg); 276 ui__error_window(ui_helpline__last_msg);
206 return -1; 277 return -1;
207 } 278 }
208 279
209 ui_helpline__push("Press <- or ESC to exit"); 280 ui_helpline__push("Press <- or ESC to exit");
210 281
211 list_for_each_entry(pos, &head, node) { 282 notes = symbol__annotation(sym);
283
284 list_for_each_entry(pos, &notes->src->source, node) {
285 struct objdump_line_rb_node *rbpos;
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 /* 294 browser.b.entries = &notes->src->source,
224 * Position the browser at the hottest line.
225 */
226 browser.curr_hot = rb_last(&browser.entries);
227 if (browser.curr_hot)
228 annotate_browser__set_top(&browser, browser.curr_hot);
229
230 browser.b.width += 18; /* Percentage */ 295 browser.b.width += 18; /* Percentage */
231 ret = annotate_browser__run(&browser); 296 ret = annotate_browser__run(&browser, evidx, refresh);
232 list_for_each_entry_safe(pos, n, &head, node) { 297 list_for_each_entry_safe(pos, n, &notes->src->source, node) {
233 list_del(&pos->node); 298 list_del(&pos->node);
234 objdump_line__free(pos); 299 objdump_line__free(pos);
235 } 300 }
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c
index 60c463c16028..5d767c622dfc 100644
--- a/tools/perf/util/ui/browsers/hists.c
+++ b/tools/perf/util/ui/browsers/hists.c
@@ -7,6 +7,8 @@
7#include <newt.h> 7#include <newt.h>
8#include <linux/rbtree.h> 8#include <linux/rbtree.h>
9 9
10#include "../../evsel.h"
11#include "../../evlist.h"
10#include "../../hist.h" 12#include "../../hist.h"
11#include "../../pstack.h" 13#include "../../pstack.h"
12#include "../../sort.h" 14#include "../../sort.h"
@@ -292,7 +294,8 @@ static int hist_browser__run(struct hist_browser *self, const char *title)
292{ 294{
293 int key; 295 int key;
294 int exit_keys[] = { 'a', '?', 'h', 'C', 'd', 'D', 'E', 't', 296 int exit_keys[] = { 'a', '?', 'h', 'C', 'd', 'D', 'E', 't',
295 NEWT_KEY_ENTER, NEWT_KEY_RIGHT, NEWT_KEY_LEFT, 0, }; 297 NEWT_KEY_ENTER, NEWT_KEY_RIGHT, NEWT_KEY_LEFT,
298 NEWT_KEY_TAB, NEWT_KEY_UNTAB, 0, };
296 299
297 self->b.entries = &self->hists->entries; 300 self->b.entries = &self->hists->entries;
298 self->b.nr_entries = self->hists->nr_entries; 301 self->b.nr_entries = self->hists->nr_entries;
@@ -377,7 +380,7 @@ static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *self,
377 while (node) { 380 while (node) {
378 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); 381 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
379 struct rb_node *next = rb_next(node); 382 struct rb_node *next = rb_next(node);
380 u64 cumul = cumul_hits(child); 383 u64 cumul = callchain_cumul_hits(child);
381 struct callchain_list *chain; 384 struct callchain_list *chain;
382 char folded_sign = ' '; 385 char folded_sign = ' ';
383 int first = true; 386 int first = true;
@@ -638,6 +641,9 @@ static void ui_browser__hists_seek(struct ui_browser *self,
638 struct rb_node *nd; 641 struct rb_node *nd;
639 bool first = true; 642 bool first = true;
640 643
644 if (self->nr_entries == 0)
645 return;
646
641 switch (whence) { 647 switch (whence) {
642 case SEEK_SET: 648 case SEEK_SET:
643 nd = hists__filter_entries(rb_first(self->entries)); 649 nd = hists__filter_entries(rb_first(self->entries));
@@ -797,8 +803,11 @@ static int hists__browser_title(struct hists *self, char *bf, size_t size,
797 return printed; 803 return printed;
798} 804}
799 805
800int hists__browse(struct hists *self, const char *helpline, const char *ev_name) 806static int perf_evsel__hists_browse(struct perf_evsel *evsel,
807 const char *helpline, const char *ev_name,
808 bool left_exits)
801{ 809{
810 struct hists *self = &evsel->hists;
802 struct hist_browser *browser = hist_browser__new(self); 811 struct hist_browser *browser = hist_browser__new(self);
803 struct pstack *fstack; 812 struct pstack *fstack;
804 const struct thread *thread_filter = NULL; 813 const struct thread *thread_filter = NULL;
@@ -818,8 +827,8 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
818 hists__browser_title(self, msg, sizeof(msg), ev_name, 827 hists__browser_title(self, msg, sizeof(msg), ev_name,
819 dso_filter, thread_filter); 828 dso_filter, thread_filter);
820 while (1) { 829 while (1) {
821 const struct thread *thread; 830 const struct thread *thread = NULL;
822 const struct dso *dso; 831 const struct dso *dso = NULL;
823 char *options[16]; 832 char *options[16];
824 int nr_options = 0, choice = 0, i, 833 int nr_options = 0, choice = 0, i,
825 annotate = -2, zoom_dso = -2, zoom_thread = -2, 834 annotate = -2, zoom_dso = -2, zoom_thread = -2,
@@ -827,8 +836,10 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
827 836
828 key = hist_browser__run(browser, msg); 837 key = hist_browser__run(browser, msg);
829 838
830 thread = hist_browser__selected_thread(browser); 839 if (browser->he_selection != NULL) {
831 dso = browser->selection->map ? browser->selection->map->dso : NULL; 840 thread = hist_browser__selected_thread(browser);
841 dso = browser->selection->map ? browser->selection->map->dso : NULL;
842 }
832 843
833 switch (key) { 844 switch (key) {
834 case NEWT_KEY_TAB: 845 case NEWT_KEY_TAB:
@@ -839,7 +850,8 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
839 */ 850 */
840 goto out_free_stack; 851 goto out_free_stack;
841 case 'a': 852 case 'a':
842 if (browser->selection->map == NULL && 853 if (browser->selection == NULL ||
854 browser->selection->sym == NULL ||
843 browser->selection->map->dso->annotate_warned) 855 browser->selection->map->dso->annotate_warned)
844 continue; 856 continue;
845 goto do_annotate; 857 goto do_annotate;
@@ -858,6 +870,7 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
858 "E Expand all callchains\n" 870 "E Expand all callchains\n"
859 "d Zoom into current DSO\n" 871 "d Zoom into current DSO\n"
860 "t Zoom into current Thread\n" 872 "t Zoom into current Thread\n"
873 "TAB/UNTAB Switch events\n"
861 "q/CTRL+C Exit browser"); 874 "q/CTRL+C Exit browser");
862 continue; 875 continue;
863 case NEWT_KEY_ENTER: 876 case NEWT_KEY_ENTER:
@@ -867,8 +880,14 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
867 case NEWT_KEY_LEFT: { 880 case NEWT_KEY_LEFT: {
868 const void *top; 881 const void *top;
869 882
870 if (pstack__empty(fstack)) 883 if (pstack__empty(fstack)) {
884 /*
885 * Go back to the perf_evsel_menu__run or other user
886 */
887 if (left_exits)
888 goto out_free_stack;
871 continue; 889 continue;
890 }
872 top = pstack__pop(fstack); 891 top = pstack__pop(fstack);
873 if (top == &dso_filter) 892 if (top == &dso_filter)
874 goto zoom_out_dso; 893 goto zoom_out_dso;
@@ -877,14 +896,16 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
877 continue; 896 continue;
878 } 897 }
879 case NEWT_KEY_ESCAPE: 898 case NEWT_KEY_ESCAPE:
880 if (!ui__dialog_yesno("Do you really want to exit?")) 899 if (!left_exits &&
900 !ui__dialog_yesno("Do you really want to exit?"))
881 continue; 901 continue;
882 /* Fall thru */ 902 /* Fall thru */
883 default: 903 default:
884 goto out_free_stack; 904 goto out_free_stack;
885 } 905 }
886 906
887 if (browser->selection->sym != NULL && 907 if (browser->selection != NULL &&
908 browser->selection->sym != NULL &&
888 !browser->selection->map->dso->annotate_warned && 909 !browser->selection->map->dso->annotate_warned &&
889 asprintf(&options[nr_options], "Annotate %s", 910 asprintf(&options[nr_options], "Annotate %s",
890 browser->selection->sym->name) > 0) 911 browser->selection->sym->name) > 0)
@@ -903,7 +924,8 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
903 (dso->kernel ? "the Kernel" : dso->short_name)) > 0) 924 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
904 zoom_dso = nr_options++; 925 zoom_dso = nr_options++;
905 926
906 if (browser->selection->map != NULL && 927 if (browser->selection != NULL &&
928 browser->selection->map != NULL &&
907 asprintf(&options[nr_options], "Browse map details") > 0) 929 asprintf(&options[nr_options], "Browse map details") > 0)
908 browse_map = nr_options++; 930 browse_map = nr_options++;
909 931
@@ -923,19 +945,11 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
923 if (choice == annotate) { 945 if (choice == annotate) {
924 struct hist_entry *he; 946 struct hist_entry *he;
925do_annotate: 947do_annotate:
926 if (browser->selection->map->dso->origin == DSO__ORIG_KERNEL) {
927 browser->selection->map->dso->annotate_warned = 1;
928 ui_helpline__puts("No vmlinux file found, can't "
929 "annotate with just a "
930 "kallsyms file");
931 continue;
932 }
933
934 he = hist_browser__selected_entry(browser); 948 he = hist_browser__selected_entry(browser);
935 if (he == NULL) 949 if (he == NULL)
936 continue; 950 continue;
937 951
938 hist_entry__tui_annotate(he); 952 hist_entry__tui_annotate(he, evsel->idx);
939 } else if (choice == browse_map) 953 } else if (choice == browse_map)
940 map__browse(browser->selection->map); 954 map__browse(browser->selection->map);
941 else if (choice == zoom_dso) { 955 else if (choice == zoom_dso) {
@@ -984,30 +998,141 @@ out:
984 return key; 998 return key;
985} 999}
986 1000
987int hists__tui_browse_tree(struct rb_root *self, const char *help) 1001struct perf_evsel_menu {
1002 struct ui_browser b;
1003 struct perf_evsel *selection;
1004};
1005
1006static void perf_evsel_menu__write(struct ui_browser *browser,
1007 void *entry, int row)
1008{
1009 struct perf_evsel_menu *menu = container_of(browser,
1010 struct perf_evsel_menu, b);
1011 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1012 bool current_entry = ui_browser__is_current_entry(browser, row);
1013 unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1014 const char *ev_name = event_name(evsel);
1015 char bf[256], unit;
1016
1017 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
1018 HE_COLORSET_NORMAL);
1019
1020 nr_events = convert_unit(nr_events, &unit);
1021 snprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
1022 unit, unit == ' ' ? "" : " ", ev_name);
1023 slsmg_write_nstring(bf, browser->width);
1024
1025 if (current_entry)
1026 menu->selection = evsel;
1027}
1028
1029static int perf_evsel_menu__run(struct perf_evsel_menu *menu, const char *help)
988{ 1030{
989 struct rb_node *first = rb_first(self), *nd = first, *next; 1031 int exit_keys[] = { NEWT_KEY_ENTER, NEWT_KEY_RIGHT, 0, };
990 int key = 0; 1032 struct perf_evlist *evlist = menu->b.priv;
1033 struct perf_evsel *pos;
1034 const char *ev_name, *title = "Available samples";
1035 int key;
1036
1037 if (ui_browser__show(&menu->b, title,
1038 "ESC: exit, ENTER|->: Browse histograms") < 0)
1039 return -1;
1040
1041 ui_browser__add_exit_keys(&menu->b, exit_keys);
991 1042
992 while (nd) { 1043 while (1) {
993 struct hists *hists = rb_entry(nd, struct hists, rb_node); 1044 key = ui_browser__run(&menu->b);
994 const char *ev_name = __event_name(hists->type, hists->config);
995 1045
996 key = hists__browse(hists, help, ev_name);
997 switch (key) { 1046 switch (key) {
998 case NEWT_KEY_TAB: 1047 case NEWT_KEY_RIGHT:
999 next = rb_next(nd); 1048 case NEWT_KEY_ENTER:
1000 if (next) 1049 if (!menu->selection)
1001 nd = next; 1050 continue;
1051 pos = menu->selection;
1052browse_hists:
1053 ev_name = event_name(pos);
1054 key = perf_evsel__hists_browse(pos, help, ev_name, true);
1055 ui_browser__show_title(&menu->b, title);
1002 break; 1056 break;
1003 case NEWT_KEY_UNTAB: 1057 case NEWT_KEY_LEFT:
1004 if (nd == first) 1058 continue;
1059 case NEWT_KEY_ESCAPE:
1060 if (!ui__dialog_yesno("Do you really want to exit?"))
1005 continue; 1061 continue;
1006 nd = rb_prev(nd); 1062 /* Fall thru */
1063 default:
1064 goto out;
1065 }
1066
1067 switch (key) {
1068 case NEWT_KEY_TAB:
1069 if (pos->node.next == &evlist->entries)
1070 pos = list_entry(evlist->entries.next, struct perf_evsel, node);
1071 else
1072 pos = list_entry(pos->node.next, struct perf_evsel, node);
1073 goto browse_hists;
1074 case NEWT_KEY_UNTAB:
1075 if (pos->node.prev == &evlist->entries)
1076 pos = list_entry(evlist->entries.prev, struct perf_evsel, node);
1077 else
1078 pos = list_entry(pos->node.prev, struct perf_evsel, node);
1079 goto browse_hists;
1080 case 'q':
1081 case CTRL('c'):
1082 goto out;
1007 default: 1083 default:
1008 return key; 1084 break;
1009 } 1085 }
1010 } 1086 }
1011 1087
1088out:
1089 ui_browser__hide(&menu->b);
1012 return key; 1090 return key;
1013} 1091}
1092
1093static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
1094 const char *help)
1095{
1096 struct perf_evsel *pos;
1097 struct perf_evsel_menu menu = {
1098 .b = {
1099 .entries = &evlist->entries,
1100 .refresh = ui_browser__list_head_refresh,
1101 .seek = ui_browser__list_head_seek,
1102 .write = perf_evsel_menu__write,
1103 .nr_entries = evlist->nr_entries,
1104 .priv = evlist,
1105 },
1106 };
1107
1108 ui_helpline__push("Press ESC to exit");
1109
1110 list_for_each_entry(pos, &evlist->entries, node) {
1111 const char *ev_name = event_name(pos);
1112 size_t line_len = strlen(ev_name) + 7;
1113
1114 if (menu.b.width < line_len)
1115 menu.b.width = line_len;
1116 /*
1117 * Cache the evsel name, tracepoints have a _high_ cost per
1118 * event_name() call.
1119 */
1120 if (pos->name == NULL)
1121 pos->name = strdup(ev_name);
1122 }
1123
1124 return perf_evsel_menu__run(&menu, help);
1125}
1126
1127int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help)
1128{
1129
1130 if (evlist->nr_entries == 1) {
1131 struct perf_evsel *first = list_entry(evlist->entries.next,
1132 struct perf_evsel, node);
1133 const char *ev_name = event_name(first);
1134 return perf_evsel__hists_browse(first, help, ev_name, false);
1135 }
1136
1137 return __perf_evlist__tui_browse_hists(evlist, help);
1138}
diff --git a/tools/perf/util/ui/browsers/map.c b/tools/perf/util/ui/browsers/map.c
index e5158369106e..8462bffe20bc 100644
--- a/tools/perf/util/ui/browsers/map.c
+++ b/tools/perf/util/ui/browsers/map.c
@@ -41,7 +41,7 @@ static int ui_entry__read(const char *title, char *bf, size_t size, int width)
41out_free_form: 41out_free_form:
42 newtPopWindow(); 42 newtPopWindow();
43 newtFormDestroy(form); 43 newtFormDestroy(form);
44 return 0; 44 return err;
45} 45}
46 46
47struct map_browser { 47struct map_browser {
diff --git a/tools/perf/util/ui/browsers/top.c b/tools/perf/util/ui/browsers/top.c
new file mode 100644
index 000000000000..5a06538532af
--- /dev/null
+++ b/tools/perf/util/ui/browsers/top.c
@@ -0,0 +1,213 @@
1/*
2 * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
3 *
4 * Parts came from builtin-{top,stat,record}.c, see those files for further
5 * copyright notes.
6 *
7 * Released under the GPL v2. (and only v2, not any later version)
8 */
9#include "../browser.h"
10#include "../../annotate.h"
11#include "../helpline.h"
12#include "../libslang.h"
13#include "../util.h"
14#include "../../evlist.h"
15#include "../../hist.h"
16#include "../../sort.h"
17#include "../../symbol.h"
18#include "../../top.h"
19
20struct perf_top_browser {
21 struct ui_browser b;
22 struct rb_root root;
23 struct sym_entry *selection;
24 float sum_ksamples;
25 int dso_width;
26 int dso_short_width;
27 int sym_width;
28};
29
30static void perf_top_browser__write(struct ui_browser *browser, void *entry, int row)
31{
32 struct perf_top_browser *top_browser = container_of(browser, struct perf_top_browser, b);
33 struct sym_entry *syme = rb_entry(entry, struct sym_entry, rb_node);
34 bool current_entry = ui_browser__is_current_entry(browser, row);
35 struct symbol *symbol = sym_entry__symbol(syme);
36 struct perf_top *top = browser->priv;
37 int width = browser->width;
38 double pcnt;
39
40 pcnt = 100.0 - (100.0 * ((top_browser->sum_ksamples - syme->snap_count) /
41 top_browser->sum_ksamples));
42 ui_browser__set_percent_color(browser, pcnt, current_entry);
43
44 if (top->evlist->nr_entries == 1 || !top->display_weighted) {
45 slsmg_printf("%20.2f ", syme->weight);
46 width -= 24;
47 } else {
48 slsmg_printf("%9.1f %10ld ", syme->weight, syme->snap_count);
49 width -= 23;
50 }
51
52 slsmg_printf("%4.1f%%", pcnt);
53 width -= 7;
54
55 if (verbose) {
56 slsmg_printf(" %016" PRIx64, symbol->start);
57 width -= 17;
58 }
59
60 slsmg_printf(" %-*.*s ", top_browser->sym_width, top_browser->sym_width,
61 symbol->name);
62 width -= top_browser->sym_width;
63 slsmg_write_nstring(width >= syme->map->dso->long_name_len ?
64 syme->map->dso->long_name :
65 syme->map->dso->short_name, width);
66
67 if (current_entry)
68 top_browser->selection = syme;
69}
70
71static void perf_top_browser__update_rb_tree(struct perf_top_browser *browser)
72{
73 struct perf_top *top = browser->b.priv;
74 u64 top_idx = browser->b.top_idx;
75
76 browser->root = RB_ROOT;
77 browser->b.top = NULL;
78 browser->sum_ksamples = perf_top__decay_samples(top, &browser->root);
79 /*
80 * No active symbols
81 */
82 if (top->rb_entries == 0)
83 return;
84
85 perf_top__find_widths(top, &browser->root, &browser->dso_width,
86 &browser->dso_short_width,
87 &browser->sym_width);
88 if (browser->sym_width + browser->dso_width > browser->b.width - 29) {
89 browser->dso_width = browser->dso_short_width;
90 if (browser->sym_width + browser->dso_width > browser->b.width - 29)
91 browser->sym_width = browser->b.width - browser->dso_width - 29;
92 }
93
94 /*
95 * Adjust the ui_browser indexes since the entries in the browser->root
96 * rb_tree may have changed, then seek it from start, so that we get a
97 * possible new top of the screen.
98 */
99 browser->b.nr_entries = top->rb_entries;
100
101 if (top_idx >= browser->b.nr_entries) {
102 if (browser->b.height >= browser->b.nr_entries)
103 top_idx = browser->b.nr_entries - browser->b.height;
104 else
105 top_idx = 0;
106 }
107
108 if (browser->b.index >= top_idx + browser->b.height)
109 browser->b.index = top_idx + browser->b.index - browser->b.top_idx;
110
111 if (browser->b.index >= browser->b.nr_entries)
112 browser->b.index = browser->b.nr_entries - 1;
113
114 browser->b.top_idx = top_idx;
115 browser->b.seek(&browser->b, top_idx, SEEK_SET);
116}
117
118static void perf_top_browser__annotate(struct perf_top_browser *browser)
119{
120 struct sym_entry *syme = browser->selection;
121 struct symbol *sym = sym_entry__symbol(syme);
122 struct annotation *notes = symbol__annotation(sym);
123 struct perf_top *top = browser->b.priv;
124
125 if (notes->src != NULL)
126 goto do_annotation;
127
128 pthread_mutex_lock(&notes->lock);
129
130 top->sym_filter_entry = NULL;
131
132 if (symbol__alloc_hist(sym, top->evlist->nr_entries) < 0) {
133 pr_err("Not enough memory for annotating '%s' symbol!\n",
134 sym->name);
135 pthread_mutex_unlock(&notes->lock);
136 return;
137 }
138
139 top->sym_filter_entry = syme;
140
141 pthread_mutex_unlock(&notes->lock);
142do_annotation:
143 symbol__tui_annotate(sym, syme->map, 0, top->delay_secs * 1000);
144}
145
146static int perf_top_browser__run(struct perf_top_browser *browser)
147{
148 int key;
149 char title[160];
150 struct perf_top *top = browser->b.priv;
151 int delay_msecs = top->delay_secs * 1000;
152 int exit_keys[] = { 'a', NEWT_KEY_ENTER, NEWT_KEY_RIGHT, 0, };
153
154 perf_top_browser__update_rb_tree(browser);
155 perf_top__header_snprintf(top, title, sizeof(title));
156 perf_top__reset_sample_counters(top);
157
158 if (ui_browser__show(&browser->b, title,
159 "ESC: exit, ENTER|->|a: Live Annotate") < 0)
160 return -1;
161
162 newtFormSetTimer(browser->b.form, delay_msecs);
163 ui_browser__add_exit_keys(&browser->b, exit_keys);
164
165 while (1) {
166 key = ui_browser__run(&browser->b);
167
168 switch (key) {
169 case -1:
170 /* FIXME we need to check if it was es.reason == NEWT_EXIT_TIMER */
171 perf_top_browser__update_rb_tree(browser);
172 perf_top__header_snprintf(top, title, sizeof(title));
173 perf_top__reset_sample_counters(top);
174 ui_browser__set_color(&browser->b, NEWT_COLORSET_ROOT);
175 SLsmg_gotorc(0, 0);
176 slsmg_write_nstring(title, browser->b.width);
177 break;
178 case 'a':
179 case NEWT_KEY_RIGHT:
180 case NEWT_KEY_ENTER:
181 if (browser->selection)
182 perf_top_browser__annotate(browser);
183 break;
184 case NEWT_KEY_LEFT:
185 continue;
186 case NEWT_KEY_ESCAPE:
187 if (!ui__dialog_yesno("Do you really want to exit?"))
188 continue;
189 /* Fall thru */
190 default:
191 goto out;
192 }
193 }
194out:
195 ui_browser__hide(&browser->b);
196 return key;
197}
198
199int perf_top__tui_browser(struct perf_top *top)
200{
201 struct perf_top_browser browser = {
202 .b = {
203 .entries = &browser.root,
204 .refresh = ui_browser__rb_tree_refresh,
205 .seek = ui_browser__rb_tree_seek,
206 .write = perf_top_browser__write,
207 .priv = top,
208 },
209 };
210
211 ui_helpline__push("Press <- or ESC to exit");
212 return perf_top_browser__run(&browser);
213}
diff --git a/tools/perf/util/ui/helpline.c b/tools/perf/util/ui/helpline.c
index 8d79daa4458a..f36d2ff509ed 100644
--- a/tools/perf/util/ui/helpline.c
+++ b/tools/perf/util/ui/helpline.c
@@ -5,6 +5,7 @@
5 5
6#include "../debug.h" 6#include "../debug.h"
7#include "helpline.h" 7#include "helpline.h"
8#include "ui.h"
8 9
9void ui_helpline__pop(void) 10void ui_helpline__pop(void)
10{ 11{
@@ -55,7 +56,8 @@ int ui_helpline__show_help(const char *format, va_list ap)
55 int ret; 56 int ret;
56 static int backlog; 57 static int backlog;
57 58
58 ret = vsnprintf(ui_helpline__last_msg + backlog, 59 pthread_mutex_lock(&ui__lock);
60 ret = vsnprintf(ui_helpline__last_msg + backlog,
59 sizeof(ui_helpline__last_msg) - backlog, format, ap); 61 sizeof(ui_helpline__last_msg) - backlog, format, ap);
60 backlog += ret; 62 backlog += ret;
61 63
@@ -64,6 +66,7 @@ int ui_helpline__show_help(const char *format, va_list ap)
64 newtRefresh(); 66 newtRefresh();
65 backlog = 0; 67 backlog = 0;
66 } 68 }
69 pthread_mutex_unlock(&ui__lock);
67 70
68 return ret; 71 return ret;
69} 72}
diff --git a/tools/perf/util/ui/libslang.h b/tools/perf/util/ui/libslang.h
index 5623da8e8080..2b63e1c9b181 100644
--- a/tools/perf/util/ui/libslang.h
+++ b/tools/perf/util/ui/libslang.h
@@ -13,11 +13,11 @@
13 13
14#if SLANG_VERSION < 20104 14#if SLANG_VERSION < 20104
15#define slsmg_printf(msg, args...) \ 15#define slsmg_printf(msg, args...) \
16 SLsmg_printf((char *)msg, ##args) 16 SLsmg_printf((char *)(msg), ##args)
17#define slsmg_write_nstring(msg, len) \ 17#define slsmg_write_nstring(msg, len) \
18 SLsmg_write_nstring((char *)msg, len) 18 SLsmg_write_nstring((char *)(msg), len)
19#define sltt_set_color(obj, name, fg, bg) \ 19#define sltt_set_color(obj, name, fg, bg) \
20 SLtt_set_color(obj,(char *)name, (char *)fg, (char *)bg) 20 SLtt_set_color(obj,(char *)(name), (char *)(fg), (char *)(bg))
21#else 21#else
22#define slsmg_printf SLsmg_printf 22#define slsmg_printf SLsmg_printf
23#define slsmg_write_nstring SLsmg_write_nstring 23#define slsmg_write_nstring SLsmg_write_nstring
diff --git a/tools/perf/util/ui/setup.c b/tools/perf/util/ui/setup.c
index 662085032eb7..ee46d671db59 100644
--- a/tools/perf/util/ui/setup.c
+++ b/tools/perf/util/ui/setup.c
@@ -6,6 +6,9 @@
6#include "../debug.h" 6#include "../debug.h"
7#include "browser.h" 7#include "browser.h"
8#include "helpline.h" 8#include "helpline.h"
9#include "ui.h"
10
11pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER;
9 12
10static void newt_suspend(void *d __used) 13static void newt_suspend(void *d __used)
11{ 14{
@@ -14,11 +17,12 @@ static void newt_suspend(void *d __used)
14 newtResume(); 17 newtResume();
15} 18}
16 19
17void setup_browser(void) 20void setup_browser(bool fallback_to_pager)
18{ 21{
19 if (!isatty(1) || !use_browser || dump_trace) { 22 if (!isatty(1) || !use_browser || dump_trace) {
20 use_browser = 0; 23 use_browser = 0;
21 setup_pager(); 24 if (fallback_to_pager)
25 setup_pager();
22 return; 26 return;
23 } 27 }
24 28
diff --git a/tools/perf/util/ui/ui.h b/tools/perf/util/ui/ui.h
new file mode 100644
index 000000000000..d264e059c829
--- /dev/null
+++ b/tools/perf/util/ui/ui.h
@@ -0,0 +1,8 @@
1#ifndef _PERF_UI_H_
2#define _PERF_UI_H_ 1
3
4#include <pthread.h>
5
6extern pthread_mutex_t ui__lock;
7
8#endif /* _PERF_UI_H_ */
diff --git a/tools/perf/util/ui/util.c b/tools/perf/util/ui/util.c
index 7b5a8926624e..fdf1fc8f08bc 100644
--- a/tools/perf/util/ui/util.c
+++ b/tools/perf/util/ui/util.c
@@ -9,6 +9,7 @@
9#include "../debug.h" 9#include "../debug.h"
10#include "browser.h" 10#include "browser.h"
11#include "helpline.h" 11#include "helpline.h"
12#include "ui.h"
12#include "util.h" 13#include "util.h"
13 14
14static void newt_form__set_exit_keys(newtComponent self) 15static void newt_form__set_exit_keys(newtComponent self)
@@ -118,10 +119,12 @@ void ui__warning(const char *format, ...)
118 va_list args; 119 va_list args;
119 120
120 va_start(args, format); 121 va_start(args, format);
121 if (use_browser > 0) 122 if (use_browser > 0) {
123 pthread_mutex_lock(&ui__lock);
122 newtWinMessagev((char *)warning_str, (char *)ok, 124 newtWinMessagev((char *)warning_str, (char *)ok,
123 (char *)format, args); 125 (char *)format, args);
124 else 126 pthread_mutex_unlock(&ui__lock);
127 } else
125 vfprintf(stderr, format, args); 128 vfprintf(stderr, format, args);
126 va_end(args); 129 va_end(args);
127} 130}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index e833f26f3bfc..0128906bac88 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
@@ -264,6 +238,7 @@ char **argv_split(const char *str, int *argcp);
264void argv_free(char **argv); 238void argv_free(char **argv);
265bool strglobmatch(const char *str, const char *pat); 239bool strglobmatch(const char *str, const char *pat);
266bool strlazymatch(const char *str, const char *pat); 240bool strlazymatch(const char *str, const char *pat);
241int strtailcmp(const char *s1, const char *s2);
267unsigned long convert_unit(unsigned long value, char *unit); 242unsigned long convert_unit(unsigned long value, char *unit);
268int readn(int fd, void *buf, size_t size); 243int readn(int fd, void *buf, size_t size);
269 244