aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/Documentation/perf-diff.txt79
-rw-r--r--tools/perf/Documentation/perf-kvm.txt46
-rw-r--r--tools/perf/Documentation/perf-list.txt6
-rw-r--r--tools/perf/Documentation/perf-report.txt13
-rw-r--r--tools/perf/Documentation/perf-stat.txt5
-rw-r--r--tools/perf/Documentation/perf-top.txt5
-rw-r--r--tools/perf/Documentation/perf-trace.txt24
-rw-r--r--tools/perf/Makefile22
-rw-r--r--tools/perf/arch/x86/Makefile2
-rw-r--r--tools/perf/arch/x86/util/tsc.c59
-rw-r--r--tools/perf/arch/x86/util/tsc.h20
-rw-r--r--tools/perf/bench/mem-memcpy.c2
-rw-r--r--tools/perf/builtin-annotate.c6
-rw-r--r--tools/perf/builtin-diff.c664
-rw-r--r--tools/perf/builtin-inject.c70
-rw-r--r--tools/perf/builtin-kmem.c7
-rw-r--r--tools/perf/builtin-kvm.c754
-rw-r--r--tools/perf/builtin-list.c3
-rw-r--r--tools/perf/builtin-lock.c3
-rw-r--r--tools/perf/builtin-mem.c7
-rw-r--r--tools/perf/builtin-record.c13
-rw-r--r--tools/perf/builtin-report.c94
-rw-r--r--tools/perf/builtin-sched.c161
-rw-r--r--tools/perf/builtin-script.c45
-rw-r--r--tools/perf/builtin-stat.c24
-rw-r--r--tools/perf/builtin-timechart.c176
-rw-r--r--tools/perf/builtin-top.c36
-rw-r--r--tools/perf/builtin-trace.c744
-rw-r--r--tools/perf/config/Makefile10
-rw-r--r--tools/perf/config/feature-tests.mak10
-rw-r--r--tools/perf/perf.h3
-rwxr-xr-xtools/perf/python/twatch.py2
-rw-r--r--tools/perf/tests/attr/test-record-group-sampling36
-rw-r--r--tools/perf/tests/builtin-test.c22
-rw-r--r--tools/perf/tests/code-reading.c572
-rw-r--r--tools/perf/tests/dso-data.c8
-rw-r--r--tools/perf/tests/evsel-tp-sched.c4
-rw-r--r--tools/perf/tests/hists_link.c27
-rw-r--r--tools/perf/tests/keep-tracking.c154
-rw-r--r--tools/perf/tests/make67
-rw-r--r--tools/perf/tests/mmap-basic.c2
-rw-r--r--tools/perf/tests/parse-events.c190
-rw-r--r--tools/perf/tests/parse-no-sample-id-all.c108
-rw-r--r--tools/perf/tests/perf-record.c15
-rw-r--r--tools/perf/tests/perf-time-to-tsc.c177
-rw-r--r--tools/perf/tests/sample-parsing.c316
-rw-r--r--tools/perf/tests/tests.h13
-rw-r--r--tools/perf/tests/vmlinux-kallsyms.c49
-rw-r--r--tools/perf/ui/browsers/annotate.c20
-rw-r--r--tools/perf/ui/browsers/hists.c18
-rw-r--r--tools/perf/ui/gtk/hists.c128
-rw-r--r--tools/perf/ui/hist.c258
-rw-r--r--tools/perf/ui/setup.c1
-rw-r--r--tools/perf/ui/stdio/hist.c68
-rw-r--r--tools/perf/util/annotate.c62
-rw-r--r--tools/perf/util/build-id.c12
-rw-r--r--tools/perf/util/callchain.c15
-rw-r--r--tools/perf/util/callchain.h11
-rw-r--r--tools/perf/util/cpumap.h2
-rw-r--r--tools/perf/util/dso.c10
-rw-r--r--tools/perf/util/dso.h17
-rw-r--r--tools/perf/util/dwarf-aux.c19
-rw-r--r--tools/perf/util/dwarf-aux.h3
-rw-r--r--tools/perf/util/event.c87
-rw-r--r--tools/perf/util/event.h54
-rw-r--r--tools/perf/util/evlist.c307
-rw-r--r--tools/perf/util/evlist.h21
-rw-r--r--tools/perf/util/evsel.c597
-rw-r--r--tools/perf/util/evsel.h19
-rw-r--r--tools/perf/util/header.c205
-rw-r--r--tools/perf/util/header.h40
-rw-r--r--tools/perf/util/hist.c6
-rw-r--r--tools/perf/util/hist.h26
-rw-r--r--tools/perf/util/include/linux/string.h1
-rw-r--r--tools/perf/util/machine.c210
-rw-r--r--tools/perf/util/machine.h15
-rw-r--r--tools/perf/util/map.c75
-rw-r--r--tools/perf/util/map.h21
-rw-r--r--tools/perf/util/parse-events.c174
-rw-r--r--tools/perf/util/parse-events.h11
-rw-r--r--tools/perf/util/parse-events.l4
-rw-r--r--tools/perf/util/parse-events.y62
-rw-r--r--tools/perf/util/pmu.c87
-rw-r--r--tools/perf/util/pmu.h5
-rw-r--r--tools/perf/util/probe-finder.c89
-rw-r--r--tools/perf/util/probe-finder.h3
-rw-r--r--tools/perf/util/python.c21
-rw-r--r--tools/perf/util/record.c108
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c14
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c9
-rw-r--r--tools/perf/util/session.c318
-rw-r--r--tools/perf/util/session.h18
-rw-r--r--tools/perf/util/sort.c12
-rw-r--r--tools/perf/util/sort.h13
-rw-r--r--tools/perf/util/stat.c6
-rw-r--r--tools/perf/util/stat.h9
-rw-r--r--tools/perf/util/string.c24
-rw-r--r--tools/perf/util/symbol-elf.c190
-rw-r--r--tools/perf/util/symbol-minimal.c7
-rw-r--r--tools/perf/util/symbol.c285
-rw-r--r--tools/perf/util/symbol.h5
-rw-r--r--tools/perf/util/thread.c11
-rw-r--r--tools/perf/util/thread.h23
-rw-r--r--tools/perf/util/tool.h11
-rw-r--r--tools/perf/util/top.h2
-rw-r--r--tools/perf/util/trace-event-info.c96
-rw-r--r--tools/perf/util/trace-event-parse.c8
-rw-r--r--tools/perf/util/trace-event-read.c52
-rw-r--r--tools/perf/util/trace-event-scripting.c3
-rw-r--r--tools/perf/util/trace-event.h21
-rw-r--r--tools/perf/util/unwind.c2
-rw-r--r--tools/perf/util/util.c92
-rw-r--r--tools/perf/util/util.h5
113 files changed, 7241 insertions, 1762 deletions
diff --git a/tools/perf/Documentation/perf-diff.txt b/tools/perf/Documentation/perf-diff.txt
index 5b3123d5721f..fdfceee0ffd0 100644
--- a/tools/perf/Documentation/perf-diff.txt
+++ b/tools/perf/Documentation/perf-diff.txt
@@ -3,17 +3,17 @@ perf-diff(1)
3 3
4NAME 4NAME
5---- 5----
6perf-diff - Read two perf.data files and display the differential profile 6perf-diff - Read perf.data files and display the differential profile
7 7
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf diff' [oldfile] [newfile] 11'perf diff' [baseline file] [data file1] [[data file2] ... ]
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
15This command displays the performance difference amongst two perf.data files 15This command displays the performance difference amongst two or more perf.data
16captured via perf record. 16files captured via perf record.
17 17
18If no parameters are passed it will assume perf.data.old and perf.data. 18If no parameters are passed it will assume perf.data.old and perf.data.
19 19
@@ -75,8 +75,6 @@ OPTIONS
75-c:: 75-c::
76--compute:: 76--compute::
77 Differential computation selection - delta,ratio,wdiff (default is delta). 77 Differential computation selection - delta,ratio,wdiff (default is delta).
78 If '+' is specified as a first character, the output is sorted based
79 on the computation results.
80 See COMPARISON METHODS section for more info. 78 See COMPARISON METHODS section for more info.
81 79
82-p:: 80-p::
@@ -87,6 +85,63 @@ OPTIONS
87--formula:: 85--formula::
88 Show formula for given computation. 86 Show formula for given computation.
89 87
88-o::
89--order::
90 Specify compute sorting column number.
91
92COMPARISON
93----------
94The comparison is governed by the baseline file. The baseline perf.data
95file is iterated for samples. All other perf.data files specified on
96the command line are searched for the baseline sample pair. If the pair
97is found, specified computation is made and result is displayed.
98
99All samples from non-baseline perf.data files, that do not match any
100baseline entry, are displayed with empty space within baseline column
101and possible computation results (delta) in their related column.
102
103Example files samples:
104- file A with samples f1, f2, f3, f4, f6
105- file B with samples f2, f4, f5
106- file C with samples f1, f2, f5
107
108Example output:
109 x - computation takes place for pair
110 b - baseline sample percentage
111
112- perf diff A B C
113
114 baseline/A compute/B compute/C samples
115 ---------------------------------------
116 b x f1
117 b x x f2
118 b f3
119 b x f4
120 b f6
121 x x f5
122
123- perf diff B A C
124
125 baseline/B compute/A compute/C samples
126 ---------------------------------------
127 b x x f2
128 b x f4
129 b x f5
130 x x f1
131 x f3
132 x f6
133
134- perf diff C B A
135
136 baseline/C compute/B compute/A samples
137 ---------------------------------------
138 b x f1
139 b x x f2
140 b x f5
141 x f3
142 x x f4
143 x f6
144
90COMPARISON METHODS 145COMPARISON METHODS
91------------------ 146------------------
92delta 147delta
@@ -96,7 +151,7 @@ If specified the 'Delta' column is displayed with value 'd' computed as:
96 d = A->period_percent - B->period_percent 151 d = A->period_percent - B->period_percent
97 152
98with: 153with:
99 - A/B being matching hist entry from first/second file specified 154 - A/B being matching hist entry from data/baseline file specified
100 (or perf.data/perf.data.old) respectively. 155 (or perf.data/perf.data.old) respectively.
101 156
102 - period_percent being the % of the hist entry period value within 157 - period_percent being the % of the hist entry period value within
@@ -109,24 +164,26 @@ If specified the 'Ratio' column is displayed with value 'r' computed as:
109 r = A->period / B->period 164 r = A->period / B->period
110 165
111with: 166with:
112 - A/B being matching hist entry from first/second file specified 167 - A/B being matching hist entry from data/baseline file specified
113 (or perf.data/perf.data.old) respectively. 168 (or perf.data/perf.data.old) respectively.
114 169
115 - period being the hist entry period value 170 - period being the hist entry period value
116 171
117wdiff 172wdiff:WEIGHT-B,WEIGHT-A
118~~~~~ 173~~~~~~~~~~~~~~~~~~~~~~~
119If specified the 'Weighted diff' column is displayed with value 'd' computed as: 174If specified the 'Weighted diff' column is displayed with value 'd' computed as:
120 175
121 d = B->period * WEIGHT-A - A->period * WEIGHT-B 176 d = B->period * WEIGHT-A - A->period * WEIGHT-B
122 177
123 - A/B being matching hist entry from first/second file specified 178 - A/B being matching hist entry from data/baseline file specified
124 (or perf.data/perf.data.old) respectively. 179 (or perf.data/perf.data.old) respectively.
125 180
126 - period being the hist entry period value 181 - period being the hist entry period value
127 182
128 - WEIGHT-A/WEIGHT-B being user suplied weights in the the '-c' option 183 - WEIGHT-A/WEIGHT-B being user suplied weights in the the '-c' option
129 behind ':' separator like '-c wdiff:1,2'. 184 behind ':' separator like '-c wdiff:1,2'.
185 - WIEGHT-A being the weight of the data file
186 - WIEGHT-B being the weight of the baseline data file
130 187
131SEE ALSO 188SEE ALSO
132-------- 189--------
diff --git a/tools/perf/Documentation/perf-kvm.txt b/tools/perf/Documentation/perf-kvm.txt
index 326f2cb333cb..ac84db2d2334 100644
--- a/tools/perf/Documentation/perf-kvm.txt
+++ b/tools/perf/Documentation/perf-kvm.txt
@@ -13,6 +13,7 @@ SYNOPSIS
13 {top|record|report|diff|buildid-list} 13 {top|record|report|diff|buildid-list}
14'perf kvm' [--host] [--guest] [--guestkallsyms=<path> --guestmodules=<path> 14'perf kvm' [--host] [--guest] [--guestkallsyms=<path> --guestmodules=<path>
15 | --guestvmlinux=<path>] {top|record|report|diff|buildid-list|stat} 15 | --guestvmlinux=<path>] {top|record|report|diff|buildid-list|stat}
16'perf kvm stat [record|report|live] [<options>]
16 17
17DESCRIPTION 18DESCRIPTION
18----------- 19-----------
@@ -50,6 +51,10 @@ There are a couple of variants of perf kvm:
50 'perf kvm stat report' reports statistical data which includes events 51 'perf kvm stat report' reports statistical data which includes events
51 handled time, samples, and so on. 52 handled time, samples, and so on.
52 53
54 'perf kvm stat live' reports statistical data in a live mode (similar to
55 record + report but with statistical data updated live at a given display
56 rate).
57
53OPTIONS 58OPTIONS
54------- 59-------
55-i:: 60-i::
@@ -85,13 +90,50 @@ STAT REPORT OPTIONS
85--vcpu=<value>:: 90--vcpu=<value>::
86 analyze events which occures on this vcpu. (default: all vcpus) 91 analyze events which occures on this vcpu. (default: all vcpus)
87 92
88--events=<value>:: 93--event=<value>::
89 events to be analyzed. Possible values: vmexit, mmio, ioport. 94 event to be analyzed. Possible values: vmexit, mmio, ioport.
90 (default: vmexit) 95 (default: vmexit)
91-k:: 96-k::
92--key=<value>:: 97--key=<value>::
93 Sorting key. Possible values: sample (default, sort by samples 98 Sorting key. Possible values: sample (default, sort by samples
94 number), time (sort by average time). 99 number), time (sort by average time).
100-p::
101--pid=::
102 Analyze events only for given process ID(s) (comma separated list).
103
104STAT LIVE OPTIONS
105-----------------
106-d::
107--display::
108 Time in seconds between display updates
109
110-m::
111--mmap-pages=::
112 Number of mmap data pages. Must be a power of two.
113
114-a::
115--all-cpus::
116 System-wide collection from all CPUs.
117
118-p::
119--pid=::
120 Analyze events only for given process ID(s) (comma separated list).
121
122--vcpu=<value>::
123 analyze events which occures on this vcpu. (default: all vcpus)
124
125
126--event=<value>::
127 event to be analyzed. Possible values: vmexit, mmio, ioport.
128 (default: vmexit)
129
130-k::
131--key=<value>::
132 Sorting key. Possible values: sample (default, sort by samples
133 number), time (sort by average time).
134
135--duration=<value>::
136 Show events other than HLT that take longer than duration usecs.
95 137
96SEE ALSO 138SEE ALSO
97-------- 139--------
diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt
index d1e39dc8c810..6fce6a622206 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' [hw|sw|cache|tracepoint|event_glob] 11'perf list' [hw|sw|cache|tracepoint|pmu|event_glob]
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
@@ -29,6 +29,8 @@ counted. The following modifiers exist:
29 G - guest counting (in KVM guests) 29 G - guest counting (in KVM guests)
30 H - host counting (not in KVM guests) 30 H - host counting (not in KVM guests)
31 p - precise level 31 p - precise level
32 S - read sample value (PERF_SAMPLE_READ)
33 D - pin the event to the PMU
32 34
33The 'p' modifier can be used for specifying how precise the instruction 35The 'p' modifier can be used for specifying how precise the instruction
34address should be. The 'p' modifier can be specified multiple times: 36address should be. The 'p' modifier can be specified multiple times:
@@ -104,6 +106,8 @@ To limit the list use:
104 'subsys_glob:event_glob' to filter by tracepoint subsystems such as sched, 106 'subsys_glob:event_glob' to filter by tracepoint subsystems such as sched,
105 block, etc. 107 block, etc.
106 108
109. 'pmu' to print the kernel supplied PMU events.
110
107. If none of the above is matched, it will apply the supplied glob to all 111. If none of the above is matched, it will apply the supplied glob to all
108 events, printing the ones that match. 112 events, printing the ones that match.
109 113
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 66dab7410c1d..2b8097ee39d8 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -115,7 +115,7 @@ OPTIONS
115--dump-raw-trace:: 115--dump-raw-trace::
116 Dump raw trace in ASCII. 116 Dump raw trace in ASCII.
117 117
118-g [type,min[,limit],order]:: 118-g [type,min[,limit],order[,key]]::
119--call-graph:: 119--call-graph::
120 Display call chains using type, min percent threshold, optional print 120 Display call chains using type, min percent threshold, optional print
121 limit and order. 121 limit and order.
@@ -129,12 +129,21 @@ OPTIONS
129 - callee: callee based call graph. 129 - callee: callee based call graph.
130 - caller: inverted caller based call graph. 130 - caller: inverted caller based call graph.
131 131
132 Default: fractal,0.5,callee. 132 key can be:
133 - function: compare on functions
134 - address: compare on individual code addresses
135
136 Default: fractal,0.5,callee,function.
133 137
134-G:: 138-G::
135--inverted:: 139--inverted::
136 alias for inverted caller based call graph. 140 alias for inverted caller based call graph.
137 141
142--ignore-callees=<regex>::
143 Ignore callees of the function(s) matching the given regex.
144 This has the effect of collecting the callers of each such
145 function into one place in the call-graph tree.
146
138--pretty=<key>:: 147--pretty=<key>::
139 Pretty printing style. key: normal, raw 148 Pretty printing style. key: normal, raw
140 149
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index 2fe87fb558f0..73c9759005a3 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -132,6 +132,11 @@ is a useful mode to detect imbalance between physical cores. To enable this mod
132use --per-core in addition to -a. (system-wide). The output includes the 132use --per-core in addition to -a. (system-wide). The output includes the
133core number and the number of online logical processors on that physical processor. 133core number and the number of online logical processors on that physical processor.
134 134
135-D msecs::
136--initial-delay msecs::
137After starting the program, wait msecs before measuring. This is useful to
138filter out the startup phase of the program, which is often very different.
139
135EXAMPLES 140EXAMPLES
136-------- 141--------
137 142
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index 7fdd1909e376..58d6598a9686 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -155,6 +155,11 @@ Default is to monitor all CPUS.
155 155
156 Default: fractal,0.5,callee. 156 Default: fractal,0.5,callee.
157 157
158--ignore-callees=<regex>::
159 Ignore callees of the function(s) matching the given regex.
160 This has the effect of collecting the callers of each such
161 function into one place in the call-graph tree.
162
158--percent-limit:: 163--percent-limit::
159 Do not show entries which have an overhead under that percent. 164 Do not show entries which have an overhead under that percent.
160 (Default: 0). 165 (Default: 0).
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt
index 68718ccdd178..daccd2c0a48f 100644
--- a/tools/perf/Documentation/perf-trace.txt
+++ b/tools/perf/Documentation/perf-trace.txt
@@ -23,25 +23,45 @@ analysis phases.
23OPTIONS 23OPTIONS
24------- 24-------
25 25
26-a::
26--all-cpus:: 27--all-cpus::
27 System-wide collection from all CPUs. 28 System-wide collection from all CPUs.
28 29
30-e::
31--expr::
32 List of events to show, currently only syscall names.
33 Prefixing with ! shows all syscalls but the ones specified. You may
34 need to escape it.
35
36-o::
37--output=::
38 Output file name.
39
29-p:: 40-p::
30--pid=:: 41--pid=::
31 Record events on existing process ID (comma separated list). 42 Record events on existing process ID (comma separated list).
32 43
44-t::
33--tid=:: 45--tid=::
34 Record events on existing thread ID (comma separated list). 46 Record events on existing thread ID (comma separated list).
35 47
48-u::
36--uid=:: 49--uid=::
37 Record events in threads owned by uid. Name or number. 50 Record events in threads owned by uid. Name or number.
38 51
52-v::
53--verbose=::
54 Verbosity level.
55
56-i::
39--no-inherit:: 57--no-inherit::
40 Child tasks do not inherit counters. 58 Child tasks do not inherit counters.
41 59
60-m::
42--mmap-pages=:: 61--mmap-pages=::
43 Number of mmap data pages. Must be a power of two. 62 Number of mmap data pages. Must be a power of two.
44 63
64-C::
45--cpu:: 65--cpu::
46Collect samples only on the list of CPUs provided. Multiple CPUs can be provided as a 66Collect samples only on the list of CPUs provided. Multiple CPUs can be provided as a
47comma-separated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2. 67comma-separated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2.
@@ -54,6 +74,10 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs.
54--sched: 74--sched:
55 Accrue thread runtime and provide a summary at the end of the session. 75 Accrue thread runtime and provide a summary at the end of the session.
56 76
77-i
78--input
79 Process events from a given perf data file.
80
57SEE ALSO 81SEE ALSO
58-------- 82--------
59linkperf:perf-record[1], linkperf:perf-script[1] 83linkperf:perf-record[1], linkperf:perf-script[1]
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 641fccddb249..3a0ff7fb71b6 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -124,7 +124,7 @@ strip-libs = $(filter-out -l%,$(1))
124ifneq ($(OUTPUT),) 124ifneq ($(OUTPUT),)
125 TE_PATH=$(OUTPUT) 125 TE_PATH=$(OUTPUT)
126ifneq ($(subdir),) 126ifneq ($(subdir),)
127 LK_PATH=$(objtree)/lib/lk/ 127 LK_PATH=$(OUTPUT)/../lib/lk/
128else 128else
129 LK_PATH=$(OUTPUT) 129 LK_PATH=$(OUTPUT)
130endif 130endif
@@ -281,7 +281,7 @@ LIB_H += util/cpumap.h
281LIB_H += util/top.h 281LIB_H += util/top.h
282LIB_H += $(ARCH_INCLUDE) 282LIB_H += $(ARCH_INCLUDE)
283LIB_H += util/cgroup.h 283LIB_H += util/cgroup.h
284LIB_H += $(TRACE_EVENT_DIR)event-parse.h 284LIB_H += $(LIB_INCLUDE)traceevent/event-parse.h
285LIB_H += util/target.h 285LIB_H += util/target.h
286LIB_H += util/rblist.h 286LIB_H += util/rblist.h
287LIB_H += util/intlist.h 287LIB_H += util/intlist.h
@@ -360,6 +360,7 @@ LIB_OBJS += $(OUTPUT)util/rblist.o
360LIB_OBJS += $(OUTPUT)util/intlist.o 360LIB_OBJS += $(OUTPUT)util/intlist.o
361LIB_OBJS += $(OUTPUT)util/vdso.o 361LIB_OBJS += $(OUTPUT)util/vdso.o
362LIB_OBJS += $(OUTPUT)util/stat.o 362LIB_OBJS += $(OUTPUT)util/stat.o
363LIB_OBJS += $(OUTPUT)util/record.o
363 364
364LIB_OBJS += $(OUTPUT)ui/setup.o 365LIB_OBJS += $(OUTPUT)ui/setup.o
365LIB_OBJS += $(OUTPUT)ui/helpline.o 366LIB_OBJS += $(OUTPUT)ui/helpline.o
@@ -389,6 +390,12 @@ LIB_OBJS += $(OUTPUT)tests/bp_signal.o
389LIB_OBJS += $(OUTPUT)tests/bp_signal_overflow.o 390LIB_OBJS += $(OUTPUT)tests/bp_signal_overflow.o
390LIB_OBJS += $(OUTPUT)tests/task-exit.o 391LIB_OBJS += $(OUTPUT)tests/task-exit.o
391LIB_OBJS += $(OUTPUT)tests/sw-clock.o 392LIB_OBJS += $(OUTPUT)tests/sw-clock.o
393ifeq ($(ARCH),x86)
394LIB_OBJS += $(OUTPUT)tests/perf-time-to-tsc.o
395endif
396LIB_OBJS += $(OUTPUT)tests/code-reading.o
397LIB_OBJS += $(OUTPUT)tests/sample-parsing.o
398LIB_OBJS += $(OUTPUT)tests/parse-no-sample-id-all.o
392 399
393BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o 400BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
394BUILTIN_OBJS += $(OUTPUT)builtin-bench.o 401BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
@@ -459,6 +466,7 @@ endif # NO_LIBELF
459ifndef NO_LIBUNWIND 466ifndef NO_LIBUNWIND
460 LIB_OBJS += $(OUTPUT)util/unwind.o 467 LIB_OBJS += $(OUTPUT)util/unwind.o
461endif 468endif
469LIB_OBJS += $(OUTPUT)tests/keep-tracking.o
462 470
463ifndef NO_LIBAUDIT 471ifndef NO_LIBAUDIT
464 BUILTIN_OBJS += $(OUTPUT)builtin-trace.o 472 BUILTIN_OBJS += $(OUTPUT)builtin-trace.o
@@ -631,10 +639,10 @@ $(OUTPUT)util/parse-events.o: util/parse-events.c $(OUTPUT)PERF-CFLAGS
631 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-redundant-decls $< 639 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-redundant-decls $<
632 640
633$(OUTPUT)util/scripting-engines/trace-event-perl.o: util/scripting-engines/trace-event-perl.c $(OUTPUT)PERF-CFLAGS 641$(OUTPUT)util/scripting-engines/trace-event-perl.o: util/scripting-engines/trace-event-perl.c $(OUTPUT)PERF-CFLAGS
634 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $< 642 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow -Wno-undef -Wno-switch-default $<
635 643
636$(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o: scripts/perl/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS 644$(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o: scripts/perl/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS
637 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $< 645 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs -Wno-undef -Wno-switch-default $<
638 646
639$(OUTPUT)util/scripting-engines/trace-event-python.o: util/scripting-engines/trace-event-python.c $(OUTPUT)PERF-CFLAGS 647$(OUTPUT)util/scripting-engines/trace-event-python.o: util/scripting-engines/trace-event-python.c $(OUTPUT)PERF-CFLAGS
640 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $< 648 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $<
@@ -762,17 +770,21 @@ check: $(OUTPUT)common-cmds.h
762install-bin: all 770install-bin: all
763 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' 771 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
764 $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)' 772 $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)'
773 $(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
774ifndef NO_LIBPERL
765 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace' 775 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
766 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin' 776 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
767 $(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
768 $(INSTALL) scripts/perl/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace' 777 $(INSTALL) scripts/perl/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
769 $(INSTALL) scripts/perl/*.pl -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl' 778 $(INSTALL) scripts/perl/*.pl -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl'
770 $(INSTALL) scripts/perl/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin' 779 $(INSTALL) scripts/perl/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
780endif
781ifndef NO_LIBPYTHON
771 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace' 782 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace'
772 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin' 783 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
773 $(INSTALL) scripts/python/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace' 784 $(INSTALL) scripts/python/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace'
774 $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python' 785 $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python'
775 $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin' 786 $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
787endif
776 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d' 788 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d'
777 $(INSTALL) bash_completion '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d/perf' 789 $(INSTALL) bash_completion '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d/perf'
778 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests' 790 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'
diff --git a/tools/perf/arch/x86/Makefile b/tools/perf/arch/x86/Makefile
index 815841c04eb2..8801fe02f206 100644
--- a/tools/perf/arch/x86/Makefile
+++ b/tools/perf/arch/x86/Makefile
@@ -6,3 +6,5 @@ ifndef NO_LIBUNWIND
6LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind.o 6LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind.o
7endif 7endif
8LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o 8LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
9LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/tsc.o
10LIB_H += arch/$(ARCH)/util/tsc.h
diff --git a/tools/perf/arch/x86/util/tsc.c b/tools/perf/arch/x86/util/tsc.c
new file mode 100644
index 000000000000..b2519e49424f
--- /dev/null
+++ b/tools/perf/arch/x86/util/tsc.c
@@ -0,0 +1,59 @@
1#include <stdbool.h>
2#include <errno.h>
3
4#include <linux/perf_event.h>
5
6#include "../../perf.h"
7#include "../../util/types.h"
8#include "../../util/debug.h"
9#include "tsc.h"
10
11u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc)
12{
13 u64 t, quot, rem;
14
15 t = ns - tc->time_zero;
16 quot = t / tc->time_mult;
17 rem = t % tc->time_mult;
18 return (quot << tc->time_shift) +
19 (rem << tc->time_shift) / tc->time_mult;
20}
21
22u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc)
23{
24 u64 quot, rem;
25
26 quot = cyc >> tc->time_shift;
27 rem = cyc & ((1 << tc->time_shift) - 1);
28 return tc->time_zero + quot * tc->time_mult +
29 ((rem * tc->time_mult) >> tc->time_shift);
30}
31
32int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
33 struct perf_tsc_conversion *tc)
34{
35 bool cap_user_time_zero;
36 u32 seq;
37 int i = 0;
38
39 while (1) {
40 seq = pc->lock;
41 rmb();
42 tc->time_mult = pc->time_mult;
43 tc->time_shift = pc->time_shift;
44 tc->time_zero = pc->time_zero;
45 cap_user_time_zero = pc->cap_user_time_zero;
46 rmb();
47 if (pc->lock == seq && !(seq & 1))
48 break;
49 if (++i > 10000) {
50 pr_debug("failed to get perf_event_mmap_page lock\n");
51 return -EINVAL;
52 }
53 }
54
55 if (!cap_user_time_zero)
56 return -EOPNOTSUPP;
57
58 return 0;
59}
diff --git a/tools/perf/arch/x86/util/tsc.h b/tools/perf/arch/x86/util/tsc.h
new file mode 100644
index 000000000000..a24dec81c795
--- /dev/null
+++ b/tools/perf/arch/x86/util/tsc.h
@@ -0,0 +1,20 @@
1#ifndef TOOLS_PERF_ARCH_X86_UTIL_TSC_H__
2#define TOOLS_PERF_ARCH_X86_UTIL_TSC_H__
3
4#include "../../util/types.h"
5
6struct perf_tsc_conversion {
7 u16 time_shift;
8 u32 time_mult;
9 u64 time_zero;
10};
11
12struct perf_event_mmap_page;
13
14int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
15 struct perf_tsc_conversion *tc);
16
17u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc);
18u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc);
19
20#endif /* TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ */
diff --git a/tools/perf/bench/mem-memcpy.c b/tools/perf/bench/mem-memcpy.c
index 25fd3f1966f1..8cdca43016b2 100644
--- a/tools/perf/bench/mem-memcpy.c
+++ b/tools/perf/bench/mem-memcpy.c
@@ -117,6 +117,8 @@ static void alloc_mem(void **dst, void **src, size_t length)
117 *src = zalloc(length); 117 *src = zalloc(length);
118 if (!*src) 118 if (!*src)
119 die("memory allocation failed - maybe length is too large?\n"); 119 die("memory allocation failed - maybe length is too large?\n");
120 /* Make sure to always replace the zero pages even if MMAP_THRESH is crossed */
121 memset(*src, 0, length);
120} 122}
121 123
122static u64 do_memcpy_cycle(memcpy_t fn, size_t len, bool prefault) 124static u64 do_memcpy_cycle(memcpy_t fn, size_t len, bool prefault)
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index db491e9a812b..5ebd0c3b71b6 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -90,8 +90,7 @@ static int process_sample_event(struct perf_tool *tool,
90 struct perf_annotate *ann = container_of(tool, struct perf_annotate, tool); 90 struct perf_annotate *ann = container_of(tool, struct perf_annotate, tool);
91 struct addr_location al; 91 struct addr_location al;
92 92
93 if (perf_event__preprocess_sample(event, machine, &al, sample, 93 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
94 symbol__annotate_init) < 0) {
95 pr_warning("problem processing %d event, skipping it.\n", 94 pr_warning("problem processing %d event, skipping it.\n",
96 event->header.type); 95 event->header.type);
97 return -1; 96 return -1;
@@ -195,6 +194,8 @@ static int __cmd_annotate(struct perf_annotate *ann)
195 if (session == NULL) 194 if (session == NULL)
196 return -ENOMEM; 195 return -ENOMEM;
197 196
197 machines__set_symbol_filter(&session->machines, symbol__annotate_init);
198
198 if (ann->cpu_list) { 199 if (ann->cpu_list) {
199 ret = perf_session__cpu_bitmap(session, ann->cpu_list, 200 ret = perf_session__cpu_bitmap(session, ann->cpu_list,
200 ann->cpu_bitmap); 201 ann->cpu_bitmap);
@@ -276,6 +277,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
276 .tool = { 277 .tool = {
277 .sample = process_sample_event, 278 .sample = process_sample_event,
278 .mmap = perf_event__process_mmap, 279 .mmap = perf_event__process_mmap,
280 .mmap2 = perf_event__process_mmap2,
279 .comm = perf_event__process_comm, 281 .comm = perf_event__process_comm,
280 .exit = perf_event__process_exit, 282 .exit = perf_event__process_exit,
281 .fork = perf_event__process_fork, 283 .fork = perf_event__process_fork,
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 0aac5f3e594d..f28799e94f2a 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -18,15 +18,53 @@
18#include "util/util.h" 18#include "util/util.h"
19 19
20#include <stdlib.h> 20#include <stdlib.h>
21#include <math.h>
21 22
22static char const *input_old = "perf.data.old", 23/* Diff command specific HPP columns. */
23 *input_new = "perf.data"; 24enum {
24static char diff__default_sort_order[] = "dso,symbol"; 25 PERF_HPP_DIFF__BASELINE,
25static bool force; 26 PERF_HPP_DIFF__PERIOD,
27 PERF_HPP_DIFF__PERIOD_BASELINE,
28 PERF_HPP_DIFF__DELTA,
29 PERF_HPP_DIFF__RATIO,
30 PERF_HPP_DIFF__WEIGHTED_DIFF,
31 PERF_HPP_DIFF__FORMULA,
32
33 PERF_HPP_DIFF__MAX_INDEX
34};
35
36struct diff_hpp_fmt {
37 struct perf_hpp_fmt fmt;
38 int idx;
39 char *header;
40 int header_width;
41};
42
43struct data__file {
44 struct perf_session *session;
45 const char *file;
46 int idx;
47 struct hists *hists;
48 struct diff_hpp_fmt fmt[PERF_HPP_DIFF__MAX_INDEX];
49};
50
51static struct data__file *data__files;
52static int data__files_cnt;
53
54#define data__for_each_file_start(i, d, s) \
55 for (i = s, d = &data__files[s]; \
56 i < data__files_cnt; \
57 i++, d = &data__files[i])
58
59#define data__for_each_file(i, d) data__for_each_file_start(i, d, 0)
60#define data__for_each_file_new(i, d) data__for_each_file_start(i, d, 1)
61
62static char diff__default_sort_order[] = "dso,symbol";
63static bool force;
26static bool show_period; 64static bool show_period;
27static bool show_formula; 65static bool show_formula;
28static bool show_baseline_only; 66static bool show_baseline_only;
29static bool sort_compute; 67static unsigned int sort_compute;
30 68
31static s64 compute_wdiff_w1; 69static s64 compute_wdiff_w1;
32static s64 compute_wdiff_w2; 70static s64 compute_wdiff_w2;
@@ -46,6 +84,47 @@ const char *compute_names[COMPUTE_MAX] = {
46 84
47static int compute; 85static int compute;
48 86
87static int compute_2_hpp[COMPUTE_MAX] = {
88 [COMPUTE_DELTA] = PERF_HPP_DIFF__DELTA,
89 [COMPUTE_RATIO] = PERF_HPP_DIFF__RATIO,
90 [COMPUTE_WEIGHTED_DIFF] = PERF_HPP_DIFF__WEIGHTED_DIFF,
91};
92
93#define MAX_COL_WIDTH 70
94
95static struct header_column {
96 const char *name;
97 int width;
98} columns[PERF_HPP_DIFF__MAX_INDEX] = {
99 [PERF_HPP_DIFF__BASELINE] = {
100 .name = "Baseline",
101 },
102 [PERF_HPP_DIFF__PERIOD] = {
103 .name = "Period",
104 .width = 14,
105 },
106 [PERF_HPP_DIFF__PERIOD_BASELINE] = {
107 .name = "Base period",
108 .width = 14,
109 },
110 [PERF_HPP_DIFF__DELTA] = {
111 .name = "Delta",
112 .width = 7,
113 },
114 [PERF_HPP_DIFF__RATIO] = {
115 .name = "Ratio",
116 .width = 14,
117 },
118 [PERF_HPP_DIFF__WEIGHTED_DIFF] = {
119 .name = "Weighted diff",
120 .width = 14,
121 },
122 [PERF_HPP_DIFF__FORMULA] = {
123 .name = "Formula",
124 .width = MAX_COL_WIDTH,
125 }
126};
127
49static int setup_compute_opt_wdiff(char *opt) 128static int setup_compute_opt_wdiff(char *opt)
50{ 129{
51 char *w1_str = opt; 130 char *w1_str = opt;
@@ -109,13 +188,6 @@ static int setup_compute(const struct option *opt, const char *str,
109 return 0; 188 return 0;
110 } 189 }
111 190
112 if (*str == '+') {
113 sort_compute = true;
114 cstr = (char *) ++str;
115 if (!*str)
116 return 0;
117 }
118
119 option = strchr(str, ':'); 191 option = strchr(str, ':');
120 if (option) { 192 if (option) {
121 unsigned len = option++ - str; 193 unsigned len = option++ - str;
@@ -145,42 +217,42 @@ static int setup_compute(const struct option *opt, const char *str,
145 return -EINVAL; 217 return -EINVAL;
146} 218}
147 219
148double perf_diff__period_percent(struct hist_entry *he, u64 period) 220static double period_percent(struct hist_entry *he, u64 period)
149{ 221{
150 u64 total = he->hists->stats.total_period; 222 u64 total = he->hists->stats.total_period;
151 return (period * 100.0) / total; 223 return (period * 100.0) / total;
152} 224}
153 225
154double perf_diff__compute_delta(struct hist_entry *he, struct hist_entry *pair) 226static double compute_delta(struct hist_entry *he, struct hist_entry *pair)
155{ 227{
156 double new_percent = perf_diff__period_percent(he, he->stat.period); 228 double old_percent = period_percent(he, he->stat.period);
157 double old_percent = perf_diff__period_percent(pair, pair->stat.period); 229 double new_percent = period_percent(pair, pair->stat.period);
158 230
159 he->diff.period_ratio_delta = new_percent - old_percent; 231 pair->diff.period_ratio_delta = new_percent - old_percent;
160 he->diff.computed = true; 232 pair->diff.computed = true;
161 return he->diff.period_ratio_delta; 233 return pair->diff.period_ratio_delta;
162} 234}
163 235
164double perf_diff__compute_ratio(struct hist_entry *he, struct hist_entry *pair) 236static double compute_ratio(struct hist_entry *he, struct hist_entry *pair)
165{ 237{
166 double new_period = he->stat.period; 238 double old_period = he->stat.period ?: 1;
167 double old_period = pair->stat.period; 239 double new_period = pair->stat.period;
168 240
169 he->diff.computed = true; 241 pair->diff.computed = true;
170 he->diff.period_ratio = new_period / old_period; 242 pair->diff.period_ratio = new_period / old_period;
171 return he->diff.period_ratio; 243 return pair->diff.period_ratio;
172} 244}
173 245
174s64 perf_diff__compute_wdiff(struct hist_entry *he, struct hist_entry *pair) 246static s64 compute_wdiff(struct hist_entry *he, struct hist_entry *pair)
175{ 247{
176 u64 new_period = he->stat.period; 248 u64 old_period = he->stat.period;
177 u64 old_period = pair->stat.period; 249 u64 new_period = pair->stat.period;
178 250
179 he->diff.computed = true; 251 pair->diff.computed = true;
180 he->diff.wdiff = new_period * compute_wdiff_w2 - 252 pair->diff.wdiff = new_period * compute_wdiff_w2 -
181 old_period * compute_wdiff_w1; 253 old_period * compute_wdiff_w1;
182 254
183 return he->diff.wdiff; 255 return pair->diff.wdiff;
184} 256}
185 257
186static int formula_delta(struct hist_entry *he, struct hist_entry *pair, 258static int formula_delta(struct hist_entry *he, struct hist_entry *pair,
@@ -189,15 +261,15 @@ static int formula_delta(struct hist_entry *he, struct hist_entry *pair,
189 return scnprintf(buf, size, 261 return scnprintf(buf, size,
190 "(%" PRIu64 " * 100 / %" PRIu64 ") - " 262 "(%" PRIu64 " * 100 / %" PRIu64 ") - "
191 "(%" PRIu64 " * 100 / %" PRIu64 ")", 263 "(%" PRIu64 " * 100 / %" PRIu64 ")",
192 he->stat.period, he->hists->stats.total_period, 264 pair->stat.period, pair->hists->stats.total_period,
193 pair->stat.period, pair->hists->stats.total_period); 265 he->stat.period, he->hists->stats.total_period);
194} 266}
195 267
196static int formula_ratio(struct hist_entry *he, struct hist_entry *pair, 268static int formula_ratio(struct hist_entry *he, struct hist_entry *pair,
197 char *buf, size_t size) 269 char *buf, size_t size)
198{ 270{
199 double new_period = he->stat.period; 271 double old_period = he->stat.period;
200 double old_period = pair->stat.period; 272 double new_period = pair->stat.period;
201 273
202 return scnprintf(buf, size, "%.0F / %.0F", new_period, old_period); 274 return scnprintf(buf, size, "%.0F / %.0F", new_period, old_period);
203} 275}
@@ -205,16 +277,16 @@ static int formula_ratio(struct hist_entry *he, struct hist_entry *pair,
205static int formula_wdiff(struct hist_entry *he, struct hist_entry *pair, 277static int formula_wdiff(struct hist_entry *he, struct hist_entry *pair,
206 char *buf, size_t size) 278 char *buf, size_t size)
207{ 279{
208 u64 new_period = he->stat.period; 280 u64 old_period = he->stat.period;
209 u64 old_period = pair->stat.period; 281 u64 new_period = pair->stat.period;
210 282
211 return scnprintf(buf, size, 283 return scnprintf(buf, size,
212 "(%" PRIu64 " * " "%" PRId64 ") - (%" PRIu64 " * " "%" PRId64 ")", 284 "(%" PRIu64 " * " "%" PRId64 ") - (%" PRIu64 " * " "%" PRId64 ")",
213 new_period, compute_wdiff_w2, old_period, compute_wdiff_w1); 285 new_period, compute_wdiff_w2, old_period, compute_wdiff_w1);
214} 286}
215 287
216int perf_diff__formula(struct hist_entry *he, struct hist_entry *pair, 288static int formula_fprintf(struct hist_entry *he, struct hist_entry *pair,
217 char *buf, size_t size) 289 char *buf, size_t size)
218{ 290{
219 switch (compute) { 291 switch (compute) {
220 case COMPUTE_DELTA: 292 case COMPUTE_DELTA:
@@ -247,7 +319,7 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused,
247{ 319{
248 struct addr_location al; 320 struct addr_location al;
249 321
250 if (perf_event__preprocess_sample(event, machine, &al, sample, NULL) < 0) { 322 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
251 pr_warning("problem processing %d event, skipping it.\n", 323 pr_warning("problem processing %d event, skipping it.\n",
252 event->header.type); 324 event->header.type);
253 return -1; 325 return -1;
@@ -299,6 +371,29 @@ static void perf_evlist__collapse_resort(struct perf_evlist *evlist)
299 } 371 }
300} 372}
301 373
374static struct hist_entry*
375get_pair_data(struct hist_entry *he, struct data__file *d)
376{
377 if (hist_entry__has_pairs(he)) {
378 struct hist_entry *pair;
379
380 list_for_each_entry(pair, &he->pairs.head, pairs.node)
381 if (pair->hists == d->hists)
382 return pair;
383 }
384
385 return NULL;
386}
387
388static struct hist_entry*
389get_pair_fmt(struct hist_entry *he, struct diff_hpp_fmt *dfmt)
390{
391 void *ptr = dfmt - dfmt->idx;
392 struct data__file *d = container_of(ptr, struct data__file, fmt);
393
394 return get_pair_data(he, d);
395}
396
302static void hists__baseline_only(struct hists *hists) 397static void hists__baseline_only(struct hists *hists)
303{ 398{
304 struct rb_root *root; 399 struct rb_root *root;
@@ -333,22 +428,24 @@ static void hists__precompute(struct hists *hists)
333 428
334 next = rb_first(root); 429 next = rb_first(root);
335 while (next != NULL) { 430 while (next != NULL) {
336 struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node_in); 431 struct hist_entry *he, *pair;
337 struct hist_entry *pair = hist_entry__next_pair(he);
338 432
433 he = rb_entry(next, struct hist_entry, rb_node_in);
339 next = rb_next(&he->rb_node_in); 434 next = rb_next(&he->rb_node_in);
435
436 pair = get_pair_data(he, &data__files[sort_compute]);
340 if (!pair) 437 if (!pair)
341 continue; 438 continue;
342 439
343 switch (compute) { 440 switch (compute) {
344 case COMPUTE_DELTA: 441 case COMPUTE_DELTA:
345 perf_diff__compute_delta(he, pair); 442 compute_delta(he, pair);
346 break; 443 break;
347 case COMPUTE_RATIO: 444 case COMPUTE_RATIO:
348 perf_diff__compute_ratio(he, pair); 445 compute_ratio(he, pair);
349 break; 446 break;
350 case COMPUTE_WEIGHTED_DIFF: 447 case COMPUTE_WEIGHTED_DIFF:
351 perf_diff__compute_wdiff(he, pair); 448 compute_wdiff(he, pair);
352 break; 449 break;
353 default: 450 default:
354 BUG_ON(1); 451 BUG_ON(1);
@@ -367,7 +464,7 @@ static int64_t cmp_doubles(double l, double r)
367} 464}
368 465
369static int64_t 466static int64_t
370hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right, 467__hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,
371 int c) 468 int c)
372{ 469{
373 switch (c) { 470 switch (c) {
@@ -399,6 +496,36 @@ hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,
399 return 0; 496 return 0;
400} 497}
401 498
499static int64_t
500hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,
501 int c)
502{
503 bool pairs_left = hist_entry__has_pairs(left);
504 bool pairs_right = hist_entry__has_pairs(right);
505 struct hist_entry *p_right, *p_left;
506
507 if (!pairs_left && !pairs_right)
508 return 0;
509
510 if (!pairs_left || !pairs_right)
511 return pairs_left ? -1 : 1;
512
513 p_left = get_pair_data(left, &data__files[sort_compute]);
514 p_right = get_pair_data(right, &data__files[sort_compute]);
515
516 if (!p_left && !p_right)
517 return 0;
518
519 if (!p_left || !p_right)
520 return p_left ? -1 : 1;
521
522 /*
523 * We have 2 entries of same kind, let's
524 * make the data comparison.
525 */
526 return __hist_entry__cmp_compute(p_left, p_right, c);
527}
528
402static void insert_hist_entry_by_compute(struct rb_root *root, 529static void insert_hist_entry_by_compute(struct rb_root *root,
403 struct hist_entry *he, 530 struct hist_entry *he,
404 int c) 531 int c)
@@ -448,75 +575,121 @@ static void hists__compute_resort(struct hists *hists)
448 } 575 }
449} 576}
450 577
451static void hists__process(struct hists *old, struct hists *new) 578static void hists__process(struct hists *hists)
452{ 579{
453 hists__match(new, old);
454
455 if (show_baseline_only) 580 if (show_baseline_only)
456 hists__baseline_only(new); 581 hists__baseline_only(hists);
457 else
458 hists__link(new, old);
459 582
460 if (sort_compute) { 583 if (sort_compute) {
461 hists__precompute(new); 584 hists__precompute(hists);
462 hists__compute_resort(new); 585 hists__compute_resort(hists);
463 } else { 586 } else {
464 hists__output_resort(new); 587 hists__output_resort(hists);
465 } 588 }
466 589
467 hists__fprintf(new, true, 0, 0, 0, stdout); 590 hists__fprintf(hists, true, 0, 0, 0, stdout);
468} 591}
469 592
470static int __cmd_diff(void) 593static void data__fprintf(void)
471{ 594{
472 int ret, i; 595 struct data__file *d;
473#define older (session[0]) 596 int i;
474#define newer (session[1]) 597
475 struct perf_session *session[2]; 598 fprintf(stdout, "# Data files:\n");
476 struct perf_evlist *evlist_new, *evlist_old; 599
477 struct perf_evsel *evsel; 600 data__for_each_file(i, d)
601 fprintf(stdout, "# [%d] %s %s\n",
602 d->idx, d->file,
603 !d->idx ? "(Baseline)" : "");
604
605 fprintf(stdout, "#\n");
606}
607
608static void data_process(void)
609{
610 struct perf_evlist *evlist_base = data__files[0].session->evlist;
611 struct perf_evsel *evsel_base;
478 bool first = true; 612 bool first = true;
479 613
480 older = perf_session__new(input_old, O_RDONLY, force, false, 614 list_for_each_entry(evsel_base, &evlist_base->entries, node) {
481 &tool); 615 struct data__file *d;
482 newer = perf_session__new(input_new, O_RDONLY, force, false, 616 int i;
483 &tool);
484 if (session[0] == NULL || session[1] == NULL)
485 return -ENOMEM;
486 617
487 for (i = 0; i < 2; ++i) { 618 data__for_each_file_new(i, d) {
488 ret = perf_session__process_events(session[i], &tool); 619 struct perf_evlist *evlist = d->session->evlist;
489 if (ret) 620 struct perf_evsel *evsel;
490 goto out_delete;
491 }
492 621
493 evlist_old = older->evlist; 622 evsel = evsel_match(evsel_base, evlist);
494 evlist_new = newer->evlist; 623 if (!evsel)
624 continue;
495 625
496 perf_evlist__collapse_resort(evlist_old); 626 d->hists = &evsel->hists;
497 perf_evlist__collapse_resort(evlist_new);
498 627
499 list_for_each_entry(evsel, &evlist_new->entries, node) { 628 hists__match(&evsel_base->hists, &evsel->hists);
500 struct perf_evsel *evsel_old;
501 629
502 evsel_old = evsel_match(evsel, evlist_old); 630 if (!show_baseline_only)
503 if (!evsel_old) 631 hists__link(&evsel_base->hists,
504 continue; 632 &evsel->hists);
633 }
505 634
506 fprintf(stdout, "%s# Event '%s'\n#\n", first ? "" : "\n", 635 fprintf(stdout, "%s# Event '%s'\n#\n", first ? "" : "\n",
507 perf_evsel__name(evsel)); 636 perf_evsel__name(evsel_base));
508 637
509 first = false; 638 first = false;
510 639
511 hists__process(&evsel_old->hists, &evsel->hists); 640 if (verbose || data__files_cnt > 2)
641 data__fprintf();
642
643 hists__process(&evsel_base->hists);
644 }
645}
646
647static void data__free(struct data__file *d)
648{
649 int col;
650
651 for (col = 0; col < PERF_HPP_DIFF__MAX_INDEX; col++) {
652 struct diff_hpp_fmt *fmt = &d->fmt[col];
653
654 free(fmt->header);
512 } 655 }
656}
513 657
514out_delete: 658static int __cmd_diff(void)
515 for (i = 0; i < 2; ++i) 659{
516 perf_session__delete(session[i]); 660 struct data__file *d;
661 int ret = -EINVAL, i;
662
663 data__for_each_file(i, d) {
664 d->session = perf_session__new(d->file, O_RDONLY, force,
665 false, &tool);
666 if (!d->session) {
667 pr_err("Failed to open %s\n", d->file);
668 ret = -ENOMEM;
669 goto out_delete;
670 }
671
672 ret = perf_session__process_events(d->session, &tool);
673 if (ret) {
674 pr_err("Failed to process %s\n", d->file);
675 goto out_delete;
676 }
677
678 perf_evlist__collapse_resort(d->session->evlist);
679 }
680
681 data_process();
682
683 out_delete:
684 data__for_each_file(i, d) {
685 if (d->session)
686 perf_session__delete(d->session);
687
688 data__free(d);
689 }
690
691 free(data__files);
517 return ret; 692 return ret;
518#undef older
519#undef newer
520} 693}
521 694
522static const char * const diff_usage[] = { 695static const char * const diff_usage[] = {
@@ -555,61 +728,310 @@ static const struct option options[] = {
555 "columns '.' is reserved."), 728 "columns '.' is reserved."),
556 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", 729 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
557 "Look for files with symbols relative to this directory"), 730 "Look for files with symbols relative to this directory"),
731 OPT_UINTEGER('o', "order", &sort_compute, "Specify compute sorting."),
558 OPT_END() 732 OPT_END()
559}; 733};
560 734
561static void ui_init(void) 735static double baseline_percent(struct hist_entry *he)
562{ 736{
563 /* 737 struct hists *hists = he->hists;
564 * Display baseline/delta/ratio 738 return 100.0 * he->stat.period / hists->stats.total_period;
565 * formula/periods columns. 739}
566 */
567 perf_hpp__column_enable(PERF_HPP__BASELINE);
568 740
569 switch (compute) { 741static int hpp__color_baseline(struct perf_hpp_fmt *fmt,
570 case COMPUTE_DELTA: 742 struct perf_hpp *hpp, struct hist_entry *he)
571 perf_hpp__column_enable(PERF_HPP__DELTA); 743{
744 struct diff_hpp_fmt *dfmt =
745 container_of(fmt, struct diff_hpp_fmt, fmt);
746 double percent = baseline_percent(he);
747 char pfmt[20] = " ";
748
749 if (!he->dummy) {
750 scnprintf(pfmt, 20, "%%%d.2f%%%%", dfmt->header_width - 1);
751 return percent_color_snprintf(hpp->buf, hpp->size,
752 pfmt, percent);
753 } else
754 return scnprintf(hpp->buf, hpp->size, "%*s",
755 dfmt->header_width, pfmt);
756}
757
758static int hpp__entry_baseline(struct hist_entry *he, char *buf, size_t size)
759{
760 double percent = baseline_percent(he);
761 const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
762 int ret = 0;
763
764 if (!he->dummy)
765 ret = scnprintf(buf, size, fmt, percent);
766
767 return ret;
768}
769
770static void
771hpp__entry_unpair(struct hist_entry *he, int idx, char *buf, size_t size)
772{
773 switch (idx) {
774 case PERF_HPP_DIFF__PERIOD_BASELINE:
775 scnprintf(buf, size, "%" PRIu64, he->stat.period);
572 break; 776 break;
573 case COMPUTE_RATIO: 777
574 perf_hpp__column_enable(PERF_HPP__RATIO); 778 default:
575 break; 779 break;
576 case COMPUTE_WEIGHTED_DIFF: 780 }
577 perf_hpp__column_enable(PERF_HPP__WEIGHTED_DIFF); 781}
782
783static void
784hpp__entry_pair(struct hist_entry *he, struct hist_entry *pair,
785 int idx, char *buf, size_t size)
786{
787 double diff;
788 double ratio;
789 s64 wdiff;
790
791 switch (idx) {
792 case PERF_HPP_DIFF__DELTA:
793 if (pair->diff.computed)
794 diff = pair->diff.period_ratio_delta;
795 else
796 diff = compute_delta(he, pair);
797
798 if (fabs(diff) >= 0.01)
799 scnprintf(buf, size, "%+4.2F%%", diff);
800 break;
801
802 case PERF_HPP_DIFF__RATIO:
803 /* No point for ratio number if we are dummy.. */
804 if (he->dummy)
805 break;
806
807 if (pair->diff.computed)
808 ratio = pair->diff.period_ratio;
809 else
810 ratio = compute_ratio(he, pair);
811
812 if (ratio > 0.0)
813 scnprintf(buf, size, "%14.6F", ratio);
814 break;
815
816 case PERF_HPP_DIFF__WEIGHTED_DIFF:
817 /* No point for wdiff number if we are dummy.. */
818 if (he->dummy)
819 break;
820
821 if (pair->diff.computed)
822 wdiff = pair->diff.wdiff;
823 else
824 wdiff = compute_wdiff(he, pair);
825
826 if (wdiff != 0)
827 scnprintf(buf, size, "%14ld", wdiff);
828 break;
829
830 case PERF_HPP_DIFF__FORMULA:
831 formula_fprintf(he, pair, buf, size);
832 break;
833
834 case PERF_HPP_DIFF__PERIOD:
835 scnprintf(buf, size, "%" PRIu64, pair->stat.period);
578 break; 836 break;
837
579 default: 838 default:
580 BUG_ON(1); 839 BUG_ON(1);
581 }; 840 };
841}
842
843static void
844__hpp__entry_global(struct hist_entry *he, struct diff_hpp_fmt *dfmt,
845 char *buf, size_t size)
846{
847 struct hist_entry *pair = get_pair_fmt(he, dfmt);
848 int idx = dfmt->idx;
849
850 /* baseline is special */
851 if (idx == PERF_HPP_DIFF__BASELINE)
852 hpp__entry_baseline(he, buf, size);
853 else {
854 if (pair)
855 hpp__entry_pair(he, pair, idx, buf, size);
856 else
857 hpp__entry_unpair(he, idx, buf, size);
858 }
859}
860
861static int hpp__entry_global(struct perf_hpp_fmt *_fmt, struct perf_hpp *hpp,
862 struct hist_entry *he)
863{
864 struct diff_hpp_fmt *dfmt =
865 container_of(_fmt, struct diff_hpp_fmt, fmt);
866 char buf[MAX_COL_WIDTH] = " ";
867
868 __hpp__entry_global(he, dfmt, buf, MAX_COL_WIDTH);
869
870 if (symbol_conf.field_sep)
871 return scnprintf(hpp->buf, hpp->size, "%s", buf);
872 else
873 return scnprintf(hpp->buf, hpp->size, "%*s",
874 dfmt->header_width, buf);
875}
876
877static int hpp__header(struct perf_hpp_fmt *fmt,
878 struct perf_hpp *hpp)
879{
880 struct diff_hpp_fmt *dfmt =
881 container_of(fmt, struct diff_hpp_fmt, fmt);
582 882
583 if (show_formula) 883 BUG_ON(!dfmt->header);
584 perf_hpp__column_enable(PERF_HPP__FORMULA); 884 return scnprintf(hpp->buf, hpp->size, dfmt->header);
885}
585 886
586 if (show_period) { 887static int hpp__width(struct perf_hpp_fmt *fmt,
587 perf_hpp__column_enable(PERF_HPP__PERIOD); 888 struct perf_hpp *hpp __maybe_unused)
588 perf_hpp__column_enable(PERF_HPP__PERIOD_BASELINE); 889{
890 struct diff_hpp_fmt *dfmt =
891 container_of(fmt, struct diff_hpp_fmt, fmt);
892
893 BUG_ON(dfmt->header_width <= 0);
894 return dfmt->header_width;
895}
896
897static void init_header(struct data__file *d, struct diff_hpp_fmt *dfmt)
898{
899#define MAX_HEADER_NAME 100
900 char buf_indent[MAX_HEADER_NAME];
901 char buf[MAX_HEADER_NAME];
902 const char *header = NULL;
903 int width = 0;
904
905 BUG_ON(dfmt->idx >= PERF_HPP_DIFF__MAX_INDEX);
906 header = columns[dfmt->idx].name;
907 width = columns[dfmt->idx].width;
908
909 /* Only our defined HPP fmts should appear here. */
910 BUG_ON(!header);
911
912 if (data__files_cnt > 2)
913 scnprintf(buf, MAX_HEADER_NAME, "%s/%d", header, d->idx);
914
915#define NAME (data__files_cnt > 2 ? buf : header)
916 dfmt->header_width = width;
917 width = (int) strlen(NAME);
918 if (dfmt->header_width < width)
919 dfmt->header_width = width;
920
921 scnprintf(buf_indent, MAX_HEADER_NAME, "%*s",
922 dfmt->header_width, NAME);
923
924 dfmt->header = strdup(buf_indent);
925#undef MAX_HEADER_NAME
926#undef NAME
927}
928
929static void data__hpp_register(struct data__file *d, int idx)
930{
931 struct diff_hpp_fmt *dfmt = &d->fmt[idx];
932 struct perf_hpp_fmt *fmt = &dfmt->fmt;
933
934 dfmt->idx = idx;
935
936 fmt->header = hpp__header;
937 fmt->width = hpp__width;
938 fmt->entry = hpp__entry_global;
939
940 /* TODO more colors */
941 if (idx == PERF_HPP_DIFF__BASELINE)
942 fmt->color = hpp__color_baseline;
943
944 init_header(d, dfmt);
945 perf_hpp__column_register(fmt);
946}
947
948static void ui_init(void)
949{
950 struct data__file *d;
951 int i;
952
953 data__for_each_file(i, d) {
954
955 /*
956 * Baseline or compute realted columns:
957 *
958 * PERF_HPP_DIFF__BASELINE
959 * PERF_HPP_DIFF__DELTA
960 * PERF_HPP_DIFF__RATIO
961 * PERF_HPP_DIFF__WEIGHTED_DIFF
962 */
963 data__hpp_register(d, i ? compute_2_hpp[compute] :
964 PERF_HPP_DIFF__BASELINE);
965
966 /*
967 * And the rest:
968 *
969 * PERF_HPP_DIFF__FORMULA
970 * PERF_HPP_DIFF__PERIOD
971 * PERF_HPP_DIFF__PERIOD_BASELINE
972 */
973 if (show_formula && i)
974 data__hpp_register(d, PERF_HPP_DIFF__FORMULA);
975
976 if (show_period)
977 data__hpp_register(d, i ? PERF_HPP_DIFF__PERIOD :
978 PERF_HPP_DIFF__PERIOD_BASELINE);
589 } 979 }
590} 980}
591 981
592int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused) 982static int data_init(int argc, const char **argv)
593{ 983{
594 sort_order = diff__default_sort_order; 984 struct data__file *d;
595 argc = parse_options(argc, argv, options, diff_usage, 0); 985 static const char *defaults[] = {
986 "perf.data.old",
987 "perf.data",
988 };
989 bool use_default = true;
990 int i;
991
992 data__files_cnt = 2;
993
596 if (argc) { 994 if (argc) {
597 if (argc > 2) 995 if (argc == 1)
598 usage_with_options(diff_usage, options); 996 defaults[1] = argv[0];
599 if (argc == 2) { 997 else {
600 input_old = argv[0]; 998 data__files_cnt = argc;
601 input_new = argv[1]; 999 use_default = false;
602 } else 1000 }
603 input_new = argv[0];
604 } else if (symbol_conf.default_guest_vmlinux_name || 1001 } else if (symbol_conf.default_guest_vmlinux_name ||
605 symbol_conf.default_guest_kallsyms) { 1002 symbol_conf.default_guest_kallsyms) {
606 input_old = "perf.data.host"; 1003 defaults[0] = "perf.data.host";
607 input_new = "perf.data.guest"; 1004 defaults[1] = "perf.data.guest";
608 } 1005 }
609 1006
1007 if (sort_compute >= (unsigned int) data__files_cnt) {
1008 pr_err("Order option out of limit.\n");
1009 return -EINVAL;
1010 }
1011
1012 data__files = zalloc(sizeof(*data__files) * data__files_cnt);
1013 if (!data__files)
1014 return -ENOMEM;
1015
1016 data__for_each_file(i, d) {
1017 d->file = use_default ? defaults[i] : argv[i];
1018 d->idx = i;
1019 }
1020
1021 return 0;
1022}
1023
1024int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
1025{
1026 sort_order = diff__default_sort_order;
1027 argc = parse_options(argc, argv, options, diff_usage, 0);
1028
610 if (symbol__init() < 0) 1029 if (symbol__init() < 0)
611 return -1; 1030 return -1;
612 1031
1032 if (data_init(argc, argv) < 0)
1033 return -1;
1034
613 ui_init(); 1035 ui_init();
614 1036
615 if (setup_sorting() < 0) 1037 if (setup_sorting() < 0)
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 84ad6abe4258..afe377b2884f 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -38,8 +38,7 @@ struct event_entry {
38}; 38};
39 39
40static int perf_event__repipe_synth(struct perf_tool *tool, 40static int perf_event__repipe_synth(struct perf_tool *tool,
41 union perf_event *event, 41 union perf_event *event)
42 struct machine *machine __maybe_unused)
43{ 42{
44 struct perf_inject *inject = container_of(tool, struct perf_inject, tool); 43 struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
45 uint32_t size; 44 uint32_t size;
@@ -65,39 +64,28 @@ static int perf_event__repipe_op2_synth(struct perf_tool *tool,
65 struct perf_session *session 64 struct perf_session *session
66 __maybe_unused) 65 __maybe_unused)
67{ 66{
68 return perf_event__repipe_synth(tool, event, NULL); 67 return perf_event__repipe_synth(tool, event);
69} 68}
70 69
71static int perf_event__repipe_event_type_synth(struct perf_tool *tool, 70static int perf_event__repipe_attr(struct perf_tool *tool,
72 union perf_event *event) 71 union perf_event *event,
73{ 72 struct perf_evlist **pevlist)
74 return perf_event__repipe_synth(tool, event, NULL);
75}
76
77static int perf_event__repipe_tracing_data_synth(union perf_event *event,
78 struct perf_session *session
79 __maybe_unused)
80{
81 return perf_event__repipe_synth(NULL, event, NULL);
82}
83
84static int perf_event__repipe_attr(union perf_event *event,
85 struct perf_evlist **pevlist __maybe_unused)
86{ 73{
87 int ret; 74 int ret;
88 ret = perf_event__process_attr(event, pevlist); 75
76 ret = perf_event__process_attr(tool, event, pevlist);
89 if (ret) 77 if (ret)
90 return ret; 78 return ret;
91 79
92 return perf_event__repipe_synth(NULL, event, NULL); 80 return perf_event__repipe_synth(tool, event);
93} 81}
94 82
95static int perf_event__repipe(struct perf_tool *tool, 83static int perf_event__repipe(struct perf_tool *tool,
96 union perf_event *event, 84 union perf_event *event,
97 struct perf_sample *sample __maybe_unused, 85 struct perf_sample *sample __maybe_unused,
98 struct machine *machine) 86 struct machine *machine __maybe_unused)
99{ 87{
100 return perf_event__repipe_synth(tool, event, machine); 88 return perf_event__repipe_synth(tool, event);
101} 89}
102 90
103typedef int (*inject_handler)(struct perf_tool *tool, 91typedef int (*inject_handler)(struct perf_tool *tool,
@@ -119,7 +107,7 @@ static int perf_event__repipe_sample(struct perf_tool *tool,
119 107
120 build_id__mark_dso_hit(tool, event, sample, evsel, machine); 108 build_id__mark_dso_hit(tool, event, sample, evsel, machine);
121 109
122 return perf_event__repipe_synth(tool, event, machine); 110 return perf_event__repipe_synth(tool, event);
123} 111}
124 112
125static int perf_event__repipe_mmap(struct perf_tool *tool, 113static int perf_event__repipe_mmap(struct perf_tool *tool,
@@ -135,6 +123,19 @@ static int perf_event__repipe_mmap(struct perf_tool *tool,
135 return err; 123 return err;
136} 124}
137 125
126static int perf_event__repipe_mmap2(struct perf_tool *tool,
127 union perf_event *event,
128 struct perf_sample *sample,
129 struct machine *machine)
130{
131 int err;
132
133 err = perf_event__process_mmap2(tool, event, sample, machine);
134 perf_event__repipe(tool, event, sample, machine);
135
136 return err;
137}
138
138static int perf_event__repipe_fork(struct perf_tool *tool, 139static int perf_event__repipe_fork(struct perf_tool *tool,
139 union perf_event *event, 140 union perf_event *event,
140 struct perf_sample *sample, 141 struct perf_sample *sample,
@@ -148,13 +149,14 @@ static int perf_event__repipe_fork(struct perf_tool *tool,
148 return err; 149 return err;
149} 150}
150 151
151static int perf_event__repipe_tracing_data(union perf_event *event, 152static int perf_event__repipe_tracing_data(struct perf_tool *tool,
153 union perf_event *event,
152 struct perf_session *session) 154 struct perf_session *session)
153{ 155{
154 int err; 156 int err;
155 157
156 perf_event__repipe_synth(NULL, event, NULL); 158 perf_event__repipe_synth(tool, event);
157 err = perf_event__process_tracing_data(event, session); 159 err = perf_event__process_tracing_data(tool, event, session);
158 160
159 return err; 161 return err;
160} 162}
@@ -209,7 +211,7 @@ static int perf_event__inject_buildid(struct perf_tool *tool,
209 211
210 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 212 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
211 213
212 thread = machine__findnew_thread(machine, event->ip.pid); 214 thread = machine__findnew_thread(machine, sample->pid, sample->pid);
213 if (thread == NULL) { 215 if (thread == NULL) {
214 pr_err("problem processing %d event, skipping it.\n", 216 pr_err("problem processing %d event, skipping it.\n",
215 event->header.type); 217 event->header.type);
@@ -217,7 +219,7 @@ static int perf_event__inject_buildid(struct perf_tool *tool,
217 } 219 }
218 220
219 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, 221 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
220 event->ip.ip, &al); 222 sample->ip, &al);
221 223
222 if (al.map != NULL) { 224 if (al.map != NULL) {
223 if (!al.map->dso->hit) { 225 if (!al.map->dso->hit) {
@@ -312,13 +314,13 @@ found:
312 sample_sw.period = sample->period; 314 sample_sw.period = sample->period;
313 sample_sw.time = sample->time; 315 sample_sw.time = sample->time;
314 perf_event__synthesize_sample(event_sw, evsel->attr.sample_type, 316 perf_event__synthesize_sample(event_sw, evsel->attr.sample_type,
315 &sample_sw, false); 317 evsel->attr.sample_regs_user,
318 evsel->attr.read_format, &sample_sw,
319 false);
316 build_id__mark_dso_hit(tool, event_sw, &sample_sw, evsel, machine); 320 build_id__mark_dso_hit(tool, event_sw, &sample_sw, evsel, machine);
317 return perf_event__repipe(tool, event_sw, &sample_sw, machine); 321 return perf_event__repipe(tool, event_sw, &sample_sw, machine);
318} 322}
319 323
320extern volatile int session_done;
321
322static void sig_handler(int sig __maybe_unused) 324static void sig_handler(int sig __maybe_unused)
323{ 325{
324 session_done = 1; 326 session_done = 1;
@@ -348,6 +350,7 @@ static int __cmd_inject(struct perf_inject *inject)
348 350
349 if (inject->build_ids || inject->sched_stat) { 351 if (inject->build_ids || inject->sched_stat) {
350 inject->tool.mmap = perf_event__repipe_mmap; 352 inject->tool.mmap = perf_event__repipe_mmap;
353 inject->tool.mmap2 = perf_event__repipe_mmap2;
351 inject->tool.fork = perf_event__repipe_fork; 354 inject->tool.fork = perf_event__repipe_fork;
352 inject->tool.tracing_data = perf_event__repipe_tracing_data; 355 inject->tool.tracing_data = perf_event__repipe_tracing_data;
353 } 356 }
@@ -399,6 +402,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
399 .tool = { 402 .tool = {
400 .sample = perf_event__repipe_sample, 403 .sample = perf_event__repipe_sample,
401 .mmap = perf_event__repipe, 404 .mmap = perf_event__repipe,
405 .mmap2 = perf_event__repipe,
402 .comm = perf_event__repipe, 406 .comm = perf_event__repipe,
403 .fork = perf_event__repipe, 407 .fork = perf_event__repipe,
404 .exit = perf_event__repipe, 408 .exit = perf_event__repipe,
@@ -407,8 +411,8 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
407 .throttle = perf_event__repipe, 411 .throttle = perf_event__repipe,
408 .unthrottle = perf_event__repipe, 412 .unthrottle = perf_event__repipe,
409 .attr = perf_event__repipe_attr, 413 .attr = perf_event__repipe_attr,
410 .event_type = perf_event__repipe_event_type_synth, 414 .tracing_data = perf_event__repipe_op2_synth,
411 .tracing_data = perf_event__repipe_tracing_data_synth, 415 .finished_round = perf_event__repipe_op2_synth,
412 .build_id = perf_event__repipe_op2_synth, 416 .build_id = perf_event__repipe_op2_synth,
413 }, 417 },
414 .input_name = "-", 418 .input_name = "-",
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 0259502638b4..9b5f077fee5b 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -101,7 +101,7 @@ static int setup_cpunode_map(void)
101 101
102 dir1 = opendir(PATH_SYS_NODE); 102 dir1 = opendir(PATH_SYS_NODE);
103 if (!dir1) 103 if (!dir1)
104 return -1; 104 return 0;
105 105
106 while ((dent1 = readdir(dir1)) != NULL) { 106 while ((dent1 = readdir(dir1)) != NULL) {
107 if (dent1->d_type != DT_DIR || 107 if (dent1->d_type != DT_DIR ||
@@ -305,7 +305,8 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
305 struct perf_evsel *evsel, 305 struct perf_evsel *evsel,
306 struct machine *machine) 306 struct machine *machine)
307{ 307{
308 struct thread *thread = machine__findnew_thread(machine, event->ip.pid); 308 struct thread *thread = machine__findnew_thread(machine, sample->pid,
309 sample->pid);
309 310
310 if (thread == NULL) { 311 if (thread == NULL) {
311 pr_debug("problem processing %d event, skipping it.\n", 312 pr_debug("problem processing %d event, skipping it.\n",
@@ -313,7 +314,7 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
313 return -1; 314 return -1;
314 } 315 }
315 316
316 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 317 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->tid);
317 318
318 if (evsel->handler.func != NULL) { 319 if (evsel->handler.func != NULL) {
319 tracepoint_handler f = evsel->handler.func; 320 tracepoint_handler f = evsel->handler.func;
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index 24b78aecc928..935d52216c89 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -2,22 +2,26 @@
2#include "perf.h" 2#include "perf.h"
3 3
4#include "util/evsel.h" 4#include "util/evsel.h"
5#include "util/evlist.h"
5#include "util/util.h" 6#include "util/util.h"
6#include "util/cache.h" 7#include "util/cache.h"
7#include "util/symbol.h" 8#include "util/symbol.h"
8#include "util/thread.h" 9#include "util/thread.h"
9#include "util/header.h" 10#include "util/header.h"
10#include "util/session.h" 11#include "util/session.h"
11 12#include "util/intlist.h"
12#include "util/parse-options.h" 13#include "util/parse-options.h"
13#include "util/trace-event.h" 14#include "util/trace-event.h"
14#include "util/debug.h" 15#include "util/debug.h"
15#include <lk/debugfs.h> 16#include <lk/debugfs.h>
16#include "util/tool.h" 17#include "util/tool.h"
17#include "util/stat.h" 18#include "util/stat.h"
19#include "util/top.h"
18 20
19#include <sys/prctl.h> 21#include <sys/prctl.h>
22#include <sys/timerfd.h>
20 23
24#include <termios.h>
21#include <semaphore.h> 25#include <semaphore.h>
22#include <pthread.h> 26#include <pthread.h>
23#include <math.h> 27#include <math.h>
@@ -82,6 +86,8 @@ struct exit_reasons_table {
82 86
83struct perf_kvm_stat { 87struct perf_kvm_stat {
84 struct perf_tool tool; 88 struct perf_tool tool;
89 struct perf_record_opts opts;
90 struct perf_evlist *evlist;
85 struct perf_session *session; 91 struct perf_session *session;
86 92
87 const char *file_name; 93 const char *file_name;
@@ -96,10 +102,20 @@ struct perf_kvm_stat {
96 struct kvm_events_ops *events_ops; 102 struct kvm_events_ops *events_ops;
97 key_cmp_fun compare; 103 key_cmp_fun compare;
98 struct list_head kvm_events_cache[EVENTS_CACHE_SIZE]; 104 struct list_head kvm_events_cache[EVENTS_CACHE_SIZE];
105
99 u64 total_time; 106 u64 total_time;
100 u64 total_count; 107 u64 total_count;
108 u64 lost_events;
109 u64 duration;
110
111 const char *pid_str;
112 struct intlist *pid_list;
101 113
102 struct rb_root result; 114 struct rb_root result;
115
116 int timerfd;
117 unsigned int display_time;
118 bool live;
103}; 119};
104 120
105 121
@@ -320,6 +336,28 @@ static void init_kvm_event_record(struct perf_kvm_stat *kvm)
320 INIT_LIST_HEAD(&kvm->kvm_events_cache[i]); 336 INIT_LIST_HEAD(&kvm->kvm_events_cache[i]);
321} 337}
322 338
339static void clear_events_cache_stats(struct list_head *kvm_events_cache)
340{
341 struct list_head *head;
342 struct kvm_event *event;
343 unsigned int i;
344 int j;
345
346 for (i = 0; i < EVENTS_CACHE_SIZE; i++) {
347 head = &kvm_events_cache[i];
348 list_for_each_entry(event, head, hash_entry) {
349 /* reset stats for event */
350 event->total.time = 0;
351 init_stats(&event->total.stats);
352
353 for (j = 0; j < event->max_vcpu; ++j) {
354 event->vcpu[j].time = 0;
355 init_stats(&event->vcpu[j].stats);
356 }
357 }
358 }
359}
360
323static int kvm_events_hash_fn(u64 key) 361static int kvm_events_hash_fn(u64 key)
324{ 362{
325 return key & (EVENTS_CACHE_SIZE - 1); 363 return key & (EVENTS_CACHE_SIZE - 1);
@@ -436,7 +474,7 @@ static bool update_kvm_event(struct kvm_event *event, int vcpu_id,
436static bool handle_end_event(struct perf_kvm_stat *kvm, 474static bool handle_end_event(struct perf_kvm_stat *kvm,
437 struct vcpu_event_record *vcpu_record, 475 struct vcpu_event_record *vcpu_record,
438 struct event_key *key, 476 struct event_key *key,
439 u64 timestamp) 477 struct perf_sample *sample)
440{ 478{
441 struct kvm_event *event; 479 struct kvm_event *event;
442 u64 time_begin, time_diff; 480 u64 time_begin, time_diff;
@@ -472,9 +510,25 @@ static bool handle_end_event(struct perf_kvm_stat *kvm,
472 vcpu_record->last_event = NULL; 510 vcpu_record->last_event = NULL;
473 vcpu_record->start_time = 0; 511 vcpu_record->start_time = 0;
474 512
475 BUG_ON(timestamp < time_begin); 513 /* seems to happen once in a while during live mode */
514 if (sample->time < time_begin) {
515 pr_debug("End time before begin time; skipping event.\n");
516 return true;
517 }
518
519 time_diff = sample->time - time_begin;
520
521 if (kvm->duration && time_diff > kvm->duration) {
522 char decode[32];
523
524 kvm->events_ops->decode_key(kvm, &event->key, decode);
525 if (strcmp(decode, "HLT")) {
526 pr_info("%" PRIu64 " VM %d, vcpu %d: %s event took %" PRIu64 "usec\n",
527 sample->time, sample->pid, vcpu_record->vcpu_id,
528 decode, time_diff/1000);
529 }
530 }
476 531
477 time_diff = timestamp - time_begin;
478 return update_kvm_event(event, vcpu, time_diff); 532 return update_kvm_event(event, vcpu, time_diff);
479} 533}
480 534
@@ -521,7 +575,7 @@ static bool handle_kvm_event(struct perf_kvm_stat *kvm,
521 return handle_begin_event(kvm, vcpu_record, &key, sample->time); 575 return handle_begin_event(kvm, vcpu_record, &key, sample->time);
522 576
523 if (kvm->events_ops->is_end_event(evsel, sample, &key)) 577 if (kvm->events_ops->is_end_event(evsel, sample, &key))
524 return handle_end_event(kvm, vcpu_record, &key, sample->time); 578 return handle_end_event(kvm, vcpu_record, &key, sample);
525 579
526 return true; 580 return true;
527} 581}
@@ -550,6 +604,8 @@ static int compare_kvm_event_ ## func(struct kvm_event *one, \
550GET_EVENT_KEY(time, time); 604GET_EVENT_KEY(time, time);
551COMPARE_EVENT_KEY(count, stats.n); 605COMPARE_EVENT_KEY(count, stats.n);
552COMPARE_EVENT_KEY(mean, stats.mean); 606COMPARE_EVENT_KEY(mean, stats.mean);
607GET_EVENT_KEY(max, stats.max);
608GET_EVENT_KEY(min, stats.min);
553 609
554#define DEF_SORT_NAME_KEY(name, compare_key) \ 610#define DEF_SORT_NAME_KEY(name, compare_key) \
555 { #name, compare_kvm_event_ ## compare_key } 611 { #name, compare_kvm_event_ ## compare_key }
@@ -639,43 +695,81 @@ static struct kvm_event *pop_from_result(struct rb_root *result)
639 return container_of(node, struct kvm_event, rb); 695 return container_of(node, struct kvm_event, rb);
640} 696}
641 697
642static void print_vcpu_info(int vcpu) 698static void print_vcpu_info(struct perf_kvm_stat *kvm)
643{ 699{
700 int vcpu = kvm->trace_vcpu;
701
644 pr_info("Analyze events for "); 702 pr_info("Analyze events for ");
645 703
704 if (kvm->live) {
705 if (kvm->opts.target.system_wide)
706 pr_info("all VMs, ");
707 else if (kvm->opts.target.pid)
708 pr_info("pid(s) %s, ", kvm->opts.target.pid);
709 else
710 pr_info("dazed and confused on what is monitored, ");
711 }
712
646 if (vcpu == -1) 713 if (vcpu == -1)
647 pr_info("all VCPUs:\n\n"); 714 pr_info("all VCPUs:\n\n");
648 else 715 else
649 pr_info("VCPU %d:\n\n", vcpu); 716 pr_info("VCPU %d:\n\n", vcpu);
650} 717}
651 718
719static void show_timeofday(void)
720{
721 char date[64];
722 struct timeval tv;
723 struct tm ltime;
724
725 gettimeofday(&tv, NULL);
726 if (localtime_r(&tv.tv_sec, &ltime)) {
727 strftime(date, sizeof(date), "%H:%M:%S", &ltime);
728 pr_info("%s.%06ld", date, tv.tv_usec);
729 } else
730 pr_info("00:00:00.000000");
731
732 return;
733}
734
652static void print_result(struct perf_kvm_stat *kvm) 735static void print_result(struct perf_kvm_stat *kvm)
653{ 736{
654 char decode[20]; 737 char decode[20];
655 struct kvm_event *event; 738 struct kvm_event *event;
656 int vcpu = kvm->trace_vcpu; 739 int vcpu = kvm->trace_vcpu;
657 740
741 if (kvm->live) {
742 puts(CONSOLE_CLEAR);
743 show_timeofday();
744 }
745
658 pr_info("\n\n"); 746 pr_info("\n\n");
659 print_vcpu_info(vcpu); 747 print_vcpu_info(kvm);
660 pr_info("%20s ", kvm->events_ops->name); 748 pr_info("%20s ", kvm->events_ops->name);
661 pr_info("%10s ", "Samples"); 749 pr_info("%10s ", "Samples");
662 pr_info("%9s ", "Samples%"); 750 pr_info("%9s ", "Samples%");
663 751
664 pr_info("%9s ", "Time%"); 752 pr_info("%9s ", "Time%");
753 pr_info("%10s ", "Min Time");
754 pr_info("%10s ", "Max Time");
665 pr_info("%16s ", "Avg time"); 755 pr_info("%16s ", "Avg time");
666 pr_info("\n\n"); 756 pr_info("\n\n");
667 757
668 while ((event = pop_from_result(&kvm->result))) { 758 while ((event = pop_from_result(&kvm->result))) {
669 u64 ecount, etime; 759 u64 ecount, etime, max, min;
670 760
671 ecount = get_event_count(event, vcpu); 761 ecount = get_event_count(event, vcpu);
672 etime = get_event_time(event, vcpu); 762 etime = get_event_time(event, vcpu);
763 max = get_event_max(event, vcpu);
764 min = get_event_min(event, vcpu);
673 765
674 kvm->events_ops->decode_key(kvm, &event->key, decode); 766 kvm->events_ops->decode_key(kvm, &event->key, decode);
675 pr_info("%20s ", decode); 767 pr_info("%20s ", decode);
676 pr_info("%10llu ", (unsigned long long)ecount); 768 pr_info("%10llu ", (unsigned long long)ecount);
677 pr_info("%8.2f%% ", (double)ecount / kvm->total_count * 100); 769 pr_info("%8.2f%% ", (double)ecount / kvm->total_count * 100);
678 pr_info("%8.2f%% ", (double)etime / kvm->total_time * 100); 770 pr_info("%8.2f%% ", (double)etime / kvm->total_time * 100);
771 pr_info("%8" PRIu64 "us ", min / 1000);
772 pr_info("%8" PRIu64 "us ", max / 1000);
679 pr_info("%9.2fus ( +-%7.2f%% )", (double)etime / ecount/1e3, 773 pr_info("%9.2fus ( +-%7.2f%% )", (double)etime / ecount/1e3,
680 kvm_event_rel_stddev(vcpu, event)); 774 kvm_event_rel_stddev(vcpu, event));
681 pr_info("\n"); 775 pr_info("\n");
@@ -683,6 +777,29 @@ static void print_result(struct perf_kvm_stat *kvm)
683 777
684 pr_info("\nTotal Samples:%" PRIu64 ", Total events handled time:%.2fus.\n\n", 778 pr_info("\nTotal Samples:%" PRIu64 ", Total events handled time:%.2fus.\n\n",
685 kvm->total_count, kvm->total_time / 1e3); 779 kvm->total_count, kvm->total_time / 1e3);
780
781 if (kvm->lost_events)
782 pr_info("\nLost events: %" PRIu64 "\n\n", kvm->lost_events);
783}
784
785static int process_lost_event(struct perf_tool *tool,
786 union perf_event *event __maybe_unused,
787 struct perf_sample *sample __maybe_unused,
788 struct machine *machine __maybe_unused)
789{
790 struct perf_kvm_stat *kvm = container_of(tool, struct perf_kvm_stat, tool);
791
792 kvm->lost_events++;
793 return 0;
794}
795
796static bool skip_sample(struct perf_kvm_stat *kvm,
797 struct perf_sample *sample)
798{
799 if (kvm->pid_list && intlist__find(kvm->pid_list, sample->pid) == NULL)
800 return true;
801
802 return false;
686} 803}
687 804
688static int process_sample_event(struct perf_tool *tool, 805static int process_sample_event(struct perf_tool *tool,
@@ -691,10 +808,14 @@ static int process_sample_event(struct perf_tool *tool,
691 struct perf_evsel *evsel, 808 struct perf_evsel *evsel,
692 struct machine *machine) 809 struct machine *machine)
693{ 810{
694 struct thread *thread = machine__findnew_thread(machine, sample->tid); 811 struct thread *thread;
695 struct perf_kvm_stat *kvm = container_of(tool, struct perf_kvm_stat, 812 struct perf_kvm_stat *kvm = container_of(tool, struct perf_kvm_stat,
696 tool); 813 tool);
697 814
815 if (skip_sample(kvm, sample))
816 return 0;
817
818 thread = machine__findnew_thread(machine, sample->pid, sample->tid);
698 if (thread == NULL) { 819 if (thread == NULL) {
699 pr_debug("problem processing %d event, skipping it.\n", 820 pr_debug("problem processing %d event, skipping it.\n",
700 event->header.type); 821 event->header.type);
@@ -707,10 +828,20 @@ static int process_sample_event(struct perf_tool *tool,
707 return 0; 828 return 0;
708} 829}
709 830
710static int get_cpu_isa(struct perf_session *session) 831static int cpu_isa_config(struct perf_kvm_stat *kvm)
711{ 832{
712 char *cpuid = session->header.env.cpuid; 833 char buf[64], *cpuid;
713 int isa; 834 int err, isa;
835
836 if (kvm->live) {
837 err = get_cpuid(buf, sizeof(buf));
838 if (err != 0) {
839 pr_err("Failed to look up CPU type (Intel or AMD)\n");
840 return err;
841 }
842 cpuid = buf;
843 } else
844 cpuid = kvm->session->header.env.cpuid;
714 845
715 if (strstr(cpuid, "Intel")) 846 if (strstr(cpuid, "Intel"))
716 isa = 1; 847 isa = 1;
@@ -718,10 +849,361 @@ static int get_cpu_isa(struct perf_session *session)
718 isa = 0; 849 isa = 0;
719 else { 850 else {
720 pr_err("CPU %s is not supported.\n", cpuid); 851 pr_err("CPU %s is not supported.\n", cpuid);
721 isa = -ENOTSUP; 852 return -ENOTSUP;
853 }
854
855 if (isa == 1) {
856 kvm->exit_reasons = vmx_exit_reasons;
857 kvm->exit_reasons_size = ARRAY_SIZE(vmx_exit_reasons);
858 kvm->exit_reasons_isa = "VMX";
859 }
860
861 return 0;
862}
863
864static bool verify_vcpu(int vcpu)
865{
866 if (vcpu != -1 && vcpu < 0) {
867 pr_err("Invalid vcpu:%d.\n", vcpu);
868 return false;
869 }
870
871 return true;
872}
873
874/* keeping the max events to a modest level to keep
875 * the processing of samples per mmap smooth.
876 */
877#define PERF_KVM__MAX_EVENTS_PER_MMAP 25
878
879static s64 perf_kvm__mmap_read_idx(struct perf_kvm_stat *kvm, int idx,
880 u64 *mmap_time)
881{
882 union perf_event *event;
883 struct perf_sample sample;
884 s64 n = 0;
885 int err;
886
887 *mmap_time = ULLONG_MAX;
888 while ((event = perf_evlist__mmap_read(kvm->evlist, idx)) != NULL) {
889 err = perf_evlist__parse_sample(kvm->evlist, event, &sample);
890 if (err) {
891 pr_err("Failed to parse sample\n");
892 return -1;
893 }
894
895 err = perf_session_queue_event(kvm->session, event, &sample, 0);
896 if (err) {
897 pr_err("Failed to enqueue sample: %d\n", err);
898 return -1;
899 }
900
901 /* save time stamp of our first sample for this mmap */
902 if (n == 0)
903 *mmap_time = sample.time;
904
905 /* limit events per mmap handled all at once */
906 n++;
907 if (n == PERF_KVM__MAX_EVENTS_PER_MMAP)
908 break;
909 }
910
911 return n;
912}
913
914static int perf_kvm__mmap_read(struct perf_kvm_stat *kvm)
915{
916 int i, err, throttled = 0;
917 s64 n, ntotal = 0;
918 u64 flush_time = ULLONG_MAX, mmap_time;
919
920 for (i = 0; i < kvm->evlist->nr_mmaps; i++) {
921 n = perf_kvm__mmap_read_idx(kvm, i, &mmap_time);
922 if (n < 0)
923 return -1;
924
925 /* flush time is going to be the minimum of all the individual
926 * mmap times. Essentially, we flush all the samples queued up
927 * from the last pass under our minimal start time -- that leaves
928 * a very small race for samples to come in with a lower timestamp.
929 * The ioctl to return the perf_clock timestamp should close the
930 * race entirely.
931 */
932 if (mmap_time < flush_time)
933 flush_time = mmap_time;
934
935 ntotal += n;
936 if (n == PERF_KVM__MAX_EVENTS_PER_MMAP)
937 throttled = 1;
938 }
939
940 /* flush queue after each round in which we processed events */
941 if (ntotal) {
942 kvm->session->ordered_samples.next_flush = flush_time;
943 err = kvm->tool.finished_round(&kvm->tool, NULL, kvm->session);
944 if (err) {
945 if (kvm->lost_events)
946 pr_info("\nLost events: %" PRIu64 "\n\n",
947 kvm->lost_events);
948 return err;
949 }
950 }
951
952 return throttled;
953}
954
955static volatile int done;
956
957static void sig_handler(int sig __maybe_unused)
958{
959 done = 1;
960}
961
962static int perf_kvm__timerfd_create(struct perf_kvm_stat *kvm)
963{
964 struct itimerspec new_value;
965 int rc = -1;
966
967 kvm->timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
968 if (kvm->timerfd < 0) {
969 pr_err("timerfd_create failed\n");
970 goto out;
971 }
972
973 new_value.it_value.tv_sec = kvm->display_time;
974 new_value.it_value.tv_nsec = 0;
975 new_value.it_interval.tv_sec = kvm->display_time;
976 new_value.it_interval.tv_nsec = 0;
977
978 if (timerfd_settime(kvm->timerfd, 0, &new_value, NULL) != 0) {
979 pr_err("timerfd_settime failed: %d\n", errno);
980 close(kvm->timerfd);
981 goto out;
982 }
983
984 rc = 0;
985out:
986 return rc;
987}
988
989static int perf_kvm__handle_timerfd(struct perf_kvm_stat *kvm)
990{
991 uint64_t c;
992 int rc;
993
994 rc = read(kvm->timerfd, &c, sizeof(uint64_t));
995 if (rc < 0) {
996 if (errno == EAGAIN)
997 return 0;
998
999 pr_err("Failed to read timer fd: %d\n", errno);
1000 return -1;
1001 }
1002
1003 if (rc != sizeof(uint64_t)) {
1004 pr_err("Error reading timer fd - invalid size returned\n");
1005 return -1;
1006 }
1007
1008 if (c != 1)
1009 pr_debug("Missed timer beats: %" PRIu64 "\n", c-1);
1010
1011 /* update display */
1012 sort_result(kvm);
1013 print_result(kvm);
1014
1015 /* reset counts */
1016 clear_events_cache_stats(kvm->kvm_events_cache);
1017 kvm->total_count = 0;
1018 kvm->total_time = 0;
1019 kvm->lost_events = 0;
1020
1021 return 0;
1022}
1023
1024static int fd_set_nonblock(int fd)
1025{
1026 long arg = 0;
1027
1028 arg = fcntl(fd, F_GETFL);
1029 if (arg < 0) {
1030 pr_err("Failed to get current flags for fd %d\n", fd);
1031 return -1;
1032 }
1033
1034 if (fcntl(fd, F_SETFL, arg | O_NONBLOCK) < 0) {
1035 pr_err("Failed to set non-block option on fd %d\n", fd);
1036 return -1;
1037 }
1038
1039 return 0;
1040}
1041
1042static
1043int perf_kvm__handle_stdin(struct termios *tc_now, struct termios *tc_save)
1044{
1045 int c;
1046
1047 tcsetattr(0, TCSANOW, tc_now);
1048 c = getc(stdin);
1049 tcsetattr(0, TCSAFLUSH, tc_save);
1050
1051 if (c == 'q')
1052 return 1;
1053
1054 return 0;
1055}
1056
1057static int kvm_events_live_report(struct perf_kvm_stat *kvm)
1058{
1059 struct pollfd *pollfds = NULL;
1060 int nr_fds, nr_stdin, ret, err = -EINVAL;
1061 struct termios tc, save;
1062
1063 /* live flag must be set first */
1064 kvm->live = true;
1065
1066 ret = cpu_isa_config(kvm);
1067 if (ret < 0)
1068 return ret;
1069
1070 if (!verify_vcpu(kvm->trace_vcpu) ||
1071 !select_key(kvm) ||
1072 !register_kvm_events_ops(kvm)) {
1073 goto out;
1074 }
1075
1076 init_kvm_event_record(kvm);
1077
1078 tcgetattr(0, &save);
1079 tc = save;
1080 tc.c_lflag &= ~(ICANON | ECHO);
1081 tc.c_cc[VMIN] = 0;
1082 tc.c_cc[VTIME] = 0;
1083
1084 signal(SIGINT, sig_handler);
1085 signal(SIGTERM, sig_handler);
1086
1087 /* copy pollfds -- need to add timerfd and stdin */
1088 nr_fds = kvm->evlist->nr_fds;
1089 pollfds = zalloc(sizeof(struct pollfd) * (nr_fds + 2));
1090 if (!pollfds) {
1091 err = -ENOMEM;
1092 goto out;
722 } 1093 }
1094 memcpy(pollfds, kvm->evlist->pollfd,
1095 sizeof(struct pollfd) * kvm->evlist->nr_fds);
1096
1097 /* add timer fd */
1098 if (perf_kvm__timerfd_create(kvm) < 0) {
1099 err = -1;
1100 goto out;
1101 }
1102
1103 pollfds[nr_fds].fd = kvm->timerfd;
1104 pollfds[nr_fds].events = POLLIN;
1105 nr_fds++;
1106
1107 pollfds[nr_fds].fd = fileno(stdin);
1108 pollfds[nr_fds].events = POLLIN;
1109 nr_stdin = nr_fds;
1110 nr_fds++;
1111 if (fd_set_nonblock(fileno(stdin)) != 0)
1112 goto out;
1113
1114 /* everything is good - enable the events and process */
1115 perf_evlist__enable(kvm->evlist);
1116
1117 while (!done) {
1118 int rc;
1119
1120 rc = perf_kvm__mmap_read(kvm);
1121 if (rc < 0)
1122 break;
1123
1124 err = perf_kvm__handle_timerfd(kvm);
1125 if (err)
1126 goto out;
1127
1128 if (pollfds[nr_stdin].revents & POLLIN)
1129 done = perf_kvm__handle_stdin(&tc, &save);
1130
1131 if (!rc && !done)
1132 err = poll(pollfds, nr_fds, 100);
1133 }
1134
1135 perf_evlist__disable(kvm->evlist);
1136
1137 if (err == 0) {
1138 sort_result(kvm);
1139 print_result(kvm);
1140 }
1141
1142out:
1143 if (kvm->timerfd >= 0)
1144 close(kvm->timerfd);
1145
1146 if (pollfds)
1147 free(pollfds);
723 1148
724 return isa; 1149 return err;
1150}
1151
1152static int kvm_live_open_events(struct perf_kvm_stat *kvm)
1153{
1154 int err, rc = -1;
1155 struct perf_evsel *pos;
1156 struct perf_evlist *evlist = kvm->evlist;
1157
1158 perf_evlist__config(evlist, &kvm->opts);
1159
1160 /*
1161 * Note: exclude_{guest,host} do not apply here.
1162 * This command processes KVM tracepoints from host only
1163 */
1164 list_for_each_entry(pos, &evlist->entries, node) {
1165 struct perf_event_attr *attr = &pos->attr;
1166
1167 /* make sure these *are* set */
1168 perf_evsel__set_sample_bit(pos, TID);
1169 perf_evsel__set_sample_bit(pos, TIME);
1170 perf_evsel__set_sample_bit(pos, CPU);
1171 perf_evsel__set_sample_bit(pos, RAW);
1172 /* make sure these are *not*; want as small a sample as possible */
1173 perf_evsel__reset_sample_bit(pos, PERIOD);
1174 perf_evsel__reset_sample_bit(pos, IP);
1175 perf_evsel__reset_sample_bit(pos, CALLCHAIN);
1176 perf_evsel__reset_sample_bit(pos, ADDR);
1177 perf_evsel__reset_sample_bit(pos, READ);
1178 attr->mmap = 0;
1179 attr->comm = 0;
1180 attr->task = 0;
1181
1182 attr->sample_period = 1;
1183
1184 attr->watermark = 0;
1185 attr->wakeup_events = 1000;
1186
1187 /* will enable all once we are ready */
1188 attr->disabled = 1;
1189 }
1190
1191 err = perf_evlist__open(evlist);
1192 if (err < 0) {
1193 printf("Couldn't create the events: %s\n", strerror(errno));
1194 goto out;
1195 }
1196
1197 if (perf_evlist__mmap(evlist, kvm->opts.mmap_pages, false) < 0) {
1198 ui__error("Failed to mmap the events: %s\n", strerror(errno));
1199 perf_evlist__close(evlist);
1200 goto out;
1201 }
1202
1203 rc = 0;
1204
1205out:
1206 return rc;
725} 1207}
726 1208
727static int read_events(struct perf_kvm_stat *kvm) 1209static int read_events(struct perf_kvm_stat *kvm)
@@ -749,28 +1231,24 @@ static int read_events(struct perf_kvm_stat *kvm)
749 * Do not use 'isa' recorded in kvm_exit tracepoint since it is not 1231 * Do not use 'isa' recorded in kvm_exit tracepoint since it is not
750 * traced in the old kernel. 1232 * traced in the old kernel.
751 */ 1233 */
752 ret = get_cpu_isa(kvm->session); 1234 ret = cpu_isa_config(kvm);
753
754 if (ret < 0) 1235 if (ret < 0)
755 return ret; 1236 return ret;
756 1237
757 if (ret == 1) {
758 kvm->exit_reasons = vmx_exit_reasons;
759 kvm->exit_reasons_size = ARRAY_SIZE(vmx_exit_reasons);
760 kvm->exit_reasons_isa = "VMX";
761 }
762
763 return perf_session__process_events(kvm->session, &kvm->tool); 1238 return perf_session__process_events(kvm->session, &kvm->tool);
764} 1239}
765 1240
766static bool verify_vcpu(int vcpu) 1241static int parse_target_str(struct perf_kvm_stat *kvm)
767{ 1242{
768 if (vcpu != -1 && vcpu < 0) { 1243 if (kvm->pid_str) {
769 pr_err("Invalid vcpu:%d.\n", vcpu); 1244 kvm->pid_list = intlist__new(kvm->pid_str);
770 return false; 1245 if (kvm->pid_list == NULL) {
1246 pr_err("Error parsing process id string\n");
1247 return -EINVAL;
1248 }
771 } 1249 }
772 1250
773 return true; 1251 return 0;
774} 1252}
775 1253
776static int kvm_events_report_vcpu(struct perf_kvm_stat *kvm) 1254static int kvm_events_report_vcpu(struct perf_kvm_stat *kvm)
@@ -778,6 +1256,9 @@ static int kvm_events_report_vcpu(struct perf_kvm_stat *kvm)
778 int ret = -EINVAL; 1256 int ret = -EINVAL;
779 int vcpu = kvm->trace_vcpu; 1257 int vcpu = kvm->trace_vcpu;
780 1258
1259 if (parse_target_str(kvm) != 0)
1260 goto exit;
1261
781 if (!verify_vcpu(vcpu)) 1262 if (!verify_vcpu(vcpu))
782 goto exit; 1263 goto exit;
783 1264
@@ -801,16 +1282,11 @@ exit:
801 return ret; 1282 return ret;
802} 1283}
803 1284
804static const char * const record_args[] = { 1285static const char * const kvm_events_tp[] = {
805 "record", 1286 "kvm:kvm_entry",
806 "-R", 1287 "kvm:kvm_exit",
807 "-f", 1288 "kvm:kvm_mmio",
808 "-m", "1024", 1289 "kvm:kvm_pio",
809 "-c", "1",
810 "-e", "kvm:kvm_entry",
811 "-e", "kvm:kvm_exit",
812 "-e", "kvm:kvm_mmio",
813 "-e", "kvm:kvm_pio",
814}; 1290};
815 1291
816#define STRDUP_FAIL_EXIT(s) \ 1292#define STRDUP_FAIL_EXIT(s) \
@@ -826,8 +1302,15 @@ kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv)
826{ 1302{
827 unsigned int rec_argc, i, j; 1303 unsigned int rec_argc, i, j;
828 const char **rec_argv; 1304 const char **rec_argv;
1305 const char * const record_args[] = {
1306 "record",
1307 "-R",
1308 "-m", "1024",
1309 "-c", "1",
1310 };
829 1311
830 rec_argc = ARRAY_SIZE(record_args) + argc + 2; 1312 rec_argc = ARRAY_SIZE(record_args) + argc + 2 +
1313 2 * ARRAY_SIZE(kvm_events_tp);
831 rec_argv = calloc(rec_argc + 1, sizeof(char *)); 1314 rec_argv = calloc(rec_argc + 1, sizeof(char *));
832 1315
833 if (rec_argv == NULL) 1316 if (rec_argv == NULL)
@@ -836,6 +1319,11 @@ kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv)
836 for (i = 0; i < ARRAY_SIZE(record_args); i++) 1319 for (i = 0; i < ARRAY_SIZE(record_args); i++)
837 rec_argv[i] = STRDUP_FAIL_EXIT(record_args[i]); 1320 rec_argv[i] = STRDUP_FAIL_EXIT(record_args[i]);
838 1321
1322 for (j = 0; j < ARRAY_SIZE(kvm_events_tp); j++) {
1323 rec_argv[i++] = "-e";
1324 rec_argv[i++] = STRDUP_FAIL_EXIT(kvm_events_tp[j]);
1325 }
1326
839 rec_argv[i++] = STRDUP_FAIL_EXIT("-o"); 1327 rec_argv[i++] = STRDUP_FAIL_EXIT("-o");
840 rec_argv[i++] = STRDUP_FAIL_EXIT(kvm->file_name); 1328 rec_argv[i++] = STRDUP_FAIL_EXIT(kvm->file_name);
841 1329
@@ -856,6 +1344,8 @@ kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv)
856 OPT_STRING('k', "key", &kvm->sort_key, "sort-key", 1344 OPT_STRING('k', "key", &kvm->sort_key, "sort-key",
857 "key for sorting: sample(sort by samples number)" 1345 "key for sorting: sample(sort by samples number)"
858 " time (sort by avg time)"), 1346 " time (sort by avg time)"),
1347 OPT_STRING('p', "pid", &kvm->pid_str, "pid",
1348 "analyze events only for given process id(s)"),
859 OPT_END() 1349 OPT_END()
860 }; 1350 };
861 1351
@@ -878,6 +1368,190 @@ kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv)
878 return kvm_events_report_vcpu(kvm); 1368 return kvm_events_report_vcpu(kvm);
879} 1369}
880 1370
1371static struct perf_evlist *kvm_live_event_list(void)
1372{
1373 struct perf_evlist *evlist;
1374 char *tp, *name, *sys;
1375 unsigned int j;
1376 int err = -1;
1377
1378 evlist = perf_evlist__new();
1379 if (evlist == NULL)
1380 return NULL;
1381
1382 for (j = 0; j < ARRAY_SIZE(kvm_events_tp); j++) {
1383
1384 tp = strdup(kvm_events_tp[j]);
1385 if (tp == NULL)
1386 goto out;
1387
1388 /* split tracepoint into subsystem and name */
1389 sys = tp;
1390 name = strchr(tp, ':');
1391 if (name == NULL) {
1392 pr_err("Error parsing %s tracepoint: subsystem delimiter not found\n",
1393 kvm_events_tp[j]);
1394 free(tp);
1395 goto out;
1396 }
1397 *name = '\0';
1398 name++;
1399
1400 if (perf_evlist__add_newtp(evlist, sys, name, NULL)) {
1401 pr_err("Failed to add %s tracepoint to the list\n", kvm_events_tp[j]);
1402 free(tp);
1403 goto out;
1404 }
1405
1406 free(tp);
1407 }
1408
1409 err = 0;
1410
1411out:
1412 if (err) {
1413 perf_evlist__delete(evlist);
1414 evlist = NULL;
1415 }
1416
1417 return evlist;
1418}
1419
1420static int kvm_events_live(struct perf_kvm_stat *kvm,
1421 int argc, const char **argv)
1422{
1423 char errbuf[BUFSIZ];
1424 int err;
1425
1426 const struct option live_options[] = {
1427 OPT_STRING('p', "pid", &kvm->opts.target.pid, "pid",
1428 "record events on existing process id"),
1429 OPT_UINTEGER('m', "mmap-pages", &kvm->opts.mmap_pages,
1430 "number of mmap data pages"),
1431 OPT_INCR('v', "verbose", &verbose,
1432 "be more verbose (show counter open errors, etc)"),
1433 OPT_BOOLEAN('a', "all-cpus", &kvm->opts.target.system_wide,
1434 "system-wide collection from all CPUs"),
1435 OPT_UINTEGER('d', "display", &kvm->display_time,
1436 "time in seconds between display updates"),
1437 OPT_STRING(0, "event", &kvm->report_event, "report event",
1438 "event for reporting: vmexit, mmio, ioport"),
1439 OPT_INTEGER(0, "vcpu", &kvm->trace_vcpu,
1440 "vcpu id to report"),
1441 OPT_STRING('k', "key", &kvm->sort_key, "sort-key",
1442 "key for sorting: sample(sort by samples number)"
1443 " time (sort by avg time)"),
1444 OPT_U64(0, "duration", &kvm->duration,
1445 "show events other than HALT that take longer than duration usecs"),
1446 OPT_END()
1447 };
1448 const char * const live_usage[] = {
1449 "perf kvm stat live [<options>]",
1450 NULL
1451 };
1452
1453
1454 /* event handling */
1455 kvm->tool.sample = process_sample_event;
1456 kvm->tool.comm = perf_event__process_comm;
1457 kvm->tool.exit = perf_event__process_exit;
1458 kvm->tool.fork = perf_event__process_fork;
1459 kvm->tool.lost = process_lost_event;
1460 kvm->tool.ordered_samples = true;
1461 perf_tool__fill_defaults(&kvm->tool);
1462
1463 /* set defaults */
1464 kvm->display_time = 1;
1465 kvm->opts.user_interval = 1;
1466 kvm->opts.mmap_pages = 512;
1467 kvm->opts.target.uses_mmap = false;
1468 kvm->opts.target.uid_str = NULL;
1469 kvm->opts.target.uid = UINT_MAX;
1470
1471 symbol__init();
1472 disable_buildid_cache();
1473
1474 use_browser = 0;
1475 setup_browser(false);
1476
1477 if (argc) {
1478 argc = parse_options(argc, argv, live_options,
1479 live_usage, 0);
1480 if (argc)
1481 usage_with_options(live_usage, live_options);
1482 }
1483
1484 kvm->duration *= NSEC_PER_USEC; /* convert usec to nsec */
1485
1486 /*
1487 * target related setups
1488 */
1489 err = perf_target__validate(&kvm->opts.target);
1490 if (err) {
1491 perf_target__strerror(&kvm->opts.target, err, errbuf, BUFSIZ);
1492 ui__warning("%s", errbuf);
1493 }
1494
1495 if (perf_target__none(&kvm->opts.target))
1496 kvm->opts.target.system_wide = true;
1497
1498
1499 /*
1500 * generate the event list
1501 */
1502 kvm->evlist = kvm_live_event_list();
1503 if (kvm->evlist == NULL) {
1504 err = -1;
1505 goto out;
1506 }
1507
1508 symbol_conf.nr_events = kvm->evlist->nr_entries;
1509
1510 if (perf_evlist__create_maps(kvm->evlist, &kvm->opts.target) < 0)
1511 usage_with_options(live_usage, live_options);
1512
1513 /*
1514 * perf session
1515 */
1516 kvm->session = perf_session__new(NULL, O_WRONLY, false, false, &kvm->tool);
1517 if (kvm->session == NULL) {
1518 err = -ENOMEM;
1519 goto out;
1520 }
1521 kvm->session->evlist = kvm->evlist;
1522 perf_session__set_id_hdr_size(kvm->session);
1523
1524
1525 if (perf_target__has_task(&kvm->opts.target))
1526 perf_event__synthesize_thread_map(&kvm->tool,
1527 kvm->evlist->threads,
1528 perf_event__process,
1529 &kvm->session->machines.host);
1530 else
1531 perf_event__synthesize_threads(&kvm->tool, perf_event__process,
1532 &kvm->session->machines.host);
1533
1534
1535 err = kvm_live_open_events(kvm);
1536 if (err)
1537 goto out;
1538
1539 err = kvm_events_live_report(kvm);
1540
1541out:
1542 exit_browser(0);
1543
1544 if (kvm->session)
1545 perf_session__delete(kvm->session);
1546 kvm->session = NULL;
1547 if (kvm->evlist) {
1548 perf_evlist__delete_maps(kvm->evlist);
1549 perf_evlist__delete(kvm->evlist);
1550 }
1551
1552 return err;
1553}
1554
881static void print_kvm_stat_usage(void) 1555static void print_kvm_stat_usage(void)
882{ 1556{
883 printf("Usage: perf kvm stat <command>\n\n"); 1557 printf("Usage: perf kvm stat <command>\n\n");
@@ -885,6 +1559,7 @@ static void print_kvm_stat_usage(void)
885 printf("# Available commands:\n"); 1559 printf("# Available commands:\n");
886 printf("\trecord: record kvm events\n"); 1560 printf("\trecord: record kvm events\n");
887 printf("\treport: report statistical data of kvm events\n"); 1561 printf("\treport: report statistical data of kvm events\n");
1562 printf("\tlive: live reporting of statistical data of kvm events\n");
888 1563
889 printf("\nOtherwise, it is the alias of 'perf stat':\n"); 1564 printf("\nOtherwise, it is the alias of 'perf stat':\n");
890} 1565}
@@ -914,6 +1589,9 @@ static int kvm_cmd_stat(const char *file_name, int argc, const char **argv)
914 if (!strncmp(argv[1], "rep", 3)) 1589 if (!strncmp(argv[1], "rep", 3))
915 return kvm_events_report(&kvm, argc - 1 , argv + 1); 1590 return kvm_events_report(&kvm, argc - 1 , argv + 1);
916 1591
1592 if (!strncmp(argv[1], "live", 4))
1593 return kvm_events_live(&kvm, argc - 1 , argv + 1);
1594
917perf_stat: 1595perf_stat:
918 return cmd_stat(argc, argv, NULL); 1596 return cmd_stat(argc, argv, NULL);
919} 1597}
diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c
index 1948eceb517a..e79f423cc302 100644
--- a/tools/perf/builtin-list.c
+++ b/tools/perf/builtin-list.c
@@ -13,6 +13,7 @@
13 13
14#include "util/parse-events.h" 14#include "util/parse-events.h"
15#include "util/cache.h" 15#include "util/cache.h"
16#include "util/pmu.h"
16 17
17int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused) 18int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
18{ 19{
@@ -37,6 +38,8 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
37 else if (strcmp(argv[i], "cache") == 0 || 38 else if (strcmp(argv[i], "cache") == 0 ||
38 strcmp(argv[i], "hwcache") == 0) 39 strcmp(argv[i], "hwcache") == 0)
39 print_hwcache_events(NULL, false); 40 print_hwcache_events(NULL, false);
41 else if (strcmp(argv[i], "pmu") == 0)
42 print_pmu_events(NULL, false);
40 else if (strcmp(argv[i], "--raw-dump") == 0) 43 else if (strcmp(argv[i], "--raw-dump") == 0)
41 print_events(NULL, true); 44 print_events(NULL, true);
42 else { 45 else {
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index 76543a4a7a30..ee33ba2f05dd 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -805,7 +805,8 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
805 struct perf_evsel *evsel, 805 struct perf_evsel *evsel,
806 struct machine *machine) 806 struct machine *machine)
807{ 807{
808 struct thread *thread = machine__findnew_thread(machine, sample->tid); 808 struct thread *thread = machine__findnew_thread(machine, sample->pid,
809 sample->tid);
809 810
810 if (thread == NULL) { 811 if (thread == NULL) {
811 pr_debug("problem processing %d event, skipping it.\n", 812 pr_debug("problem processing %d event, skipping it.\n",
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c
index a8ff6d264e50..253133a6251d 100644
--- a/tools/perf/builtin-mem.c
+++ b/tools/perf/builtin-mem.c
@@ -14,7 +14,6 @@ static const char *mem_operation = MEM_OPERATION_LOAD;
14struct perf_mem { 14struct perf_mem {
15 struct perf_tool tool; 15 struct perf_tool tool;
16 char const *input_name; 16 char const *input_name;
17 symbol_filter_t annotate_init;
18 bool hide_unresolved; 17 bool hide_unresolved;
19 bool dump_raw; 18 bool dump_raw;
20 const char *cpu_list; 19 const char *cpu_list;
@@ -69,8 +68,7 @@ dump_raw_samples(struct perf_tool *tool,
69 struct addr_location al; 68 struct addr_location al;
70 const char *fmt; 69 const char *fmt;
71 70
72 if (perf_event__preprocess_sample(event, machine, &al, sample, 71 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
73 mem->annotate_init) < 0) {
74 fprintf(stderr, "problem processing %d event, skipping it.\n", 72 fprintf(stderr, "problem processing %d event, skipping it.\n",
75 event->header.type); 73 event->header.type);
76 return -1; 74 return -1;
@@ -96,7 +94,7 @@ dump_raw_samples(struct perf_tool *tool,
96 symbol_conf.field_sep, 94 symbol_conf.field_sep,
97 sample->tid, 95 sample->tid,
98 symbol_conf.field_sep, 96 symbol_conf.field_sep,
99 event->ip.ip, 97 sample->ip,
100 symbol_conf.field_sep, 98 symbol_conf.field_sep,
101 sample->addr, 99 sample->addr,
102 symbol_conf.field_sep, 100 symbol_conf.field_sep,
@@ -192,6 +190,7 @@ int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused)
192 .tool = { 190 .tool = {
193 .sample = process_sample_event, 191 .sample = process_sample_event,
194 .mmap = perf_event__process_mmap, 192 .mmap = perf_event__process_mmap,
193 .mmap2 = perf_event__process_mmap2,
195 .comm = perf_event__process_comm, 194 .comm = perf_event__process_comm,
196 .lost = perf_event__process_lost, 195 .lost = perf_event__process_lost,
197 .fork = perf_event__process_fork, 196 .fork = perf_event__process_fork,
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index ecca62e27b28..a41ac41546c9 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -474,13 +474,6 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
474 goto out_delete_session; 474 goto out_delete_session;
475 } 475 }
476 476
477 err = perf_event__synthesize_event_types(tool, process_synthesized_event,
478 machine);
479 if (err < 0) {
480 pr_err("Couldn't synthesize event_types.\n");
481 goto out_delete_session;
482 }
483
484 if (have_tracepoints(&evsel_list->entries)) { 477 if (have_tracepoints(&evsel_list->entries)) {
485 /* 478 /*
486 * FIXME err <= 0 here actually means that 479 * FIXME err <= 0 here actually means that
@@ -904,7 +897,6 @@ const struct option record_options[] = {
904int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) 897int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
905{ 898{
906 int err = -ENOMEM; 899 int err = -ENOMEM;
907 struct perf_evsel *pos;
908 struct perf_evlist *evsel_list; 900 struct perf_evlist *evsel_list;
909 struct perf_record *rec = &record; 901 struct perf_record *rec = &record;
910 char errbuf[BUFSIZ]; 902 char errbuf[BUFSIZ];
@@ -968,11 +960,6 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
968 if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0) 960 if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0)
969 usage_with_options(record_usage, record_options); 961 usage_with_options(record_usage, record_options);
970 962
971 list_for_each_entry(pos, &evsel_list->entries, node) {
972 if (perf_header__push_event(pos->attr.config, perf_evsel__name(pos)))
973 goto out_free_fd;
974 }
975
976 if (rec->opts.user_interval != ULLONG_MAX) 963 if (rec->opts.user_interval != ULLONG_MAX)
977 rec->opts.default_interval = rec->opts.user_interval; 964 rec->opts.default_interval = rec->opts.user_interval;
978 if (rec->opts.user_freq != UINT_MAX) 965 if (rec->opts.user_freq != UINT_MAX)
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 3662047cc6b1..72eae7498c09 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -49,7 +49,6 @@ struct perf_report {
49 bool mem_mode; 49 bool mem_mode;
50 struct perf_read_values show_threads_values; 50 struct perf_read_values show_threads_values;
51 const char *pretty_printing_style; 51 const char *pretty_printing_style;
52 symbol_filter_t annotate_init;
53 const char *cpu_list; 52 const char *cpu_list;
54 const char *symbol_filter_str; 53 const char *symbol_filter_str;
55 float min_percent; 54 float min_percent;
@@ -89,7 +88,7 @@ static int perf_report__add_mem_hist_entry(struct perf_tool *tool,
89 if ((sort__has_parent || symbol_conf.use_callchain) && 88 if ((sort__has_parent || symbol_conf.use_callchain) &&
90 sample->callchain) { 89 sample->callchain) {
91 err = machine__resolve_callchain(machine, evsel, al->thread, 90 err = machine__resolve_callchain(machine, evsel, al->thread,
92 sample, &parent); 91 sample, &parent, al);
93 if (err) 92 if (err)
94 return err; 93 return err;
95 } 94 }
@@ -180,7 +179,7 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
180 if ((sort__has_parent || symbol_conf.use_callchain) 179 if ((sort__has_parent || symbol_conf.use_callchain)
181 && sample->callchain) { 180 && sample->callchain) {
182 err = machine__resolve_callchain(machine, evsel, al->thread, 181 err = machine__resolve_callchain(machine, evsel, al->thread,
183 sample, &parent); 182 sample, &parent, al);
184 if (err) 183 if (err)
185 return err; 184 return err;
186 } 185 }
@@ -254,7 +253,7 @@ static int perf_evsel__add_hist_entry(struct perf_evsel *evsel,
254 253
255 if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) { 254 if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) {
256 err = machine__resolve_callchain(machine, evsel, al->thread, 255 err = machine__resolve_callchain(machine, evsel, al->thread,
257 sample, &parent); 256 sample, &parent, al);
258 if (err) 257 if (err)
259 return err; 258 return err;
260 } 259 }
@@ -305,8 +304,7 @@ static int process_sample_event(struct perf_tool *tool,
305 struct addr_location al; 304 struct addr_location al;
306 int ret; 305 int ret;
307 306
308 if (perf_event__preprocess_sample(event, machine, &al, sample, 307 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
309 rep->annotate_init) < 0) {
310 fprintf(stderr, "problem processing %d event, skipping it.\n", 308 fprintf(stderr, "problem processing %d event, skipping it.\n",
311 event->header.type); 309 event->header.type);
312 return -1; 310 return -1;
@@ -367,7 +365,7 @@ static int process_read_event(struct perf_tool *tool,
367static int perf_report__setup_sample_type(struct perf_report *rep) 365static int perf_report__setup_sample_type(struct perf_report *rep)
368{ 366{
369 struct perf_session *self = rep->session; 367 struct perf_session *self = rep->session;
370 u64 sample_type = perf_evlist__sample_type(self->evlist); 368 u64 sample_type = perf_evlist__combined_sample_type(self->evlist);
371 369
372 if (!self->fd_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) { 370 if (!self->fd_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) {
373 if (sort__has_parent) { 371 if (sort__has_parent) {
@@ -403,8 +401,6 @@ static int perf_report__setup_sample_type(struct perf_report *rep)
403 return 0; 401 return 0;
404} 402}
405 403
406extern volatile int session_done;
407
408static void sig_handler(int sig __maybe_unused) 404static void sig_handler(int sig __maybe_unused)
409{ 405{
410 session_done = 1; 406 session_done = 1;
@@ -497,7 +493,7 @@ static int __cmd_report(struct perf_report *rep)
497 ret = perf_session__cpu_bitmap(session, rep->cpu_list, 493 ret = perf_session__cpu_bitmap(session, rep->cpu_list,
498 rep->cpu_bitmap); 494 rep->cpu_bitmap);
499 if (ret) 495 if (ret)
500 goto out_delete; 496 return ret;
501 } 497 }
502 498
503 if (use_browser <= 0) 499 if (use_browser <= 0)
@@ -508,11 +504,11 @@ static int __cmd_report(struct perf_report *rep)
508 504
509 ret = perf_report__setup_sample_type(rep); 505 ret = perf_report__setup_sample_type(rep);
510 if (ret) 506 if (ret)
511 goto out_delete; 507 return ret;
512 508
513 ret = perf_session__process_events(session, &rep->tool); 509 ret = perf_session__process_events(session, &rep->tool);
514 if (ret) 510 if (ret)
515 goto out_delete; 511 return ret;
516 512
517 kernel_map = session->machines.host.vmlinux_maps[MAP__FUNCTION]; 513 kernel_map = session->machines.host.vmlinux_maps[MAP__FUNCTION];
518 kernel_kmap = map__kmap(kernel_map); 514 kernel_kmap = map__kmap(kernel_map);
@@ -547,7 +543,7 @@ static int __cmd_report(struct perf_report *rep)
547 543
548 if (dump_trace) { 544 if (dump_trace) {
549 perf_session__fprintf_nr_events(session, stdout); 545 perf_session__fprintf_nr_events(session, stdout);
550 goto out_delete; 546 return 0;
551 } 547 }
552 548
553 nr_samples = 0; 549 nr_samples = 0;
@@ -570,9 +566,12 @@ static int __cmd_report(struct perf_report *rep)
570 } 566 }
571 } 567 }
572 568
569 if (session_done())
570 return 0;
571
573 if (nr_samples == 0) { 572 if (nr_samples == 0) {
574 ui__error("The %s file has no samples!\n", session->filename); 573 ui__error("The %s file has no samples!\n", session->filename);
575 goto out_delete; 574 return 0;
576 } 575 }
577 576
578 list_for_each_entry(pos, &session->evlist->entries, node) 577 list_for_each_entry(pos, &session->evlist->entries, node)
@@ -598,19 +597,6 @@ static int __cmd_report(struct perf_report *rep)
598 } else 597 } else
599 perf_evlist__tty_browse_hists(session->evlist, rep, help); 598 perf_evlist__tty_browse_hists(session->evlist, rep, help);
600 599
601out_delete:
602 /*
603 * Speed up the exit process, for large files this can
604 * take quite a while.
605 *
606 * XXX Enable this when using valgrind or if we ever
607 * librarize this command.
608 *
609 * Also experiment with obstacks to see how much speed
610 * up we'll get here.
611 *
612 * perf_session__delete(session);
613 */
614 return ret; 600 return ret;
615} 601}
616 602
@@ -680,12 +666,23 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset)
680 } 666 }
681 667
682 /* get the call chain order */ 668 /* get the call chain order */
683 if (!strcmp(tok2, "caller")) 669 if (!strncmp(tok2, "caller", strlen("caller")))
684 callchain_param.order = ORDER_CALLER; 670 callchain_param.order = ORDER_CALLER;
685 else if (!strcmp(tok2, "callee")) 671 else if (!strncmp(tok2, "callee", strlen("callee")))
686 callchain_param.order = ORDER_CALLEE; 672 callchain_param.order = ORDER_CALLEE;
687 else 673 else
688 return -1; 674 return -1;
675
676 /* Get the sort key */
677 tok2 = strtok(NULL, ",");
678 if (!tok2)
679 goto setup;
680 if (!strncmp(tok2, "function", strlen("function")))
681 callchain_param.key = CCKEY_FUNCTION;
682 else if (!strncmp(tok2, "address", strlen("address")))
683 callchain_param.key = CCKEY_ADDRESS;
684 else
685 return -1;
689setup: 686setup:
690 if (callchain_register_param(&callchain_param) < 0) { 687 if (callchain_register_param(&callchain_param) < 0) {
691 fprintf(stderr, "Can't register callchain params\n"); 688 fprintf(stderr, "Can't register callchain params\n");
@@ -694,6 +691,24 @@ setup:
694 return 0; 691 return 0;
695} 692}
696 693
694int
695report_parse_ignore_callees_opt(const struct option *opt __maybe_unused,
696 const char *arg, int unset __maybe_unused)
697{
698 if (arg) {
699 int err = regcomp(&ignore_callees_regex, arg, REG_EXTENDED);
700 if (err) {
701 char buf[BUFSIZ];
702 regerror(err, &ignore_callees_regex, buf, sizeof(buf));
703 pr_err("Invalid --ignore-callees regex: %s\n%s", arg, buf);
704 return -1;
705 }
706 have_ignore_callees = 1;
707 }
708
709 return 0;
710}
711
697static int 712static int
698parse_branch_mode(const struct option *opt __maybe_unused, 713parse_branch_mode(const struct option *opt __maybe_unused,
699 const char *str __maybe_unused, int unset) 714 const char *str __maybe_unused, int unset)
@@ -730,13 +745,13 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
730 .tool = { 745 .tool = {
731 .sample = process_sample_event, 746 .sample = process_sample_event,
732 .mmap = perf_event__process_mmap, 747 .mmap = perf_event__process_mmap,
748 .mmap2 = perf_event__process_mmap2,
733 .comm = perf_event__process_comm, 749 .comm = perf_event__process_comm,
734 .exit = perf_event__process_exit, 750 .exit = perf_event__process_exit,
735 .fork = perf_event__process_fork, 751 .fork = perf_event__process_fork,
736 .lost = perf_event__process_lost, 752 .lost = perf_event__process_lost,
737 .read = process_read_event, 753 .read = process_read_event,
738 .attr = perf_event__process_attr, 754 .attr = perf_event__process_attr,
739 .event_type = perf_event__process_event_type,
740 .tracing_data = perf_event__process_tracing_data, 755 .tracing_data = perf_event__process_tracing_data,
741 .build_id = perf_event__process_build_id, 756 .build_id = perf_event__process_build_id,
742 .ordered_samples = true, 757 .ordered_samples = true,
@@ -780,10 +795,13 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
780 OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other, 795 OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other,
781 "Only display entries with parent-match"), 796 "Only display entries with parent-match"),
782 OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order", 797 OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order",
783 "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit and callchain order. " 798 "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit, callchain order, key (function or address). "
784 "Default: fractal,0.5,callee", &parse_callchain_opt, callchain_default_opt), 799 "Default: fractal,0.5,callee,function", &parse_callchain_opt, callchain_default_opt),
785 OPT_BOOLEAN('G', "inverted", &report.inverted_callchain, 800 OPT_BOOLEAN('G', "inverted", &report.inverted_callchain,
786 "alias for inverted call graph"), 801 "alias for inverted call graph"),
802 OPT_CALLBACK(0, "ignore-callees", NULL, "regex",
803 "ignore callees of these functions in call graphs",
804 report_parse_ignore_callees_opt),
787 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", 805 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
788 "only consider symbols in these dsos"), 806 "only consider symbols in these dsos"),
789 OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]", 807 OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
@@ -853,7 +871,6 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
853 setup_browser(true); 871 setup_browser(true);
854 else { 872 else {
855 use_browser = 0; 873 use_browser = 0;
856 perf_hpp__column_enable(PERF_HPP__OVERHEAD);
857 perf_hpp__init(); 874 perf_hpp__init();
858 } 875 }
859 876
@@ -907,7 +924,8 @@ repeat:
907 */ 924 */
908 if (use_browser == 1 && sort__has_sym) { 925 if (use_browser == 1 && sort__has_sym) {
909 symbol_conf.priv_size = sizeof(struct annotation); 926 symbol_conf.priv_size = sizeof(struct annotation);
910 report.annotate_init = symbol__annotate_init; 927 machines__set_symbol_filter(&session->machines,
928 symbol__annotate_init);
911 /* 929 /*
912 * For searching by name on the "Browse map details". 930 * For searching by name on the "Browse map details".
913 * providing it only in verbose mode not to bloat too 931 * providing it only in verbose mode not to bloat too
@@ -931,14 +949,6 @@ repeat:
931 if (parent_pattern != default_parent_pattern) { 949 if (parent_pattern != default_parent_pattern) {
932 if (sort_dimension__add("parent") < 0) 950 if (sort_dimension__add("parent") < 0)
933 goto error; 951 goto error;
934
935 /*
936 * Only show the parent fields if we explicitly
937 * sort that way. If we only use parent machinery
938 * for filtering, we don't want it.
939 */
940 if (!strstr(sort_order, "parent"))
941 sort_parent.elide = 1;
942 } 952 }
943 953
944 if (argc) { 954 if (argc) {
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index fed9ae432c16..d8c51b2f263f 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -109,8 +109,9 @@ struct trace_sched_handler {
109 int (*wakeup_event)(struct perf_sched *sched, struct perf_evsel *evsel, 109 int (*wakeup_event)(struct perf_sched *sched, struct perf_evsel *evsel,
110 struct perf_sample *sample, struct machine *machine); 110 struct perf_sample *sample, struct machine *machine);
111 111
112 int (*fork_event)(struct perf_sched *sched, struct perf_evsel *evsel, 112 /* PERF_RECORD_FORK event, not sched_process_fork tracepoint */
113 struct perf_sample *sample); 113 int (*fork_event)(struct perf_sched *sched, union perf_event *event,
114 struct machine *machine);
114 115
115 int (*migrate_task_event)(struct perf_sched *sched, 116 int (*migrate_task_event)(struct perf_sched *sched,
116 struct perf_evsel *evsel, 117 struct perf_evsel *evsel,
@@ -717,22 +718,31 @@ static int replay_switch_event(struct perf_sched *sched,
717 return 0; 718 return 0;
718} 719}
719 720
720static int replay_fork_event(struct perf_sched *sched, struct perf_evsel *evsel, 721static int replay_fork_event(struct perf_sched *sched,
721 struct perf_sample *sample) 722 union perf_event *event,
723 struct machine *machine)
722{ 724{
723 const char *parent_comm = perf_evsel__strval(evsel, sample, "parent_comm"), 725 struct thread *child, *parent;
724 *child_comm = perf_evsel__strval(evsel, sample, "child_comm"); 726
725 const u32 parent_pid = perf_evsel__intval(evsel, sample, "parent_pid"), 727 child = machine__findnew_thread(machine, event->fork.pid,
726 child_pid = perf_evsel__intval(evsel, sample, "child_pid"); 728 event->fork.tid);
729 parent = machine__findnew_thread(machine, event->fork.ppid,
730 event->fork.ptid);
731
732 if (child == NULL || parent == NULL) {
733 pr_debug("thread does not exist on fork event: child %p, parent %p\n",
734 child, parent);
735 return 0;
736 }
727 737
728 if (verbose) { 738 if (verbose) {
729 printf("sched_fork event %p\n", evsel); 739 printf("fork event\n");
730 printf("... parent: %s/%d\n", parent_comm, parent_pid); 740 printf("... parent: %s/%d\n", parent->comm, parent->tid);
731 printf("... child: %s/%d\n", child_comm, child_pid); 741 printf("... child: %s/%d\n", child->comm, child->tid);
732 } 742 }
733 743
734 register_pid(sched, parent_pid, parent_comm); 744 register_pid(sched, parent->tid, parent->comm);
735 register_pid(sched, child_pid, child_comm); 745 register_pid(sched, child->tid, child->comm);
736 return 0; 746 return 0;
737} 747}
738 748
@@ -824,14 +834,6 @@ static int thread_atoms_insert(struct perf_sched *sched, struct thread *thread)
824 return 0; 834 return 0;
825} 835}
826 836
827static int latency_fork_event(struct perf_sched *sched __maybe_unused,
828 struct perf_evsel *evsel __maybe_unused,
829 struct perf_sample *sample __maybe_unused)
830{
831 /* should insert the newcomer */
832 return 0;
833}
834
835static char sched_out_state(u64 prev_state) 837static char sched_out_state(u64 prev_state)
836{ 838{
837 const char *str = TASK_STATE_TO_CHAR_STR; 839 const char *str = TASK_STATE_TO_CHAR_STR;
@@ -934,8 +936,8 @@ static int latency_switch_event(struct perf_sched *sched,
934 return -1; 936 return -1;
935 } 937 }
936 938
937 sched_out = machine__findnew_thread(machine, prev_pid); 939 sched_out = machine__findnew_thread(machine, 0, prev_pid);
938 sched_in = machine__findnew_thread(machine, next_pid); 940 sched_in = machine__findnew_thread(machine, 0, next_pid);
939 941
940 out_events = thread_atoms_search(&sched->atom_root, sched_out, &sched->cmp_pid); 942 out_events = thread_atoms_search(&sched->atom_root, sched_out, &sched->cmp_pid);
941 if (!out_events) { 943 if (!out_events) {
@@ -978,7 +980,7 @@ static int latency_runtime_event(struct perf_sched *sched,
978{ 980{
979 const u32 pid = perf_evsel__intval(evsel, sample, "pid"); 981 const u32 pid = perf_evsel__intval(evsel, sample, "pid");
980 const u64 runtime = perf_evsel__intval(evsel, sample, "runtime"); 982 const u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
981 struct thread *thread = machine__findnew_thread(machine, pid); 983 struct thread *thread = machine__findnew_thread(machine, 0, pid);
982 struct work_atoms *atoms = thread_atoms_search(&sched->atom_root, thread, &sched->cmp_pid); 984 struct work_atoms *atoms = thread_atoms_search(&sched->atom_root, thread, &sched->cmp_pid);
983 u64 timestamp = sample->time; 985 u64 timestamp = sample->time;
984 int cpu = sample->cpu; 986 int cpu = sample->cpu;
@@ -1016,7 +1018,7 @@ static int latency_wakeup_event(struct perf_sched *sched,
1016 if (!success) 1018 if (!success)
1017 return 0; 1019 return 0;
1018 1020
1019 wakee = machine__findnew_thread(machine, pid); 1021 wakee = machine__findnew_thread(machine, 0, pid);
1020 atoms = thread_atoms_search(&sched->atom_root, wakee, &sched->cmp_pid); 1022 atoms = thread_atoms_search(&sched->atom_root, wakee, &sched->cmp_pid);
1021 if (!atoms) { 1023 if (!atoms) {
1022 if (thread_atoms_insert(sched, wakee)) 1024 if (thread_atoms_insert(sched, wakee))
@@ -1070,12 +1072,12 @@ static int latency_migrate_task_event(struct perf_sched *sched,
1070 if (sched->profile_cpu == -1) 1072 if (sched->profile_cpu == -1)
1071 return 0; 1073 return 0;
1072 1074
1073 migrant = machine__findnew_thread(machine, pid); 1075 migrant = machine__findnew_thread(machine, 0, pid);
1074 atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid); 1076 atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid);
1075 if (!atoms) { 1077 if (!atoms) {
1076 if (thread_atoms_insert(sched, migrant)) 1078 if (thread_atoms_insert(sched, migrant))
1077 return -1; 1079 return -1;
1078 register_pid(sched, migrant->pid, migrant->comm); 1080 register_pid(sched, migrant->tid, migrant->comm);
1079 atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid); 1081 atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid);
1080 if (!atoms) { 1082 if (!atoms) {
1081 pr_err("migration-event: Internal tree error"); 1083 pr_err("migration-event: Internal tree error");
@@ -1115,7 +1117,7 @@ static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_
1115 sched->all_runtime += work_list->total_runtime; 1117 sched->all_runtime += work_list->total_runtime;
1116 sched->all_count += work_list->nb_atoms; 1118 sched->all_count += work_list->nb_atoms;
1117 1119
1118 ret = printf(" %s:%d ", work_list->thread->comm, work_list->thread->pid); 1120 ret = printf(" %s:%d ", work_list->thread->comm, work_list->thread->tid);
1119 1121
1120 for (i = 0; i < 24 - ret; i++) 1122 for (i = 0; i < 24 - ret; i++)
1121 printf(" "); 1123 printf(" ");
@@ -1131,9 +1133,9 @@ static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_
1131 1133
1132static int pid_cmp(struct work_atoms *l, struct work_atoms *r) 1134static int pid_cmp(struct work_atoms *l, struct work_atoms *r)
1133{ 1135{
1134 if (l->thread->pid < r->thread->pid) 1136 if (l->thread->tid < r->thread->tid)
1135 return -1; 1137 return -1;
1136 if (l->thread->pid > r->thread->pid) 1138 if (l->thread->tid > r->thread->tid)
1137 return 1; 1139 return 1;
1138 1140
1139 return 0; 1141 return 0;
@@ -1289,8 +1291,8 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,
1289 return -1; 1291 return -1;
1290 } 1292 }
1291 1293
1292 sched_out = machine__findnew_thread(machine, prev_pid); 1294 sched_out = machine__findnew_thread(machine, 0, prev_pid);
1293 sched_in = machine__findnew_thread(machine, next_pid); 1295 sched_in = machine__findnew_thread(machine, 0, next_pid);
1294 1296
1295 sched->curr_thread[this_cpu] = sched_in; 1297 sched->curr_thread[this_cpu] = sched_in;
1296 1298
@@ -1321,7 +1323,7 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,
1321 printf("*"); 1323 printf("*");
1322 1324
1323 if (sched->curr_thread[cpu]) { 1325 if (sched->curr_thread[cpu]) {
1324 if (sched->curr_thread[cpu]->pid) 1326 if (sched->curr_thread[cpu]->tid)
1325 printf("%2s ", sched->curr_thread[cpu]->shortname); 1327 printf("%2s ", sched->curr_thread[cpu]->shortname);
1326 else 1328 else
1327 printf(". "); 1329 printf(". ");
@@ -1332,7 +1334,7 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,
1332 printf(" %12.6f secs ", (double)timestamp/1e9); 1334 printf(" %12.6f secs ", (double)timestamp/1e9);
1333 if (new_shortname) { 1335 if (new_shortname) {
1334 printf("%s => %s:%d\n", 1336 printf("%s => %s:%d\n",
1335 sched_in->shortname, sched_in->comm, sched_in->pid); 1337 sched_in->shortname, sched_in->comm, sched_in->tid);
1336 } else { 1338 } else {
1337 printf("\n"); 1339 printf("\n");
1338 } 1340 }
@@ -1379,25 +1381,20 @@ static int process_sched_runtime_event(struct perf_tool *tool,
1379 return 0; 1381 return 0;
1380} 1382}
1381 1383
1382static int process_sched_fork_event(struct perf_tool *tool, 1384static int perf_sched__process_fork_event(struct perf_tool *tool,
1383 struct perf_evsel *evsel, 1385 union perf_event *event,
1384 struct perf_sample *sample, 1386 struct perf_sample *sample,
1385 struct machine *machine __maybe_unused) 1387 struct machine *machine)
1386{ 1388{
1387 struct perf_sched *sched = container_of(tool, struct perf_sched, tool); 1389 struct perf_sched *sched = container_of(tool, struct perf_sched, tool);
1388 1390
1389 if (sched->tp_handler->fork_event) 1391 /* run the fork event through the perf machineruy */
1390 return sched->tp_handler->fork_event(sched, evsel, sample); 1392 perf_event__process_fork(tool, event, sample, machine);
1391 1393
1392 return 0; 1394 /* and then run additional processing needed for this command */
1393} 1395 if (sched->tp_handler->fork_event)
1396 return sched->tp_handler->fork_event(sched, event, machine);
1394 1397
1395static int process_sched_exit_event(struct perf_tool *tool __maybe_unused,
1396 struct perf_evsel *evsel,
1397 struct perf_sample *sample __maybe_unused,
1398 struct machine *machine __maybe_unused)
1399{
1400 pr_debug("sched_exit event %p\n", evsel);
1401 return 0; 1398 return 0;
1402} 1399}
1403 1400
@@ -1425,15 +1422,8 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool __maybe_
1425 struct perf_evsel *evsel, 1422 struct perf_evsel *evsel,
1426 struct machine *machine) 1423 struct machine *machine)
1427{ 1424{
1428 struct thread *thread = machine__findnew_thread(machine, sample->tid);
1429 int err = 0; 1425 int err = 0;
1430 1426
1431 if (thread == NULL) {
1432 pr_debug("problem processing %s event, skipping it.\n",
1433 perf_evsel__name(evsel));
1434 return -1;
1435 }
1436
1437 evsel->hists.stats.total_period += sample->period; 1427 evsel->hists.stats.total_period += sample->period;
1438 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); 1428 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
1439 1429
@@ -1445,7 +1435,7 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool __maybe_
1445 return err; 1435 return err;
1446} 1436}
1447 1437
1448static int perf_sched__read_events(struct perf_sched *sched, bool destroy, 1438static int perf_sched__read_events(struct perf_sched *sched,
1449 struct perf_session **psession) 1439 struct perf_session **psession)
1450{ 1440{
1451 const struct perf_evsel_str_handler handlers[] = { 1441 const struct perf_evsel_str_handler handlers[] = {
@@ -1453,8 +1443,6 @@ static int perf_sched__read_events(struct perf_sched *sched, bool destroy,
1453 { "sched:sched_stat_runtime", process_sched_runtime_event, }, 1443 { "sched:sched_stat_runtime", process_sched_runtime_event, },
1454 { "sched:sched_wakeup", process_sched_wakeup_event, }, 1444 { "sched:sched_wakeup", process_sched_wakeup_event, },
1455 { "sched:sched_wakeup_new", process_sched_wakeup_event, }, 1445 { "sched:sched_wakeup_new", process_sched_wakeup_event, },
1456 { "sched:sched_process_fork", process_sched_fork_event, },
1457 { "sched:sched_process_exit", process_sched_exit_event, },
1458 { "sched:sched_migrate_task", process_sched_migrate_task_event, }, 1446 { "sched:sched_migrate_task", process_sched_migrate_task_event, },
1459 }; 1447 };
1460 struct perf_session *session; 1448 struct perf_session *session;
@@ -1480,11 +1468,10 @@ static int perf_sched__read_events(struct perf_sched *sched, bool destroy,
1480 sched->nr_lost_chunks = session->stats.nr_events[PERF_RECORD_LOST]; 1468 sched->nr_lost_chunks = session->stats.nr_events[PERF_RECORD_LOST];
1481 } 1469 }
1482 1470
1483 if (destroy)
1484 perf_session__delete(session);
1485
1486 if (psession) 1471 if (psession)
1487 *psession = session; 1472 *psession = session;
1473 else
1474 perf_session__delete(session);
1488 1475
1489 return 0; 1476 return 0;
1490 1477
@@ -1529,8 +1516,11 @@ static int perf_sched__lat(struct perf_sched *sched)
1529 struct perf_session *session; 1516 struct perf_session *session;
1530 1517
1531 setup_pager(); 1518 setup_pager();
1532 if (perf_sched__read_events(sched, false, &session)) 1519
1520 /* save session -- references to threads are held in work_list */
1521 if (perf_sched__read_events(sched, &session))
1533 return -1; 1522 return -1;
1523
1534 perf_sched__sort_lat(sched); 1524 perf_sched__sort_lat(sched);
1535 1525
1536 printf("\n ---------------------------------------------------------------------------------------------------------------\n"); 1526 printf("\n ---------------------------------------------------------------------------------------------------------------\n");
@@ -1565,7 +1555,7 @@ static int perf_sched__map(struct perf_sched *sched)
1565 sched->max_cpu = sysconf(_SC_NPROCESSORS_CONF); 1555 sched->max_cpu = sysconf(_SC_NPROCESSORS_CONF);
1566 1556
1567 setup_pager(); 1557 setup_pager();
1568 if (perf_sched__read_events(sched, true, NULL)) 1558 if (perf_sched__read_events(sched, NULL))
1569 return -1; 1559 return -1;
1570 print_bad_events(sched); 1560 print_bad_events(sched);
1571 return 0; 1561 return 0;
@@ -1580,7 +1570,7 @@ static int perf_sched__replay(struct perf_sched *sched)
1580 1570
1581 test_calibrations(sched); 1571 test_calibrations(sched);
1582 1572
1583 if (perf_sched__read_events(sched, true, NULL)) 1573 if (perf_sched__read_events(sched, NULL))
1584 return -1; 1574 return -1;
1585 1575
1586 printf("nr_run_events: %ld\n", sched->nr_run_events); 1576 printf("nr_run_events: %ld\n", sched->nr_run_events);
@@ -1639,7 +1629,6 @@ static int __cmd_record(int argc, const char **argv)
1639 "-e", "sched:sched_stat_sleep", 1629 "-e", "sched:sched_stat_sleep",
1640 "-e", "sched:sched_stat_iowait", 1630 "-e", "sched:sched_stat_iowait",
1641 "-e", "sched:sched_stat_runtime", 1631 "-e", "sched:sched_stat_runtime",
1642 "-e", "sched:sched_process_exit",
1643 "-e", "sched:sched_process_fork", 1632 "-e", "sched:sched_process_fork",
1644 "-e", "sched:sched_wakeup", 1633 "-e", "sched:sched_wakeup",
1645 "-e", "sched:sched_migrate_task", 1634 "-e", "sched:sched_migrate_task",
@@ -1662,28 +1651,29 @@ static int __cmd_record(int argc, const char **argv)
1662 return cmd_record(i, rec_argv, NULL); 1651 return cmd_record(i, rec_argv, NULL);
1663} 1652}
1664 1653
1654static const char default_sort_order[] = "avg, max, switch, runtime";
1655static struct perf_sched sched = {
1656 .tool = {
1657 .sample = perf_sched__process_tracepoint_sample,
1658 .comm = perf_event__process_comm,
1659 .lost = perf_event__process_lost,
1660 .fork = perf_sched__process_fork_event,
1661 .ordered_samples = true,
1662 },
1663 .cmp_pid = LIST_HEAD_INIT(sched.cmp_pid),
1664 .sort_list = LIST_HEAD_INIT(sched.sort_list),
1665 .start_work_mutex = PTHREAD_MUTEX_INITIALIZER,
1666 .work_done_wait_mutex = PTHREAD_MUTEX_INITIALIZER,
1667 .curr_pid = { [0 ... MAX_CPUS - 1] = -1 },
1668 .sort_order = default_sort_order,
1669 .replay_repeat = 10,
1670 .profile_cpu = -1,
1671 .next_shortname1 = 'A',
1672 .next_shortname2 = '0',
1673};
1674
1665int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) 1675int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
1666{ 1676{
1667 const char default_sort_order[] = "avg, max, switch, runtime";
1668 struct perf_sched sched = {
1669 .tool = {
1670 .sample = perf_sched__process_tracepoint_sample,
1671 .comm = perf_event__process_comm,
1672 .lost = perf_event__process_lost,
1673 .fork = perf_event__process_fork,
1674 .ordered_samples = true,
1675 },
1676 .cmp_pid = LIST_HEAD_INIT(sched.cmp_pid),
1677 .sort_list = LIST_HEAD_INIT(sched.sort_list),
1678 .start_work_mutex = PTHREAD_MUTEX_INITIALIZER,
1679 .work_done_wait_mutex = PTHREAD_MUTEX_INITIALIZER,
1680 .curr_pid = { [0 ... MAX_CPUS - 1] = -1 },
1681 .sort_order = default_sort_order,
1682 .replay_repeat = 10,
1683 .profile_cpu = -1,
1684 .next_shortname1 = 'A',
1685 .next_shortname2 = '0',
1686 };
1687 const struct option latency_options[] = { 1677 const struct option latency_options[] = {
1688 OPT_STRING('s', "sort", &sched.sort_order, "key[,key2...]", 1678 OPT_STRING('s', "sort", &sched.sort_order, "key[,key2...]",
1689 "sort by key(s): runtime, switch, avg, max"), 1679 "sort by key(s): runtime, switch, avg, max"),
@@ -1729,7 +1719,6 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
1729 .wakeup_event = latency_wakeup_event, 1719 .wakeup_event = latency_wakeup_event,
1730 .switch_event = latency_switch_event, 1720 .switch_event = latency_switch_event,
1731 .runtime_event = latency_runtime_event, 1721 .runtime_event = latency_runtime_event,
1732 .fork_event = latency_fork_event,
1733 .migrate_task_event = latency_migrate_task_event, 1722 .migrate_task_event = latency_migrate_task_event,
1734 }; 1723 };
1735 struct trace_sched_handler map_ops = { 1724 struct trace_sched_handler map_ops = {
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 92d4658f56fb..9c333ff3dfeb 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -24,6 +24,7 @@ static u64 last_timestamp;
24static u64 nr_unordered; 24static u64 nr_unordered;
25extern const struct option record_options[]; 25extern const struct option record_options[];
26static bool no_callchain; 26static bool no_callchain;
27static bool latency_format;
27static bool system_wide; 28static bool system_wide;
28static const char *cpu_list; 29static const char *cpu_list;
29static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 30static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
@@ -65,6 +66,7 @@ struct output_option {
65static struct { 66static struct {
66 bool user_set; 67 bool user_set;
67 bool wildcard_set; 68 bool wildcard_set;
69 unsigned int print_ip_opts;
68 u64 fields; 70 u64 fields;
69 u64 invalid_fields; 71 u64 invalid_fields;
70} output[PERF_TYPE_MAX] = { 72} output[PERF_TYPE_MAX] = {
@@ -234,6 +236,7 @@ static int perf_session__check_output_opt(struct perf_session *session)
234{ 236{
235 int j; 237 int j;
236 struct perf_evsel *evsel; 238 struct perf_evsel *evsel;
239 struct perf_event_attr *attr;
237 240
238 for (j = 0; j < PERF_TYPE_MAX; ++j) { 241 for (j = 0; j < PERF_TYPE_MAX; ++j) {
239 evsel = perf_session__find_first_evtype(session, j); 242 evsel = perf_session__find_first_evtype(session, j);
@@ -252,6 +255,24 @@ static int perf_session__check_output_opt(struct perf_session *session)
252 if (evsel && output[j].fields && 255 if (evsel && output[j].fields &&
253 perf_evsel__check_attr(evsel, session)) 256 perf_evsel__check_attr(evsel, session))
254 return -1; 257 return -1;
258
259 if (evsel == NULL)
260 continue;
261
262 attr = &evsel->attr;
263
264 output[j].print_ip_opts = 0;
265 if (PRINT_FIELD(IP))
266 output[j].print_ip_opts |= PRINT_IP_OPT_IP;
267
268 if (PRINT_FIELD(SYM))
269 output[j].print_ip_opts |= PRINT_IP_OPT_SYM;
270
271 if (PRINT_FIELD(DSO))
272 output[j].print_ip_opts |= PRINT_IP_OPT_DSO;
273
274 if (PRINT_FIELD(SYMOFFSET))
275 output[j].print_ip_opts |= PRINT_IP_OPT_SYMOFFSET;
255 } 276 }
256 277
257 return 0; 278 return 0;
@@ -381,8 +402,8 @@ static void print_sample_bts(union perf_event *event,
381 else 402 else
382 printf("\n"); 403 printf("\n");
383 perf_evsel__print_ip(evsel, event, sample, machine, 404 perf_evsel__print_ip(evsel, event, sample, machine,
384 PRINT_FIELD(SYM), PRINT_FIELD(DSO), 405 output[attr->type].print_ip_opts,
385 PRINT_FIELD(SYMOFFSET)); 406 PERF_MAX_STACK_DEPTH);
386 } 407 }
387 408
388 printf(" => "); 409 printf(" => ");
@@ -396,10 +417,10 @@ static void print_sample_bts(union perf_event *event,
396 417
397static void process_event(union perf_event *event, struct perf_sample *sample, 418static void process_event(union perf_event *event, struct perf_sample *sample,
398 struct perf_evsel *evsel, struct machine *machine, 419 struct perf_evsel *evsel, struct machine *machine,
399 struct addr_location *al) 420 struct thread *thread,
421 struct addr_location *al __maybe_unused)
400{ 422{
401 struct perf_event_attr *attr = &evsel->attr; 423 struct perf_event_attr *attr = &evsel->attr;
402 struct thread *thread = al->thread;
403 424
404 if (output[attr->type].fields == 0) 425 if (output[attr->type].fields == 0)
405 return; 426 return;
@@ -422,9 +443,10 @@ static void process_event(union perf_event *event, struct perf_sample *sample,
422 printf(" "); 443 printf(" ");
423 else 444 else
424 printf("\n"); 445 printf("\n");
446
425 perf_evsel__print_ip(evsel, event, sample, machine, 447 perf_evsel__print_ip(evsel, event, sample, machine,
426 PRINT_FIELD(SYM), PRINT_FIELD(DSO), 448 output[attr->type].print_ip_opts,
427 PRINT_FIELD(SYMOFFSET)); 449 PERF_MAX_STACK_DEPTH);
428 } 450 }
429 451
430 printf("\n"); 452 printf("\n");
@@ -479,7 +501,8 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
479 struct machine *machine) 501 struct machine *machine)
480{ 502{
481 struct addr_location al; 503 struct addr_location al;
482 struct thread *thread = machine__findnew_thread(machine, event->ip.tid); 504 struct thread *thread = machine__findnew_thread(machine, sample->pid,
505 sample->tid);
483 506
484 if (thread == NULL) { 507 if (thread == NULL) {
485 pr_debug("problem processing %d event, skipping it.\n", 508 pr_debug("problem processing %d event, skipping it.\n",
@@ -498,7 +521,7 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
498 return 0; 521 return 0;
499 } 522 }
500 523
501 if (perf_event__preprocess_sample(event, machine, &al, sample, 0) < 0) { 524 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
502 pr_err("problem processing %d event, skipping it.\n", 525 pr_err("problem processing %d event, skipping it.\n",
503 event->header.type); 526 event->header.type);
504 return -1; 527 return -1;
@@ -510,7 +533,7 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
510 if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) 533 if (cpu_list && !test_bit(sample->cpu, cpu_bitmap))
511 return 0; 534 return 0;
512 535
513 scripting_ops->process_event(event, sample, evsel, machine, &al); 536 scripting_ops->process_event(event, sample, evsel, machine, thread, &al);
514 537
515 evsel->hists.stats.total_period += sample->period; 538 evsel->hists.stats.total_period += sample->period;
516 return 0; 539 return 0;
@@ -519,19 +542,17 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
519static struct perf_tool perf_script = { 542static struct perf_tool perf_script = {
520 .sample = process_sample_event, 543 .sample = process_sample_event,
521 .mmap = perf_event__process_mmap, 544 .mmap = perf_event__process_mmap,
545 .mmap2 = perf_event__process_mmap2,
522 .comm = perf_event__process_comm, 546 .comm = perf_event__process_comm,
523 .exit = perf_event__process_exit, 547 .exit = perf_event__process_exit,
524 .fork = perf_event__process_fork, 548 .fork = perf_event__process_fork,
525 .attr = perf_event__process_attr, 549 .attr = perf_event__process_attr,
526 .event_type = perf_event__process_event_type,
527 .tracing_data = perf_event__process_tracing_data, 550 .tracing_data = perf_event__process_tracing_data,
528 .build_id = perf_event__process_build_id, 551 .build_id = perf_event__process_build_id,
529 .ordered_samples = true, 552 .ordered_samples = true,
530 .ordering_requires_timestamps = true, 553 .ordering_requires_timestamps = true,
531}; 554};
532 555
533extern volatile int session_done;
534
535static void sig_handler(int sig __maybe_unused) 556static void sig_handler(int sig __maybe_unused)
536{ 557{
537 session_done = 1; 558 session_done = 1;
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 352fbd7ff4a1..f686d5ff594e 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -100,6 +100,7 @@ static const char *pre_cmd = NULL;
100static const char *post_cmd = NULL; 100static const char *post_cmd = NULL;
101static bool sync_run = false; 101static bool sync_run = false;
102static unsigned int interval = 0; 102static unsigned int interval = 0;
103static unsigned int initial_delay = 0;
103static bool forever = false; 104static bool forever = false;
104static struct timespec ref_time; 105static struct timespec ref_time;
105static struct cpu_map *aggr_map; 106static struct cpu_map *aggr_map;
@@ -254,7 +255,8 @@ static int create_perf_stat_counter(struct perf_evsel *evsel)
254 if (!perf_target__has_task(&target) && 255 if (!perf_target__has_task(&target) &&
255 perf_evsel__is_group_leader(evsel)) { 256 perf_evsel__is_group_leader(evsel)) {
256 attr->disabled = 1; 257 attr->disabled = 1;
257 attr->enable_on_exec = 1; 258 if (!initial_delay)
259 attr->enable_on_exec = 1;
258 } 260 }
259 261
260 return perf_evsel__open_per_thread(evsel, evsel_list->threads); 262 return perf_evsel__open_per_thread(evsel, evsel_list->threads);
@@ -414,6 +416,22 @@ static void print_interval(void)
414 list_for_each_entry(counter, &evsel_list->entries, node) 416 list_for_each_entry(counter, &evsel_list->entries, node)
415 print_counter_aggr(counter, prefix); 417 print_counter_aggr(counter, prefix);
416 } 418 }
419
420 fflush(output);
421}
422
423static void handle_initial_delay(void)
424{
425 struct perf_evsel *counter;
426
427 if (initial_delay) {
428 const int ncpus = cpu_map__nr(evsel_list->cpus),
429 nthreads = thread_map__nr(evsel_list->threads);
430
431 usleep(initial_delay * 1000);
432 list_for_each_entry(counter, &evsel_list->entries, node)
433 perf_evsel__enable(counter, ncpus, nthreads);
434 }
417} 435}
418 436
419static int __run_perf_stat(int argc, const char **argv) 437static int __run_perf_stat(int argc, const char **argv)
@@ -486,6 +504,7 @@ static int __run_perf_stat(int argc, const char **argv)
486 504
487 if (forks) { 505 if (forks) {
488 perf_evlist__start_workload(evsel_list); 506 perf_evlist__start_workload(evsel_list);
507 handle_initial_delay();
489 508
490 if (interval) { 509 if (interval) {
491 while (!waitpid(child_pid, &status, WNOHANG)) { 510 while (!waitpid(child_pid, &status, WNOHANG)) {
@@ -497,6 +516,7 @@ static int __run_perf_stat(int argc, const char **argv)
497 if (WIFSIGNALED(status)) 516 if (WIFSIGNALED(status))
498 psignal(WTERMSIG(status), argv[0]); 517 psignal(WTERMSIG(status), argv[0]);
499 } else { 518 } else {
519 handle_initial_delay();
500 while (!done) { 520 while (!done) {
501 nanosleep(&ts, NULL); 521 nanosleep(&ts, NULL);
502 if (interval) 522 if (interval)
@@ -1419,6 +1439,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1419 "aggregate counts per processor socket", AGGR_SOCKET), 1439 "aggregate counts per processor socket", AGGR_SOCKET),
1420 OPT_SET_UINT(0, "per-core", &aggr_mode, 1440 OPT_SET_UINT(0, "per-core", &aggr_mode,
1421 "aggregate counts per physical processor core", AGGR_CORE), 1441 "aggregate counts per physical processor core", AGGR_CORE),
1442 OPT_UINTEGER('D', "delay", &initial_delay,
1443 "ms to wait before starting measurement after program start"),
1422 OPT_END() 1444 OPT_END()
1423 }; 1445 };
1424 const char * const stat_usage[] = { 1446 const char * const stat_usage[] = {
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 4536a92b18f3..c2e02319347a 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -12,6 +12,8 @@
12 * of the License. 12 * of the License.
13 */ 13 */
14 14
15#include <traceevent/event-parse.h>
16
15#include "builtin.h" 17#include "builtin.h"
16 18
17#include "util/util.h" 19#include "util/util.h"
@@ -19,6 +21,7 @@
19#include "util/color.h" 21#include "util/color.h"
20#include <linux/list.h> 22#include <linux/list.h>
21#include "util/cache.h" 23#include "util/cache.h"
24#include "util/evlist.h"
22#include "util/evsel.h" 25#include "util/evsel.h"
23#include <linux/rbtree.h> 26#include <linux/rbtree.h>
24#include "util/symbol.h" 27#include "util/symbol.h"
@@ -328,25 +331,6 @@ struct wakeup_entry {
328 int success; 331 int success;
329}; 332};
330 333
331/*
332 * trace_flag_type is an enumeration that holds different
333 * states when a trace occurs. These are:
334 * IRQS_OFF - interrupts were disabled
335 * IRQS_NOSUPPORT - arch does not support irqs_disabled_flags
336 * NEED_RESCED - reschedule is requested
337 * HARDIRQ - inside an interrupt handler
338 * SOFTIRQ - inside a softirq handler
339 */
340enum trace_flag_type {
341 TRACE_FLAG_IRQS_OFF = 0x01,
342 TRACE_FLAG_IRQS_NOSUPPORT = 0x02,
343 TRACE_FLAG_NEED_RESCHED = 0x04,
344 TRACE_FLAG_HARDIRQ = 0x08,
345 TRACE_FLAG_SOFTIRQ = 0x10,
346};
347
348
349
350struct sched_switch { 334struct sched_switch {
351 struct trace_entry te; 335 struct trace_entry te;
352 char prev_comm[TASK_COMM_LEN]; 336 char prev_comm[TASK_COMM_LEN];
@@ -479,6 +463,8 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te)
479 } 463 }
480} 464}
481 465
466typedef int (*tracepoint_handler)(struct perf_evsel *evsel,
467 struct perf_sample *sample);
482 468
483static int process_sample_event(struct perf_tool *tool __maybe_unused, 469static int process_sample_event(struct perf_tool *tool __maybe_unused,
484 union perf_event *event __maybe_unused, 470 union perf_event *event __maybe_unused,
@@ -486,8 +472,6 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
486 struct perf_evsel *evsel, 472 struct perf_evsel *evsel,
487 struct machine *machine __maybe_unused) 473 struct machine *machine __maybe_unused)
488{ 474{
489 struct trace_entry *te;
490
491 if (evsel->attr.sample_type & PERF_SAMPLE_TIME) { 475 if (evsel->attr.sample_type & PERF_SAMPLE_TIME) {
492 if (!first_time || first_time > sample->time) 476 if (!first_time || first_time > sample->time)
493 first_time = sample->time; 477 first_time = sample->time;
@@ -495,69 +479,90 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
495 last_time = sample->time; 479 last_time = sample->time;
496 } 480 }
497 481
498 te = (void *)sample->raw_data; 482 if (sample->cpu > numcpus)
499 if ((evsel->attr.sample_type & PERF_SAMPLE_RAW) && sample->raw_size > 0) { 483 numcpus = sample->cpu;
500 char *event_str; 484
501#ifdef SUPPORT_OLD_POWER_EVENTS 485 if (evsel->handler.func != NULL) {
502 struct power_entry_old *peo; 486 tracepoint_handler f = evsel->handler.func;
503 peo = (void *)te; 487 return f(evsel, sample);
504#endif 488 }
505 /* 489
506 * FIXME: use evsel, its already mapped from id to perf_evsel, 490 return 0;
507 * remove perf_header__find_event infrastructure bits. 491}
508 * Mapping all these "power:cpu_idle" strings to the tracepoint 492
509 * ID and then just comparing against evsel->attr.config. 493static int
510 * 494process_sample_cpu_idle(struct perf_evsel *evsel __maybe_unused,
511 * e.g.: 495 struct perf_sample *sample)
512 * 496{
513 * if (evsel->attr.config == power_cpu_idle_id) 497 struct power_processor_entry *ppe = sample->raw_data;
514 */ 498
515 event_str = perf_header__find_event(te->type); 499 if (ppe->state == (u32) PWR_EVENT_EXIT)
516 500 c_state_end(ppe->cpu_id, sample->time);
517 if (!event_str) 501 else
518 return 0; 502 c_state_start(ppe->cpu_id, sample->time, ppe->state);
519 503 return 0;
520 if (sample->cpu > numcpus) 504}
521 numcpus = sample->cpu; 505
522 506static int
523 if (strcmp(event_str, "power:cpu_idle") == 0) { 507process_sample_cpu_frequency(struct perf_evsel *evsel __maybe_unused,
524 struct power_processor_entry *ppe = (void *)te; 508 struct perf_sample *sample)
525 if (ppe->state == (u32)PWR_EVENT_EXIT) 509{
526 c_state_end(ppe->cpu_id, sample->time); 510 struct power_processor_entry *ppe = sample->raw_data;
527 else 511
528 c_state_start(ppe->cpu_id, sample->time, 512 p_state_change(ppe->cpu_id, sample->time, ppe->state);
529 ppe->state); 513 return 0;
530 } 514}
531 else if (strcmp(event_str, "power:cpu_frequency") == 0) { 515
532 struct power_processor_entry *ppe = (void *)te; 516static int
533 p_state_change(ppe->cpu_id, sample->time, ppe->state); 517process_sample_sched_wakeup(struct perf_evsel *evsel __maybe_unused,
534 } 518 struct perf_sample *sample)
519{
520 struct trace_entry *te = sample->raw_data;
521
522 sched_wakeup(sample->cpu, sample->time, sample->pid, te);
523 return 0;
524}
535 525
536 else if (strcmp(event_str, "sched:sched_wakeup") == 0) 526static int
537 sched_wakeup(sample->cpu, sample->time, sample->pid, te); 527process_sample_sched_switch(struct perf_evsel *evsel __maybe_unused,
528 struct perf_sample *sample)
529{
530 struct trace_entry *te = sample->raw_data;
538 531
539 else if (strcmp(event_str, "sched:sched_switch") == 0) 532 sched_switch(sample->cpu, sample->time, te);
540 sched_switch(sample->cpu, sample->time, te); 533 return 0;
534}
541 535
542#ifdef SUPPORT_OLD_POWER_EVENTS 536#ifdef SUPPORT_OLD_POWER_EVENTS
543 if (use_old_power_events) { 537static int
544 if (strcmp(event_str, "power:power_start") == 0) 538process_sample_power_start(struct perf_evsel *evsel __maybe_unused,
545 c_state_start(peo->cpu_id, sample->time, 539 struct perf_sample *sample)
546 peo->value); 540{
547 541 struct power_entry_old *peo = sample->raw_data;
548 else if (strcmp(event_str, "power:power_end") == 0) 542
549 c_state_end(sample->cpu, sample->time); 543 c_state_start(peo->cpu_id, sample->time, peo->value);
550
551 else if (strcmp(event_str,
552 "power:power_frequency") == 0)
553 p_state_change(peo->cpu_id, sample->time,
554 peo->value);
555 }
556#endif
557 }
558 return 0; 544 return 0;
559} 545}
560 546
547static int
548process_sample_power_end(struct perf_evsel *evsel __maybe_unused,
549 struct perf_sample *sample)
550{
551 c_state_end(sample->cpu, sample->time);
552 return 0;
553}
554
555static int
556process_sample_power_frequency(struct perf_evsel *evsel __maybe_unused,
557 struct perf_sample *sample)
558{
559 struct power_entry_old *peo = sample->raw_data;
560
561 p_state_change(peo->cpu_id, sample->time, peo->value);
562 return 0;
563}
564#endif /* SUPPORT_OLD_POWER_EVENTS */
565
561/* 566/*
562 * After the last sample we need to wrap up the current C/P state 567 * After the last sample we need to wrap up the current C/P state
563 * and close out each CPU for these. 568 * and close out each CPU for these.
@@ -974,6 +979,17 @@ static int __cmd_timechart(const char *output_name)
974 .sample = process_sample_event, 979 .sample = process_sample_event,
975 .ordered_samples = true, 980 .ordered_samples = true,
976 }; 981 };
982 const struct perf_evsel_str_handler power_tracepoints[] = {
983 { "power:cpu_idle", process_sample_cpu_idle },
984 { "power:cpu_frequency", process_sample_cpu_frequency },
985 { "sched:sched_wakeup", process_sample_sched_wakeup },
986 { "sched:sched_switch", process_sample_sched_switch },
987#ifdef SUPPORT_OLD_POWER_EVENTS
988 { "power:power_start", process_sample_power_start },
989 { "power:power_end", process_sample_power_end },
990 { "power:power_frequency", process_sample_power_frequency },
991#endif
992 };
977 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 993 struct perf_session *session = perf_session__new(input_name, O_RDONLY,
978 0, false, &perf_timechart); 994 0, false, &perf_timechart);
979 int ret = -EINVAL; 995 int ret = -EINVAL;
@@ -984,6 +1000,12 @@ static int __cmd_timechart(const char *output_name)
984 if (!perf_session__has_traces(session, "timechart record")) 1000 if (!perf_session__has_traces(session, "timechart record"))
985 goto out_delete; 1001 goto out_delete;
986 1002
1003 if (perf_session__set_tracepoints_handlers(session,
1004 power_tracepoints)) {
1005 pr_err("Initializing session tracepoint handlers failed\n");
1006 goto out_delete;
1007 }
1008
987 ret = perf_session__process_events(session, &perf_timechart); 1009 ret = perf_session__process_events(session, &perf_timechart);
988 if (ret) 1010 if (ret)
989 goto out_delete; 1011 goto out_delete;
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index e06c4f869330..212214162bb2 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -40,6 +40,7 @@
40#include "util/xyarray.h" 40#include "util/xyarray.h"
41#include "util/sort.h" 41#include "util/sort.h"
42#include "util/intlist.h" 42#include "util/intlist.h"
43#include "arch/common.h"
43 44
44#include "util/debug.h" 45#include "util/debug.h"
45 46
@@ -102,7 +103,8 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he)
102 /* 103 /*
103 * We can't annotate with just /proc/kallsyms 104 * We can't annotate with just /proc/kallsyms
104 */ 105 */
105 if (map->dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS) { 106 if (map->dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS &&
107 !dso__is_kcore(map->dso)) {
106 pr_err("Can't annotate %s: No vmlinux file was found in the " 108 pr_err("Can't annotate %s: No vmlinux file was found in the "
107 "path\n", sym->name); 109 "path\n", sym->name);
108 sleep(1); 110 sleep(1);
@@ -237,8 +239,6 @@ out_unlock:
237 pthread_mutex_unlock(&notes->lock); 239 pthread_mutex_unlock(&notes->lock);
238} 240}
239 241
240static const char CONSOLE_CLEAR[] = "";
241
242static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel, 242static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel,
243 struct addr_location *al, 243 struct addr_location *al,
244 struct perf_sample *sample) 244 struct perf_sample *sample)
@@ -689,7 +689,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
689{ 689{
690 struct perf_top *top = container_of(tool, struct perf_top, tool); 690 struct perf_top *top = container_of(tool, struct perf_top, tool);
691 struct symbol *parent = NULL; 691 struct symbol *parent = NULL;
692 u64 ip = event->ip.ip; 692 u64 ip = sample->ip;
693 struct addr_location al; 693 struct addr_location al;
694 int err; 694 int err;
695 695
@@ -699,10 +699,10 @@ static void perf_event__process_sample(struct perf_tool *tool,
699 if (!seen) 699 if (!seen)
700 seen = intlist__new(NULL); 700 seen = intlist__new(NULL);
701 701
702 if (!intlist__has_entry(seen, event->ip.pid)) { 702 if (!intlist__has_entry(seen, sample->pid)) {
703 pr_err("Can't find guest [%d]'s kernel information\n", 703 pr_err("Can't find guest [%d]'s kernel information\n",
704 event->ip.pid); 704 sample->pid);
705 intlist__add(seen, event->ip.pid); 705 intlist__add(seen, sample->pid);
706 } 706 }
707 return; 707 return;
708 } 708 }
@@ -716,8 +716,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
716 if (event->header.misc & PERF_RECORD_MISC_EXACT_IP) 716 if (event->header.misc & PERF_RECORD_MISC_EXACT_IP)
717 top->exact_samples++; 717 top->exact_samples++;
718 718
719 if (perf_event__preprocess_sample(event, machine, &al, sample, 719 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0 ||
720 symbol_filter) < 0 ||
721 al.filtered) 720 al.filtered)
722 return; 721 return;
723 722
@@ -772,8 +771,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
772 sample->callchain) { 771 sample->callchain) {
773 err = machine__resolve_callchain(machine, evsel, 772 err = machine__resolve_callchain(machine, evsel,
774 al.thread, sample, 773 al.thread, sample,
775 &parent); 774 &parent, &al);
776
777 if (err) 775 if (err)
778 return; 776 return;
779 } 777 }
@@ -838,7 +836,8 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
838 break; 836 break;
839 case PERF_RECORD_MISC_GUEST_KERNEL: 837 case PERF_RECORD_MISC_GUEST_KERNEL:
840 ++top->guest_kernel_samples; 838 ++top->guest_kernel_samples;
841 machine = perf_session__find_machine(session, event->ip.pid); 839 machine = perf_session__find_machine(session,
840 sample.pid);
842 break; 841 break;
843 case PERF_RECORD_MISC_GUEST_USER: 842 case PERF_RECORD_MISC_GUEST_USER:
844 ++top->guest_us_samples; 843 ++top->guest_us_samples;
@@ -939,6 +938,14 @@ static int __cmd_top(struct perf_top *top)
939 if (top->session == NULL) 938 if (top->session == NULL)
940 return -ENOMEM; 939 return -ENOMEM;
941 940
941 machines__set_symbol_filter(&top->session->machines, symbol_filter);
942
943 if (!objdump_path) {
944 ret = perf_session_env__lookup_objdump(&top->session->header.env);
945 if (ret)
946 goto out_delete;
947 }
948
942 ret = perf_top__setup_sample_type(top); 949 ret = perf_top__setup_sample_type(top);
943 if (ret) 950 if (ret)
944 goto out_delete; 951 goto out_delete;
@@ -1102,6 +1109,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1102 OPT_CALLBACK_DEFAULT('G', "call-graph", &top.record_opts, 1109 OPT_CALLBACK_DEFAULT('G', "call-graph", &top.record_opts,
1103 "mode[,dump_size]", record_callchain_help, 1110 "mode[,dump_size]", record_callchain_help,
1104 &parse_callchain_opt, "fp"), 1111 &parse_callchain_opt, "fp"),
1112 OPT_CALLBACK(0, "ignore-callees", NULL, "regex",
1113 "ignore callees of these functions in call graphs",
1114 report_parse_ignore_callees_opt),
1105 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, 1115 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
1106 "Show a column with the sum of periods"), 1116 "Show a column with the sum of periods"),
1107 OPT_STRING(0, "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", 1117 OPT_STRING(0, "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
@@ -1114,6 +1124,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1114 "Interleave source code with assembly code (default)"), 1124 "Interleave source code with assembly code (default)"),
1115 OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw, 1125 OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw,
1116 "Display raw encoding of assembly instructions (default)"), 1126 "Display raw encoding of assembly instructions (default)"),
1127 OPT_STRING(0, "objdump", &objdump_path, "path",
1128 "objdump binary to use for disassembly and annotations"),
1117 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", 1129 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
1118 "Specify disassembler style (e.g. -M intel for intel syntax)"), 1130 "Specify disassembler style (e.g. -M intel for intel syntax)"),
1119 OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"), 1131 OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"),
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index ab3ed4af1466..71aa3e35406b 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -1,34 +1,350 @@
1#include <traceevent/event-parse.h>
1#include "builtin.h" 2#include "builtin.h"
2#include "util/color.h" 3#include "util/color.h"
4#include "util/debug.h"
3#include "util/evlist.h" 5#include "util/evlist.h"
4#include "util/machine.h" 6#include "util/machine.h"
7#include "util/session.h"
5#include "util/thread.h" 8#include "util/thread.h"
6#include "util/parse-options.h" 9#include "util/parse-options.h"
10#include "util/strlist.h"
11#include "util/intlist.h"
7#include "util/thread_map.h" 12#include "util/thread_map.h"
8#include "event-parse.h"
9 13
10#include <libaudit.h> 14#include <libaudit.h>
11#include <stdlib.h> 15#include <stdlib.h>
16#include <sys/mman.h>
17#include <linux/futex.h>
18
19/* For older distros: */
20#ifndef MAP_STACK
21# define MAP_STACK 0x20000
22#endif
23
24#ifndef MADV_HWPOISON
25# define MADV_HWPOISON 100
26#endif
27
28#ifndef MADV_MERGEABLE
29# define MADV_MERGEABLE 12
30#endif
31
32#ifndef MADV_UNMERGEABLE
33# define MADV_UNMERGEABLE 13
34#endif
35
36static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
37 unsigned long arg,
38 u8 arg_idx __maybe_unused,
39 u8 *arg_mask __maybe_unused)
40{
41 return scnprintf(bf, size, "%#lx", arg);
42}
43
44#define SCA_HEX syscall_arg__scnprintf_hex
45
46static size_t syscall_arg__scnprintf_whence(char *bf, size_t size,
47 unsigned long arg,
48 u8 arg_idx __maybe_unused,
49 u8 *arg_mask __maybe_unused)
50{
51 int whence = arg;
52
53 switch (whence) {
54#define P_WHENCE(n) case SEEK_##n: return scnprintf(bf, size, #n)
55 P_WHENCE(SET);
56 P_WHENCE(CUR);
57 P_WHENCE(END);
58#ifdef SEEK_DATA
59 P_WHENCE(DATA);
60#endif
61#ifdef SEEK_HOLE
62 P_WHENCE(HOLE);
63#endif
64#undef P_WHENCE
65 default: break;
66 }
67
68 return scnprintf(bf, size, "%#x", whence);
69}
70
71#define SCA_WHENCE syscall_arg__scnprintf_whence
72
73static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
74 unsigned long arg,
75 u8 arg_idx __maybe_unused,
76 u8 *arg_mask __maybe_unused)
77{
78 int printed = 0, prot = arg;
79
80 if (prot == PROT_NONE)
81 return scnprintf(bf, size, "NONE");
82#define P_MMAP_PROT(n) \
83 if (prot & PROT_##n) { \
84 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
85 prot &= ~PROT_##n; \
86 }
87
88 P_MMAP_PROT(EXEC);
89 P_MMAP_PROT(READ);
90 P_MMAP_PROT(WRITE);
91#ifdef PROT_SEM
92 P_MMAP_PROT(SEM);
93#endif
94 P_MMAP_PROT(GROWSDOWN);
95 P_MMAP_PROT(GROWSUP);
96#undef P_MMAP_PROT
97
98 if (prot)
99 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
100
101 return printed;
102}
103
104#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
105
106static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
107 unsigned long arg, u8 arg_idx __maybe_unused,
108 u8 *arg_mask __maybe_unused)
109{
110 int printed = 0, flags = arg;
111
112#define P_MMAP_FLAG(n) \
113 if (flags & MAP_##n) { \
114 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
115 flags &= ~MAP_##n; \
116 }
117
118 P_MMAP_FLAG(SHARED);
119 P_MMAP_FLAG(PRIVATE);
120#ifdef MAP_32BIT
121 P_MMAP_FLAG(32BIT);
122#endif
123 P_MMAP_FLAG(ANONYMOUS);
124 P_MMAP_FLAG(DENYWRITE);
125 P_MMAP_FLAG(EXECUTABLE);
126 P_MMAP_FLAG(FILE);
127 P_MMAP_FLAG(FIXED);
128 P_MMAP_FLAG(GROWSDOWN);
129#ifdef MAP_HUGETLB
130 P_MMAP_FLAG(HUGETLB);
131#endif
132 P_MMAP_FLAG(LOCKED);
133 P_MMAP_FLAG(NONBLOCK);
134 P_MMAP_FLAG(NORESERVE);
135 P_MMAP_FLAG(POPULATE);
136 P_MMAP_FLAG(STACK);
137#ifdef MAP_UNINITIALIZED
138 P_MMAP_FLAG(UNINITIALIZED);
139#endif
140#undef P_MMAP_FLAG
141
142 if (flags)
143 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
144
145 return printed;
146}
147
148#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
149
150static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
151 unsigned long arg, u8 arg_idx __maybe_unused,
152 u8 *arg_mask __maybe_unused)
153{
154 int behavior = arg;
155
156 switch (behavior) {
157#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
158 P_MADV_BHV(NORMAL);
159 P_MADV_BHV(RANDOM);
160 P_MADV_BHV(SEQUENTIAL);
161 P_MADV_BHV(WILLNEED);
162 P_MADV_BHV(DONTNEED);
163 P_MADV_BHV(REMOVE);
164 P_MADV_BHV(DONTFORK);
165 P_MADV_BHV(DOFORK);
166 P_MADV_BHV(HWPOISON);
167#ifdef MADV_SOFT_OFFLINE
168 P_MADV_BHV(SOFT_OFFLINE);
169#endif
170 P_MADV_BHV(MERGEABLE);
171 P_MADV_BHV(UNMERGEABLE);
172#ifdef MADV_HUGEPAGE
173 P_MADV_BHV(HUGEPAGE);
174#endif
175#ifdef MADV_NOHUGEPAGE
176 P_MADV_BHV(NOHUGEPAGE);
177#endif
178#ifdef MADV_DONTDUMP
179 P_MADV_BHV(DONTDUMP);
180#endif
181#ifdef MADV_DODUMP
182 P_MADV_BHV(DODUMP);
183#endif
184#undef P_MADV_PHV
185 default: break;
186 }
187
188 return scnprintf(bf, size, "%#x", behavior);
189}
190
191#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
192
193static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, unsigned long arg,
194 u8 arg_idx __maybe_unused, u8 *arg_mask)
195{
196 enum syscall_futex_args {
197 SCF_UADDR = (1 << 0),
198 SCF_OP = (1 << 1),
199 SCF_VAL = (1 << 2),
200 SCF_TIMEOUT = (1 << 3),
201 SCF_UADDR2 = (1 << 4),
202 SCF_VAL3 = (1 << 5),
203 };
204 int op = arg;
205 int cmd = op & FUTEX_CMD_MASK;
206 size_t printed = 0;
207
208 switch (cmd) {
209#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
210 P_FUTEX_OP(WAIT); *arg_mask |= SCF_VAL3|SCF_UADDR2; break;
211 P_FUTEX_OP(WAKE); *arg_mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
212 P_FUTEX_OP(FD); *arg_mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
213 P_FUTEX_OP(REQUEUE); *arg_mask |= SCF_VAL3|SCF_TIMEOUT; break;
214 P_FUTEX_OP(CMP_REQUEUE); *arg_mask |= SCF_TIMEOUT; break;
215 P_FUTEX_OP(CMP_REQUEUE_PI); *arg_mask |= SCF_TIMEOUT; break;
216 P_FUTEX_OP(WAKE_OP); break;
217 P_FUTEX_OP(LOCK_PI); *arg_mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
218 P_FUTEX_OP(UNLOCK_PI); *arg_mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
219 P_FUTEX_OP(TRYLOCK_PI); *arg_mask |= SCF_VAL3|SCF_UADDR2; break;
220 P_FUTEX_OP(WAIT_BITSET); *arg_mask |= SCF_UADDR2; break;
221 P_FUTEX_OP(WAKE_BITSET); *arg_mask |= SCF_UADDR2; break;
222 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
223 default: printed = scnprintf(bf, size, "%#x", cmd); break;
224 }
225
226 if (op & FUTEX_PRIVATE_FLAG)
227 printed += scnprintf(bf + printed, size - printed, "|PRIV");
228
229 if (op & FUTEX_CLOCK_REALTIME)
230 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
231
232 return printed;
233}
234
235#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
236
237static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
238 unsigned long arg,
239 u8 arg_idx, u8 *arg_mask)
240{
241 int printed = 0, flags = arg;
242
243 if (!(flags & O_CREAT))
244 *arg_mask |= 1 << (arg_idx + 1); /* Mask the mode parm */
245
246 if (flags == 0)
247 return scnprintf(bf, size, "RDONLY");
248#define P_FLAG(n) \
249 if (flags & O_##n) { \
250 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
251 flags &= ~O_##n; \
252 }
253
254 P_FLAG(APPEND);
255 P_FLAG(ASYNC);
256 P_FLAG(CLOEXEC);
257 P_FLAG(CREAT);
258 P_FLAG(DIRECT);
259 P_FLAG(DIRECTORY);
260 P_FLAG(EXCL);
261 P_FLAG(LARGEFILE);
262 P_FLAG(NOATIME);
263 P_FLAG(NOCTTY);
264#ifdef O_NONBLOCK
265 P_FLAG(NONBLOCK);
266#elif O_NDELAY
267 P_FLAG(NDELAY);
268#endif
269#ifdef O_PATH
270 P_FLAG(PATH);
271#endif
272 P_FLAG(RDWR);
273#ifdef O_DSYNC
274 if ((flags & O_SYNC) == O_SYNC)
275 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
276 else {
277 P_FLAG(DSYNC);
278 }
279#else
280 P_FLAG(SYNC);
281#endif
282 P_FLAG(TRUNC);
283 P_FLAG(WRONLY);
284#undef P_FLAG
285
286 if (flags)
287 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
288
289 return printed;
290}
291
292#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
12 293
13static struct syscall_fmt { 294static struct syscall_fmt {
14 const char *name; 295 const char *name;
15 const char *alias; 296 const char *alias;
297 size_t (*arg_scnprintf[6])(char *bf, size_t size, unsigned long arg, u8 arg_idx, u8 *arg_mask);
16 bool errmsg; 298 bool errmsg;
17 bool timeout; 299 bool timeout;
300 bool hexret;
18} syscall_fmts[] = { 301} syscall_fmts[] = {
19 { .name = "access", .errmsg = true, }, 302 { .name = "access", .errmsg = true, },
20 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", }, 303 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
304 { .name = "brk", .hexret = true,
305 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
306 { .name = "mmap", .hexret = true, },
307 { .name = "connect", .errmsg = true, },
21 { .name = "fstat", .errmsg = true, .alias = "newfstat", }, 308 { .name = "fstat", .errmsg = true, .alias = "newfstat", },
22 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", }, 309 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", },
23 { .name = "futex", .errmsg = true, }, 310 { .name = "futex", .errmsg = true,
24 { .name = "open", .errmsg = true, }, 311 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
312 { .name = "ioctl", .errmsg = true,
313 .arg_scnprintf = { [2] = SCA_HEX, /* arg */ }, },
314 { .name = "lseek", .errmsg = true,
315 .arg_scnprintf = { [2] = SCA_WHENCE, /* whence */ }, },
316 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
317 { .name = "madvise", .errmsg = true,
318 .arg_scnprintf = { [0] = SCA_HEX, /* start */
319 [2] = SCA_MADV_BHV, /* behavior */ }, },
320 { .name = "mmap", .hexret = true,
321 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
322 [2] = SCA_MMAP_PROT, /* prot */
323 [3] = SCA_MMAP_FLAGS, /* flags */ }, },
324 { .name = "mprotect", .errmsg = true,
325 .arg_scnprintf = { [0] = SCA_HEX, /* start */
326 [2] = SCA_MMAP_PROT, /* prot */ }, },
327 { .name = "mremap", .hexret = true,
328 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
329 [4] = SCA_HEX, /* new_addr */ }, },
330 { .name = "munmap", .errmsg = true,
331 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
332 { .name = "open", .errmsg = true,
333 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
334 { .name = "open_by_handle_at", .errmsg = true,
335 .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, },
336 { .name = "openat", .errmsg = true,
337 .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, },
25 { .name = "poll", .errmsg = true, .timeout = true, }, 338 { .name = "poll", .errmsg = true, .timeout = true, },
26 { .name = "ppoll", .errmsg = true, .timeout = true, }, 339 { .name = "ppoll", .errmsg = true, .timeout = true, },
340 { .name = "pread", .errmsg = true, .alias = "pread64", },
341 { .name = "pwrite", .errmsg = true, .alias = "pwrite64", },
27 { .name = "read", .errmsg = true, }, 342 { .name = "read", .errmsg = true, },
28 { .name = "recvfrom", .errmsg = true, }, 343 { .name = "recvfrom", .errmsg = true, },
29 { .name = "select", .errmsg = true, .timeout = true, }, 344 { .name = "select", .errmsg = true, .timeout = true, },
30 { .name = "socket", .errmsg = true, }, 345 { .name = "socket", .errmsg = true, },
31 { .name = "stat", .errmsg = true, .alias = "newstat", }, 346 { .name = "stat", .errmsg = true, .alias = "newstat", },
347 { .name = "uname", .errmsg = true, .alias = "newuname", },
32}; 348};
33 349
34static int syscall_fmt__cmp(const void *name, const void *fmtp) 350static int syscall_fmt__cmp(const void *name, const void *fmtp)
@@ -46,7 +362,10 @@ static struct syscall_fmt *syscall_fmt__find(const char *name)
46struct syscall { 362struct syscall {
47 struct event_format *tp_format; 363 struct event_format *tp_format;
48 const char *name; 364 const char *name;
365 bool filtered;
49 struct syscall_fmt *fmt; 366 struct syscall_fmt *fmt;
367 size_t (**arg_scnprintf)(char *bf, size_t size,
368 unsigned long arg, u8 arg_idx, u8 *args_mask);
50}; 369};
51 370
52static size_t fprintf_duration(unsigned long t, FILE *fp) 371static size_t fprintf_duration(unsigned long t, FILE *fp)
@@ -60,7 +379,7 @@ static size_t fprintf_duration(unsigned long t, FILE *fp)
60 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration); 379 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
61 else 380 else
62 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration); 381 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
63 return printed + fprintf(stdout, "): "); 382 return printed + fprintf(fp, "): ");
64} 383}
65 384
66struct thread_trace { 385struct thread_trace {
@@ -77,7 +396,7 @@ static struct thread_trace *thread_trace__new(void)
77 return zalloc(sizeof(struct thread_trace)); 396 return zalloc(sizeof(struct thread_trace));
78} 397}
79 398
80static struct thread_trace *thread__trace(struct thread *thread) 399static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
81{ 400{
82 struct thread_trace *ttrace; 401 struct thread_trace *ttrace;
83 402
@@ -95,12 +414,13 @@ static struct thread_trace *thread__trace(struct thread *thread)
95 414
96 return ttrace; 415 return ttrace;
97fail: 416fail:
98 color_fprintf(stdout, PERF_COLOR_RED, 417 color_fprintf(fp, PERF_COLOR_RED,
99 "WARNING: not enough memory, dropping samples!\n"); 418 "WARNING: not enough memory, dropping samples!\n");
100 return NULL; 419 return NULL;
101} 420}
102 421
103struct trace { 422struct trace {
423 struct perf_tool tool;
104 int audit_machine; 424 int audit_machine;
105 struct { 425 struct {
106 int max; 426 int max;
@@ -109,7 +429,12 @@ struct trace {
109 struct perf_record_opts opts; 429 struct perf_record_opts opts;
110 struct machine host; 430 struct machine host;
111 u64 base_time; 431 u64 base_time;
432 FILE *output;
112 unsigned long nr_events; 433 unsigned long nr_events;
434 struct strlist *ev_qualifier;
435 bool not_ev_qualifier;
436 struct intlist *tid_list;
437 struct intlist *pid_list;
113 bool sched; 438 bool sched;
114 bool multiple_threads; 439 bool multiple_threads;
115 double duration_filter; 440 double duration_filter;
@@ -142,18 +467,19 @@ static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thre
142 printed += fprintf_duration(duration, fp); 467 printed += fprintf_duration(duration, fp);
143 468
144 if (trace->multiple_threads) 469 if (trace->multiple_threads)
145 printed += fprintf(fp, "%d ", thread->pid); 470 printed += fprintf(fp, "%d ", thread->tid);
146 471
147 return printed; 472 return printed;
148} 473}
149 474
150static int trace__process_event(struct machine *machine, union perf_event *event) 475static int trace__process_event(struct trace *trace, struct machine *machine,
476 union perf_event *event)
151{ 477{
152 int ret = 0; 478 int ret = 0;
153 479
154 switch (event->header.type) { 480 switch (event->header.type) {
155 case PERF_RECORD_LOST: 481 case PERF_RECORD_LOST:
156 color_fprintf(stdout, PERF_COLOR_RED, 482 color_fprintf(trace->output, PERF_COLOR_RED,
157 "LOST %" PRIu64 " events!\n", event->lost.lost); 483 "LOST %" PRIu64 " events!\n", event->lost.lost);
158 ret = machine__process_lost_event(machine, event); 484 ret = machine__process_lost_event(machine, event);
159 default: 485 default:
@@ -164,12 +490,13 @@ static int trace__process_event(struct machine *machine, union perf_event *event
164 return ret; 490 return ret;
165} 491}
166 492
167static int trace__tool_process(struct perf_tool *tool __maybe_unused, 493static int trace__tool_process(struct perf_tool *tool,
168 union perf_event *event, 494 union perf_event *event,
169 struct perf_sample *sample __maybe_unused, 495 struct perf_sample *sample __maybe_unused,
170 struct machine *machine) 496 struct machine *machine)
171{ 497{
172 return trace__process_event(machine, event); 498 struct trace *trace = container_of(tool, struct trace, tool);
499 return trace__process_event(trace, machine, event);
173} 500}
174 501
175static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist) 502static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
@@ -183,11 +510,11 @@ static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
183 machine__create_kernel_maps(&trace->host); 510 machine__create_kernel_maps(&trace->host);
184 511
185 if (perf_target__has_task(&trace->opts.target)) { 512 if (perf_target__has_task(&trace->opts.target)) {
186 err = perf_event__synthesize_thread_map(NULL, evlist->threads, 513 err = perf_event__synthesize_thread_map(&trace->tool, evlist->threads,
187 trace__tool_process, 514 trace__tool_process,
188 &trace->host); 515 &trace->host);
189 } else { 516 } else {
190 err = perf_event__synthesize_threads(NULL, trace__tool_process, 517 err = perf_event__synthesize_threads(&trace->tool, trace__tool_process,
191 &trace->host); 518 &trace->host);
192 } 519 }
193 520
@@ -197,6 +524,26 @@ static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
197 return err; 524 return err;
198} 525}
199 526
527static int syscall__set_arg_fmts(struct syscall *sc)
528{
529 struct format_field *field;
530 int idx = 0;
531
532 sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
533 if (sc->arg_scnprintf == NULL)
534 return -1;
535
536 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
537 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
538 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
539 else if (field->flags & FIELD_IS_POINTER)
540 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
541 ++idx;
542 }
543
544 return 0;
545}
546
200static int trace__read_syscall_info(struct trace *trace, int id) 547static int trace__read_syscall_info(struct trace *trace, int id)
201{ 548{
202 char tp_name[128]; 549 char tp_name[128];
@@ -225,6 +572,20 @@ static int trace__read_syscall_info(struct trace *trace, int id)
225 572
226 sc = trace->syscalls.table + id; 573 sc = trace->syscalls.table + id;
227 sc->name = name; 574 sc->name = name;
575
576 if (trace->ev_qualifier) {
577 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
578
579 if (!(in ^ trace->not_ev_qualifier)) {
580 sc->filtered = true;
581 /*
582 * No need to do read tracepoint information since this will be
583 * filtered out.
584 */
585 return 0;
586 }
587 }
588
228 sc->fmt = syscall_fmt__find(sc->name); 589 sc->fmt = syscall_fmt__find(sc->name);
229 590
230 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name); 591 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
@@ -235,7 +596,10 @@ static int trace__read_syscall_info(struct trace *trace, int id)
235 sc->tp_format = event_format__new("syscalls", tp_name); 596 sc->tp_format = event_format__new("syscalls", tp_name);
236 } 597 }
237 598
238 return sc->tp_format != NULL ? 0 : -1; 599 if (sc->tp_format == NULL)
600 return -1;
601
602 return syscall__set_arg_fmts(sc);
239} 603}
240 604
241static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size, 605static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
@@ -246,11 +610,23 @@ static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
246 610
247 if (sc->tp_format != NULL) { 611 if (sc->tp_format != NULL) {
248 struct format_field *field; 612 struct format_field *field;
613 u8 mask = 0, bit = 1;
614
615 for (field = sc->tp_format->format.fields->next; field;
616 field = field->next, ++i, bit <<= 1) {
617 if (mask & bit)
618 continue;
249 619
250 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
251 printed += scnprintf(bf + printed, size - printed, 620 printed += scnprintf(bf + printed, size - printed,
252 "%s%s: %ld", printed ? ", " : "", 621 "%s%s: ", printed ? ", " : "", field->name);
253 field->name, args[i++]); 622
623 if (sc->arg_scnprintf && sc->arg_scnprintf[i]) {
624 printed += sc->arg_scnprintf[i](bf + printed, size - printed,
625 args[i], i, &mask);
626 } else {
627 printed += scnprintf(bf + printed, size - printed,
628 "%ld", args[i]);
629 }
254 } 630 }
255 } else { 631 } else {
256 while (i < 6) { 632 while (i < 6) {
@@ -274,7 +650,22 @@ static struct syscall *trace__syscall_info(struct trace *trace,
274 int id = perf_evsel__intval(evsel, sample, "id"); 650 int id = perf_evsel__intval(evsel, sample, "id");
275 651
276 if (id < 0) { 652 if (id < 0) {
277 printf("Invalid syscall %d id, skipping...\n", id); 653
654 /*
655 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
656 * before that, leaving at a higher verbosity level till that is
657 * explained. Reproduced with plain ftrace with:
658 *
659 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
660 * grep "NR -1 " /t/trace_pipe
661 *
662 * After generating some load on the machine.
663 */
664 if (verbose > 1) {
665 static u64 n;
666 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
667 id, perf_evsel__name(evsel), ++n);
668 }
278 return NULL; 669 return NULL;
279 } 670 }
280 671
@@ -288,10 +679,12 @@ static struct syscall *trace__syscall_info(struct trace *trace,
288 return &trace->syscalls.table[id]; 679 return &trace->syscalls.table[id];
289 680
290out_cant_read: 681out_cant_read:
291 printf("Problems reading syscall %d", id); 682 if (verbose) {
292 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL) 683 fprintf(trace->output, "Problems reading syscall %d", id);
293 printf("(%s)", trace->syscalls.table[id].name); 684 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
294 puts(" information"); 685 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
686 fputs(" information\n", trace->output);
687 }
295 return NULL; 688 return NULL;
296} 689}
297 690
@@ -301,16 +694,25 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
301 char *msg; 694 char *msg;
302 void *args; 695 void *args;
303 size_t printed = 0; 696 size_t printed = 0;
304 struct thread *thread = machine__findnew_thread(&trace->host, sample->tid); 697 struct thread *thread;
305 struct syscall *sc = trace__syscall_info(trace, evsel, sample); 698 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
306 struct thread_trace *ttrace = thread__trace(thread); 699 struct thread_trace *ttrace;
307 700
308 if (ttrace == NULL || sc == NULL) 701 if (sc == NULL)
702 return -1;
703
704 if (sc->filtered)
705 return 0;
706
707 thread = machine__findnew_thread(&trace->host, sample->pid,
708 sample->tid);
709 ttrace = thread__trace(thread, trace->output);
710 if (ttrace == NULL)
309 return -1; 711 return -1;
310 712
311 args = perf_evsel__rawptr(evsel, sample, "args"); 713 args = perf_evsel__rawptr(evsel, sample, "args");
312 if (args == NULL) { 714 if (args == NULL) {
313 printf("Problems reading syscall arguments\n"); 715 fprintf(trace->output, "Problems reading syscall arguments\n");
314 return -1; 716 return -1;
315 } 717 }
316 718
@@ -330,8 +732,8 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
330 732
331 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) { 733 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
332 if (!trace->duration_filter) { 734 if (!trace->duration_filter) {
333 trace__fprintf_entry_head(trace, thread, 1, sample->time, stdout); 735 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
334 printf("%-70s\n", ttrace->entry_str); 736 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
335 } 737 }
336 } else 738 } else
337 ttrace->entry_pending = true; 739 ttrace->entry_pending = true;
@@ -344,11 +746,20 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
344{ 746{
345 int ret; 747 int ret;
346 u64 duration = 0; 748 u64 duration = 0;
347 struct thread *thread = machine__findnew_thread(&trace->host, sample->tid); 749 struct thread *thread;
348 struct thread_trace *ttrace = thread__trace(thread);
349 struct syscall *sc = trace__syscall_info(trace, evsel, sample); 750 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
751 struct thread_trace *ttrace;
350 752
351 if (ttrace == NULL || sc == NULL) 753 if (sc == NULL)
754 return -1;
755
756 if (sc->filtered)
757 return 0;
758
759 thread = machine__findnew_thread(&trace->host, sample->pid,
760 sample->tid);
761 ttrace = thread__trace(thread, trace->output);
762 if (ttrace == NULL)
352 return -1; 763 return -1;
353 764
354 ret = perf_evsel__intval(evsel, sample, "ret"); 765 ret = perf_evsel__intval(evsel, sample, "ret");
@@ -364,28 +775,33 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
364 } else if (trace->duration_filter) 775 } else if (trace->duration_filter)
365 goto out; 776 goto out;
366 777
367 trace__fprintf_entry_head(trace, thread, duration, sample->time, stdout); 778 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
368 779
369 if (ttrace->entry_pending) { 780 if (ttrace->entry_pending) {
370 printf("%-70s", ttrace->entry_str); 781 fprintf(trace->output, "%-70s", ttrace->entry_str);
371 } else { 782 } else {
372 printf(" ... ["); 783 fprintf(trace->output, " ... [");
373 color_fprintf(stdout, PERF_COLOR_YELLOW, "continued"); 784 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
374 printf("]: %s()", sc->name); 785 fprintf(trace->output, "]: %s()", sc->name);
375 } 786 }
376 787
377 if (ret < 0 && sc->fmt && sc->fmt->errmsg) { 788 if (sc->fmt == NULL) {
789signed_print:
790 fprintf(trace->output, ") = %d", ret);
791 } else if (ret < 0 && sc->fmt->errmsg) {
378 char bf[256]; 792 char bf[256];
379 const char *emsg = strerror_r(-ret, bf, sizeof(bf)), 793 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
380 *e = audit_errno_to_name(-ret); 794 *e = audit_errno_to_name(-ret);
381 795
382 printf(") = -1 %s %s", e, emsg); 796 fprintf(trace->output, ") = -1 %s %s", e, emsg);
383 } else if (ret == 0 && sc->fmt && sc->fmt->timeout) 797 } else if (ret == 0 && sc->fmt->timeout)
384 printf(") = 0 Timeout"); 798 fprintf(trace->output, ") = 0 Timeout");
799 else if (sc->fmt->hexret)
800 fprintf(trace->output, ") = %#x", ret);
385 else 801 else
386 printf(") = %d", ret); 802 goto signed_print;
387 803
388 putchar('\n'); 804 fputc('\n', trace->output);
389out: 805out:
390 ttrace->entry_pending = false; 806 ttrace->entry_pending = false;
391 807
@@ -397,8 +813,10 @@ static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evs
397{ 813{
398 u64 runtime = perf_evsel__intval(evsel, sample, "runtime"); 814 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
399 double runtime_ms = (double)runtime / NSEC_PER_MSEC; 815 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
400 struct thread *thread = machine__findnew_thread(&trace->host, sample->tid); 816 struct thread *thread = machine__findnew_thread(&trace->host,
401 struct thread_trace *ttrace = thread__trace(thread); 817 sample->pid,
818 sample->tid);
819 struct thread_trace *ttrace = thread__trace(thread, trace->output);
402 820
403 if (ttrace == NULL) 821 if (ttrace == NULL)
404 goto out_dump; 822 goto out_dump;
@@ -408,7 +826,7 @@ static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evs
408 return 0; 826 return 0;
409 827
410out_dump: 828out_dump:
411 printf("%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n", 829 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
412 evsel->name, 830 evsel->name,
413 perf_evsel__strval(evsel, sample, "comm"), 831 perf_evsel__strval(evsel, sample, "comm"),
414 (pid_t)perf_evsel__intval(evsel, sample, "pid"), 832 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
@@ -417,6 +835,72 @@ out_dump:
417 return 0; 835 return 0;
418} 836}
419 837
838static bool skip_sample(struct trace *trace, struct perf_sample *sample)
839{
840 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
841 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
842 return false;
843
844 if (trace->pid_list || trace->tid_list)
845 return true;
846
847 return false;
848}
849
850static int trace__process_sample(struct perf_tool *tool,
851 union perf_event *event __maybe_unused,
852 struct perf_sample *sample,
853 struct perf_evsel *evsel,
854 struct machine *machine __maybe_unused)
855{
856 struct trace *trace = container_of(tool, struct trace, tool);
857 int err = 0;
858
859 tracepoint_handler handler = evsel->handler.func;
860
861 if (skip_sample(trace, sample))
862 return 0;
863
864 if (trace->base_time == 0)
865 trace->base_time = sample->time;
866
867 if (handler)
868 handler(trace, evsel, sample);
869
870 return err;
871}
872
873static bool
874perf_session__has_tp(struct perf_session *session, const char *name)
875{
876 struct perf_evsel *evsel;
877
878 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, name);
879
880 return evsel != NULL;
881}
882
883static int parse_target_str(struct trace *trace)
884{
885 if (trace->opts.target.pid) {
886 trace->pid_list = intlist__new(trace->opts.target.pid);
887 if (trace->pid_list == NULL) {
888 pr_err("Error parsing process id string\n");
889 return -EINVAL;
890 }
891 }
892
893 if (trace->opts.target.tid) {
894 trace->tid_list = intlist__new(trace->opts.target.tid);
895 if (trace->tid_list == NULL) {
896 pr_err("Error parsing thread id string\n");
897 return -EINVAL;
898 }
899 }
900
901 return 0;
902}
903
420static int trace__run(struct trace *trace, int argc, const char **argv) 904static int trace__run(struct trace *trace, int argc, const char **argv)
421{ 905{
422 struct perf_evlist *evlist = perf_evlist__new(); 906 struct perf_evlist *evlist = perf_evlist__new();
@@ -426,32 +910,32 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
426 const bool forks = argc > 0; 910 const bool forks = argc > 0;
427 911
428 if (evlist == NULL) { 912 if (evlist == NULL) {
429 printf("Not enough memory to run!\n"); 913 fprintf(trace->output, "Not enough memory to run!\n");
430 goto out; 914 goto out;
431 } 915 }
432 916
433 if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) || 917 if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) ||
434 perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) { 918 perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) {
435 printf("Couldn't read the raw_syscalls tracepoints information!\n"); 919 fprintf(trace->output, "Couldn't read the raw_syscalls tracepoints information!\n");
436 goto out_delete_evlist; 920 goto out_delete_evlist;
437 } 921 }
438 922
439 if (trace->sched && 923 if (trace->sched &&
440 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime", 924 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
441 trace__sched_stat_runtime)) { 925 trace__sched_stat_runtime)) {
442 printf("Couldn't read the sched_stat_runtime tracepoint information!\n"); 926 fprintf(trace->output, "Couldn't read the sched_stat_runtime tracepoint information!\n");
443 goto out_delete_evlist; 927 goto out_delete_evlist;
444 } 928 }
445 929
446 err = perf_evlist__create_maps(evlist, &trace->opts.target); 930 err = perf_evlist__create_maps(evlist, &trace->opts.target);
447 if (err < 0) { 931 if (err < 0) {
448 printf("Problems parsing the target to trace, check your options!\n"); 932 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
449 goto out_delete_evlist; 933 goto out_delete_evlist;
450 } 934 }
451 935
452 err = trace__symbols_init(trace, evlist); 936 err = trace__symbols_init(trace, evlist);
453 if (err < 0) { 937 if (err < 0) {
454 printf("Problems initializing symbol libraries!\n"); 938 fprintf(trace->output, "Problems initializing symbol libraries!\n");
455 goto out_delete_maps; 939 goto out_delete_maps;
456 } 940 }
457 941
@@ -464,20 +948,20 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
464 err = perf_evlist__prepare_workload(evlist, &trace->opts.target, 948 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
465 argv, false, false); 949 argv, false, false);
466 if (err < 0) { 950 if (err < 0) {
467 printf("Couldn't run the workload!\n"); 951 fprintf(trace->output, "Couldn't run the workload!\n");
468 goto out_delete_maps; 952 goto out_delete_maps;
469 } 953 }
470 } 954 }
471 955
472 err = perf_evlist__open(evlist); 956 err = perf_evlist__open(evlist);
473 if (err < 0) { 957 if (err < 0) {
474 printf("Couldn't create the events: %s\n", strerror(errno)); 958 fprintf(trace->output, "Couldn't create the events: %s\n", strerror(errno));
475 goto out_delete_maps; 959 goto out_delete_maps;
476 } 960 }
477 961
478 err = perf_evlist__mmap(evlist, UINT_MAX, false); 962 err = perf_evlist__mmap(evlist, UINT_MAX, false);
479 if (err < 0) { 963 if (err < 0) {
480 printf("Couldn't mmap the events: %s\n", strerror(errno)); 964 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
481 goto out_close_evlist; 965 goto out_close_evlist;
482 } 966 }
483 967
@@ -502,7 +986,7 @@ again:
502 986
503 err = perf_evlist__parse_sample(evlist, event, &sample); 987 err = perf_evlist__parse_sample(evlist, event, &sample);
504 if (err) { 988 if (err) {
505 printf("Can't parse sample, err = %d, skipping...\n", err); 989 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
506 continue; 990 continue;
507 } 991 }
508 992
@@ -510,18 +994,18 @@ again:
510 trace->base_time = sample.time; 994 trace->base_time = sample.time;
511 995
512 if (type != PERF_RECORD_SAMPLE) { 996 if (type != PERF_RECORD_SAMPLE) {
513 trace__process_event(&trace->host, event); 997 trace__process_event(trace, &trace->host, event);
514 continue; 998 continue;
515 } 999 }
516 1000
517 evsel = perf_evlist__id2evsel(evlist, sample.id); 1001 evsel = perf_evlist__id2evsel(evlist, sample.id);
518 if (evsel == NULL) { 1002 if (evsel == NULL) {
519 printf("Unknown tp ID %" PRIu64 ", skipping...\n", sample.id); 1003 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
520 continue; 1004 continue;
521 } 1005 }
522 1006
523 if (sample.raw_data == NULL) { 1007 if (sample.raw_data == NULL) {
524 printf("%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n", 1008 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
525 perf_evsel__name(evsel), sample.tid, 1009 perf_evsel__name(evsel), sample.tid,
526 sample.cpu, sample.raw_size); 1010 sample.cpu, sample.raw_size);
527 continue; 1011 continue;
@@ -529,6 +1013,9 @@ again:
529 1013
530 handler = evsel->handler.func; 1014 handler = evsel->handler.func;
531 handler(trace, evsel, &sample); 1015 handler(trace, evsel, &sample);
1016
1017 if (done)
1018 goto out_unmap_evlist;
532 } 1019 }
533 } 1020 }
534 1021
@@ -556,6 +1043,70 @@ out:
556 return err; 1043 return err;
557} 1044}
558 1045
1046static int trace__replay(struct trace *trace)
1047{
1048 const struct perf_evsel_str_handler handlers[] = {
1049 { "raw_syscalls:sys_enter", trace__sys_enter, },
1050 { "raw_syscalls:sys_exit", trace__sys_exit, },
1051 };
1052
1053 struct perf_session *session;
1054 int err = -1;
1055
1056 trace->tool.sample = trace__process_sample;
1057 trace->tool.mmap = perf_event__process_mmap;
1058 trace->tool.mmap2 = perf_event__process_mmap2;
1059 trace->tool.comm = perf_event__process_comm;
1060 trace->tool.exit = perf_event__process_exit;
1061 trace->tool.fork = perf_event__process_fork;
1062 trace->tool.attr = perf_event__process_attr;
1063 trace->tool.tracing_data = perf_event__process_tracing_data;
1064 trace->tool.build_id = perf_event__process_build_id;
1065
1066 trace->tool.ordered_samples = true;
1067 trace->tool.ordering_requires_timestamps = true;
1068
1069 /* add tid to output */
1070 trace->multiple_threads = true;
1071
1072 if (symbol__init() < 0)
1073 return -1;
1074
1075 session = perf_session__new(input_name, O_RDONLY, 0, false,
1076 &trace->tool);
1077 if (session == NULL)
1078 return -ENOMEM;
1079
1080 err = perf_session__set_tracepoints_handlers(session, handlers);
1081 if (err)
1082 goto out;
1083
1084 if (!perf_session__has_tp(session, "raw_syscalls:sys_enter")) {
1085 pr_err("Data file does not have raw_syscalls:sys_enter events\n");
1086 goto out;
1087 }
1088
1089 if (!perf_session__has_tp(session, "raw_syscalls:sys_exit")) {
1090 pr_err("Data file does not have raw_syscalls:sys_exit events\n");
1091 goto out;
1092 }
1093
1094 err = parse_target_str(trace);
1095 if (err != 0)
1096 goto out;
1097
1098 setup_pager();
1099
1100 err = perf_session__process_events(session, &trace->tool);
1101 if (err)
1102 pr_err("Failed to process events, error %d", err);
1103
1104out:
1105 perf_session__delete(session);
1106
1107 return err;
1108}
1109
559static size_t trace__fprintf_threads_header(FILE *fp) 1110static size_t trace__fprintf_threads_header(FILE *fp)
560{ 1111{
561 size_t printed; 1112 size_t printed;
@@ -593,7 +1144,7 @@ static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
593 color = PERF_COLOR_YELLOW; 1144 color = PERF_COLOR_YELLOW;
594 1145
595 printed += color_fprintf(fp, color, "%20s", thread->comm); 1146 printed += color_fprintf(fp, color, "%20s", thread->comm);
596 printed += fprintf(fp, " - %-5d :%11lu [", thread->pid, ttrace->nr_events); 1147 printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
597 printed += color_fprintf(fp, color, "%5.1f%%", ratio); 1148 printed += color_fprintf(fp, color, "%5.1f%%", ratio);
598 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms); 1149 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
599 } 1150 }
@@ -610,6 +1161,23 @@ static int trace__set_duration(const struct option *opt, const char *str,
610 return 0; 1161 return 0;
611} 1162}
612 1163
1164static int trace__open_output(struct trace *trace, const char *filename)
1165{
1166 struct stat st;
1167
1168 if (!stat(filename, &st) && st.st_size) {
1169 char oldname[PATH_MAX];
1170
1171 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
1172 unlink(oldname);
1173 rename(filename, oldname);
1174 }
1175
1176 trace->output = fopen(filename, "w");
1177
1178 return trace->output == NULL ? -errno : 0;
1179}
1180
613int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) 1181int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
614{ 1182{
615 const char * const trace_usage[] = { 1183 const char * const trace_usage[] = {
@@ -632,26 +1200,34 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
632 .no_delay = true, 1200 .no_delay = true,
633 .mmap_pages = 1024, 1201 .mmap_pages = 1024,
634 }, 1202 },
1203 .output = stdout,
635 }; 1204 };
1205 const char *output_name = NULL;
1206 const char *ev_qualifier_str = NULL;
636 const struct option trace_options[] = { 1207 const struct option trace_options[] = {
1208 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
1209 "list of events to trace"),
1210 OPT_STRING('o', "output", &output_name, "file", "output file name"),
1211 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
637 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid", 1212 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
638 "trace events on existing process id"), 1213 "trace events on existing process id"),
639 OPT_STRING(0, "tid", &trace.opts.target.tid, "tid", 1214 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
640 "trace events on existing thread id"), 1215 "trace events on existing thread id"),
641 OPT_BOOLEAN(0, "all-cpus", &trace.opts.target.system_wide, 1216 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
642 "system-wide collection from all CPUs"), 1217 "system-wide collection from all CPUs"),
643 OPT_STRING(0, "cpu", &trace.opts.target.cpu_list, "cpu", 1218 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
644 "list of cpus to monitor"), 1219 "list of cpus to monitor"),
645 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit, 1220 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
646 "child tasks do not inherit counters"), 1221 "child tasks do not inherit counters"),
647 OPT_UINTEGER(0, "mmap-pages", &trace.opts.mmap_pages, 1222 OPT_UINTEGER('m', "mmap-pages", &trace.opts.mmap_pages,
648 "number of mmap data pages"), 1223 "number of mmap data pages"),
649 OPT_STRING(0, "uid", &trace.opts.target.uid_str, "user", 1224 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
650 "user to profile"), 1225 "user to profile"),
651 OPT_CALLBACK(0, "duration", &trace, "float", 1226 OPT_CALLBACK(0, "duration", &trace, "float",
652 "show only events with duration > N.M ms", 1227 "show only events with duration > N.M ms",
653 trace__set_duration), 1228 trace__set_duration),
654 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"), 1229 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
1230 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
655 OPT_END() 1231 OPT_END()
656 }; 1232 };
657 int err; 1233 int err;
@@ -659,27 +1235,57 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
659 1235
660 argc = parse_options(argc, argv, trace_options, trace_usage, 0); 1236 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
661 1237
1238 if (output_name != NULL) {
1239 err = trace__open_output(&trace, output_name);
1240 if (err < 0) {
1241 perror("failed to create output file");
1242 goto out;
1243 }
1244 }
1245
1246 if (ev_qualifier_str != NULL) {
1247 const char *s = ev_qualifier_str;
1248
1249 trace.not_ev_qualifier = *s == '!';
1250 if (trace.not_ev_qualifier)
1251 ++s;
1252 trace.ev_qualifier = strlist__new(true, s);
1253 if (trace.ev_qualifier == NULL) {
1254 fputs("Not enough memory to parse event qualifier",
1255 trace.output);
1256 err = -ENOMEM;
1257 goto out_close;
1258 }
1259 }
1260
662 err = perf_target__validate(&trace.opts.target); 1261 err = perf_target__validate(&trace.opts.target);
663 if (err) { 1262 if (err) {
664 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf)); 1263 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
665 printf("%s", bf); 1264 fprintf(trace.output, "%s", bf);
666 return err; 1265 goto out_close;
667 } 1266 }
668 1267
669 err = perf_target__parse_uid(&trace.opts.target); 1268 err = perf_target__parse_uid(&trace.opts.target);
670 if (err) { 1269 if (err) {
671 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf)); 1270 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
672 printf("%s", bf); 1271 fprintf(trace.output, "%s", bf);
673 return err; 1272 goto out_close;
674 } 1273 }
675 1274
676 if (!argc && perf_target__none(&trace.opts.target)) 1275 if (!argc && perf_target__none(&trace.opts.target))
677 trace.opts.target.system_wide = true; 1276 trace.opts.target.system_wide = true;
678 1277
679 err = trace__run(&trace, argc, argv); 1278 if (input_name)
1279 err = trace__replay(&trace);
1280 else
1281 err = trace__run(&trace, argc, argv);
680 1282
681 if (trace.sched && !err) 1283 if (trace.sched && !err)
682 trace__fprintf_thread_summary(&trace, stdout); 1284 trace__fprintf_thread_summary(&trace, trace.output);
683 1285
1286out_close:
1287 if (output_name != NULL)
1288 fclose(trace.output);
1289out:
684 return err; 1290 return err;
685} 1291}
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index b5d9238cb181..5f6f9b3271bb 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -46,6 +46,8 @@ ifneq ($(obj-perf),)
46obj-perf := $(abspath $(obj-perf))/ 46obj-perf := $(abspath $(obj-perf))/
47endif 47endif
48 48
49LIB_INCLUDE := $(srctree)/tools/lib/
50
49# include ARCH specific config 51# include ARCH specific config
50-include $(src-perf)/arch/$(ARCH)/Makefile 52-include $(src-perf)/arch/$(ARCH)/Makefile
51 53
@@ -85,7 +87,7 @@ CFLAGS += -Wall
85CFLAGS += -Wextra 87CFLAGS += -Wextra
86CFLAGS += -std=gnu99 88CFLAGS += -std=gnu99
87 89
88EXTLIBS = -lelf -lpthread -lrt -lm 90EXTLIBS = -lelf -lpthread -lrt -lm -ldl
89 91
90ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -fstack-protector-all,-fstack-protector-all),y) 92ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -fstack-protector-all,-fstack-protector-all),y)
91 CFLAGS += -fstack-protector-all 93 CFLAGS += -fstack-protector-all
@@ -121,8 +123,7 @@ endif
121 123
122CFLAGS += -I$(src-perf)/util 124CFLAGS += -I$(src-perf)/util
123CFLAGS += -I$(src-perf) 125CFLAGS += -I$(src-perf)
124CFLAGS += -I$(TRACE_EVENT_DIR) 126CFLAGS += -I$(LIB_INCLUDE)
125CFLAGS += -I$(srctree)/tools/lib/
126 127
127CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE 128CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
128 129
@@ -179,6 +180,9 @@ FLAGS_LIBELF=$(CFLAGS) $(LDFLAGS) $(EXTLIBS)
179ifeq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_LIBELF),-DLIBELF_MMAP),y) 180ifeq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_LIBELF),-DLIBELF_MMAP),y)
180 CFLAGS += -DLIBELF_MMAP 181 CFLAGS += -DLIBELF_MMAP
181endif 182endif
183ifeq ($(call try-cc,$(SOURCE_ELF_GETPHDRNUM),$(FLAGS_LIBELF),-DHAVE_ELF_GETPHDRNUM),y)
184 CFLAGS += -DHAVE_ELF_GETPHDRNUM
185endif
182 186
183# include ARCH specific config 187# include ARCH specific config
184-include $(src-perf)/arch/$(ARCH)/Makefile 188-include $(src-perf)/arch/$(ARCH)/Makefile
diff --git a/tools/perf/config/feature-tests.mak b/tools/perf/config/feature-tests.mak
index 708fb8e9822a..d5a8dd44945f 100644
--- a/tools/perf/config/feature-tests.mak
+++ b/tools/perf/config/feature-tests.mak
@@ -61,6 +61,15 @@ int main(void)
61} 61}
62endef 62endef
63 63
64define SOURCE_ELF_GETPHDRNUM
65#include <libelf.h>
66int main(void)
67{
68 size_t dst;
69 return elf_getphdrnum(0, &dst);
70}
71endef
72
64ifndef NO_SLANG 73ifndef NO_SLANG
65define SOURCE_SLANG 74define SOURCE_SLANG
66#include <slang.h> 75#include <slang.h>
@@ -210,6 +219,7 @@ define SOURCE_LIBAUDIT
210 219
211int main(void) 220int main(void)
212{ 221{
222 printf(\"error message: %s\n\", audit_errno_to_name(0));
213 return audit_open(); 223 return audit_open();
214} 224}
215endef 225endef
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 32bd102c32b6..cf20187eee0a 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -125,6 +125,9 @@
125#ifndef NSEC_PER_SEC 125#ifndef NSEC_PER_SEC
126# define NSEC_PER_SEC 1000000000ULL 126# define NSEC_PER_SEC 1000000000ULL
127#endif 127#endif
128#ifndef NSEC_PER_USEC
129# define NSEC_PER_USEC 1000ULL
130#endif
128 131
129static inline unsigned long long rdclock(void) 132static inline unsigned long long rdclock(void)
130{ 133{
diff --git a/tools/perf/python/twatch.py b/tools/perf/python/twatch.py
index b11cca584238..2225162ee1fc 100755
--- a/tools/perf/python/twatch.py
+++ b/tools/perf/python/twatch.py
@@ -21,7 +21,7 @@ def main():
21 evsel = perf.evsel(task = 1, comm = 1, mmap = 0, 21 evsel = perf.evsel(task = 1, comm = 1, mmap = 0,
22 wakeup_events = 1, watermark = 1, 22 wakeup_events = 1, watermark = 1,
23 sample_id_all = 1, 23 sample_id_all = 1,
24 sample_type = perf.SAMPLE_PERIOD | perf.SAMPLE_TID | perf.SAMPLE_CPU | perf.SAMPLE_TID) 24 sample_type = perf.SAMPLE_PERIOD | perf.SAMPLE_TID | perf.SAMPLE_CPU)
25 evsel.open(cpus = cpus, threads = threads); 25 evsel.open(cpus = cpus, threads = threads);
26 evlist = perf.evlist(cpus, threads) 26 evlist = perf.evlist(cpus, threads)
27 evlist.add(evsel) 27 evlist.add(evsel)
diff --git a/tools/perf/tests/attr/test-record-group-sampling b/tools/perf/tests/attr/test-record-group-sampling
new file mode 100644
index 000000000000..658f5d60c873
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-group-sampling
@@ -0,0 +1,36 @@
1[config]
2command = record
3args = -e '{cycles,cache-misses}:S' kill >/dev/null 2>&1
4
5[event-1:base-record]
6fd=1
7group_fd=-1
8sample_type=343
9read_format=12
10inherit=0
11
12[event-2:base-record]
13fd=2
14group_fd=1
15
16# cache-misses
17type=0
18config=3
19
20# default | PERF_SAMPLE_READ
21sample_type=343
22
23# PERF_FORMAT_ID | PERF_FORMAT_GROUP
24read_format=12
25
26mmap=0
27comm=0
28enable_on_exec=0
29disabled=0
30
31# inherit is disabled for group sampling
32inherit=0
33
34# sampling disabled
35sample_freq=0
36sample_period=0
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index 35b45f1466b5..1e67437fb4ca 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -93,6 +93,28 @@ static struct test {
93 .desc = "Test software clock events have valid period values", 93 .desc = "Test software clock events have valid period values",
94 .func = test__sw_clock_freq, 94 .func = test__sw_clock_freq,
95 }, 95 },
96#if defined(__x86_64__) || defined(__i386__)
97 {
98 .desc = "Test converting perf time to TSC",
99 .func = test__perf_time_to_tsc,
100 },
101#endif
102 {
103 .desc = "Test object code reading",
104 .func = test__code_reading,
105 },
106 {
107 .desc = "Test sample parsing",
108 .func = test__sample_parsing,
109 },
110 {
111 .desc = "Test using a dummy software event to keep tracking",
112 .func = test__keep_tracking,
113 },
114 {
115 .desc = "Test parsing with no sample_id_all bit set",
116 .func = test__parse_no_sample_id_all,
117 },
96 { 118 {
97 .func = NULL, 119 .func = NULL,
98 }, 120 },
diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c
new file mode 100644
index 000000000000..6fb781d5586c
--- /dev/null
+++ b/tools/perf/tests/code-reading.c
@@ -0,0 +1,572 @@
1#include <sys/types.h>
2#include <stdlib.h>
3#include <unistd.h>
4#include <stdio.h>
5#include <inttypes.h>
6#include <ctype.h>
7#include <string.h>
8
9#include "parse-events.h"
10#include "evlist.h"
11#include "evsel.h"
12#include "thread_map.h"
13#include "cpumap.h"
14#include "machine.h"
15#include "event.h"
16#include "thread.h"
17
18#include "tests.h"
19
20#define BUFSZ 1024
21#define READLEN 128
22
23struct state {
24 u64 done[1024];
25 size_t done_cnt;
26};
27
28static unsigned int hex(char c)
29{
30 if (c >= '0' && c <= '9')
31 return c - '0';
32 if (c >= 'a' && c <= 'f')
33 return c - 'a' + 10;
34 return c - 'A' + 10;
35}
36
37static void read_objdump_line(const char *line, size_t line_len, void **buf,
38 size_t *len)
39{
40 const char *p;
41 size_t i;
42
43 /* Skip to a colon */
44 p = strchr(line, ':');
45 if (!p)
46 return;
47 i = p + 1 - line;
48
49 /* Read bytes */
50 while (*len) {
51 char c1, c2;
52
53 /* Skip spaces */
54 for (; i < line_len; i++) {
55 if (!isspace(line[i]))
56 break;
57 }
58 /* Get 2 hex digits */
59 if (i >= line_len || !isxdigit(line[i]))
60 break;
61 c1 = line[i++];
62 if (i >= line_len || !isxdigit(line[i]))
63 break;
64 c2 = line[i++];
65 /* Followed by a space */
66 if (i < line_len && line[i] && !isspace(line[i]))
67 break;
68 /* Store byte */
69 *(unsigned char *)*buf = (hex(c1) << 4) | hex(c2);
70 *buf += 1;
71 *len -= 1;
72 }
73}
74
75static int read_objdump_output(FILE *f, void **buf, size_t *len)
76{
77 char *line = NULL;
78 size_t line_len;
79 ssize_t ret;
80 int err = 0;
81
82 while (1) {
83 ret = getline(&line, &line_len, f);
84 if (feof(f))
85 break;
86 if (ret < 0) {
87 pr_debug("getline failed\n");
88 err = -1;
89 break;
90 }
91 read_objdump_line(line, ret, buf, len);
92 }
93
94 free(line);
95
96 return err;
97}
98
99static int read_via_objdump(const char *filename, u64 addr, void *buf,
100 size_t len)
101{
102 char cmd[PATH_MAX * 2];
103 const char *fmt;
104 FILE *f;
105 int ret;
106
107 fmt = "%s -d --start-address=0x%"PRIx64" --stop-address=0x%"PRIx64" %s";
108 ret = snprintf(cmd, sizeof(cmd), fmt, "objdump", addr, addr + len,
109 filename);
110 if (ret <= 0 || (size_t)ret >= sizeof(cmd))
111 return -1;
112
113 pr_debug("Objdump command is: %s\n", cmd);
114
115 /* Ignore objdump errors */
116 strcat(cmd, " 2>/dev/null");
117
118 f = popen(cmd, "r");
119 if (!f) {
120 pr_debug("popen failed\n");
121 return -1;
122 }
123
124 ret = read_objdump_output(f, &buf, &len);
125 if (len) {
126 pr_debug("objdump read too few bytes\n");
127 if (!ret)
128 ret = len;
129 }
130
131 pclose(f);
132
133 return ret;
134}
135
136static int read_object_code(u64 addr, size_t len, u8 cpumode,
137 struct thread *thread, struct machine *machine,
138 struct state *state)
139{
140 struct addr_location al;
141 unsigned char buf1[BUFSZ];
142 unsigned char buf2[BUFSZ];
143 size_t ret_len;
144 u64 objdump_addr;
145 int ret;
146
147 pr_debug("Reading object code for memory address: %#"PRIx64"\n", addr);
148
149 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, addr,
150 &al);
151 if (!al.map || !al.map->dso) {
152 pr_debug("thread__find_addr_map failed\n");
153 return -1;
154 }
155
156 pr_debug("File is: %s\n", al.map->dso->long_name);
157
158 if (al.map->dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS &&
159 !dso__is_kcore(al.map->dso)) {
160 pr_debug("Unexpected kernel address - skipping\n");
161 return 0;
162 }
163
164 pr_debug("On file address is: %#"PRIx64"\n", al.addr);
165
166 if (len > BUFSZ)
167 len = BUFSZ;
168
169 /* Do not go off the map */
170 if (addr + len > al.map->end)
171 len = al.map->end - addr;
172
173 /* Read the object code using perf */
174 ret_len = dso__data_read_offset(al.map->dso, machine, al.addr, buf1,
175 len);
176 if (ret_len != len) {
177 pr_debug("dso__data_read_offset failed\n");
178 return -1;
179 }
180
181 /*
182 * Converting addresses for use by objdump requires more information.
183 * map__load() does that. See map__rip_2objdump() for details.
184 */
185 if (map__load(al.map, NULL))
186 return -1;
187
188 /* objdump struggles with kcore - try each map only once */
189 if (dso__is_kcore(al.map->dso)) {
190 size_t d;
191
192 for (d = 0; d < state->done_cnt; d++) {
193 if (state->done[d] == al.map->start) {
194 pr_debug("kcore map tested already");
195 pr_debug(" - skipping\n");
196 return 0;
197 }
198 }
199 if (state->done_cnt >= ARRAY_SIZE(state->done)) {
200 pr_debug("Too many kcore maps - skipping\n");
201 return 0;
202 }
203 state->done[state->done_cnt++] = al.map->start;
204 }
205
206 /* Read the object code using objdump */
207 objdump_addr = map__rip_2objdump(al.map, al.addr);
208 ret = read_via_objdump(al.map->dso->long_name, objdump_addr, buf2, len);
209 if (ret > 0) {
210 /*
211 * The kernel maps are inaccurate - assume objdump is right in
212 * that case.
213 */
214 if (cpumode == PERF_RECORD_MISC_KERNEL ||
215 cpumode == PERF_RECORD_MISC_GUEST_KERNEL) {
216 len -= ret;
217 if (len) {
218 pr_debug("Reducing len to %zu\n", len);
219 } else if (dso__is_kcore(al.map->dso)) {
220 /*
221 * objdump cannot handle very large segments
222 * that may be found in kcore.
223 */
224 pr_debug("objdump failed for kcore");
225 pr_debug(" - skipping\n");
226 return 0;
227 } else {
228 return -1;
229 }
230 }
231 }
232 if (ret < 0) {
233 pr_debug("read_via_objdump failed\n");
234 return -1;
235 }
236
237 /* The results should be identical */
238 if (memcmp(buf1, buf2, len)) {
239 pr_debug("Bytes read differ from those read by objdump\n");
240 return -1;
241 }
242 pr_debug("Bytes read match those read by objdump\n");
243
244 return 0;
245}
246
247static int process_sample_event(struct machine *machine,
248 struct perf_evlist *evlist,
249 union perf_event *event, struct state *state)
250{
251 struct perf_sample sample;
252 struct thread *thread;
253 u8 cpumode;
254
255 if (perf_evlist__parse_sample(evlist, event, &sample)) {
256 pr_debug("perf_evlist__parse_sample failed\n");
257 return -1;
258 }
259
260 thread = machine__findnew_thread(machine, sample.pid, sample.pid);
261 if (!thread) {
262 pr_debug("machine__findnew_thread failed\n");
263 return -1;
264 }
265
266 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
267
268 return read_object_code(sample.ip, READLEN, cpumode, thread, machine,
269 state);
270}
271
272static int process_event(struct machine *machine, struct perf_evlist *evlist,
273 union perf_event *event, struct state *state)
274{
275 if (event->header.type == PERF_RECORD_SAMPLE)
276 return process_sample_event(machine, evlist, event, state);
277
278 if (event->header.type < PERF_RECORD_MAX)
279 return machine__process_event(machine, event);
280
281 return 0;
282}
283
284static int process_events(struct machine *machine, struct perf_evlist *evlist,
285 struct state *state)
286{
287 union perf_event *event;
288 int i, ret;
289
290 for (i = 0; i < evlist->nr_mmaps; i++) {
291 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
292 ret = process_event(machine, evlist, event, state);
293 if (ret < 0)
294 return ret;
295 }
296 }
297 return 0;
298}
299
300static int comp(const void *a, const void *b)
301{
302 return *(int *)a - *(int *)b;
303}
304
305static void do_sort_something(void)
306{
307 int buf[40960], i;
308
309 for (i = 0; i < (int)ARRAY_SIZE(buf); i++)
310 buf[i] = ARRAY_SIZE(buf) - i - 1;
311
312 qsort(buf, ARRAY_SIZE(buf), sizeof(int), comp);
313
314 for (i = 0; i < (int)ARRAY_SIZE(buf); i++) {
315 if (buf[i] != i) {
316 pr_debug("qsort failed\n");
317 break;
318 }
319 }
320}
321
322static void sort_something(void)
323{
324 int i;
325
326 for (i = 0; i < 10; i++)
327 do_sort_something();
328}
329
330static void syscall_something(void)
331{
332 int pipefd[2];
333 int i;
334
335 for (i = 0; i < 1000; i++) {
336 if (pipe(pipefd) < 0) {
337 pr_debug("pipe failed\n");
338 break;
339 }
340 close(pipefd[1]);
341 close(pipefd[0]);
342 }
343}
344
345static void fs_something(void)
346{
347 const char *test_file_name = "temp-perf-code-reading-test-file--";
348 FILE *f;
349 int i;
350
351 for (i = 0; i < 1000; i++) {
352 f = fopen(test_file_name, "w+");
353 if (f) {
354 fclose(f);
355 unlink(test_file_name);
356 }
357 }
358}
359
360static void do_something(void)
361{
362 fs_something();
363
364 sort_something();
365
366 syscall_something();
367}
368
369enum {
370 TEST_CODE_READING_OK,
371 TEST_CODE_READING_NO_VMLINUX,
372 TEST_CODE_READING_NO_KCORE,
373 TEST_CODE_READING_NO_ACCESS,
374 TEST_CODE_READING_NO_KERNEL_OBJ,
375};
376
377static int do_test_code_reading(bool try_kcore)
378{
379 struct machines machines;
380 struct machine *machine;
381 struct thread *thread;
382 struct perf_record_opts opts = {
383 .mmap_pages = UINT_MAX,
384 .user_freq = UINT_MAX,
385 .user_interval = ULLONG_MAX,
386 .freq = 4000,
387 .target = {
388 .uses_mmap = true,
389 },
390 };
391 struct state state = {
392 .done_cnt = 0,
393 };
394 struct thread_map *threads = NULL;
395 struct cpu_map *cpus = NULL;
396 struct perf_evlist *evlist = NULL;
397 struct perf_evsel *evsel = NULL;
398 int err = -1, ret;
399 pid_t pid;
400 struct map *map;
401 bool have_vmlinux, have_kcore, excl_kernel = false;
402
403 pid = getpid();
404
405 machines__init(&machines);
406 machine = &machines.host;
407
408 ret = machine__create_kernel_maps(machine);
409 if (ret < 0) {
410 pr_debug("machine__create_kernel_maps failed\n");
411 goto out_err;
412 }
413
414 /* Force the use of kallsyms instead of vmlinux to try kcore */
415 if (try_kcore)
416 symbol_conf.kallsyms_name = "/proc/kallsyms";
417
418 /* Load kernel map */
419 map = machine->vmlinux_maps[MAP__FUNCTION];
420 ret = map__load(map, NULL);
421 if (ret < 0) {
422 pr_debug("map__load failed\n");
423 goto out_err;
424 }
425 have_vmlinux = dso__is_vmlinux(map->dso);
426 have_kcore = dso__is_kcore(map->dso);
427
428 /* 2nd time through we just try kcore */
429 if (try_kcore && !have_kcore)
430 return TEST_CODE_READING_NO_KCORE;
431
432 /* No point getting kernel events if there is no kernel object */
433 if (!have_vmlinux && !have_kcore)
434 excl_kernel = true;
435
436 threads = thread_map__new_by_tid(pid);
437 if (!threads) {
438 pr_debug("thread_map__new_by_tid failed\n");
439 goto out_err;
440 }
441
442 ret = perf_event__synthesize_thread_map(NULL, threads,
443 perf_event__process, machine);
444 if (ret < 0) {
445 pr_debug("perf_event__synthesize_thread_map failed\n");
446 goto out_err;
447 }
448
449 thread = machine__findnew_thread(machine, pid, pid);
450 if (!thread) {
451 pr_debug("machine__findnew_thread failed\n");
452 goto out_err;
453 }
454
455 cpus = cpu_map__new(NULL);
456 if (!cpus) {
457 pr_debug("cpu_map__new failed\n");
458 goto out_err;
459 }
460
461 while (1) {
462 const char *str;
463
464 evlist = perf_evlist__new();
465 if (!evlist) {
466 pr_debug("perf_evlist__new failed\n");
467 goto out_err;
468 }
469
470 perf_evlist__set_maps(evlist, cpus, threads);
471
472 if (excl_kernel)
473 str = "cycles:u";
474 else
475 str = "cycles";
476 pr_debug("Parsing event '%s'\n", str);
477 ret = parse_events(evlist, str);
478 if (ret < 0) {
479 pr_debug("parse_events failed\n");
480 goto out_err;
481 }
482
483 perf_evlist__config(evlist, &opts);
484
485 evsel = perf_evlist__first(evlist);
486
487 evsel->attr.comm = 1;
488 evsel->attr.disabled = 1;
489 evsel->attr.enable_on_exec = 0;
490
491 ret = perf_evlist__open(evlist);
492 if (ret < 0) {
493 if (!excl_kernel) {
494 excl_kernel = true;
495 perf_evlist__delete(evlist);
496 evlist = NULL;
497 continue;
498 }
499 pr_debug("perf_evlist__open failed\n");
500 goto out_err;
501 }
502 break;
503 }
504
505 ret = perf_evlist__mmap(evlist, UINT_MAX, false);
506 if (ret < 0) {
507 pr_debug("perf_evlist__mmap failed\n");
508 goto out_err;
509 }
510
511 perf_evlist__enable(evlist);
512
513 do_something();
514
515 perf_evlist__disable(evlist);
516
517 ret = process_events(machine, evlist, &state);
518 if (ret < 0)
519 goto out_err;
520
521 if (!have_vmlinux && !have_kcore && !try_kcore)
522 err = TEST_CODE_READING_NO_KERNEL_OBJ;
523 else if (!have_vmlinux && !try_kcore)
524 err = TEST_CODE_READING_NO_VMLINUX;
525 else if (excl_kernel)
526 err = TEST_CODE_READING_NO_ACCESS;
527 else
528 err = TEST_CODE_READING_OK;
529out_err:
530 if (evlist) {
531 perf_evlist__munmap(evlist);
532 perf_evlist__close(evlist);
533 perf_evlist__delete(evlist);
534 }
535 if (cpus)
536 cpu_map__delete(cpus);
537 if (threads)
538 thread_map__delete(threads);
539 machines__destroy_kernel_maps(&machines);
540 machine__delete_threads(machine);
541 machines__exit(&machines);
542
543 return err;
544}
545
546int test__code_reading(void)
547{
548 int ret;
549
550 ret = do_test_code_reading(false);
551 if (!ret)
552 ret = do_test_code_reading(true);
553
554 switch (ret) {
555 case TEST_CODE_READING_OK:
556 return 0;
557 case TEST_CODE_READING_NO_VMLINUX:
558 fprintf(stderr, " (no vmlinux)");
559 return 0;
560 case TEST_CODE_READING_NO_KCORE:
561 fprintf(stderr, " (no kcore)");
562 return 0;
563 case TEST_CODE_READING_NO_ACCESS:
564 fprintf(stderr, " (no access)");
565 return 0;
566 case TEST_CODE_READING_NO_KERNEL_OBJ:
567 fprintf(stderr, " (no kernel obj)");
568 return 0;
569 default:
570 return -1;
571 };
572}
diff --git a/tools/perf/tests/dso-data.c b/tools/perf/tests/dso-data.c
index 5eaffa2de9c5..dffe0551acaa 100644
--- a/tools/perf/tests/dso-data.c
+++ b/tools/perf/tests/dso-data.c
@@ -10,14 +10,6 @@
10#include "symbol.h" 10#include "symbol.h"
11#include "tests.h" 11#include "tests.h"
12 12
13#define TEST_ASSERT_VAL(text, cond) \
14do { \
15 if (!(cond)) { \
16 pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
17 return -1; \
18 } \
19} while (0)
20
21static char *test_file(int size) 13static char *test_file(int size)
22{ 14{
23 static char buf_templ[] = "/tmp/test-XXXXXX"; 15 static char buf_templ[] = "/tmp/test-XXXXXX";
diff --git a/tools/perf/tests/evsel-tp-sched.c b/tools/perf/tests/evsel-tp-sched.c
index a5d2fcc5ae35..9b98c1554833 100644
--- a/tools/perf/tests/evsel-tp-sched.c
+++ b/tools/perf/tests/evsel-tp-sched.c
@@ -1,6 +1,6 @@
1#include <traceevent/event-parse.h>
1#include "evsel.h" 2#include "evsel.h"
2#include "tests.h" 3#include "tests.h"
3#include "event-parse.h"
4 4
5static int perf_evsel__test_field(struct perf_evsel *evsel, const char *name, 5static int perf_evsel__test_field(struct perf_evsel *evsel, const char *name,
6 int size, bool should_be_signed) 6 int size, bool should_be_signed)
@@ -49,7 +49,7 @@ int test__perf_evsel__tp_sched_test(void)
49 if (perf_evsel__test_field(evsel, "prev_prio", 4, true)) 49 if (perf_evsel__test_field(evsel, "prev_prio", 4, true))
50 ret = -1; 50 ret = -1;
51 51
52 if (perf_evsel__test_field(evsel, "prev_state", 8, true)) 52 if (perf_evsel__test_field(evsel, "prev_state", sizeof(long), true))
53 ret = -1; 53 ret = -1;
54 54
55 if (perf_evsel__test_field(evsel, "next_comm", 16, true)) 55 if (perf_evsel__test_field(evsel, "next_comm", 16, true))
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c
index 89085a9615e2..4228ffc0d968 100644
--- a/tools/perf/tests/hists_link.c
+++ b/tools/perf/tests/hists_link.c
@@ -88,7 +88,8 @@ static struct machine *setup_fake_machine(struct machines *machines)
88 for (i = 0; i < ARRAY_SIZE(fake_threads); i++) { 88 for (i = 0; i < ARRAY_SIZE(fake_threads); i++) {
89 struct thread *thread; 89 struct thread *thread;
90 90
91 thread = machine__findnew_thread(machine, fake_threads[i].pid); 91 thread = machine__findnew_thread(machine, fake_threads[i].pid,
92 fake_threads[i].pid);
92 if (thread == NULL) 93 if (thread == NULL)
93 goto out; 94 goto out;
94 95
@@ -210,17 +211,15 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
210 list_for_each_entry(evsel, &evlist->entries, node) { 211 list_for_each_entry(evsel, &evlist->entries, node) {
211 for (k = 0; k < ARRAY_SIZE(fake_common_samples); k++) { 212 for (k = 0; k < ARRAY_SIZE(fake_common_samples); k++) {
212 const union perf_event event = { 213 const union perf_event event = {
213 .ip = { 214 .header = {
214 .header = { 215 .misc = PERF_RECORD_MISC_USER,
215 .misc = PERF_RECORD_MISC_USER,
216 },
217 .pid = fake_common_samples[k].pid,
218 .ip = fake_common_samples[k].ip,
219 }, 216 },
220 }; 217 };
221 218
219 sample.pid = fake_common_samples[k].pid;
220 sample.ip = fake_common_samples[k].ip;
222 if (perf_event__preprocess_sample(&event, machine, &al, 221 if (perf_event__preprocess_sample(&event, machine, &al,
223 &sample, 0) < 0) 222 &sample) < 0)
224 goto out; 223 goto out;
225 224
226 he = __hists__add_entry(&evsel->hists, &al, NULL, 1, 1); 225 he = __hists__add_entry(&evsel->hists, &al, NULL, 1, 1);
@@ -234,17 +233,15 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
234 233
235 for (k = 0; k < ARRAY_SIZE(fake_samples[i]); k++) { 234 for (k = 0; k < ARRAY_SIZE(fake_samples[i]); k++) {
236 const union perf_event event = { 235 const union perf_event event = {
237 .ip = { 236 .header = {
238 .header = { 237 .misc = PERF_RECORD_MISC_USER,
239 .misc = PERF_RECORD_MISC_USER,
240 },
241 .pid = fake_samples[i][k].pid,
242 .ip = fake_samples[i][k].ip,
243 }, 238 },
244 }; 239 };
245 240
241 sample.pid = fake_samples[i][k].pid;
242 sample.ip = fake_samples[i][k].ip;
246 if (perf_event__preprocess_sample(&event, machine, &al, 243 if (perf_event__preprocess_sample(&event, machine, &al,
247 &sample, 0) < 0) 244 &sample) < 0)
248 goto out; 245 goto out;
249 246
250 he = __hists__add_entry(&evsel->hists, &al, NULL, 1, 1); 247 he = __hists__add_entry(&evsel->hists, &al, NULL, 1, 1);
diff --git a/tools/perf/tests/keep-tracking.c b/tools/perf/tests/keep-tracking.c
new file mode 100644
index 000000000000..d444ea2c47d9
--- /dev/null
+++ b/tools/perf/tests/keep-tracking.c
@@ -0,0 +1,154 @@
1#include <sys/types.h>
2#include <unistd.h>
3#include <sys/prctl.h>
4
5#include "parse-events.h"
6#include "evlist.h"
7#include "evsel.h"
8#include "thread_map.h"
9#include "cpumap.h"
10#include "tests.h"
11
12#define CHECK__(x) { \
13 while ((x) < 0) { \
14 pr_debug(#x " failed!\n"); \
15 goto out_err; \
16 } \
17}
18
19#define CHECK_NOT_NULL__(x) { \
20 while ((x) == NULL) { \
21 pr_debug(#x " failed!\n"); \
22 goto out_err; \
23 } \
24}
25
26static int find_comm(struct perf_evlist *evlist, const char *comm)
27{
28 union perf_event *event;
29 int i, found;
30
31 found = 0;
32 for (i = 0; i < evlist->nr_mmaps; i++) {
33 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
34 if (event->header.type == PERF_RECORD_COMM &&
35 (pid_t)event->comm.pid == getpid() &&
36 (pid_t)event->comm.tid == getpid() &&
37 strcmp(event->comm.comm, comm) == 0)
38 found += 1;
39 }
40 }
41 return found;
42}
43
44/**
45 * test__keep_tracking - test using a dummy software event to keep tracking.
46 *
47 * This function implements a test that checks that tracking events continue
48 * when an event is disabled but a dummy software event is not disabled. If the
49 * test passes %0 is returned, otherwise %-1 is returned.
50 */
51int test__keep_tracking(void)
52{
53 struct perf_record_opts opts = {
54 .mmap_pages = UINT_MAX,
55 .user_freq = UINT_MAX,
56 .user_interval = ULLONG_MAX,
57 .freq = 4000,
58 .target = {
59 .uses_mmap = true,
60 },
61 };
62 struct thread_map *threads = NULL;
63 struct cpu_map *cpus = NULL;
64 struct perf_evlist *evlist = NULL;
65 struct perf_evsel *evsel = NULL;
66 int found, err = -1;
67 const char *comm;
68
69 threads = thread_map__new(-1, getpid(), UINT_MAX);
70 CHECK_NOT_NULL__(threads);
71
72 cpus = cpu_map__new(NULL);
73 CHECK_NOT_NULL__(cpus);
74
75 evlist = perf_evlist__new();
76 CHECK_NOT_NULL__(evlist);
77
78 perf_evlist__set_maps(evlist, cpus, threads);
79
80 CHECK__(parse_events(evlist, "dummy:u"));
81 CHECK__(parse_events(evlist, "cycles:u"));
82
83 perf_evlist__config(evlist, &opts);
84
85 evsel = perf_evlist__first(evlist);
86
87 evsel->attr.comm = 1;
88 evsel->attr.disabled = 1;
89 evsel->attr.enable_on_exec = 0;
90
91 if (perf_evlist__open(evlist) < 0) {
92 fprintf(stderr, " (not supported)");
93 err = 0;
94 goto out_err;
95 }
96
97 CHECK__(perf_evlist__mmap(evlist, UINT_MAX, false));
98
99 /*
100 * First, test that a 'comm' event can be found when the event is
101 * enabled.
102 */
103
104 perf_evlist__enable(evlist);
105
106 comm = "Test COMM 1";
107 CHECK__(prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0));
108
109 perf_evlist__disable(evlist);
110
111 found = find_comm(evlist, comm);
112 if (found != 1) {
113 pr_debug("First time, failed to find tracking event.\n");
114 goto out_err;
115 }
116
117 /*
118 * Secondly, test that a 'comm' event can be found when the event is
119 * disabled with the dummy event still enabled.
120 */
121
122 perf_evlist__enable(evlist);
123
124 evsel = perf_evlist__last(evlist);
125
126 CHECK__(perf_evlist__disable_event(evlist, evsel));
127
128 comm = "Test COMM 2";
129 CHECK__(prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0));
130
131 perf_evlist__disable(evlist);
132
133 found = find_comm(evlist, comm);
134 if (found != 1) {
135 pr_debug("Seconf time, failed to find tracking event.\n");
136 goto out_err;
137 }
138
139 err = 0;
140
141out_err:
142 if (evlist) {
143 perf_evlist__disable(evlist);
144 perf_evlist__munmap(evlist);
145 perf_evlist__close(evlist);
146 perf_evlist__delete(evlist);
147 }
148 if (cpus)
149 cpu_map__delete(cpus);
150 if (threads)
151 thread_map__delete(threads);
152
153 return err;
154}
diff --git a/tools/perf/tests/make b/tools/perf/tests/make
index c441a2875128..2ca0abf1b2b6 100644
--- a/tools/perf/tests/make
+++ b/tools/perf/tests/make
@@ -1,6 +1,8 @@
1PERF := . 1PERF := .
2MK := Makefile 2MK := Makefile
3 3
4has = $(shell which $1 2>/dev/null)
5
4# standard single make variable specified 6# standard single make variable specified
5make_clean_all := clean all 7make_clean_all := clean all
6make_python_perf_so := python/perf.so 8make_python_perf_so := python/perf.so
@@ -25,6 +27,13 @@ make_help := help
25make_doc := doc 27make_doc := doc
26make_perf_o := perf.o 28make_perf_o := perf.o
27make_util_map_o := util/map.o 29make_util_map_o := util/map.o
30make_install := install
31make_install_bin := install-bin
32make_install_doc := install-doc
33make_install_man := install-man
34make_install_html := install-html
35make_install_info := install-info
36make_install_pdf := install-pdf
28 37
29# all the NO_* variable combined 38# all the NO_* variable combined
30make_minimal := NO_LIBPERL=1 NO_LIBPYTHON=1 NO_NEWT=1 NO_GTK2=1 39make_minimal := NO_LIBPERL=1 NO_LIBPYTHON=1 NO_NEWT=1 NO_GTK2=1
@@ -50,14 +59,27 @@ run += make_no_backtrace
50run += make_no_libnuma 59run += make_no_libnuma
51run += make_no_libaudit 60run += make_no_libaudit
52run += make_no_libbionic 61run += make_no_libbionic
53run += make_tags
54run += make_cscope
55run += make_help 62run += make_help
56run += make_doc 63run += make_doc
57run += make_perf_o 64run += make_perf_o
58run += make_util_map_o 65run += make_util_map_o
66run += make_install
67run += make_install_bin
68# FIXME 'install-*' commented out till they're fixed
69# run += make_install_doc
70# run += make_install_man
71# run += make_install_html
72# run += make_install_info
73# run += make_install_pdf
59run += make_minimal 74run += make_minimal
60 75
76ifneq ($(call has,ctags),)
77run += make_tags
78endif
79ifneq ($(call has,cscope),)
80run += make_cscope
81endif
82
61# $(run_O) contains same portion of $(run) tests with '_O' attached 83# $(run_O) contains same portion of $(run) tests with '_O' attached
62# to distinguish O=... tests 84# to distinguish O=... tests
63run_O := $(addsuffix _O,$(run)) 85run_O := $(addsuffix _O,$(run))
@@ -84,6 +106,31 @@ test_make_python_perf_so := test -f $(PERF)/python/perf.so
84test_make_perf_o := test -f $(PERF)/perf.o 106test_make_perf_o := test -f $(PERF)/perf.o
85test_make_util_map_o := test -f $(PERF)/util/map.o 107test_make_util_map_o := test -f $(PERF)/util/map.o
86 108
109test_make_install := test -x $$TMP_DEST/bin/perf
110test_make_install_O := $(test_make_install)
111test_make_install_bin := $(test_make_install)
112test_make_install_bin_O := $(test_make_install)
113
114# FIXME nothing gets installed
115test_make_install_man := test -f $$TMP_DEST/share/man/man1/perf.1
116test_make_install_man_O := $(test_make_install_man)
117
118# FIXME nothing gets installed
119test_make_install_doc := $(test_ok)
120test_make_install_doc_O := $(test_ok)
121
122# FIXME nothing gets installed
123test_make_install_html := $(test_ok)
124test_make_install_html_O := $(test_ok)
125
126# FIXME nothing gets installed
127test_make_install_info := $(test_ok)
128test_make_install_info_O := $(test_ok)
129
130# FIXME nothing gets installed
131test_make_install_pdf := $(test_ok)
132test_make_install_pdf_O := $(test_ok)
133
87# Kbuild tests only 134# Kbuild tests only
88#test_make_python_perf_so_O := test -f $$TMP/tools/perf/python/perf.so 135#test_make_python_perf_so_O := test -f $$TMP/tools/perf/python/perf.so
89#test_make_perf_o_O := test -f $$TMP/tools/perf/perf.o 136#test_make_perf_o_O := test -f $$TMP/tools/perf/perf.o
@@ -95,7 +142,7 @@ test_make_util_map_o_O := true
95test_default = test -x $(PERF)/perf 142test_default = test -x $(PERF)/perf
96test = $(if $(test_$1),$(test_$1),$(test_default)) 143test = $(if $(test_$1),$(test_$1),$(test_default))
97 144
98test_default_O = test -x $$TMP/perf 145test_default_O = test -x $$TMP_O/perf
99test_O = $(if $(test_$1),$(test_$1),$(test_default_O)) 146test_O = $(if $(test_$1),$(test_$1),$(test_default_O))
100 147
101all: 148all:
@@ -111,23 +158,27 @@ clean := @(cd $(PERF); make -s -f $(MK) clean >/dev/null)
111 158
112$(run): 159$(run):
113 $(call clean) 160 $(call clean)
114 @cmd="cd $(PERF) && make -f $(MK) $($@)"; \ 161 @TMP_DEST=$$(mktemp -d); \
162 cmd="cd $(PERF) && make -f $(MK) DESTDIR=$$TMP_DEST $($@)"; \
115 echo "- $@: $$cmd" && echo $$cmd > $@ && \ 163 echo "- $@: $$cmd" && echo $$cmd > $@ && \
116 ( eval $$cmd ) >> $@ 2>&1; \ 164 ( eval $$cmd ) >> $@ 2>&1; \
117 echo " test: $(call test,$@)"; \ 165 echo " test: $(call test,$@)"; \
118 $(call test,$@) && \ 166 $(call test,$@) && \
119 rm -f $@ 167 rm -f $@ \
168 rm -rf $$TMP_DEST
120 169
121$(run_O): 170$(run_O):
122 $(call clean) 171 $(call clean)
123 @TMP=$$(mktemp -d); \ 172 @TMP_O=$$(mktemp -d); \
124 cmd="cd $(PERF) && make -f $(MK) $($(patsubst %_O,%,$@)) O=$$TMP"; \ 173 TMP_DEST=$$(mktemp -d); \
174 cmd="cd $(PERF) && make -f $(MK) O=$$TMP_O DESTDIR=$$TMP_DEST $($(patsubst %_O,%,$@))"; \
125 echo "- $@: $$cmd" && echo $$cmd > $@ && \ 175 echo "- $@: $$cmd" && echo $$cmd > $@ && \
126 ( eval $$cmd ) >> $@ 2>&1 && \ 176 ( eval $$cmd ) >> $@ 2>&1 && \
127 echo " test: $(call test_O,$@)"; \ 177 echo " test: $(call test_O,$@)"; \
128 $(call test_O,$@) && \ 178 $(call test_O,$@) && \
129 rm -f $@ && \ 179 rm -f $@ && \
130 rm -rf $$TMP 180 rm -rf $$TMP_O \
181 rm -rf $$TMP_DEST
131 182
132all: $(run) $(run_O) 183all: $(run) $(run_O)
133 @echo OK 184 @echo OK
diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c
index 5b1b5aba722b..c4185b9aeb80 100644
--- a/tools/perf/tests/mmap-basic.c
+++ b/tools/perf/tests/mmap-basic.c
@@ -72,7 +72,7 @@ int test__basic_mmap(void)
72 } 72 }
73 73
74 evsels[i]->attr.wakeup_events = 1; 74 evsels[i]->attr.wakeup_events = 1;
75 perf_evsel__set_sample_id(evsels[i]); 75 perf_evsel__set_sample_id(evsels[i], false);
76 76
77 perf_evlist__add(evlist, evsels[i]); 77 perf_evlist__add(evlist, evsels[i]);
78 78
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
index 0275bab4ea9e..48114d164e9f 100644
--- a/tools/perf/tests/parse-events.c
+++ b/tools/perf/tests/parse-events.c
@@ -7,14 +7,6 @@
7#include "tests.h" 7#include "tests.h"
8#include <linux/hw_breakpoint.h> 8#include <linux/hw_breakpoint.h>
9 9
10#define TEST_ASSERT_VAL(text, cond) \
11do { \
12 if (!(cond)) { \
13 pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
14 return -1; \
15 } \
16} while (0)
17
18#define PERF_TP_SAMPLE_TYPE (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | \ 10#define PERF_TP_SAMPLE_TYPE (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | \
19 PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD) 11 PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD)
20 12
@@ -460,6 +452,7 @@ static int test__checkevent_pmu_events(struct perf_evlist *evlist)
460 evsel->attr.exclude_kernel); 452 evsel->attr.exclude_kernel);
461 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); 453 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
462 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 454 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
455 TEST_ASSERT_VAL("wrong pinned", !evsel->attr.pinned);
463 456
464 return 0; 457 return 0;
465} 458}
@@ -528,6 +521,7 @@ static int test__group1(struct perf_evlist *evlist)
528 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); 521 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
529 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2); 522 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
530 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0); 523 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
524 TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
531 525
532 /* cycles:upp */ 526 /* cycles:upp */
533 evsel = perf_evsel__next(evsel); 527 evsel = perf_evsel__next(evsel);
@@ -543,6 +537,7 @@ static int test__group1(struct perf_evlist *evlist)
543 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2); 537 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2);
544 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); 538 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
545 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1); 539 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
540 TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
546 541
547 return 0; 542 return 0;
548} 543}
@@ -568,6 +563,7 @@ static int test__group2(struct perf_evlist *evlist)
568 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); 563 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
569 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2); 564 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
570 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0); 565 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
566 TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
571 567
572 /* cache-references + :u modifier */ 568 /* cache-references + :u modifier */
573 evsel = perf_evsel__next(evsel); 569 evsel = perf_evsel__next(evsel);
@@ -582,6 +578,7 @@ static int test__group2(struct perf_evlist *evlist)
582 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 578 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
583 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); 579 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
584 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1); 580 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
581 TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
585 582
586 /* cycles:k */ 583 /* cycles:k */
587 evsel = perf_evsel__next(evsel); 584 evsel = perf_evsel__next(evsel);
@@ -595,6 +592,7 @@ static int test__group2(struct perf_evlist *evlist)
595 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); 592 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
596 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 593 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
597 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); 594 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
595 TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
598 596
599 return 0; 597 return 0;
600} 598}
@@ -623,6 +621,7 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused)
623 !strcmp(leader->group_name, "group1")); 621 !strcmp(leader->group_name, "group1"));
624 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2); 622 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
625 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0); 623 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
624 TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
626 625
627 /* group1 cycles:kppp */ 626 /* group1 cycles:kppp */
628 evsel = perf_evsel__next(evsel); 627 evsel = perf_evsel__next(evsel);
@@ -639,6 +638,7 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused)
639 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); 638 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
640 TEST_ASSERT_VAL("wrong group name", !evsel->group_name); 639 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
641 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1); 640 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
641 TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
642 642
643 /* group2 cycles + G modifier */ 643 /* group2 cycles + G modifier */
644 evsel = leader = perf_evsel__next(evsel); 644 evsel = leader = perf_evsel__next(evsel);
@@ -656,6 +656,7 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused)
656 !strcmp(leader->group_name, "group2")); 656 !strcmp(leader->group_name, "group2"));
657 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2); 657 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
658 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0); 658 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
659 TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
659 660
660 /* group2 1:3 + G modifier */ 661 /* group2 1:3 + G modifier */
661 evsel = perf_evsel__next(evsel); 662 evsel = perf_evsel__next(evsel);
@@ -669,6 +670,7 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused)
669 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 670 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
670 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); 671 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
671 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1); 672 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
673 TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
672 674
673 /* instructions:u */ 675 /* instructions:u */
674 evsel = perf_evsel__next(evsel); 676 evsel = perf_evsel__next(evsel);
@@ -682,6 +684,7 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused)
682 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); 684 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
683 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 685 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
684 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); 686 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
687 TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
685 688
686 return 0; 689 return 0;
687} 690}
@@ -709,6 +712,7 @@ static int test__group4(struct perf_evlist *evlist __maybe_unused)
709 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); 712 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
710 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2); 713 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
711 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0); 714 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
715 TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
712 716
713 /* instructions:kp + p */ 717 /* instructions:kp + p */
714 evsel = perf_evsel__next(evsel); 718 evsel = perf_evsel__next(evsel);
@@ -724,6 +728,7 @@ static int test__group4(struct perf_evlist *evlist __maybe_unused)
724 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2); 728 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2);
725 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); 729 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
726 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1); 730 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
731 TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
727 732
728 return 0; 733 return 0;
729} 734}
@@ -750,6 +755,7 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused)
750 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); 755 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
751 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2); 756 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
752 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0); 757 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
758 TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
753 759
754 /* instructions + G */ 760 /* instructions + G */
755 evsel = perf_evsel__next(evsel); 761 evsel = perf_evsel__next(evsel);
@@ -764,6 +770,7 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused)
764 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 770 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
765 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); 771 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
766 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1); 772 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
773 TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
767 774
768 /* cycles:G */ 775 /* cycles:G */
769 evsel = leader = perf_evsel__next(evsel); 776 evsel = leader = perf_evsel__next(evsel);
@@ -780,6 +787,7 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused)
780 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); 787 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
781 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2); 788 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
782 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0); 789 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
790 TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
783 791
784 /* instructions:G */ 792 /* instructions:G */
785 evsel = perf_evsel__next(evsel); 793 evsel = perf_evsel__next(evsel);
@@ -971,6 +979,142 @@ static int test__group_gh4(struct perf_evlist *evlist)
971 return 0; 979 return 0;
972} 980}
973 981
982static int test__leader_sample1(struct perf_evlist *evlist)
983{
984 struct perf_evsel *evsel, *leader;
985
986 TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries);
987
988 /* cycles - sampling group leader */
989 evsel = leader = perf_evlist__first(evlist);
990 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
991 TEST_ASSERT_VAL("wrong config",
992 PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
993 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
994 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
995 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
996 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
997 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
998 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
999 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
1000 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
1001 TEST_ASSERT_VAL("wrong sample_read", evsel->sample_read);
1002
1003 /* cache-misses - not sampling */
1004 evsel = perf_evsel__next(evsel);
1005 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
1006 TEST_ASSERT_VAL("wrong config",
1007 PERF_COUNT_HW_CACHE_MISSES == evsel->attr.config);
1008 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
1009 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
1010 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
1011 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
1012 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
1013 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
1014 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
1015 TEST_ASSERT_VAL("wrong sample_read", evsel->sample_read);
1016
1017 /* branch-misses - not sampling */
1018 evsel = perf_evsel__next(evsel);
1019 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
1020 TEST_ASSERT_VAL("wrong config",
1021 PERF_COUNT_HW_BRANCH_MISSES == evsel->attr.config);
1022 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
1023 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
1024 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
1025 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
1026 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
1027 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
1028 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
1029 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
1030 TEST_ASSERT_VAL("wrong sample_read", evsel->sample_read);
1031
1032 return 0;
1033}
1034
1035static int test__leader_sample2(struct perf_evlist *evlist __maybe_unused)
1036{
1037 struct perf_evsel *evsel, *leader;
1038
1039 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
1040
1041 /* instructions - sampling group leader */
1042 evsel = leader = perf_evlist__first(evlist);
1043 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
1044 TEST_ASSERT_VAL("wrong config",
1045 PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config);
1046 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
1047 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
1048 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
1049 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
1050 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
1051 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
1052 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
1053 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
1054 TEST_ASSERT_VAL("wrong sample_read", evsel->sample_read);
1055
1056 /* branch-misses - not sampling */
1057 evsel = perf_evsel__next(evsel);
1058 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
1059 TEST_ASSERT_VAL("wrong config",
1060 PERF_COUNT_HW_BRANCH_MISSES == evsel->attr.config);
1061 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
1062 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
1063 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
1064 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
1065 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
1066 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
1067 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
1068 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
1069 TEST_ASSERT_VAL("wrong sample_read", evsel->sample_read);
1070
1071 return 0;
1072}
1073
1074static int test__checkevent_pinned_modifier(struct perf_evlist *evlist)
1075{
1076 struct perf_evsel *evsel = perf_evlist__first(evlist);
1077
1078 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
1079 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
1080 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
1081 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
1082 TEST_ASSERT_VAL("wrong pinned", evsel->attr.pinned);
1083
1084 return test__checkevent_symbolic_name(evlist);
1085}
1086
1087static int test__pinned_group(struct perf_evlist *evlist)
1088{
1089 struct perf_evsel *evsel, *leader;
1090
1091 TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries);
1092
1093 /* cycles - group leader */
1094 evsel = leader = perf_evlist__first(evlist);
1095 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
1096 TEST_ASSERT_VAL("wrong config",
1097 PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
1098 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
1099 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
1100 TEST_ASSERT_VAL("wrong pinned", evsel->attr.pinned);
1101
1102 /* cache-misses - can not be pinned, but will go on with the leader */
1103 evsel = perf_evsel__next(evsel);
1104 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
1105 TEST_ASSERT_VAL("wrong config",
1106 PERF_COUNT_HW_CACHE_MISSES == evsel->attr.config);
1107 TEST_ASSERT_VAL("wrong pinned", !evsel->attr.pinned);
1108
1109 /* branch-misses - ditto */
1110 evsel = perf_evsel__next(evsel);
1111 TEST_ASSERT_VAL("wrong config",
1112 PERF_COUNT_HW_BRANCH_MISSES == evsel->attr.config);
1113 TEST_ASSERT_VAL("wrong pinned", !evsel->attr.pinned);
1114
1115 return 0;
1116}
1117
974static int count_tracepoints(void) 1118static int count_tracepoints(void)
975{ 1119{
976 char events_path[PATH_MAX]; 1120 char events_path[PATH_MAX];
@@ -1187,6 +1331,22 @@ static struct evlist_test test__events[] = {
1187 .name = "{cycles:G,cache-misses:H}:uG", 1331 .name = "{cycles:G,cache-misses:H}:uG",
1188 .check = test__group_gh4, 1332 .check = test__group_gh4,
1189 }, 1333 },
1334 [38] = {
1335 .name = "{cycles,cache-misses,branch-misses}:S",
1336 .check = test__leader_sample1,
1337 },
1338 [39] = {
1339 .name = "{instructions,branch-misses}:Su",
1340 .check = test__leader_sample2,
1341 },
1342 [40] = {
1343 .name = "instructions:uDp",
1344 .check = test__checkevent_pinned_modifier,
1345 },
1346 [41] = {
1347 .name = "{cycles,cache-misses,branch-misses}:D",
1348 .check = test__pinned_group,
1349 },
1190}; 1350};
1191 1351
1192static struct evlist_test test__events_pmu[] = { 1352static struct evlist_test test__events_pmu[] = {
@@ -1254,24 +1414,20 @@ static int test_events(struct evlist_test *events, unsigned cnt)
1254 1414
1255static int test_term(struct terms_test *t) 1415static int test_term(struct terms_test *t)
1256{ 1416{
1257 struct list_head *terms; 1417 struct list_head terms;
1258 int ret; 1418 int ret;
1259 1419
1260 terms = malloc(sizeof(*terms)); 1420 INIT_LIST_HEAD(&terms);
1261 if (!terms)
1262 return -ENOMEM;
1263
1264 INIT_LIST_HEAD(terms);
1265 1421
1266 ret = parse_events_terms(terms, t->str); 1422 ret = parse_events_terms(&terms, t->str);
1267 if (ret) { 1423 if (ret) {
1268 pr_debug("failed to parse terms '%s', err %d\n", 1424 pr_debug("failed to parse terms '%s', err %d\n",
1269 t->str , ret); 1425 t->str , ret);
1270 return ret; 1426 return ret;
1271 } 1427 }
1272 1428
1273 ret = t->check(terms); 1429 ret = t->check(&terms);
1274 parse_events__free_terms(terms); 1430 parse_events__free_terms(&terms);
1275 1431
1276 return ret; 1432 return ret;
1277} 1433}
diff --git a/tools/perf/tests/parse-no-sample-id-all.c b/tools/perf/tests/parse-no-sample-id-all.c
new file mode 100644
index 000000000000..e117b6c6a248
--- /dev/null
+++ b/tools/perf/tests/parse-no-sample-id-all.c
@@ -0,0 +1,108 @@
1#include <sys/types.h>
2#include <stddef.h>
3
4#include "tests.h"
5
6#include "event.h"
7#include "evlist.h"
8#include "header.h"
9#include "util.h"
10
11static int process_event(struct perf_evlist **pevlist, union perf_event *event)
12{
13 struct perf_sample sample;
14
15 if (event->header.type == PERF_RECORD_HEADER_ATTR) {
16 if (perf_event__process_attr(NULL, event, pevlist)) {
17 pr_debug("perf_event__process_attr failed\n");
18 return -1;
19 }
20 return 0;
21 }
22
23 if (event->header.type >= PERF_RECORD_USER_TYPE_START)
24 return -1;
25
26 if (!*pevlist)
27 return -1;
28
29 if (perf_evlist__parse_sample(*pevlist, event, &sample)) {
30 pr_debug("perf_evlist__parse_sample failed\n");
31 return -1;
32 }
33
34 return 0;
35}
36
37static int process_events(union perf_event **events, size_t count)
38{
39 struct perf_evlist *evlist = NULL;
40 int err = 0;
41 size_t i;
42
43 for (i = 0; i < count && !err; i++)
44 err = process_event(&evlist, events[i]);
45
46 if (evlist)
47 perf_evlist__delete(evlist);
48
49 return err;
50}
51
52struct test_attr_event {
53 struct attr_event attr;
54 u64 id;
55};
56
57/**
58 * test__parse_no_sample_id_all - test parsing with no sample_id_all bit set.
59 *
60 * This function tests parsing data produced on kernel's that do not support the
61 * sample_id_all bit. Without the sample_id_all bit, non-sample events (such as
62 * mmap events) do not have an id sample appended, and consequently logic
63 * designed to determine the id will not work. That case happens when there is
64 * more than one selected event, so this test processes three events: 2
65 * attributes representing the selected events and one mmap event.
66 *
67 * Return: %0 on success, %-1 if the test fails.
68 */
69int test__parse_no_sample_id_all(void)
70{
71 int err;
72
73 struct test_attr_event event1 = {
74 .attr = {
75 .header = {
76 .type = PERF_RECORD_HEADER_ATTR,
77 .size = sizeof(struct test_attr_event),
78 },
79 },
80 .id = 1,
81 };
82 struct test_attr_event event2 = {
83 .attr = {
84 .header = {
85 .type = PERF_RECORD_HEADER_ATTR,
86 .size = sizeof(struct test_attr_event),
87 },
88 },
89 .id = 2,
90 };
91 struct mmap_event event3 = {
92 .header = {
93 .type = PERF_RECORD_MMAP,
94 .size = sizeof(struct mmap_event),
95 },
96 };
97 union perf_event *events[] = {
98 (union perf_event *)&event1,
99 (union perf_event *)&event2,
100 (union perf_event *)&event3,
101 };
102
103 err = process_events(events, ARRAY_SIZE(events));
104 if (err)
105 return -1;
106
107 return 0;
108}
diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c
index 72d8881873b0..b8a7056519ac 100644
--- a/tools/perf/tests/perf-record.c
+++ b/tools/perf/tests/perf-record.c
@@ -50,7 +50,7 @@ int test__PERF_RECORD(void)
50 struct perf_sample sample; 50 struct perf_sample sample;
51 const char *cmd = "sleep"; 51 const char *cmd = "sleep";
52 const char *argv[] = { cmd, "1", NULL, }; 52 const char *argv[] = { cmd, "1", NULL, };
53 char *bname; 53 char *bname, *mmap_filename;
54 u64 prev_time = 0; 54 u64 prev_time = 0;
55 bool found_cmd_mmap = false, 55 bool found_cmd_mmap = false,
56 found_libc_mmap = false, 56 found_libc_mmap = false,
@@ -212,6 +212,7 @@ int test__PERF_RECORD(void)
212 212
213 if ((type == PERF_RECORD_COMM || 213 if ((type == PERF_RECORD_COMM ||
214 type == PERF_RECORD_MMAP || 214 type == PERF_RECORD_MMAP ||
215 type == PERF_RECORD_MMAP2 ||
215 type == PERF_RECORD_FORK || 216 type == PERF_RECORD_FORK ||
216 type == PERF_RECORD_EXIT) && 217 type == PERF_RECORD_EXIT) &&
217 (pid_t)event->comm.pid != evlist->workload.pid) { 218 (pid_t)event->comm.pid != evlist->workload.pid) {
@@ -220,7 +221,8 @@ int test__PERF_RECORD(void)
220 } 221 }
221 222
222 if ((type == PERF_RECORD_COMM || 223 if ((type == PERF_RECORD_COMM ||
223 type == PERF_RECORD_MMAP) && 224 type == PERF_RECORD_MMAP ||
225 type == PERF_RECORD_MMAP2) &&
224 event->comm.pid != event->comm.tid) { 226 event->comm.pid != event->comm.tid) {
225 pr_debug("%s with different pid/tid!\n", name); 227 pr_debug("%s with different pid/tid!\n", name);
226 ++errs; 228 ++errs;
@@ -236,7 +238,12 @@ int test__PERF_RECORD(void)
236 case PERF_RECORD_EXIT: 238 case PERF_RECORD_EXIT:
237 goto found_exit; 239 goto found_exit;
238 case PERF_RECORD_MMAP: 240 case PERF_RECORD_MMAP:
239 bname = strrchr(event->mmap.filename, '/'); 241 mmap_filename = event->mmap.filename;
242 goto check_bname;
243 case PERF_RECORD_MMAP2:
244 mmap_filename = event->mmap2.filename;
245 check_bname:
246 bname = strrchr(mmap_filename, '/');
240 if (bname != NULL) { 247 if (bname != NULL) {
241 if (!found_cmd_mmap) 248 if (!found_cmd_mmap)
242 found_cmd_mmap = !strcmp(bname + 1, cmd); 249 found_cmd_mmap = !strcmp(bname + 1, cmd);
@@ -245,7 +252,7 @@ int test__PERF_RECORD(void)
245 if (!found_ld_mmap) 252 if (!found_ld_mmap)
246 found_ld_mmap = !strncmp(bname + 1, "ld", 2); 253 found_ld_mmap = !strncmp(bname + 1, "ld", 2);
247 } else if (!found_vdso_mmap) 254 } else if (!found_vdso_mmap)
248 found_vdso_mmap = !strcmp(event->mmap.filename, "[vdso]"); 255 found_vdso_mmap = !strcmp(mmap_filename, "[vdso]");
249 break; 256 break;
250 257
251 case PERF_RECORD_SAMPLE: 258 case PERF_RECORD_SAMPLE:
diff --git a/tools/perf/tests/perf-time-to-tsc.c b/tools/perf/tests/perf-time-to-tsc.c
new file mode 100644
index 000000000000..0ab61b1f408e
--- /dev/null
+++ b/tools/perf/tests/perf-time-to-tsc.c
@@ -0,0 +1,177 @@
1#include <stdio.h>
2#include <sys/types.h>
3#include <unistd.h>
4#include <inttypes.h>
5#include <sys/prctl.h>
6
7#include "parse-events.h"
8#include "evlist.h"
9#include "evsel.h"
10#include "thread_map.h"
11#include "cpumap.h"
12#include "tests.h"
13
14#include "../arch/x86/util/tsc.h"
15
16#define CHECK__(x) { \
17 while ((x) < 0) { \
18 pr_debug(#x " failed!\n"); \
19 goto out_err; \
20 } \
21}
22
23#define CHECK_NOT_NULL__(x) { \
24 while ((x) == NULL) { \
25 pr_debug(#x " failed!\n"); \
26 goto out_err; \
27 } \
28}
29
30static u64 rdtsc(void)
31{
32 unsigned int low, high;
33
34 asm volatile("rdtsc" : "=a" (low), "=d" (high));
35
36 return low | ((u64)high) << 32;
37}
38
39/**
40 * test__perf_time_to_tsc - test converting perf time to TSC.
41 *
42 * This function implements a test that checks that the conversion of perf time
43 * to and from TSC is consistent with the order of events. If the test passes
44 * %0 is returned, otherwise %-1 is returned. If TSC conversion is not
45 * supported then then the test passes but " (not supported)" is printed.
46 */
47int test__perf_time_to_tsc(void)
48{
49 struct perf_record_opts opts = {
50 .mmap_pages = UINT_MAX,
51 .user_freq = UINT_MAX,
52 .user_interval = ULLONG_MAX,
53 .freq = 4000,
54 .target = {
55 .uses_mmap = true,
56 },
57 .sample_time = true,
58 };
59 struct thread_map *threads = NULL;
60 struct cpu_map *cpus = NULL;
61 struct perf_evlist *evlist = NULL;
62 struct perf_evsel *evsel = NULL;
63 int err = -1, ret, i;
64 const char *comm1, *comm2;
65 struct perf_tsc_conversion tc;
66 struct perf_event_mmap_page *pc;
67 union perf_event *event;
68 u64 test_tsc, comm1_tsc, comm2_tsc;
69 u64 test_time, comm1_time = 0, comm2_time = 0;
70
71 threads = thread_map__new(-1, getpid(), UINT_MAX);
72 CHECK_NOT_NULL__(threads);
73
74 cpus = cpu_map__new(NULL);
75 CHECK_NOT_NULL__(cpus);
76
77 evlist = perf_evlist__new();
78 CHECK_NOT_NULL__(evlist);
79
80 perf_evlist__set_maps(evlist, cpus, threads);
81
82 CHECK__(parse_events(evlist, "cycles:u"));
83
84 perf_evlist__config(evlist, &opts);
85
86 evsel = perf_evlist__first(evlist);
87
88 evsel->attr.comm = 1;
89 evsel->attr.disabled = 1;
90 evsel->attr.enable_on_exec = 0;
91
92 CHECK__(perf_evlist__open(evlist));
93
94 CHECK__(perf_evlist__mmap(evlist, UINT_MAX, false));
95
96 pc = evlist->mmap[0].base;
97 ret = perf_read_tsc_conversion(pc, &tc);
98 if (ret) {
99 if (ret == -EOPNOTSUPP) {
100 fprintf(stderr, " (not supported)");
101 return 0;
102 }
103 goto out_err;
104 }
105
106 perf_evlist__enable(evlist);
107
108 comm1 = "Test COMM 1";
109 CHECK__(prctl(PR_SET_NAME, (unsigned long)comm1, 0, 0, 0));
110
111 test_tsc = rdtsc();
112
113 comm2 = "Test COMM 2";
114 CHECK__(prctl(PR_SET_NAME, (unsigned long)comm2, 0, 0, 0));
115
116 perf_evlist__disable(evlist);
117
118 for (i = 0; i < evlist->nr_mmaps; i++) {
119 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
120 struct perf_sample sample;
121
122 if (event->header.type != PERF_RECORD_COMM ||
123 (pid_t)event->comm.pid != getpid() ||
124 (pid_t)event->comm.tid != getpid())
125 continue;
126
127 if (strcmp(event->comm.comm, comm1) == 0) {
128 CHECK__(perf_evsel__parse_sample(evsel, event,
129 &sample));
130 comm1_time = sample.time;
131 }
132 if (strcmp(event->comm.comm, comm2) == 0) {
133 CHECK__(perf_evsel__parse_sample(evsel, event,
134 &sample));
135 comm2_time = sample.time;
136 }
137 }
138 }
139
140 if (!comm1_time || !comm2_time)
141 goto out_err;
142
143 test_time = tsc_to_perf_time(test_tsc, &tc);
144 comm1_tsc = perf_time_to_tsc(comm1_time, &tc);
145 comm2_tsc = perf_time_to_tsc(comm2_time, &tc);
146
147 pr_debug("1st event perf time %"PRIu64" tsc %"PRIu64"\n",
148 comm1_time, comm1_tsc);
149 pr_debug("rdtsc time %"PRIu64" tsc %"PRIu64"\n",
150 test_time, test_tsc);
151 pr_debug("2nd event perf time %"PRIu64" tsc %"PRIu64"\n",
152 comm2_time, comm2_tsc);
153
154 if (test_time <= comm1_time ||
155 test_time >= comm2_time)
156 goto out_err;
157
158 if (test_tsc <= comm1_tsc ||
159 test_tsc >= comm2_tsc)
160 goto out_err;
161
162 err = 0;
163
164out_err:
165 if (evlist) {
166 perf_evlist__disable(evlist);
167 perf_evlist__munmap(evlist);
168 perf_evlist__close(evlist);
169 perf_evlist__delete(evlist);
170 }
171 if (cpus)
172 cpu_map__delete(cpus);
173 if (threads)
174 thread_map__delete(threads);
175
176 return err;
177}
diff --git a/tools/perf/tests/sample-parsing.c b/tools/perf/tests/sample-parsing.c
new file mode 100644
index 000000000000..77f598dbd97a
--- /dev/null
+++ b/tools/perf/tests/sample-parsing.c
@@ -0,0 +1,316 @@
1#include <stdbool.h>
2#include <inttypes.h>
3
4#include "util.h"
5#include "event.h"
6#include "evsel.h"
7
8#include "tests.h"
9
10#define COMP(m) do { \
11 if (s1->m != s2->m) { \
12 pr_debug("Samples differ at '"#m"'\n"); \
13 return false; \
14 } \
15} while (0)
16
17#define MCOMP(m) do { \
18 if (memcmp(&s1->m, &s2->m, sizeof(s1->m))) { \
19 pr_debug("Samples differ at '"#m"'\n"); \
20 return false; \
21 } \
22} while (0)
23
24static bool samples_same(const struct perf_sample *s1,
25 const struct perf_sample *s2, u64 type, u64 regs_user,
26 u64 read_format)
27{
28 size_t i;
29
30 if (type & PERF_SAMPLE_IDENTIFIER)
31 COMP(id);
32
33 if (type & PERF_SAMPLE_IP)
34 COMP(ip);
35
36 if (type & PERF_SAMPLE_TID) {
37 COMP(pid);
38 COMP(tid);
39 }
40
41 if (type & PERF_SAMPLE_TIME)
42 COMP(time);
43
44 if (type & PERF_SAMPLE_ADDR)
45 COMP(addr);
46
47 if (type & PERF_SAMPLE_ID)
48 COMP(id);
49
50 if (type & PERF_SAMPLE_STREAM_ID)
51 COMP(stream_id);
52
53 if (type & PERF_SAMPLE_CPU)
54 COMP(cpu);
55
56 if (type & PERF_SAMPLE_PERIOD)
57 COMP(period);
58
59 if (type & PERF_SAMPLE_READ) {
60 if (read_format & PERF_FORMAT_GROUP)
61 COMP(read.group.nr);
62 else
63 COMP(read.one.value);
64 if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
65 COMP(read.time_enabled);
66 if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
67 COMP(read.time_running);
68 /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */
69 if (read_format & PERF_FORMAT_GROUP) {
70 for (i = 0; i < s1->read.group.nr; i++)
71 MCOMP(read.group.values[i]);
72 } else {
73 COMP(read.one.id);
74 }
75 }
76
77 if (type & PERF_SAMPLE_CALLCHAIN) {
78 COMP(callchain->nr);
79 for (i = 0; i < s1->callchain->nr; i++)
80 COMP(callchain->ips[i]);
81 }
82
83 if (type & PERF_SAMPLE_RAW) {
84 COMP(raw_size);
85 if (memcmp(s1->raw_data, s2->raw_data, s1->raw_size)) {
86 pr_debug("Samples differ at 'raw_data'\n");
87 return false;
88 }
89 }
90
91 if (type & PERF_SAMPLE_BRANCH_STACK) {
92 COMP(branch_stack->nr);
93 for (i = 0; i < s1->branch_stack->nr; i++)
94 MCOMP(branch_stack->entries[i]);
95 }
96
97 if (type & PERF_SAMPLE_REGS_USER) {
98 size_t sz = hweight_long(regs_user) * sizeof(u64);
99
100 COMP(user_regs.abi);
101 if (s1->user_regs.abi &&
102 (!s1->user_regs.regs || !s2->user_regs.regs ||
103 memcmp(s1->user_regs.regs, s2->user_regs.regs, sz))) {
104 pr_debug("Samples differ at 'user_regs'\n");
105 return false;
106 }
107 }
108
109 if (type & PERF_SAMPLE_STACK_USER) {
110 COMP(user_stack.size);
111 if (memcmp(s1->user_stack.data, s1->user_stack.data,
112 s1->user_stack.size)) {
113 pr_debug("Samples differ at 'user_stack'\n");
114 return false;
115 }
116 }
117
118 if (type & PERF_SAMPLE_WEIGHT)
119 COMP(weight);
120
121 if (type & PERF_SAMPLE_DATA_SRC)
122 COMP(data_src);
123
124 return true;
125}
126
127static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format)
128{
129 struct perf_evsel evsel = {
130 .needs_swap = false,
131 .attr = {
132 .sample_type = sample_type,
133 .sample_regs_user = sample_regs_user,
134 .read_format = read_format,
135 },
136 };
137 union perf_event *event;
138 union {
139 struct ip_callchain callchain;
140 u64 data[64];
141 } callchain = {
142 /* 3 ips */
143 .data = {3, 201, 202, 203},
144 };
145 union {
146 struct branch_stack branch_stack;
147 u64 data[64];
148 } branch_stack = {
149 /* 1 branch_entry */
150 .data = {1, 211, 212, 213},
151 };
152 u64 user_regs[64];
153 const u64 raw_data[] = {0x123456780a0b0c0dULL, 0x1102030405060708ULL};
154 const u64 data[] = {0x2211443366558877ULL, 0, 0xaabbccddeeff4321ULL};
155 struct perf_sample sample = {
156 .ip = 101,
157 .pid = 102,
158 .tid = 103,
159 .time = 104,
160 .addr = 105,
161 .id = 106,
162 .stream_id = 107,
163 .period = 108,
164 .weight = 109,
165 .cpu = 110,
166 .raw_size = sizeof(raw_data),
167 .data_src = 111,
168 .raw_data = (void *)raw_data,
169 .callchain = &callchain.callchain,
170 .branch_stack = &branch_stack.branch_stack,
171 .user_regs = {
172 .abi = PERF_SAMPLE_REGS_ABI_64,
173 .regs = user_regs,
174 },
175 .user_stack = {
176 .size = sizeof(data),
177 .data = (void *)data,
178 },
179 .read = {
180 .time_enabled = 0x030a59d664fca7deULL,
181 .time_running = 0x011b6ae553eb98edULL,
182 },
183 };
184 struct sample_read_value values[] = {{1, 5}, {9, 3}, {2, 7}, {6, 4},};
185 struct perf_sample sample_out;
186 size_t i, sz, bufsz;
187 int err, ret = -1;
188
189 for (i = 0; i < sizeof(user_regs); i++)
190 *(i + (u8 *)user_regs) = i & 0xfe;
191
192 if (read_format & PERF_FORMAT_GROUP) {
193 sample.read.group.nr = 4;
194 sample.read.group.values = values;
195 } else {
196 sample.read.one.value = 0x08789faeb786aa87ULL;
197 sample.read.one.id = 99;
198 }
199
200 sz = perf_event__sample_event_size(&sample, sample_type,
201 sample_regs_user, read_format);
202 bufsz = sz + 4096; /* Add a bit for overrun checking */
203 event = malloc(bufsz);
204 if (!event) {
205 pr_debug("malloc failed\n");
206 return -1;
207 }
208
209 memset(event, 0xff, bufsz);
210 event->header.type = PERF_RECORD_SAMPLE;
211 event->header.misc = 0;
212 event->header.size = sz;
213
214 err = perf_event__synthesize_sample(event, sample_type,
215 sample_regs_user, read_format,
216 &sample, false);
217 if (err) {
218 pr_debug("%s failed for sample_type %#"PRIx64", error %d\n",
219 "perf_event__synthesize_sample", sample_type, err);
220 goto out_free;
221 }
222
223 /* The data does not contain 0xff so we use that to check the size */
224 for (i = bufsz; i > 0; i--) {
225 if (*(i - 1 + (u8 *)event) != 0xff)
226 break;
227 }
228 if (i != sz) {
229 pr_debug("Event size mismatch: actual %zu vs expected %zu\n",
230 i, sz);
231 goto out_free;
232 }
233
234 evsel.sample_size = __perf_evsel__sample_size(sample_type);
235
236 err = perf_evsel__parse_sample(&evsel, event, &sample_out);
237 if (err) {
238 pr_debug("%s failed for sample_type %#"PRIx64", error %d\n",
239 "perf_evsel__parse_sample", sample_type, err);
240 goto out_free;
241 }
242
243 if (!samples_same(&sample, &sample_out, sample_type,
244 sample_regs_user, read_format)) {
245 pr_debug("parsing failed for sample_type %#"PRIx64"\n",
246 sample_type);
247 goto out_free;
248 }
249
250 ret = 0;
251out_free:
252 free(event);
253 if (ret && read_format)
254 pr_debug("read_format %#"PRIx64"\n", read_format);
255 return ret;
256}
257
258/**
259 * test__sample_parsing - test sample parsing.
260 *
261 * This function implements a test that synthesizes a sample event, parses it
262 * and then checks that the parsed sample matches the original sample. The test
263 * checks sample format bits separately and together. If the test passes %0 is
264 * returned, otherwise %-1 is returned.
265 */
266int test__sample_parsing(void)
267{
268 const u64 rf[] = {4, 5, 6, 7, 12, 13, 14, 15};
269 u64 sample_type;
270 u64 sample_regs_user;
271 size_t i;
272 int err;
273
274 /*
275 * Fail the test if it has not been updated when new sample format bits
276 * were added.
277 */
278 if (PERF_SAMPLE_MAX > PERF_SAMPLE_IDENTIFIER << 1) {
279 pr_debug("sample format has changed - test needs updating\n");
280 return -1;
281 }
282
283 /* Test each sample format bit separately */
284 for (sample_type = 1; sample_type != PERF_SAMPLE_MAX;
285 sample_type <<= 1) {
286 /* Test read_format variations */
287 if (sample_type == PERF_SAMPLE_READ) {
288 for (i = 0; i < ARRAY_SIZE(rf); i++) {
289 err = do_test(sample_type, 0, rf[i]);
290 if (err)
291 return err;
292 }
293 continue;
294 }
295
296 if (sample_type == PERF_SAMPLE_REGS_USER)
297 sample_regs_user = 0x3fff;
298 else
299 sample_regs_user = 0;
300
301 err = do_test(sample_type, sample_regs_user, 0);
302 if (err)
303 return err;
304 }
305
306 /* Test all sample format bits together */
307 sample_type = PERF_SAMPLE_MAX - 1;
308 sample_regs_user = 0x3fff;
309 for (i = 0; i < ARRAY_SIZE(rf); i++) {
310 err = do_test(sample_type, sample_regs_user, rf[i]);
311 if (err)
312 return err;
313 }
314
315 return 0;
316}
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index dd7feae2d37b..e0ac713857ba 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -1,6 +1,14 @@
1#ifndef TESTS_H 1#ifndef TESTS_H
2#define TESTS_H 2#define TESTS_H
3 3
4#define TEST_ASSERT_VAL(text, cond) \
5do { \
6 if (!(cond)) { \
7 pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
8 return -1; \
9 } \
10} while (0)
11
4enum { 12enum {
5 TEST_OK = 0, 13 TEST_OK = 0,
6 TEST_FAIL = -1, 14 TEST_FAIL = -1,
@@ -27,5 +35,10 @@ int test__bp_signal(void);
27int test__bp_signal_overflow(void); 35int test__bp_signal_overflow(void);
28int test__task_exit(void); 36int test__task_exit(void);
29int test__sw_clock_freq(void); 37int test__sw_clock_freq(void);
38int test__perf_time_to_tsc(void);
39int test__code_reading(void);
40int test__sample_parsing(void);
41int test__keep_tracking(void);
42int test__parse_no_sample_id_all(void);
30 43
31#endif /* TESTS_H */ 44#endif /* TESTS_H */
diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c
index 7b4c4d26d1ba..2bd13edcbc17 100644
--- a/tools/perf/tests/vmlinux-kallsyms.c
+++ b/tools/perf/tests/vmlinux-kallsyms.c
@@ -16,6 +16,8 @@ static int vmlinux_matches_kallsyms_filter(struct map *map __maybe_unused,
16 return 0; 16 return 0;
17} 17}
18 18
19#define UM(x) kallsyms_map->unmap_ip(kallsyms_map, (x))
20
19int test__vmlinux_matches_kallsyms(void) 21int test__vmlinux_matches_kallsyms(void)
20{ 22{
21 int err = -1; 23 int err = -1;
@@ -25,6 +27,7 @@ int test__vmlinux_matches_kallsyms(void)
25 struct machine kallsyms, vmlinux; 27 struct machine kallsyms, vmlinux;
26 enum map_type type = MAP__FUNCTION; 28 enum map_type type = MAP__FUNCTION;
27 struct ref_reloc_sym ref_reloc_sym = { .name = "_stext", }; 29 struct ref_reloc_sym ref_reloc_sym = { .name = "_stext", };
30 u64 mem_start, mem_end;
28 31
29 /* 32 /*
30 * Step 1: 33 * Step 1:
@@ -73,7 +76,7 @@ int test__vmlinux_matches_kallsyms(void)
73 goto out; 76 goto out;
74 } 77 }
75 78
76 ref_reloc_sym.addr = sym->start; 79 ref_reloc_sym.addr = UM(sym->start);
77 80
78 /* 81 /*
79 * Step 5: 82 * Step 5:
@@ -123,10 +126,14 @@ int test__vmlinux_matches_kallsyms(void)
123 if (sym->start == sym->end) 126 if (sym->start == sym->end)
124 continue; 127 continue;
125 128
126 first_pair = machine__find_kernel_symbol(&kallsyms, type, sym->start, NULL, NULL); 129 mem_start = vmlinux_map->unmap_ip(vmlinux_map, sym->start);
130 mem_end = vmlinux_map->unmap_ip(vmlinux_map, sym->end);
131
132 first_pair = machine__find_kernel_symbol(&kallsyms, type,
133 mem_start, NULL, NULL);
127 pair = first_pair; 134 pair = first_pair;
128 135
129 if (pair && pair->start == sym->start) { 136 if (pair && UM(pair->start) == mem_start) {
130next_pair: 137next_pair:
131 if (strcmp(sym->name, pair->name) == 0) { 138 if (strcmp(sym->name, pair->name) == 0) {
132 /* 139 /*
@@ -138,12 +145,20 @@ next_pair:
138 * off the real size. More than that and we 145 * off the real size. More than that and we
139 * _really_ have a problem. 146 * _really_ have a problem.
140 */ 147 */
141 s64 skew = sym->end - pair->end; 148 s64 skew = mem_end - UM(pair->end);
142 if (llabs(skew) < page_size) 149 if (llabs(skew) >= page_size)
143 continue; 150 pr_debug("%#" PRIx64 ": diff end addr for %s v: %#" PRIx64 " k: %#" PRIx64 "\n",
151 mem_start, sym->name, mem_end,
152 UM(pair->end));
153
154 /*
155 * Do not count this as a failure, because we
156 * could really find a case where it's not
157 * possible to get proper function end from
158 * kallsyms.
159 */
160 continue;
144 161
145 pr_debug("%#" PRIx64 ": diff end addr for %s v: %#" PRIx64 " k: %#" PRIx64 "\n",
146 sym->start, sym->name, sym->end, pair->end);
147 } else { 162 } else {
148 struct rb_node *nnd; 163 struct rb_node *nnd;
149detour: 164detour:
@@ -152,7 +167,7 @@ detour:
152 if (nnd) { 167 if (nnd) {
153 struct symbol *next = rb_entry(nnd, struct symbol, rb_node); 168 struct symbol *next = rb_entry(nnd, struct symbol, rb_node);
154 169
155 if (next->start == sym->start) { 170 if (UM(next->start) == mem_start) {
156 pair = next; 171 pair = next;
157 goto next_pair; 172 goto next_pair;
158 } 173 }
@@ -165,10 +180,11 @@ detour:
165 } 180 }
166 181
167 pr_debug("%#" PRIx64 ": diff name v: %s k: %s\n", 182 pr_debug("%#" PRIx64 ": diff name v: %s k: %s\n",
168 sym->start, sym->name, pair->name); 183 mem_start, sym->name, pair->name);
169 } 184 }
170 } else 185 } else
171 pr_debug("%#" PRIx64 ": %s not on kallsyms\n", sym->start, sym->name); 186 pr_debug("%#" PRIx64 ": %s not on kallsyms\n",
187 mem_start, sym->name);
172 188
173 err = -1; 189 err = -1;
174 } 190 }
@@ -201,16 +217,19 @@ detour:
201 for (nd = rb_first(&vmlinux.kmaps.maps[type]); nd; nd = rb_next(nd)) { 217 for (nd = rb_first(&vmlinux.kmaps.maps[type]); nd; nd = rb_next(nd)) {
202 struct map *pos = rb_entry(nd, struct map, rb_node), *pair; 218 struct map *pos = rb_entry(nd, struct map, rb_node), *pair;
203 219
204 pair = map_groups__find(&kallsyms.kmaps, type, pos->start); 220 mem_start = vmlinux_map->unmap_ip(vmlinux_map, pos->start);
221 mem_end = vmlinux_map->unmap_ip(vmlinux_map, pos->end);
222
223 pair = map_groups__find(&kallsyms.kmaps, type, mem_start);
205 if (pair == NULL || pair->priv) 224 if (pair == NULL || pair->priv)
206 continue; 225 continue;
207 226
208 if (pair->start == pos->start) { 227 if (pair->start == mem_start) {
209 pair->priv = 1; 228 pair->priv = 1;
210 pr_info(" %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s in kallsyms as", 229 pr_info(" %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s in kallsyms as",
211 pos->start, pos->end, pos->pgoff, pos->dso->name); 230 pos->start, pos->end, pos->pgoff, pos->dso->name);
212 if (pos->pgoff != pair->pgoff || pos->end != pair->end) 231 if (mem_end != pair->end)
213 pr_info(": \n*%" PRIx64 "-%" PRIx64 " %" PRIx64 "", 232 pr_info(":\n*%" PRIx64 "-%" PRIx64 " %" PRIx64,
214 pair->start, pair->end, pair->pgoff); 233 pair->start, pair->end, pair->pgoff);
215 pr_info(" %s\n", pair->dso->name); 234 pr_info(" %s\n", pair->dso->name);
216 pair->priv = 1; 235 pair->priv = 1;
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
index cc64d3f7fc36..08545ae46992 100644
--- a/tools/perf/ui/browsers/annotate.c
+++ b/tools/perf/ui/browsers/annotate.c
@@ -428,6 +428,14 @@ static void annotate_browser__init_asm_mode(struct annotate_browser *browser)
428 browser->b.nr_entries = browser->nr_asm_entries; 428 browser->b.nr_entries = browser->nr_asm_entries;
429} 429}
430 430
431#define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
432
433static int sym_title(struct symbol *sym, struct map *map, char *title,
434 size_t sz)
435{
436 return snprintf(title, sz, "%s %s", sym->name, map->dso->long_name);
437}
438
431static bool annotate_browser__callq(struct annotate_browser *browser, 439static bool annotate_browser__callq(struct annotate_browser *browser,
432 struct perf_evsel *evsel, 440 struct perf_evsel *evsel,
433 struct hist_browser_timer *hbt) 441 struct hist_browser_timer *hbt)
@@ -438,6 +446,7 @@ static bool annotate_browser__callq(struct annotate_browser *browser,
438 struct annotation *notes; 446 struct annotation *notes;
439 struct symbol *target; 447 struct symbol *target;
440 u64 ip; 448 u64 ip;
449 char title[SYM_TITLE_MAX_SIZE];
441 450
442 if (!ins__is_call(dl->ins)) 451 if (!ins__is_call(dl->ins))
443 return false; 452 return false;
@@ -461,7 +470,8 @@ static bool annotate_browser__callq(struct annotate_browser *browser,
461 470
462 pthread_mutex_unlock(&notes->lock); 471 pthread_mutex_unlock(&notes->lock);
463 symbol__tui_annotate(target, ms->map, evsel, hbt); 472 symbol__tui_annotate(target, ms->map, evsel, hbt);
464 ui_browser__show_title(&browser->b, sym->name); 473 sym_title(sym, ms->map, title, sizeof(title));
474 ui_browser__show_title(&browser->b, title);
465 return true; 475 return true;
466} 476}
467 477
@@ -495,7 +505,7 @@ static bool annotate_browser__jump(struct annotate_browser *browser)
495 505
496 dl = annotate_browser__find_offset(browser, dl->ops.target.offset, &idx); 506 dl = annotate_browser__find_offset(browser, dl->ops.target.offset, &idx);
497 if (dl == NULL) { 507 if (dl == NULL) {
498 ui_helpline__puts("Invallid jump offset"); 508 ui_helpline__puts("Invalid jump offset");
499 return true; 509 return true;
500 } 510 }
501 511
@@ -653,8 +663,10 @@ static int annotate_browser__run(struct annotate_browser *browser,
653 const char *help = "Press 'h' for help on key bindings"; 663 const char *help = "Press 'h' for help on key bindings";
654 int delay_secs = hbt ? hbt->refresh : 0; 664 int delay_secs = hbt ? hbt->refresh : 0;
655 int key; 665 int key;
666 char title[SYM_TITLE_MAX_SIZE];
656 667
657 if (ui_browser__show(&browser->b, sym->name, help) < 0) 668 sym_title(sym, ms->map, title, sizeof(title));
669 if (ui_browser__show(&browser->b, title, help) < 0)
658 return -1; 670 return -1;
659 671
660 annotate_browser__calc_percent(browser, evsel); 672 annotate_browser__calc_percent(browser, evsel);
@@ -720,7 +732,7 @@ static int annotate_browser__run(struct annotate_browser *browser,
720 "s Toggle source code view\n" 732 "s Toggle source code view\n"
721 "/ Search string\n" 733 "/ Search string\n"
722 "r Run available scripts\n" 734 "r Run available scripts\n"
723 "? Search previous string\n"); 735 "? Search string backwards\n");
724 continue; 736 continue;
725 case 'r': 737 case 'r':
726 { 738 {
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index fc0bd3843d34..7ef36c360471 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -685,8 +685,10 @@ static u64 __hpp_get_##_field(struct hist_entry *he) \
685 return he->stat._field; \ 685 return he->stat._field; \
686} \ 686} \
687 \ 687 \
688static int hist_browser__hpp_color_##_type(struct perf_hpp *hpp, \ 688static int \
689 struct hist_entry *he) \ 689hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\
690 struct perf_hpp *hpp, \
691 struct hist_entry *he) \
690{ \ 692{ \
691 return __hpp__color_fmt(hpp, he, __hpp_get_##_field, _cb); \ 693 return __hpp__color_fmt(hpp, he, __hpp_get_##_field, _cb); \
692} 694}
@@ -701,8 +703,6 @@ __HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us, NULL)
701 703
702void hist_browser__init_hpp(void) 704void hist_browser__init_hpp(void)
703{ 705{
704 perf_hpp__column_enable(PERF_HPP__OVERHEAD);
705
706 perf_hpp__init(); 706 perf_hpp__init();
707 707
708 perf_hpp__format[PERF_HPP__OVERHEAD].color = 708 perf_hpp__format[PERF_HPP__OVERHEAD].color =
@@ -762,9 +762,9 @@ static int hist_browser__show_entry(struct hist_browser *browser,
762 first = false; 762 first = false;
763 763
764 if (fmt->color) { 764 if (fmt->color) {
765 width -= fmt->color(&hpp, entry); 765 width -= fmt->color(fmt, &hpp, entry);
766 } else { 766 } else {
767 width -= fmt->entry(&hpp, entry); 767 width -= fmt->entry(fmt, &hpp, entry);
768 slsmg_printf("%s", s); 768 slsmg_printf("%s", s);
769 } 769 }
770 } 770 }
@@ -1256,7 +1256,7 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size,
1256 printed += scnprintf(bf + printed, size - printed, 1256 printed += scnprintf(bf + printed, size - printed,
1257 ", Thread: %s(%d)", 1257 ", Thread: %s(%d)",
1258 (thread->comm_set ? thread->comm : ""), 1258 (thread->comm_set ? thread->comm : ""),
1259 thread->pid); 1259 thread->tid);
1260 if (dso) 1260 if (dso)
1261 printed += scnprintf(bf + printed, size - printed, 1261 printed += scnprintf(bf + printed, size - printed,
1262 ", DSO: %s", dso->short_name); 1262 ", DSO: %s", dso->short_name);
@@ -1579,7 +1579,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1579 asprintf(&options[nr_options], "Zoom %s %s(%d) thread", 1579 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
1580 (browser->hists->thread_filter ? "out of" : "into"), 1580 (browser->hists->thread_filter ? "out of" : "into"),
1581 (thread->comm_set ? thread->comm : ""), 1581 (thread->comm_set ? thread->comm : ""),
1582 thread->pid) > 0) 1582 thread->tid) > 0)
1583 zoom_thread = nr_options++; 1583 zoom_thread = nr_options++;
1584 1584
1585 if (dso != NULL && 1585 if (dso != NULL &&
@@ -1702,7 +1702,7 @@ zoom_out_thread:
1702 } else { 1702 } else {
1703 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"", 1703 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
1704 thread->comm_set ? thread->comm : "", 1704 thread->comm_set ? thread->comm : "",
1705 thread->pid); 1705 thread->tid);
1706 browser->hists->thread_filter = thread; 1706 browser->hists->thread_filter = thread;
1707 sort_thread.elide = true; 1707 sort_thread.elide = true;
1708 pstack__push(fstack, &browser->hists->thread_filter); 1708 pstack__push(fstack, &browser->hists->thread_filter);
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c
index 9708dd5fb8f3..2ca66cc1160f 100644
--- a/tools/perf/ui/gtk/hists.c
+++ b/tools/perf/ui/gtk/hists.c
@@ -91,7 +91,8 @@ static u64 he_get_##_field(struct hist_entry *he) \
91 return he->stat._field; \ 91 return he->stat._field; \
92} \ 92} \
93 \ 93 \
94static int perf_gtk__hpp_color_##_type(struct perf_hpp *hpp, \ 94static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
95 struct perf_hpp *hpp, \
95 struct hist_entry *he) \ 96 struct hist_entry *he) \
96{ \ 97{ \
97 return __hpp__color_fmt(hpp, he, he_get_##_field); \ 98 return __hpp__color_fmt(hpp, he, he_get_##_field); \
@@ -108,8 +109,6 @@ __HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
108 109
109void perf_gtk__init_hpp(void) 110void perf_gtk__init_hpp(void)
110{ 111{
111 perf_hpp__column_enable(PERF_HPP__OVERHEAD);
112
113 perf_hpp__init(); 112 perf_hpp__init();
114 113
115 perf_hpp__format[PERF_HPP__OVERHEAD].color = 114 perf_hpp__format[PERF_HPP__OVERHEAD].color =
@@ -124,6 +123,81 @@ void perf_gtk__init_hpp(void)
124 perf_gtk__hpp_color_overhead_guest_us; 123 perf_gtk__hpp_color_overhead_guest_us;
125} 124}
126 125
126static void callchain_list__sym_name(struct callchain_list *cl,
127 char *bf, size_t bfsize)
128{
129 if (cl->ms.sym)
130 scnprintf(bf, bfsize, "%s", cl->ms.sym->name);
131 else
132 scnprintf(bf, bfsize, "%#" PRIx64, cl->ip);
133}
134
135static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store,
136 GtkTreeIter *parent, int col, u64 total)
137{
138 struct rb_node *nd;
139 bool has_single_node = (rb_first(root) == rb_last(root));
140
141 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
142 struct callchain_node *node;
143 struct callchain_list *chain;
144 GtkTreeIter iter, new_parent;
145 bool need_new_parent;
146 double percent;
147 u64 hits, child_total;
148
149 node = rb_entry(nd, struct callchain_node, rb_node);
150
151 hits = callchain_cumul_hits(node);
152 percent = 100.0 * hits / total;
153
154 new_parent = *parent;
155 need_new_parent = !has_single_node && (node->val_nr > 1);
156
157 list_for_each_entry(chain, &node->val, list) {
158 char buf[128];
159
160 gtk_tree_store_append(store, &iter, &new_parent);
161
162 scnprintf(buf, sizeof(buf), "%5.2f%%", percent);
163 gtk_tree_store_set(store, &iter, 0, buf, -1);
164
165 callchain_list__sym_name(chain, buf, sizeof(buf));
166 gtk_tree_store_set(store, &iter, col, buf, -1);
167
168 if (need_new_parent) {
169 /*
170 * Only show the top-most symbol in a callchain
171 * if it's not the only callchain.
172 */
173 new_parent = iter;
174 need_new_parent = false;
175 }
176 }
177
178 if (callchain_param.mode == CHAIN_GRAPH_REL)
179 child_total = node->children_hit;
180 else
181 child_total = total;
182
183 /* Now 'iter' contains info of the last callchain_list */
184 perf_gtk__add_callchain(&node->rb_root, store, &iter, col,
185 child_total);
186 }
187}
188
189static void on_row_activated(GtkTreeView *view, GtkTreePath *path,
190 GtkTreeViewColumn *col __maybe_unused,
191 gpointer user_data __maybe_unused)
192{
193 bool expanded = gtk_tree_view_row_expanded(view, path);
194
195 if (expanded)
196 gtk_tree_view_collapse_row(view, path);
197 else
198 gtk_tree_view_expand_row(view, path, FALSE);
199}
200
127static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, 201static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
128 float min_pcnt) 202 float min_pcnt)
129{ 203{
@@ -131,10 +205,11 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
131 GType col_types[MAX_COLUMNS]; 205 GType col_types[MAX_COLUMNS];
132 GtkCellRenderer *renderer; 206 GtkCellRenderer *renderer;
133 struct sort_entry *se; 207 struct sort_entry *se;
134 GtkListStore *store; 208 GtkTreeStore *store;
135 struct rb_node *nd; 209 struct rb_node *nd;
136 GtkWidget *view; 210 GtkWidget *view;
137 int col_idx; 211 int col_idx;
212 int sym_col = -1;
138 int nr_cols; 213 int nr_cols;
139 char s[512]; 214 char s[512];
140 215
@@ -153,10 +228,13 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
153 if (se->elide) 228 if (se->elide)
154 continue; 229 continue;
155 230
231 if (se == &sort_sym)
232 sym_col = nr_cols;
233
156 col_types[nr_cols++] = G_TYPE_STRING; 234 col_types[nr_cols++] = G_TYPE_STRING;
157 } 235 }
158 236
159 store = gtk_list_store_newv(nr_cols, col_types); 237 store = gtk_tree_store_newv(nr_cols, col_types);
160 238
161 view = gtk_tree_view_new(); 239 view = gtk_tree_view_new();
162 240
@@ -165,7 +243,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
165 col_idx = 0; 243 col_idx = 0;
166 244
167 perf_hpp__for_each_format(fmt) { 245 perf_hpp__for_each_format(fmt) {
168 fmt->header(&hpp); 246 fmt->header(fmt, &hpp);
169 247
170 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), 248 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
171 -1, ltrim(s), 249 -1, ltrim(s),
@@ -183,6 +261,18 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
183 col_idx++, NULL); 261 col_idx++, NULL);
184 } 262 }
185 263
264 for (col_idx = 0; col_idx < nr_cols; col_idx++) {
265 GtkTreeViewColumn *column;
266
267 column = gtk_tree_view_get_column(GTK_TREE_VIEW(view), col_idx);
268 gtk_tree_view_column_set_resizable(column, TRUE);
269
270 if (col_idx == sym_col) {
271 gtk_tree_view_set_expander_column(GTK_TREE_VIEW(view),
272 column);
273 }
274 }
275
186 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store)); 276 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
187 277
188 g_object_unref(GTK_TREE_MODEL(store)); 278 g_object_unref(GTK_TREE_MODEL(store));
@@ -199,17 +289,17 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
199 if (percent < min_pcnt) 289 if (percent < min_pcnt)
200 continue; 290 continue;
201 291
202 gtk_list_store_append(store, &iter); 292 gtk_tree_store_append(store, &iter, NULL);
203 293
204 col_idx = 0; 294 col_idx = 0;
205 295
206 perf_hpp__for_each_format(fmt) { 296 perf_hpp__for_each_format(fmt) {
207 if (fmt->color) 297 if (fmt->color)
208 fmt->color(&hpp, h); 298 fmt->color(fmt, &hpp, h);
209 else 299 else
210 fmt->entry(&hpp, h); 300 fmt->entry(fmt, &hpp, h);
211 301
212 gtk_list_store_set(store, &iter, col_idx++, s, -1); 302 gtk_tree_store_set(store, &iter, col_idx++, s, -1);
213 } 303 }
214 304
215 list_for_each_entry(se, &hist_entry__sort_list, list) { 305 list_for_each_entry(se, &hist_entry__sort_list, list) {
@@ -219,10 +309,26 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
219 se->se_snprintf(h, s, ARRAY_SIZE(s), 309 se->se_snprintf(h, s, ARRAY_SIZE(s),
220 hists__col_len(hists, se->se_width_idx)); 310 hists__col_len(hists, se->se_width_idx));
221 311
222 gtk_list_store_set(store, &iter, col_idx++, s, -1); 312 gtk_tree_store_set(store, &iter, col_idx++, s, -1);
313 }
314
315 if (symbol_conf.use_callchain && sort__has_sym) {
316 u64 total;
317
318 if (callchain_param.mode == CHAIN_GRAPH_REL)
319 total = h->stat.period;
320 else
321 total = hists->stats.total_period;
322
323 perf_gtk__add_callchain(&h->sorted_chain, store, &iter,
324 sym_col, total);
223 } 325 }
224 } 326 }
225 327
328 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(view), TRUE);
329
330 g_signal_connect(view, "row-activated",
331 G_CALLBACK(on_row_activated), NULL);
226 gtk_container_add(GTK_CONTAINER(window), view); 332 gtk_container_add(GTK_CONTAINER(window), view);
227} 333}
228 334
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index 4bf91b09d62d..0a193281eba8 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -1,4 +1,5 @@
1#include <math.h> 1#include <math.h>
2#include <linux/compiler.h>
2 3
3#include "../util/hist.h" 4#include "../util/hist.h"
4#include "../util/util.h" 5#include "../util/util.h"
@@ -79,7 +80,8 @@ static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
79} 80}
80 81
81#define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ 82#define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \
82static int hpp__header_##_type(struct perf_hpp *hpp) \ 83static int hpp__header_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
84 struct perf_hpp *hpp) \
83{ \ 85{ \
84 int len = _min_width; \ 86 int len = _min_width; \
85 \ 87 \
@@ -92,7 +94,8 @@ static int hpp__header_##_type(struct perf_hpp *hpp) \
92} 94}
93 95
94#define __HPP_WIDTH_FN(_type, _min_width, _unit_width) \ 96#define __HPP_WIDTH_FN(_type, _min_width, _unit_width) \
95static int hpp__width_##_type(struct perf_hpp *hpp __maybe_unused) \ 97static int hpp__width_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
98 struct perf_hpp *hpp __maybe_unused) \
96{ \ 99{ \
97 int len = _min_width; \ 100 int len = _min_width; \
98 \ 101 \
@@ -110,14 +113,16 @@ static u64 he_get_##_field(struct hist_entry *he) \
110 return he->stat._field; \ 113 return he->stat._field; \
111} \ 114} \
112 \ 115 \
113static int hpp__color_##_type(struct perf_hpp *hpp, struct hist_entry *he) \ 116static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
117 struct perf_hpp *hpp, struct hist_entry *he) \
114{ \ 118{ \
115 return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%", \ 119 return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%", \
116 (hpp_snprint_fn)percent_color_snprintf, true); \ 120 (hpp_snprint_fn)percent_color_snprintf, true); \
117} 121}
118 122
119#define __HPP_ENTRY_PERCENT_FN(_type, _field) \ 123#define __HPP_ENTRY_PERCENT_FN(_type, _field) \
120static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \ 124static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \
125 struct perf_hpp *hpp, struct hist_entry *he) \
121{ \ 126{ \
122 const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \ 127 const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \
123 return __hpp__fmt(hpp, he, he_get_##_field, fmt, \ 128 return __hpp__fmt(hpp, he, he_get_##_field, fmt, \
@@ -130,7 +135,8 @@ static u64 he_get_raw_##_field(struct hist_entry *he) \
130 return he->stat._field; \ 135 return he->stat._field; \
131} \ 136} \
132 \ 137 \
133static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \ 138static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \
139 struct perf_hpp *hpp, struct hist_entry *he) \
134{ \ 140{ \
135 const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64; \ 141 const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64; \
136 return __hpp__fmt(hpp, he, he_get_raw_##_field, fmt, scnprintf, false); \ 142 return __hpp__fmt(hpp, he, he_get_raw_##_field, fmt, scnprintf, false); \
@@ -157,196 +163,6 @@ HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us, 9, 8)
157HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12) 163HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12)
158HPP_RAW_FNS(period, "Period", period, 12, 12) 164HPP_RAW_FNS(period, "Period", period, 12, 12)
159 165
160
161static int hpp__header_baseline(struct perf_hpp *hpp)
162{
163 return scnprintf(hpp->buf, hpp->size, "Baseline");
164}
165
166static int hpp__width_baseline(struct perf_hpp *hpp __maybe_unused)
167{
168 return 8;
169}
170
171static double baseline_percent(struct hist_entry *he)
172{
173 struct hist_entry *pair = hist_entry__next_pair(he);
174 struct hists *pair_hists = pair ? pair->hists : NULL;
175 double percent = 0.0;
176
177 if (pair) {
178 u64 total_period = pair_hists->stats.total_period;
179 u64 base_period = pair->stat.period;
180
181 percent = 100.0 * base_period / total_period;
182 }
183
184 return percent;
185}
186
187static int hpp__color_baseline(struct perf_hpp *hpp, struct hist_entry *he)
188{
189 double percent = baseline_percent(he);
190
191 if (hist_entry__has_pairs(he) || symbol_conf.field_sep)
192 return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent);
193 else
194 return scnprintf(hpp->buf, hpp->size, " ");
195}
196
197static int hpp__entry_baseline(struct perf_hpp *hpp, struct hist_entry *he)
198{
199 double percent = baseline_percent(he);
200 const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%";
201
202 if (hist_entry__has_pairs(he) || symbol_conf.field_sep)
203 return scnprintf(hpp->buf, hpp->size, fmt, percent);
204 else
205 return scnprintf(hpp->buf, hpp->size, " ");
206}
207
208static int hpp__header_period_baseline(struct perf_hpp *hpp)
209{
210 const char *fmt = symbol_conf.field_sep ? "%s" : "%12s";
211
212 return scnprintf(hpp->buf, hpp->size, fmt, "Period Base");
213}
214
215static int hpp__width_period_baseline(struct perf_hpp *hpp __maybe_unused)
216{
217 return 12;
218}
219
220static int hpp__entry_period_baseline(struct perf_hpp *hpp, struct hist_entry *he)
221{
222 struct hist_entry *pair = hist_entry__next_pair(he);
223 u64 period = pair ? pair->stat.period : 0;
224 const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%12" PRIu64;
225
226 return scnprintf(hpp->buf, hpp->size, fmt, period);
227}
228
229static int hpp__header_delta(struct perf_hpp *hpp)
230{
231 const char *fmt = symbol_conf.field_sep ? "%s" : "%7s";
232
233 return scnprintf(hpp->buf, hpp->size, fmt, "Delta");
234}
235
236static int hpp__width_delta(struct perf_hpp *hpp __maybe_unused)
237{
238 return 7;
239}
240
241static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he)
242{
243 struct hist_entry *pair = hist_entry__next_pair(he);
244 const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s";
245 char buf[32] = " ";
246 double diff = 0.0;
247
248 if (pair) {
249 if (he->diff.computed)
250 diff = he->diff.period_ratio_delta;
251 else
252 diff = perf_diff__compute_delta(he, pair);
253 } else
254 diff = perf_diff__period_percent(he, he->stat.period);
255
256 if (fabs(diff) >= 0.01)
257 scnprintf(buf, sizeof(buf), "%+4.2F%%", diff);
258
259 return scnprintf(hpp->buf, hpp->size, fmt, buf);
260}
261
262static int hpp__header_ratio(struct perf_hpp *hpp)
263{
264 const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
265
266 return scnprintf(hpp->buf, hpp->size, fmt, "Ratio");
267}
268
269static int hpp__width_ratio(struct perf_hpp *hpp __maybe_unused)
270{
271 return 14;
272}
273
274static int hpp__entry_ratio(struct perf_hpp *hpp, struct hist_entry *he)
275{
276 struct hist_entry *pair = hist_entry__next_pair(he);
277 const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
278 char buf[32] = " ";
279 double ratio = 0.0;
280
281 if (pair) {
282 if (he->diff.computed)
283 ratio = he->diff.period_ratio;
284 else
285 ratio = perf_diff__compute_ratio(he, pair);
286 }
287
288 if (ratio > 0.0)
289 scnprintf(buf, sizeof(buf), "%+14.6F", ratio);
290
291 return scnprintf(hpp->buf, hpp->size, fmt, buf);
292}
293
294static int hpp__header_wdiff(struct perf_hpp *hpp)
295{
296 const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
297
298 return scnprintf(hpp->buf, hpp->size, fmt, "Weighted diff");
299}
300
301static int hpp__width_wdiff(struct perf_hpp *hpp __maybe_unused)
302{
303 return 14;
304}
305
306static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he)
307{
308 struct hist_entry *pair = hist_entry__next_pair(he);
309 const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
310 char buf[32] = " ";
311 s64 wdiff = 0;
312
313 if (pair) {
314 if (he->diff.computed)
315 wdiff = he->diff.wdiff;
316 else
317 wdiff = perf_diff__compute_wdiff(he, pair);
318 }
319
320 if (wdiff != 0)
321 scnprintf(buf, sizeof(buf), "%14ld", wdiff);
322
323 return scnprintf(hpp->buf, hpp->size, fmt, buf);
324}
325
326static int hpp__header_formula(struct perf_hpp *hpp)
327{
328 const char *fmt = symbol_conf.field_sep ? "%s" : "%70s";
329
330 return scnprintf(hpp->buf, hpp->size, fmt, "Formula");
331}
332
333static int hpp__width_formula(struct perf_hpp *hpp __maybe_unused)
334{
335 return 70;
336}
337
338static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he)
339{
340 struct hist_entry *pair = hist_entry__next_pair(he);
341 const char *fmt = symbol_conf.field_sep ? "%s" : "%-70s";
342 char buf[96] = " ";
343
344 if (pair)
345 perf_diff__formula(he, pair, buf, sizeof(buf));
346
347 return scnprintf(hpp->buf, hpp->size, fmt, buf);
348}
349
350#define HPP__COLOR_PRINT_FNS(_name) \ 166#define HPP__COLOR_PRINT_FNS(_name) \
351 { \ 167 { \
352 .header = hpp__header_ ## _name, \ 168 .header = hpp__header_ ## _name, \
@@ -363,19 +179,13 @@ static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he)
363 } 179 }
364 180
365struct perf_hpp_fmt perf_hpp__format[] = { 181struct perf_hpp_fmt perf_hpp__format[] = {
366 HPP__COLOR_PRINT_FNS(baseline),
367 HPP__COLOR_PRINT_FNS(overhead), 182 HPP__COLOR_PRINT_FNS(overhead),
368 HPP__COLOR_PRINT_FNS(overhead_sys), 183 HPP__COLOR_PRINT_FNS(overhead_sys),
369 HPP__COLOR_PRINT_FNS(overhead_us), 184 HPP__COLOR_PRINT_FNS(overhead_us),
370 HPP__COLOR_PRINT_FNS(overhead_guest_sys), 185 HPP__COLOR_PRINT_FNS(overhead_guest_sys),
371 HPP__COLOR_PRINT_FNS(overhead_guest_us), 186 HPP__COLOR_PRINT_FNS(overhead_guest_us),
372 HPP__PRINT_FNS(samples), 187 HPP__PRINT_FNS(samples),
373 HPP__PRINT_FNS(period), 188 HPP__PRINT_FNS(period)
374 HPP__PRINT_FNS(period_baseline),
375 HPP__PRINT_FNS(delta),
376 HPP__PRINT_FNS(ratio),
377 HPP__PRINT_FNS(wdiff),
378 HPP__PRINT_FNS(formula)
379}; 189};
380 190
381LIST_HEAD(perf_hpp__list); 191LIST_HEAD(perf_hpp__list);
@@ -396,6 +206,8 @@ LIST_HEAD(perf_hpp__list);
396 206
397void perf_hpp__init(void) 207void perf_hpp__init(void)
398{ 208{
209 perf_hpp__column_enable(PERF_HPP__OVERHEAD);
210
399 if (symbol_conf.show_cpu_utilization) { 211 if (symbol_conf.show_cpu_utilization) {
400 perf_hpp__column_enable(PERF_HPP__OVERHEAD_SYS); 212 perf_hpp__column_enable(PERF_HPP__OVERHEAD_SYS);
401 perf_hpp__column_enable(PERF_HPP__OVERHEAD_US); 213 perf_hpp__column_enable(PERF_HPP__OVERHEAD_US);
@@ -424,46 +236,6 @@ void perf_hpp__column_enable(unsigned col)
424 perf_hpp__column_register(&perf_hpp__format[col]); 236 perf_hpp__column_register(&perf_hpp__format[col]);
425} 237}
426 238
427static inline void advance_hpp(struct perf_hpp *hpp, int inc)
428{
429 hpp->buf += inc;
430 hpp->size -= inc;
431}
432
433int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he,
434 bool color)
435{
436 const char *sep = symbol_conf.field_sep;
437 struct perf_hpp_fmt *fmt;
438 char *start = hpp->buf;
439 int ret;
440 bool first = true;
441
442 if (symbol_conf.exclude_other && !he->parent)
443 return 0;
444
445 perf_hpp__for_each_format(fmt) {
446 /*
447 * If there's no field_sep, we still need
448 * to display initial ' '.
449 */
450 if (!sep || !first) {
451 ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " ");
452 advance_hpp(hpp, ret);
453 } else
454 first = false;
455
456 if (color && fmt->color)
457 ret = fmt->color(hpp, he);
458 else
459 ret = fmt->entry(hpp, he);
460
461 advance_hpp(hpp, ret);
462 }
463
464 return hpp->buf - start;
465}
466
467int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size, 239int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size,
468 struct hists *hists) 240 struct hists *hists)
469{ 241{
@@ -499,7 +271,7 @@ unsigned int hists__sort_list_width(struct hists *hists)
499 if (i) 271 if (i)
500 ret += 2; 272 ret += 2;
501 273
502 ret += fmt->width(&dummy_hpp); 274 ret += fmt->width(fmt, &dummy_hpp);
503 } 275 }
504 276
505 list_for_each_entry(se, &hist_entry__sort_list, list) 277 list_for_each_entry(se, &hist_entry__sort_list, list)
diff --git a/tools/perf/ui/setup.c b/tools/perf/ui/setup.c
index ae6a789cb0f6..47d9a571f261 100644
--- a/tools/perf/ui/setup.c
+++ b/tools/perf/ui/setup.c
@@ -30,7 +30,6 @@ void setup_browser(bool fallback_to_pager)
30 if (fallback_to_pager) 30 if (fallback_to_pager)
31 setup_pager(); 31 setup_pager();
32 32
33 perf_hpp__column_enable(PERF_HPP__OVERHEAD);
34 perf_hpp__init(); 33 perf_hpp__init();
35 break; 34 break;
36 } 35 }
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index ae7a75432249..194e2f42ff5d 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -308,10 +308,51 @@ static size_t hist_entry__callchain_fprintf(struct hist_entry *he,
308 return hist_entry_callchain__fprintf(he, total_period, left_margin, fp); 308 return hist_entry_callchain__fprintf(he, total_period, left_margin, fp);
309} 309}
310 310
311static inline void advance_hpp(struct perf_hpp *hpp, int inc)
312{
313 hpp->buf += inc;
314 hpp->size -= inc;
315}
316
317static int hist_entry__period_snprintf(struct perf_hpp *hpp,
318 struct hist_entry *he,
319 bool color)
320{
321 const char *sep = symbol_conf.field_sep;
322 struct perf_hpp_fmt *fmt;
323 char *start = hpp->buf;
324 int ret;
325 bool first = true;
326
327 if (symbol_conf.exclude_other && !he->parent)
328 return 0;
329
330 perf_hpp__for_each_format(fmt) {
331 /*
332 * If there's no field_sep, we still need
333 * to display initial ' '.
334 */
335 if (!sep || !first) {
336 ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " ");
337 advance_hpp(hpp, ret);
338 } else
339 first = false;
340
341 if (color && fmt->color)
342 ret = fmt->color(fmt, hpp, he);
343 else
344 ret = fmt->entry(fmt, hpp, he);
345
346 advance_hpp(hpp, ret);
347 }
348
349 return hpp->buf - start;
350}
351
311static int hist_entry__fprintf(struct hist_entry *he, size_t size, 352static int hist_entry__fprintf(struct hist_entry *he, size_t size,
312 struct hists *hists, FILE *fp) 353 struct hists *hists,
354 char *bf, size_t bfsz, FILE *fp)
313{ 355{
314 char bf[512];
315 int ret; 356 int ret;
316 struct perf_hpp hpp = { 357 struct perf_hpp hpp = {
317 .buf = bf, 358 .buf = bf,
@@ -319,8 +360,8 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
319 }; 360 };
320 bool color = !symbol_conf.field_sep; 361 bool color = !symbol_conf.field_sep;
321 362
322 if (size == 0 || size > sizeof(bf)) 363 if (size == 0 || size > bfsz)
323 size = hpp.size = sizeof(bf); 364 size = hpp.size = bfsz;
324 365
325 ret = hist_entry__period_snprintf(&hpp, he, color); 366 ret = hist_entry__period_snprintf(&hpp, he, color);
326 hist_entry__sort_snprintf(he, bf + ret, size - ret, hists); 367 hist_entry__sort_snprintf(he, bf + ret, size - ret, hists);
@@ -351,6 +392,8 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
351 .ptr = hists_to_evsel(hists), 392 .ptr = hists_to_evsel(hists),
352 }; 393 };
353 bool first = true; 394 bool first = true;
395 size_t linesz;
396 char *line = NULL;
354 397
355 init_rem_hits(); 398 init_rem_hits();
356 399
@@ -365,7 +408,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
365 else 408 else
366 first = false; 409 first = false;
367 410
368 fmt->header(&dummy_hpp); 411 fmt->header(fmt, &dummy_hpp);
369 fprintf(fp, "%s", bf); 412 fprintf(fp, "%s", bf);
370 } 413 }
371 414
@@ -410,7 +453,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
410 else 453 else
411 first = false; 454 first = false;
412 455
413 width = fmt->width(&dummy_hpp); 456 width = fmt->width(fmt, &dummy_hpp);
414 for (i = 0; i < width; i++) 457 for (i = 0; i < width; i++)
415 fprintf(fp, "."); 458 fprintf(fp, ".");
416 } 459 }
@@ -438,6 +481,13 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
438 goto out; 481 goto out;
439 482
440print_entries: 483print_entries:
484 linesz = hists__sort_list_width(hists) + 3 + 1;
485 line = malloc(linesz);
486 if (line == NULL) {
487 ret = -1;
488 goto out;
489 }
490
441 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 491 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
442 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 492 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
443 float percent = h->stat.period * 100.0 / 493 float percent = h->stat.period * 100.0 /
@@ -449,10 +499,10 @@ print_entries:
449 if (percent < min_pcnt) 499 if (percent < min_pcnt)
450 continue; 500 continue;
451 501
452 ret += hist_entry__fprintf(h, max_cols, hists, fp); 502 ret += hist_entry__fprintf(h, max_cols, hists, line, linesz, fp);
453 503
454 if (max_rows && ++nr_rows >= max_rows) 504 if (max_rows && ++nr_rows >= max_rows)
455 goto out; 505 break;
456 506
457 if (h->ms.map == NULL && verbose > 1) { 507 if (h->ms.map == NULL && verbose > 1) {
458 __map_groups__fprintf_maps(&h->thread->mg, 508 __map_groups__fprintf_maps(&h->thread->mg,
@@ -460,6 +510,8 @@ print_entries:
460 fprintf(fp, "%.10s end\n", graph_dotted_line); 510 fprintf(fp, "%.10s end\n", graph_dotted_line);
461 } 511 }
462 } 512 }
513
514 free(line);
463out: 515out:
464 free(rem_sq_bracket); 516 free(rem_sq_bracket);
465 517
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index d102716c43a1..7eae5488ecea 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -110,10 +110,10 @@ static int jump__parse(struct ins_operands *ops)
110{ 110{
111 const char *s = strchr(ops->raw, '+'); 111 const char *s = strchr(ops->raw, '+');
112 112
113 ops->target.addr = strtoll(ops->raw, NULL, 16); 113 ops->target.addr = strtoull(ops->raw, NULL, 16);
114 114
115 if (s++ != NULL) 115 if (s++ != NULL)
116 ops->target.offset = strtoll(s, NULL, 16); 116 ops->target.offset = strtoull(s, NULL, 16);
117 else 117 else
118 ops->target.offset = UINT64_MAX; 118 ops->target.offset = UINT64_MAX;
119 119
@@ -809,7 +809,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
809 end = map__rip_2objdump(map, sym->end); 809 end = map__rip_2objdump(map, sym->end);
810 810
811 offset = line_ip - start; 811 offset = line_ip - start;
812 if (offset < 0 || (u64)line_ip > end) 812 if ((u64)line_ip < start || (u64)line_ip > end)
813 offset = -1; 813 offset = -1;
814 else 814 else
815 parsed_line = tmp2 + 1; 815 parsed_line = tmp2 + 1;
@@ -821,11 +821,55 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
821 if (dl == NULL) 821 if (dl == NULL)
822 return -1; 822 return -1;
823 823
824 if (dl->ops.target.offset == UINT64_MAX)
825 dl->ops.target.offset = dl->ops.target.addr -
826 map__rip_2objdump(map, sym->start);
827
828 /*
829 * kcore has no symbols, so add the call target name if it is on the
830 * same map.
831 */
832 if (dl->ins && ins__is_call(dl->ins) && !dl->ops.target.name) {
833 struct symbol *s;
834 u64 ip = dl->ops.target.addr;
835
836 if (ip >= map->start && ip <= map->end) {
837 ip = map->map_ip(map, ip);
838 s = map__find_symbol(map, ip, NULL);
839 if (s && s->start == ip)
840 dl->ops.target.name = strdup(s->name);
841 }
842 }
843
824 disasm__add(&notes->src->source, dl); 844 disasm__add(&notes->src->source, dl);
825 845
826 return 0; 846 return 0;
827} 847}
828 848
849static void delete_last_nop(struct symbol *sym)
850{
851 struct annotation *notes = symbol__annotation(sym);
852 struct list_head *list = &notes->src->source;
853 struct disasm_line *dl;
854
855 while (!list_empty(list)) {
856 dl = list_entry(list->prev, struct disasm_line, node);
857
858 if (dl->ins && dl->ins->ops) {
859 if (dl->ins->ops != &nop_ops)
860 return;
861 } else {
862 if (!strstr(dl->line, " nop ") &&
863 !strstr(dl->line, " nopl ") &&
864 !strstr(dl->line, " nopw "))
865 return;
866 }
867
868 list_del(&dl->node);
869 disasm_line__free(dl);
870 }
871}
872
829int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize) 873int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
830{ 874{
831 struct dso *dso = map->dso; 875 struct dso *dso = map->dso;
@@ -864,7 +908,8 @@ fallback:
864 free_filename = false; 908 free_filename = false;
865 } 909 }
866 910
867 if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS) { 911 if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS &&
912 !dso__is_kcore(dso)) {
868 char bf[BUILD_ID_SIZE * 2 + 16] = " with build id "; 913 char bf[BUILD_ID_SIZE * 2 + 16] = " with build id ";
869 char *build_id_msg = NULL; 914 char *build_id_msg = NULL;
870 915
@@ -898,7 +943,7 @@ fallback:
898 snprintf(command, sizeof(command), 943 snprintf(command, sizeof(command),
899 "%s %s%s --start-address=0x%016" PRIx64 944 "%s %s%s --start-address=0x%016" PRIx64
900 " --stop-address=0x%016" PRIx64 945 " --stop-address=0x%016" PRIx64
901 " -d %s %s -C %s|grep -v %s|expand", 946 " -d %s %s -C %s 2>/dev/null|grep -v %s|expand",
902 objdump_path ? objdump_path : "objdump", 947 objdump_path ? objdump_path : "objdump",
903 disassembler_style ? "-M " : "", 948 disassembler_style ? "-M " : "",
904 disassembler_style ? disassembler_style : "", 949 disassembler_style ? disassembler_style : "",
@@ -918,6 +963,13 @@ fallback:
918 if (symbol__parse_objdump_line(sym, map, file, privsize) < 0) 963 if (symbol__parse_objdump_line(sym, map, file, privsize) < 0)
919 break; 964 break;
920 965
966 /*
967 * kallsyms does not have symbol sizes so there may a nop at the end.
968 * Remove it.
969 */
970 if (dso__is_kcore(dso))
971 delete_last_nop(sym);
972
921 pclose(file); 973 pclose(file);
922out_free_filename: 974out_free_filename:
923 if (free_filename) 975 if (free_filename)
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 5295625c0c00..7ded71d19d75 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -18,13 +18,14 @@
18 18
19int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused, 19int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused,
20 union perf_event *event, 20 union perf_event *event,
21 struct perf_sample *sample __maybe_unused, 21 struct perf_sample *sample,
22 struct perf_evsel *evsel __maybe_unused, 22 struct perf_evsel *evsel __maybe_unused,
23 struct machine *machine) 23 struct machine *machine)
24{ 24{
25 struct addr_location al; 25 struct addr_location al;
26 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 26 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
27 struct thread *thread = machine__findnew_thread(machine, event->ip.pid); 27 struct thread *thread = machine__findnew_thread(machine, sample->pid,
28 sample->pid);
28 29
29 if (thread == NULL) { 30 if (thread == NULL) {
30 pr_err("problem processing %d event, skipping it.\n", 31 pr_err("problem processing %d event, skipping it.\n",
@@ -33,7 +34,7 @@ int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused,
33 } 34 }
34 35
35 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, 36 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
36 event->ip.ip, &al); 37 sample->ip, &al);
37 38
38 if (al.map != NULL) 39 if (al.map != NULL)
39 al.map->dso->hit = 1; 40 al.map->dso->hit = 1;
@@ -47,7 +48,9 @@ static int perf_event__exit_del_thread(struct perf_tool *tool __maybe_unused,
47 __maybe_unused, 48 __maybe_unused,
48 struct machine *machine) 49 struct machine *machine)
49{ 50{
50 struct thread *thread = machine__findnew_thread(machine, event->fork.tid); 51 struct thread *thread = machine__findnew_thread(machine,
52 event->fork.pid,
53 event->fork.tid);
51 54
52 dump_printf("(%d:%d):(%d:%d)\n", event->fork.pid, event->fork.tid, 55 dump_printf("(%d:%d):(%d:%d)\n", event->fork.pid, event->fork.tid,
53 event->fork.ppid, event->fork.ptid); 56 event->fork.ppid, event->fork.ptid);
@@ -64,6 +67,7 @@ static int perf_event__exit_del_thread(struct perf_tool *tool __maybe_unused,
64struct perf_tool build_id__mark_dso_hit_ops = { 67struct perf_tool build_id__mark_dso_hit_ops = {
65 .sample = build_id__mark_dso_hit, 68 .sample = build_id__mark_dso_hit,
66 .mmap = perf_event__process_mmap, 69 .mmap = perf_event__process_mmap,
70 .mmap2 = perf_event__process_mmap2,
67 .fork = perf_event__process_fork, 71 .fork = perf_event__process_fork,
68 .exit = perf_event__exit_del_thread, 72 .exit = perf_event__exit_del_thread,
69 .attr = perf_event__process_attr, 73 .attr = perf_event__process_attr,
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 42b6a632fe7b..482f68081cd8 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -15,19 +15,12 @@
15#include <errno.h> 15#include <errno.h>
16#include <math.h> 16#include <math.h>
17 17
18#include "hist.h"
18#include "util.h" 19#include "util.h"
19#include "callchain.h" 20#include "callchain.h"
20 21
21__thread struct callchain_cursor callchain_cursor; 22__thread struct callchain_cursor callchain_cursor;
22 23
23bool ip_callchain__valid(struct ip_callchain *chain,
24 const union perf_event *event)
25{
26 unsigned int chain_size = event->header.size;
27 chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event;
28 return chain->nr * sizeof(u64) <= chain_size;
29}
30
31#define chain_for_each_child(child, parent) \ 24#define chain_for_each_child(child, parent) \
32 list_for_each_entry(child, &parent->children, siblings) 25 list_for_each_entry(child, &parent->children, siblings)
33 26
@@ -327,7 +320,8 @@ append_chain(struct callchain_node *root,
327 /* 320 /*
328 * Lookup in the current node 321 * Lookup in the current node
329 * If we have a symbol, then compare the start to match 322 * If we have a symbol, then compare the start to match
330 * anywhere inside a function. 323 * anywhere inside a function, unless function
324 * mode is disabled.
331 */ 325 */
332 list_for_each_entry(cnode, &root->val, list) { 326 list_for_each_entry(cnode, &root->val, list) {
333 struct callchain_cursor_node *node; 327 struct callchain_cursor_node *node;
@@ -339,7 +333,8 @@ append_chain(struct callchain_node *root,
339 333
340 sym = node->sym; 334 sym = node->sym;
341 335
342 if (cnode->ms.sym && sym) { 336 if (cnode->ms.sym && sym &&
337 callchain_param.key == CCKEY_FUNCTION) {
343 if (cnode->ms.sym->start != sym->start) 338 if (cnode->ms.sym->start != sym->start)
344 break; 339 break;
345 } else if (cnode->ip != node->ip) 340 } else if (cnode->ip != node->ip)
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 3ee9f67d5af0..2b585bc308cf 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -41,12 +41,18 @@ struct callchain_param;
41typedef void (*sort_chain_func_t)(struct rb_root *, struct callchain_root *, 41typedef void (*sort_chain_func_t)(struct rb_root *, struct callchain_root *,
42 u64, struct callchain_param *); 42 u64, struct callchain_param *);
43 43
44enum chain_key {
45 CCKEY_FUNCTION,
46 CCKEY_ADDRESS
47};
48
44struct callchain_param { 49struct callchain_param {
45 enum chain_mode mode; 50 enum chain_mode mode;
46 u32 print_limit; 51 u32 print_limit;
47 double min_percent; 52 double min_percent;
48 sort_chain_func_t sort; 53 sort_chain_func_t sort;
49 enum chain_order order; 54 enum chain_order order;
55 enum chain_key key;
50}; 56};
51 57
52struct callchain_list { 58struct callchain_list {
@@ -103,11 +109,6 @@ int callchain_append(struct callchain_root *root,
103int callchain_merge(struct callchain_cursor *cursor, 109int callchain_merge(struct callchain_cursor *cursor,
104 struct callchain_root *dst, struct callchain_root *src); 110 struct callchain_root *dst, struct callchain_root *src);
105 111
106struct ip_callchain;
107union perf_event;
108
109bool ip_callchain__valid(struct ip_callchain *chain,
110 const union perf_event *event);
111/* 112/*
112 * Initialize a cursor before adding entries inside, but keep 113 * Initialize a cursor before adding entries inside, but keep
113 * the previously allocated entries as a cache. 114 * the previously allocated entries as a cache.
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
index 9bed02e5fb3d..b123bb9d6f55 100644
--- a/tools/perf/util/cpumap.h
+++ b/tools/perf/util/cpumap.h
@@ -41,7 +41,7 @@ static inline int cpu_map__nr(const struct cpu_map *map)
41 return map ? map->nr : 1; 41 return map ? map->nr : 1;
42} 42}
43 43
44static inline bool cpu_map__all(const struct cpu_map *map) 44static inline bool cpu_map__empty(const struct cpu_map *map)
45{ 45{
46 return map ? map->map[0] == -1 : true; 46 return map ? map->map[0] == -1 : true;
47} 47}
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index c4374f07603c..e3c1ff8512c8 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -78,6 +78,8 @@ int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
78 symbol_conf.symfs, build_id_hex, build_id_hex + 2); 78 symbol_conf.symfs, build_id_hex, build_id_hex + 2);
79 break; 79 break;
80 80
81 case DSO_BINARY_TYPE__VMLINUX:
82 case DSO_BINARY_TYPE__GUEST_VMLINUX:
81 case DSO_BINARY_TYPE__SYSTEM_PATH_DSO: 83 case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
82 snprintf(file, size, "%s%s", 84 snprintf(file, size, "%s%s",
83 symbol_conf.symfs, dso->long_name); 85 symbol_conf.symfs, dso->long_name);
@@ -93,11 +95,14 @@ int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
93 dso->long_name); 95 dso->long_name);
94 break; 96 break;
95 97
98 case DSO_BINARY_TYPE__KCORE:
99 case DSO_BINARY_TYPE__GUEST_KCORE:
100 snprintf(file, size, "%s", dso->long_name);
101 break;
102
96 default: 103 default:
97 case DSO_BINARY_TYPE__KALLSYMS: 104 case DSO_BINARY_TYPE__KALLSYMS:
98 case DSO_BINARY_TYPE__VMLINUX:
99 case DSO_BINARY_TYPE__GUEST_KALLSYMS: 105 case DSO_BINARY_TYPE__GUEST_KALLSYMS:
100 case DSO_BINARY_TYPE__GUEST_VMLINUX:
101 case DSO_BINARY_TYPE__JAVA_JIT: 106 case DSO_BINARY_TYPE__JAVA_JIT:
102 case DSO_BINARY_TYPE__NOT_FOUND: 107 case DSO_BINARY_TYPE__NOT_FOUND:
103 ret = -1; 108 ret = -1;
@@ -419,6 +424,7 @@ struct dso *dso__new(const char *name)
419 dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND; 424 dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND;
420 dso->data_type = DSO_BINARY_TYPE__NOT_FOUND; 425 dso->data_type = DSO_BINARY_TYPE__NOT_FOUND;
421 dso->loaded = 0; 426 dso->loaded = 0;
427 dso->rel = 0;
422 dso->sorted_by_name = 0; 428 dso->sorted_by_name = 0;
423 dso->has_build_id = 0; 429 dso->has_build_id = 0;
424 dso->kernel = DSO_TYPE_USER; 430 dso->kernel = DSO_TYPE_USER;
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index d51aaf272c68..b793053335d6 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -3,6 +3,7 @@
3 3
4#include <linux/types.h> 4#include <linux/types.h>
5#include <linux/rbtree.h> 5#include <linux/rbtree.h>
6#include <stdbool.h>
6#include "types.h" 7#include "types.h"
7#include "map.h" 8#include "map.h"
8 9
@@ -20,6 +21,8 @@ enum dso_binary_type {
20 DSO_BINARY_TYPE__SYSTEM_PATH_DSO, 21 DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
21 DSO_BINARY_TYPE__GUEST_KMODULE, 22 DSO_BINARY_TYPE__GUEST_KMODULE,
22 DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE, 23 DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
24 DSO_BINARY_TYPE__KCORE,
25 DSO_BINARY_TYPE__GUEST_KCORE,
23 DSO_BINARY_TYPE__NOT_FOUND, 26 DSO_BINARY_TYPE__NOT_FOUND,
24}; 27};
25 28
@@ -84,6 +87,7 @@ struct dso {
84 u8 lname_alloc:1; 87 u8 lname_alloc:1;
85 u8 sorted_by_name; 88 u8 sorted_by_name;
86 u8 loaded; 89 u8 loaded;
90 u8 rel;
87 u8 build_id[BUILD_ID_SIZE]; 91 u8 build_id[BUILD_ID_SIZE];
88 const char *short_name; 92 const char *short_name;
89 char *long_name; 93 char *long_name;
@@ -146,4 +150,17 @@ size_t dso__fprintf_buildid(struct dso *dso, FILE *fp);
146size_t dso__fprintf_symbols_by_name(struct dso *dso, 150size_t dso__fprintf_symbols_by_name(struct dso *dso,
147 enum map_type type, FILE *fp); 151 enum map_type type, FILE *fp);
148size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp); 152size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp);
153
154static inline bool dso__is_vmlinux(struct dso *dso)
155{
156 return dso->data_type == DSO_BINARY_TYPE__VMLINUX ||
157 dso->data_type == DSO_BINARY_TYPE__GUEST_VMLINUX;
158}
159
160static inline bool dso__is_kcore(struct dso *dso)
161{
162 return dso->data_type == DSO_BINARY_TYPE__KCORE ||
163 dso->data_type == DSO_BINARY_TYPE__GUEST_KCORE;
164}
165
149#endif /* __PERF_DSO */ 166#endif /* __PERF_DSO */
diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c
index 3e5f5430a28a..e23bde19d590 100644
--- a/tools/perf/util/dwarf-aux.c
+++ b/tools/perf/util/dwarf-aux.c
@@ -263,6 +263,21 @@ bool die_is_signed_type(Dwarf_Die *tp_die)
263} 263}
264 264
265/** 265/**
266 * die_is_func_def - Ensure that this DIE is a subprogram and definition
267 * @dw_die: a DIE
268 *
269 * Ensure that this DIE is a subprogram and NOT a declaration. This
270 * returns true if @dw_die is a function definition.
271 **/
272bool die_is_func_def(Dwarf_Die *dw_die)
273{
274 Dwarf_Attribute attr;
275
276 return (dwarf_tag(dw_die) == DW_TAG_subprogram &&
277 dwarf_attr(dw_die, DW_AT_declaration, &attr) == NULL);
278}
279
280/**
266 * die_get_data_member_location - Get the data-member offset 281 * die_get_data_member_location - Get the data-member offset
267 * @mb_die: a DIE of a member of a data structure 282 * @mb_die: a DIE of a member of a data structure
268 * @offs: The offset of the member in the data structure 283 * @offs: The offset of the member in the data structure
@@ -392,6 +407,10 @@ static int __die_search_func_cb(Dwarf_Die *fn_die, void *data)
392{ 407{
393 struct __addr_die_search_param *ad = data; 408 struct __addr_die_search_param *ad = data;
394 409
410 /*
411 * Since a declaration entry doesn't has given pc, this always returns
412 * function definition entry.
413 */
395 if (dwarf_tag(fn_die) == DW_TAG_subprogram && 414 if (dwarf_tag(fn_die) == DW_TAG_subprogram &&
396 dwarf_haspc(fn_die, ad->addr)) { 415 dwarf_haspc(fn_die, ad->addr)) {
397 memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die)); 416 memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die));
diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h
index 6ce1717784b7..8658d41697d2 100644
--- a/tools/perf/util/dwarf-aux.h
+++ b/tools/perf/util/dwarf-aux.h
@@ -38,6 +38,9 @@ extern int cu_find_lineinfo(Dwarf_Die *cudie, unsigned long addr,
38extern int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr, 38extern int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr,
39 int (*callback)(Dwarf_Die *, void *), void *data); 39 int (*callback)(Dwarf_Die *, void *), void *data);
40 40
41/* Ensure that this DIE is a subprogram and definition (not declaration) */
42extern bool die_is_func_def(Dwarf_Die *dw_die);
43
41/* Compare diename and tname */ 44/* Compare diename and tname */
42extern bool die_compare_name(Dwarf_Die *dw_die, const char *tname); 45extern bool die_compare_name(Dwarf_Die *dw_die, const char *tname);
43 46
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 5cd13d768cec..9b393e7dca6f 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -11,6 +11,7 @@
11static const char *perf_event__names[] = { 11static const char *perf_event__names[] = {
12 [0] = "TOTAL", 12 [0] = "TOTAL",
13 [PERF_RECORD_MMAP] = "MMAP", 13 [PERF_RECORD_MMAP] = "MMAP",
14 [PERF_RECORD_MMAP2] = "MMAP2",
14 [PERF_RECORD_LOST] = "LOST", 15 [PERF_RECORD_LOST] = "LOST",
15 [PERF_RECORD_COMM] = "COMM", 16 [PERF_RECORD_COMM] = "COMM",
16 [PERF_RECORD_EXIT] = "EXIT", 17 [PERF_RECORD_EXIT] = "EXIT",
@@ -186,7 +187,7 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
186 return -1; 187 return -1;
187 } 188 }
188 189
189 event->header.type = PERF_RECORD_MMAP; 190 event->header.type = PERF_RECORD_MMAP2;
190 /* 191 /*
191 * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c 192 * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c
192 */ 193 */
@@ -197,7 +198,9 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
197 char prot[5]; 198 char prot[5];
198 char execname[PATH_MAX]; 199 char execname[PATH_MAX];
199 char anonstr[] = "//anon"; 200 char anonstr[] = "//anon";
201 unsigned int ino;
200 size_t size; 202 size_t size;
203 ssize_t n;
201 204
202 if (fgets(bf, sizeof(bf), fp) == NULL) 205 if (fgets(bf, sizeof(bf), fp) == NULL)
203 break; 206 break;
@@ -206,9 +209,16 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
206 strcpy(execname, ""); 209 strcpy(execname, "");
207 210
208 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ 211 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
209 sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %*x:%*x %*u %s\n", 212 n = sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %x:%x %u %s\n",
210 &event->mmap.start, &event->mmap.len, prot, 213 &event->mmap2.start, &event->mmap2.len, prot,
211 &event->mmap.pgoff, execname); 214 &event->mmap2.pgoff, &event->mmap2.maj,
215 &event->mmap2.min,
216 &ino, execname);
217
218 event->mmap2.ino = (u64)ino;
219
220 if (n != 8)
221 continue;
212 222
213 if (prot[2] != 'x') 223 if (prot[2] != 'x')
214 continue; 224 continue;
@@ -217,15 +227,15 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
217 strcpy(execname, anonstr); 227 strcpy(execname, anonstr);
218 228
219 size = strlen(execname) + 1; 229 size = strlen(execname) + 1;
220 memcpy(event->mmap.filename, execname, size); 230 memcpy(event->mmap2.filename, execname, size);
221 size = PERF_ALIGN(size, sizeof(u64)); 231 size = PERF_ALIGN(size, sizeof(u64));
222 event->mmap.len -= event->mmap.start; 232 event->mmap2.len -= event->mmap.start;
223 event->mmap.header.size = (sizeof(event->mmap) - 233 event->mmap2.header.size = (sizeof(event->mmap2) -
224 (sizeof(event->mmap.filename) - size)); 234 (sizeof(event->mmap2.filename) - size));
225 memset(event->mmap.filename + size, 0, machine->id_hdr_size); 235 memset(event->mmap2.filename + size, 0, machine->id_hdr_size);
226 event->mmap.header.size += machine->id_hdr_size; 236 event->mmap2.header.size += machine->id_hdr_size;
227 event->mmap.pid = tgid; 237 event->mmap2.pid = tgid;
228 event->mmap.tid = pid; 238 event->mmap2.tid = pid;
229 239
230 if (process(tool, event, &synth_sample, machine) != 0) { 240 if (process(tool, event, &synth_sample, machine) != 0) {
231 rc = -1; 241 rc = -1;
@@ -527,6 +537,17 @@ size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp)
527 event->mmap.len, event->mmap.pgoff, event->mmap.filename); 537 event->mmap.len, event->mmap.pgoff, event->mmap.filename);
528} 538}
529 539
540size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp)
541{
542 return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64
543 " %02x:%02x %"PRIu64" %"PRIu64"]: %s\n",
544 event->mmap2.pid, event->mmap2.tid, event->mmap2.start,
545 event->mmap2.len, event->mmap2.pgoff, event->mmap2.maj,
546 event->mmap2.min, event->mmap2.ino,
547 event->mmap2.ino_generation,
548 event->mmap2.filename);
549}
550
530int perf_event__process_mmap(struct perf_tool *tool __maybe_unused, 551int perf_event__process_mmap(struct perf_tool *tool __maybe_unused,
531 union perf_event *event, 552 union perf_event *event,
532 struct perf_sample *sample __maybe_unused, 553 struct perf_sample *sample __maybe_unused,
@@ -535,6 +556,14 @@ int perf_event__process_mmap(struct perf_tool *tool __maybe_unused,
535 return machine__process_mmap_event(machine, event); 556 return machine__process_mmap_event(machine, event);
536} 557}
537 558
559int perf_event__process_mmap2(struct perf_tool *tool __maybe_unused,
560 union perf_event *event,
561 struct perf_sample *sample __maybe_unused,
562 struct machine *machine)
563{
564 return machine__process_mmap2_event(machine, event);
565}
566
538size_t perf_event__fprintf_task(union perf_event *event, FILE *fp) 567size_t perf_event__fprintf_task(union perf_event *event, FILE *fp)
539{ 568{
540 return fprintf(fp, "(%d:%d):(%d:%d)\n", 569 return fprintf(fp, "(%d:%d):(%d:%d)\n",
@@ -574,6 +603,9 @@ size_t perf_event__fprintf(union perf_event *event, FILE *fp)
574 case PERF_RECORD_MMAP: 603 case PERF_RECORD_MMAP:
575 ret += perf_event__fprintf_mmap(event, fp); 604 ret += perf_event__fprintf_mmap(event, fp);
576 break; 605 break;
606 case PERF_RECORD_MMAP2:
607 ret += perf_event__fprintf_mmap2(event, fp);
608 break;
577 default: 609 default:
578 ret += fprintf(fp, "\n"); 610 ret += fprintf(fp, "\n");
579 } 611 }
@@ -595,6 +627,7 @@ void thread__find_addr_map(struct thread *self,
595 struct addr_location *al) 627 struct addr_location *al)
596{ 628{
597 struct map_groups *mg = &self->mg; 629 struct map_groups *mg = &self->mg;
630 bool load_map = false;
598 631
599 al->thread = self; 632 al->thread = self;
600 al->addr = addr; 633 al->addr = addr;
@@ -609,11 +642,13 @@ void thread__find_addr_map(struct thread *self,
609 if (cpumode == PERF_RECORD_MISC_KERNEL && perf_host) { 642 if (cpumode == PERF_RECORD_MISC_KERNEL && perf_host) {
610 al->level = 'k'; 643 al->level = 'k';
611 mg = &machine->kmaps; 644 mg = &machine->kmaps;
645 load_map = true;
612 } else if (cpumode == PERF_RECORD_MISC_USER && perf_host) { 646 } else if (cpumode == PERF_RECORD_MISC_USER && perf_host) {
613 al->level = '.'; 647 al->level = '.';
614 } else if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) { 648 } else if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) {
615 al->level = 'g'; 649 al->level = 'g';
616 mg = &machine->kmaps; 650 mg = &machine->kmaps;
651 load_map = true;
617 } else { 652 } else {
618 /* 653 /*
619 * 'u' means guest os user space. 654 * 'u' means guest os user space.
@@ -654,18 +689,25 @@ try_again:
654 mg = &machine->kmaps; 689 mg = &machine->kmaps;
655 goto try_again; 690 goto try_again;
656 } 691 }
657 } else 692 } else {
693 /*
694 * Kernel maps might be changed when loading symbols so loading
695 * must be done prior to using kernel maps.
696 */
697 if (load_map)
698 map__load(al->map, machine->symbol_filter);
658 al->addr = al->map->map_ip(al->map, al->addr); 699 al->addr = al->map->map_ip(al->map, al->addr);
700 }
659} 701}
660 702
661void thread__find_addr_location(struct thread *thread, struct machine *machine, 703void thread__find_addr_location(struct thread *thread, struct machine *machine,
662 u8 cpumode, enum map_type type, u64 addr, 704 u8 cpumode, enum map_type type, u64 addr,
663 struct addr_location *al, 705 struct addr_location *al)
664 symbol_filter_t filter)
665{ 706{
666 thread__find_addr_map(thread, machine, cpumode, type, addr, al); 707 thread__find_addr_map(thread, machine, cpumode, type, addr, al);
667 if (al->map != NULL) 708 if (al->map != NULL)
668 al->sym = map__find_symbol(al->map, al->addr, filter); 709 al->sym = map__find_symbol(al->map, al->addr,
710 machine->symbol_filter);
669 else 711 else
670 al->sym = NULL; 712 al->sym = NULL;
671} 713}
@@ -673,11 +715,11 @@ void thread__find_addr_location(struct thread *thread, struct machine *machine,
673int perf_event__preprocess_sample(const union perf_event *event, 715int perf_event__preprocess_sample(const union perf_event *event,
674 struct machine *machine, 716 struct machine *machine,
675 struct addr_location *al, 717 struct addr_location *al,
676 struct perf_sample *sample, 718 struct perf_sample *sample)
677 symbol_filter_t filter)
678{ 719{
679 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 720 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
680 struct thread *thread = machine__findnew_thread(machine, event->ip.pid); 721 struct thread *thread = machine__findnew_thread(machine, sample->pid,
722 sample->pid);
681 723
682 if (thread == NULL) 724 if (thread == NULL)
683 return -1; 725 return -1;
@@ -686,7 +728,7 @@ int perf_event__preprocess_sample(const union perf_event *event,
686 !strlist__has_entry(symbol_conf.comm_list, thread->comm)) 728 !strlist__has_entry(symbol_conf.comm_list, thread->comm))
687 goto out_filtered; 729 goto out_filtered;
688 730
689 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 731 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->tid);
690 /* 732 /*
691 * Have we already created the kernel maps for this machine? 733 * Have we already created the kernel maps for this machine?
692 * 734 *
@@ -699,7 +741,7 @@ int perf_event__preprocess_sample(const union perf_event *event,
699 machine__create_kernel_maps(machine); 741 machine__create_kernel_maps(machine);
700 742
701 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, 743 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
702 event->ip.ip, al); 744 sample->ip, al);
703 dump_printf(" ...... dso: %s\n", 745 dump_printf(" ...... dso: %s\n",
704 al->map ? al->map->dso->long_name : 746 al->map ? al->map->dso->long_name :
705 al->level == 'H' ? "[hypervisor]" : "<not found>"); 747 al->level == 'H' ? "[hypervisor]" : "<not found>");
@@ -717,7 +759,8 @@ int perf_event__preprocess_sample(const union perf_event *event,
717 dso->long_name))))) 759 dso->long_name)))))
718 goto out_filtered; 760 goto out_filtered;
719 761
720 al->sym = map__find_symbol(al->map, al->addr, filter); 762 al->sym = map__find_symbol(al->map, al->addr,
763 machine->symbol_filter);
721 } 764 }
722 765
723 if (symbol_conf.sym_list && 766 if (symbol_conf.sym_list &&
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 181389535c0c..c67ecc457d29 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -8,22 +8,25 @@
8#include "map.h" 8#include "map.h"
9#include "build-id.h" 9#include "build-id.h"
10 10
11/* 11struct mmap_event {
12 * PERF_SAMPLE_IP | PERF_SAMPLE_TID | *
13 */
14struct ip_event {
15 struct perf_event_header header; 12 struct perf_event_header header;
16 u64 ip;
17 u32 pid, tid; 13 u32 pid, tid;
18 unsigned char __more_data[]; 14 u64 start;
15 u64 len;
16 u64 pgoff;
17 char filename[PATH_MAX];
19}; 18};
20 19
21struct mmap_event { 20struct mmap2_event {
22 struct perf_event_header header; 21 struct perf_event_header header;
23 u32 pid, tid; 22 u32 pid, tid;
24 u64 start; 23 u64 start;
25 u64 len; 24 u64 len;
26 u64 pgoff; 25 u64 pgoff;
26 u32 maj;
27 u32 min;
28 u64 ino;
29 u64 ino_generation;
27 char filename[PATH_MAX]; 30 char filename[PATH_MAX];
28}; 31};
29 32
@@ -63,7 +66,8 @@ struct read_event {
63 (PERF_SAMPLE_IP | PERF_SAMPLE_TID | \ 66 (PERF_SAMPLE_IP | PERF_SAMPLE_TID | \
64 PERF_SAMPLE_TIME | PERF_SAMPLE_ADDR | \ 67 PERF_SAMPLE_TIME | PERF_SAMPLE_ADDR | \
65 PERF_SAMPLE_ID | PERF_SAMPLE_STREAM_ID | \ 68 PERF_SAMPLE_ID | PERF_SAMPLE_STREAM_ID | \
66 PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD) 69 PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD | \
70 PERF_SAMPLE_IDENTIFIER)
67 71
68struct sample_event { 72struct sample_event {
69 struct perf_event_header header; 73 struct perf_event_header header;
@@ -71,6 +75,7 @@ struct sample_event {
71}; 75};
72 76
73struct regs_dump { 77struct regs_dump {
78 u64 abi;
74 u64 *regs; 79 u64 *regs;
75}; 80};
76 81
@@ -80,6 +85,23 @@ struct stack_dump {
80 char *data; 85 char *data;
81}; 86};
82 87
88struct sample_read_value {
89 u64 value;
90 u64 id;
91};
92
93struct sample_read {
94 u64 time_enabled;
95 u64 time_running;
96 union {
97 struct {
98 u64 nr;
99 struct sample_read_value *values;
100 } group;
101 struct sample_read_value one;
102 };
103};
104
83struct perf_sample { 105struct perf_sample {
84 u64 ip; 106 u64 ip;
85 u32 pid, tid; 107 u32 pid, tid;
@@ -97,6 +119,7 @@ struct perf_sample {
97 struct branch_stack *branch_stack; 119 struct branch_stack *branch_stack;
98 struct regs_dump user_regs; 120 struct regs_dump user_regs;
99 struct stack_dump user_stack; 121 struct stack_dump user_stack;
122 struct sample_read read;
100}; 123};
101 124
102#define PERF_MEM_DATA_SRC_NONE \ 125#define PERF_MEM_DATA_SRC_NONE \
@@ -116,7 +139,7 @@ struct build_id_event {
116enum perf_user_event_type { /* above any possible kernel type */ 139enum perf_user_event_type { /* above any possible kernel type */
117 PERF_RECORD_USER_TYPE_START = 64, 140 PERF_RECORD_USER_TYPE_START = 64,
118 PERF_RECORD_HEADER_ATTR = 64, 141 PERF_RECORD_HEADER_ATTR = 64,
119 PERF_RECORD_HEADER_EVENT_TYPE = 65, 142 PERF_RECORD_HEADER_EVENT_TYPE = 65, /* depreceated */
120 PERF_RECORD_HEADER_TRACING_DATA = 66, 143 PERF_RECORD_HEADER_TRACING_DATA = 66,
121 PERF_RECORD_HEADER_BUILD_ID = 67, 144 PERF_RECORD_HEADER_BUILD_ID = 67,
122 PERF_RECORD_FINISHED_ROUND = 68, 145 PERF_RECORD_FINISHED_ROUND = 68,
@@ -148,8 +171,8 @@ struct tracing_data_event {
148 171
149union perf_event { 172union perf_event {
150 struct perf_event_header header; 173 struct perf_event_header header;
151 struct ip_event ip;
152 struct mmap_event mmap; 174 struct mmap_event mmap;
175 struct mmap2_event mmap2;
153 struct comm_event comm; 176 struct comm_event comm;
154 struct fork_event fork; 177 struct fork_event fork;
155 struct lost_event lost; 178 struct lost_event lost;
@@ -199,6 +222,10 @@ int perf_event__process_mmap(struct perf_tool *tool,
199 union perf_event *event, 222 union perf_event *event,
200 struct perf_sample *sample, 223 struct perf_sample *sample,
201 struct machine *machine); 224 struct machine *machine);
225int perf_event__process_mmap2(struct perf_tool *tool,
226 union perf_event *event,
227 struct perf_sample *sample,
228 struct machine *machine);
202int perf_event__process_fork(struct perf_tool *tool, 229int perf_event__process_fork(struct perf_tool *tool,
203 union perf_event *event, 230 union perf_event *event,
204 struct perf_sample *sample, 231 struct perf_sample *sample,
@@ -216,17 +243,20 @@ struct addr_location;
216int perf_event__preprocess_sample(const union perf_event *self, 243int perf_event__preprocess_sample(const union perf_event *self,
217 struct machine *machine, 244 struct machine *machine,
218 struct addr_location *al, 245 struct addr_location *al,
219 struct perf_sample *sample, 246 struct perf_sample *sample);
220 symbol_filter_t filter);
221 247
222const char *perf_event__name(unsigned int id); 248const char *perf_event__name(unsigned int id);
223 249
250size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
251 u64 sample_regs_user, u64 read_format);
224int perf_event__synthesize_sample(union perf_event *event, u64 type, 252int perf_event__synthesize_sample(union perf_event *event, u64 type,
253 u64 sample_regs_user, u64 read_format,
225 const struct perf_sample *sample, 254 const struct perf_sample *sample,
226 bool swapped); 255 bool swapped);
227 256
228size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp); 257size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp);
229size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp); 258size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp);
259size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp);
230size_t perf_event__fprintf_task(union perf_event *event, FILE *fp); 260size_t perf_event__fprintf_task(union perf_event *event, FILE *fp);
231size_t perf_event__fprintf(union perf_event *event, FILE *fp); 261size_t perf_event__fprintf(union perf_event *event, FILE *fp);
232 262
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 8065ce8fa9a5..f9f77bee0b1b 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -14,6 +14,7 @@
14#include "target.h" 14#include "target.h"
15#include "evlist.h" 15#include "evlist.h"
16#include "evsel.h" 16#include "evsel.h"
17#include "debug.h"
17#include <unistd.h> 18#include <unistd.h>
18 19
19#include "parse-events.h" 20#include "parse-events.h"
@@ -48,26 +49,29 @@ struct perf_evlist *perf_evlist__new(void)
48 return evlist; 49 return evlist;
49} 50}
50 51
51void perf_evlist__config(struct perf_evlist *evlist, 52/**
52 struct perf_record_opts *opts) 53 * perf_evlist__set_id_pos - set the positions of event ids.
54 * @evlist: selected event list
55 *
56 * Events with compatible sample types all have the same id_pos
57 * and is_pos. For convenience, put a copy on evlist.
58 */
59void perf_evlist__set_id_pos(struct perf_evlist *evlist)
53{ 60{
54 struct perf_evsel *evsel; 61 struct perf_evsel *first = perf_evlist__first(evlist);
55 /*
56 * Set the evsel leader links before we configure attributes,
57 * since some might depend on this info.
58 */
59 if (opts->group)
60 perf_evlist__set_leader(evlist);
61 62
62 if (evlist->cpus->map[0] < 0) 63 evlist->id_pos = first->id_pos;
63 opts->no_inherit = true; 64 evlist->is_pos = first->is_pos;
65}
64 66
65 list_for_each_entry(evsel, &evlist->entries, node) { 67static void perf_evlist__update_id_pos(struct perf_evlist *evlist)
66 perf_evsel__config(evsel, opts); 68{
69 struct perf_evsel *evsel;
67 70
68 if (evlist->nr_entries > 1) 71 list_for_each_entry(evsel, &evlist->entries, node)
69 perf_evsel__set_sample_id(evsel); 72 perf_evsel__calc_id_pos(evsel);
70 } 73
74 perf_evlist__set_id_pos(evlist);
71} 75}
72 76
73static void perf_evlist__purge(struct perf_evlist *evlist) 77static void perf_evlist__purge(struct perf_evlist *evlist)
@@ -100,15 +104,20 @@ void perf_evlist__delete(struct perf_evlist *evlist)
100void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry) 104void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry)
101{ 105{
102 list_add_tail(&entry->node, &evlist->entries); 106 list_add_tail(&entry->node, &evlist->entries);
103 ++evlist->nr_entries; 107 if (!evlist->nr_entries++)
108 perf_evlist__set_id_pos(evlist);
104} 109}
105 110
106void perf_evlist__splice_list_tail(struct perf_evlist *evlist, 111void perf_evlist__splice_list_tail(struct perf_evlist *evlist,
107 struct list_head *list, 112 struct list_head *list,
108 int nr_entries) 113 int nr_entries)
109{ 114{
115 bool set_id_pos = !evlist->nr_entries;
116
110 list_splice_tail(list, &evlist->entries); 117 list_splice_tail(list, &evlist->entries);
111 evlist->nr_entries += nr_entries; 118 evlist->nr_entries += nr_entries;
119 if (set_id_pos)
120 perf_evlist__set_id_pos(evlist);
112} 121}
113 122
114void __perf_evlist__set_leader(struct list_head *list) 123void __perf_evlist__set_leader(struct list_head *list)
@@ -209,6 +218,21 @@ perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id)
209 return NULL; 218 return NULL;
210} 219}
211 220
221struct perf_evsel *
222perf_evlist__find_tracepoint_by_name(struct perf_evlist *evlist,
223 const char *name)
224{
225 struct perf_evsel *evsel;
226
227 list_for_each_entry(evsel, &evlist->entries, node) {
228 if ((evsel->attr.type == PERF_TYPE_TRACEPOINT) &&
229 (strcmp(evsel->name, name) == 0))
230 return evsel;
231 }
232
233 return NULL;
234}
235
212int perf_evlist__add_newtp(struct perf_evlist *evlist, 236int perf_evlist__add_newtp(struct perf_evlist *evlist,
213 const char *sys, const char *name, void *handler) 237 const char *sys, const char *name, void *handler)
214{ 238{
@@ -232,7 +256,7 @@ void perf_evlist__disable(struct perf_evlist *evlist)
232 256
233 for (cpu = 0; cpu < nr_cpus; cpu++) { 257 for (cpu = 0; cpu < nr_cpus; cpu++) {
234 list_for_each_entry(pos, &evlist->entries, node) { 258 list_for_each_entry(pos, &evlist->entries, node) {
235 if (!perf_evsel__is_group_leader(pos)) 259 if (!perf_evsel__is_group_leader(pos) || !pos->fd)
236 continue; 260 continue;
237 for (thread = 0; thread < nr_threads; thread++) 261 for (thread = 0; thread < nr_threads; thread++)
238 ioctl(FD(pos, cpu, thread), 262 ioctl(FD(pos, cpu, thread),
@@ -250,7 +274,7 @@ void perf_evlist__enable(struct perf_evlist *evlist)
250 274
251 for (cpu = 0; cpu < nr_cpus; cpu++) { 275 for (cpu = 0; cpu < nr_cpus; cpu++) {
252 list_for_each_entry(pos, &evlist->entries, node) { 276 list_for_each_entry(pos, &evlist->entries, node) {
253 if (!perf_evsel__is_group_leader(pos)) 277 if (!perf_evsel__is_group_leader(pos) || !pos->fd)
254 continue; 278 continue;
255 for (thread = 0; thread < nr_threads; thread++) 279 for (thread = 0; thread < nr_threads; thread++)
256 ioctl(FD(pos, cpu, thread), 280 ioctl(FD(pos, cpu, thread),
@@ -259,6 +283,44 @@ void perf_evlist__enable(struct perf_evlist *evlist)
259 } 283 }
260} 284}
261 285
286int perf_evlist__disable_event(struct perf_evlist *evlist,
287 struct perf_evsel *evsel)
288{
289 int cpu, thread, err;
290
291 if (!evsel->fd)
292 return 0;
293
294 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
295 for (thread = 0; thread < evlist->threads->nr; thread++) {
296 err = ioctl(FD(evsel, cpu, thread),
297 PERF_EVENT_IOC_DISABLE, 0);
298 if (err)
299 return err;
300 }
301 }
302 return 0;
303}
304
305int perf_evlist__enable_event(struct perf_evlist *evlist,
306 struct perf_evsel *evsel)
307{
308 int cpu, thread, err;
309
310 if (!evsel->fd)
311 return -EINVAL;
312
313 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
314 for (thread = 0; thread < evlist->threads->nr; thread++) {
315 err = ioctl(FD(evsel, cpu, thread),
316 PERF_EVENT_IOC_ENABLE, 0);
317 if (err)
318 return err;
319 }
320 }
321 return 0;
322}
323
262static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) 324static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
263{ 325{
264 int nr_cpus = cpu_map__nr(evlist->cpus); 326 int nr_cpus = cpu_map__nr(evlist->cpus);
@@ -302,6 +364,24 @@ static int perf_evlist__id_add_fd(struct perf_evlist *evlist,
302{ 364{
303 u64 read_data[4] = { 0, }; 365 u64 read_data[4] = { 0, };
304 int id_idx = 1; /* The first entry is the counter value */ 366 int id_idx = 1; /* The first entry is the counter value */
367 u64 id;
368 int ret;
369
370 ret = ioctl(fd, PERF_EVENT_IOC_ID, &id);
371 if (!ret)
372 goto add;
373
374 if (errno != ENOTTY)
375 return -1;
376
377 /* Legacy way to get event id.. All hail to old kernels! */
378
379 /*
380 * This way does not work with group format read, so bail
381 * out in that case.
382 */
383 if (perf_evlist__read_format(evlist) & PERF_FORMAT_GROUP)
384 return -1;
305 385
306 if (!(evsel->attr.read_format & PERF_FORMAT_ID) || 386 if (!(evsel->attr.read_format & PERF_FORMAT_ID) ||
307 read(fd, &read_data, sizeof(read_data)) == -1) 387 read(fd, &read_data, sizeof(read_data)) == -1)
@@ -312,25 +392,39 @@ static int perf_evlist__id_add_fd(struct perf_evlist *evlist,
312 if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) 392 if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
313 ++id_idx; 393 ++id_idx;
314 394
315 perf_evlist__id_add(evlist, evsel, cpu, thread, read_data[id_idx]); 395 id = read_data[id_idx];
396
397 add:
398 perf_evlist__id_add(evlist, evsel, cpu, thread, id);
316 return 0; 399 return 0;
317} 400}
318 401
319struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id) 402struct perf_sample_id *perf_evlist__id2sid(struct perf_evlist *evlist, u64 id)
320{ 403{
321 struct hlist_head *head; 404 struct hlist_head *head;
322 struct perf_sample_id *sid; 405 struct perf_sample_id *sid;
323 int hash; 406 int hash;
324 407
325 if (evlist->nr_entries == 1)
326 return perf_evlist__first(evlist);
327
328 hash = hash_64(id, PERF_EVLIST__HLIST_BITS); 408 hash = hash_64(id, PERF_EVLIST__HLIST_BITS);
329 head = &evlist->heads[hash]; 409 head = &evlist->heads[hash];
330 410
331 hlist_for_each_entry(sid, head, node) 411 hlist_for_each_entry(sid, head, node)
332 if (sid->id == id) 412 if (sid->id == id)
333 return sid->evsel; 413 return sid;
414
415 return NULL;
416}
417
418struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id)
419{
420 struct perf_sample_id *sid;
421
422 if (evlist->nr_entries == 1)
423 return perf_evlist__first(evlist);
424
425 sid = perf_evlist__id2sid(evlist, id);
426 if (sid)
427 return sid->evsel;
334 428
335 if (!perf_evlist__sample_id_all(evlist)) 429 if (!perf_evlist__sample_id_all(evlist))
336 return perf_evlist__first(evlist); 430 return perf_evlist__first(evlist);
@@ -338,6 +432,60 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id)
338 return NULL; 432 return NULL;
339} 433}
340 434
435static int perf_evlist__event2id(struct perf_evlist *evlist,
436 union perf_event *event, u64 *id)
437{
438 const u64 *array = event->sample.array;
439 ssize_t n;
440
441 n = (event->header.size - sizeof(event->header)) >> 3;
442
443 if (event->header.type == PERF_RECORD_SAMPLE) {
444 if (evlist->id_pos >= n)
445 return -1;
446 *id = array[evlist->id_pos];
447 } else {
448 if (evlist->is_pos > n)
449 return -1;
450 n -= evlist->is_pos;
451 *id = array[n];
452 }
453 return 0;
454}
455
456static struct perf_evsel *perf_evlist__event2evsel(struct perf_evlist *evlist,
457 union perf_event *event)
458{
459 struct perf_evsel *first = perf_evlist__first(evlist);
460 struct hlist_head *head;
461 struct perf_sample_id *sid;
462 int hash;
463 u64 id;
464
465 if (evlist->nr_entries == 1)
466 return first;
467
468 if (!first->attr.sample_id_all &&
469 event->header.type != PERF_RECORD_SAMPLE)
470 return first;
471
472 if (perf_evlist__event2id(evlist, event, &id))
473 return NULL;
474
475 /* Synthesized events have an id of zero */
476 if (!id)
477 return first;
478
479 hash = hash_64(id, PERF_EVLIST__HLIST_BITS);
480 head = &evlist->heads[hash];
481
482 hlist_for_each_entry(sid, head, node) {
483 if (sid->id == id)
484 return sid->evsel;
485 }
486 return NULL;
487}
488
341union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) 489union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
342{ 490{
343 struct perf_mmap *md = &evlist->mmap[idx]; 491 struct perf_mmap *md = &evlist->mmap[idx];
@@ -403,16 +551,20 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
403 return event; 551 return event;
404} 552}
405 553
554static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx)
555{
556 if (evlist->mmap[idx].base != NULL) {
557 munmap(evlist->mmap[idx].base, evlist->mmap_len);
558 evlist->mmap[idx].base = NULL;
559 }
560}
561
406void perf_evlist__munmap(struct perf_evlist *evlist) 562void perf_evlist__munmap(struct perf_evlist *evlist)
407{ 563{
408 int i; 564 int i;
409 565
410 for (i = 0; i < evlist->nr_mmaps; i++) { 566 for (i = 0; i < evlist->nr_mmaps; i++)
411 if (evlist->mmap[i].base != NULL) { 567 __perf_evlist__munmap(evlist, i);
412 munmap(evlist->mmap[i].base, evlist->mmap_len);
413 evlist->mmap[i].base = NULL;
414 }
415 }
416 568
417 free(evlist->mmap); 569 free(evlist->mmap);
418 evlist->mmap = NULL; 570 evlist->mmap = NULL;
@@ -421,7 +573,7 @@ void perf_evlist__munmap(struct perf_evlist *evlist)
421static int perf_evlist__alloc_mmap(struct perf_evlist *evlist) 573static int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
422{ 574{
423 evlist->nr_mmaps = cpu_map__nr(evlist->cpus); 575 evlist->nr_mmaps = cpu_map__nr(evlist->cpus);
424 if (cpu_map__all(evlist->cpus)) 576 if (cpu_map__empty(evlist->cpus))
425 evlist->nr_mmaps = thread_map__nr(evlist->threads); 577 evlist->nr_mmaps = thread_map__nr(evlist->threads);
426 evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap)); 578 evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap));
427 return evlist->mmap != NULL ? 0 : -ENOMEM; 579 return evlist->mmap != NULL ? 0 : -ENOMEM;
@@ -450,6 +602,7 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int m
450 int nr_cpus = cpu_map__nr(evlist->cpus); 602 int nr_cpus = cpu_map__nr(evlist->cpus);
451 int nr_threads = thread_map__nr(evlist->threads); 603 int nr_threads = thread_map__nr(evlist->threads);
452 604
605 pr_debug2("perf event ring buffer mmapped per cpu\n");
453 for (cpu = 0; cpu < nr_cpus; cpu++) { 606 for (cpu = 0; cpu < nr_cpus; cpu++) {
454 int output = -1; 607 int output = -1;
455 608
@@ -477,12 +630,8 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int m
477 return 0; 630 return 0;
478 631
479out_unmap: 632out_unmap:
480 for (cpu = 0; cpu < nr_cpus; cpu++) { 633 for (cpu = 0; cpu < nr_cpus; cpu++)
481 if (evlist->mmap[cpu].base != NULL) { 634 __perf_evlist__munmap(evlist, cpu);
482 munmap(evlist->mmap[cpu].base, evlist->mmap_len);
483 evlist->mmap[cpu].base = NULL;
484 }
485 }
486 return -1; 635 return -1;
487} 636}
488 637
@@ -492,6 +641,7 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, in
492 int thread; 641 int thread;
493 int nr_threads = thread_map__nr(evlist->threads); 642 int nr_threads = thread_map__nr(evlist->threads);
494 643
644 pr_debug2("perf event ring buffer mmapped per thread\n");
495 for (thread = 0; thread < nr_threads; thread++) { 645 for (thread = 0; thread < nr_threads; thread++) {
496 int output = -1; 646 int output = -1;
497 647
@@ -517,12 +667,8 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, in
517 return 0; 667 return 0;
518 668
519out_unmap: 669out_unmap:
520 for (thread = 0; thread < nr_threads; thread++) { 670 for (thread = 0; thread < nr_threads; thread++)
521 if (evlist->mmap[thread].base != NULL) { 671 __perf_evlist__munmap(evlist, thread);
522 munmap(evlist->mmap[thread].base, evlist->mmap_len);
523 evlist->mmap[thread].base = NULL;
524 }
525 }
526 return -1; 672 return -1;
527} 673}
528 674
@@ -573,7 +719,7 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
573 return -ENOMEM; 719 return -ENOMEM;
574 } 720 }
575 721
576 if (cpu_map__all(cpus)) 722 if (cpu_map__empty(cpus))
577 return perf_evlist__mmap_per_thread(evlist, prot, mask); 723 return perf_evlist__mmap_per_thread(evlist, prot, mask);
578 724
579 return perf_evlist__mmap_per_cpu(evlist, prot, mask); 725 return perf_evlist__mmap_per_cpu(evlist, prot, mask);
@@ -650,20 +796,66 @@ int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter)
650 796
651bool perf_evlist__valid_sample_type(struct perf_evlist *evlist) 797bool perf_evlist__valid_sample_type(struct perf_evlist *evlist)
652{ 798{
799 struct perf_evsel *pos;
800
801 if (evlist->nr_entries == 1)
802 return true;
803
804 if (evlist->id_pos < 0 || evlist->is_pos < 0)
805 return false;
806
807 list_for_each_entry(pos, &evlist->entries, node) {
808 if (pos->id_pos != evlist->id_pos ||
809 pos->is_pos != evlist->is_pos)
810 return false;
811 }
812
813 return true;
814}
815
816u64 __perf_evlist__combined_sample_type(struct perf_evlist *evlist)
817{
818 struct perf_evsel *evsel;
819
820 if (evlist->combined_sample_type)
821 return evlist->combined_sample_type;
822
823 list_for_each_entry(evsel, &evlist->entries, node)
824 evlist->combined_sample_type |= evsel->attr.sample_type;
825
826 return evlist->combined_sample_type;
827}
828
829u64 perf_evlist__combined_sample_type(struct perf_evlist *evlist)
830{
831 evlist->combined_sample_type = 0;
832 return __perf_evlist__combined_sample_type(evlist);
833}
834
835bool perf_evlist__valid_read_format(struct perf_evlist *evlist)
836{
653 struct perf_evsel *first = perf_evlist__first(evlist), *pos = first; 837 struct perf_evsel *first = perf_evlist__first(evlist), *pos = first;
838 u64 read_format = first->attr.read_format;
839 u64 sample_type = first->attr.sample_type;
654 840
655 list_for_each_entry_continue(pos, &evlist->entries, node) { 841 list_for_each_entry_continue(pos, &evlist->entries, node) {
656 if (first->attr.sample_type != pos->attr.sample_type) 842 if (read_format != pos->attr.read_format)
657 return false; 843 return false;
658 } 844 }
659 845
846 /* PERF_SAMPLE_READ imples PERF_FORMAT_ID. */
847 if ((sample_type & PERF_SAMPLE_READ) &&
848 !(read_format & PERF_FORMAT_ID)) {
849 return false;
850 }
851
660 return true; 852 return true;
661} 853}
662 854
663u64 perf_evlist__sample_type(struct perf_evlist *evlist) 855u64 perf_evlist__read_format(struct perf_evlist *evlist)
664{ 856{
665 struct perf_evsel *first = perf_evlist__first(evlist); 857 struct perf_evsel *first = perf_evlist__first(evlist);
666 return first->attr.sample_type; 858 return first->attr.read_format;
667} 859}
668 860
669u16 perf_evlist__id_hdr_size(struct perf_evlist *evlist) 861u16 perf_evlist__id_hdr_size(struct perf_evlist *evlist)
@@ -692,6 +884,9 @@ u16 perf_evlist__id_hdr_size(struct perf_evlist *evlist)
692 884
693 if (sample_type & PERF_SAMPLE_CPU) 885 if (sample_type & PERF_SAMPLE_CPU)
694 size += sizeof(data->cpu) * 2; 886 size += sizeof(data->cpu) * 2;
887
888 if (sample_type & PERF_SAMPLE_IDENTIFIER)
889 size += sizeof(data->id);
695out: 890out:
696 return size; 891 return size;
697} 892}
@@ -735,6 +930,8 @@ int perf_evlist__open(struct perf_evlist *evlist)
735 struct perf_evsel *evsel; 930 struct perf_evsel *evsel;
736 int err; 931 int err;
737 932
933 perf_evlist__update_id_pos(evlist);
934
738 list_for_each_entry(evsel, &evlist->entries, node) { 935 list_for_each_entry(evsel, &evlist->entries, node) {
739 err = perf_evsel__open(evsel, evlist->cpus, evlist->threads); 936 err = perf_evsel__open(evsel, evlist->cpus, evlist->threads);
740 if (err < 0) 937 if (err < 0)
@@ -783,13 +980,6 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist,
783 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC); 980 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
784 981
785 /* 982 /*
786 * Do a dummy execvp to get the PLT entry resolved,
787 * so we avoid the resolver overhead on the real
788 * execvp call.
789 */
790 execvp("", (char **)argv);
791
792 /*
793 * Tell the parent we're ready to go 983 * Tell the parent we're ready to go
794 */ 984 */
795 close(child_ready_pipe[1]); 985 close(child_ready_pipe[1]);
@@ -838,7 +1028,7 @@ out_close_ready_pipe:
838int perf_evlist__start_workload(struct perf_evlist *evlist) 1028int perf_evlist__start_workload(struct perf_evlist *evlist)
839{ 1029{
840 if (evlist->workload.cork_fd > 0) { 1030 if (evlist->workload.cork_fd > 0) {
841 char bf; 1031 char bf = 0;
842 int ret; 1032 int ret;
843 /* 1033 /*
844 * Remove the cork, let it rip! 1034 * Remove the cork, let it rip!
@@ -857,7 +1047,10 @@ int perf_evlist__start_workload(struct perf_evlist *evlist)
857int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event, 1047int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event,
858 struct perf_sample *sample) 1048 struct perf_sample *sample)
859{ 1049{
860 struct perf_evsel *evsel = perf_evlist__first(evlist); 1050 struct perf_evsel *evsel = perf_evlist__event2evsel(evlist, event);
1051
1052 if (!evsel)
1053 return -EFAULT;
861 return perf_evsel__parse_sample(evsel, event, sample); 1054 return perf_evsel__parse_sample(evsel, event, sample);
862} 1055}
863 1056
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 0583d36252be..880d7139d2fb 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -32,6 +32,9 @@ struct perf_evlist {
32 int nr_fds; 32 int nr_fds;
33 int nr_mmaps; 33 int nr_mmaps;
34 int mmap_len; 34 int mmap_len;
35 int id_pos;
36 int is_pos;
37 u64 combined_sample_type;
35 struct { 38 struct {
36 int cork_fd; 39 int cork_fd;
37 pid_t pid; 40 pid_t pid;
@@ -71,6 +74,10 @@ int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter);
71struct perf_evsel * 74struct perf_evsel *
72perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id); 75perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id);
73 76
77struct perf_evsel *
78perf_evlist__find_tracepoint_by_name(struct perf_evlist *evlist,
79 const char *name);
80
74void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel, 81void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel,
75 int cpu, int thread, u64 id); 82 int cpu, int thread, u64 id);
76 83
@@ -78,11 +85,15 @@ void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd);
78 85
79struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id); 86struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id);
80 87
88struct perf_sample_id *perf_evlist__id2sid(struct perf_evlist *evlist, u64 id);
89
81union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx); 90union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx);
82 91
83int perf_evlist__open(struct perf_evlist *evlist); 92int perf_evlist__open(struct perf_evlist *evlist);
84void perf_evlist__close(struct perf_evlist *evlist); 93void perf_evlist__close(struct perf_evlist *evlist);
85 94
95void perf_evlist__set_id_pos(struct perf_evlist *evlist);
96bool perf_can_sample_identifier(void);
86void perf_evlist__config(struct perf_evlist *evlist, 97void perf_evlist__config(struct perf_evlist *evlist,
87 struct perf_record_opts *opts); 98 struct perf_record_opts *opts);
88 99
@@ -99,6 +110,11 @@ void perf_evlist__munmap(struct perf_evlist *evlist);
99void perf_evlist__disable(struct perf_evlist *evlist); 110void perf_evlist__disable(struct perf_evlist *evlist);
100void perf_evlist__enable(struct perf_evlist *evlist); 111void perf_evlist__enable(struct perf_evlist *evlist);
101 112
113int perf_evlist__disable_event(struct perf_evlist *evlist,
114 struct perf_evsel *evsel);
115int perf_evlist__enable_event(struct perf_evlist *evlist,
116 struct perf_evsel *evsel);
117
102void perf_evlist__set_selected(struct perf_evlist *evlist, 118void perf_evlist__set_selected(struct perf_evlist *evlist,
103 struct perf_evsel *evsel); 119 struct perf_evsel *evsel);
104 120
@@ -118,7 +134,9 @@ int perf_evlist__apply_filters(struct perf_evlist *evlist);
118void __perf_evlist__set_leader(struct list_head *list); 134void __perf_evlist__set_leader(struct list_head *list);
119void perf_evlist__set_leader(struct perf_evlist *evlist); 135void perf_evlist__set_leader(struct perf_evlist *evlist);
120 136
121u64 perf_evlist__sample_type(struct perf_evlist *evlist); 137u64 perf_evlist__read_format(struct perf_evlist *evlist);
138u64 __perf_evlist__combined_sample_type(struct perf_evlist *evlist);
139u64 perf_evlist__combined_sample_type(struct perf_evlist *evlist);
122bool perf_evlist__sample_id_all(struct perf_evlist *evlist); 140bool perf_evlist__sample_id_all(struct perf_evlist *evlist);
123u16 perf_evlist__id_hdr_size(struct perf_evlist *evlist); 141u16 perf_evlist__id_hdr_size(struct perf_evlist *evlist);
124 142
@@ -127,6 +145,7 @@ int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *even
127 145
128bool perf_evlist__valid_sample_type(struct perf_evlist *evlist); 146bool perf_evlist__valid_sample_type(struct perf_evlist *evlist);
129bool perf_evlist__valid_sample_id_all(struct perf_evlist *evlist); 147bool perf_evlist__valid_sample_id_all(struct perf_evlist *evlist);
148bool perf_evlist__valid_read_format(struct perf_evlist *evlist);
130 149
131void perf_evlist__splice_list_tail(struct perf_evlist *evlist, 150void perf_evlist__splice_list_tail(struct perf_evlist *evlist,
132 struct list_head *list, 151 struct list_head *list,
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index c9c7494506a1..0ce9febf1ba0 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -9,27 +9,30 @@
9 9
10#include <byteswap.h> 10#include <byteswap.h>
11#include <linux/bitops.h> 11#include <linux/bitops.h>
12#include "asm/bug.h"
13#include <lk/debugfs.h> 12#include <lk/debugfs.h>
14#include "event-parse.h" 13#include <traceevent/event-parse.h>
14#include <linux/hw_breakpoint.h>
15#include <linux/perf_event.h>
16#include <sys/resource.h>
17#include "asm/bug.h"
15#include "evsel.h" 18#include "evsel.h"
16#include "evlist.h" 19#include "evlist.h"
17#include "util.h" 20#include "util.h"
18#include "cpumap.h" 21#include "cpumap.h"
19#include "thread_map.h" 22#include "thread_map.h"
20#include "target.h" 23#include "target.h"
21#include <linux/hw_breakpoint.h>
22#include <linux/perf_event.h>
23#include "perf_regs.h" 24#include "perf_regs.h"
25#include "debug.h"
24 26
25static struct { 27static struct {
26 bool sample_id_all; 28 bool sample_id_all;
27 bool exclude_guest; 29 bool exclude_guest;
30 bool mmap2;
28} perf_missing_features; 31} perf_missing_features;
29 32
30#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) 33#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
31 34
32static int __perf_evsel__sample_size(u64 sample_type) 35int __perf_evsel__sample_size(u64 sample_type)
33{ 36{
34 u64 mask = sample_type & PERF_SAMPLE_MASK; 37 u64 mask = sample_type & PERF_SAMPLE_MASK;
35 int size = 0; 38 int size = 0;
@@ -45,6 +48,72 @@ static int __perf_evsel__sample_size(u64 sample_type)
45 return size; 48 return size;
46} 49}
47 50
51/**
52 * __perf_evsel__calc_id_pos - calculate id_pos.
53 * @sample_type: sample type
54 *
55 * This function returns the position of the event id (PERF_SAMPLE_ID or
56 * PERF_SAMPLE_IDENTIFIER) in a sample event i.e. in the array of struct
57 * sample_event.
58 */
59static int __perf_evsel__calc_id_pos(u64 sample_type)
60{
61 int idx = 0;
62
63 if (sample_type & PERF_SAMPLE_IDENTIFIER)
64 return 0;
65
66 if (!(sample_type & PERF_SAMPLE_ID))
67 return -1;
68
69 if (sample_type & PERF_SAMPLE_IP)
70 idx += 1;
71
72 if (sample_type & PERF_SAMPLE_TID)
73 idx += 1;
74
75 if (sample_type & PERF_SAMPLE_TIME)
76 idx += 1;
77
78 if (sample_type & PERF_SAMPLE_ADDR)
79 idx += 1;
80
81 return idx;
82}
83
84/**
85 * __perf_evsel__calc_is_pos - calculate is_pos.
86 * @sample_type: sample type
87 *
88 * This function returns the position (counting backwards) of the event id
89 * (PERF_SAMPLE_ID or PERF_SAMPLE_IDENTIFIER) in a non-sample event i.e. if
90 * sample_id_all is used there is an id sample appended to non-sample events.
91 */
92static int __perf_evsel__calc_is_pos(u64 sample_type)
93{
94 int idx = 1;
95
96 if (sample_type & PERF_SAMPLE_IDENTIFIER)
97 return 1;
98
99 if (!(sample_type & PERF_SAMPLE_ID))
100 return -1;
101
102 if (sample_type & PERF_SAMPLE_CPU)
103 idx += 1;
104
105 if (sample_type & PERF_SAMPLE_STREAM_ID)
106 idx += 1;
107
108 return idx;
109}
110
111void perf_evsel__calc_id_pos(struct perf_evsel *evsel)
112{
113 evsel->id_pos = __perf_evsel__calc_id_pos(evsel->attr.sample_type);
114 evsel->is_pos = __perf_evsel__calc_is_pos(evsel->attr.sample_type);
115}
116
48void hists__init(struct hists *hists) 117void hists__init(struct hists *hists)
49{ 118{
50 memset(hists, 0, sizeof(*hists)); 119 memset(hists, 0, sizeof(*hists));
@@ -61,6 +130,7 @@ void __perf_evsel__set_sample_bit(struct perf_evsel *evsel,
61 if (!(evsel->attr.sample_type & bit)) { 130 if (!(evsel->attr.sample_type & bit)) {
62 evsel->attr.sample_type |= bit; 131 evsel->attr.sample_type |= bit;
63 evsel->sample_size += sizeof(u64); 132 evsel->sample_size += sizeof(u64);
133 perf_evsel__calc_id_pos(evsel);
64 } 134 }
65} 135}
66 136
@@ -70,12 +140,19 @@ void __perf_evsel__reset_sample_bit(struct perf_evsel *evsel,
70 if (evsel->attr.sample_type & bit) { 140 if (evsel->attr.sample_type & bit) {
71 evsel->attr.sample_type &= ~bit; 141 evsel->attr.sample_type &= ~bit;
72 evsel->sample_size -= sizeof(u64); 142 evsel->sample_size -= sizeof(u64);
143 perf_evsel__calc_id_pos(evsel);
73 } 144 }
74} 145}
75 146
76void perf_evsel__set_sample_id(struct perf_evsel *evsel) 147void perf_evsel__set_sample_id(struct perf_evsel *evsel,
148 bool can_sample_identifier)
77{ 149{
78 perf_evsel__set_sample_bit(evsel, ID); 150 if (can_sample_identifier) {
151 perf_evsel__reset_sample_bit(evsel, ID);
152 perf_evsel__set_sample_bit(evsel, IDENTIFIER);
153 } else {
154 perf_evsel__set_sample_bit(evsel, ID);
155 }
79 evsel->attr.read_format |= PERF_FORMAT_ID; 156 evsel->attr.read_format |= PERF_FORMAT_ID;
80} 157}
81 158
@@ -88,6 +165,7 @@ void perf_evsel__init(struct perf_evsel *evsel,
88 INIT_LIST_HEAD(&evsel->node); 165 INIT_LIST_HEAD(&evsel->node);
89 hists__init(&evsel->hists); 166 hists__init(&evsel->hists);
90 evsel->sample_size = __perf_evsel__sample_size(attr->sample_type); 167 evsel->sample_size = __perf_evsel__sample_size(attr->sample_type);
168 perf_evsel__calc_id_pos(evsel);
91} 169}
92 170
93struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) 171struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
@@ -246,6 +324,7 @@ const char *perf_evsel__sw_names[PERF_COUNT_SW_MAX] = {
246 "major-faults", 324 "major-faults",
247 "alignment-faults", 325 "alignment-faults",
248 "emulation-faults", 326 "emulation-faults",
327 "dummy",
249}; 328};
250 329
251static const char *__perf_evsel__sw_name(u64 config) 330static const char *__perf_evsel__sw_name(u64 config)
@@ -490,6 +569,7 @@ int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size)
490void perf_evsel__config(struct perf_evsel *evsel, 569void perf_evsel__config(struct perf_evsel *evsel,
491 struct perf_record_opts *opts) 570 struct perf_record_opts *opts)
492{ 571{
572 struct perf_evsel *leader = evsel->leader;
493 struct perf_event_attr *attr = &evsel->attr; 573 struct perf_event_attr *attr = &evsel->attr;
494 int track = !evsel->idx; /* only the first counter needs these */ 574 int track = !evsel->idx; /* only the first counter needs these */
495 575
@@ -499,6 +579,25 @@ void perf_evsel__config(struct perf_evsel *evsel,
499 perf_evsel__set_sample_bit(evsel, IP); 579 perf_evsel__set_sample_bit(evsel, IP);
500 perf_evsel__set_sample_bit(evsel, TID); 580 perf_evsel__set_sample_bit(evsel, TID);
501 581
582 if (evsel->sample_read) {
583 perf_evsel__set_sample_bit(evsel, READ);
584
585 /*
586 * We need ID even in case of single event, because
587 * PERF_SAMPLE_READ process ID specific data.
588 */
589 perf_evsel__set_sample_id(evsel, false);
590
591 /*
592 * Apply group format only if we belong to group
593 * with more than one members.
594 */
595 if (leader->nr_members > 1) {
596 attr->read_format |= PERF_FORMAT_GROUP;
597 attr->inherit = 0;
598 }
599 }
600
502 /* 601 /*
503 * We default some events to a 1 default interval. But keep 602 * We default some events to a 1 default interval. But keep
504 * it a weak assumption overridable by the user. 603 * it a weak assumption overridable by the user.
@@ -514,6 +613,15 @@ void perf_evsel__config(struct perf_evsel *evsel,
514 } 613 }
515 } 614 }
516 615
616 /*
617 * Disable sampling for all group members other
618 * than leader in case leader 'leads' the sampling.
619 */
620 if ((leader != evsel) && leader->sample_read) {
621 attr->sample_freq = 0;
622 attr->sample_period = 0;
623 }
624
517 if (opts->no_samples) 625 if (opts->no_samples)
518 attr->sample_freq = 0; 626 attr->sample_freq = 0;
519 627
@@ -569,8 +677,9 @@ void perf_evsel__config(struct perf_evsel *evsel,
569 if (opts->sample_weight) 677 if (opts->sample_weight)
570 attr->sample_type |= PERF_SAMPLE_WEIGHT; 678 attr->sample_type |= PERF_SAMPLE_WEIGHT;
571 679
572 attr->mmap = track; 680 attr->mmap = track;
573 attr->comm = track; 681 attr->mmap2 = track && !perf_missing_features.mmap2;
682 attr->comm = track;
574 683
575 /* 684 /*
576 * XXX see the function comment above 685 * XXX see the function comment above
@@ -605,15 +714,15 @@ int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
605 return evsel->fd != NULL ? 0 : -ENOMEM; 714 return evsel->fd != NULL ? 0 : -ENOMEM;
606} 715}
607 716
608int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads, 717static int perf_evsel__run_ioctl(struct perf_evsel *evsel, int ncpus, int nthreads,
609 const char *filter) 718 int ioc, void *arg)
610{ 719{
611 int cpu, thread; 720 int cpu, thread;
612 721
613 for (cpu = 0; cpu < ncpus; cpu++) { 722 for (cpu = 0; cpu < ncpus; cpu++) {
614 for (thread = 0; thread < nthreads; thread++) { 723 for (thread = 0; thread < nthreads; thread++) {
615 int fd = FD(evsel, cpu, thread), 724 int fd = FD(evsel, cpu, thread),
616 err = ioctl(fd, PERF_EVENT_IOC_SET_FILTER, filter); 725 err = ioctl(fd, ioc, arg);
617 726
618 if (err) 727 if (err)
619 return err; 728 return err;
@@ -623,6 +732,21 @@ int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
623 return 0; 732 return 0;
624} 733}
625 734
735int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
736 const char *filter)
737{
738 return perf_evsel__run_ioctl(evsel, ncpus, nthreads,
739 PERF_EVENT_IOC_SET_FILTER,
740 (void *)filter);
741}
742
743int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads)
744{
745 return perf_evsel__run_ioctl(evsel, ncpus, nthreads,
746 PERF_EVENT_IOC_ENABLE,
747 0);
748}
749
626int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads) 750int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
627{ 751{
628 evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id)); 752 evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id));
@@ -817,12 +941,72 @@ static int get_group_fd(struct perf_evsel *evsel, int cpu, int thread)
817 return fd; 941 return fd;
818} 942}
819 943
944#define __PRINT_ATTR(fmt, cast, field) \
945 fprintf(fp, " %-19s "fmt"\n", #field, cast attr->field)
946
947#define PRINT_ATTR_U32(field) __PRINT_ATTR("%u" , , field)
948#define PRINT_ATTR_X32(field) __PRINT_ATTR("%#x", , field)
949#define PRINT_ATTR_U64(field) __PRINT_ATTR("%" PRIu64, (uint64_t), field)
950#define PRINT_ATTR_X64(field) __PRINT_ATTR("%#"PRIx64, (uint64_t), field)
951
952#define PRINT_ATTR2N(name1, field1, name2, field2) \
953 fprintf(fp, " %-19s %u %-19s %u\n", \
954 name1, attr->field1, name2, attr->field2)
955
956#define PRINT_ATTR2(field1, field2) \
957 PRINT_ATTR2N(#field1, field1, #field2, field2)
958
959static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp)
960{
961 size_t ret = 0;
962
963 ret += fprintf(fp, "%.60s\n", graph_dotted_line);
964 ret += fprintf(fp, "perf_event_attr:\n");
965
966 ret += PRINT_ATTR_U32(type);
967 ret += PRINT_ATTR_U32(size);
968 ret += PRINT_ATTR_X64(config);
969 ret += PRINT_ATTR_U64(sample_period);
970 ret += PRINT_ATTR_U64(sample_freq);
971 ret += PRINT_ATTR_X64(sample_type);
972 ret += PRINT_ATTR_X64(read_format);
973
974 ret += PRINT_ATTR2(disabled, inherit);
975 ret += PRINT_ATTR2(pinned, exclusive);
976 ret += PRINT_ATTR2(exclude_user, exclude_kernel);
977 ret += PRINT_ATTR2(exclude_hv, exclude_idle);
978 ret += PRINT_ATTR2(mmap, comm);
979 ret += PRINT_ATTR2(freq, inherit_stat);
980 ret += PRINT_ATTR2(enable_on_exec, task);
981 ret += PRINT_ATTR2(watermark, precise_ip);
982 ret += PRINT_ATTR2(mmap_data, sample_id_all);
983 ret += PRINT_ATTR2(exclude_host, exclude_guest);
984 ret += PRINT_ATTR2N("excl.callchain_kern", exclude_callchain_kernel,
985 "excl.callchain_user", exclude_callchain_user);
986
987 ret += PRINT_ATTR_U32(wakeup_events);
988 ret += PRINT_ATTR_U32(wakeup_watermark);
989 ret += PRINT_ATTR_X32(bp_type);
990 ret += PRINT_ATTR_X64(bp_addr);
991 ret += PRINT_ATTR_X64(config1);
992 ret += PRINT_ATTR_U64(bp_len);
993 ret += PRINT_ATTR_X64(config2);
994 ret += PRINT_ATTR_X64(branch_sample_type);
995 ret += PRINT_ATTR_X64(sample_regs_user);
996 ret += PRINT_ATTR_U32(sample_stack_user);
997
998 ret += fprintf(fp, "%.60s\n", graph_dotted_line);
999
1000 return ret;
1001}
1002
820static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, 1003static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
821 struct thread_map *threads) 1004 struct thread_map *threads)
822{ 1005{
823 int cpu, thread; 1006 int cpu, thread;
824 unsigned long flags = 0; 1007 unsigned long flags = 0;
825 int pid = -1, err; 1008 int pid = -1, err;
1009 enum { NO_CHANGE, SET_TO_MAX, INCREASED_MAX } set_rlimit = NO_CHANGE;
826 1010
827 if (evsel->fd == NULL && 1011 if (evsel->fd == NULL &&
828 perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0) 1012 perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0)
@@ -834,12 +1018,17 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
834 } 1018 }
835 1019
836fallback_missing_features: 1020fallback_missing_features:
1021 if (perf_missing_features.mmap2)
1022 evsel->attr.mmap2 = 0;
837 if (perf_missing_features.exclude_guest) 1023 if (perf_missing_features.exclude_guest)
838 evsel->attr.exclude_guest = evsel->attr.exclude_host = 0; 1024 evsel->attr.exclude_guest = evsel->attr.exclude_host = 0;
839retry_sample_id: 1025retry_sample_id:
840 if (perf_missing_features.sample_id_all) 1026 if (perf_missing_features.sample_id_all)
841 evsel->attr.sample_id_all = 0; 1027 evsel->attr.sample_id_all = 0;
842 1028
1029 if (verbose >= 2)
1030 perf_event_attr__fprintf(&evsel->attr, stderr);
1031
843 for (cpu = 0; cpu < cpus->nr; cpu++) { 1032 for (cpu = 0; cpu < cpus->nr; cpu++) {
844 1033
845 for (thread = 0; thread < threads->nr; thread++) { 1034 for (thread = 0; thread < threads->nr; thread++) {
@@ -849,6 +1038,9 @@ retry_sample_id:
849 pid = threads->map[thread]; 1038 pid = threads->map[thread];
850 1039
851 group_fd = get_group_fd(evsel, cpu, thread); 1040 group_fd = get_group_fd(evsel, cpu, thread);
1041retry_open:
1042 pr_debug2("perf_event_open: pid %d cpu %d group_fd %d flags %#lx\n",
1043 pid, cpus->map[cpu], group_fd, flags);
852 1044
853 FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr, 1045 FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr,
854 pid, 1046 pid,
@@ -858,17 +1050,45 @@ retry_sample_id:
858 err = -errno; 1050 err = -errno;
859 goto try_fallback; 1051 goto try_fallback;
860 } 1052 }
1053 set_rlimit = NO_CHANGE;
861 } 1054 }
862 } 1055 }
863 1056
864 return 0; 1057 return 0;
865 1058
866try_fallback: 1059try_fallback:
1060 /*
1061 * perf stat needs between 5 and 22 fds per CPU. When we run out
1062 * of them try to increase the limits.
1063 */
1064 if (err == -EMFILE && set_rlimit < INCREASED_MAX) {
1065 struct rlimit l;
1066 int old_errno = errno;
1067
1068 if (getrlimit(RLIMIT_NOFILE, &l) == 0) {
1069 if (set_rlimit == NO_CHANGE)
1070 l.rlim_cur = l.rlim_max;
1071 else {
1072 l.rlim_cur = l.rlim_max + 1000;
1073 l.rlim_max = l.rlim_cur;
1074 }
1075 if (setrlimit(RLIMIT_NOFILE, &l) == 0) {
1076 set_rlimit++;
1077 errno = old_errno;
1078 goto retry_open;
1079 }
1080 }
1081 errno = old_errno;
1082 }
1083
867 if (err != -EINVAL || cpu > 0 || thread > 0) 1084 if (err != -EINVAL || cpu > 0 || thread > 0)
868 goto out_close; 1085 goto out_close;
869 1086
870 if (!perf_missing_features.exclude_guest && 1087 if (!perf_missing_features.mmap2 && evsel->attr.mmap2) {
871 (evsel->attr.exclude_guest || evsel->attr.exclude_host)) { 1088 perf_missing_features.mmap2 = true;
1089 goto fallback_missing_features;
1090 } else if (!perf_missing_features.exclude_guest &&
1091 (evsel->attr.exclude_guest || evsel->attr.exclude_host)) {
872 perf_missing_features.exclude_guest = true; 1092 perf_missing_features.exclude_guest = true;
873 goto fallback_missing_features; 1093 goto fallback_missing_features;
874 } else if (!perf_missing_features.sample_id_all) { 1094 } else if (!perf_missing_features.sample_id_all) {
@@ -951,6 +1171,11 @@ static int perf_evsel__parse_id_sample(const struct perf_evsel *evsel,
951 array += ((event->header.size - 1171 array += ((event->header.size -
952 sizeof(event->header)) / sizeof(u64)) - 1; 1172 sizeof(event->header)) / sizeof(u64)) - 1;
953 1173
1174 if (type & PERF_SAMPLE_IDENTIFIER) {
1175 sample->id = *array;
1176 array--;
1177 }
1178
954 if (type & PERF_SAMPLE_CPU) { 1179 if (type & PERF_SAMPLE_CPU) {
955 u.val64 = *array; 1180 u.val64 = *array;
956 if (swapped) { 1181 if (swapped) {
@@ -994,24 +1219,30 @@ static int perf_evsel__parse_id_sample(const struct perf_evsel *evsel,
994 return 0; 1219 return 0;
995} 1220}
996 1221
997static bool sample_overlap(const union perf_event *event, 1222static inline bool overflow(const void *endp, u16 max_size, const void *offset,
998 const void *offset, u64 size) 1223 u64 size)
999{ 1224{
1000 const void *base = event; 1225 return size > max_size || offset + size > endp;
1226}
1001 1227
1002 if (offset + size > base + event->header.size) 1228#define OVERFLOW_CHECK(offset, size, max_size) \
1003 return true; 1229 do { \
1230 if (overflow(endp, (max_size), (offset), (size))) \
1231 return -EFAULT; \
1232 } while (0)
1004 1233
1005 return false; 1234#define OVERFLOW_CHECK_u64(offset) \
1006} 1235 OVERFLOW_CHECK(offset, sizeof(u64), sizeof(u64))
1007 1236
1008int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, 1237int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
1009 struct perf_sample *data) 1238 struct perf_sample *data)
1010{ 1239{
1011 u64 type = evsel->attr.sample_type; 1240 u64 type = evsel->attr.sample_type;
1012 u64 regs_user = evsel->attr.sample_regs_user;
1013 bool swapped = evsel->needs_swap; 1241 bool swapped = evsel->needs_swap;
1014 const u64 *array; 1242 const u64 *array;
1243 u16 max_size = event->header.size;
1244 const void *endp = (void *)event + max_size;
1245 u64 sz;
1015 1246
1016 /* 1247 /*
1017 * used for cross-endian analysis. See git commit 65014ab3 1248 * used for cross-endian analysis. See git commit 65014ab3
@@ -1033,11 +1264,22 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
1033 1264
1034 array = event->sample.array; 1265 array = event->sample.array;
1035 1266
1267 /*
1268 * The evsel's sample_size is based on PERF_SAMPLE_MASK which includes
1269 * up to PERF_SAMPLE_PERIOD. After that overflow() must be used to
1270 * check the format does not go past the end of the event.
1271 */
1036 if (evsel->sample_size + sizeof(event->header) > event->header.size) 1272 if (evsel->sample_size + sizeof(event->header) > event->header.size)
1037 return -EFAULT; 1273 return -EFAULT;
1038 1274
1275 data->id = -1ULL;
1276 if (type & PERF_SAMPLE_IDENTIFIER) {
1277 data->id = *array;
1278 array++;
1279 }
1280
1039 if (type & PERF_SAMPLE_IP) { 1281 if (type & PERF_SAMPLE_IP) {
1040 data->ip = event->ip.ip; 1282 data->ip = *array;
1041 array++; 1283 array++;
1042 } 1284 }
1043 1285
@@ -1066,7 +1308,6 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
1066 array++; 1308 array++;
1067 } 1309 }
1068 1310
1069 data->id = -1ULL;
1070 if (type & PERF_SAMPLE_ID) { 1311 if (type & PERF_SAMPLE_ID) {
1071 data->id = *array; 1312 data->id = *array;
1072 array++; 1313 array++;
@@ -1096,25 +1337,62 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
1096 } 1337 }
1097 1338
1098 if (type & PERF_SAMPLE_READ) { 1339 if (type & PERF_SAMPLE_READ) {
1099 fprintf(stderr, "PERF_SAMPLE_READ is unsupported for now\n"); 1340 u64 read_format = evsel->attr.read_format;
1100 return -1; 1341
1342 OVERFLOW_CHECK_u64(array);
1343 if (read_format & PERF_FORMAT_GROUP)
1344 data->read.group.nr = *array;
1345 else
1346 data->read.one.value = *array;
1347
1348 array++;
1349
1350 if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) {
1351 OVERFLOW_CHECK_u64(array);
1352 data->read.time_enabled = *array;
1353 array++;
1354 }
1355
1356 if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) {
1357 OVERFLOW_CHECK_u64(array);
1358 data->read.time_running = *array;
1359 array++;
1360 }
1361
1362 /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */
1363 if (read_format & PERF_FORMAT_GROUP) {
1364 const u64 max_group_nr = UINT64_MAX /
1365 sizeof(struct sample_read_value);
1366
1367 if (data->read.group.nr > max_group_nr)
1368 return -EFAULT;
1369 sz = data->read.group.nr *
1370 sizeof(struct sample_read_value);
1371 OVERFLOW_CHECK(array, sz, max_size);
1372 data->read.group.values =
1373 (struct sample_read_value *)array;
1374 array = (void *)array + sz;
1375 } else {
1376 OVERFLOW_CHECK_u64(array);
1377 data->read.one.id = *array;
1378 array++;
1379 }
1101 } 1380 }
1102 1381
1103 if (type & PERF_SAMPLE_CALLCHAIN) { 1382 if (type & PERF_SAMPLE_CALLCHAIN) {
1104 if (sample_overlap(event, array, sizeof(data->callchain->nr))) 1383 const u64 max_callchain_nr = UINT64_MAX / sizeof(u64);
1105 return -EFAULT;
1106
1107 data->callchain = (struct ip_callchain *)array;
1108 1384
1109 if (sample_overlap(event, array, data->callchain->nr)) 1385 OVERFLOW_CHECK_u64(array);
1386 data->callchain = (struct ip_callchain *)array++;
1387 if (data->callchain->nr > max_callchain_nr)
1110 return -EFAULT; 1388 return -EFAULT;
1111 1389 sz = data->callchain->nr * sizeof(u64);
1112 array += 1 + data->callchain->nr; 1390 OVERFLOW_CHECK(array, sz, max_size);
1391 array = (void *)array + sz;
1113 } 1392 }
1114 1393
1115 if (type & PERF_SAMPLE_RAW) { 1394 if (type & PERF_SAMPLE_RAW) {
1116 const u64 *pdata; 1395 OVERFLOW_CHECK_u64(array);
1117
1118 u.val64 = *array; 1396 u.val64 = *array;
1119 if (WARN_ONCE(swapped, 1397 if (WARN_ONCE(swapped,
1120 "Endianness of raw data not corrected!\n")) { 1398 "Endianness of raw data not corrected!\n")) {
@@ -1123,65 +1401,71 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
1123 u.val32[0] = bswap_32(u.val32[0]); 1401 u.val32[0] = bswap_32(u.val32[0]);
1124 u.val32[1] = bswap_32(u.val32[1]); 1402 u.val32[1] = bswap_32(u.val32[1]);
1125 } 1403 }
1126
1127 if (sample_overlap(event, array, sizeof(u32)))
1128 return -EFAULT;
1129
1130 data->raw_size = u.val32[0]; 1404 data->raw_size = u.val32[0];
1131 pdata = (void *) array + sizeof(u32); 1405 array = (void *)array + sizeof(u32);
1132 1406
1133 if (sample_overlap(event, pdata, data->raw_size)) 1407 OVERFLOW_CHECK(array, data->raw_size, max_size);
1134 return -EFAULT; 1408 data->raw_data = (void *)array;
1135 1409 array = (void *)array + data->raw_size;
1136 data->raw_data = (void *) pdata;
1137
1138 array = (void *)array + data->raw_size + sizeof(u32);
1139 } 1410 }
1140 1411
1141 if (type & PERF_SAMPLE_BRANCH_STACK) { 1412 if (type & PERF_SAMPLE_BRANCH_STACK) {
1142 u64 sz; 1413 const u64 max_branch_nr = UINT64_MAX /
1414 sizeof(struct branch_entry);
1143 1415
1144 data->branch_stack = (struct branch_stack *)array; 1416 OVERFLOW_CHECK_u64(array);
1145 array++; /* nr */ 1417 data->branch_stack = (struct branch_stack *)array++;
1146 1418
1419 if (data->branch_stack->nr > max_branch_nr)
1420 return -EFAULT;
1147 sz = data->branch_stack->nr * sizeof(struct branch_entry); 1421 sz = data->branch_stack->nr * sizeof(struct branch_entry);
1148 sz /= sizeof(u64); 1422 OVERFLOW_CHECK(array, sz, max_size);
1149 array += sz; 1423 array = (void *)array + sz;
1150 } 1424 }
1151 1425
1152 if (type & PERF_SAMPLE_REGS_USER) { 1426 if (type & PERF_SAMPLE_REGS_USER) {
1153 /* First u64 tells us if we have any regs in sample. */ 1427 OVERFLOW_CHECK_u64(array);
1154 u64 avail = *array++; 1428 data->user_regs.abi = *array;
1429 array++;
1430
1431 if (data->user_regs.abi) {
1432 u64 regs_user = evsel->attr.sample_regs_user;
1155 1433
1156 if (avail) { 1434 sz = hweight_long(regs_user) * sizeof(u64);
1435 OVERFLOW_CHECK(array, sz, max_size);
1157 data->user_regs.regs = (u64 *)array; 1436 data->user_regs.regs = (u64 *)array;
1158 array += hweight_long(regs_user); 1437 array = (void *)array + sz;
1159 } 1438 }
1160 } 1439 }
1161 1440
1162 if (type & PERF_SAMPLE_STACK_USER) { 1441 if (type & PERF_SAMPLE_STACK_USER) {
1163 u64 size = *array++; 1442 OVERFLOW_CHECK_u64(array);
1443 sz = *array++;
1164 1444
1165 data->user_stack.offset = ((char *)(array - 1) 1445 data->user_stack.offset = ((char *)(array - 1)
1166 - (char *) event); 1446 - (char *) event);
1167 1447
1168 if (!size) { 1448 if (!sz) {
1169 data->user_stack.size = 0; 1449 data->user_stack.size = 0;
1170 } else { 1450 } else {
1451 OVERFLOW_CHECK(array, sz, max_size);
1171 data->user_stack.data = (char *)array; 1452 data->user_stack.data = (char *)array;
1172 array += size / sizeof(*array); 1453 array = (void *)array + sz;
1454 OVERFLOW_CHECK_u64(array);
1173 data->user_stack.size = *array++; 1455 data->user_stack.size = *array++;
1174 } 1456 }
1175 } 1457 }
1176 1458
1177 data->weight = 0; 1459 data->weight = 0;
1178 if (type & PERF_SAMPLE_WEIGHT) { 1460 if (type & PERF_SAMPLE_WEIGHT) {
1461 OVERFLOW_CHECK_u64(array);
1179 data->weight = *array; 1462 data->weight = *array;
1180 array++; 1463 array++;
1181 } 1464 }
1182 1465
1183 data->data_src = PERF_MEM_DATA_SRC_NONE; 1466 data->data_src = PERF_MEM_DATA_SRC_NONE;
1184 if (type & PERF_SAMPLE_DATA_SRC) { 1467 if (type & PERF_SAMPLE_DATA_SRC) {
1468 OVERFLOW_CHECK_u64(array);
1185 data->data_src = *array; 1469 data->data_src = *array;
1186 array++; 1470 array++;
1187 } 1471 }
@@ -1189,12 +1473,105 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
1189 return 0; 1473 return 0;
1190} 1474}
1191 1475
1476size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
1477 u64 sample_regs_user, u64 read_format)
1478{
1479 size_t sz, result = sizeof(struct sample_event);
1480
1481 if (type & PERF_SAMPLE_IDENTIFIER)
1482 result += sizeof(u64);
1483
1484 if (type & PERF_SAMPLE_IP)
1485 result += sizeof(u64);
1486
1487 if (type & PERF_SAMPLE_TID)
1488 result += sizeof(u64);
1489
1490 if (type & PERF_SAMPLE_TIME)
1491 result += sizeof(u64);
1492
1493 if (type & PERF_SAMPLE_ADDR)
1494 result += sizeof(u64);
1495
1496 if (type & PERF_SAMPLE_ID)
1497 result += sizeof(u64);
1498
1499 if (type & PERF_SAMPLE_STREAM_ID)
1500 result += sizeof(u64);
1501
1502 if (type & PERF_SAMPLE_CPU)
1503 result += sizeof(u64);
1504
1505 if (type & PERF_SAMPLE_PERIOD)
1506 result += sizeof(u64);
1507
1508 if (type & PERF_SAMPLE_READ) {
1509 result += sizeof(u64);
1510 if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
1511 result += sizeof(u64);
1512 if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
1513 result += sizeof(u64);
1514 /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */
1515 if (read_format & PERF_FORMAT_GROUP) {
1516 sz = sample->read.group.nr *
1517 sizeof(struct sample_read_value);
1518 result += sz;
1519 } else {
1520 result += sizeof(u64);
1521 }
1522 }
1523
1524 if (type & PERF_SAMPLE_CALLCHAIN) {
1525 sz = (sample->callchain->nr + 1) * sizeof(u64);
1526 result += sz;
1527 }
1528
1529 if (type & PERF_SAMPLE_RAW) {
1530 result += sizeof(u32);
1531 result += sample->raw_size;
1532 }
1533
1534 if (type & PERF_SAMPLE_BRANCH_STACK) {
1535 sz = sample->branch_stack->nr * sizeof(struct branch_entry);
1536 sz += sizeof(u64);
1537 result += sz;
1538 }
1539
1540 if (type & PERF_SAMPLE_REGS_USER) {
1541 if (sample->user_regs.abi) {
1542 result += sizeof(u64);
1543 sz = hweight_long(sample_regs_user) * sizeof(u64);
1544 result += sz;
1545 } else {
1546 result += sizeof(u64);
1547 }
1548 }
1549
1550 if (type & PERF_SAMPLE_STACK_USER) {
1551 sz = sample->user_stack.size;
1552 result += sizeof(u64);
1553 if (sz) {
1554 result += sz;
1555 result += sizeof(u64);
1556 }
1557 }
1558
1559 if (type & PERF_SAMPLE_WEIGHT)
1560 result += sizeof(u64);
1561
1562 if (type & PERF_SAMPLE_DATA_SRC)
1563 result += sizeof(u64);
1564
1565 return result;
1566}
1567
1192int perf_event__synthesize_sample(union perf_event *event, u64 type, 1568int perf_event__synthesize_sample(union perf_event *event, u64 type,
1569 u64 sample_regs_user, u64 read_format,
1193 const struct perf_sample *sample, 1570 const struct perf_sample *sample,
1194 bool swapped) 1571 bool swapped)
1195{ 1572{
1196 u64 *array; 1573 u64 *array;
1197 1574 size_t sz;
1198 /* 1575 /*
1199 * used for cross-endian analysis. See git commit 65014ab3 1576 * used for cross-endian analysis. See git commit 65014ab3
1200 * for why this goofiness is needed. 1577 * for why this goofiness is needed.
@@ -1203,8 +1580,13 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,
1203 1580
1204 array = event->sample.array; 1581 array = event->sample.array;
1205 1582
1583 if (type & PERF_SAMPLE_IDENTIFIER) {
1584 *array = sample->id;
1585 array++;
1586 }
1587
1206 if (type & PERF_SAMPLE_IP) { 1588 if (type & PERF_SAMPLE_IP) {
1207 event->ip.ip = sample->ip; 1589 *array = sample->ip;
1208 array++; 1590 array++;
1209 } 1591 }
1210 1592
@@ -1262,6 +1644,97 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,
1262 array++; 1644 array++;
1263 } 1645 }
1264 1646
1647 if (type & PERF_SAMPLE_READ) {
1648 if (read_format & PERF_FORMAT_GROUP)
1649 *array = sample->read.group.nr;
1650 else
1651 *array = sample->read.one.value;
1652 array++;
1653
1654 if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) {
1655 *array = sample->read.time_enabled;
1656 array++;
1657 }
1658
1659 if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) {
1660 *array = sample->read.time_running;
1661 array++;
1662 }
1663
1664 /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */
1665 if (read_format & PERF_FORMAT_GROUP) {
1666 sz = sample->read.group.nr *
1667 sizeof(struct sample_read_value);
1668 memcpy(array, sample->read.group.values, sz);
1669 array = (void *)array + sz;
1670 } else {
1671 *array = sample->read.one.id;
1672 array++;
1673 }
1674 }
1675
1676 if (type & PERF_SAMPLE_CALLCHAIN) {
1677 sz = (sample->callchain->nr + 1) * sizeof(u64);
1678 memcpy(array, sample->callchain, sz);
1679 array = (void *)array + sz;
1680 }
1681
1682 if (type & PERF_SAMPLE_RAW) {
1683 u.val32[0] = sample->raw_size;
1684 if (WARN_ONCE(swapped,
1685 "Endianness of raw data not corrected!\n")) {
1686 /*
1687 * Inverse of what is done in perf_evsel__parse_sample
1688 */
1689 u.val32[0] = bswap_32(u.val32[0]);
1690 u.val32[1] = bswap_32(u.val32[1]);
1691 u.val64 = bswap_64(u.val64);
1692 }
1693 *array = u.val64;
1694 array = (void *)array + sizeof(u32);
1695
1696 memcpy(array, sample->raw_data, sample->raw_size);
1697 array = (void *)array + sample->raw_size;
1698 }
1699
1700 if (type & PERF_SAMPLE_BRANCH_STACK) {
1701 sz = sample->branch_stack->nr * sizeof(struct branch_entry);
1702 sz += sizeof(u64);
1703 memcpy(array, sample->branch_stack, sz);
1704 array = (void *)array + sz;
1705 }
1706
1707 if (type & PERF_SAMPLE_REGS_USER) {
1708 if (sample->user_regs.abi) {
1709 *array++ = sample->user_regs.abi;
1710 sz = hweight_long(sample_regs_user) * sizeof(u64);
1711 memcpy(array, sample->user_regs.regs, sz);
1712 array = (void *)array + sz;
1713 } else {
1714 *array++ = 0;
1715 }
1716 }
1717
1718 if (type & PERF_SAMPLE_STACK_USER) {
1719 sz = sample->user_stack.size;
1720 *array++ = sz;
1721 if (sz) {
1722 memcpy(array, sample->user_stack.data, sz);
1723 array = (void *)array + sz;
1724 *array++ = sz;
1725 }
1726 }
1727
1728 if (type & PERF_SAMPLE_WEIGHT) {
1729 *array = sample->weight;
1730 array++;
1731 }
1732
1733 if (type & PERF_SAMPLE_DATA_SRC) {
1734 *array = sample->data_src;
1735 array++;
1736 }
1737
1265 return 0; 1738 return 0;
1266} 1739}
1267 1740
@@ -1391,6 +1864,7 @@ static int sample_type__fprintf(FILE *fp, bool *first, u64 value)
1391 bit_name(READ), bit_name(CALLCHAIN), bit_name(ID), bit_name(CPU), 1864 bit_name(READ), bit_name(CALLCHAIN), bit_name(ID), bit_name(CPU),
1392 bit_name(PERIOD), bit_name(STREAM_ID), bit_name(RAW), 1865 bit_name(PERIOD), bit_name(STREAM_ID), bit_name(RAW),
1393 bit_name(BRANCH_STACK), bit_name(REGS_USER), bit_name(STACK_USER), 1866 bit_name(BRANCH_STACK), bit_name(REGS_USER), bit_name(STACK_USER),
1867 bit_name(IDENTIFIER),
1394 { .name = NULL, } 1868 { .name = NULL, }
1395 }; 1869 };
1396#undef bit_name 1870#undef bit_name
@@ -1458,6 +1932,7 @@ int perf_evsel__fprintf(struct perf_evsel *evsel,
1458 if_print(exclude_hv); 1932 if_print(exclude_hv);
1459 if_print(exclude_idle); 1933 if_print(exclude_idle);
1460 if_print(mmap); 1934 if_print(mmap);
1935 if_print(mmap2);
1461 if_print(comm); 1936 if_print(comm);
1462 if_print(freq); 1937 if_print(freq);
1463 if_print(inherit_stat); 1938 if_print(inherit_stat);
@@ -1482,7 +1957,7 @@ out:
1482bool perf_evsel__fallback(struct perf_evsel *evsel, int err, 1957bool perf_evsel__fallback(struct perf_evsel *evsel, int err,
1483 char *msg, size_t msgsize) 1958 char *msg, size_t msgsize)
1484{ 1959{
1485 if ((err == ENOENT || err == ENXIO) && 1960 if ((err == ENOENT || err == ENXIO || err == ENODEV) &&
1486 evsel->attr.type == PERF_TYPE_HARDWARE && 1961 evsel->attr.type == PERF_TYPE_HARDWARE &&
1487 evsel->attr.config == PERF_COUNT_HW_CPU_CYCLES) { 1962 evsel->attr.config == PERF_COUNT_HW_CPU_CYCLES) {
1488 /* 1963 /*
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 3f156ccc1acb..4a7bdc713bab 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -38,6 +38,9 @@ struct perf_sample_id {
38 struct hlist_node node; 38 struct hlist_node node;
39 u64 id; 39 u64 id;
40 struct perf_evsel *evsel; 40 struct perf_evsel *evsel;
41
42 /* Holds total ID period value for PERF_SAMPLE_READ processing. */
43 u64 period;
41}; 44};
42 45
43/** struct perf_evsel - event selector 46/** struct perf_evsel - event selector
@@ -45,6 +48,12 @@ struct perf_sample_id {
45 * @name - Can be set to retain the original event name passed by the user, 48 * @name - Can be set to retain the original event name passed by the user,
46 * so that when showing results in tools such as 'perf stat', we 49 * so that when showing results in tools such as 'perf stat', we
47 * show the name used, not some alias. 50 * show the name used, not some alias.
51 * @id_pos: the position of the event id (PERF_SAMPLE_ID or
52 * PERF_SAMPLE_IDENTIFIER) in a sample event i.e. in the array of
53 * struct sample_event
54 * @is_pos: the position (counting backwards) of the event id (PERF_SAMPLE_ID or
55 * PERF_SAMPLE_IDENTIFIER) in a non-sample event i.e. if sample_id_all
56 * is used there is an id sample appended to non-sample events
48 */ 57 */
49struct perf_evsel { 58struct perf_evsel {
50 struct list_head node; 59 struct list_head node;
@@ -71,11 +80,14 @@ struct perf_evsel {
71 } handler; 80 } handler;
72 struct cpu_map *cpus; 81 struct cpu_map *cpus;
73 unsigned int sample_size; 82 unsigned int sample_size;
83 int id_pos;
84 int is_pos;
74 bool supported; 85 bool supported;
75 bool needs_swap; 86 bool needs_swap;
76 /* parse modifier helper */ 87 /* parse modifier helper */
77 int exclude_GH; 88 int exclude_GH;
78 int nr_members; 89 int nr_members;
90 int sample_read;
79 struct perf_evsel *leader; 91 struct perf_evsel *leader;
80 char *group_name; 92 char *group_name;
81}; 93};
@@ -100,6 +112,9 @@ void perf_evsel__delete(struct perf_evsel *evsel);
100void perf_evsel__config(struct perf_evsel *evsel, 112void perf_evsel__config(struct perf_evsel *evsel,
101 struct perf_record_opts *opts); 113 struct perf_record_opts *opts);
102 114
115int __perf_evsel__sample_size(u64 sample_type);
116void perf_evsel__calc_id_pos(struct perf_evsel *evsel);
117
103bool perf_evsel__is_cache_op_valid(u8 type, u8 op); 118bool perf_evsel__is_cache_op_valid(u8 type, u8 op);
104 119
105#define PERF_EVSEL__MAX_ALIASES 8 120#define PERF_EVSEL__MAX_ALIASES 8
@@ -138,10 +153,12 @@ void __perf_evsel__reset_sample_bit(struct perf_evsel *evsel,
138#define perf_evsel__reset_sample_bit(evsel, bit) \ 153#define perf_evsel__reset_sample_bit(evsel, bit) \
139 __perf_evsel__reset_sample_bit(evsel, PERF_SAMPLE_##bit) 154 __perf_evsel__reset_sample_bit(evsel, PERF_SAMPLE_##bit)
140 155
141void perf_evsel__set_sample_id(struct perf_evsel *evsel); 156void perf_evsel__set_sample_id(struct perf_evsel *evsel,
157 bool use_sample_identifier);
142 158
143int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads, 159int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
144 const char *filter); 160 const char *filter);
161int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads);
145 162
146int perf_evsel__open_per_cpu(struct perf_evsel *evsel, 163int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
147 struct cpu_map *cpus); 164 struct cpu_map *cpus);
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index a4dafbee2511..ce69901176d8 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -25,41 +25,9 @@
25 25
26static bool no_buildid_cache = false; 26static bool no_buildid_cache = false;
27 27
28static int trace_event_count;
29static struct perf_trace_event_type *trace_events;
30
31static u32 header_argc; 28static u32 header_argc;
32static const char **header_argv; 29static const char **header_argv;
33 30
34int perf_header__push_event(u64 id, const char *name)
35{
36 struct perf_trace_event_type *nevents;
37
38 if (strlen(name) > MAX_EVENT_NAME)
39 pr_warning("Event %s will be truncated\n", name);
40
41 nevents = realloc(trace_events, (trace_event_count + 1) * sizeof(*trace_events));
42 if (nevents == NULL)
43 return -ENOMEM;
44 trace_events = nevents;
45
46 memset(&trace_events[trace_event_count], 0, sizeof(struct perf_trace_event_type));
47 trace_events[trace_event_count].event_id = id;
48 strncpy(trace_events[trace_event_count].name, name, MAX_EVENT_NAME - 1);
49 trace_event_count++;
50 return 0;
51}
52
53char *perf_header__find_event(u64 id)
54{
55 int i;
56 for (i = 0 ; i < trace_event_count; i++) {
57 if (trace_events[i].event_id == id)
58 return trace_events[i].name;
59 }
60 return NULL;
61}
62
63/* 31/*
64 * magic2 = "PERFILE2" 32 * magic2 = "PERFILE2"
65 * must be a numerical value to let the endianness 33 * must be a numerical value to let the endianness
@@ -231,9 +199,11 @@ static int write_buildid(char *name, size_t name_len, u8 *build_id,
231 return write_padded(fd, name, name_len + 1, len); 199 return write_padded(fd, name, name_len + 1, len);
232} 200}
233 201
234static int __dsos__write_buildid_table(struct list_head *head, pid_t pid, 202static int __dsos__write_buildid_table(struct list_head *head,
235 u16 misc, int fd) 203 struct machine *machine,
204 pid_t pid, u16 misc, int fd)
236{ 205{
206 char nm[PATH_MAX];
237 struct dso *pos; 207 struct dso *pos;
238 208
239 dsos__for_each_with_build_id(pos, head) { 209 dsos__for_each_with_build_id(pos, head) {
@@ -247,6 +217,10 @@ static int __dsos__write_buildid_table(struct list_head *head, pid_t pid,
247 if (is_vdso_map(pos->short_name)) { 217 if (is_vdso_map(pos->short_name)) {
248 name = (char *) VDSO__MAP_NAME; 218 name = (char *) VDSO__MAP_NAME;
249 name_len = sizeof(VDSO__MAP_NAME) + 1; 219 name_len = sizeof(VDSO__MAP_NAME) + 1;
220 } else if (dso__is_kcore(pos)) {
221 machine__mmap_name(machine, nm, sizeof(nm));
222 name = nm;
223 name_len = strlen(nm) + 1;
250 } else { 224 } else {
251 name = pos->long_name; 225 name = pos->long_name;
252 name_len = pos->long_name_len + 1; 226 name_len = pos->long_name_len + 1;
@@ -272,10 +246,10 @@ static int machine__write_buildid_table(struct machine *machine, int fd)
272 umisc = PERF_RECORD_MISC_GUEST_USER; 246 umisc = PERF_RECORD_MISC_GUEST_USER;
273 } 247 }
274 248
275 err = __dsos__write_buildid_table(&machine->kernel_dsos, machine->pid, 249 err = __dsos__write_buildid_table(&machine->kernel_dsos, machine,
276 kmisc, fd); 250 machine->pid, kmisc, fd);
277 if (err == 0) 251 if (err == 0)
278 err = __dsos__write_buildid_table(&machine->user_dsos, 252 err = __dsos__write_buildid_table(&machine->user_dsos, machine,
279 machine->pid, umisc, fd); 253 machine->pid, umisc, fd);
280 return err; 254 return err;
281} 255}
@@ -407,23 +381,31 @@ out_free:
407 return err; 381 return err;
408} 382}
409 383
410static int dso__cache_build_id(struct dso *dso, const char *debugdir) 384static int dso__cache_build_id(struct dso *dso, struct machine *machine,
385 const char *debugdir)
411{ 386{
412 bool is_kallsyms = dso->kernel && dso->long_name[0] != '/'; 387 bool is_kallsyms = dso->kernel && dso->long_name[0] != '/';
413 bool is_vdso = is_vdso_map(dso->short_name); 388 bool is_vdso = is_vdso_map(dso->short_name);
389 char *name = dso->long_name;
390 char nm[PATH_MAX];
414 391
415 return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id), 392 if (dso__is_kcore(dso)) {
416 dso->long_name, debugdir, 393 is_kallsyms = true;
417 is_kallsyms, is_vdso); 394 machine__mmap_name(machine, nm, sizeof(nm));
395 name = nm;
396 }
397 return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id), name,
398 debugdir, is_kallsyms, is_vdso);
418} 399}
419 400
420static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir) 401static int __dsos__cache_build_ids(struct list_head *head,
402 struct machine *machine, const char *debugdir)
421{ 403{
422 struct dso *pos; 404 struct dso *pos;
423 int err = 0; 405 int err = 0;
424 406
425 dsos__for_each_with_build_id(pos, head) 407 dsos__for_each_with_build_id(pos, head)
426 if (dso__cache_build_id(pos, debugdir)) 408 if (dso__cache_build_id(pos, machine, debugdir))
427 err = -1; 409 err = -1;
428 410
429 return err; 411 return err;
@@ -431,8 +413,9 @@ static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir)
431 413
432static int machine__cache_build_ids(struct machine *machine, const char *debugdir) 414static int machine__cache_build_ids(struct machine *machine, const char *debugdir)
433{ 415{
434 int ret = __dsos__cache_build_ids(&machine->kernel_dsos, debugdir); 416 int ret = __dsos__cache_build_ids(&machine->kernel_dsos, machine,
435 ret |= __dsos__cache_build_ids(&machine->user_dsos, debugdir); 417 debugdir);
418 ret |= __dsos__cache_build_ids(&machine->user_dsos, machine, debugdir);
436 return ret; 419 return ret;
437} 420}
438 421
@@ -748,18 +731,19 @@ static int build_cpu_topo(struct cpu_topo *tp, int cpu)
748 char filename[MAXPATHLEN]; 731 char filename[MAXPATHLEN];
749 char *buf = NULL, *p; 732 char *buf = NULL, *p;
750 size_t len = 0; 733 size_t len = 0;
734 ssize_t sret;
751 u32 i = 0; 735 u32 i = 0;
752 int ret = -1; 736 int ret = -1;
753 737
754 sprintf(filename, CORE_SIB_FMT, cpu); 738 sprintf(filename, CORE_SIB_FMT, cpu);
755 fp = fopen(filename, "r"); 739 fp = fopen(filename, "r");
756 if (!fp) 740 if (!fp)
757 return -1; 741 goto try_threads;
758
759 if (getline(&buf, &len, fp) <= 0)
760 goto done;
761 742
743 sret = getline(&buf, &len, fp);
762 fclose(fp); 744 fclose(fp);
745 if (sret <= 0)
746 goto try_threads;
763 747
764 p = strchr(buf, '\n'); 748 p = strchr(buf, '\n');
765 if (p) 749 if (p)
@@ -775,7 +759,9 @@ static int build_cpu_topo(struct cpu_topo *tp, int cpu)
775 buf = NULL; 759 buf = NULL;
776 len = 0; 760 len = 0;
777 } 761 }
762 ret = 0;
778 763
764try_threads:
779 sprintf(filename, THRD_SIB_FMT, cpu); 765 sprintf(filename, THRD_SIB_FMT, cpu);
780 fp = fopen(filename, "r"); 766 fp = fopen(filename, "r");
781 if (!fp) 767 if (!fp)
@@ -1380,6 +1366,9 @@ static void print_event_desc(struct perf_header *ph, int fd, FILE *fp)
1380 1366
1381 fprintf(fp, ", precise_ip = %d", evsel->attr.precise_ip); 1367 fprintf(fp, ", precise_ip = %d", evsel->attr.precise_ip);
1382 1368
1369 fprintf(fp, ", attr_mmap2 = %d", evsel->attr.mmap2);
1370 fprintf(fp, ", attr_mmap = %d", evsel->attr.mmap);
1371 fprintf(fp, ", attr_mmap_data = %d", evsel->attr.mmap_data);
1383 if (evsel->ids) { 1372 if (evsel->ids) {
1384 fprintf(fp, ", id = {"); 1373 fprintf(fp, ", id = {");
1385 for (j = 0, id = evsel->id; j < evsel->ids; j++, id++) { 1374 for (j = 0, id = evsel->id; j < evsel->ids; j++, id++) {
@@ -2257,7 +2246,7 @@ static int perf_header__adds_write(struct perf_header *header,
2257 2246
2258 sec_size = sizeof(*feat_sec) * nr_sections; 2247 sec_size = sizeof(*feat_sec) * nr_sections;
2259 2248
2260 sec_start = header->data_offset + header->data_size; 2249 sec_start = header->feat_offset;
2261 lseek(fd, sec_start + sec_size, SEEK_SET); 2250 lseek(fd, sec_start + sec_size, SEEK_SET);
2262 2251
2263 for_each_set_bit(feat, header->adds_features, HEADER_FEAT_BITS) { 2252 for_each_set_bit(feat, header->adds_features, HEADER_FEAT_BITS) {
@@ -2304,6 +2293,7 @@ int perf_session__write_header(struct perf_session *session,
2304 struct perf_file_attr f_attr; 2293 struct perf_file_attr f_attr;
2305 struct perf_header *header = &session->header; 2294 struct perf_header *header = &session->header;
2306 struct perf_evsel *evsel; 2295 struct perf_evsel *evsel;
2296 u64 attr_offset;
2307 int err; 2297 int err;
2308 2298
2309 lseek(fd, sizeof(f_header), SEEK_SET); 2299 lseek(fd, sizeof(f_header), SEEK_SET);
@@ -2317,7 +2307,7 @@ int perf_session__write_header(struct perf_session *session,
2317 } 2307 }
2318 } 2308 }
2319 2309
2320 header->attr_offset = lseek(fd, 0, SEEK_CUR); 2310 attr_offset = lseek(fd, 0, SEEK_CUR);
2321 2311
2322 list_for_each_entry(evsel, &evlist->entries, node) { 2312 list_for_each_entry(evsel, &evlist->entries, node) {
2323 f_attr = (struct perf_file_attr){ 2313 f_attr = (struct perf_file_attr){
@@ -2334,17 +2324,8 @@ int perf_session__write_header(struct perf_session *session,
2334 } 2324 }
2335 } 2325 }
2336 2326
2337 header->event_offset = lseek(fd, 0, SEEK_CUR);
2338 header->event_size = trace_event_count * sizeof(struct perf_trace_event_type);
2339 if (trace_events) {
2340 err = do_write(fd, trace_events, header->event_size);
2341 if (err < 0) {
2342 pr_debug("failed to write perf header events\n");
2343 return err;
2344 }
2345 }
2346
2347 header->data_offset = lseek(fd, 0, SEEK_CUR); 2327 header->data_offset = lseek(fd, 0, SEEK_CUR);
2328 header->feat_offset = header->data_offset + header->data_size;
2348 2329
2349 if (at_exit) { 2330 if (at_exit) {
2350 err = perf_header__adds_write(header, evlist, fd); 2331 err = perf_header__adds_write(header, evlist, fd);
@@ -2357,17 +2338,14 @@ int perf_session__write_header(struct perf_session *session,
2357 .size = sizeof(f_header), 2338 .size = sizeof(f_header),
2358 .attr_size = sizeof(f_attr), 2339 .attr_size = sizeof(f_attr),
2359 .attrs = { 2340 .attrs = {
2360 .offset = header->attr_offset, 2341 .offset = attr_offset,
2361 .size = evlist->nr_entries * sizeof(f_attr), 2342 .size = evlist->nr_entries * sizeof(f_attr),
2362 }, 2343 },
2363 .data = { 2344 .data = {
2364 .offset = header->data_offset, 2345 .offset = header->data_offset,
2365 .size = header->data_size, 2346 .size = header->data_size,
2366 }, 2347 },
2367 .event_types = { 2348 /* event_types is ignored, store zeros */
2368 .offset = header->event_offset,
2369 .size = header->event_size,
2370 },
2371 }; 2349 };
2372 2350
2373 memcpy(&f_header.adds_features, &header->adds_features, sizeof(header->adds_features)); 2351 memcpy(&f_header.adds_features, &header->adds_features, sizeof(header->adds_features));
@@ -2417,7 +2395,7 @@ int perf_header__process_sections(struct perf_header *header, int fd,
2417 2395
2418 sec_size = sizeof(*feat_sec) * nr_sections; 2396 sec_size = sizeof(*feat_sec) * nr_sections;
2419 2397
2420 lseek(fd, header->data_offset + header->data_size, SEEK_SET); 2398 lseek(fd, header->feat_offset, SEEK_SET);
2421 2399
2422 err = perf_header__getbuffer64(header, fd, feat_sec, sec_size); 2400 err = perf_header__getbuffer64(header, fd, feat_sec, sec_size);
2423 if (err < 0) 2401 if (err < 0)
@@ -2523,6 +2501,7 @@ static int check_magic_endian(u64 magic, uint64_t hdr_sz,
2523 /* check for legacy format */ 2501 /* check for legacy format */
2524 ret = memcmp(&magic, __perf_magic1, sizeof(magic)); 2502 ret = memcmp(&magic, __perf_magic1, sizeof(magic));
2525 if (ret == 0) { 2503 if (ret == 0) {
2504 ph->version = PERF_HEADER_VERSION_1;
2526 pr_debug("legacy perf.data format\n"); 2505 pr_debug("legacy perf.data format\n");
2527 if (is_pipe) 2506 if (is_pipe)
2528 return try_all_pipe_abis(hdr_sz, ph); 2507 return try_all_pipe_abis(hdr_sz, ph);
@@ -2544,6 +2523,7 @@ static int check_magic_endian(u64 magic, uint64_t hdr_sz,
2544 return -1; 2523 return -1;
2545 2524
2546 ph->needs_swap = true; 2525 ph->needs_swap = true;
2526 ph->version = PERF_HEADER_VERSION_2;
2547 2527
2548 return 0; 2528 return 0;
2549} 2529}
@@ -2614,10 +2594,9 @@ int perf_file_header__read(struct perf_file_header *header,
2614 memcpy(&ph->adds_features, &header->adds_features, 2594 memcpy(&ph->adds_features, &header->adds_features,
2615 sizeof(ph->adds_features)); 2595 sizeof(ph->adds_features));
2616 2596
2617 ph->event_offset = header->event_types.offset;
2618 ph->event_size = header->event_types.size;
2619 ph->data_offset = header->data.offset; 2597 ph->data_offset = header->data.offset;
2620 ph->data_size = header->data.size; 2598 ph->data_size = header->data.size;
2599 ph->feat_offset = header->data.offset + header->data.size;
2621 return 0; 2600 return 0;
2622} 2601}
2623 2602
@@ -2666,19 +2645,17 @@ static int perf_file_header__read_pipe(struct perf_pipe_file_header *header,
2666 return 0; 2645 return 0;
2667} 2646}
2668 2647
2669static int perf_header__read_pipe(struct perf_session *session, int fd) 2648static int perf_header__read_pipe(struct perf_session *session)
2670{ 2649{
2671 struct perf_header *header = &session->header; 2650 struct perf_header *header = &session->header;
2672 struct perf_pipe_file_header f_header; 2651 struct perf_pipe_file_header f_header;
2673 2652
2674 if (perf_file_header__read_pipe(&f_header, header, fd, 2653 if (perf_file_header__read_pipe(&f_header, header, session->fd,
2675 session->repipe) < 0) { 2654 session->repipe) < 0) {
2676 pr_debug("incompatible file format\n"); 2655 pr_debug("incompatible file format\n");
2677 return -EINVAL; 2656 return -EINVAL;
2678 } 2657 }
2679 2658
2680 session->fd = fd;
2681
2682 return 0; 2659 return 0;
2683} 2660}
2684 2661
@@ -2772,20 +2749,21 @@ static int perf_evlist__prepare_tracepoint_events(struct perf_evlist *evlist,
2772 return 0; 2749 return 0;
2773} 2750}
2774 2751
2775int perf_session__read_header(struct perf_session *session, int fd) 2752int perf_session__read_header(struct perf_session *session)
2776{ 2753{
2777 struct perf_header *header = &session->header; 2754 struct perf_header *header = &session->header;
2778 struct perf_file_header f_header; 2755 struct perf_file_header f_header;
2779 struct perf_file_attr f_attr; 2756 struct perf_file_attr f_attr;
2780 u64 f_id; 2757 u64 f_id;
2781 int nr_attrs, nr_ids, i, j; 2758 int nr_attrs, nr_ids, i, j;
2759 int fd = session->fd;
2782 2760
2783 session->evlist = perf_evlist__new(); 2761 session->evlist = perf_evlist__new();
2784 if (session->evlist == NULL) 2762 if (session->evlist == NULL)
2785 return -ENOMEM; 2763 return -ENOMEM;
2786 2764
2787 if (session->fd_pipe) 2765 if (session->fd_pipe)
2788 return perf_header__read_pipe(session, fd); 2766 return perf_header__read_pipe(session);
2789 2767
2790 if (perf_file_header__read(&f_header, header, fd) < 0) 2768 if (perf_file_header__read(&f_header, header, fd) < 0)
2791 return -EINVAL; 2769 return -EINVAL;
@@ -2839,22 +2817,9 @@ int perf_session__read_header(struct perf_session *session, int fd)
2839 2817
2840 symbol_conf.nr_events = nr_attrs; 2818 symbol_conf.nr_events = nr_attrs;
2841 2819
2842 if (f_header.event_types.size) {
2843 lseek(fd, f_header.event_types.offset, SEEK_SET);
2844 trace_events = malloc(f_header.event_types.size);
2845 if (trace_events == NULL)
2846 return -ENOMEM;
2847 if (perf_header__getbuffer64(header, fd, trace_events,
2848 f_header.event_types.size))
2849 goto out_errno;
2850 trace_event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
2851 }
2852
2853 perf_header__process_sections(header, fd, &session->pevent, 2820 perf_header__process_sections(header, fd, &session->pevent,
2854 perf_file_section__process); 2821 perf_file_section__process);
2855 2822
2856 lseek(fd, header->data_offset, SEEK_SET);
2857
2858 if (perf_evlist__prepare_tracepoint_events(session->evlist, 2823 if (perf_evlist__prepare_tracepoint_events(session->evlist,
2859 session->pevent)) 2824 session->pevent))
2860 goto out_delete_evlist; 2825 goto out_delete_evlist;
@@ -2922,7 +2887,8 @@ int perf_event__synthesize_attrs(struct perf_tool *tool,
2922 return err; 2887 return err;
2923} 2888}
2924 2889
2925int perf_event__process_attr(union perf_event *event, 2890int perf_event__process_attr(struct perf_tool *tool __maybe_unused,
2891 union perf_event *event,
2926 struct perf_evlist **pevlist) 2892 struct perf_evlist **pevlist)
2927{ 2893{
2928 u32 i, ids, n_ids; 2894 u32 i, ids, n_ids;
@@ -2961,64 +2927,6 @@ int perf_event__process_attr(union perf_event *event,
2961 return 0; 2927 return 0;
2962} 2928}
2963 2929
2964int perf_event__synthesize_event_type(struct perf_tool *tool,
2965 u64 event_id, char *name,
2966 perf_event__handler_t process,
2967 struct machine *machine)
2968{
2969 union perf_event ev;
2970 size_t size = 0;
2971 int err = 0;
2972
2973 memset(&ev, 0, sizeof(ev));
2974
2975 ev.event_type.event_type.event_id = event_id;
2976 memset(ev.event_type.event_type.name, 0, MAX_EVENT_NAME);
2977 strncpy(ev.event_type.event_type.name, name, MAX_EVENT_NAME - 1);
2978
2979 ev.event_type.header.type = PERF_RECORD_HEADER_EVENT_TYPE;
2980 size = strlen(ev.event_type.event_type.name);
2981 size = PERF_ALIGN(size, sizeof(u64));
2982 ev.event_type.header.size = sizeof(ev.event_type) -
2983 (sizeof(ev.event_type.event_type.name) - size);
2984
2985 err = process(tool, &ev, NULL, machine);
2986
2987 return err;
2988}
2989
2990int perf_event__synthesize_event_types(struct perf_tool *tool,
2991 perf_event__handler_t process,
2992 struct machine *machine)
2993{
2994 struct perf_trace_event_type *type;
2995 int i, err = 0;
2996
2997 for (i = 0; i < trace_event_count; i++) {
2998 type = &trace_events[i];
2999
3000 err = perf_event__synthesize_event_type(tool, type->event_id,
3001 type->name, process,
3002 machine);
3003 if (err) {
3004 pr_debug("failed to create perf header event type\n");
3005 return err;
3006 }
3007 }
3008
3009 return err;
3010}
3011
3012int perf_event__process_event_type(struct perf_tool *tool __maybe_unused,
3013 union perf_event *event)
3014{
3015 if (perf_header__push_event(event->event_type.event_type.event_id,
3016 event->event_type.event_type.name) < 0)
3017 return -ENOMEM;
3018
3019 return 0;
3020}
3021
3022int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, 2930int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd,
3023 struct perf_evlist *evlist, 2931 struct perf_evlist *evlist,
3024 perf_event__handler_t process) 2932 perf_event__handler_t process)
@@ -3065,7 +2973,8 @@ int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd,
3065 return aligned_size; 2973 return aligned_size;
3066} 2974}
3067 2975
3068int perf_event__process_tracing_data(union perf_event *event, 2976int perf_event__process_tracing_data(struct perf_tool *tool __maybe_unused,
2977 union perf_event *event,
3069 struct perf_session *session) 2978 struct perf_session *session)
3070{ 2979{
3071 ssize_t size_read, padding, size = event->tracing_data.size; 2980 ssize_t size_read, padding, size = event->tracing_data.size;
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 16a3e83c584e..307c9aed972e 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -34,6 +34,11 @@ enum {
34 HEADER_FEAT_BITS = 256, 34 HEADER_FEAT_BITS = 256,
35}; 35};
36 36
37enum perf_header_version {
38 PERF_HEADER_VERSION_1,
39 PERF_HEADER_VERSION_2,
40};
41
37struct perf_file_section { 42struct perf_file_section {
38 u64 offset; 43 u64 offset;
39 u64 size; 44 u64 size;
@@ -45,6 +50,7 @@ struct perf_file_header {
45 u64 attr_size; 50 u64 attr_size;
46 struct perf_file_section attrs; 51 struct perf_file_section attrs;
47 struct perf_file_section data; 52 struct perf_file_section data;
53 /* event_types is ignored */
48 struct perf_file_section event_types; 54 struct perf_file_section event_types;
49 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS); 55 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
50}; 56};
@@ -84,28 +90,24 @@ struct perf_session_env {
84}; 90};
85 91
86struct perf_header { 92struct perf_header {
87 bool needs_swap; 93 enum perf_header_version version;
88 s64 attr_offset; 94 bool needs_swap;
89 u64 data_offset; 95 u64 data_offset;
90 u64 data_size; 96 u64 data_size;
91 u64 event_offset; 97 u64 feat_offset;
92 u64 event_size;
93 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS); 98 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
94 struct perf_session_env env; 99 struct perf_session_env env;
95}; 100};
96 101
97struct perf_evlist; 102struct perf_evlist;
98struct perf_session; 103struct perf_session;
99 104
100int perf_session__read_header(struct perf_session *session, int fd); 105int perf_session__read_header(struct perf_session *session);
101int perf_session__write_header(struct perf_session *session, 106int perf_session__write_header(struct perf_session *session,
102 struct perf_evlist *evlist, 107 struct perf_evlist *evlist,
103 int fd, bool at_exit); 108 int fd, bool at_exit);
104int perf_header__write_pipe(int fd); 109int perf_header__write_pipe(int fd);
105 110
106int perf_header__push_event(u64 id, const char *name);
107char *perf_header__find_event(u64 id);
108
109void perf_header__set_feat(struct perf_header *header, int feat); 111void perf_header__set_feat(struct perf_header *header, int feat);
110void perf_header__clear_feat(struct perf_header *header, int feat); 112void perf_header__clear_feat(struct perf_header *header, int feat);
111bool perf_header__has_feat(const struct perf_header *header, int feat); 113bool perf_header__has_feat(const struct perf_header *header, int feat);
@@ -130,22 +132,14 @@ int perf_event__synthesize_attr(struct perf_tool *tool,
130int perf_event__synthesize_attrs(struct perf_tool *tool, 132int perf_event__synthesize_attrs(struct perf_tool *tool,
131 struct perf_session *session, 133 struct perf_session *session,
132 perf_event__handler_t process); 134 perf_event__handler_t process);
133int perf_event__process_attr(union perf_event *event, struct perf_evlist **pevlist); 135int perf_event__process_attr(struct perf_tool *tool, union perf_event *event,
134 136 struct perf_evlist **pevlist);
135int perf_event__synthesize_event_type(struct perf_tool *tool,
136 u64 event_id, char *name,
137 perf_event__handler_t process,
138 struct machine *machine);
139int perf_event__synthesize_event_types(struct perf_tool *tool,
140 perf_event__handler_t process,
141 struct machine *machine);
142int perf_event__process_event_type(struct perf_tool *tool,
143 union perf_event *event);
144 137
145int perf_event__synthesize_tracing_data(struct perf_tool *tool, 138int perf_event__synthesize_tracing_data(struct perf_tool *tool,
146 int fd, struct perf_evlist *evlist, 139 int fd, struct perf_evlist *evlist,
147 perf_event__handler_t process); 140 perf_event__handler_t process);
148int perf_event__process_tracing_data(union perf_event *event, 141int perf_event__process_tracing_data(struct perf_tool *tool,
142 union perf_event *event,
149 struct perf_session *session); 143 struct perf_session *session);
150 144
151int perf_event__synthesize_build_id(struct perf_tool *tool, 145int perf_event__synthesize_build_id(struct perf_tool *tool,
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index b11a6cfdb414..9ff6cf3e9a99 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -24,7 +24,8 @@ enum hist_filter {
24struct callchain_param callchain_param = { 24struct callchain_param callchain_param = {
25 .mode = CHAIN_GRAPH_REL, 25 .mode = CHAIN_GRAPH_REL,
26 .min_percent = 0.5, 26 .min_percent = 0.5,
27 .order = ORDER_CALLEE 27 .order = ORDER_CALLEE,
28 .key = CCKEY_FUNCTION
28}; 29};
29 30
30u16 hists__col_len(struct hists *hists, enum hist_column col) 31u16 hists__col_len(struct hists *hists, enum hist_column col)
@@ -610,6 +611,8 @@ void hists__collapse_resort(struct hists *hists)
610 next = rb_first(root); 611 next = rb_first(root);
611 612
612 while (next) { 613 while (next) {
614 if (session_done())
615 break;
613 n = rb_entry(next, struct hist_entry, rb_node_in); 616 n = rb_entry(next, struct hist_entry, rb_node_in);
614 next = rb_next(&n->rb_node_in); 617 next = rb_next(&n->rb_node_in);
615 618
@@ -912,6 +915,7 @@ static struct hist_entry *hists__add_dummy_entry(struct hists *hists,
912 rb_link_node(&he->rb_node_in, parent, p); 915 rb_link_node(&he->rb_node_in, parent, p);
913 rb_insert_color(&he->rb_node_in, root); 916 rb_insert_color(&he->rb_node_in, root);
914 hists__inc_nr_entries(hists, he); 917 hists__inc_nr_entries(hists, he);
918 he->dummy = true;
915 } 919 }
916out: 920out:
917 return he; 921 return he;
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 2d3790fd99bb..1329b6b6ffe6 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -141,10 +141,12 @@ struct perf_hpp {
141}; 141};
142 142
143struct perf_hpp_fmt { 143struct perf_hpp_fmt {
144 int (*header)(struct perf_hpp *hpp); 144 int (*header)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp);
145 int (*width)(struct perf_hpp *hpp); 145 int (*width)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp);
146 int (*color)(struct perf_hpp *hpp, struct hist_entry *he); 146 int (*color)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
147 int (*entry)(struct perf_hpp *hpp, struct hist_entry *he); 147 struct hist_entry *he);
148 int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
149 struct hist_entry *he);
148 150
149 struct list_head list; 151 struct list_head list;
150}; 152};
@@ -157,7 +159,7 @@ extern struct list_head perf_hpp__list;
157extern struct perf_hpp_fmt perf_hpp__format[]; 159extern struct perf_hpp_fmt perf_hpp__format[];
158 160
159enum { 161enum {
160 PERF_HPP__BASELINE, 162 /* Matches perf_hpp__format array. */
161 PERF_HPP__OVERHEAD, 163 PERF_HPP__OVERHEAD,
162 PERF_HPP__OVERHEAD_SYS, 164 PERF_HPP__OVERHEAD_SYS,
163 PERF_HPP__OVERHEAD_US, 165 PERF_HPP__OVERHEAD_US,
@@ -165,11 +167,6 @@ enum {
165 PERF_HPP__OVERHEAD_GUEST_US, 167 PERF_HPP__OVERHEAD_GUEST_US,
166 PERF_HPP__SAMPLES, 168 PERF_HPP__SAMPLES,
167 PERF_HPP__PERIOD, 169 PERF_HPP__PERIOD,
168 PERF_HPP__PERIOD_BASELINE,
169 PERF_HPP__DELTA,
170 PERF_HPP__RATIO,
171 PERF_HPP__WEIGHTED_DIFF,
172 PERF_HPP__FORMULA,
173 170
174 PERF_HPP__MAX_INDEX 171 PERF_HPP__MAX_INDEX
175}; 172};
@@ -177,8 +174,6 @@ enum {
177void perf_hpp__init(void); 174void perf_hpp__init(void);
178void perf_hpp__column_register(struct perf_hpp_fmt *format); 175void perf_hpp__column_register(struct perf_hpp_fmt *format);
179void perf_hpp__column_enable(unsigned col); 176void perf_hpp__column_enable(unsigned col);
180int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he,
181 bool color);
182 177
183struct perf_evlist; 178struct perf_evlist;
184 179
@@ -245,11 +240,4 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused,
245#endif 240#endif
246 241
247unsigned int hists__sort_list_width(struct hists *self); 242unsigned int hists__sort_list_width(struct hists *self);
248
249double perf_diff__compute_delta(struct hist_entry *he, struct hist_entry *pair);
250double perf_diff__compute_ratio(struct hist_entry *he, struct hist_entry *pair);
251s64 perf_diff__compute_wdiff(struct hist_entry *he, struct hist_entry *pair);
252int perf_diff__formula(struct hist_entry *he, struct hist_entry *pair,
253 char *buf, size_t size);
254double perf_diff__period_percent(struct hist_entry *he, u64 period);
255#endif /* __PERF_HIST_H */ 243#endif /* __PERF_HIST_H */
diff --git a/tools/perf/util/include/linux/string.h b/tools/perf/util/include/linux/string.h
index 6f19c548ecc0..97a800738226 100644
--- a/tools/perf/util/include/linux/string.h
+++ b/tools/perf/util/include/linux/string.h
@@ -1,3 +1,4 @@
1#include <string.h> 1#include <string.h>
2 2
3void *memdup(const void *src, size_t len); 3void *memdup(const void *src, size_t len);
4int str_append(char **s, int *len, const char *a);
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index b2ecad6ec46b..6188d2876a71 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -25,12 +25,15 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
25 machine->kmaps.machine = machine; 25 machine->kmaps.machine = machine;
26 machine->pid = pid; 26 machine->pid = pid;
27 27
28 machine->symbol_filter = NULL;
29
28 machine->root_dir = strdup(root_dir); 30 machine->root_dir = strdup(root_dir);
29 if (machine->root_dir == NULL) 31 if (machine->root_dir == NULL)
30 return -ENOMEM; 32 return -ENOMEM;
31 33
32 if (pid != HOST_KERNEL_ID) { 34 if (pid != HOST_KERNEL_ID) {
33 struct thread *thread = machine__findnew_thread(machine, pid); 35 struct thread *thread = machine__findnew_thread(machine, 0,
36 pid);
34 char comm[64]; 37 char comm[64];
35 38
36 if (thread == NULL) 39 if (thread == NULL)
@@ -95,6 +98,7 @@ void machines__init(struct machines *machines)
95{ 98{
96 machine__init(&machines->host, "", HOST_KERNEL_ID); 99 machine__init(&machines->host, "", HOST_KERNEL_ID);
97 machines->guests = RB_ROOT; 100 machines->guests = RB_ROOT;
101 machines->symbol_filter = NULL;
98} 102}
99 103
100void machines__exit(struct machines *machines) 104void machines__exit(struct machines *machines)
@@ -118,6 +122,8 @@ struct machine *machines__add(struct machines *machines, pid_t pid,
118 return NULL; 122 return NULL;
119 } 123 }
120 124
125 machine->symbol_filter = machines->symbol_filter;
126
121 while (*p != NULL) { 127 while (*p != NULL) {
122 parent = *p; 128 parent = *p;
123 pos = rb_entry(parent, struct machine, rb_node); 129 pos = rb_entry(parent, struct machine, rb_node);
@@ -133,6 +139,21 @@ struct machine *machines__add(struct machines *machines, pid_t pid,
133 return machine; 139 return machine;
134} 140}
135 141
142void machines__set_symbol_filter(struct machines *machines,
143 symbol_filter_t symbol_filter)
144{
145 struct rb_node *nd;
146
147 machines->symbol_filter = symbol_filter;
148 machines->host.symbol_filter = symbol_filter;
149
150 for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
151 struct machine *machine = rb_entry(nd, struct machine, rb_node);
152
153 machine->symbol_filter = symbol_filter;
154 }
155}
156
136struct machine *machines__find(struct machines *machines, pid_t pid) 157struct machine *machines__find(struct machines *machines, pid_t pid)
137{ 158{
138 struct rb_node **p = &machines->guests.rb_node; 159 struct rb_node **p = &machines->guests.rb_node;
@@ -233,7 +254,8 @@ void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size)
233 return; 254 return;
234} 255}
235 256
236static struct thread *__machine__findnew_thread(struct machine *machine, pid_t pid, 257static struct thread *__machine__findnew_thread(struct machine *machine,
258 pid_t pid, pid_t tid,
237 bool create) 259 bool create)
238{ 260{
239 struct rb_node **p = &machine->threads.rb_node; 261 struct rb_node **p = &machine->threads.rb_node;
@@ -241,23 +263,28 @@ static struct thread *__machine__findnew_thread(struct machine *machine, pid_t p
241 struct thread *th; 263 struct thread *th;
242 264
243 /* 265 /*
244 * Font-end cache - PID lookups come in blocks, 266 * Front-end cache - TID lookups come in blocks,
245 * so most of the time we dont have to look up 267 * so most of the time we dont have to look up
246 * the full rbtree: 268 * the full rbtree:
247 */ 269 */
248 if (machine->last_match && machine->last_match->pid == pid) 270 if (machine->last_match && machine->last_match->tid == tid) {
271 if (pid && pid != machine->last_match->pid_)
272 machine->last_match->pid_ = pid;
249 return machine->last_match; 273 return machine->last_match;
274 }
250 275
251 while (*p != NULL) { 276 while (*p != NULL) {
252 parent = *p; 277 parent = *p;
253 th = rb_entry(parent, struct thread, rb_node); 278 th = rb_entry(parent, struct thread, rb_node);
254 279
255 if (th->pid == pid) { 280 if (th->tid == tid) {
256 machine->last_match = th; 281 machine->last_match = th;
282 if (pid && pid != th->pid_)
283 th->pid_ = pid;
257 return th; 284 return th;
258 } 285 }
259 286
260 if (pid < th->pid) 287 if (tid < th->tid)
261 p = &(*p)->rb_left; 288 p = &(*p)->rb_left;
262 else 289 else
263 p = &(*p)->rb_right; 290 p = &(*p)->rb_right;
@@ -266,7 +293,7 @@ static struct thread *__machine__findnew_thread(struct machine *machine, pid_t p
266 if (!create) 293 if (!create)
267 return NULL; 294 return NULL;
268 295
269 th = thread__new(pid); 296 th = thread__new(pid, tid);
270 if (th != NULL) { 297 if (th != NULL) {
271 rb_link_node(&th->rb_node, parent, p); 298 rb_link_node(&th->rb_node, parent, p);
272 rb_insert_color(&th->rb_node, &machine->threads); 299 rb_insert_color(&th->rb_node, &machine->threads);
@@ -276,19 +303,22 @@ static struct thread *__machine__findnew_thread(struct machine *machine, pid_t p
276 return th; 303 return th;
277} 304}
278 305
279struct thread *machine__findnew_thread(struct machine *machine, pid_t pid) 306struct thread *machine__findnew_thread(struct machine *machine, pid_t pid,
307 pid_t tid)
280{ 308{
281 return __machine__findnew_thread(machine, pid, true); 309 return __machine__findnew_thread(machine, pid, tid, true);
282} 310}
283 311
284struct thread *machine__find_thread(struct machine *machine, pid_t pid) 312struct thread *machine__find_thread(struct machine *machine, pid_t tid)
285{ 313{
286 return __machine__findnew_thread(machine, pid, false); 314 return __machine__findnew_thread(machine, 0, tid, false);
287} 315}
288 316
289int machine__process_comm_event(struct machine *machine, union perf_event *event) 317int machine__process_comm_event(struct machine *machine, union perf_event *event)
290{ 318{
291 struct thread *thread = machine__findnew_thread(machine, event->comm.tid); 319 struct thread *thread = machine__findnew_thread(machine,
320 event->comm.pid,
321 event->comm.tid);
292 322
293 if (dump_trace) 323 if (dump_trace)
294 perf_event__fprintf_comm(event, stdout); 324 perf_event__fprintf_comm(event, stdout);
@@ -628,10 +658,8 @@ int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
628 struct map *map = machine->vmlinux_maps[type]; 658 struct map *map = machine->vmlinux_maps[type];
629 int ret = dso__load_vmlinux_path(map->dso, map, filter); 659 int ret = dso__load_vmlinux_path(map->dso, map, filter);
630 660
631 if (ret > 0) { 661 if (ret > 0)
632 dso__set_loaded(map->dso, type); 662 dso__set_loaded(map->dso, type);
633 map__reloc_vmlinux(map);
634 }
635 663
636 return ret; 664 return ret;
637} 665}
@@ -764,7 +792,7 @@ static int machine__create_modules(struct machine *machine)
764 modules = path; 792 modules = path;
765 } 793 }
766 794
767 if (symbol__restricted_filename(path, "/proc/modules")) 795 if (symbol__restricted_filename(modules, "/proc/modules"))
768 return -1; 796 return -1;
769 797
770 file = fopen(modules, "r"); 798 file = fopen(modules, "r");
@@ -808,7 +836,10 @@ static int machine__create_modules(struct machine *machine)
808 free(line); 836 free(line);
809 fclose(file); 837 fclose(file);
810 838
811 return machine__set_modules_path(machine); 839 if (machine__set_modules_path(machine) < 0) {
840 pr_debug("Problems setting modules path maps, continuing anyway...\n");
841 }
842 return 0;
812 843
813out_delete_line: 844out_delete_line:
814 free(line); 845 free(line);
@@ -858,6 +889,18 @@ static void machine__set_kernel_mmap_len(struct machine *machine,
858 } 889 }
859} 890}
860 891
892static bool machine__uses_kcore(struct machine *machine)
893{
894 struct dso *dso;
895
896 list_for_each_entry(dso, &machine->kernel_dsos, node) {
897 if (dso__is_kcore(dso))
898 return true;
899 }
900
901 return false;
902}
903
861static int machine__process_kernel_mmap_event(struct machine *machine, 904static int machine__process_kernel_mmap_event(struct machine *machine,
862 union perf_event *event) 905 union perf_event *event)
863{ 906{
@@ -866,6 +909,10 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
866 enum dso_kernel_type kernel_type; 909 enum dso_kernel_type kernel_type;
867 bool is_kernel_mmap; 910 bool is_kernel_mmap;
868 911
912 /* If we have maps from kcore then we do not need or want any others */
913 if (machine__uses_kcore(machine))
914 return 0;
915
869 machine__mmap_name(machine, kmmap_prefix, sizeof(kmmap_prefix)); 916 machine__mmap_name(machine, kmmap_prefix, sizeof(kmmap_prefix));
870 if (machine__is_host(machine)) 917 if (machine__is_host(machine))
871 kernel_type = DSO_TYPE_KERNEL; 918 kernel_type = DSO_TYPE_KERNEL;
@@ -950,6 +997,54 @@ out_problem:
950 return -1; 997 return -1;
951} 998}
952 999
1000int machine__process_mmap2_event(struct machine *machine,
1001 union perf_event *event)
1002{
1003 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
1004 struct thread *thread;
1005 struct map *map;
1006 enum map_type type;
1007 int ret = 0;
1008
1009 if (dump_trace)
1010 perf_event__fprintf_mmap2(event, stdout);
1011
1012 if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
1013 cpumode == PERF_RECORD_MISC_KERNEL) {
1014 ret = machine__process_kernel_mmap_event(machine, event);
1015 if (ret < 0)
1016 goto out_problem;
1017 return 0;
1018 }
1019
1020 thread = machine__findnew_thread(machine, event->mmap2.pid,
1021 event->mmap2.pid);
1022 if (thread == NULL)
1023 goto out_problem;
1024
1025 if (event->header.misc & PERF_RECORD_MISC_MMAP_DATA)
1026 type = MAP__VARIABLE;
1027 else
1028 type = MAP__FUNCTION;
1029
1030 map = map__new(&machine->user_dsos, event->mmap2.start,
1031 event->mmap2.len, event->mmap2.pgoff,
1032 event->mmap2.pid, event->mmap2.maj,
1033 event->mmap2.min, event->mmap2.ino,
1034 event->mmap2.ino_generation,
1035 event->mmap2.filename, type);
1036
1037 if (map == NULL)
1038 goto out_problem;
1039
1040 thread__insert_map(thread, map);
1041 return 0;
1042
1043out_problem:
1044 dump_printf("problem processing PERF_RECORD_MMAP2, skipping event.\n");
1045 return 0;
1046}
1047
953int machine__process_mmap_event(struct machine *machine, union perf_event *event) 1048int machine__process_mmap_event(struct machine *machine, union perf_event *event)
954{ 1049{
955 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 1050 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
@@ -969,7 +1064,8 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
969 return 0; 1064 return 0;
970 } 1065 }
971 1066
972 thread = machine__findnew_thread(machine, event->mmap.pid); 1067 thread = machine__findnew_thread(machine, event->mmap.pid,
1068 event->mmap.pid);
973 if (thread == NULL) 1069 if (thread == NULL)
974 goto out_problem; 1070 goto out_problem;
975 1071
@@ -980,7 +1076,8 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
980 1076
981 map = map__new(&machine->user_dsos, event->mmap.start, 1077 map = map__new(&machine->user_dsos, event->mmap.start,
982 event->mmap.len, event->mmap.pgoff, 1078 event->mmap.len, event->mmap.pgoff,
983 event->mmap.pid, event->mmap.filename, 1079 event->mmap.pid, 0, 0, 0, 0,
1080 event->mmap.filename,
984 type); 1081 type);
985 1082
986 if (map == NULL) 1083 if (map == NULL)
@@ -994,11 +1091,30 @@ out_problem:
994 return 0; 1091 return 0;
995} 1092}
996 1093
1094static void machine__remove_thread(struct machine *machine, struct thread *th)
1095{
1096 machine->last_match = NULL;
1097 rb_erase(&th->rb_node, &machine->threads);
1098 /*
1099 * We may have references to this thread, for instance in some hist_entry
1100 * instances, so just move them to a separate list.
1101 */
1102 list_add_tail(&th->node, &machine->dead_threads);
1103}
1104
997int machine__process_fork_event(struct machine *machine, union perf_event *event) 1105int machine__process_fork_event(struct machine *machine, union perf_event *event)
998{ 1106{
999 struct thread *thread = machine__findnew_thread(machine, event->fork.tid); 1107 struct thread *thread = machine__find_thread(machine, event->fork.tid);
1000 struct thread *parent = machine__findnew_thread(machine, event->fork.ptid); 1108 struct thread *parent = machine__findnew_thread(machine,
1109 event->fork.ppid,
1110 event->fork.ptid);
1001 1111
1112 /* if a thread currently exists for the thread id remove it */
1113 if (thread != NULL)
1114 machine__remove_thread(machine, thread);
1115
1116 thread = machine__findnew_thread(machine, event->fork.pid,
1117 event->fork.tid);
1002 if (dump_trace) 1118 if (dump_trace)
1003 perf_event__fprintf_task(event, stdout); 1119 perf_event__fprintf_task(event, stdout);
1004 1120
@@ -1011,18 +1127,8 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event
1011 return 0; 1127 return 0;
1012} 1128}
1013 1129
1014static void machine__remove_thread(struct machine *machine, struct thread *th) 1130int machine__process_exit_event(struct machine *machine __maybe_unused,
1015{ 1131 union perf_event *event)
1016 machine->last_match = NULL;
1017 rb_erase(&th->rb_node, &machine->threads);
1018 /*
1019 * We may have references to this thread, for instance in some hist_entry
1020 * instances, so just move them to a separate list.
1021 */
1022 list_add_tail(&th->node, &machine->dead_threads);
1023}
1024
1025int machine__process_exit_event(struct machine *machine, union perf_event *event)
1026{ 1132{
1027 struct thread *thread = machine__find_thread(machine, event->fork.tid); 1133 struct thread *thread = machine__find_thread(machine, event->fork.tid);
1028 1134
@@ -1030,7 +1136,7 @@ int machine__process_exit_event(struct machine *machine, union perf_event *event
1030 perf_event__fprintf_task(event, stdout); 1136 perf_event__fprintf_task(event, stdout);
1031 1137
1032 if (thread != NULL) 1138 if (thread != NULL)
1033 machine__remove_thread(machine, thread); 1139 thread__exited(thread);
1034 1140
1035 return 0; 1141 return 0;
1036} 1142}
@@ -1044,6 +1150,8 @@ int machine__process_event(struct machine *machine, union perf_event *event)
1044 ret = machine__process_comm_event(machine, event); break; 1150 ret = machine__process_comm_event(machine, event); break;
1045 case PERF_RECORD_MMAP: 1151 case PERF_RECORD_MMAP:
1046 ret = machine__process_mmap_event(machine, event); break; 1152 ret = machine__process_mmap_event(machine, event); break;
1153 case PERF_RECORD_MMAP2:
1154 ret = machine__process_mmap2_event(machine, event); break;
1047 case PERF_RECORD_FORK: 1155 case PERF_RECORD_FORK:
1048 ret = machine__process_fork_event(machine, event); break; 1156 ret = machine__process_fork_event(machine, event); break;
1049 case PERF_RECORD_EXIT: 1157 case PERF_RECORD_EXIT:
@@ -1058,11 +1166,10 @@ int machine__process_event(struct machine *machine, union perf_event *event)
1058 return ret; 1166 return ret;
1059} 1167}
1060 1168
1061static bool symbol__match_parent_regex(struct symbol *sym) 1169static bool symbol__match_regex(struct symbol *sym, regex_t *regex)
1062{ 1170{
1063 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0)) 1171 if (sym->name && !regexec(regex, sym->name, 0, NULL, 0))
1064 return 1; 1172 return 1;
1065
1066 return 0; 1173 return 0;
1067} 1174}
1068 1175
@@ -1094,7 +1201,7 @@ static void ip__resolve_ams(struct machine *machine, struct thread *thread,
1094 * or else, the symbol is unknown 1201 * or else, the symbol is unknown
1095 */ 1202 */
1096 thread__find_addr_location(thread, machine, m, MAP__FUNCTION, 1203 thread__find_addr_location(thread, machine, m, MAP__FUNCTION,
1097 ip, &al, NULL); 1204 ip, &al);
1098 if (al.sym) 1205 if (al.sym)
1099 goto found; 1206 goto found;
1100 } 1207 }
@@ -1112,8 +1219,8 @@ static void ip__resolve_data(struct machine *machine, struct thread *thread,
1112 1219
1113 memset(&al, 0, sizeof(al)); 1220 memset(&al, 0, sizeof(al));
1114 1221
1115 thread__find_addr_location(thread, machine, m, MAP__VARIABLE, addr, &al, 1222 thread__find_addr_location(thread, machine, m, MAP__VARIABLE, addr,
1116 NULL); 1223 &al);
1117 ams->addr = addr; 1224 ams->addr = addr;
1118 ams->al_addr = al.addr; 1225 ams->al_addr = al.addr;
1119 ams->sym = al.sym; 1226 ams->sym = al.sym;
@@ -1159,8 +1266,8 @@ struct branch_info *machine__resolve_bstack(struct machine *machine,
1159static int machine__resolve_callchain_sample(struct machine *machine, 1266static int machine__resolve_callchain_sample(struct machine *machine,
1160 struct thread *thread, 1267 struct thread *thread,
1161 struct ip_callchain *chain, 1268 struct ip_callchain *chain,
1162 struct symbol **parent) 1269 struct symbol **parent,
1163 1270 struct addr_location *root_al)
1164{ 1271{
1165 u8 cpumode = PERF_RECORD_MISC_USER; 1272 u8 cpumode = PERF_RECORD_MISC_USER;
1166 unsigned int i; 1273 unsigned int i;
@@ -1208,11 +1315,18 @@ static int machine__resolve_callchain_sample(struct machine *machine,
1208 1315
1209 al.filtered = false; 1316 al.filtered = false;
1210 thread__find_addr_location(thread, machine, cpumode, 1317 thread__find_addr_location(thread, machine, cpumode,
1211 MAP__FUNCTION, ip, &al, NULL); 1318 MAP__FUNCTION, ip, &al);
1212 if (al.sym != NULL) { 1319 if (al.sym != NULL) {
1213 if (sort__has_parent && !*parent && 1320 if (sort__has_parent && !*parent &&
1214 symbol__match_parent_regex(al.sym)) 1321 symbol__match_regex(al.sym, &parent_regex))
1215 *parent = al.sym; 1322 *parent = al.sym;
1323 else if (have_ignore_callees && root_al &&
1324 symbol__match_regex(al.sym, &ignore_callees_regex)) {
1325 /* Treat this symbol as the root,
1326 forgetting its callees. */
1327 *root_al = al;
1328 callchain_cursor_reset(&callchain_cursor);
1329 }
1216 if (!symbol_conf.use_callchain) 1330 if (!symbol_conf.use_callchain)
1217 break; 1331 break;
1218 } 1332 }
@@ -1237,15 +1351,13 @@ int machine__resolve_callchain(struct machine *machine,
1237 struct perf_evsel *evsel, 1351 struct perf_evsel *evsel,
1238 struct thread *thread, 1352 struct thread *thread,
1239 struct perf_sample *sample, 1353 struct perf_sample *sample,
1240 struct symbol **parent) 1354 struct symbol **parent,
1241 1355 struct addr_location *root_al)
1242{ 1356{
1243 int ret; 1357 int ret;
1244 1358
1245 callchain_cursor_reset(&callchain_cursor);
1246
1247 ret = machine__resolve_callchain_sample(machine, thread, 1359 ret = machine__resolve_callchain_sample(machine, thread,
1248 sample->callchain, parent); 1360 sample->callchain, parent, root_al);
1249 if (ret) 1361 if (ret)
1250 return ret; 1362 return ret;
1251 1363
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index 77940680f1fc..58a6be1fc739 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -5,6 +5,7 @@
5#include <linux/rbtree.h> 5#include <linux/rbtree.h>
6#include "map.h" 6#include "map.h"
7 7
8struct addr_location;
8struct branch_stack; 9struct branch_stack;
9struct perf_evsel; 10struct perf_evsel;
10struct perf_sample; 11struct perf_sample;
@@ -28,6 +29,7 @@ struct machine {
28 struct list_head kernel_dsos; 29 struct list_head kernel_dsos;
29 struct map_groups kmaps; 30 struct map_groups kmaps;
30 struct map *vmlinux_maps[MAP__NR_TYPES]; 31 struct map *vmlinux_maps[MAP__NR_TYPES];
32 symbol_filter_t symbol_filter;
31}; 33};
32 34
33static inline 35static inline
@@ -36,13 +38,14 @@ struct map *machine__kernel_map(struct machine *machine, enum map_type type)
36 return machine->vmlinux_maps[type]; 38 return machine->vmlinux_maps[type];
37} 39}
38 40
39struct thread *machine__find_thread(struct machine *machine, pid_t pid); 41struct thread *machine__find_thread(struct machine *machine, pid_t tid);
40 42
41int machine__process_comm_event(struct machine *machine, union perf_event *event); 43int machine__process_comm_event(struct machine *machine, union perf_event *event);
42int machine__process_exit_event(struct machine *machine, union perf_event *event); 44int machine__process_exit_event(struct machine *machine, union perf_event *event);
43int machine__process_fork_event(struct machine *machine, union perf_event *event); 45int machine__process_fork_event(struct machine *machine, union perf_event *event);
44int machine__process_lost_event(struct machine *machine, union perf_event *event); 46int machine__process_lost_event(struct machine *machine, union perf_event *event);
45int machine__process_mmap_event(struct machine *machine, union perf_event *event); 47int machine__process_mmap_event(struct machine *machine, union perf_event *event);
48int machine__process_mmap2_event(struct machine *machine, union perf_event *event);
46int machine__process_event(struct machine *machine, union perf_event *event); 49int machine__process_event(struct machine *machine, union perf_event *event);
47 50
48typedef void (*machine__process_t)(struct machine *machine, void *data); 51typedef void (*machine__process_t)(struct machine *machine, void *data);
@@ -50,6 +53,7 @@ typedef void (*machine__process_t)(struct machine *machine, void *data);
50struct machines { 53struct machines {
51 struct machine host; 54 struct machine host;
52 struct rb_root guests; 55 struct rb_root guests;
56 symbol_filter_t symbol_filter;
53}; 57};
54 58
55void machines__init(struct machines *machines); 59void machines__init(struct machines *machines);
@@ -67,6 +71,9 @@ struct machine *machines__findnew(struct machines *machines, pid_t pid);
67void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size); 71void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size);
68char *machine__mmap_name(struct machine *machine, char *bf, size_t size); 72char *machine__mmap_name(struct machine *machine, char *bf, size_t size);
69 73
74void machines__set_symbol_filter(struct machines *machines,
75 symbol_filter_t symbol_filter);
76
70int machine__init(struct machine *machine, const char *root_dir, pid_t pid); 77int machine__init(struct machine *machine, const char *root_dir, pid_t pid);
71void machine__exit(struct machine *machine); 78void machine__exit(struct machine *machine);
72void machine__delete_dead_threads(struct machine *machine); 79void machine__delete_dead_threads(struct machine *machine);
@@ -83,7 +90,8 @@ int machine__resolve_callchain(struct machine *machine,
83 struct perf_evsel *evsel, 90 struct perf_evsel *evsel,
84 struct thread *thread, 91 struct thread *thread,
85 struct perf_sample *sample, 92 struct perf_sample *sample,
86 struct symbol **parent); 93 struct symbol **parent,
94 struct addr_location *root_al);
87 95
88/* 96/*
89 * Default guest kernel is defined by parameter --guestkallsyms 97 * Default guest kernel is defined by parameter --guestkallsyms
@@ -99,7 +107,8 @@ static inline bool machine__is_host(struct machine *machine)
99 return machine ? machine->pid == HOST_KERNEL_ID : false; 107 return machine ? machine->pid == HOST_KERNEL_ID : false;
100} 108}
101 109
102struct thread *machine__findnew_thread(struct machine *machine, pid_t pid); 110struct thread *machine__findnew_thread(struct machine *machine, pid_t pid,
111 pid_t tid);
103 112
104size_t machine__fprintf(struct machine *machine, FILE *fp); 113size_t machine__fprintf(struct machine *machine, FILE *fp);
105 114
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 8bcdf9e54089..4f6680d2043b 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -48,7 +48,8 @@ void map__init(struct map *map, enum map_type type,
48} 48}
49 49
50struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, 50struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
51 u64 pgoff, u32 pid, char *filename, 51 u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
52 u64 ino_gen, char *filename,
52 enum map_type type) 53 enum map_type type)
53{ 54{
54 struct map *map = malloc(sizeof(*map)); 55 struct map *map = malloc(sizeof(*map));
@@ -62,6 +63,11 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
62 vdso = is_vdso_map(filename); 63 vdso = is_vdso_map(filename);
63 no_dso = is_no_dso_memory(filename); 64 no_dso = is_no_dso_memory(filename);
64 65
66 map->maj = d_maj;
67 map->min = d_min;
68 map->ino = ino;
69 map->ino_generation = ino_gen;
70
65 if (anon) { 71 if (anon) {
66 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid); 72 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid);
67 filename = newfilename; 73 filename = newfilename;
@@ -182,12 +188,6 @@ int map__load(struct map *map, symbol_filter_t filter)
182#endif 188#endif
183 return -1; 189 return -1;
184 } 190 }
185 /*
186 * Only applies to the kernel, as its symtabs aren't relative like the
187 * module ones.
188 */
189 if (map->dso->kernel)
190 map__reloc_vmlinux(map);
191 191
192 return 0; 192 return 0;
193} 193}
@@ -254,14 +254,18 @@ size_t map__fprintf_dsoname(struct map *map, FILE *fp)
254 254
255/* 255/*
256 * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN. 256 * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN.
257 * map->dso->adjust_symbols==1 for ET_EXEC-like cases. 257 * map->dso->adjust_symbols==1 for ET_EXEC-like cases except ET_REL which is
258 * relative to section start.
258 */ 259 */
259u64 map__rip_2objdump(struct map *map, u64 rip) 260u64 map__rip_2objdump(struct map *map, u64 rip)
260{ 261{
261 u64 addr = map->dso->adjust_symbols ? 262 if (!map->dso->adjust_symbols)
262 map->unmap_ip(map, rip) : /* RIP -> IP */ 263 return rip;
263 rip; 264
264 return addr; 265 if (map->dso->rel)
266 return rip - map->pgoff;
267
268 return map->unmap_ip(map, rip);
265} 269}
266 270
267void map_groups__init(struct map_groups *mg) 271void map_groups__init(struct map_groups *mg)
@@ -513,35 +517,6 @@ int map_groups__clone(struct map_groups *mg,
513 return 0; 517 return 0;
514} 518}
515 519
516static u64 map__reloc_map_ip(struct map *map, u64 ip)
517{
518 return ip + (s64)map->pgoff;
519}
520
521static u64 map__reloc_unmap_ip(struct map *map, u64 ip)
522{
523 return ip - (s64)map->pgoff;
524}
525
526void map__reloc_vmlinux(struct map *map)
527{
528 struct kmap *kmap = map__kmap(map);
529 s64 reloc;
530
531 if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->unrelocated_addr)
532 return;
533
534 reloc = (kmap->ref_reloc_sym->unrelocated_addr -
535 kmap->ref_reloc_sym->addr);
536
537 if (!reloc)
538 return;
539
540 map->map_ip = map__reloc_map_ip;
541 map->unmap_ip = map__reloc_unmap_ip;
542 map->pgoff = reloc;
543}
544
545void maps__insert(struct rb_root *maps, struct map *map) 520void maps__insert(struct rb_root *maps, struct map *map)
546{ 521{
547 struct rb_node **p = &maps->rb_node; 522 struct rb_node **p = &maps->rb_node;
@@ -586,3 +561,21 @@ struct map *maps__find(struct rb_root *maps, u64 ip)
586 561
587 return NULL; 562 return NULL;
588} 563}
564
565struct map *maps__first(struct rb_root *maps)
566{
567 struct rb_node *first = rb_first(maps);
568
569 if (first)
570 return rb_entry(first, struct map, rb_node);
571 return NULL;
572}
573
574struct map *maps__next(struct map *map)
575{
576 struct rb_node *next = rb_next(&map->rb_node);
577
578 if (next)
579 return rb_entry(next, struct map, rb_node);
580 return NULL;
581}
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index a887f2c9dfbb..4886ca280536 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -36,6 +36,9 @@ struct map {
36 bool erange_warned; 36 bool erange_warned;
37 u32 priv; 37 u32 priv;
38 u64 pgoff; 38 u64 pgoff;
39 u32 maj, min; /* only valid for MMAP2 record */
40 u64 ino; /* only valid for MMAP2 record */
41 u64 ino_generation;/* only valid for MMAP2 record */
39 42
40 /* ip -> dso rip */ 43 /* ip -> dso rip */
41 u64 (*map_ip)(struct map *, u64); 44 u64 (*map_ip)(struct map *, u64);
@@ -88,8 +91,9 @@ typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
88void map__init(struct map *map, enum map_type type, 91void map__init(struct map *map, enum map_type type,
89 u64 start, u64 end, u64 pgoff, struct dso *dso); 92 u64 start, u64 end, u64 pgoff, struct dso *dso);
90struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, 93struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
91 u64 pgoff, u32 pid, char *filename, 94 u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
92 enum map_type type); 95 u64 ino_gen,
96 char *filename, enum map_type type);
93struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 97struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
94void map__delete(struct map *map); 98void map__delete(struct map *map);
95struct map *map__clone(struct map *map); 99struct map *map__clone(struct map *map);
@@ -112,6 +116,8 @@ size_t __map_groups__fprintf_maps(struct map_groups *mg,
112void maps__insert(struct rb_root *maps, struct map *map); 116void maps__insert(struct rb_root *maps, struct map *map);
113void maps__remove(struct rb_root *maps, struct map *map); 117void maps__remove(struct rb_root *maps, struct map *map);
114struct map *maps__find(struct rb_root *maps, u64 addr); 118struct map *maps__find(struct rb_root *maps, u64 addr);
119struct map *maps__first(struct rb_root *maps);
120struct map *maps__next(struct map *map);
115void map_groups__init(struct map_groups *mg); 121void map_groups__init(struct map_groups *mg);
116void map_groups__exit(struct map_groups *mg); 122void map_groups__exit(struct map_groups *mg);
117int map_groups__clone(struct map_groups *mg, 123int map_groups__clone(struct map_groups *mg,
@@ -139,6 +145,17 @@ static inline struct map *map_groups__find(struct map_groups *mg,
139 return maps__find(&mg->maps[type], addr); 145 return maps__find(&mg->maps[type], addr);
140} 146}
141 147
148static inline struct map *map_groups__first(struct map_groups *mg,
149 enum map_type type)
150{
151 return maps__first(&mg->maps[type]);
152}
153
154static inline struct map *map_groups__next(struct map *map)
155{
156 return maps__next(map);
157}
158
142struct symbol *map_groups__find_symbol(struct map_groups *mg, 159struct symbol *map_groups__find_symbol(struct map_groups *mg,
143 enum map_type type, u64 addr, 160 enum map_type type, u64 addr,
144 struct map **mapp, 161 struct map **mapp,
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 995fc25db8c6..98125319b158 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -6,7 +6,7 @@
6#include "parse-options.h" 6#include "parse-options.h"
7#include "parse-events.h" 7#include "parse-events.h"
8#include "exec_cmd.h" 8#include "exec_cmd.h"
9#include "string.h" 9#include "linux/string.h"
10#include "symbol.h" 10#include "symbol.h"
11#include "cache.h" 11#include "cache.h"
12#include "header.h" 12#include "header.h"
@@ -15,6 +15,7 @@
15#define YY_EXTRA_TYPE int 15#define YY_EXTRA_TYPE int
16#include "parse-events-flex.h" 16#include "parse-events-flex.h"
17#include "pmu.h" 17#include "pmu.h"
18#include "thread_map.h"
18 19
19#define MAX_NAME_LEN 100 20#define MAX_NAME_LEN 100
20 21
@@ -108,6 +109,10 @@ static struct event_symbol event_symbols_sw[PERF_COUNT_SW_MAX] = {
108 .symbol = "emulation-faults", 109 .symbol = "emulation-faults",
109 .alias = "", 110 .alias = "",
110 }, 111 },
112 [PERF_COUNT_SW_DUMMY] = {
113 .symbol = "dummy",
114 .alias = "",
115 },
111}; 116};
112 117
113#define __PERF_EVENT_FIELD(config, name) \ 118#define __PERF_EVENT_FIELD(config, name) \
@@ -217,6 +222,29 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
217 return NULL; 222 return NULL;
218} 223}
219 224
225struct tracepoint_path *tracepoint_name_to_path(const char *name)
226{
227 struct tracepoint_path *path = zalloc(sizeof(*path));
228 char *str = strchr(name, ':');
229
230 if (path == NULL || str == NULL) {
231 free(path);
232 return NULL;
233 }
234
235 path->system = strndup(name, str - name);
236 path->name = strdup(str+1);
237
238 if (path->system == NULL || path->name == NULL) {
239 free(path->system);
240 free(path->name);
241 free(path);
242 path = NULL;
243 }
244
245 return path;
246}
247
220const char *event_type(int type) 248const char *event_type(int type)
221{ 249{
222 switch (type) { 250 switch (type) {
@@ -241,40 +269,29 @@ const char *event_type(int type)
241 269
242 270
243 271
244static int __add_event(struct list_head **_list, int *idx, 272static int __add_event(struct list_head *list, int *idx,
245 struct perf_event_attr *attr, 273 struct perf_event_attr *attr,
246 char *name, struct cpu_map *cpus) 274 char *name, struct cpu_map *cpus)
247{ 275{
248 struct perf_evsel *evsel; 276 struct perf_evsel *evsel;
249 struct list_head *list = *_list;
250
251 if (!list) {
252 list = malloc(sizeof(*list));
253 if (!list)
254 return -ENOMEM;
255 INIT_LIST_HEAD(list);
256 }
257 277
258 event_attr_init(attr); 278 event_attr_init(attr);
259 279
260 evsel = perf_evsel__new(attr, (*idx)++); 280 evsel = perf_evsel__new(attr, (*idx)++);
261 if (!evsel) { 281 if (!evsel)
262 free(list);
263 return -ENOMEM; 282 return -ENOMEM;
264 }
265 283
266 evsel->cpus = cpus; 284 evsel->cpus = cpus;
267 if (name) 285 if (name)
268 evsel->name = strdup(name); 286 evsel->name = strdup(name);
269 list_add_tail(&evsel->node, list); 287 list_add_tail(&evsel->node, list);
270 *_list = list;
271 return 0; 288 return 0;
272} 289}
273 290
274static int add_event(struct list_head **_list, int *idx, 291static int add_event(struct list_head *list, int *idx,
275 struct perf_event_attr *attr, char *name) 292 struct perf_event_attr *attr, char *name)
276{ 293{
277 return __add_event(_list, idx, attr, name, NULL); 294 return __add_event(list, idx, attr, name, NULL);
278} 295}
279 296
280static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size) 297static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size)
@@ -295,7 +312,7 @@ static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES]
295 return -1; 312 return -1;
296} 313}
297 314
298int parse_events_add_cache(struct list_head **list, int *idx, 315int parse_events_add_cache(struct list_head *list, int *idx,
299 char *type, char *op_result1, char *op_result2) 316 char *type, char *op_result1, char *op_result2)
300{ 317{
301 struct perf_event_attr attr; 318 struct perf_event_attr attr;
@@ -356,31 +373,21 @@ int parse_events_add_cache(struct list_head **list, int *idx,
356 return add_event(list, idx, &attr, name); 373 return add_event(list, idx, &attr, name);
357} 374}
358 375
359static int add_tracepoint(struct list_head **listp, int *idx, 376static int add_tracepoint(struct list_head *list, int *idx,
360 char *sys_name, char *evt_name) 377 char *sys_name, char *evt_name)
361{ 378{
362 struct perf_evsel *evsel; 379 struct perf_evsel *evsel;
363 struct list_head *list = *listp;
364
365 if (!list) {
366 list = malloc(sizeof(*list));
367 if (!list)
368 return -ENOMEM;
369 INIT_LIST_HEAD(list);
370 }
371 380
372 evsel = perf_evsel__newtp(sys_name, evt_name, (*idx)++); 381 evsel = perf_evsel__newtp(sys_name, evt_name, (*idx)++);
373 if (!evsel) { 382 if (!evsel)
374 free(list);
375 return -ENOMEM; 383 return -ENOMEM;
376 }
377 384
378 list_add_tail(&evsel->node, list); 385 list_add_tail(&evsel->node, list);
379 *listp = list; 386
380 return 0; 387 return 0;
381} 388}
382 389
383static int add_tracepoint_multi_event(struct list_head **list, int *idx, 390static int add_tracepoint_multi_event(struct list_head *list, int *idx,
384 char *sys_name, char *evt_name) 391 char *sys_name, char *evt_name)
385{ 392{
386 char evt_path[MAXPATHLEN]; 393 char evt_path[MAXPATHLEN];
@@ -412,7 +419,7 @@ static int add_tracepoint_multi_event(struct list_head **list, int *idx,
412 return ret; 419 return ret;
413} 420}
414 421
415static int add_tracepoint_event(struct list_head **list, int *idx, 422static int add_tracepoint_event(struct list_head *list, int *idx,
416 char *sys_name, char *evt_name) 423 char *sys_name, char *evt_name)
417{ 424{
418 return strpbrk(evt_name, "*?") ? 425 return strpbrk(evt_name, "*?") ?
@@ -420,7 +427,7 @@ static int add_tracepoint_event(struct list_head **list, int *idx,
420 add_tracepoint(list, idx, sys_name, evt_name); 427 add_tracepoint(list, idx, sys_name, evt_name);
421} 428}
422 429
423static int add_tracepoint_multi_sys(struct list_head **list, int *idx, 430static int add_tracepoint_multi_sys(struct list_head *list, int *idx,
424 char *sys_name, char *evt_name) 431 char *sys_name, char *evt_name)
425{ 432{
426 struct dirent *events_ent; 433 struct dirent *events_ent;
@@ -452,7 +459,7 @@ static int add_tracepoint_multi_sys(struct list_head **list, int *idx,
452 return ret; 459 return ret;
453} 460}
454 461
455int parse_events_add_tracepoint(struct list_head **list, int *idx, 462int parse_events_add_tracepoint(struct list_head *list, int *idx,
456 char *sys, char *event) 463 char *sys, char *event)
457{ 464{
458 int ret; 465 int ret;
@@ -507,7 +514,7 @@ do { \
507 return 0; 514 return 0;
508} 515}
509 516
510int parse_events_add_breakpoint(struct list_head **list, int *idx, 517int parse_events_add_breakpoint(struct list_head *list, int *idx,
511 void *ptr, char *type) 518 void *ptr, char *type)
512{ 519{
513 struct perf_event_attr attr; 520 struct perf_event_attr attr;
@@ -588,7 +595,7 @@ static int config_attr(struct perf_event_attr *attr,
588 return 0; 595 return 0;
589} 596}
590 597
591int parse_events_add_numeric(struct list_head **list, int *idx, 598int parse_events_add_numeric(struct list_head *list, int *idx,
592 u32 type, u64 config, 599 u32 type, u64 config,
593 struct list_head *head_config) 600 struct list_head *head_config)
594{ 601{
@@ -621,7 +628,7 @@ static char *pmu_event_name(struct list_head *head_terms)
621 return NULL; 628 return NULL;
622} 629}
623 630
624int parse_events_add_pmu(struct list_head **list, int *idx, 631int parse_events_add_pmu(struct list_head *list, int *idx,
625 char *name, struct list_head *head_config) 632 char *name, struct list_head *head_config)
626{ 633{
627 struct perf_event_attr attr; 634 struct perf_event_attr attr;
@@ -664,6 +671,7 @@ void parse_events__set_leader(char *name, struct list_head *list)
664 leader->group_name = name ? strdup(name) : NULL; 671 leader->group_name = name ? strdup(name) : NULL;
665} 672}
666 673
674/* list_event is assumed to point to malloc'ed memory */
667void parse_events_update_lists(struct list_head *list_event, 675void parse_events_update_lists(struct list_head *list_event,
668 struct list_head *list_all) 676 struct list_head *list_all)
669{ 677{
@@ -684,6 +692,8 @@ struct event_modifier {
684 int eG; 692 int eG;
685 int precise; 693 int precise;
686 int exclude_GH; 694 int exclude_GH;
695 int sample_read;
696 int pinned;
687}; 697};
688 698
689static int get_event_modifier(struct event_modifier *mod, char *str, 699static int get_event_modifier(struct event_modifier *mod, char *str,
@@ -695,6 +705,8 @@ static int get_event_modifier(struct event_modifier *mod, char *str,
695 int eH = evsel ? evsel->attr.exclude_host : 0; 705 int eH = evsel ? evsel->attr.exclude_host : 0;
696 int eG = evsel ? evsel->attr.exclude_guest : 0; 706 int eG = evsel ? evsel->attr.exclude_guest : 0;
697 int precise = evsel ? evsel->attr.precise_ip : 0; 707 int precise = evsel ? evsel->attr.precise_ip : 0;
708 int sample_read = 0;
709 int pinned = evsel ? evsel->attr.pinned : 0;
698 710
699 int exclude = eu | ek | eh; 711 int exclude = eu | ek | eh;
700 int exclude_GH = evsel ? evsel->exclude_GH : 0; 712 int exclude_GH = evsel ? evsel->exclude_GH : 0;
@@ -727,6 +739,10 @@ static int get_event_modifier(struct event_modifier *mod, char *str,
727 /* use of precise requires exclude_guest */ 739 /* use of precise requires exclude_guest */
728 if (!exclude_GH) 740 if (!exclude_GH)
729 eG = 1; 741 eG = 1;
742 } else if (*str == 'S') {
743 sample_read = 1;
744 } else if (*str == 'D') {
745 pinned = 1;
730 } else 746 } else
731 break; 747 break;
732 748
@@ -753,6 +769,9 @@ static int get_event_modifier(struct event_modifier *mod, char *str,
753 mod->eG = eG; 769 mod->eG = eG;
754 mod->precise = precise; 770 mod->precise = precise;
755 mod->exclude_GH = exclude_GH; 771 mod->exclude_GH = exclude_GH;
772 mod->sample_read = sample_read;
773 mod->pinned = pinned;
774
756 return 0; 775 return 0;
757} 776}
758 777
@@ -765,7 +784,7 @@ static int check_modifier(char *str)
765 char *p = str; 784 char *p = str;
766 785
767 /* The sizeof includes 0 byte as well. */ 786 /* The sizeof includes 0 byte as well. */
768 if (strlen(str) > (sizeof("ukhGHppp") - 1)) 787 if (strlen(str) > (sizeof("ukhGHpppSD") - 1))
769 return -1; 788 return -1;
770 789
771 while (*p) { 790 while (*p) {
@@ -803,6 +822,10 @@ int parse_events__modifier_event(struct list_head *list, char *str, bool add)
803 evsel->attr.exclude_host = mod.eH; 822 evsel->attr.exclude_host = mod.eH;
804 evsel->attr.exclude_guest = mod.eG; 823 evsel->attr.exclude_guest = mod.eG;
805 evsel->exclude_GH = mod.exclude_GH; 824 evsel->exclude_GH = mod.exclude_GH;
825 evsel->sample_read = mod.sample_read;
826
827 if (perf_evsel__is_group_leader(evsel))
828 evsel->attr.pinned = mod.pinned;
806 } 829 }
807 830
808 return 0; 831 return 0;
@@ -820,6 +843,32 @@ int parse_events_name(struct list_head *list, char *name)
820 return 0; 843 return 0;
821} 844}
822 845
846static int parse_events__scanner(const char *str, void *data, int start_token);
847
848static int parse_events_fixup(int ret, const char *str, void *data,
849 int start_token)
850{
851 char *o = strdup(str);
852 char *s = NULL;
853 char *t = o;
854 char *p;
855 int len = 0;
856
857 if (!o)
858 return ret;
859 while ((p = strsep(&t, ",")) != NULL) {
860 if (s)
861 str_append(&s, &len, ",");
862 str_append(&s, &len, "cpu/");
863 str_append(&s, &len, p);
864 str_append(&s, &len, "/");
865 }
866 free(o);
867 if (!s)
868 return -ENOMEM;
869 return parse_events__scanner(s, data, start_token);
870}
871
823static int parse_events__scanner(const char *str, void *data, int start_token) 872static int parse_events__scanner(const char *str, void *data, int start_token)
824{ 873{
825 YY_BUFFER_STATE buffer; 874 YY_BUFFER_STATE buffer;
@@ -840,6 +889,8 @@ static int parse_events__scanner(const char *str, void *data, int start_token)
840 parse_events__flush_buffer(buffer, scanner); 889 parse_events__flush_buffer(buffer, scanner);
841 parse_events__delete_buffer(buffer, scanner); 890 parse_events__delete_buffer(buffer, scanner);
842 parse_events_lex_destroy(scanner); 891 parse_events_lex_destroy(scanner);
892 if (ret && !strchr(str, '/'))
893 ret = parse_events_fixup(ret, str, data, start_token);
843 return ret; 894 return ret;
844} 895}
845 896
@@ -1026,6 +1077,33 @@ int is_valid_tracepoint(const char *event_string)
1026 return 0; 1077 return 0;
1027} 1078}
1028 1079
1080static bool is_event_supported(u8 type, unsigned config)
1081{
1082 bool ret = true;
1083 struct perf_evsel *evsel;
1084 struct perf_event_attr attr = {
1085 .type = type,
1086 .config = config,
1087 .disabled = 1,
1088 .exclude_kernel = 1,
1089 };
1090 struct {
1091 struct thread_map map;
1092 int threads[1];
1093 } tmap = {
1094 .map.nr = 1,
1095 .threads = { 0 },
1096 };
1097
1098 evsel = perf_evsel__new(&attr, 0);
1099 if (evsel) {
1100 ret = perf_evsel__open(evsel, NULL, &tmap.map) >= 0;
1101 perf_evsel__delete(evsel);
1102 }
1103
1104 return ret;
1105}
1106
1029static void __print_events_type(u8 type, struct event_symbol *syms, 1107static void __print_events_type(u8 type, struct event_symbol *syms,
1030 unsigned max) 1108 unsigned max)
1031{ 1109{
@@ -1033,14 +1111,16 @@ static void __print_events_type(u8 type, struct event_symbol *syms,
1033 unsigned i; 1111 unsigned i;
1034 1112
1035 for (i = 0; i < max ; i++, syms++) { 1113 for (i = 0; i < max ; i++, syms++) {
1114 if (!is_event_supported(type, i))
1115 continue;
1116
1036 if (strlen(syms->alias)) 1117 if (strlen(syms->alias))
1037 snprintf(name, sizeof(name), "%s OR %s", 1118 snprintf(name, sizeof(name), "%s OR %s",
1038 syms->symbol, syms->alias); 1119 syms->symbol, syms->alias);
1039 else 1120 else
1040 snprintf(name, sizeof(name), "%s", syms->symbol); 1121 snprintf(name, sizeof(name), "%s", syms->symbol);
1041 1122
1042 printf(" %-50s [%s]\n", name, 1123 printf(" %-50s [%s]\n", name, event_type_descriptors[type]);
1043 event_type_descriptors[type]);
1044 } 1124 }
1045} 1125}
1046 1126
@@ -1069,6 +1149,10 @@ int print_hwcache_events(const char *event_glob, bool name_only)
1069 if (event_glob != NULL && !strglobmatch(name, event_glob)) 1149 if (event_glob != NULL && !strglobmatch(name, event_glob))
1070 continue; 1150 continue;
1071 1151
1152 if (!is_event_supported(PERF_TYPE_HW_CACHE,
1153 type | (op << 8) | (i << 16)))
1154 continue;
1155
1072 if (name_only) 1156 if (name_only)
1073 printf("%s ", name); 1157 printf("%s ", name);
1074 else 1158 else
@@ -1079,6 +1163,8 @@ int print_hwcache_events(const char *event_glob, bool name_only)
1079 } 1163 }
1080 } 1164 }
1081 1165
1166 if (printed)
1167 printf("\n");
1082 return printed; 1168 return printed;
1083} 1169}
1084 1170
@@ -1096,6 +1182,9 @@ static void print_symbol_events(const char *event_glob, unsigned type,
1096 (syms->alias && strglobmatch(syms->alias, event_glob)))) 1182 (syms->alias && strglobmatch(syms->alias, event_glob))))
1097 continue; 1183 continue;
1098 1184
1185 if (!is_event_supported(type, i))
1186 continue;
1187
1099 if (name_only) { 1188 if (name_only) {
1100 printf("%s ", syms->symbol); 1189 printf("%s ", syms->symbol);
1101 continue; 1190 continue;
@@ -1133,11 +1222,12 @@ void print_events(const char *event_glob, bool name_only)
1133 1222
1134 print_hwcache_events(event_glob, name_only); 1223 print_hwcache_events(event_glob, name_only);
1135 1224
1225 print_pmu_events(event_glob, name_only);
1226
1136 if (event_glob != NULL) 1227 if (event_glob != NULL)
1137 return; 1228 return;
1138 1229
1139 if (!name_only) { 1230 if (!name_only) {
1140 printf("\n");
1141 printf(" %-50s [%s]\n", 1231 printf(" %-50s [%s]\n",
1142 "rNNN", 1232 "rNNN",
1143 event_type_descriptors[PERF_TYPE_RAW]); 1233 event_type_descriptors[PERF_TYPE_RAW]);
@@ -1237,6 +1327,4 @@ void parse_events__free_terms(struct list_head *terms)
1237 1327
1238 list_for_each_entry_safe(term, h, terms, list) 1328 list_for_each_entry_safe(term, h, terms, list)
1239 free(term); 1329 free(term);
1240
1241 free(terms);
1242} 1330}
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 8a4859315fd9..f1cb4c4b3c70 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -23,6 +23,7 @@ struct tracepoint_path {
23}; 23};
24 24
25extern struct tracepoint_path *tracepoint_id_to_path(u64 config); 25extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
26extern struct tracepoint_path *tracepoint_name_to_path(const char *name);
26extern bool have_tracepoints(struct list_head *evlist); 27extern bool have_tracepoints(struct list_head *evlist);
27 28
28const char *event_type(int type); 29const char *event_type(int type);
@@ -84,16 +85,16 @@ void parse_events__free_terms(struct list_head *terms);
84int parse_events__modifier_event(struct list_head *list, char *str, bool add); 85int parse_events__modifier_event(struct list_head *list, char *str, bool add);
85int parse_events__modifier_group(struct list_head *list, char *event_mod); 86int parse_events__modifier_group(struct list_head *list, char *event_mod);
86int parse_events_name(struct list_head *list, char *name); 87int parse_events_name(struct list_head *list, char *name);
87int parse_events_add_tracepoint(struct list_head **list, int *idx, 88int parse_events_add_tracepoint(struct list_head *list, int *idx,
88 char *sys, char *event); 89 char *sys, char *event);
89int parse_events_add_numeric(struct list_head **list, int *idx, 90int parse_events_add_numeric(struct list_head *list, int *idx,
90 u32 type, u64 config, 91 u32 type, u64 config,
91 struct list_head *head_config); 92 struct list_head *head_config);
92int parse_events_add_cache(struct list_head **list, int *idx, 93int parse_events_add_cache(struct list_head *list, int *idx,
93 char *type, char *op_result1, char *op_result2); 94 char *type, char *op_result1, char *op_result2);
94int parse_events_add_breakpoint(struct list_head **list, int *idx, 95int parse_events_add_breakpoint(struct list_head *list, int *idx,
95 void *ptr, char *type); 96 void *ptr, char *type);
96int parse_events_add_pmu(struct list_head **list, int *idx, 97int parse_events_add_pmu(struct list_head *list, int *idx,
97 char *pmu , struct list_head *head_config); 98 char *pmu , struct list_head *head_config);
98void parse_events__set_leader(char *name, struct list_head *list); 99void parse_events__set_leader(char *name, struct list_head *list);
99void parse_events_update_lists(struct list_head *list_event, 100void parse_events_update_lists(struct list_head *list_event,
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index e9d1134c2c68..91346b753960 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -82,7 +82,8 @@ num_hex 0x[a-fA-F0-9]+
82num_raw_hex [a-fA-F0-9]+ 82num_raw_hex [a-fA-F0-9]+
83name [a-zA-Z_*?][a-zA-Z0-9_*?]* 83name [a-zA-Z_*?][a-zA-Z0-9_*?]*
84name_minus [a-zA-Z_*?][a-zA-Z0-9\-_*?]* 84name_minus [a-zA-Z_*?][a-zA-Z0-9\-_*?]*
85modifier_event [ukhpGH]+ 85/* If you add a modifier you need to update check_modifier() */
86modifier_event [ukhpGHSD]+
86modifier_bp [rwx]{1,3} 87modifier_bp [rwx]{1,3}
87 88
88%% 89%%
@@ -144,6 +145,7 @@ context-switches|cs { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW
144cpu-migrations|migrations { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS); } 145cpu-migrations|migrations { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS); }
145alignment-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); } 146alignment-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); }
146emulation-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); } 147emulation-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); }
148dummy { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_DUMMY); }
147 149
148L1-dcache|l1-d|l1d|L1-data | 150L1-dcache|l1-d|l1d|L1-data |
149L1-icache|l1-i|l1i|L1-instruction | 151L1-icache|l1-i|l1i|L1-instruction |
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index afc44c18dfe1..4eb67ec333f1 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -22,6 +22,13 @@ do { \
22 YYABORT; \ 22 YYABORT; \
23} while (0) 23} while (0)
24 24
25#define ALLOC_LIST(list) \
26do { \
27 list = malloc(sizeof(*list)); \
28 ABORT_ON(!list); \
29 INIT_LIST_HEAD(list); \
30} while (0)
31
25static inc_group_count(struct list_head *list, 32static inc_group_count(struct list_head *list,
26 struct parse_events_evlist *data) 33 struct parse_events_evlist *data)
27{ 34{
@@ -196,9 +203,10 @@ event_pmu:
196PE_NAME '/' event_config '/' 203PE_NAME '/' event_config '/'
197{ 204{
198 struct parse_events_evlist *data = _data; 205 struct parse_events_evlist *data = _data;
199 struct list_head *list = NULL; 206 struct list_head *list;
200 207
201 ABORT_ON(parse_events_add_pmu(&list, &data->idx, $1, $3)); 208 ALLOC_LIST(list);
209 ABORT_ON(parse_events_add_pmu(list, &data->idx, $1, $3));
202 parse_events__free_terms($3); 210 parse_events__free_terms($3);
203 $$ = list; 211 $$ = list;
204} 212}
@@ -212,11 +220,12 @@ event_legacy_symbol:
212value_sym '/' event_config '/' 220value_sym '/' event_config '/'
213{ 221{
214 struct parse_events_evlist *data = _data; 222 struct parse_events_evlist *data = _data;
215 struct list_head *list = NULL; 223 struct list_head *list;
216 int type = $1 >> 16; 224 int type = $1 >> 16;
217 int config = $1 & 255; 225 int config = $1 & 255;
218 226
219 ABORT_ON(parse_events_add_numeric(&list, &data->idx, 227 ALLOC_LIST(list);
228 ABORT_ON(parse_events_add_numeric(list, &data->idx,
220 type, config, $3)); 229 type, config, $3));
221 parse_events__free_terms($3); 230 parse_events__free_terms($3);
222 $$ = list; 231 $$ = list;
@@ -225,11 +234,12 @@ value_sym '/' event_config '/'
225value_sym sep_slash_dc 234value_sym sep_slash_dc
226{ 235{
227 struct parse_events_evlist *data = _data; 236 struct parse_events_evlist *data = _data;
228 struct list_head *list = NULL; 237 struct list_head *list;
229 int type = $1 >> 16; 238 int type = $1 >> 16;
230 int config = $1 & 255; 239 int config = $1 & 255;
231 240
232 ABORT_ON(parse_events_add_numeric(&list, &data->idx, 241 ALLOC_LIST(list);
242 ABORT_ON(parse_events_add_numeric(list, &data->idx,
233 type, config, NULL)); 243 type, config, NULL));
234 $$ = list; 244 $$ = list;
235} 245}
@@ -238,27 +248,30 @@ event_legacy_cache:
238PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT 248PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT
239{ 249{
240 struct parse_events_evlist *data = _data; 250 struct parse_events_evlist *data = _data;
241 struct list_head *list = NULL; 251 struct list_head *list;
242 252
243 ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, $5)); 253 ALLOC_LIST(list);
254 ABORT_ON(parse_events_add_cache(list, &data->idx, $1, $3, $5));
244 $$ = list; 255 $$ = list;
245} 256}
246| 257|
247PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT 258PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT
248{ 259{
249 struct parse_events_evlist *data = _data; 260 struct parse_events_evlist *data = _data;
250 struct list_head *list = NULL; 261 struct list_head *list;
251 262
252 ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, NULL)); 263 ALLOC_LIST(list);
264 ABORT_ON(parse_events_add_cache(list, &data->idx, $1, $3, NULL));
253 $$ = list; 265 $$ = list;
254} 266}
255| 267|
256PE_NAME_CACHE_TYPE 268PE_NAME_CACHE_TYPE
257{ 269{
258 struct parse_events_evlist *data = _data; 270 struct parse_events_evlist *data = _data;
259 struct list_head *list = NULL; 271 struct list_head *list;
260 272
261 ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, NULL, NULL)); 273 ALLOC_LIST(list);
274 ABORT_ON(parse_events_add_cache(list, &data->idx, $1, NULL, NULL));
262 $$ = list; 275 $$ = list;
263} 276}
264 277
@@ -266,9 +279,10 @@ event_legacy_mem:
266PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc 279PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
267{ 280{
268 struct parse_events_evlist *data = _data; 281 struct parse_events_evlist *data = _data;
269 struct list_head *list = NULL; 282 struct list_head *list;
270 283
271 ABORT_ON(parse_events_add_breakpoint(&list, &data->idx, 284 ALLOC_LIST(list);
285 ABORT_ON(parse_events_add_breakpoint(list, &data->idx,
272 (void *) $2, $4)); 286 (void *) $2, $4));
273 $$ = list; 287 $$ = list;
274} 288}
@@ -276,9 +290,10 @@ PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
276PE_PREFIX_MEM PE_VALUE sep_dc 290PE_PREFIX_MEM PE_VALUE sep_dc
277{ 291{
278 struct parse_events_evlist *data = _data; 292 struct parse_events_evlist *data = _data;
279 struct list_head *list = NULL; 293 struct list_head *list;
280 294
281 ABORT_ON(parse_events_add_breakpoint(&list, &data->idx, 295 ALLOC_LIST(list);
296 ABORT_ON(parse_events_add_breakpoint(list, &data->idx,
282 (void *) $2, NULL)); 297 (void *) $2, NULL));
283 $$ = list; 298 $$ = list;
284} 299}
@@ -287,9 +302,10 @@ event_legacy_tracepoint:
287PE_NAME ':' PE_NAME 302PE_NAME ':' PE_NAME
288{ 303{
289 struct parse_events_evlist *data = _data; 304 struct parse_events_evlist *data = _data;
290 struct list_head *list = NULL; 305 struct list_head *list;
291 306
292 ABORT_ON(parse_events_add_tracepoint(&list, &data->idx, $1, $3)); 307 ALLOC_LIST(list);
308 ABORT_ON(parse_events_add_tracepoint(list, &data->idx, $1, $3));
293 $$ = list; 309 $$ = list;
294} 310}
295 311
@@ -297,9 +313,10 @@ event_legacy_numeric:
297PE_VALUE ':' PE_VALUE 313PE_VALUE ':' PE_VALUE
298{ 314{
299 struct parse_events_evlist *data = _data; 315 struct parse_events_evlist *data = _data;
300 struct list_head *list = NULL; 316 struct list_head *list;
301 317
302 ABORT_ON(parse_events_add_numeric(&list, &data->idx, (u32)$1, $3, NULL)); 318 ALLOC_LIST(list);
319 ABORT_ON(parse_events_add_numeric(list, &data->idx, (u32)$1, $3, NULL));
303 $$ = list; 320 $$ = list;
304} 321}
305 322
@@ -307,9 +324,10 @@ event_legacy_raw:
307PE_RAW 324PE_RAW
308{ 325{
309 struct parse_events_evlist *data = _data; 326 struct parse_events_evlist *data = _data;
310 struct list_head *list = NULL; 327 struct list_head *list;
311 328
312 ABORT_ON(parse_events_add_numeric(&list, &data->idx, 329 ALLOC_LIST(list);
330 ABORT_ON(parse_events_add_numeric(list, &data->idx,
313 PERF_TYPE_RAW, $1, NULL)); 331 PERF_TYPE_RAW, $1, NULL));
314 $$ = list; 332 $$ = list;
315} 333}
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 4c6f9c490a8d..bc9d8069d376 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -73,7 +73,7 @@ int perf_pmu__format_parse(char *dir, struct list_head *head)
73 * located at: 73 * located at:
74 * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes. 74 * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes.
75 */ 75 */
76static int pmu_format(char *name, struct list_head *format) 76static int pmu_format(const char *name, struct list_head *format)
77{ 77{
78 struct stat st; 78 struct stat st;
79 char path[PATH_MAX]; 79 char path[PATH_MAX];
@@ -162,7 +162,7 @@ static int pmu_aliases_parse(char *dir, struct list_head *head)
162 * Reading the pmu event aliases definition, which should be located at: 162 * Reading the pmu event aliases definition, which should be located at:
163 * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes. 163 * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes.
164 */ 164 */
165static int pmu_aliases(char *name, struct list_head *head) 165static int pmu_aliases(const char *name, struct list_head *head)
166{ 166{
167 struct stat st; 167 struct stat st;
168 char path[PATH_MAX]; 168 char path[PATH_MAX];
@@ -208,7 +208,7 @@ static int pmu_alias_terms(struct perf_pmu_alias *alias,
208 * located at: 208 * located at:
209 * /sys/bus/event_source/devices/<dev>/type as sysfs attribute. 209 * /sys/bus/event_source/devices/<dev>/type as sysfs attribute.
210 */ 210 */
211static int pmu_type(char *name, __u32 *type) 211static int pmu_type(const char *name, __u32 *type)
212{ 212{
213 struct stat st; 213 struct stat st;
214 char path[PATH_MAX]; 214 char path[PATH_MAX];
@@ -266,7 +266,7 @@ static void pmu_read_sysfs(void)
266 closedir(dir); 266 closedir(dir);
267} 267}
268 268
269static struct cpu_map *pmu_cpumask(char *name) 269static struct cpu_map *pmu_cpumask(const char *name)
270{ 270{
271 struct stat st; 271 struct stat st;
272 char path[PATH_MAX]; 272 char path[PATH_MAX];
@@ -293,7 +293,7 @@ static struct cpu_map *pmu_cpumask(char *name)
293 return cpus; 293 return cpus;
294} 294}
295 295
296static struct perf_pmu *pmu_lookup(char *name) 296static struct perf_pmu *pmu_lookup(const char *name)
297{ 297{
298 struct perf_pmu *pmu; 298 struct perf_pmu *pmu;
299 LIST_HEAD(format); 299 LIST_HEAD(format);
@@ -330,7 +330,7 @@ static struct perf_pmu *pmu_lookup(char *name)
330 return pmu; 330 return pmu;
331} 331}
332 332
333static struct perf_pmu *pmu_find(char *name) 333static struct perf_pmu *pmu_find(const char *name)
334{ 334{
335 struct perf_pmu *pmu; 335 struct perf_pmu *pmu;
336 336
@@ -356,7 +356,7 @@ struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu)
356 return NULL; 356 return NULL;
357} 357}
358 358
359struct perf_pmu *perf_pmu__find(char *name) 359struct perf_pmu *perf_pmu__find(const char *name)
360{ 360{
361 struct perf_pmu *pmu; 361 struct perf_pmu *pmu;
362 362
@@ -564,3 +564,76 @@ void perf_pmu__set_format(unsigned long *bits, long from, long to)
564 for (b = from; b <= to; b++) 564 for (b = from; b <= to; b++)
565 set_bit(b, bits); 565 set_bit(b, bits);
566} 566}
567
568static char *format_alias(char *buf, int len, struct perf_pmu *pmu,
569 struct perf_pmu_alias *alias)
570{
571 snprintf(buf, len, "%s/%s/", pmu->name, alias->name);
572 return buf;
573}
574
575static char *format_alias_or(char *buf, int len, struct perf_pmu *pmu,
576 struct perf_pmu_alias *alias)
577{
578 snprintf(buf, len, "%s OR %s/%s/", alias->name, pmu->name, alias->name);
579 return buf;
580}
581
582static int cmp_string(const void *a, const void *b)
583{
584 const char * const *as = a;
585 const char * const *bs = b;
586 return strcmp(*as, *bs);
587}
588
589void print_pmu_events(const char *event_glob, bool name_only)
590{
591 struct perf_pmu *pmu;
592 struct perf_pmu_alias *alias;
593 char buf[1024];
594 int printed = 0;
595 int len, j;
596 char **aliases;
597
598 pmu = NULL;
599 len = 0;
600 while ((pmu = perf_pmu__scan(pmu)) != NULL)
601 list_for_each_entry(alias, &pmu->aliases, list)
602 len++;
603 aliases = malloc(sizeof(char *) * len);
604 if (!aliases)
605 return;
606 pmu = NULL;
607 j = 0;
608 while ((pmu = perf_pmu__scan(pmu)) != NULL)
609 list_for_each_entry(alias, &pmu->aliases, list) {
610 char *name = format_alias(buf, sizeof(buf), pmu, alias);
611 bool is_cpu = !strcmp(pmu->name, "cpu");
612
613 if (event_glob != NULL &&
614 !(strglobmatch(name, event_glob) ||
615 (!is_cpu && strglobmatch(alias->name,
616 event_glob))))
617 continue;
618 aliases[j] = name;
619 if (is_cpu && !name_only)
620 aliases[j] = format_alias_or(buf, sizeof(buf),
621 pmu, alias);
622 aliases[j] = strdup(aliases[j]);
623 j++;
624 }
625 len = j;
626 qsort(aliases, len, sizeof(char *), cmp_string);
627 for (j = 0; j < len; j++) {
628 if (name_only) {
629 printf("%s ", aliases[j]);
630 continue;
631 }
632 printf(" %-50s [Kernel PMU event]\n", aliases[j]);
633 free(aliases[j]);
634 printed++;
635 }
636 if (printed)
637 printf("\n");
638 free(aliases);
639}
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 32fe55b659fa..6b2cbe2d4cc3 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -3,6 +3,7 @@
3 3
4#include <linux/bitops.h> 4#include <linux/bitops.h>
5#include <linux/perf_event.h> 5#include <linux/perf_event.h>
6#include <stdbool.h>
6 7
7enum { 8enum {
8 PERF_PMU_FORMAT_VALUE_CONFIG, 9 PERF_PMU_FORMAT_VALUE_CONFIG,
@@ -21,7 +22,7 @@ struct perf_pmu {
21 struct list_head list; 22 struct list_head list;
22}; 23};
23 24
24struct perf_pmu *perf_pmu__find(char *name); 25struct perf_pmu *perf_pmu__find(const char *name);
25int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, 26int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
26 struct list_head *head_terms); 27 struct list_head *head_terms);
27int perf_pmu__config_terms(struct list_head *formats, 28int perf_pmu__config_terms(struct list_head *formats,
@@ -40,5 +41,7 @@ int perf_pmu__format_parse(char *dir, struct list_head *head);
40 41
41struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu); 42struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu);
42 43
44void print_pmu_events(const char *event_glob, bool name_only);
45
43int perf_pmu__test(void); 46int perf_pmu__test(void);
44#endif /* __PMU_H */ 47#endif /* __PMU_H */
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index be0329394d56..371476cb8ddc 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -118,7 +118,6 @@ static const Dwfl_Callbacks offline_callbacks = {
118static int debuginfo__init_offline_dwarf(struct debuginfo *self, 118static int debuginfo__init_offline_dwarf(struct debuginfo *self,
119 const char *path) 119 const char *path)
120{ 120{
121 Dwfl_Module *mod;
122 int fd; 121 int fd;
123 122
124 fd = open(path, O_RDONLY); 123 fd = open(path, O_RDONLY);
@@ -129,11 +128,11 @@ static int debuginfo__init_offline_dwarf(struct debuginfo *self,
129 if (!self->dwfl) 128 if (!self->dwfl)
130 goto error; 129 goto error;
131 130
132 mod = dwfl_report_offline(self->dwfl, "", "", fd); 131 self->mod = dwfl_report_offline(self->dwfl, "", "", fd);
133 if (!mod) 132 if (!self->mod)
134 goto error; 133 goto error;
135 134
136 self->dbg = dwfl_module_getdwarf(mod, &self->bias); 135 self->dbg = dwfl_module_getdwarf(self->mod, &self->bias);
137 if (!self->dbg) 136 if (!self->dbg)
138 goto error; 137 goto error;
139 138
@@ -676,37 +675,42 @@ static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf)
676} 675}
677 676
678/* Convert subprogram DIE to trace point */ 677/* Convert subprogram DIE to trace point */
679static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr, 678static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod,
680 bool retprobe, struct probe_trace_point *tp) 679 Dwarf_Addr paddr, bool retprobe,
680 struct probe_trace_point *tp)
681{ 681{
682 Dwarf_Addr eaddr, highaddr; 682 Dwarf_Addr eaddr, highaddr;
683 const char *name; 683 GElf_Sym sym;
684 684 const char *symbol;
685 /* Copy the name of probe point */ 685
686 name = dwarf_diename(sp_die); 686 /* Verify the address is correct */
687 if (name) { 687 if (dwarf_entrypc(sp_die, &eaddr) != 0) {
688 if (dwarf_entrypc(sp_die, &eaddr) != 0) { 688 pr_warning("Failed to get entry address of %s\n",
689 pr_warning("Failed to get entry address of %s\n", 689 dwarf_diename(sp_die));
690 dwarf_diename(sp_die)); 690 return -ENOENT;
691 return -ENOENT; 691 }
692 } 692 if (dwarf_highpc(sp_die, &highaddr) != 0) {
693 if (dwarf_highpc(sp_die, &highaddr) != 0) { 693 pr_warning("Failed to get end address of %s\n",
694 pr_warning("Failed to get end address of %s\n", 694 dwarf_diename(sp_die));
695 dwarf_diename(sp_die)); 695 return -ENOENT;
696 return -ENOENT; 696 }
697 } 697 if (paddr > highaddr) {
698 if (paddr > highaddr) { 698 pr_warning("Offset specified is greater than size of %s\n",
699 pr_warning("Offset specified is greater than size of %s\n", 699 dwarf_diename(sp_die));
700 dwarf_diename(sp_die)); 700 return -EINVAL;
701 return -EINVAL; 701 }
702 } 702
703 tp->symbol = strdup(name); 703 /* Get an appropriate symbol from symtab */
704 if (tp->symbol == NULL) 704 symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL);
705 return -ENOMEM; 705 if (!symbol) {
706 tp->offset = (unsigned long)(paddr - eaddr); 706 pr_warning("Failed to find symbol at 0x%lx\n",
707 } else 707 (unsigned long)paddr);
708 /* This function has no name. */ 708 return -ENOENT;
709 tp->offset = (unsigned long)paddr; 709 }
710 tp->offset = (unsigned long)(paddr - sym.st_value);
711 tp->symbol = strdup(symbol);
712 if (!tp->symbol)
713 return -ENOMEM;
710 714
711 /* Return probe must be on the head of a subprogram */ 715 /* Return probe must be on the head of a subprogram */
712 if (retprobe) { 716 if (retprobe) {
@@ -734,7 +738,7 @@ static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf)
734 } 738 }
735 739
736 /* If not a real subprogram, find a real one */ 740 /* If not a real subprogram, find a real one */
737 if (dwarf_tag(sc_die) != DW_TAG_subprogram) { 741 if (!die_is_func_def(sc_die)) {
738 if (!die_find_realfunc(&pf->cu_die, pf->addr, &pf->sp_die)) { 742 if (!die_find_realfunc(&pf->cu_die, pf->addr, &pf->sp_die)) {
739 pr_warning("Failed to find probe point in any " 743 pr_warning("Failed to find probe point in any "
740 "functions.\n"); 744 "functions.\n");
@@ -980,12 +984,10 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
980 struct dwarf_callback_param *param = data; 984 struct dwarf_callback_param *param = data;
981 struct probe_finder *pf = param->data; 985 struct probe_finder *pf = param->data;
982 struct perf_probe_point *pp = &pf->pev->point; 986 struct perf_probe_point *pp = &pf->pev->point;
983 Dwarf_Attribute attr;
984 987
985 /* Check tag and diename */ 988 /* Check tag and diename */
986 if (dwarf_tag(sp_die) != DW_TAG_subprogram || 989 if (!die_is_func_def(sp_die) ||
987 !die_compare_name(sp_die, pp->function) || 990 !die_compare_name(sp_die, pp->function))
988 dwarf_attr(sp_die, DW_AT_declaration, &attr))
989 return DWARF_CB_OK; 991 return DWARF_CB_OK;
990 992
991 /* Check declared file */ 993 /* Check declared file */
@@ -1151,7 +1153,7 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
1151 tev = &tf->tevs[tf->ntevs++]; 1153 tev = &tf->tevs[tf->ntevs++];
1152 1154
1153 /* Trace point should be converted from subprogram DIE */ 1155 /* Trace point should be converted from subprogram DIE */
1154 ret = convert_to_trace_point(&pf->sp_die, pf->addr, 1156 ret = convert_to_trace_point(&pf->sp_die, tf->mod, pf->addr,
1155 pf->pev->point.retprobe, &tev->point); 1157 pf->pev->point.retprobe, &tev->point);
1156 if (ret < 0) 1158 if (ret < 0)
1157 return ret; 1159 return ret;
@@ -1183,7 +1185,7 @@ int debuginfo__find_trace_events(struct debuginfo *self,
1183{ 1185{
1184 struct trace_event_finder tf = { 1186 struct trace_event_finder tf = {
1185 .pf = {.pev = pev, .callback = add_probe_trace_event}, 1187 .pf = {.pev = pev, .callback = add_probe_trace_event},
1186 .max_tevs = max_tevs}; 1188 .mod = self->mod, .max_tevs = max_tevs};
1187 int ret; 1189 int ret;
1188 1190
1189 /* Allocate result tevs array */ 1191 /* Allocate result tevs array */
@@ -1252,7 +1254,7 @@ static int add_available_vars(Dwarf_Die *sc_die, struct probe_finder *pf)
1252 vl = &af->vls[af->nvls++]; 1254 vl = &af->vls[af->nvls++];
1253 1255
1254 /* Trace point should be converted from subprogram DIE */ 1256 /* Trace point should be converted from subprogram DIE */
1255 ret = convert_to_trace_point(&pf->sp_die, pf->addr, 1257 ret = convert_to_trace_point(&pf->sp_die, af->mod, pf->addr,
1256 pf->pev->point.retprobe, &vl->point); 1258 pf->pev->point.retprobe, &vl->point);
1257 if (ret < 0) 1259 if (ret < 0)
1258 return ret; 1260 return ret;
@@ -1291,6 +1293,7 @@ int debuginfo__find_available_vars_at(struct debuginfo *self,
1291{ 1293{
1292 struct available_var_finder af = { 1294 struct available_var_finder af = {
1293 .pf = {.pev = pev, .callback = add_available_vars}, 1295 .pf = {.pev = pev, .callback = add_available_vars},
1296 .mod = self->mod,
1294 .max_vls = max_vls, .externs = externs}; 1297 .max_vls = max_vls, .externs = externs};
1295 int ret; 1298 int ret;
1296 1299
@@ -1474,7 +1477,7 @@ static int line_range_inline_cb(Dwarf_Die *in_die, void *data)
1474 return 0; 1477 return 0;
1475} 1478}
1476 1479
1477/* Search function from function name */ 1480/* Search function definition from function name */
1478static int line_range_search_cb(Dwarf_Die *sp_die, void *data) 1481static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
1479{ 1482{
1480 struct dwarf_callback_param *param = data; 1483 struct dwarf_callback_param *param = data;
@@ -1485,7 +1488,7 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
1485 if (lr->file && strtailcmp(lr->file, dwarf_decl_file(sp_die))) 1488 if (lr->file && strtailcmp(lr->file, dwarf_decl_file(sp_die)))
1486 return DWARF_CB_OK; 1489 return DWARF_CB_OK;
1487 1490
1488 if (dwarf_tag(sp_die) == DW_TAG_subprogram && 1491 if (die_is_func_def(sp_die) &&
1489 die_compare_name(sp_die, lr->function)) { 1492 die_compare_name(sp_die, lr->function)) {
1490 lf->fname = dwarf_decl_file(sp_die); 1493 lf->fname = dwarf_decl_file(sp_die);
1491 dwarf_decl_line(sp_die, &lr->offset); 1494 dwarf_decl_line(sp_die, &lr->offset);
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index 17e94d0c36f9..3b7d63018960 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -23,6 +23,7 @@ static inline int is_c_varname(const char *name)
23/* debug information structure */ 23/* debug information structure */
24struct debuginfo { 24struct debuginfo {
25 Dwarf *dbg; 25 Dwarf *dbg;
26 Dwfl_Module *mod;
26 Dwfl *dwfl; 27 Dwfl *dwfl;
27 Dwarf_Addr bias; 28 Dwarf_Addr bias;
28}; 29};
@@ -77,6 +78,7 @@ struct probe_finder {
77 78
78struct trace_event_finder { 79struct trace_event_finder {
79 struct probe_finder pf; 80 struct probe_finder pf;
81 Dwfl_Module *mod; /* For solving symbols */
80 struct probe_trace_event *tevs; /* Found trace events */ 82 struct probe_trace_event *tevs; /* Found trace events */
81 int ntevs; /* Number of trace events */ 83 int ntevs; /* Number of trace events */
82 int max_tevs; /* Max number of trace events */ 84 int max_tevs; /* Max number of trace events */
@@ -84,6 +86,7 @@ struct trace_event_finder {
84 86
85struct available_var_finder { 87struct available_var_finder {
86 struct probe_finder pf; 88 struct probe_finder pf;
89 Dwfl_Module *mod; /* For solving symbols */
87 struct variable_list *vls; /* Found variable lists */ 90 struct variable_list *vls; /* Found variable lists */
88 int nvls; /* Number of variable lists */ 91 int nvls; /* Number of variable lists */
89 int max_vls; /* Max no. of variable lists */ 92 int max_vls; /* Max no. of variable lists */
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index 925e0c3e6d91..71b5412bbbb9 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -8,6 +8,26 @@
8#include "cpumap.h" 8#include "cpumap.h"
9#include "thread_map.h" 9#include "thread_map.h"
10 10
11/*
12 * Support debug printing even though util/debug.c is not linked. That means
13 * implementing 'verbose' and 'eprintf'.
14 */
15int verbose;
16
17int eprintf(int level, const char *fmt, ...)
18{
19 va_list args;
20 int ret = 0;
21
22 if (verbose >= level) {
23 va_start(args, fmt);
24 ret = vfprintf(stderr, fmt, args);
25 va_end(args);
26 }
27
28 return ret;
29}
30
11/* Define PyVarObject_HEAD_INIT for python 2.5 */ 31/* Define PyVarObject_HEAD_INIT for python 2.5 */
12#ifndef PyVarObject_HEAD_INIT 32#ifndef PyVarObject_HEAD_INIT
13# define PyVarObject_HEAD_INIT(type, size) PyObject_HEAD_INIT(type) size, 33# define PyVarObject_HEAD_INIT(type, size) PyObject_HEAD_INIT(type) size,
@@ -967,6 +987,7 @@ static struct {
967 { "COUNT_SW_PAGE_FAULTS_MAJ", PERF_COUNT_SW_PAGE_FAULTS_MAJ }, 987 { "COUNT_SW_PAGE_FAULTS_MAJ", PERF_COUNT_SW_PAGE_FAULTS_MAJ },
968 { "COUNT_SW_ALIGNMENT_FAULTS", PERF_COUNT_SW_ALIGNMENT_FAULTS }, 988 { "COUNT_SW_ALIGNMENT_FAULTS", PERF_COUNT_SW_ALIGNMENT_FAULTS },
969 { "COUNT_SW_EMULATION_FAULTS", PERF_COUNT_SW_EMULATION_FAULTS }, 989 { "COUNT_SW_EMULATION_FAULTS", PERF_COUNT_SW_EMULATION_FAULTS },
990 { "COUNT_SW_DUMMY", PERF_COUNT_SW_DUMMY },
970 991
971 { "SAMPLE_IP", PERF_SAMPLE_IP }, 992 { "SAMPLE_IP", PERF_SAMPLE_IP },
972 { "SAMPLE_TID", PERF_SAMPLE_TID }, 993 { "SAMPLE_TID", PERF_SAMPLE_TID },
diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c
new file mode 100644
index 000000000000..18d73aa2f0f8
--- /dev/null
+++ b/tools/perf/util/record.c
@@ -0,0 +1,108 @@
1#include "evlist.h"
2#include "evsel.h"
3#include "cpumap.h"
4#include "parse-events.h"
5
6typedef void (*setup_probe_fn_t)(struct perf_evsel *evsel);
7
8static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str)
9{
10 struct perf_evlist *evlist;
11 struct perf_evsel *evsel;
12 int err = -EAGAIN, fd;
13
14 evlist = perf_evlist__new();
15 if (!evlist)
16 return -ENOMEM;
17
18 if (parse_events(evlist, str))
19 goto out_delete;
20
21 evsel = perf_evlist__first(evlist);
22
23 fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0);
24 if (fd < 0)
25 goto out_delete;
26 close(fd);
27
28 fn(evsel);
29
30 fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0);
31 if (fd < 0) {
32 if (errno == EINVAL)
33 err = -EINVAL;
34 goto out_delete;
35 }
36 close(fd);
37 err = 0;
38
39out_delete:
40 perf_evlist__delete(evlist);
41 return err;
42}
43
44static bool perf_probe_api(setup_probe_fn_t fn)
45{
46 const char *try[] = {"cycles:u", "instructions:u", "cpu-clock", NULL};
47 struct cpu_map *cpus;
48 int cpu, ret, i = 0;
49
50 cpus = cpu_map__new(NULL);
51 if (!cpus)
52 return false;
53 cpu = cpus->map[0];
54 cpu_map__delete(cpus);
55
56 do {
57 ret = perf_do_probe_api(fn, cpu, try[i++]);
58 if (!ret)
59 return true;
60 } while (ret == -EAGAIN && try[i]);
61
62 return false;
63}
64
65static void perf_probe_sample_identifier(struct perf_evsel *evsel)
66{
67 evsel->attr.sample_type |= PERF_SAMPLE_IDENTIFIER;
68}
69
70bool perf_can_sample_identifier(void)
71{
72 return perf_probe_api(perf_probe_sample_identifier);
73}
74
75void perf_evlist__config(struct perf_evlist *evlist,
76 struct perf_record_opts *opts)
77{
78 struct perf_evsel *evsel;
79 bool use_sample_identifier = false;
80
81 /*
82 * Set the evsel leader links before we configure attributes,
83 * since some might depend on this info.
84 */
85 if (opts->group)
86 perf_evlist__set_leader(evlist);
87
88 if (evlist->cpus->map[0] < 0)
89 opts->no_inherit = true;
90
91 list_for_each_entry(evsel, &evlist->entries, node)
92 perf_evsel__config(evsel, opts);
93
94 if (evlist->nr_entries > 1) {
95 struct perf_evsel *first = perf_evlist__first(evlist);
96
97 list_for_each_entry(evsel, &evlist->entries, node) {
98 if (evsel->attr.sample_type == first->attr.sample_type)
99 continue;
100 use_sample_identifier = perf_can_sample_identifier();
101 break;
102 }
103 list_for_each_entry(evsel, &evlist->entries, node)
104 perf_evsel__set_sample_id(evsel, use_sample_identifier);
105 }
106
107 perf_evlist__set_id_pos(evlist);
108}
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index eacec859f299..a85e4ae5f3ac 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -261,7 +261,8 @@ static void perl_process_tracepoint(union perf_event *perf_event __maybe_unused,
261 struct perf_sample *sample, 261 struct perf_sample *sample,
262 struct perf_evsel *evsel, 262 struct perf_evsel *evsel,
263 struct machine *machine __maybe_unused, 263 struct machine *machine __maybe_unused,
264 struct addr_location *al) 264 struct thread *thread,
265 struct addr_location *al)
265{ 266{
266 struct format_field *field; 267 struct format_field *field;
267 static char handler[256]; 268 static char handler[256];
@@ -272,7 +273,6 @@ static void perl_process_tracepoint(union perf_event *perf_event __maybe_unused,
272 int cpu = sample->cpu; 273 int cpu = sample->cpu;
273 void *data = sample->raw_data; 274 void *data = sample->raw_data;
274 unsigned long long nsecs = sample->time; 275 unsigned long long nsecs = sample->time;
275 struct thread *thread = al->thread;
276 char *comm = thread->comm; 276 char *comm = thread->comm;
277 277
278 dSP; 278 dSP;
@@ -351,7 +351,8 @@ static void perl_process_event_generic(union perf_event *event,
351 struct perf_sample *sample, 351 struct perf_sample *sample,
352 struct perf_evsel *evsel, 352 struct perf_evsel *evsel,
353 struct machine *machine __maybe_unused, 353 struct machine *machine __maybe_unused,
354 struct addr_location *al __maybe_unused) 354 struct thread *thread __maybe_unused,
355 struct addr_location *al __maybe_unused)
355{ 356{
356 dSP; 357 dSP;
357 358
@@ -377,10 +378,11 @@ static void perl_process_event(union perf_event *event,
377 struct perf_sample *sample, 378 struct perf_sample *sample,
378 struct perf_evsel *evsel, 379 struct perf_evsel *evsel,
379 struct machine *machine, 380 struct machine *machine,
380 struct addr_location *al) 381 struct thread *thread,
382 struct addr_location *al)
381{ 383{
382 perl_process_tracepoint(event, sample, evsel, machine, al); 384 perl_process_tracepoint(event, sample, evsel, machine, thread, al);
383 perl_process_event_generic(event, sample, evsel, machine, al); 385 perl_process_event_generic(event, sample, evsel, machine, thread, al);
384} 386}
385 387
386static void run_start_sub(void) 388static void run_start_sub(void)
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index e87aa5d9696b..cc75a3cef388 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -225,6 +225,7 @@ static void python_process_tracepoint(union perf_event *perf_event
225 struct perf_sample *sample, 225 struct perf_sample *sample,
226 struct perf_evsel *evsel, 226 struct perf_evsel *evsel,
227 struct machine *machine __maybe_unused, 227 struct machine *machine __maybe_unused,
228 struct thread *thread,
228 struct addr_location *al) 229 struct addr_location *al)
229{ 230{
230 PyObject *handler, *retval, *context, *t, *obj, *dict = NULL; 231 PyObject *handler, *retval, *context, *t, *obj, *dict = NULL;
@@ -238,7 +239,6 @@ static void python_process_tracepoint(union perf_event *perf_event
238 int cpu = sample->cpu; 239 int cpu = sample->cpu;
239 void *data = sample->raw_data; 240 void *data = sample->raw_data;
240 unsigned long long nsecs = sample->time; 241 unsigned long long nsecs = sample->time;
241 struct thread *thread = al->thread;
242 char *comm = thread->comm; 242 char *comm = thread->comm;
243 243
244 t = PyTuple_New(MAX_FIELDS); 244 t = PyTuple_New(MAX_FIELDS);
@@ -345,12 +345,12 @@ static void python_process_general_event(union perf_event *perf_event
345 struct perf_sample *sample, 345 struct perf_sample *sample,
346 struct perf_evsel *evsel, 346 struct perf_evsel *evsel,
347 struct machine *machine __maybe_unused, 347 struct machine *machine __maybe_unused,
348 struct thread *thread,
348 struct addr_location *al) 349 struct addr_location *al)
349{ 350{
350 PyObject *handler, *retval, *t, *dict; 351 PyObject *handler, *retval, *t, *dict;
351 static char handler_name[64]; 352 static char handler_name[64];
352 unsigned n = 0; 353 unsigned n = 0;
353 struct thread *thread = al->thread;
354 354
355 /* 355 /*
356 * Use the MAX_FIELDS to make the function expandable, though 356 * Use the MAX_FIELDS to make the function expandable, though
@@ -404,17 +404,18 @@ static void python_process_event(union perf_event *perf_event,
404 struct perf_sample *sample, 404 struct perf_sample *sample,
405 struct perf_evsel *evsel, 405 struct perf_evsel *evsel,
406 struct machine *machine, 406 struct machine *machine,
407 struct thread *thread,
407 struct addr_location *al) 408 struct addr_location *al)
408{ 409{
409 switch (evsel->attr.type) { 410 switch (evsel->attr.type) {
410 case PERF_TYPE_TRACEPOINT: 411 case PERF_TYPE_TRACEPOINT:
411 python_process_tracepoint(perf_event, sample, evsel, 412 python_process_tracepoint(perf_event, sample, evsel,
412 machine, al); 413 machine, thread, al);
413 break; 414 break;
414 /* Reserve for future process_hw/sw/raw APIs */ 415 /* Reserve for future process_hw/sw/raw APIs */
415 default: 416 default:
416 python_process_general_event(perf_event, sample, evsel, 417 python_process_general_event(perf_event, sample, evsel,
417 machine, al); 418 machine, thread, al);
418 } 419 }
419} 420}
420 421
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index cf1fe01b7e89..70ffa41518f3 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1,4 +1,5 @@
1#include <linux/kernel.h> 1#include <linux/kernel.h>
2#include <traceevent/event-parse.h>
2 3
3#include <byteswap.h> 4#include <byteswap.h>
4#include <unistd.h> 5#include <unistd.h>
@@ -12,7 +13,6 @@
12#include "sort.h" 13#include "sort.h"
13#include "util.h" 14#include "util.h"
14#include "cpumap.h" 15#include "cpumap.h"
15#include "event-parse.h"
16#include "perf_regs.h" 16#include "perf_regs.h"
17#include "vdso.h" 17#include "vdso.h"
18 18
@@ -24,7 +24,7 @@ static int perf_session__open(struct perf_session *self, bool force)
24 self->fd_pipe = true; 24 self->fd_pipe = true;
25 self->fd = STDIN_FILENO; 25 self->fd = STDIN_FILENO;
26 26
27 if (perf_session__read_header(self, self->fd) < 0) 27 if (perf_session__read_header(self) < 0)
28 pr_err("incompatible file format (rerun with -v to learn more)"); 28 pr_err("incompatible file format (rerun with -v to learn more)");
29 29
30 return 0; 30 return 0;
@@ -56,7 +56,7 @@ static int perf_session__open(struct perf_session *self, bool force)
56 goto out_close; 56 goto out_close;
57 } 57 }
58 58
59 if (perf_session__read_header(self, self->fd) < 0) { 59 if (perf_session__read_header(self) < 0) {
60 pr_err("incompatible file format (rerun with -v to learn more)"); 60 pr_err("incompatible file format (rerun with -v to learn more)");
61 goto out_close; 61 goto out_close;
62 } 62 }
@@ -71,6 +71,11 @@ static int perf_session__open(struct perf_session *self, bool force)
71 goto out_close; 71 goto out_close;
72 } 72 }
73 73
74 if (!perf_evlist__valid_read_format(self->evlist)) {
75 pr_err("non matching read_format");
76 goto out_close;
77 }
78
74 self->size = input_stat.st_size; 79 self->size = input_stat.st_size;
75 return 0; 80 return 0;
76 81
@@ -193,7 +198,9 @@ void perf_session__delete(struct perf_session *self)
193 vdso__exit(); 198 vdso__exit();
194} 199}
195 200
196static int process_event_synth_tracing_data_stub(union perf_event *event 201static int process_event_synth_tracing_data_stub(struct perf_tool *tool
202 __maybe_unused,
203 union perf_event *event
197 __maybe_unused, 204 __maybe_unused,
198 struct perf_session *session 205 struct perf_session *session
199 __maybe_unused) 206 __maybe_unused)
@@ -202,7 +209,8 @@ static int process_event_synth_tracing_data_stub(union perf_event *event
202 return 0; 209 return 0;
203} 210}
204 211
205static int process_event_synth_attr_stub(union perf_event *event __maybe_unused, 212static int process_event_synth_attr_stub(struct perf_tool *tool __maybe_unused,
213 union perf_event *event __maybe_unused,
206 struct perf_evlist **pevlist 214 struct perf_evlist **pevlist
207 __maybe_unused) 215 __maybe_unused)
208{ 216{
@@ -238,18 +246,11 @@ static int process_finished_round_stub(struct perf_tool *tool __maybe_unused,
238 return 0; 246 return 0;
239} 247}
240 248
241static int process_event_type_stub(struct perf_tool *tool __maybe_unused,
242 union perf_event *event __maybe_unused)
243{
244 dump_printf(": unhandled!\n");
245 return 0;
246}
247
248static int process_finished_round(struct perf_tool *tool, 249static int process_finished_round(struct perf_tool *tool,
249 union perf_event *event, 250 union perf_event *event,
250 struct perf_session *session); 251 struct perf_session *session);
251 252
252static void perf_tool__fill_defaults(struct perf_tool *tool) 253void perf_tool__fill_defaults(struct perf_tool *tool)
253{ 254{
254 if (tool->sample == NULL) 255 if (tool->sample == NULL)
255 tool->sample = process_event_sample_stub; 256 tool->sample = process_event_sample_stub;
@@ -271,8 +272,6 @@ static void perf_tool__fill_defaults(struct perf_tool *tool)
271 tool->unthrottle = process_event_stub; 272 tool->unthrottle = process_event_stub;
272 if (tool->attr == NULL) 273 if (tool->attr == NULL)
273 tool->attr = process_event_synth_attr_stub; 274 tool->attr = process_event_synth_attr_stub;
274 if (tool->event_type == NULL)
275 tool->event_type = process_event_type_stub;
276 if (tool->tracing_data == NULL) 275 if (tool->tracing_data == NULL)
277 tool->tracing_data = process_event_synth_tracing_data_stub; 276 tool->tracing_data = process_event_synth_tracing_data_stub;
278 if (tool->build_id == NULL) 277 if (tool->build_id == NULL)
@@ -352,6 +351,25 @@ static void perf_event__mmap_swap(union perf_event *event,
352 } 351 }
353} 352}
354 353
354static void perf_event__mmap2_swap(union perf_event *event,
355 bool sample_id_all)
356{
357 event->mmap2.pid = bswap_32(event->mmap2.pid);
358 event->mmap2.tid = bswap_32(event->mmap2.tid);
359 event->mmap2.start = bswap_64(event->mmap2.start);
360 event->mmap2.len = bswap_64(event->mmap2.len);
361 event->mmap2.pgoff = bswap_64(event->mmap2.pgoff);
362 event->mmap2.maj = bswap_32(event->mmap2.maj);
363 event->mmap2.min = bswap_32(event->mmap2.min);
364 event->mmap2.ino = bswap_64(event->mmap2.ino);
365
366 if (sample_id_all) {
367 void *data = &event->mmap2.filename;
368
369 data += PERF_ALIGN(strlen(data) + 1, sizeof(u64));
370 swap_sample_id_all(event, data);
371 }
372}
355static void perf_event__task_swap(union perf_event *event, bool sample_id_all) 373static void perf_event__task_swap(union perf_event *event, bool sample_id_all)
356{ 374{
357 event->fork.pid = bswap_32(event->fork.pid); 375 event->fork.pid = bswap_32(event->fork.pid);
@@ -456,6 +474,7 @@ typedef void (*perf_event__swap_op)(union perf_event *event,
456 474
457static perf_event__swap_op perf_event__swap_ops[] = { 475static perf_event__swap_op perf_event__swap_ops[] = {
458 [PERF_RECORD_MMAP] = perf_event__mmap_swap, 476 [PERF_RECORD_MMAP] = perf_event__mmap_swap,
477 [PERF_RECORD_MMAP2] = perf_event__mmap2_swap,
459 [PERF_RECORD_COMM] = perf_event__comm_swap, 478 [PERF_RECORD_COMM] = perf_event__comm_swap,
460 [PERF_RECORD_FORK] = perf_event__task_swap, 479 [PERF_RECORD_FORK] = perf_event__task_swap,
461 [PERF_RECORD_EXIT] = perf_event__task_swap, 480 [PERF_RECORD_EXIT] = perf_event__task_swap,
@@ -496,7 +515,7 @@ static int perf_session_deliver_event(struct perf_session *session,
496 u64 file_offset); 515 u64 file_offset);
497 516
498static int flush_sample_queue(struct perf_session *s, 517static int flush_sample_queue(struct perf_session *s,
499 struct perf_tool *tool) 518 struct perf_tool *tool)
500{ 519{
501 struct ordered_samples *os = &s->ordered_samples; 520 struct ordered_samples *os = &s->ordered_samples;
502 struct list_head *head = &os->samples; 521 struct list_head *head = &os->samples;
@@ -505,12 +524,16 @@ static int flush_sample_queue(struct perf_session *s,
505 u64 limit = os->next_flush; 524 u64 limit = os->next_flush;
506 u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL; 525 u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL;
507 unsigned idx = 0, progress_next = os->nr_samples / 16; 526 unsigned idx = 0, progress_next = os->nr_samples / 16;
527 bool show_progress = limit == ULLONG_MAX;
508 int ret; 528 int ret;
509 529
510 if (!tool->ordered_samples || !limit) 530 if (!tool->ordered_samples || !limit)
511 return 0; 531 return 0;
512 532
513 list_for_each_entry_safe(iter, tmp, head, list) { 533 list_for_each_entry_safe(iter, tmp, head, list) {
534 if (session_done())
535 return 0;
536
514 if (iter->timestamp > limit) 537 if (iter->timestamp > limit)
515 break; 538 break;
516 539
@@ -527,7 +550,7 @@ static int flush_sample_queue(struct perf_session *s,
527 os->last_flush = iter->timestamp; 550 os->last_flush = iter->timestamp;
528 list_del(&iter->list); 551 list_del(&iter->list);
529 list_add(&iter->list, &os->sample_cache); 552 list_add(&iter->list, &os->sample_cache);
530 if (++idx >= progress_next) { 553 if (show_progress && (++idx >= progress_next)) {
531 progress_next += os->nr_samples / 16; 554 progress_next += os->nr_samples / 16;
532 ui_progress__update(idx, os->nr_samples, 555 ui_progress__update(idx, os->nr_samples,
533 "Processing time ordered events..."); 556 "Processing time ordered events...");
@@ -644,7 +667,7 @@ static void __queue_event(struct sample_queue *new, struct perf_session *s)
644 667
645#define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct sample_queue)) 668#define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct sample_queue))
646 669
647static int perf_session_queue_event(struct perf_session *s, union perf_event *event, 670int perf_session_queue_event(struct perf_session *s, union perf_event *event,
648 struct perf_sample *sample, u64 file_offset) 671 struct perf_sample *sample, u64 file_offset)
649{ 672{
650 struct ordered_samples *os = &s->ordered_samples; 673 struct ordered_samples *os = &s->ordered_samples;
@@ -740,7 +763,7 @@ static void perf_session__print_tstamp(struct perf_session *session,
740 union perf_event *event, 763 union perf_event *event,
741 struct perf_sample *sample) 764 struct perf_sample *sample)
742{ 765{
743 u64 sample_type = perf_evlist__sample_type(session->evlist); 766 u64 sample_type = __perf_evlist__combined_sample_type(session->evlist);
744 767
745 if (event->header.type != PERF_RECORD_SAMPLE && 768 if (event->header.type != PERF_RECORD_SAMPLE &&
746 !perf_evlist__sample_id_all(session->evlist)) { 769 !perf_evlist__sample_id_all(session->evlist)) {
@@ -755,6 +778,36 @@ static void perf_session__print_tstamp(struct perf_session *session,
755 printf("%" PRIu64 " ", sample->time); 778 printf("%" PRIu64 " ", sample->time);
756} 779}
757 780
781static void sample_read__printf(struct perf_sample *sample, u64 read_format)
782{
783 printf("... sample_read:\n");
784
785 if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
786 printf("...... time enabled %016" PRIx64 "\n",
787 sample->read.time_enabled);
788
789 if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
790 printf("...... time running %016" PRIx64 "\n",
791 sample->read.time_running);
792
793 if (read_format & PERF_FORMAT_GROUP) {
794 u64 i;
795
796 printf(".... group nr %" PRIu64 "\n", sample->read.group.nr);
797
798 for (i = 0; i < sample->read.group.nr; i++) {
799 struct sample_read_value *value;
800
801 value = &sample->read.group.values[i];
802 printf("..... id %016" PRIx64
803 ", value %016" PRIx64 "\n",
804 value->id, value->value);
805 }
806 } else
807 printf("..... id %016" PRIx64 ", value %016" PRIx64 "\n",
808 sample->read.one.id, sample->read.one.value);
809}
810
758static void dump_event(struct perf_session *session, union perf_event *event, 811static void dump_event(struct perf_session *session, union perf_event *event,
759 u64 file_offset, struct perf_sample *sample) 812 u64 file_offset, struct perf_sample *sample)
760{ 813{
@@ -804,11 +857,15 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event,
804 857
805 if (sample_type & PERF_SAMPLE_DATA_SRC) 858 if (sample_type & PERF_SAMPLE_DATA_SRC)
806 printf(" . data_src: 0x%"PRIx64"\n", sample->data_src); 859 printf(" . data_src: 0x%"PRIx64"\n", sample->data_src);
860
861 if (sample_type & PERF_SAMPLE_READ)
862 sample_read__printf(sample, evsel->attr.read_format);
807} 863}
808 864
809static struct machine * 865static struct machine *
810 perf_session__find_machine_for_cpumode(struct perf_session *session, 866 perf_session__find_machine_for_cpumode(struct perf_session *session,
811 union perf_event *event) 867 union perf_event *event,
868 struct perf_sample *sample)
812{ 869{
813 const u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 870 const u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
814 871
@@ -817,10 +874,11 @@ static struct machine *
817 (cpumode == PERF_RECORD_MISC_GUEST_USER))) { 874 (cpumode == PERF_RECORD_MISC_GUEST_USER))) {
818 u32 pid; 875 u32 pid;
819 876
820 if (event->header.type == PERF_RECORD_MMAP) 877 if (event->header.type == PERF_RECORD_MMAP
878 || event->header.type == PERF_RECORD_MMAP2)
821 pid = event->mmap.pid; 879 pid = event->mmap.pid;
822 else 880 else
823 pid = event->ip.pid; 881 pid = sample->pid;
824 882
825 return perf_session__findnew_machine(session, pid); 883 return perf_session__findnew_machine(session, pid);
826 } 884 }
@@ -828,6 +886,75 @@ static struct machine *
828 return &session->machines.host; 886 return &session->machines.host;
829} 887}
830 888
889static int deliver_sample_value(struct perf_session *session,
890 struct perf_tool *tool,
891 union perf_event *event,
892 struct perf_sample *sample,
893 struct sample_read_value *v,
894 struct machine *machine)
895{
896 struct perf_sample_id *sid;
897
898 sid = perf_evlist__id2sid(session->evlist, v->id);
899 if (sid) {
900 sample->id = v->id;
901 sample->period = v->value - sid->period;
902 sid->period = v->value;
903 }
904
905 if (!sid || sid->evsel == NULL) {
906 ++session->stats.nr_unknown_id;
907 return 0;
908 }
909
910 return tool->sample(tool, event, sample, sid->evsel, machine);
911}
912
913static int deliver_sample_group(struct perf_session *session,
914 struct perf_tool *tool,
915 union perf_event *event,
916 struct perf_sample *sample,
917 struct machine *machine)
918{
919 int ret = -EINVAL;
920 u64 i;
921
922 for (i = 0; i < sample->read.group.nr; i++) {
923 ret = deliver_sample_value(session, tool, event, sample,
924 &sample->read.group.values[i],
925 machine);
926 if (ret)
927 break;
928 }
929
930 return ret;
931}
932
933static int
934perf_session__deliver_sample(struct perf_session *session,
935 struct perf_tool *tool,
936 union perf_event *event,
937 struct perf_sample *sample,
938 struct perf_evsel *evsel,
939 struct machine *machine)
940{
941 /* We know evsel != NULL. */
942 u64 sample_type = evsel->attr.sample_type;
943 u64 read_format = evsel->attr.read_format;
944
945 /* Standard sample delievery. */
946 if (!(sample_type & PERF_SAMPLE_READ))
947 return tool->sample(tool, event, sample, evsel, machine);
948
949 /* For PERF_SAMPLE_READ we have either single or group mode. */
950 if (read_format & PERF_FORMAT_GROUP)
951 return deliver_sample_group(session, tool, event, sample,
952 machine);
953 else
954 return deliver_sample_value(session, tool, event, sample,
955 &sample->read.one, machine);
956}
957
831static int perf_session_deliver_event(struct perf_session *session, 958static int perf_session_deliver_event(struct perf_session *session,
832 union perf_event *event, 959 union perf_event *event,
833 struct perf_sample *sample, 960 struct perf_sample *sample,
@@ -857,7 +984,8 @@ static int perf_session_deliver_event(struct perf_session *session,
857 hists__inc_nr_events(&evsel->hists, event->header.type); 984 hists__inc_nr_events(&evsel->hists, event->header.type);
858 } 985 }
859 986
860 machine = perf_session__find_machine_for_cpumode(session, event); 987 machine = perf_session__find_machine_for_cpumode(session, event,
988 sample);
861 989
862 switch (event->header.type) { 990 switch (event->header.type) {
863 case PERF_RECORD_SAMPLE: 991 case PERF_RECORD_SAMPLE:
@@ -870,9 +998,12 @@ static int perf_session_deliver_event(struct perf_session *session,
870 ++session->stats.nr_unprocessable_samples; 998 ++session->stats.nr_unprocessable_samples;
871 return 0; 999 return 0;
872 } 1000 }
873 return tool->sample(tool, event, sample, evsel, machine); 1001 return perf_session__deliver_sample(session, tool, event,
1002 sample, evsel, machine);
874 case PERF_RECORD_MMAP: 1003 case PERF_RECORD_MMAP:
875 return tool->mmap(tool, event, sample, machine); 1004 return tool->mmap(tool, event, sample, machine);
1005 case PERF_RECORD_MMAP2:
1006 return tool->mmap2(tool, event, sample, machine);
876 case PERF_RECORD_COMM: 1007 case PERF_RECORD_COMM:
877 return tool->comm(tool, event, sample, machine); 1008 return tool->comm(tool, event, sample, machine);
878 case PERF_RECORD_FORK: 1009 case PERF_RECORD_FORK:
@@ -895,22 +1026,6 @@ static int perf_session_deliver_event(struct perf_session *session,
895 } 1026 }
896} 1027}
897 1028
898static int perf_session__preprocess_sample(struct perf_session *session,
899 union perf_event *event, struct perf_sample *sample)
900{
901 if (event->header.type != PERF_RECORD_SAMPLE ||
902 !(perf_evlist__sample_type(session->evlist) & PERF_SAMPLE_CALLCHAIN))
903 return 0;
904
905 if (!ip_callchain__valid(sample->callchain, event)) {
906 pr_debug("call-chain problem with event, skipping it.\n");
907 ++session->stats.nr_invalid_chains;
908 session->stats.total_invalid_chains += sample->period;
909 return -EINVAL;
910 }
911 return 0;
912}
913
914static int perf_session__process_user_event(struct perf_session *session, union perf_event *event, 1029static int perf_session__process_user_event(struct perf_session *session, union perf_event *event,
915 struct perf_tool *tool, u64 file_offset) 1030 struct perf_tool *tool, u64 file_offset)
916{ 1031{
@@ -921,16 +1036,14 @@ static int perf_session__process_user_event(struct perf_session *session, union
921 /* These events are processed right away */ 1036 /* These events are processed right away */
922 switch (event->header.type) { 1037 switch (event->header.type) {
923 case PERF_RECORD_HEADER_ATTR: 1038 case PERF_RECORD_HEADER_ATTR:
924 err = tool->attr(event, &session->evlist); 1039 err = tool->attr(tool, event, &session->evlist);
925 if (err == 0) 1040 if (err == 0)
926 perf_session__set_id_hdr_size(session); 1041 perf_session__set_id_hdr_size(session);
927 return err; 1042 return err;
928 case PERF_RECORD_HEADER_EVENT_TYPE:
929 return tool->event_type(tool, event);
930 case PERF_RECORD_HEADER_TRACING_DATA: 1043 case PERF_RECORD_HEADER_TRACING_DATA:
931 /* setup for reading amidst mmap */ 1044 /* setup for reading amidst mmap */
932 lseek(session->fd, file_offset, SEEK_SET); 1045 lseek(session->fd, file_offset, SEEK_SET);
933 return tool->tracing_data(event, session); 1046 return tool->tracing_data(tool, event, session);
934 case PERF_RECORD_HEADER_BUILD_ID: 1047 case PERF_RECORD_HEADER_BUILD_ID:
935 return tool->build_id(tool, event, session); 1048 return tool->build_id(tool, event, session);
936 case PERF_RECORD_FINISHED_ROUND: 1049 case PERF_RECORD_FINISHED_ROUND:
@@ -975,10 +1088,6 @@ static int perf_session__process_event(struct perf_session *session,
975 if (ret) 1088 if (ret)
976 return ret; 1089 return ret;
977 1090
978 /* Preprocess sample records - precheck callchains */
979 if (perf_session__preprocess_sample(session, event, &sample))
980 return 0;
981
982 if (tool->ordered_samples) { 1091 if (tool->ordered_samples) {
983 ret = perf_session_queue_event(session, event, &sample, 1092 ret = perf_session_queue_event(session, event, &sample,
984 file_offset); 1093 file_offset);
@@ -999,7 +1108,7 @@ void perf_event_header__bswap(struct perf_event_header *self)
999 1108
1000struct thread *perf_session__findnew(struct perf_session *session, pid_t pid) 1109struct thread *perf_session__findnew(struct perf_session *session, pid_t pid)
1001{ 1110{
1002 return machine__findnew_thread(&session->machines.host, pid); 1111 return machine__findnew_thread(&session->machines.host, 0, pid);
1003} 1112}
1004 1113
1005static struct thread *perf_session__register_idle_thread(struct perf_session *self) 1114static struct thread *perf_session__register_idle_thread(struct perf_session *self)
@@ -1054,7 +1163,6 @@ static void perf_session__warn_about_errors(const struct perf_session *session,
1054 } 1163 }
1055} 1164}
1056 1165
1057#define session_done() (*(volatile int *)(&session_done))
1058volatile int session_done; 1166volatile int session_done;
1059 1167
1060static int __perf_session__process_pipe_events(struct perf_session *self, 1168static int __perf_session__process_pipe_events(struct perf_session *self,
@@ -1091,8 +1199,10 @@ more:
1091 perf_event_header__bswap(&event->header); 1199 perf_event_header__bswap(&event->header);
1092 1200
1093 size = event->header.size; 1201 size = event->header.size;
1094 if (size == 0) 1202 if (size < sizeof(struct perf_event_header)) {
1095 size = 8; 1203 pr_err("bad event header size\n");
1204 goto out_err;
1205 }
1096 1206
1097 if (size > cur_size) { 1207 if (size > cur_size) {
1098 void *new = realloc(buf, size); 1208 void *new = realloc(buf, size);
@@ -1161,8 +1271,12 @@ fetch_mmaped_event(struct perf_session *session,
1161 if (session->header.needs_swap) 1271 if (session->header.needs_swap)
1162 perf_event_header__bswap(&event->header); 1272 perf_event_header__bswap(&event->header);
1163 1273
1164 if (head + event->header.size > mmap_size) 1274 if (head + event->header.size > mmap_size) {
1275 /* We're not fetching the event so swap back again */
1276 if (session->header.needs_swap)
1277 perf_event_header__bswap(&event->header);
1165 return NULL; 1278 return NULL;
1279 }
1166 1280
1167 return event; 1281 return event;
1168} 1282}
@@ -1242,7 +1356,7 @@ more:
1242 1356
1243 size = event->header.size; 1357 size = event->header.size;
1244 1358
1245 if (size == 0 || 1359 if (size < sizeof(struct perf_event_header) ||
1246 perf_session__process_event(session, event, tool, file_pos) < 0) { 1360 perf_session__process_event(session, event, tool, file_pos) < 0) {
1247 pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n", 1361 pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n",
1248 file_offset + head, event->header.size, 1362 file_offset + head, event->header.size,
@@ -1260,10 +1374,13 @@ more:
1260 "Processing events..."); 1374 "Processing events...");
1261 } 1375 }
1262 1376
1377 err = 0;
1378 if (session_done())
1379 goto out_err;
1380
1263 if (file_pos < file_size) 1381 if (file_pos < file_size)
1264 goto more; 1382 goto more;
1265 1383
1266 err = 0;
1267 /* do the final flush for ordered samples */ 1384 /* do the final flush for ordered samples */
1268 session->ordered_samples.next_flush = ULLONG_MAX; 1385 session->ordered_samples.next_flush = ULLONG_MAX;
1269 err = flush_sample_queue(session, tool); 1386 err = flush_sample_queue(session, tool);
@@ -1295,12 +1412,15 @@ int perf_session__process_events(struct perf_session *self,
1295 1412
1296bool perf_session__has_traces(struct perf_session *session, const char *msg) 1413bool perf_session__has_traces(struct perf_session *session, const char *msg)
1297{ 1414{
1298 if (!(perf_evlist__sample_type(session->evlist) & PERF_SAMPLE_RAW)) { 1415 struct perf_evsel *evsel;
1299 pr_err("No trace sample to read. Did you call 'perf %s'?\n", msg); 1416
1300 return false; 1417 list_for_each_entry(evsel, &session->evlist->entries, node) {
1418 if (evsel->attr.type == PERF_TYPE_TRACEPOINT)
1419 return true;
1301 } 1420 }
1302 1421
1303 return true; 1422 pr_err("No trace sample to read. Did you call 'perf %s'?\n", msg);
1423 return false;
1304} 1424}
1305 1425
1306int maps__set_kallsyms_ref_reloc_sym(struct map **maps, 1426int maps__set_kallsyms_ref_reloc_sym(struct map **maps,
@@ -1383,13 +1503,18 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
1383 1503
1384void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, 1504void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
1385 struct perf_sample *sample, struct machine *machine, 1505 struct perf_sample *sample, struct machine *machine,
1386 int print_sym, int print_dso, int print_symoffset) 1506 unsigned int print_opts, unsigned int stack_depth)
1387{ 1507{
1388 struct addr_location al; 1508 struct addr_location al;
1389 struct callchain_cursor_node *node; 1509 struct callchain_cursor_node *node;
1390 1510 int print_ip = print_opts & PRINT_IP_OPT_IP;
1391 if (perf_event__preprocess_sample(event, machine, &al, sample, 1511 int print_sym = print_opts & PRINT_IP_OPT_SYM;
1392 NULL) < 0) { 1512 int print_dso = print_opts & PRINT_IP_OPT_DSO;
1513 int print_symoffset = print_opts & PRINT_IP_OPT_SYMOFFSET;
1514 int print_oneline = print_opts & PRINT_IP_OPT_ONELINE;
1515 char s = print_oneline ? ' ' : '\t';
1516
1517 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
1393 error("problem processing %d event, skipping it.\n", 1518 error("problem processing %d event, skipping it.\n",
1394 event->header.type); 1519 event->header.type);
1395 return; 1520 return;
@@ -1397,37 +1522,50 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
1397 1522
1398 if (symbol_conf.use_callchain && sample->callchain) { 1523 if (symbol_conf.use_callchain && sample->callchain) {
1399 1524
1400
1401 if (machine__resolve_callchain(machine, evsel, al.thread, 1525 if (machine__resolve_callchain(machine, evsel, al.thread,
1402 sample, NULL) != 0) { 1526 sample, NULL, NULL) != 0) {
1403 if (verbose) 1527 if (verbose)
1404 error("Failed to resolve callchain. Skipping\n"); 1528 error("Failed to resolve callchain. Skipping\n");
1405 return; 1529 return;
1406 } 1530 }
1407 callchain_cursor_commit(&callchain_cursor); 1531 callchain_cursor_commit(&callchain_cursor);
1408 1532
1409 while (1) { 1533 while (stack_depth) {
1410 node = callchain_cursor_current(&callchain_cursor); 1534 node = callchain_cursor_current(&callchain_cursor);
1411 if (!node) 1535 if (!node)
1412 break; 1536 break;
1413 1537
1414 printf("\t%16" PRIx64, node->ip); 1538 if (print_ip)
1539 printf("%c%16" PRIx64, s, node->ip);
1540
1415 if (print_sym) { 1541 if (print_sym) {
1416 printf(" "); 1542 printf(" ");
1417 symbol__fprintf_symname(node->sym, stdout); 1543 if (print_symoffset) {
1544 al.addr = node->ip;
1545 al.map = node->map;
1546 symbol__fprintf_symname_offs(node->sym, &al, stdout);
1547 } else
1548 symbol__fprintf_symname(node->sym, stdout);
1418 } 1549 }
1550
1419 if (print_dso) { 1551 if (print_dso) {
1420 printf(" ("); 1552 printf(" (");
1421 map__fprintf_dsoname(node->map, stdout); 1553 map__fprintf_dsoname(node->map, stdout);
1422 printf(")"); 1554 printf(")");
1423 } 1555 }
1424 printf("\n"); 1556
1557 if (!print_oneline)
1558 printf("\n");
1425 1559
1426 callchain_cursor_advance(&callchain_cursor); 1560 callchain_cursor_advance(&callchain_cursor);
1561
1562 stack_depth--;
1427 } 1563 }
1428 1564
1429 } else { 1565 } else {
1430 printf("%16" PRIx64, sample->ip); 1566 if (print_ip)
1567 printf("%16" PRIx64, sample->ip);
1568
1431 if (print_sym) { 1569 if (print_sym) {
1432 printf(" "); 1570 printf(" ");
1433 if (print_symoffset) 1571 if (print_symoffset)
@@ -1510,52 +1648,26 @@ int __perf_session__set_tracepoints_handlers(struct perf_session *session,
1510 const struct perf_evsel_str_handler *assocs, 1648 const struct perf_evsel_str_handler *assocs,
1511 size_t nr_assocs) 1649 size_t nr_assocs)
1512{ 1650{
1513 struct perf_evlist *evlist = session->evlist;
1514 struct event_format *format;
1515 struct perf_evsel *evsel; 1651 struct perf_evsel *evsel;
1516 char *tracepoint, *name;
1517 size_t i; 1652 size_t i;
1518 int err; 1653 int err;
1519 1654
1520 for (i = 0; i < nr_assocs; i++) { 1655 for (i = 0; i < nr_assocs; i++) {
1521 err = -ENOMEM; 1656 /*
1522 tracepoint = strdup(assocs[i].name); 1657 * Adding a handler for an event not in the session,
1523 if (tracepoint == NULL) 1658 * just ignore it.
1524 goto out; 1659 */
1525 1660 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, assocs[i].name);
1526 err = -ENOENT;
1527 name = strchr(tracepoint, ':');
1528 if (name == NULL)
1529 goto out_free;
1530
1531 *name++ = '\0';
1532 format = pevent_find_event_by_name(session->pevent,
1533 tracepoint, name);
1534 if (format == NULL) {
1535 /*
1536 * Adding a handler for an event not in the session,
1537 * just ignore it.
1538 */
1539 goto next;
1540 }
1541
1542 evsel = perf_evlist__find_tracepoint_by_id(evlist, format->id);
1543 if (evsel == NULL) 1661 if (evsel == NULL)
1544 goto next; 1662 continue;
1545 1663
1546 err = -EEXIST; 1664 err = -EEXIST;
1547 if (evsel->handler.func != NULL) 1665 if (evsel->handler.func != NULL)
1548 goto out_free; 1666 goto out;
1549 evsel->handler.func = assocs[i].handler; 1667 evsel->handler.func = assocs[i].handler;
1550next:
1551 free(tracepoint);
1552 } 1668 }
1553 1669
1554 err = 0; 1670 err = 0;
1555out: 1671out:
1556 return err; 1672 return err;
1557
1558out_free:
1559 free(tracepoint);
1560 goto out;
1561} 1673}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index f3b235ec7bf4..04bf7373a7e5 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -37,11 +37,16 @@ struct perf_session {
37 int fd; 37 int fd;
38 bool fd_pipe; 38 bool fd_pipe;
39 bool repipe; 39 bool repipe;
40 char *cwd;
41 struct ordered_samples ordered_samples; 40 struct ordered_samples ordered_samples;
42 char filename[1]; 41 char filename[1];
43}; 42};
44 43
44#define PRINT_IP_OPT_IP (1<<0)
45#define PRINT_IP_OPT_SYM (1<<1)
46#define PRINT_IP_OPT_DSO (1<<2)
47#define PRINT_IP_OPT_SYMOFFSET (1<<3)
48#define PRINT_IP_OPT_ONELINE (1<<4)
49
45struct perf_tool; 50struct perf_tool;
46 51
47struct perf_session *perf_session__new(const char *filename, int mode, 52struct perf_session *perf_session__new(const char *filename, int mode,
@@ -57,6 +62,11 @@ int __perf_session__process_events(struct perf_session *self,
57int perf_session__process_events(struct perf_session *self, 62int perf_session__process_events(struct perf_session *self,
58 struct perf_tool *tool); 63 struct perf_tool *tool);
59 64
65int perf_session_queue_event(struct perf_session *s, union perf_event *event,
66 struct perf_sample *sample, u64 file_offset);
67
68void perf_tool__fill_defaults(struct perf_tool *tool);
69
60int perf_session__resolve_callchain(struct perf_session *self, struct perf_evsel *evsel, 70int perf_session__resolve_callchain(struct perf_session *self, struct perf_evsel *evsel,
61 struct thread *thread, 71 struct thread *thread,
62 struct ip_callchain *chain, 72 struct ip_callchain *chain,
@@ -99,7 +109,7 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
99 109
100void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, 110void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
101 struct perf_sample *sample, struct machine *machine, 111 struct perf_sample *sample, struct machine *machine,
102 int print_sym, int print_dso, int print_symoffset); 112 unsigned int print_opts, unsigned int stack_depth);
103 113
104int perf_session__cpu_bitmap(struct perf_session *session, 114int perf_session__cpu_bitmap(struct perf_session *session,
105 const char *cpu_list, unsigned long *cpu_bitmap); 115 const char *cpu_list, unsigned long *cpu_bitmap);
@@ -114,4 +124,8 @@ int __perf_session__set_tracepoints_handlers(struct perf_session *session,
114 124
115#define perf_session__set_tracepoints_handlers(session, array) \ 125#define perf_session__set_tracepoints_handlers(session, array) \
116 __perf_session__set_tracepoints_handlers(session, array, ARRAY_SIZE(array)) 126 __perf_session__set_tracepoints_handlers(session, array, ARRAY_SIZE(array))
127
128extern volatile int session_done;
129
130#define session_done() (*(volatile int *)(&session_done))
117#endif /* __PERF_SESSION_H */ 131#endif /* __PERF_SESSION_H */
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 313a5a730112..5f118a089519 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -7,6 +7,8 @@ const char default_parent_pattern[] = "^sys_|^do_page_fault";
7const char *parent_pattern = default_parent_pattern; 7const char *parent_pattern = default_parent_pattern;
8const char default_sort_order[] = "comm,dso,symbol"; 8const char default_sort_order[] = "comm,dso,symbol";
9const char *sort_order = default_sort_order; 9const char *sort_order = default_sort_order;
10regex_t ignore_callees_regex;
11int have_ignore_callees = 0;
10int sort__need_collapse = 0; 12int sort__need_collapse = 0;
11int sort__has_parent = 0; 13int sort__has_parent = 0;
12int sort__has_sym = 0; 14int sort__has_sym = 0;
@@ -55,14 +57,14 @@ static int64_t cmp_null(void *l, void *r)
55static int64_t 57static int64_t
56sort__thread_cmp(struct hist_entry *left, struct hist_entry *right) 58sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
57{ 59{
58 return right->thread->pid - left->thread->pid; 60 return right->thread->tid - left->thread->tid;
59} 61}
60 62
61static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf, 63static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf,
62 size_t size, unsigned int width) 64 size_t size, unsigned int width)
63{ 65{
64 return repsep_snprintf(bf, size, "%*s:%5d", width - 6, 66 return repsep_snprintf(bf, size, "%*s:%5d", width - 6,
65 self->thread->comm ?: "", self->thread->pid); 67 self->thread->comm ?: "", self->thread->tid);
66} 68}
67 69
68struct sort_entry sort_thread = { 70struct sort_entry sort_thread = {
@@ -77,7 +79,7 @@ struct sort_entry sort_thread = {
77static int64_t 79static int64_t
78sort__comm_cmp(struct hist_entry *left, struct hist_entry *right) 80sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
79{ 81{
80 return right->thread->pid - left->thread->pid; 82 return right->thread->tid - left->thread->tid;
81} 83}
82 84
83static int64_t 85static int64_t
@@ -872,6 +874,8 @@ static struct sort_dimension common_sort_dimensions[] = {
872 DIM(SORT_PARENT, "parent", sort_parent), 874 DIM(SORT_PARENT, "parent", sort_parent),
873 DIM(SORT_CPU, "cpu", sort_cpu), 875 DIM(SORT_CPU, "cpu", sort_cpu),
874 DIM(SORT_SRCLINE, "srcline", sort_srcline), 876 DIM(SORT_SRCLINE, "srcline", sort_srcline),
877 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
878 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
875}; 879};
876 880
877#undef DIM 881#undef DIM
@@ -891,8 +895,6 @@ static struct sort_dimension bstack_sort_dimensions[] = {
891#define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) } 895#define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
892 896
893static struct sort_dimension memory_sort_dimensions[] = { 897static struct sort_dimension memory_sort_dimensions[] = {
894 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
895 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
896 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym), 898 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
897 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso), 899 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
898 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked), 900 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 45ac84c1e037..4e80dbd271e7 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -29,6 +29,8 @@ extern const char *sort_order;
29extern const char default_parent_pattern[]; 29extern const char default_parent_pattern[];
30extern const char *parent_pattern; 30extern const char *parent_pattern;
31extern const char default_sort_order[]; 31extern const char default_sort_order[];
32extern regex_t ignore_callees_regex;
33extern int have_ignore_callees;
32extern int sort__need_collapse; 34extern int sort__need_collapse;
33extern int sort__has_parent; 35extern int sort__has_parent;
34extern int sort__has_sym; 36extern int sort__has_sym;
@@ -87,6 +89,9 @@ struct hist_entry {
87 89
88 struct hist_entry_diff diff; 90 struct hist_entry_diff diff;
89 91
92 /* We are added by hists__add_dummy_entry. */
93 bool dummy;
94
90 /* XXX These two should move to some tree widget lib */ 95 /* XXX These two should move to some tree widget lib */
91 u16 row_offset; 96 u16 row_offset;
92 u16 nr_rows; 97 u16 nr_rows;
@@ -138,6 +143,8 @@ enum sort_type {
138 SORT_PARENT, 143 SORT_PARENT,
139 SORT_CPU, 144 SORT_CPU,
140 SORT_SRCLINE, 145 SORT_SRCLINE,
146 SORT_LOCAL_WEIGHT,
147 SORT_GLOBAL_WEIGHT,
141 148
142 /* branch stack specific sort keys */ 149 /* branch stack specific sort keys */
143 __SORT_BRANCH_STACK, 150 __SORT_BRANCH_STACK,
@@ -149,9 +156,7 @@ enum sort_type {
149 156
150 /* memory mode specific sort keys */ 157 /* memory mode specific sort keys */
151 __SORT_MEMORY_MODE, 158 __SORT_MEMORY_MODE,
152 SORT_LOCAL_WEIGHT = __SORT_MEMORY_MODE, 159 SORT_MEM_DADDR_SYMBOL = __SORT_MEMORY_MODE,
153 SORT_GLOBAL_WEIGHT,
154 SORT_MEM_DADDR_SYMBOL,
155 SORT_MEM_DADDR_DSO, 160 SORT_MEM_DADDR_DSO,
156 SORT_MEM_LOCKED, 161 SORT_MEM_LOCKED,
157 SORT_MEM_TLB, 162 SORT_MEM_TLB,
@@ -183,4 +188,6 @@ int setup_sorting(void);
183extern int sort_dimension__add(const char *); 188extern int sort_dimension__add(const char *);
184void sort__setup_elide(FILE *fp); 189void sort__setup_elide(FILE *fp);
185 190
191int report_parse_ignore_callees_opt(const struct option *opt, const char *arg, int unset);
192
186#endif /* __PERF_SORT_H */ 193#endif /* __PERF_SORT_H */
diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c
index 7c59c28afcc5..6506b3dfb605 100644
--- a/tools/perf/util/stat.c
+++ b/tools/perf/util/stat.c
@@ -10,6 +10,12 @@ void update_stats(struct stats *stats, u64 val)
10 delta = val - stats->mean; 10 delta = val - stats->mean;
11 stats->mean += delta / stats->n; 11 stats->mean += delta / stats->n;
12 stats->M2 += delta*(val - stats->mean); 12 stats->M2 += delta*(val - stats->mean);
13
14 if (val > stats->max)
15 stats->max = val;
16
17 if (val < stats->min)
18 stats->min = val;
13} 19}
14 20
15double avg_stats(struct stats *stats) 21double avg_stats(struct stats *stats)
diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h
index 588367c3c767..ae8ccd7227cf 100644
--- a/tools/perf/util/stat.h
+++ b/tools/perf/util/stat.h
@@ -6,6 +6,7 @@
6struct stats 6struct stats
7{ 7{
8 double n, mean, M2; 8 double n, mean, M2;
9 u64 max, min;
9}; 10};
10 11
11void update_stats(struct stats *stats, u64 val); 12void update_stats(struct stats *stats, u64 val);
@@ -13,4 +14,12 @@ double avg_stats(struct stats *stats);
13double stddev_stats(struct stats *stats); 14double stddev_stats(struct stats *stats);
14double rel_stddev_stats(double stddev, double avg); 15double rel_stddev_stats(double stddev, double avg);
15 16
17static inline void init_stats(struct stats *stats)
18{
19 stats->n = 0.0;
20 stats->mean = 0.0;
21 stats->M2 = 0.0;
22 stats->min = (u64) -1;
23 stats->max = 0;
24}
16#endif 25#endif
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index 29c7b2cb2521..f0b0c008c507 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -387,3 +387,27 @@ void *memdup(const void *src, size_t len)
387 387
388 return p; 388 return p;
389} 389}
390
391/**
392 * str_append - reallocate string and append another
393 * @s: pointer to string pointer
394 * @len: pointer to len (initialized)
395 * @a: string to append.
396 */
397int str_append(char **s, int *len, const char *a)
398{
399 int olen = *s ? strlen(*s) : 0;
400 int nlen = olen + strlen(a) + 1;
401 if (*len < nlen) {
402 *len = *len * 2;
403 if (*len < nlen)
404 *len = nlen;
405 *s = realloc(*s, *len);
406 if (!*s)
407 return -ENOMEM;
408 if (olen == 0)
409 **s = 0;
410 }
411 strcat(*s, a);
412 return 0;
413}
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 4b12bf850325..a9c829be5216 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -8,6 +8,22 @@
8#include "symbol.h" 8#include "symbol.h"
9#include "debug.h" 9#include "debug.h"
10 10
11#ifndef HAVE_ELF_GETPHDRNUM
12static int elf_getphdrnum(Elf *elf, size_t *dst)
13{
14 GElf_Ehdr gehdr;
15 GElf_Ehdr *ehdr;
16
17 ehdr = gelf_getehdr(elf, &gehdr);
18 if (!ehdr)
19 return -1;
20
21 *dst = ehdr->e_phnum;
22
23 return 0;
24}
25#endif
26
11#ifndef NT_GNU_BUILD_ID 27#ifndef NT_GNU_BUILD_ID
12#define NT_GNU_BUILD_ID 3 28#define NT_GNU_BUILD_ID 3
13#endif 29#endif
@@ -599,11 +615,13 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
599 if (dso->kernel == DSO_TYPE_USER) { 615 if (dso->kernel == DSO_TYPE_USER) {
600 GElf_Shdr shdr; 616 GElf_Shdr shdr;
601 ss->adjust_symbols = (ehdr.e_type == ET_EXEC || 617 ss->adjust_symbols = (ehdr.e_type == ET_EXEC ||
618 ehdr.e_type == ET_REL ||
602 elf_section_by_name(elf, &ehdr, &shdr, 619 elf_section_by_name(elf, &ehdr, &shdr,
603 ".gnu.prelink_undo", 620 ".gnu.prelink_undo",
604 NULL) != NULL); 621 NULL) != NULL);
605 } else { 622 } else {
606 ss->adjust_symbols = 0; 623 ss->adjust_symbols = ehdr.e_type == ET_EXEC ||
624 ehdr.e_type == ET_REL;
607 } 625 }
608 626
609 ss->name = strdup(name); 627 ss->name = strdup(name);
@@ -624,6 +642,37 @@ out_close:
624 return err; 642 return err;
625} 643}
626 644
645/**
646 * ref_reloc_sym_not_found - has kernel relocation symbol been found.
647 * @kmap: kernel maps and relocation reference symbol
648 *
649 * This function returns %true if we are dealing with the kernel maps and the
650 * relocation reference symbol has not yet been found. Otherwise %false is
651 * returned.
652 */
653static bool ref_reloc_sym_not_found(struct kmap *kmap)
654{
655 return kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name &&
656 !kmap->ref_reloc_sym->unrelocated_addr;
657}
658
659/**
660 * ref_reloc - kernel relocation offset.
661 * @kmap: kernel maps and relocation reference symbol
662 *
663 * This function returns the offset of kernel addresses as determined by using
664 * the relocation reference symbol i.e. if the kernel has not been relocated
665 * then the return value is zero.
666 */
667static u64 ref_reloc(struct kmap *kmap)
668{
669 if (kmap && kmap->ref_reloc_sym &&
670 kmap->ref_reloc_sym->unrelocated_addr)
671 return kmap->ref_reloc_sym->addr -
672 kmap->ref_reloc_sym->unrelocated_addr;
673 return 0;
674}
675
627int dso__load_sym(struct dso *dso, struct map *map, 676int dso__load_sym(struct dso *dso, struct map *map,
628 struct symsrc *syms_ss, struct symsrc *runtime_ss, 677 struct symsrc *syms_ss, struct symsrc *runtime_ss,
629 symbol_filter_t filter, int kmodule) 678 symbol_filter_t filter, int kmodule)
@@ -642,8 +691,17 @@ int dso__load_sym(struct dso *dso, struct map *map,
642 Elf_Scn *sec, *sec_strndx; 691 Elf_Scn *sec, *sec_strndx;
643 Elf *elf; 692 Elf *elf;
644 int nr = 0; 693 int nr = 0;
694 bool remap_kernel = false, adjust_kernel_syms = false;
645 695
646 dso->symtab_type = syms_ss->type; 696 dso->symtab_type = syms_ss->type;
697 dso->rel = syms_ss->ehdr.e_type == ET_REL;
698
699 /*
700 * Modules may already have symbols from kallsyms, but those symbols
701 * have the wrong values for the dso maps, so remove them.
702 */
703 if (kmodule && syms_ss->symtab)
704 symbols__delete(&dso->symbols[map->type]);
647 705
648 if (!syms_ss->symtab) { 706 if (!syms_ss->symtab) {
649 syms_ss->symtab = syms_ss->dynsym; 707 syms_ss->symtab = syms_ss->dynsym;
@@ -681,7 +739,31 @@ int dso__load_sym(struct dso *dso, struct map *map,
681 nr_syms = shdr.sh_size / shdr.sh_entsize; 739 nr_syms = shdr.sh_size / shdr.sh_entsize;
682 740
683 memset(&sym, 0, sizeof(sym)); 741 memset(&sym, 0, sizeof(sym));
684 dso->adjust_symbols = runtime_ss->adjust_symbols; 742
743 /*
744 * The kernel relocation symbol is needed in advance in order to adjust
745 * kernel maps correctly.
746 */
747 if (ref_reloc_sym_not_found(kmap)) {
748 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
749 const char *elf_name = elf_sym__name(&sym, symstrs);
750
751 if (strcmp(elf_name, kmap->ref_reloc_sym->name))
752 continue;
753 kmap->ref_reloc_sym->unrelocated_addr = sym.st_value;
754 break;
755 }
756 }
757
758 dso->adjust_symbols = runtime_ss->adjust_symbols || ref_reloc(kmap);
759 /*
760 * Initial kernel and module mappings do not map to the dso. For
761 * function mappings, flag the fixups.
762 */
763 if (map->type == MAP__FUNCTION && (dso->kernel || kmodule)) {
764 remap_kernel = true;
765 adjust_kernel_syms = dso->adjust_symbols;
766 }
685 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 767 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
686 struct symbol *f; 768 struct symbol *f;
687 const char *elf_name = elf_sym__name(&sym, symstrs); 769 const char *elf_name = elf_sym__name(&sym, symstrs);
@@ -690,10 +772,6 @@ int dso__load_sym(struct dso *dso, struct map *map,
690 const char *section_name; 772 const char *section_name;
691 bool used_opd = false; 773 bool used_opd = false;
692 774
693 if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name &&
694 strcmp(elf_name, kmap->ref_reloc_sym->name) == 0)
695 kmap->ref_reloc_sym->unrelocated_addr = sym.st_value;
696
697 if (!is_label && !elf_sym__is_a(&sym, map->type)) 775 if (!is_label && !elf_sym__is_a(&sym, map->type))
698 continue; 776 continue;
699 777
@@ -745,20 +823,55 @@ int dso__load_sym(struct dso *dso, struct map *map,
745 (sym.st_value & 1)) 823 (sym.st_value & 1))
746 --sym.st_value; 824 --sym.st_value;
747 825
748 if (dso->kernel != DSO_TYPE_USER || kmodule) { 826 if (dso->kernel || kmodule) {
749 char dso_name[PATH_MAX]; 827 char dso_name[PATH_MAX];
750 828
829 /* Adjust symbol to map to file offset */
830 if (adjust_kernel_syms)
831 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
832
751 if (strcmp(section_name, 833 if (strcmp(section_name,
752 (curr_dso->short_name + 834 (curr_dso->short_name +
753 dso->short_name_len)) == 0) 835 dso->short_name_len)) == 0)
754 goto new_symbol; 836 goto new_symbol;
755 837
756 if (strcmp(section_name, ".text") == 0) { 838 if (strcmp(section_name, ".text") == 0) {
839 /*
840 * The initial kernel mapping is based on
841 * kallsyms and identity maps. Overwrite it to
842 * map to the kernel dso.
843 */
844 if (remap_kernel && dso->kernel) {
845 remap_kernel = false;
846 map->start = shdr.sh_addr +
847 ref_reloc(kmap);
848 map->end = map->start + shdr.sh_size;
849 map->pgoff = shdr.sh_offset;
850 map->map_ip = map__map_ip;
851 map->unmap_ip = map__unmap_ip;
852 /* Ensure maps are correctly ordered */
853 map_groups__remove(kmap->kmaps, map);
854 map_groups__insert(kmap->kmaps, map);
855 }
856
857 /*
858 * The initial module mapping is based on
859 * /proc/modules mapped to offset zero.
860 * Overwrite it to map to the module dso.
861 */
862 if (remap_kernel && kmodule) {
863 remap_kernel = false;
864 map->pgoff = shdr.sh_offset;
865 }
866
757 curr_map = map; 867 curr_map = map;
758 curr_dso = dso; 868 curr_dso = dso;
759 goto new_symbol; 869 goto new_symbol;
760 } 870 }
761 871
872 if (!kmap)
873 goto new_symbol;
874
762 snprintf(dso_name, sizeof(dso_name), 875 snprintf(dso_name, sizeof(dso_name),
763 "%s%s", dso->short_name, section_name); 876 "%s%s", dso->short_name, section_name);
764 877
@@ -781,8 +894,16 @@ int dso__load_sym(struct dso *dso, struct map *map,
781 dso__delete(curr_dso); 894 dso__delete(curr_dso);
782 goto out_elf_end; 895 goto out_elf_end;
783 } 896 }
784 curr_map->map_ip = identity__map_ip; 897 if (adjust_kernel_syms) {
785 curr_map->unmap_ip = identity__map_ip; 898 curr_map->start = shdr.sh_addr +
899 ref_reloc(kmap);
900 curr_map->end = curr_map->start +
901 shdr.sh_size;
902 curr_map->pgoff = shdr.sh_offset;
903 } else {
904 curr_map->map_ip = identity__map_ip;
905 curr_map->unmap_ip = identity__map_ip;
906 }
786 curr_dso->symtab_type = dso->symtab_type; 907 curr_dso->symtab_type = dso->symtab_type;
787 map_groups__insert(kmap->kmaps, curr_map); 908 map_groups__insert(kmap->kmaps, curr_map);
788 dsos__add(&dso->node, curr_dso); 909 dsos__add(&dso->node, curr_dso);
@@ -846,6 +967,57 @@ out_elf_end:
846 return err; 967 return err;
847} 968}
848 969
970static int elf_read_maps(Elf *elf, bool exe, mapfn_t mapfn, void *data)
971{
972 GElf_Phdr phdr;
973 size_t i, phdrnum;
974 int err;
975 u64 sz;
976
977 if (elf_getphdrnum(elf, &phdrnum))
978 return -1;
979
980 for (i = 0; i < phdrnum; i++) {
981 if (gelf_getphdr(elf, i, &phdr) == NULL)
982 return -1;
983 if (phdr.p_type != PT_LOAD)
984 continue;
985 if (exe) {
986 if (!(phdr.p_flags & PF_X))
987 continue;
988 } else {
989 if (!(phdr.p_flags & PF_R))
990 continue;
991 }
992 sz = min(phdr.p_memsz, phdr.p_filesz);
993 if (!sz)
994 continue;
995 err = mapfn(phdr.p_vaddr, sz, phdr.p_offset, data);
996 if (err)
997 return err;
998 }
999 return 0;
1000}
1001
1002int file__read_maps(int fd, bool exe, mapfn_t mapfn, void *data,
1003 bool *is_64_bit)
1004{
1005 int err;
1006 Elf *elf;
1007
1008 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
1009 if (elf == NULL)
1010 return -1;
1011
1012 if (is_64_bit)
1013 *is_64_bit = (gelf_getclass(elf) == ELFCLASS64);
1014
1015 err = elf_read_maps(elf, exe, mapfn, data);
1016
1017 elf_end(elf);
1018 return err;
1019}
1020
849void symbol__elf_init(void) 1021void symbol__elf_init(void)
850{ 1022{
851 elf_version(EV_CURRENT); 1023 elf_version(EV_CURRENT);
diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c
index a7390cde63bc..3a802c300fc5 100644
--- a/tools/perf/util/symbol-minimal.c
+++ b/tools/perf/util/symbol-minimal.c
@@ -301,6 +301,13 @@ int dso__load_sym(struct dso *dso, struct map *map __maybe_unused,
301 return 0; 301 return 0;
302} 302}
303 303
304int file__read_maps(int fd __maybe_unused, bool exe __maybe_unused,
305 mapfn_t mapfn __maybe_unused, void *data __maybe_unused,
306 bool *is_64_bit __maybe_unused)
307{
308 return -1;
309}
310
304void symbol__elf_init(void) 311void symbol__elf_init(void)
305{ 312{
306} 313}
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index d5528e1cc03a..7eb0362f4ffd 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -87,6 +87,7 @@ static int choose_best_symbol(struct symbol *syma, struct symbol *symb)
87{ 87{
88 s64 a; 88 s64 a;
89 s64 b; 89 s64 b;
90 size_t na, nb;
90 91
91 /* Prefer a symbol with non zero length */ 92 /* Prefer a symbol with non zero length */
92 a = syma->end - syma->start; 93 a = syma->end - syma->start;
@@ -120,11 +121,21 @@ static int choose_best_symbol(struct symbol *syma, struct symbol *symb)
120 else if (a > b) 121 else if (a > b)
121 return SYMBOL_B; 122 return SYMBOL_B;
122 123
123 /* If all else fails, choose the symbol with the longest name */ 124 /* Choose the symbol with the longest name */
124 if (strlen(syma->name) >= strlen(symb->name)) 125 na = strlen(syma->name);
126 nb = strlen(symb->name);
127 if (na > nb)
125 return SYMBOL_A; 128 return SYMBOL_A;
126 else 129 else if (na < nb)
130 return SYMBOL_B;
131
132 /* Avoid "SyS" kernel syscall aliases */
133 if (na >= 3 && !strncmp(syma->name, "SyS", 3))
134 return SYMBOL_B;
135 if (na >= 10 && !strncmp(syma->name, "compat_SyS", 10))
127 return SYMBOL_B; 136 return SYMBOL_B;
137
138 return SYMBOL_A;
128} 139}
129 140
130void symbols__fixup_duplicate(struct rb_root *symbols) 141void symbols__fixup_duplicate(struct rb_root *symbols)
@@ -248,7 +259,10 @@ size_t symbol__fprintf_symname_offs(const struct symbol *sym,
248 if (sym && sym->name) { 259 if (sym && sym->name) {
249 length = fprintf(fp, "%s", sym->name); 260 length = fprintf(fp, "%s", sym->name);
250 if (al) { 261 if (al) {
251 offset = al->addr - sym->start; 262 if (al->addr < sym->end)
263 offset = al->addr - sym->start;
264 else
265 offset = al->addr - al->map->start - sym->start;
252 length += fprintf(fp, "+0x%lx", offset); 266 length += fprintf(fp, "+0x%lx", offset);
253 } 267 }
254 return length; 268 return length;
@@ -316,6 +330,16 @@ static struct symbol *symbols__find(struct rb_root *symbols, u64 ip)
316 return NULL; 330 return NULL;
317} 331}
318 332
333static struct symbol *symbols__first(struct rb_root *symbols)
334{
335 struct rb_node *n = rb_first(symbols);
336
337 if (n)
338 return rb_entry(n, struct symbol, rb_node);
339
340 return NULL;
341}
342
319struct symbol_name_rb_node { 343struct symbol_name_rb_node {
320 struct rb_node rb_node; 344 struct rb_node rb_node;
321 struct symbol sym; 345 struct symbol sym;
@@ -386,6 +410,11 @@ struct symbol *dso__find_symbol(struct dso *dso,
386 return symbols__find(&dso->symbols[type], addr); 410 return symbols__find(&dso->symbols[type], addr);
387} 411}
388 412
413struct symbol *dso__first_symbol(struct dso *dso, enum map_type type)
414{
415 return symbols__first(&dso->symbols[type]);
416}
417
389struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, 418struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
390 const char *name) 419 const char *name)
391{ 420{
@@ -522,6 +551,53 @@ static int dso__load_all_kallsyms(struct dso *dso, const char *filename,
522 return kallsyms__parse(filename, &args, map__process_kallsym_symbol); 551 return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
523} 552}
524 553
554static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map,
555 symbol_filter_t filter)
556{
557 struct map_groups *kmaps = map__kmap(map)->kmaps;
558 struct map *curr_map;
559 struct symbol *pos;
560 int count = 0, moved = 0;
561 struct rb_root *root = &dso->symbols[map->type];
562 struct rb_node *next = rb_first(root);
563
564 while (next) {
565 char *module;
566
567 pos = rb_entry(next, struct symbol, rb_node);
568 next = rb_next(&pos->rb_node);
569
570 module = strchr(pos->name, '\t');
571 if (module)
572 *module = '\0';
573
574 curr_map = map_groups__find(kmaps, map->type, pos->start);
575
576 if (!curr_map || (filter && filter(curr_map, pos))) {
577 rb_erase(&pos->rb_node, root);
578 symbol__delete(pos);
579 } else {
580 pos->start -= curr_map->start - curr_map->pgoff;
581 if (pos->end)
582 pos->end -= curr_map->start - curr_map->pgoff;
583 if (curr_map != map) {
584 rb_erase(&pos->rb_node, root);
585 symbols__insert(
586 &curr_map->dso->symbols[curr_map->type],
587 pos);
588 ++moved;
589 } else {
590 ++count;
591 }
592 }
593 }
594
595 /* Symbols have been adjusted */
596 dso->adjust_symbols = 1;
597
598 return count + moved;
599}
600
525/* 601/*
526 * Split the symbols into maps, making sure there are no overlaps, i.e. the 602 * Split the symbols into maps, making sure there are no overlaps, i.e. the
527 * kernel range is broken in several maps, named [kernel].N, as we don't have 603 * kernel range is broken in several maps, named [kernel].N, as we don't have
@@ -663,6 +739,161 @@ bool symbol__restricted_filename(const char *filename,
663 return restricted; 739 return restricted;
664} 740}
665 741
742struct kcore_mapfn_data {
743 struct dso *dso;
744 enum map_type type;
745 struct list_head maps;
746};
747
748static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data)
749{
750 struct kcore_mapfn_data *md = data;
751 struct map *map;
752
753 map = map__new2(start, md->dso, md->type);
754 if (map == NULL)
755 return -ENOMEM;
756
757 map->end = map->start + len;
758 map->pgoff = pgoff;
759
760 list_add(&map->node, &md->maps);
761
762 return 0;
763}
764
765/*
766 * If kallsyms is referenced by name then we look for kcore in the same
767 * directory.
768 */
769static bool kcore_filename_from_kallsyms_filename(char *kcore_filename,
770 const char *kallsyms_filename)
771{
772 char *name;
773
774 strcpy(kcore_filename, kallsyms_filename);
775 name = strrchr(kcore_filename, '/');
776 if (!name)
777 return false;
778
779 if (!strcmp(name, "/kallsyms")) {
780 strcpy(name, "/kcore");
781 return true;
782 }
783
784 return false;
785}
786
787static int dso__load_kcore(struct dso *dso, struct map *map,
788 const char *kallsyms_filename)
789{
790 struct map_groups *kmaps = map__kmap(map)->kmaps;
791 struct machine *machine = kmaps->machine;
792 struct kcore_mapfn_data md;
793 struct map *old_map, *new_map, *replacement_map = NULL;
794 bool is_64_bit;
795 int err, fd;
796 char kcore_filename[PATH_MAX];
797 struct symbol *sym;
798
799 /* This function requires that the map is the kernel map */
800 if (map != machine->vmlinux_maps[map->type])
801 return -EINVAL;
802
803 if (!kcore_filename_from_kallsyms_filename(kcore_filename,
804 kallsyms_filename))
805 return -EINVAL;
806
807 md.dso = dso;
808 md.type = map->type;
809 INIT_LIST_HEAD(&md.maps);
810
811 fd = open(kcore_filename, O_RDONLY);
812 if (fd < 0)
813 return -EINVAL;
814
815 /* Read new maps into temporary lists */
816 err = file__read_maps(fd, md.type == MAP__FUNCTION, kcore_mapfn, &md,
817 &is_64_bit);
818 if (err)
819 goto out_err;
820
821 if (list_empty(&md.maps)) {
822 err = -EINVAL;
823 goto out_err;
824 }
825
826 /* Remove old maps */
827 old_map = map_groups__first(kmaps, map->type);
828 while (old_map) {
829 struct map *next = map_groups__next(old_map);
830
831 if (old_map != map)
832 map_groups__remove(kmaps, old_map);
833 old_map = next;
834 }
835
836 /* Find the kernel map using the first symbol */
837 sym = dso__first_symbol(dso, map->type);
838 list_for_each_entry(new_map, &md.maps, node) {
839 if (sym && sym->start >= new_map->start &&
840 sym->start < new_map->end) {
841 replacement_map = new_map;
842 break;
843 }
844 }
845
846 if (!replacement_map)
847 replacement_map = list_entry(md.maps.next, struct map, node);
848
849 /* Add new maps */
850 while (!list_empty(&md.maps)) {
851 new_map = list_entry(md.maps.next, struct map, node);
852 list_del(&new_map->node);
853 if (new_map == replacement_map) {
854 map->start = new_map->start;
855 map->end = new_map->end;
856 map->pgoff = new_map->pgoff;
857 map->map_ip = new_map->map_ip;
858 map->unmap_ip = new_map->unmap_ip;
859 map__delete(new_map);
860 /* Ensure maps are correctly ordered */
861 map_groups__remove(kmaps, map);
862 map_groups__insert(kmaps, map);
863 } else {
864 map_groups__insert(kmaps, new_map);
865 }
866 }
867
868 /*
869 * Set the data type and long name so that kcore can be read via
870 * dso__data_read_addr().
871 */
872 if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
873 dso->data_type = DSO_BINARY_TYPE__GUEST_KCORE;
874 else
875 dso->data_type = DSO_BINARY_TYPE__KCORE;
876 dso__set_long_name(dso, strdup(kcore_filename));
877
878 close(fd);
879
880 if (map->type == MAP__FUNCTION)
881 pr_debug("Using %s for kernel object code\n", kcore_filename);
882 else
883 pr_debug("Using %s for kernel data\n", kcore_filename);
884
885 return 0;
886
887out_err:
888 while (!list_empty(&md.maps)) {
889 map = list_entry(md.maps.next, struct map, node);
890 list_del(&map->node);
891 map__delete(map);
892 }
893 close(fd);
894 return -EINVAL;
895}
896
666int dso__load_kallsyms(struct dso *dso, const char *filename, 897int dso__load_kallsyms(struct dso *dso, const char *filename,
667 struct map *map, symbol_filter_t filter) 898 struct map *map, symbol_filter_t filter)
668{ 899{
@@ -680,7 +911,10 @@ int dso__load_kallsyms(struct dso *dso, const char *filename,
680 else 911 else
681 dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS; 912 dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS;
682 913
683 return dso__split_kallsyms(dso, map, filter); 914 if (!dso__load_kcore(dso, map, filename))
915 return dso__split_kallsyms_for_kcore(dso, map, filter);
916 else
917 return dso__split_kallsyms(dso, map, filter);
684} 918}
685 919
686static int dso__load_perf_map(struct dso *dso, struct map *map, 920static int dso__load_perf_map(struct dso *dso, struct map *map,
@@ -843,10 +1077,15 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
843 if (!runtime_ss && syms_ss) 1077 if (!runtime_ss && syms_ss)
844 runtime_ss = syms_ss; 1078 runtime_ss = syms_ss;
845 1079
846 if (syms_ss) 1080 if (syms_ss) {
847 ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, 0); 1081 int km;
848 else 1082
1083 km = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE ||
1084 dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE;
1085 ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, km);
1086 } else {
849 ret = -1; 1087 ret = -1;
1088 }
850 1089
851 if (ret > 0) { 1090 if (ret > 0) {
852 int nr_plt; 1091 int nr_plt;
@@ -888,8 +1127,11 @@ int dso__load_vmlinux(struct dso *dso, struct map *map,
888 char symfs_vmlinux[PATH_MAX]; 1127 char symfs_vmlinux[PATH_MAX];
889 enum dso_binary_type symtab_type; 1128 enum dso_binary_type symtab_type;
890 1129
891 snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s", 1130 if (vmlinux[0] == '/')
892 symbol_conf.symfs, vmlinux); 1131 snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s", vmlinux);
1132 else
1133 snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s",
1134 symbol_conf.symfs, vmlinux);
893 1135
894 if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 1136 if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
895 symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX; 1137 symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX;
@@ -903,6 +1145,10 @@ int dso__load_vmlinux(struct dso *dso, struct map *map,
903 symsrc__destroy(&ss); 1145 symsrc__destroy(&ss);
904 1146
905 if (err > 0) { 1147 if (err > 0) {
1148 if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
1149 dso->data_type = DSO_BINARY_TYPE__GUEST_VMLINUX;
1150 else
1151 dso->data_type = DSO_BINARY_TYPE__VMLINUX;
906 dso__set_long_name(dso, (char *)vmlinux); 1152 dso__set_long_name(dso, (char *)vmlinux);
907 dso__set_loaded(dso, map->type); 1153 dso__set_loaded(dso, map->type);
908 pr_debug("Using %s for symbols\n", symfs_vmlinux); 1154 pr_debug("Using %s for symbols\n", symfs_vmlinux);
@@ -975,7 +1221,7 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map,
975 dso__set_long_name(dso, 1221 dso__set_long_name(dso,
976 strdup(symbol_conf.vmlinux_name)); 1222 strdup(symbol_conf.vmlinux_name));
977 dso->lname_alloc = 1; 1223 dso->lname_alloc = 1;
978 goto out_fixup; 1224 return err;
979 } 1225 }
980 return err; 1226 return err;
981 } 1227 }
@@ -983,7 +1229,7 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map,
983 if (vmlinux_path != NULL) { 1229 if (vmlinux_path != NULL) {
984 err = dso__load_vmlinux_path(dso, map, filter); 1230 err = dso__load_vmlinux_path(dso, map, filter);
985 if (err > 0) 1231 if (err > 0)
986 goto out_fixup; 1232 return err;
987 } 1233 }
988 1234
989 /* do not try local files if a symfs was given */ 1235 /* do not try local files if a symfs was given */
@@ -1042,9 +1288,8 @@ do_kallsyms:
1042 pr_debug("Using %s for symbols\n", kallsyms_filename); 1288 pr_debug("Using %s for symbols\n", kallsyms_filename);
1043 free(kallsyms_allocated_filename); 1289 free(kallsyms_allocated_filename);
1044 1290
1045 if (err > 0) { 1291 if (err > 0 && !dso__is_kcore(dso)) {
1046 dso__set_long_name(dso, strdup("[kernel.kallsyms]")); 1292 dso__set_long_name(dso, strdup("[kernel.kallsyms]"));
1047out_fixup:
1048 map__fixup_start(map); 1293 map__fixup_start(map);
1049 map__fixup_end(map); 1294 map__fixup_end(map);
1050 } 1295 }
@@ -1075,7 +1320,7 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
1075 if (symbol_conf.default_guest_vmlinux_name != NULL) { 1320 if (symbol_conf.default_guest_vmlinux_name != NULL) {
1076 err = dso__load_vmlinux(dso, map, 1321 err = dso__load_vmlinux(dso, map,
1077 symbol_conf.default_guest_vmlinux_name, filter); 1322 symbol_conf.default_guest_vmlinux_name, filter);
1078 goto out_try_fixup; 1323 return err;
1079 } 1324 }
1080 1325
1081 kallsyms_filename = symbol_conf.default_guest_kallsyms; 1326 kallsyms_filename = symbol_conf.default_guest_kallsyms;
@@ -1089,13 +1334,9 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
1089 err = dso__load_kallsyms(dso, kallsyms_filename, map, filter); 1334 err = dso__load_kallsyms(dso, kallsyms_filename, map, filter);
1090 if (err > 0) 1335 if (err > 0)
1091 pr_debug("Using %s for symbols\n", kallsyms_filename); 1336 pr_debug("Using %s for symbols\n", kallsyms_filename);
1092 1337 if (err > 0 && !dso__is_kcore(dso)) {
1093out_try_fixup: 1338 machine__mmap_name(machine, path, sizeof(path));
1094 if (err > 0) { 1339 dso__set_long_name(dso, strdup(path));
1095 if (kallsyms_filename != NULL) {
1096 machine__mmap_name(machine, path, sizeof(path));
1097 dso__set_long_name(dso, strdup(path));
1098 }
1099 map__fixup_start(map); 1340 map__fixup_start(map);
1100 map__fixup_end(map); 1341 map__fixup_end(map);
1101 } 1342 }
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 5f720dc076da..fd5b70ea2981 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -215,6 +215,7 @@ struct symbol *dso__find_symbol(struct dso *dso, enum map_type type,
215 u64 addr); 215 u64 addr);
216struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, 216struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
217 const char *name); 217 const char *name);
218struct symbol *dso__first_symbol(struct dso *dso, enum map_type type);
218 219
219int filename__read_build_id(const char *filename, void *bf, size_t size); 220int filename__read_build_id(const char *filename, void *bf, size_t size);
220int sysfs__read_build_id(const char *filename, void *bf, size_t size); 221int sysfs__read_build_id(const char *filename, void *bf, size_t size);
@@ -247,4 +248,8 @@ void symbols__fixup_duplicate(struct rb_root *symbols);
247void symbols__fixup_end(struct rb_root *symbols); 248void symbols__fixup_end(struct rb_root *symbols);
248void __map_groups__fixup_end(struct map_groups *mg, enum map_type type); 249void __map_groups__fixup_end(struct map_groups *mg, enum map_type type);
249 250
251typedef int (*mapfn_t)(u64 start, u64 len, u64 pgoff, void *data);
252int file__read_maps(int fd, bool exe, mapfn_t mapfn, void *data,
253 bool *is_64_bit);
254
250#endif /* __PERF_SYMBOL */ 255#endif /* __PERF_SYMBOL */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 40399cbcca77..e3d4a550a703 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -7,17 +7,18 @@
7#include "util.h" 7#include "util.h"
8#include "debug.h" 8#include "debug.h"
9 9
10struct thread *thread__new(pid_t pid) 10struct thread *thread__new(pid_t pid, pid_t tid)
11{ 11{
12 struct thread *self = zalloc(sizeof(*self)); 12 struct thread *self = zalloc(sizeof(*self));
13 13
14 if (self != NULL) { 14 if (self != NULL) {
15 map_groups__init(&self->mg); 15 map_groups__init(&self->mg);
16 self->pid = pid; 16 self->pid_ = pid;
17 self->tid = tid;
17 self->ppid = -1; 18 self->ppid = -1;
18 self->comm = malloc(32); 19 self->comm = malloc(32);
19 if (self->comm) 20 if (self->comm)
20 snprintf(self->comm, 32, ":%d", self->pid); 21 snprintf(self->comm, 32, ":%d", self->tid);
21 } 22 }
22 23
23 return self; 24 return self;
@@ -57,7 +58,7 @@ int thread__comm_len(struct thread *self)
57 58
58size_t thread__fprintf(struct thread *thread, FILE *fp) 59size_t thread__fprintf(struct thread *thread, FILE *fp)
59{ 60{
60 return fprintf(fp, "Thread %d %s\n", thread->pid, thread->comm) + 61 return fprintf(fp, "Thread %d %s\n", thread->tid, thread->comm) +
61 map_groups__fprintf(&thread->mg, verbose, fp); 62 map_groups__fprintf(&thread->mg, verbose, fp);
62} 63}
63 64
@@ -84,7 +85,7 @@ int thread__fork(struct thread *self, struct thread *parent)
84 if (map_groups__clone(&self->mg, &parent->mg, i) < 0) 85 if (map_groups__clone(&self->mg, &parent->mg, i) < 0)
85 return -ENOMEM; 86 return -ENOMEM;
86 87
87 self->ppid = parent->pid; 88 self->ppid = parent->tid;
88 89
89 return 0; 90 return 0;
90} 91}
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index eeb7ac62b9e3..4ebbb40d46d4 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -12,10 +12,12 @@ struct thread {
12 struct list_head node; 12 struct list_head node;
13 }; 13 };
14 struct map_groups mg; 14 struct map_groups mg;
15 pid_t pid; 15 pid_t pid_; /* Not all tools update this */
16 pid_t tid;
16 pid_t ppid; 17 pid_t ppid;
17 char shortname[3]; 18 char shortname[3];
18 bool comm_set; 19 bool comm_set;
20 bool dead; /* if set thread has exited */
19 char *comm; 21 char *comm;
20 int comm_len; 22 int comm_len;
21 23
@@ -24,8 +26,12 @@ struct thread {
24 26
25struct machine; 27struct machine;
26 28
27struct thread *thread__new(pid_t pid); 29struct thread *thread__new(pid_t pid, pid_t tid);
28void thread__delete(struct thread *self); 30void thread__delete(struct thread *self);
31static inline void thread__exited(struct thread *thread)
32{
33 thread->dead = true;
34}
29 35
30int thread__set_comm(struct thread *self, const char *comm); 36int thread__set_comm(struct thread *self, const char *comm);
31int thread__comm_len(struct thread *self); 37int thread__comm_len(struct thread *self);
@@ -45,6 +51,15 @@ void thread__find_addr_map(struct thread *thread, struct machine *machine,
45 51
46void thread__find_addr_location(struct thread *thread, struct machine *machine, 52void thread__find_addr_location(struct thread *thread, struct machine *machine,
47 u8 cpumode, enum map_type type, u64 addr, 53 u8 cpumode, enum map_type type, u64 addr,
48 struct addr_location *al, 54 struct addr_location *al);
49 symbol_filter_t filter); 55
56static inline void *thread__priv(struct thread *thread)
57{
58 return thread->priv;
59}
60
61static inline void thread__set_priv(struct thread *thread, void *p)
62{
63 thread->priv = p;
64}
50#endif /* __PERF_THREAD_H */ 65#endif /* __PERF_THREAD_H */
diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h
index b0e1aadba8d5..4385816d3d49 100644
--- a/tools/perf/util/tool.h
+++ b/tools/perf/util/tool.h
@@ -18,12 +18,9 @@ typedef int (*event_sample)(struct perf_tool *tool, union perf_event *event,
18typedef int (*event_op)(struct perf_tool *tool, union perf_event *event, 18typedef int (*event_op)(struct perf_tool *tool, union perf_event *event,
19 struct perf_sample *sample, struct machine *machine); 19 struct perf_sample *sample, struct machine *machine);
20 20
21typedef int (*event_attr_op)(union perf_event *event, 21typedef int (*event_attr_op)(struct perf_tool *tool,
22 union perf_event *event,
22 struct perf_evlist **pevlist); 23 struct perf_evlist **pevlist);
23typedef int (*event_simple_op)(struct perf_tool *tool, union perf_event *event);
24
25typedef int (*event_synth_op)(union perf_event *event,
26 struct perf_session *session);
27 24
28typedef int (*event_op2)(struct perf_tool *tool, union perf_event *event, 25typedef int (*event_op2)(struct perf_tool *tool, union perf_event *event,
29 struct perf_session *session); 26 struct perf_session *session);
@@ -32,6 +29,7 @@ struct perf_tool {
32 event_sample sample, 29 event_sample sample,
33 read; 30 read;
34 event_op mmap, 31 event_op mmap,
32 mmap2,
35 comm, 33 comm,
36 fork, 34 fork,
37 exit, 35 exit,
@@ -39,8 +37,7 @@ struct perf_tool {
39 throttle, 37 throttle,
40 unthrottle; 38 unthrottle;
41 event_attr_op attr; 39 event_attr_op attr;
42 event_synth_op tracing_data; 40 event_op2 tracing_data;
43 event_simple_op event_type;
44 event_op2 finished_round, 41 event_op2 finished_round,
45 build_id; 42 build_id;
46 bool ordered_samples; 43 bool ordered_samples;
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index df46be93d902..b554ffc462b6 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -39,6 +39,8 @@ struct perf_top {
39 float min_percent; 39 float min_percent;
40}; 40};
41 41
42#define CONSOLE_CLEAR ""
43
42size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size); 44size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size);
43void perf_top__reset_sample_counters(struct perf_top *top); 45void perf_top__reset_sample_counters(struct perf_top *top);
44#endif /* __PERF_TOP_H */ 46#endif /* __PERF_TOP_H */
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index 3917eb9a8479..f3c9e551bd35 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -46,65 +46,6 @@
46static int output_fd; 46static int output_fd;
47 47
48 48
49static const char *find_debugfs(void)
50{
51 const char *path = perf_debugfs_mount(NULL);
52
53 if (!path)
54 pr_debug("Your kernel does not support the debugfs filesystem");
55
56 return path;
57}
58
59/*
60 * Finds the path to the debugfs/tracing
61 * Allocates the string and stores it.
62 */
63static const char *find_tracing_dir(void)
64{
65 static char *tracing;
66 static int tracing_found;
67 const char *debugfs;
68
69 if (tracing_found)
70 return tracing;
71
72 debugfs = find_debugfs();
73 if (!debugfs)
74 return NULL;
75
76 tracing = malloc(strlen(debugfs) + 9);
77 if (!tracing)
78 return NULL;
79
80 sprintf(tracing, "%s/tracing", debugfs);
81
82 tracing_found = 1;
83 return tracing;
84}
85
86static char *get_tracing_file(const char *name)
87{
88 const char *tracing;
89 char *file;
90
91 tracing = find_tracing_dir();
92 if (!tracing)
93 return NULL;
94
95 file = malloc(strlen(tracing) + strlen(name) + 2);
96 if (!file)
97 return NULL;
98
99 sprintf(file, "%s/%s", tracing, name);
100 return file;
101}
102
103static void put_tracing_file(char *file)
104{
105 free(file);
106}
107
108int bigendian(void) 49int bigendian(void)
109{ 50{
110 unsigned char str[] = { 0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0}; 51 unsigned char str[] = { 0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0};
@@ -160,7 +101,7 @@ out:
160 return err; 101 return err;
161} 102}
162 103
163static int read_header_files(void) 104static int record_header_files(void)
164{ 105{
165 char *path; 106 char *path;
166 struct stat st; 107 struct stat st;
@@ -299,7 +240,7 @@ out:
299 return err; 240 return err;
300} 241}
301 242
302static int read_ftrace_files(struct tracepoint_path *tps) 243static int record_ftrace_files(struct tracepoint_path *tps)
303{ 244{
304 char *path; 245 char *path;
305 int ret; 246 int ret;
@@ -328,7 +269,7 @@ static bool system_in_tp_list(char *sys, struct tracepoint_path *tps)
328 return false; 269 return false;
329} 270}
330 271
331static int read_event_files(struct tracepoint_path *tps) 272static int record_event_files(struct tracepoint_path *tps)
332{ 273{
333 struct dirent *dent; 274 struct dirent *dent;
334 struct stat st; 275 struct stat st;
@@ -403,7 +344,7 @@ out:
403 return err; 344 return err;
404} 345}
405 346
406static int read_proc_kallsyms(void) 347static int record_proc_kallsyms(void)
407{ 348{
408 unsigned int size; 349 unsigned int size;
409 const char *path = "/proc/kallsyms"; 350 const char *path = "/proc/kallsyms";
@@ -421,7 +362,7 @@ static int read_proc_kallsyms(void)
421 return record_file(path, 4); 362 return record_file(path, 4);
422} 363}
423 364
424static int read_ftrace_printk(void) 365static int record_ftrace_printk(void)
425{ 366{
426 unsigned int size; 367 unsigned int size;
427 char *path; 368 char *path;
@@ -473,12 +414,27 @@ get_tracepoints_path(struct list_head *pattrs)
473 if (pos->attr.type != PERF_TYPE_TRACEPOINT) 414 if (pos->attr.type != PERF_TYPE_TRACEPOINT)
474 continue; 415 continue;
475 ++nr_tracepoints; 416 ++nr_tracepoints;
417
418 if (pos->name) {
419 ppath->next = tracepoint_name_to_path(pos->name);
420 if (ppath->next)
421 goto next;
422
423 if (strchr(pos->name, ':') == NULL)
424 goto try_id;
425
426 goto error;
427 }
428
429try_id:
476 ppath->next = tracepoint_id_to_path(pos->attr.config); 430 ppath->next = tracepoint_id_to_path(pos->attr.config);
477 if (!ppath->next) { 431 if (!ppath->next) {
432error:
478 pr_debug("No memory to alloc tracepoints list\n"); 433 pr_debug("No memory to alloc tracepoints list\n");
479 put_tracepoints_path(&path); 434 put_tracepoints_path(&path);
480 return NULL; 435 return NULL;
481 } 436 }
437next:
482 ppath = ppath->next; 438 ppath = ppath->next;
483 } 439 }
484 440
@@ -520,8 +476,6 @@ static int tracing_data_header(void)
520 else 476 else
521 buf[0] = 0; 477 buf[0] = 0;
522 478
523 read_trace_init(buf[0], buf[0]);
524
525 if (write(output_fd, buf, 1) != 1) 479 if (write(output_fd, buf, 1) != 1)
526 return -1; 480 return -1;
527 481
@@ -583,19 +537,19 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs,
583 err = tracing_data_header(); 537 err = tracing_data_header();
584 if (err) 538 if (err)
585 goto out; 539 goto out;
586 err = read_header_files(); 540 err = record_header_files();
587 if (err) 541 if (err)
588 goto out; 542 goto out;
589 err = read_ftrace_files(tps); 543 err = record_ftrace_files(tps);
590 if (err) 544 if (err)
591 goto out; 545 goto out;
592 err = read_event_files(tps); 546 err = record_event_files(tps);
593 if (err) 547 if (err)
594 goto out; 548 goto out;
595 err = read_proc_kallsyms(); 549 err = record_proc_kallsyms();
596 if (err) 550 if (err)
597 goto out; 551 goto out;
598 err = read_ftrace_printk(); 552 err = record_ftrace_printk();
599 553
600out: 554out:
601 /* 555 /*
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index 4454835a9ebc..e9e1c03f927d 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -28,12 +28,6 @@
28#include "util.h" 28#include "util.h"
29#include "trace-event.h" 29#include "trace-event.h"
30 30
31int header_page_size_size;
32int header_page_ts_size;
33int header_page_data_offset;
34
35bool latency_format;
36
37struct pevent *read_trace_init(int file_bigendian, int host_bigendian) 31struct pevent *read_trace_init(int file_bigendian, int host_bigendian)
38{ 32{
39 struct pevent *pevent = pevent_alloc(); 33 struct pevent *pevent = pevent_alloc();
@@ -192,7 +186,7 @@ void parse_proc_kallsyms(struct pevent *pevent,
192 char *next = NULL; 186 char *next = NULL;
193 char *addr_str; 187 char *addr_str;
194 char *mod; 188 char *mod;
195 char *fmt; 189 char *fmt = NULL;
196 190
197 line = strtok_r(file, "\n", &next); 191 line = strtok_r(file, "\n", &next);
198 while (line) { 192 while (line) {
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index af215c0d2379..f2112270c663 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -39,10 +39,6 @@
39 39
40static int input_fd; 40static int input_fd;
41 41
42int file_bigendian;
43int host_bigendian;
44static int long_size;
45
46static ssize_t trace_data_size; 42static ssize_t trace_data_size;
47static bool repipe; 43static bool repipe;
48 44
@@ -216,7 +212,7 @@ static int read_ftrace_printk(struct pevent *pevent)
216static int read_header_files(struct pevent *pevent) 212static int read_header_files(struct pevent *pevent)
217{ 213{
218 unsigned long long size; 214 unsigned long long size;
219 char *header_event; 215 char *header_page;
220 char buf[BUFSIZ]; 216 char buf[BUFSIZ];
221 int ret = 0; 217 int ret = 0;
222 218
@@ -229,13 +225,26 @@ static int read_header_files(struct pevent *pevent)
229 } 225 }
230 226
231 size = read8(pevent); 227 size = read8(pevent);
232 skip(size);
233 228
234 /* 229 header_page = malloc(size);
235 * The size field in the page is of type long, 230 if (header_page == NULL)
236 * use that instead, since it represents the kernel. 231 return -1;
237 */ 232
238 long_size = header_page_size_size; 233 if (do_read(header_page, size) < 0) {
234 pr_debug("did not read header page");
235 free(header_page);
236 return -1;
237 }
238
239 if (!pevent_parse_header_page(pevent, header_page, size,
240 pevent_get_long_size(pevent))) {
241 /*
242 * The commit field in the page is of type long,
243 * use that instead, since it represents the kernel.
244 */
245 pevent_set_long_size(pevent, pevent->header_page_size_size);
246 }
247 free(header_page);
239 248
240 if (do_read(buf, 13) < 0) 249 if (do_read(buf, 13) < 0)
241 return -1; 250 return -1;
@@ -246,14 +255,8 @@ static int read_header_files(struct pevent *pevent)
246 } 255 }
247 256
248 size = read8(pevent); 257 size = read8(pevent);
249 header_event = malloc(size); 258 skip(size);
250 if (header_event == NULL)
251 return -1;
252
253 if (do_read(header_event, size) < 0)
254 ret = -1;
255 259
256 free(header_event);
257 return ret; 260 return ret;
258} 261}
259 262
@@ -349,6 +352,10 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
349 int show_funcs = 0; 352 int show_funcs = 0;
350 int show_printk = 0; 353 int show_printk = 0;
351 ssize_t size = -1; 354 ssize_t size = -1;
355 int file_bigendian;
356 int host_bigendian;
357 int file_long_size;
358 int file_page_size;
352 struct pevent *pevent; 359 struct pevent *pevent;
353 int err; 360 int err;
354 361
@@ -391,12 +398,15 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
391 398
392 if (do_read(buf, 1) < 0) 399 if (do_read(buf, 1) < 0)
393 goto out; 400 goto out;
394 long_size = buf[0]; 401 file_long_size = buf[0];
395 402
396 page_size = read4(pevent); 403 file_page_size = read4(pevent);
397 if (!page_size) 404 if (!file_page_size)
398 goto out; 405 goto out;
399 406
407 pevent_set_long_size(pevent, file_long_size);
408 pevent_set_page_size(pevent, file_page_size);
409
400 err = read_header_files(pevent); 410 err = read_header_files(pevent);
401 if (err) 411 if (err)
402 goto out; 412 goto out;
diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c
index 8715a1006d00..95199e4eea97 100644
--- a/tools/perf/util/trace-event-scripting.c
+++ b/tools/perf/util/trace-event-scripting.c
@@ -39,7 +39,8 @@ static void process_event_unsupported(union perf_event *event __maybe_unused,
39 struct perf_sample *sample __maybe_unused, 39 struct perf_sample *sample __maybe_unused,
40 struct perf_evsel *evsel __maybe_unused, 40 struct perf_evsel *evsel __maybe_unused,
41 struct machine *machine __maybe_unused, 41 struct machine *machine __maybe_unused,
42 struct addr_location *al __maybe_unused) 42 struct thread *thread __maybe_unused,
43 struct addr_location *al __maybe_unused)
43{ 44{
44} 45}
45 46
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index 1978c398ad87..fafe1a40444a 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -1,32 +1,18 @@
1#ifndef _PERF_UTIL_TRACE_EVENT_H 1#ifndef _PERF_UTIL_TRACE_EVENT_H
2#define _PERF_UTIL_TRACE_EVENT_H 2#define _PERF_UTIL_TRACE_EVENT_H
3 3
4#include <traceevent/event-parse.h>
4#include "parse-events.h" 5#include "parse-events.h"
5#include "event-parse.h"
6#include "session.h" 6#include "session.h"
7 7
8struct machine; 8struct machine;
9struct perf_sample; 9struct perf_sample;
10union perf_event; 10union perf_event;
11struct perf_tool; 11struct perf_tool;
12struct thread;
12 13
13extern int header_page_size_size;
14extern int header_page_ts_size;
15extern int header_page_data_offset;
16
17extern bool latency_format;
18extern struct pevent *perf_pevent; 14extern struct pevent *perf_pevent;
19 15
20enum {
21 RINGBUF_TYPE_PADDING = 29,
22 RINGBUF_TYPE_TIME_EXTEND = 30,
23 RINGBUF_TYPE_TIME_STAMP = 31,
24};
25
26#ifndef TS_SHIFT
27#define TS_SHIFT 27
28#endif
29
30int bigendian(void); 16int bigendian(void);
31 17
32struct pevent *read_trace_init(int file_bigendian, int host_bigendian); 18struct pevent *read_trace_init(int file_bigendian, int host_bigendian);
@@ -83,7 +69,8 @@ struct scripting_ops {
83 struct perf_sample *sample, 69 struct perf_sample *sample,
84 struct perf_evsel *evsel, 70 struct perf_evsel *evsel,
85 struct machine *machine, 71 struct machine *machine,
86 struct addr_location *al); 72 struct thread *thread,
73 struct addr_location *al);
87 int (*generate_script) (struct pevent *pevent, const char *outfile); 74 int (*generate_script) (struct pevent *pevent, const char *outfile);
88}; 75};
89 76
diff --git a/tools/perf/util/unwind.c b/tools/perf/util/unwind.c
index 958723ba3d2e..2f891f7e70bf 100644
--- a/tools/perf/util/unwind.c
+++ b/tools/perf/util/unwind.c
@@ -473,7 +473,7 @@ static int entry(u64 ip, struct thread *thread, struct machine *machine,
473 473
474 thread__find_addr_location(thread, machine, 474 thread__find_addr_location(thread, machine,
475 PERF_RECORD_MISC_USER, 475 PERF_RECORD_MISC_USER,
476 MAP__FUNCTION, ip, &al, NULL); 476 MAP__FUNCTION, ip, &al);
477 477
478 e.ip = ip; 478 e.ip = ip;
479 e.map = al.map; 479 e.map = al.map;
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 59d868add275..6d17b18e915d 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -269,3 +269,95 @@ void perf_debugfs_set_path(const char *mntpt)
269 snprintf(debugfs_mountpoint, strlen(debugfs_mountpoint), "%s", mntpt); 269 snprintf(debugfs_mountpoint, strlen(debugfs_mountpoint), "%s", mntpt);
270 set_tracing_events_path(mntpt); 270 set_tracing_events_path(mntpt);
271} 271}
272
273static const char *find_debugfs(void)
274{
275 const char *path = perf_debugfs_mount(NULL);
276
277 if (!path)
278 fprintf(stderr, "Your kernel does not support the debugfs filesystem");
279
280 return path;
281}
282
283/*
284 * Finds the path to the debugfs/tracing
285 * Allocates the string and stores it.
286 */
287const char *find_tracing_dir(void)
288{
289 static char *tracing;
290 static int tracing_found;
291 const char *debugfs;
292
293 if (tracing_found)
294 return tracing;
295
296 debugfs = find_debugfs();
297 if (!debugfs)
298 return NULL;
299
300 tracing = malloc(strlen(debugfs) + 9);
301 if (!tracing)
302 return NULL;
303
304 sprintf(tracing, "%s/tracing", debugfs);
305
306 tracing_found = 1;
307 return tracing;
308}
309
310char *get_tracing_file(const char *name)
311{
312 const char *tracing;
313 char *file;
314
315 tracing = find_tracing_dir();
316 if (!tracing)
317 return NULL;
318
319 file = malloc(strlen(tracing) + strlen(name) + 2);
320 if (!file)
321 return NULL;
322
323 sprintf(file, "%s/%s", tracing, name);
324 return file;
325}
326
327void put_tracing_file(char *file)
328{
329 free(file);
330}
331
332int parse_nsec_time(const char *str, u64 *ptime)
333{
334 u64 time_sec, time_nsec;
335 char *end;
336
337 time_sec = strtoul(str, &end, 10);
338 if (*end != '.' && *end != '\0')
339 return -1;
340
341 if (*end == '.') {
342 int i;
343 char nsec_buf[10];
344
345 if (strlen(++end) > 9)
346 return -1;
347
348 strncpy(nsec_buf, end, 9);
349 nsec_buf[9] = '\0';
350
351 /* make it nsec precision */
352 for (i = strlen(nsec_buf); i < 9; i++)
353 nsec_buf[i] = '0';
354
355 time_nsec = strtoul(nsec_buf, &end, 10);
356 if (*end != '\0')
357 return -1;
358 } else
359 time_nsec = 0;
360
361 *ptime = time_sec * NSEC_PER_SEC + time_nsec;
362 return 0;
363}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 2732fad03908..a53535949043 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -80,6 +80,9 @@ extern char buildid_dir[];
80extern char tracing_events_path[]; 80extern char tracing_events_path[];
81extern void perf_debugfs_set_path(const char *mountpoint); 81extern void perf_debugfs_set_path(const char *mountpoint);
82const char *perf_debugfs_mount(const char *mountpoint); 82const char *perf_debugfs_mount(const char *mountpoint);
83const char *find_tracing_dir(void);
84char *get_tracing_file(const char *name);
85void put_tracing_file(char *file);
83 86
84/* On most systems <limits.h> would have given us this, but 87/* On most systems <limits.h> would have given us this, but
85 * not on some systems (e.g. GNU/Hurd). 88 * not on some systems (e.g. GNU/Hurd).
@@ -205,6 +208,8 @@ static inline int has_extension(const char *filename, const char *ext)
205#define NSEC_PER_MSEC 1000000L 208#define NSEC_PER_MSEC 1000000L
206#endif 209#endif
207 210
211int parse_nsec_time(const char *str, u64 *ptime);
212
208extern unsigned char sane_ctype[256]; 213extern unsigned char sane_ctype[256];
209#define GIT_SPACE 0x01 214#define GIT_SPACE 0x01
210#define GIT_DIGIT 0x02 215#define GIT_DIGIT 0x02