aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2011-11-28 12:46:22 -0500
committerTejun Heo <tj@kernel.org>2011-11-28 12:46:22 -0500
commitd4bbf7e7759afc172e2bfbc5c416324590049cdd (patch)
tree7eab5ee5481cd3dcf1162329fec827177640018a /tools/perf
parenta150439c4a97db379f0ed6faa46fbbb6e7bf3cb2 (diff)
parent401d0069cb344f401bc9d264c31db55876ff78c0 (diff)
Merge branch 'master' into x86/memblock
Conflicts & resolutions: * arch/x86/xen/setup.c dc91c728fd "xen: allow extra memory to be in multiple regions" 24aa07882b "memblock, x86: Replace memblock_x86_reserve/free..." conflicted on xen_add_extra_mem() updates. The resolution is trivial as the latter just want to replace memblock_x86_reserve_range() with memblock_reserve(). * drivers/pci/intel-iommu.c 166e9278a3f "x86/ia64: intel-iommu: move to drivers/iommu/" 5dfe8660a3d "bootmem: Replace work_with_active_regions() with..." conflicted as the former moved the file under drivers/iommu/. Resolved by applying the chnages from the latter on the moved file. * mm/Kconfig 6661672053a "memblock: add NO_BOOTMEM config symbol" c378ddd53f9 "memblock, x86: Make ARCH_DISCARD_MEMBLOCK a config option" conflicted trivially. Both added config options. Just letting both add their own options resolves the conflict. * mm/memblock.c d1f0ece6cdc "mm/memblock.c: small function definition fixes" ed7b56a799c "memblock: Remove memblock_memory_can_coalesce()" confliected. The former updates function removed by the latter. Resolution is trivial. Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/Documentation/perf-annotate.txt19
-rw-r--r--tools/perf/Documentation/perf-buildid-list.txt6
-rw-r--r--tools/perf/Documentation/perf-probe.txt6
-rw-r--r--tools/perf/Documentation/perf-report.txt41
-rw-r--r--tools/perf/Documentation/perf-sched.txt6
-rw-r--r--tools/perf/Documentation/perf-script.txt25
-rw-r--r--tools/perf/Documentation/perf-stat.txt16
-rw-r--r--tools/perf/Documentation/perf-top.txt48
-rw-r--r--tools/perf/Documentation/perfconfig.example20
-rw-r--r--tools/perf/Makefile42
-rw-r--r--tools/perf/arch/arm/util/dwarf-regs.c3
-rw-r--r--tools/perf/arch/powerpc/Makefile1
-rw-r--r--tools/perf/arch/powerpc/util/header.c36
-rw-r--r--tools/perf/arch/x86/Makefile1
-rw-r--r--tools/perf/arch/x86/util/header.c59
-rw-r--r--tools/perf/builtin-annotate.c40
-rw-r--r--tools/perf/builtin-buildid-list.c52
-rw-r--r--tools/perf/builtin-diff.c2
-rw-r--r--tools/perf/builtin-lock.c8
-rw-r--r--tools/perf/builtin-probe.c17
-rw-r--r--tools/perf/builtin-record.c75
-rw-r--r--tools/perf/builtin-report.c100
-rw-r--r--tools/perf/builtin-sched.c24
-rw-r--r--tools/perf/builtin-script.c127
-rw-r--r--tools/perf/builtin-stat.c227
-rw-r--r--tools/perf/builtin-test.c257
-rw-r--r--tools/perf/builtin-top.c534
-rw-r--r--tools/perf/builtin.h1
-rw-r--r--tools/perf/perf.c24
-rw-r--r--tools/perf/perf.h13
-rwxr-xr-xtools/perf/scripts/python/bin/net_dropmonitor-record2
-rwxr-xr-xtools/perf/scripts/python/bin/net_dropmonitor-report4
-rwxr-xr-xtools/perf/scripts/python/net_dropmonitor.py72
-rw-r--r--tools/perf/util/annotate.c20
-rw-r--r--tools/perf/util/annotate.h9
-rw-r--r--tools/perf/util/callchain.h6
-rw-r--r--tools/perf/util/color.c2
-rw-r--r--tools/perf/util/config.c36
-rw-r--r--tools/perf/util/debug.c7
-rw-r--r--tools/perf/util/debug.h17
-rw-r--r--tools/perf/util/dwarf-aux.c843
-rw-r--r--tools/perf/util/dwarf-aux.h111
-rw-r--r--tools/perf/util/event.c5
-rw-r--r--tools/perf/util/event.h2
-rw-r--r--tools/perf/util/evlist.c73
-rw-r--r--tools/perf/util/evlist.h9
-rw-r--r--tools/perf/util/evsel.c102
-rw-r--r--tools/perf/util/evsel.h11
-rw-r--r--tools/perf/util/header.c1257
-rw-r--r--tools/perf/util/header.h29
-rw-r--r--tools/perf/util/hist.c452
-rw-r--r--tools/perf/util/hist.h62
-rw-r--r--tools/perf/util/include/linux/compiler.h2
-rw-r--r--tools/perf/util/map.c102
-rw-r--r--tools/perf/util/map.h42
-rw-r--r--tools/perf/util/parse-events.c47
-rw-r--r--tools/perf/util/parse-events.h6
-rw-r--r--tools/perf/util/probe-event.c173
-rw-r--r--tools/perf/util/probe-event.h1
-rw-r--r--tools/perf/util/probe-finder.c981
-rw-r--r--tools/perf/util/probe-finder.h45
-rw-r--r--tools/perf/util/python.c165
-rw-r--r--tools/perf/util/session.c197
-rw-r--r--tools/perf/util/session.h14
-rw-r--r--tools/perf/util/setup.py21
-rw-r--r--tools/perf/util/sort.c237
-rw-r--r--tools/perf/util/sort.h16
-rw-r--r--tools/perf/util/string.c19
-rw-r--r--tools/perf/util/symbol.c224
-rw-r--r--tools/perf/util/symbol.h6
-rw-r--r--tools/perf/util/top.c141
-rw-r--r--tools/perf/util/top.h38
-rw-r--r--tools/perf/util/trace-event-info.c230
-rw-r--r--tools/perf/util/trace-event.h13
-rw-r--r--tools/perf/util/ui/browser.c429
-rw-r--r--tools/perf/util/ui/browser.h21
-rw-r--r--tools/perf/util/ui/browsers/annotate.c215
-rw-r--r--tools/perf/util/ui/browsers/hists.c351
-rw-r--r--tools/perf/util/ui/browsers/map.c6
-rw-r--r--tools/perf/util/ui/browsers/top.c213
-rw-r--r--tools/perf/util/ui/helpline.c16
-rw-r--r--tools/perf/util/ui/helpline.h5
-rw-r--r--tools/perf/util/ui/keysyms.h25
-rw-r--r--tools/perf/util/ui/libslang.h2
-rw-r--r--tools/perf/util/ui/progress.c65
-rw-r--r--tools/perf/util/ui/progress.h7
-rw-r--r--tools/perf/util/ui/setup.c121
-rw-r--r--tools/perf/util/ui/ui.h3
-rw-r--r--tools/perf/util/ui/util.c182
-rw-r--r--tools/perf/util/ui/util.h8
-rw-r--r--tools/perf/util/util.h1
91 files changed, 6663 insertions, 2688 deletions
diff --git a/tools/perf/Documentation/perf-annotate.txt b/tools/perf/Documentation/perf-annotate.txt
index 6f5a498608b2..fe6762ed56bd 100644
--- a/tools/perf/Documentation/perf-annotate.txt
+++ b/tools/perf/Documentation/perf-annotate.txt
@@ -66,6 +66,25 @@ OPTIONS
66 used. This interfaces starts by centering on the line with more 66 used. This interfaces starts by centering on the line with more
67 samples, TAB/UNTAB cycles through the lines with more samples. 67 samples, TAB/UNTAB cycles through the lines with more samples.
68 68
69-c::
70--cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can
71 be provided as a comma-separated list with no space: 0,1. Ranges of
72 CPUs are specified with -: 0-2. Default is to report samples on all
73 CPUs.
74
75--asm-raw::
76 Show raw instruction encoding of assembly instructions.
77
78--source::
79 Interleave source code with assembly code. Enabled by default,
80 disable with --no-source.
81
82--symfs=<directory>::
83 Look for files with symbols relative to this directory.
84
85-M::
86--disassembler-style=:: Set disassembler style for objdump.
87
69SEE ALSO 88SEE ALSO
70-------- 89--------
71linkperf:perf-record[1], linkperf:perf-report[1] 90linkperf:perf-record[1], linkperf:perf-report[1]
diff --git a/tools/perf/Documentation/perf-buildid-list.txt b/tools/perf/Documentation/perf-buildid-list.txt
index 5eaac6f26d51..cc22325ffd1b 100644
--- a/tools/perf/Documentation/perf-buildid-list.txt
+++ b/tools/perf/Documentation/perf-buildid-list.txt
@@ -16,6 +16,9 @@ This command displays the buildids found in a perf.data file, so that other
16tools can be used to fetch packages with matching symbol tables for use by 16tools can be used to fetch packages with matching symbol tables for use by
17perf report. 17perf report.
18 18
19It can also be used to show the build id of the running kernel or in an ELF
20file using -i/--input.
21
19OPTIONS 22OPTIONS
20------- 23-------
21-H:: 24-H::
@@ -27,6 +30,9 @@ OPTIONS
27-f:: 30-f::
28--force:: 31--force::
29 Don't do ownership validation. 32 Don't do ownership validation.
33-k::
34--kernel::
35 Show running kernel build id.
30-v:: 36-v::
31--verbose:: 37--verbose::
32 Be more verbose. 38 Be more verbose.
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 02bafce4b341..2780d9ce48bf 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -34,9 +34,11 @@ OPTIONS
34 Specify vmlinux path which has debuginfo (Dwarf binary). 34 Specify vmlinux path which has debuginfo (Dwarf binary).
35 35
36-m:: 36-m::
37--module=MODNAME:: 37--module=MODNAME|PATH::
38 Specify module name in which perf-probe searches probe points 38 Specify module name in which perf-probe searches probe points
39 or lines. 39 or lines. If a path of module file is passed, perf-probe
40 treat it as an offline module (this means you can add a probe on
41 a module which has not been loaded yet).
40 42
41-s:: 43-s::
42--source=PATH:: 44--source=PATH::
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 8ba03d6e5398..212f24d672e1 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -80,15 +80,24 @@ OPTIONS
80--dump-raw-trace:: 80--dump-raw-trace::
81 Dump raw trace in ASCII. 81 Dump raw trace in ASCII.
82 82
83-g [type,min]:: 83-g [type,min,order]::
84--call-graph:: 84--call-graph::
85 Display call chains using type and min percent threshold. 85 Display call chains using type, min percent threshold and order.
86 type can be either: 86 type can be either:
87 - flat: single column, linear exposure of call chains. 87 - flat: single column, linear exposure of call chains.
88 - graph: use a graph tree, displaying absolute overhead rates. 88 - graph: use a graph tree, displaying absolute overhead rates.
89 - fractal: like graph, but displays relative rates. Each branch of 89 - fractal: like graph, but displays relative rates. Each branch of
90 the tree is considered as a new profiled object. + 90 the tree is considered as a new profiled object. +
91 Default: fractal,0.5. 91
92 order can be either:
93 - callee: callee based call graph.
94 - caller: inverted caller based call graph.
95
96 Default: fractal,0.5,callee.
97
98-G::
99--inverted::
100 alias for inverted caller based call graph.
92 101
93--pretty=<key>:: 102--pretty=<key>::
94 Pretty printing style. key: normal, raw 103 Pretty printing style. key: normal, raw
@@ -119,6 +128,30 @@ OPTIONS
119--symfs=<directory>:: 128--symfs=<directory>::
120 Look for files with symbols relative to this directory. 129 Look for files with symbols relative to this directory.
121 130
131-c::
132--cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can
133 be provided as a comma-separated list with no space: 0,1. Ranges of
134 CPUs are specified with -: 0-2. Default is to report samples on all
135 CPUs.
136
137-M::
138--disassembler-style=:: Set disassembler style for objdump.
139
140--source::
141 Interleave source code with assembly code. Enabled by default,
142 disable with --no-source.
143
144--asm-raw::
145 Show raw instruction encoding of assembly instructions.
146
147--show-total-period:: Show a column with the sum of periods.
148
149-I::
150--show-info::
151 Display extended information about the perf.data file. This adds
152 information which may be very large and thus may clutter the display.
153 It currently includes: cpu and numa topology of the host system.
154
122SEE ALSO 155SEE ALSO
123-------- 156--------
124linkperf:perf-stat[1] 157linkperf:perf-stat[1], linkperf:perf-annotate[1]
diff --git a/tools/perf/Documentation/perf-sched.txt b/tools/perf/Documentation/perf-sched.txt
index 46822d5fde1c..5b212b57f70b 100644
--- a/tools/perf/Documentation/perf-sched.txt
+++ b/tools/perf/Documentation/perf-sched.txt
@@ -8,7 +8,7 @@ perf-sched - Tool to trace/measure scheduler properties (latencies)
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf sched' {record|latency|map|replay|trace} 11'perf sched' {record|latency|map|replay|script}
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
@@ -20,8 +20,8 @@ There are five variants of perf sched:
20 'perf sched latency' to report the per task scheduling latencies 20 'perf sched latency' to report the per task scheduling latencies
21 and other scheduling properties of the workload. 21 and other scheduling properties of the workload.
22 22
23 'perf sched trace' to see a detailed trace of the workload that 23 'perf sched script' to see a detailed trace of the workload that
24 was recorded. 24 was recorded (aliased to 'perf script' for now).
25 25
26 'perf sched replay' to simulate the workload that was recorded 26 'perf sched replay' to simulate the workload that was recorded
27 via perf sched record. (this is done by starting up mockup threads 27 via perf sched record. (this is done by starting up mockup threads
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt
index 86c87e214b11..dec87ecb530e 100644
--- a/tools/perf/Documentation/perf-script.txt
+++ b/tools/perf/Documentation/perf-script.txt
@@ -115,10 +115,10 @@ OPTIONS
115-f:: 115-f::
116--fields:: 116--fields::
117 Comma separated list of fields to print. Options are: 117 Comma separated list of fields to print. Options are:
118 comm, tid, pid, time, cpu, event, trace, sym. Field 118 comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr.
119 list can be prepended with the type, trace, sw or hw, 119 Field list can be prepended with the type, trace, sw or hw,
120 to indicate to which event type the field list applies. 120 to indicate to which event type the field list applies.
121 e.g., -f sw:comm,tid,time,sym and -f trace:time,cpu,trace 121 e.g., -f sw:comm,tid,time,ip,sym and -f trace:time,cpu,trace
122 122
123 perf script -f <fields> 123 perf script -f <fields>
124 124
@@ -132,17 +132,17 @@ OPTIONS
132 The arguments are processed in the order received. A later usage can 132 The arguments are processed in the order received. A later usage can
133 reset a prior request. e.g.: 133 reset a prior request. e.g.:
134 134
135 -f trace: -f comm,tid,time,sym 135 -f trace: -f comm,tid,time,ip,sym
136 136
137 The first -f suppresses trace events (field list is ""), but then the 137 The first -f suppresses trace events (field list is ""), but then the
138 second invocation sets the fields to comm,tid,time,sym. In this case a 138 second invocation sets the fields to comm,tid,time,ip,sym. In this case a
139 warning is given to the user: 139 warning is given to the user:
140 140
141 "Overriding previous field request for all events." 141 "Overriding previous field request for all events."
142 142
143 Alternativey, consider the order: 143 Alternativey, consider the order:
144 144
145 -f comm,tid,time,sym -f trace: 145 -f comm,tid,time,ip,sym -f trace:
146 146
147 The first -f sets the fields for all events and the second -f 147 The first -f sets the fields for all events and the second -f
148 suppresses trace events. The user is given a warning message about 148 suppresses trace events. The user is given a warning message about
@@ -182,6 +182,19 @@ OPTIONS
182--hide-call-graph:: 182--hide-call-graph::
183 When printing symbols do not display call chain. 183 When printing symbols do not display call chain.
184 184
185-c::
186--cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can
187 be provided as a comma-separated list with no space: 0,1. Ranges of
188 CPUs are specified with -: 0-2. Default is to report samples on all
189 CPUs.
190
191-I::
192--show-info::
193 Display extended information about the perf.data file. This adds
194 information which may be very large and thus may clutter the display.
195 It currently includes: cpu and numa topology of the host system.
196 It can only be used with the perf script report mode.
197
185SEE ALSO 198SEE ALSO
186-------- 199--------
187linkperf:perf-record[1], linkperf:perf-script-perl[1], 200linkperf:perf-record[1], linkperf:perf-script-perl[1],
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index 918cc38ee6d1..8966b9ab2014 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -94,6 +94,22 @@ an empty cgroup (monitor all the time) using, e.g., -G foo,,bar. Cgroups must ha
94corresponding events, i.e., they always refer to events defined earlier on the command 94corresponding events, i.e., they always refer to events defined earlier on the command
95line. 95line.
96 96
97-o file::
98--output file::
99Print the output into the designated file.
100
101--append::
102Append to the output file designated with the -o option. Ignored if -o is not specified.
103
104--log-fd::
105
106Log output to fd, instead of stderr. Complementary to --output, and mutually exclusive
107with it. --append may be used here. Examples:
108 3>results perf stat --log-fd 3 -- $cmd
109 3>>results perf stat --log-fd 3 --append -- $cmd
110
111
112
97EXAMPLES 113EXAMPLES
98-------- 114--------
99 115
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index f6eb1cdafb77..b1a5bbbfebef 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -106,6 +106,51 @@ Default is to monitor all CPUS.
106--zero:: 106--zero::
107 Zero history across display updates. 107 Zero history across display updates.
108 108
109-s::
110--sort::
111 Sort by key(s): pid, comm, dso, symbol, parent
112
113-n::
114--show-nr-samples::
115 Show a column with the number of samples.
116
117--show-total-period::
118 Show a column with the sum of periods.
119
120--dsos::
121 Only consider symbols in these dsos.
122
123--comms::
124 Only consider symbols in these comms.
125
126--symbols::
127 Only consider these symbols.
128
129-M::
130--disassembler-style=:: Set disassembler style for objdump.
131
132--source::
133 Interleave source code with assembly code. Enabled by default,
134 disable with --no-source.
135
136--asm-raw::
137 Show raw instruction encoding of assembly instructions.
138
139-G [type,min,order]::
140--call-graph::
141 Display call chains using type, min percent threshold and order.
142 type can be either:
143 - flat: single column, linear exposure of call chains.
144 - graph: use a graph tree, displaying absolute overhead rates.
145 - fractal: like graph, but displays relative rates. Each branch of
146 the tree is considered as a new profiled object.
147
148 order can be either:
149 - callee: callee based call graph.
150 - caller: inverted caller based call graph.
151
152 Default: fractal,0.5,callee.
153
109INTERACTIVE PROMPTING KEYS 154INTERACTIVE PROMPTING KEYS
110-------------------------- 155--------------------------
111 156
@@ -130,9 +175,6 @@ INTERACTIVE PROMPTING KEYS
130[S]:: 175[S]::
131 Stop annotation, return to full profile display. 176 Stop annotation, return to full profile display.
132 177
133[w]::
134 Toggle between weighted sum and individual count[E]r profile.
135
136[z]:: 178[z]::
137 Toggle event count zeroing across display updates. 179 Toggle event count zeroing across display updates.
138 180
diff --git a/tools/perf/Documentation/perfconfig.example b/tools/perf/Documentation/perfconfig.example
new file mode 100644
index 000000000000..d1448668f4d4
--- /dev/null
+++ b/tools/perf/Documentation/perfconfig.example
@@ -0,0 +1,20 @@
1[colors]
2
3 # These were the old defaults
4 top = red, lightgray
5 medium = green, lightgray
6 normal = black, lightgray
7 selected = lightgray, magenta
8 code = blue, lightgray
9
10[tui]
11
12 # Defaults if linked with libslang
13 report = on
14 annotate = on
15 top = on
16
17[buildid]
18
19 # Default, disable using /dev/null
20 dir = /root/.debug
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 940257b5774e..b98e3075646b 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -30,6 +30,8 @@ endif
30# Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds. 30# Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds.
31# 31#
32# Define NO_DWARF if you do not want debug-info analysis feature at all. 32# Define NO_DWARF if you do not want debug-info analysis feature at all.
33#
34# Define WERROR=0 to disable treating any warnings as errors.
33 35
34$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE 36$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
35 @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT) 37 @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT)
@@ -52,7 +54,10 @@ ifeq ($(ARCH),i386)
52endif 54endif
53ifeq ($(ARCH),x86_64) 55ifeq ($(ARCH),x86_64)
54 ARCH := x86 56 ARCH := x86
55 IS_X86_64 := $(shell echo __x86_64__ | ${CC} -E -xc - | tail -n 1) 57 IS_X86_64 := 0
58 ifeq (, $(findstring m32,$(EXTRA_CFLAGS)))
59 IS_X86_64 := $(shell echo __x86_64__ | ${CC} -E -xc - | tail -n 1)
60 endif
56 ifeq (${IS_X86_64}, 1) 61 ifeq (${IS_X86_64}, 1)
57 RAW_ARCH := x86_64 62 RAW_ARCH := x86_64
58 ARCH_CFLAGS := -DARCH_X86_64 63 ARCH_CFLAGS := -DARCH_X86_64
@@ -60,6 +65,11 @@ ifeq ($(ARCH),x86_64)
60 endif 65 endif
61endif 66endif
62 67
68# Treat warnings as errors unless directed not to
69ifneq ($(WERROR),0)
70 CFLAGS_WERROR := -Werror
71endif
72
63# 73#
64# Include saner warnings here, which can catch bugs: 74# Include saner warnings here, which can catch bugs:
65# 75#
@@ -92,7 +102,7 @@ ifndef PERF_DEBUG
92 CFLAGS_OPTIMIZE = -O6 102 CFLAGS_OPTIMIZE = -O6
93endif 103endif
94 104
95CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 -Werror $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) 105CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS)
96EXTLIBS = -lpthread -lrt -lelf -lm 106EXTLIBS = -lpthread -lrt -lelf -lm
97ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 107ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
98ALL_LDFLAGS = $(LDFLAGS) 108ALL_LDFLAGS = $(LDFLAGS)
@@ -178,9 +188,9 @@ strip-libs = $(filter-out -l%,$(1))
178 188
179$(OUTPUT)python/perf.so: $(PYRF_OBJS) 189$(OUTPUT)python/perf.so: $(PYRF_OBJS)
180 $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \ 190 $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \
181 --quiet build_ext \ 191 --quiet build_ext; \
182 --build-lib='$(OUTPUT)python' \ 192 mkdir -p $(OUTPUT)python && \
183 --build-temp='$(OUTPUT)python/temp' 193 cp $(PYTHON_EXTBUILD_LIB)perf.so $(OUTPUT)python/
184# 194#
185# No Perl scripts right now: 195# No Perl scripts right now:
186# 196#
@@ -279,6 +289,7 @@ LIB_H += util/thread.h
279LIB_H += util/thread_map.h 289LIB_H += util/thread_map.h
280LIB_H += util/trace-event.h 290LIB_H += util/trace-event.h
281LIB_H += util/probe-finder.h 291LIB_H += util/probe-finder.h
292LIB_H += util/dwarf-aux.h
282LIB_H += util/probe-event.h 293LIB_H += util/probe-event.h
283LIB_H += util/pstack.h 294LIB_H += util/pstack.h
284LIB_H += util/cpumap.h 295LIB_H += util/cpumap.h
@@ -435,6 +446,7 @@ else
435 BASIC_CFLAGS += -DDWARF_SUPPORT 446 BASIC_CFLAGS += -DDWARF_SUPPORT
436 EXTLIBS += -lelf -ldw 447 EXTLIBS += -lelf -ldw
437 LIB_OBJS += $(OUTPUT)util/probe-finder.o 448 LIB_OBJS += $(OUTPUT)util/probe-finder.o
449 LIB_OBJS += $(OUTPUT)util/dwarf-aux.o
438endif # PERF_HAVE_DWARF_REGS 450endif # PERF_HAVE_DWARF_REGS
439endif # NO_DWARF 451endif # NO_DWARF
440 452
@@ -454,13 +466,13 @@ else
454 LIB_OBJS += $(OUTPUT)util/ui/browsers/annotate.o 466 LIB_OBJS += $(OUTPUT)util/ui/browsers/annotate.o
455 LIB_OBJS += $(OUTPUT)util/ui/browsers/hists.o 467 LIB_OBJS += $(OUTPUT)util/ui/browsers/hists.o
456 LIB_OBJS += $(OUTPUT)util/ui/browsers/map.o 468 LIB_OBJS += $(OUTPUT)util/ui/browsers/map.o
457 LIB_OBJS += $(OUTPUT)util/ui/browsers/top.o
458 LIB_OBJS += $(OUTPUT)util/ui/helpline.o 469 LIB_OBJS += $(OUTPUT)util/ui/helpline.o
459 LIB_OBJS += $(OUTPUT)util/ui/progress.o 470 LIB_OBJS += $(OUTPUT)util/ui/progress.o
460 LIB_OBJS += $(OUTPUT)util/ui/util.o 471 LIB_OBJS += $(OUTPUT)util/ui/util.o
461 LIB_H += util/ui/browser.h 472 LIB_H += util/ui/browser.h
462 LIB_H += util/ui/browsers/map.h 473 LIB_H += util/ui/browsers/map.h
463 LIB_H += util/ui/helpline.h 474 LIB_H += util/ui/helpline.h
475 LIB_H += util/ui/keysyms.h
464 LIB_H += util/ui/libslang.h 476 LIB_H += util/ui/libslang.h
465 LIB_H += util/ui/progress.h 477 LIB_H += util/ui/progress.h
466 LIB_H += util/ui/util.h 478 LIB_H += util/ui/util.h
@@ -504,9 +516,13 @@ else
504 516
505 PYTHON_WORD := $(call shell-wordify,$(PYTHON)) 517 PYTHON_WORD := $(call shell-wordify,$(PYTHON))
506 518
507 python-clean := $(PYTHON_WORD) util/setup.py clean \ 519 # python extension build directories
508 --build-lib='$(OUTPUT)python' \ 520 PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/
509 --build-temp='$(OUTPUT)python/temp' 521 PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/
522 PYTHON_EXTBUILD_TMP := $(PYTHON_EXTBUILD)tmp/
523 export PYTHON_EXTBUILD_LIB PYTHON_EXTBUILD_TMP
524
525 python-clean := rm -rf $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so
510 526
511 ifdef NO_LIBPYTHON 527 ifdef NO_LIBPYTHON
512 $(call disable-python) 528 $(call disable-python)
@@ -713,9 +729,6 @@ $(OUTPUT)util/ui/browser.o: util/ui/browser.c $(OUTPUT)PERF-CFLAGS
713$(OUTPUT)util/ui/browsers/annotate.o: util/ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS 729$(OUTPUT)util/ui/browsers/annotate.o: util/ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS
714 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 730 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
715 731
716$(OUTPUT)util/ui/browsers/top.o: util/ui/browsers/top.c $(OUTPUT)PERF-CFLAGS
717 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
718
719$(OUTPUT)util/ui/browsers/hists.o: util/ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS 732$(OUTPUT)util/ui/browsers/hists.o: util/ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS
720 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 733 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
721 734
@@ -863,6 +876,9 @@ install: all
863 $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python' 876 $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python'
864 $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin' 877 $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
865 878
879install-python_ext:
880 $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)'
881
866install-doc: 882install-doc:
867 $(MAKE) -C Documentation install 883 $(MAKE) -C Documentation install
868 884
@@ -890,7 +906,7 @@ quick-install-html:
890### Cleaning rules 906### Cleaning rules
891 907
892clean: 908clean:
893 $(RM) $(OUTPUT){*.o,*/*.o,*/*/*.o,*/*/*/*.o,$(LIB_FILE),perf-archive} 909 $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS)
894 $(RM) $(ALL_PROGRAMS) perf 910 $(RM) $(ALL_PROGRAMS) perf
895 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* 911 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope*
896 $(MAKE) -C Documentation/ clean 912 $(MAKE) -C Documentation/ clean
diff --git a/tools/perf/arch/arm/util/dwarf-regs.c b/tools/perf/arch/arm/util/dwarf-regs.c
index fff6450c8c99..e8d5c551c69c 100644
--- a/tools/perf/arch/arm/util/dwarf-regs.c
+++ b/tools/perf/arch/arm/util/dwarf-regs.c
@@ -8,7 +8,10 @@
8 * published by the Free Software Foundation. 8 * published by the Free Software Foundation.
9 */ 9 */
10 10
11#include <stdlib.h>
12#ifndef __UCLIBC__
11#include <libio.h> 13#include <libio.h>
14#endif
12#include <dwarf-regs.h> 15#include <dwarf-regs.h>
13 16
14struct pt_regs_dwarfnum { 17struct pt_regs_dwarfnum {
diff --git a/tools/perf/arch/powerpc/Makefile b/tools/perf/arch/powerpc/Makefile
index 15130b50dfe3..744e629797be 100644
--- a/tools/perf/arch/powerpc/Makefile
+++ b/tools/perf/arch/powerpc/Makefile
@@ -2,3 +2,4 @@ ifndef NO_DWARF
2PERF_HAVE_DWARF_REGS := 1 2PERF_HAVE_DWARF_REGS := 1
3LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o 3LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
4endif 4endif
5LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
diff --git a/tools/perf/arch/powerpc/util/header.c b/tools/perf/arch/powerpc/util/header.c
new file mode 100644
index 000000000000..eba80c292945
--- /dev/null
+++ b/tools/perf/arch/powerpc/util/header.c
@@ -0,0 +1,36 @@
1#include <sys/types.h>
2#include <unistd.h>
3#include <stdio.h>
4#include <stdlib.h>
5#include <string.h>
6
7#include "../../util/header.h"
8
9#define __stringify_1(x) #x
10#define __stringify(x) __stringify_1(x)
11
12#define mfspr(rn) ({unsigned long rval; \
13 asm volatile("mfspr %0," __stringify(rn) \
14 : "=r" (rval)); rval; })
15
16#define SPRN_PVR 0x11F /* Processor Version Register */
17#define PVR_VER(pvr) (((pvr) >> 16) & 0xFFFF) /* Version field */
18#define PVR_REV(pvr) (((pvr) >> 0) & 0xFFFF) /* Revison field */
19
20int
21get_cpuid(char *buffer, size_t sz)
22{
23 unsigned long pvr;
24 int nb;
25
26 pvr = mfspr(SPRN_PVR);
27
28 nb = snprintf(buffer, sz, "%lu,%lu$", PVR_VER(pvr), PVR_REV(pvr));
29
30 /* look for end marker to ensure the entire data fit */
31 if (strchr(buffer, '$')) {
32 buffer[nb-1] = '\0';
33 return 0;
34 }
35 return -1;
36}
diff --git a/tools/perf/arch/x86/Makefile b/tools/perf/arch/x86/Makefile
index 15130b50dfe3..744e629797be 100644
--- a/tools/perf/arch/x86/Makefile
+++ b/tools/perf/arch/x86/Makefile
@@ -2,3 +2,4 @@ ifndef NO_DWARF
2PERF_HAVE_DWARF_REGS := 1 2PERF_HAVE_DWARF_REGS := 1
3LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o 3LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
4endif 4endif
5LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
diff --git a/tools/perf/arch/x86/util/header.c b/tools/perf/arch/x86/util/header.c
new file mode 100644
index 000000000000..f94006068d2b
--- /dev/null
+++ b/tools/perf/arch/x86/util/header.c
@@ -0,0 +1,59 @@
1#include <sys/types.h>
2#include <unistd.h>
3#include <stdio.h>
4#include <stdlib.h>
5#include <string.h>
6
7#include "../../util/header.h"
8
9static inline void
10cpuid(unsigned int op, unsigned int *a, unsigned int *b, unsigned int *c,
11 unsigned int *d)
12{
13 __asm__ __volatile__ (".byte 0x53\n\tcpuid\n\t"
14 "movl %%ebx, %%esi\n\t.byte 0x5b"
15 : "=a" (*a),
16 "=S" (*b),
17 "=c" (*c),
18 "=d" (*d)
19 : "a" (op));
20}
21
22int
23get_cpuid(char *buffer, size_t sz)
24{
25 unsigned int a, b, c, d, lvl;
26 int family = -1, model = -1, step = -1;
27 int nb;
28 char vendor[16];
29
30 cpuid(0, &lvl, &b, &c, &d);
31 strncpy(&vendor[0], (char *)(&b), 4);
32 strncpy(&vendor[4], (char *)(&d), 4);
33 strncpy(&vendor[8], (char *)(&c), 4);
34 vendor[12] = '\0';
35
36 if (lvl >= 1) {
37 cpuid(1, &a, &b, &c, &d);
38
39 family = (a >> 8) & 0xf; /* bits 11 - 8 */
40 model = (a >> 4) & 0xf; /* Bits 7 - 4 */
41 step = a & 0xf;
42
43 /* extended family */
44 if (family == 0xf)
45 family += (a >> 20) & 0xff;
46
47 /* extended model */
48 if (family >= 0x6)
49 model += ((a >> 16) & 0xf) << 4;
50 }
51 nb = snprintf(buffer, sz, "%s,%u,%u,%u$", vendor, family, model, step);
52
53 /* look for end marker to ensure the entire data fit */
54 if (strchr(buffer, '$')) {
55 buffer[nb-1] = '\0';
56 return 0;
57 }
58 return -1;
59}
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 7b139e1e7e86..46b4c24f338e 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -28,6 +28,8 @@
28#include "util/hist.h" 28#include "util/hist.h"
29#include "util/session.h" 29#include "util/session.h"
30 30
31#include <linux/bitmap.h>
32
31static char const *input_name = "perf.data"; 33static char const *input_name = "perf.data";
32 34
33static bool force, use_tui, use_stdio; 35static bool force, use_tui, use_stdio;
@@ -38,6 +40,9 @@ static bool print_line;
38 40
39static const char *sym_hist_filter; 41static const char *sym_hist_filter;
40 42
43static const char *cpu_list;
44static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
45
41static int perf_evlist__add_sample(struct perf_evlist *evlist, 46static int perf_evlist__add_sample(struct perf_evlist *evlist,
42 struct perf_sample *sample, 47 struct perf_sample *sample,
43 struct perf_evsel *evsel, 48 struct perf_evsel *evsel,
@@ -90,6 +95,9 @@ static int process_sample_event(union perf_event *event,
90 return -1; 95 return -1;
91 } 96 }
92 97
98 if (cpu_list && !test_bit(sample->cpu, cpu_bitmap))
99 return 0;
100
93 if (!al.filtered && 101 if (!al.filtered &&
94 perf_evlist__add_sample(session->evlist, sample, evsel, &al)) { 102 perf_evlist__add_sample(session->evlist, sample, evsel, &al)) {
95 pr_warning("problem incrementing symbol count, " 103 pr_warning("problem incrementing symbol count, "
@@ -106,10 +114,11 @@ static int hist_entry__tty_annotate(struct hist_entry *he, int evidx)
106 print_line, full_paths, 0, 0); 114 print_line, full_paths, 0, 0);
107} 115}
108 116
109static void hists__find_annotations(struct hists *self, int evidx) 117static void hists__find_annotations(struct hists *self, int evidx,
118 int nr_events)
110{ 119{
111 struct rb_node *nd = rb_first(&self->entries), *next; 120 struct rb_node *nd = rb_first(&self->entries), *next;
112 int key = KEY_RIGHT; 121 int key = K_RIGHT;
113 122
114 while (nd) { 123 while (nd) {
115 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); 124 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
@@ -121,7 +130,7 @@ static void hists__find_annotations(struct hists *self, int evidx)
121 notes = symbol__annotation(he->ms.sym); 130 notes = symbol__annotation(he->ms.sym);
122 if (notes->src == NULL) { 131 if (notes->src == NULL) {
123find_next: 132find_next:
124 if (key == KEY_LEFT) 133 if (key == K_LEFT)
125 nd = rb_prev(nd); 134 nd = rb_prev(nd);
126 else 135 else
127 nd = rb_next(nd); 136 nd = rb_next(nd);
@@ -129,12 +138,13 @@ find_next:
129 } 138 }
130 139
131 if (use_browser > 0) { 140 if (use_browser > 0) {
132 key = hist_entry__tui_annotate(he, evidx); 141 key = hist_entry__tui_annotate(he, evidx, nr_events,
142 NULL, NULL, 0);
133 switch (key) { 143 switch (key) {
134 case KEY_RIGHT: 144 case K_RIGHT:
135 next = rb_next(nd); 145 next = rb_next(nd);
136 break; 146 break;
137 case KEY_LEFT: 147 case K_LEFT:
138 next = rb_prev(nd); 148 next = rb_prev(nd);
139 break; 149 break;
140 default: 150 default:
@@ -177,6 +187,12 @@ static int __cmd_annotate(void)
177 if (session == NULL) 187 if (session == NULL)
178 return -ENOMEM; 188 return -ENOMEM;
179 189
190 if (cpu_list) {
191 ret = perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap);
192 if (ret)
193 goto out_delete;
194 }
195
180 ret = perf_session__process_events(session, &event_ops); 196 ret = perf_session__process_events(session, &event_ops);
181 if (ret) 197 if (ret)
182 goto out_delete; 198 goto out_delete;
@@ -201,7 +217,8 @@ static int __cmd_annotate(void)
201 total_nr_samples += nr_samples; 217 total_nr_samples += nr_samples;
202 hists__collapse_resort(hists); 218 hists__collapse_resort(hists);
203 hists__output_resort(hists); 219 hists__output_resort(hists);
204 hists__find_annotations(hists, pos->idx); 220 hists__find_annotations(hists, pos->idx,
221 session->evlist->nr_entries);
205 } 222 }
206 } 223 }
207 224
@@ -252,6 +269,15 @@ static const struct option options[] = {
252 "print matching source lines (may be slow)"), 269 "print matching source lines (may be slow)"),
253 OPT_BOOLEAN('P', "full-paths", &full_paths, 270 OPT_BOOLEAN('P', "full-paths", &full_paths,
254 "Don't shorten the displayed pathnames"), 271 "Don't shorten the displayed pathnames"),
272 OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"),
273 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
274 "Look for files with symbols relative to this directory"),
275 OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src,
276 "Interleave source code with assembly code (default)"),
277 OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw,
278 "Display raw encoding of assembly instructions (default)"),
279 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
280 "Specify disassembler style (e.g. -M intel for intel syntax)"),
255 OPT_END() 281 OPT_END()
256}; 282};
257 283
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index 5af32ae9031e..cb690a65bf02 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -1,7 +1,8 @@
1/* 1/*
2 * builtin-buildid-list.c 2 * builtin-buildid-list.c
3 * 3 *
4 * Builtin buildid-list command: list buildids in perf.data 4 * Builtin buildid-list command: list buildids in perf.data, in the running
5 * kernel and in ELF files.
5 * 6 *
6 * Copyright (C) 2009, Red Hat Inc. 7 * Copyright (C) 2009, Red Hat Inc.
7 * Copyright (C) 2009, Arnaldo Carvalho de Melo <acme@redhat.com> 8 * Copyright (C) 2009, Arnaldo Carvalho de Melo <acme@redhat.com>
@@ -15,8 +16,11 @@
15#include "util/session.h" 16#include "util/session.h"
16#include "util/symbol.h" 17#include "util/symbol.h"
17 18
19#include <libelf.h>
20
18static char const *input_name = "perf.data"; 21static char const *input_name = "perf.data";
19static bool force; 22static bool force;
23static bool show_kernel;
20static bool with_hits; 24static bool with_hits;
21 25
22static const char * const buildid_list_usage[] = { 26static const char * const buildid_list_usage[] = {
@@ -29,12 +33,13 @@ static const struct option options[] = {
29 OPT_STRING('i', "input", &input_name, "file", 33 OPT_STRING('i', "input", &input_name, "file",
30 "input file name"), 34 "input file name"),
31 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), 35 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
36 OPT_BOOLEAN('k', "kernel", &show_kernel, "Show current kernel build id"),
32 OPT_INCR('v', "verbose", &verbose, 37 OPT_INCR('v', "verbose", &verbose,
33 "be more verbose"), 38 "be more verbose"),
34 OPT_END() 39 OPT_END()
35}; 40};
36 41
37static int __cmd_buildid_list(void) 42static int perf_session__list_build_ids(void)
38{ 43{
39 struct perf_session *session; 44 struct perf_session *session;
40 45
@@ -52,6 +57,49 @@ static int __cmd_buildid_list(void)
52 return 0; 57 return 0;
53} 58}
54 59
60static int sysfs__fprintf_build_id(FILE *fp)
61{
62 u8 kallsyms_build_id[BUILD_ID_SIZE];
63 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
64
65 if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
66 sizeof(kallsyms_build_id)) != 0)
67 return -1;
68
69 build_id__sprintf(kallsyms_build_id, sizeof(kallsyms_build_id),
70 sbuild_id);
71 fprintf(fp, "%s\n", sbuild_id);
72 return 0;
73}
74
75static int filename__fprintf_build_id(const char *name, FILE *fp)
76{
77 u8 build_id[BUILD_ID_SIZE];
78 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
79
80 if (filename__read_build_id(name, build_id,
81 sizeof(build_id)) != sizeof(build_id))
82 return 0;
83
84 build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
85 return fprintf(fp, "%s\n", sbuild_id);
86}
87
88static int __cmd_buildid_list(void)
89{
90 if (show_kernel)
91 return sysfs__fprintf_build_id(stdout);
92
93 elf_version(EV_CURRENT);
94 /*
95 * See if this is an ELF file first:
96 */
97 if (filename__fprintf_build_id(input_name, stdout))
98 return 0;
99
100 return perf_session__list_build_ids();
101}
102
55int cmd_buildid_list(int argc, const char **argv, const char *prefix __used) 103int cmd_buildid_list(int argc, const char **argv, const char *prefix __used)
56{ 104{
57 argc = parse_options(argc, argv, options, buildid_list_usage, 0); 105 argc = parse_options(argc, argv, options, buildid_list_usage, 0);
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index e8219990f8b8..b39f3a1ee7dc 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -162,7 +162,7 @@ static int __cmd_diff(void)
162 162
163 hists__match(&session[0]->hists, &session[1]->hists); 163 hists__match(&session[0]->hists, &session[1]->hists);
164 hists__fprintf(&session[1]->hists, &session[0]->hists, 164 hists__fprintf(&session[1]->hists, &session[0]->hists,
165 show_displacement, stdout); 165 show_displacement, true, 0, 0, stdout);
166out_delete: 166out_delete:
167 for (i = 0; i < 2; ++i) 167 for (i = 0; i < 2; ++i)
168 perf_session__delete(session[i]); 168 perf_session__delete(session[i]);
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index 9ac05aafd9b2..899080ace267 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -942,10 +942,10 @@ static const char *record_args[] = {
942 "-f", 942 "-f",
943 "-m", "1024", 943 "-m", "1024",
944 "-c", "1", 944 "-c", "1",
945 "-e", "lock:lock_acquire:r", 945 "-e", "lock:lock_acquire",
946 "-e", "lock:lock_acquired:r", 946 "-e", "lock:lock_acquired",
947 "-e", "lock:lock_contended:r", 947 "-e", "lock:lock_contended",
948 "-e", "lock:lock_release:r", 948 "-e", "lock:lock_release",
949}; 949};
950 950
951static int __cmd_record(int argc, const char **argv) 951static int __cmd_record(int argc, const char **argv)
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 2c0e64d0b4aa..710ae3d0a489 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -134,10 +134,18 @@ static int opt_show_lines(const struct option *opt __used,
134{ 134{
135 int ret = 0; 135 int ret = 0;
136 136
137 if (str) 137 if (!str)
138 ret = parse_line_range_desc(str, &params.line_range); 138 return 0;
139 INIT_LIST_HEAD(&params.line_range.line_list); 139
140 if (params.show_lines) {
141 pr_warning("Warning: more than one --line options are"
142 " detected. Only the first one is valid.\n");
143 return 0;
144 }
145
140 params.show_lines = true; 146 params.show_lines = true;
147 ret = parse_line_range_desc(str, &params.line_range);
148 INIT_LIST_HEAD(&params.line_range.line_list);
141 149
142 return ret; 150 return ret;
143} 151}
@@ -242,7 +250,8 @@ static const struct option options[] = {
242 OPT_STRING('s', "source", &symbol_conf.source_prefix, 250 OPT_STRING('s', "source", &symbol_conf.source_prefix,
243 "directory", "path to kernel source"), 251 "directory", "path to kernel source"),
244 OPT_STRING('m', "module", &params.target_module, 252 OPT_STRING('m', "module", &params.target_module,
245 "modname", "target module name"), 253 "modname|path",
254 "target module name (for online) or path (for offline)"),
246#endif 255#endif
247 OPT__DRY_RUN(&probe_event_dry_run), 256 OPT__DRY_RUN(&probe_event_dry_run),
248 OPT_INTEGER('\0', "max-probes", &params.max_probe_points, 257 OPT_INTEGER('\0', "max-probes", &params.max_probe_points,
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 8e2c85798185..6ab58cc99d53 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -30,8 +30,6 @@
30#include <sched.h> 30#include <sched.h>
31#include <sys/mman.h> 31#include <sys/mman.h>
32 32
33#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
34
35enum write_mode_t { 33enum write_mode_t {
36 WRITE_FORCE, 34 WRITE_FORCE,
37 WRITE_APPEND 35 WRITE_APPEND
@@ -47,7 +45,7 @@ static int freq = 1000;
47static int output; 45static int output;
48static int pipe_output = 0; 46static int pipe_output = 0;
49static const char *output_name = NULL; 47static const char *output_name = NULL;
50static int group = 0; 48static bool group = false;
51static int realtime_prio = 0; 49static int realtime_prio = 0;
52static bool nodelay = false; 50static bool nodelay = false;
53static bool raw_samples = false; 51static bool raw_samples = false;
@@ -75,6 +73,7 @@ static off_t post_processing_offset;
75 73
76static struct perf_session *session; 74static struct perf_session *session;
77static const char *cpu_list; 75static const char *cpu_list;
76static const char *progname;
78 77
79static void advance_output(size_t size) 78static void advance_output(size_t size)
80{ 79{
@@ -139,17 +138,29 @@ static void mmap_read(struct perf_mmap *md)
139 138
140static volatile int done = 0; 139static volatile int done = 0;
141static volatile int signr = -1; 140static volatile int signr = -1;
141static volatile int child_finished = 0;
142 142
143static void sig_handler(int sig) 143static void sig_handler(int sig)
144{ 144{
145 if (sig == SIGCHLD)
146 child_finished = 1;
147
145 done = 1; 148 done = 1;
146 signr = sig; 149 signr = sig;
147} 150}
148 151
149static void sig_atexit(void) 152static void sig_atexit(void)
150{ 153{
151 if (child_pid > 0) 154 int status;
152 kill(child_pid, SIGTERM); 155
156 if (child_pid > 0) {
157 if (!child_finished)
158 kill(child_pid, SIGTERM);
159
160 wait(&status);
161 if (WIFSIGNALED(status))
162 psignal(WTERMSIG(status), progname);
163 }
153 164
154 if (signr == -1 || signr == SIGUSR1) 165 if (signr == -1 || signr == SIGUSR1)
155 return; 166 return;
@@ -163,6 +174,7 @@ static void config_attr(struct perf_evsel *evsel, struct perf_evlist *evlist)
163 struct perf_event_attr *attr = &evsel->attr; 174 struct perf_event_attr *attr = &evsel->attr;
164 int track = !evsel->idx; /* only the first counter needs these */ 175 int track = !evsel->idx; /* only the first counter needs these */
165 176
177 attr->disabled = 1;
166 attr->inherit = !no_inherit; 178 attr->inherit = !no_inherit;
167 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | 179 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
168 PERF_FORMAT_TOTAL_TIME_RUNNING | 180 PERF_FORMAT_TOTAL_TIME_RUNNING |
@@ -250,13 +262,16 @@ static bool perf_evlist__equal(struct perf_evlist *evlist,
250 262
251static void open_counters(struct perf_evlist *evlist) 263static void open_counters(struct perf_evlist *evlist)
252{ 264{
253 struct perf_evsel *pos; 265 struct perf_evsel *pos, *first;
254 266
255 if (evlist->cpus->map[0] < 0) 267 if (evlist->cpus->map[0] < 0)
256 no_inherit = true; 268 no_inherit = true;
257 269
270 first = list_entry(evlist->entries.next, struct perf_evsel, node);
271
258 list_for_each_entry(pos, &evlist->entries, node) { 272 list_for_each_entry(pos, &evlist->entries, node) {
259 struct perf_event_attr *attr = &pos->attr; 273 struct perf_event_attr *attr = &pos->attr;
274 struct xyarray *group_fd = NULL;
260 /* 275 /*
261 * Check if parse_single_tracepoint_event has already asked for 276 * Check if parse_single_tracepoint_event has already asked for
262 * PERF_SAMPLE_TIME. 277 * PERF_SAMPLE_TIME.
@@ -271,15 +286,19 @@ static void open_counters(struct perf_evlist *evlist)
271 */ 286 */
272 bool time_needed = attr->sample_type & PERF_SAMPLE_TIME; 287 bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
273 288
289 if (group && pos != first)
290 group_fd = first->fd;
291
274 config_attr(pos, evlist); 292 config_attr(pos, evlist);
275retry_sample_id: 293retry_sample_id:
276 attr->sample_id_all = sample_id_all_avail ? 1 : 0; 294 attr->sample_id_all = sample_id_all_avail ? 1 : 0;
277try_again: 295try_again:
278 if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group) < 0) { 296 if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group,
297 group_fd) < 0) {
279 int err = errno; 298 int err = errno;
280 299
281 if (err == EPERM || err == EACCES) { 300 if (err == EPERM || err == EACCES) {
282 ui__warning_paranoid(); 301 ui__error_paranoid();
283 exit(EXIT_FAILURE); 302 exit(EXIT_FAILURE);
284 } else if (err == ENODEV && cpu_list) { 303 } else if (err == ENODEV && cpu_list) {
285 die("No such device - did you specify" 304 die("No such device - did you specify"
@@ -438,7 +457,6 @@ static void mmap_read_all(void)
438 457
439static int __cmd_record(int argc, const char **argv) 458static int __cmd_record(int argc, const char **argv)
440{ 459{
441 int i;
442 struct stat st; 460 struct stat st;
443 int flags; 461 int flags;
444 int err; 462 int err;
@@ -448,6 +466,8 @@ static int __cmd_record(int argc, const char **argv)
448 char buf; 466 char buf;
449 struct machine *machine; 467 struct machine *machine;
450 468
469 progname = argv[0];
470
451 page_size = sysconf(_SC_PAGE_SIZE); 471 page_size = sysconf(_SC_PAGE_SIZE);
452 472
453 atexit(sig_atexit); 473 atexit(sig_atexit);
@@ -516,6 +536,19 @@ static int __cmd_record(int argc, const char **argv)
516 if (have_tracepoints(&evsel_list->entries)) 536 if (have_tracepoints(&evsel_list->entries))
517 perf_header__set_feat(&session->header, HEADER_TRACE_INFO); 537 perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
518 538
539 perf_header__set_feat(&session->header, HEADER_HOSTNAME);
540 perf_header__set_feat(&session->header, HEADER_OSRELEASE);
541 perf_header__set_feat(&session->header, HEADER_ARCH);
542 perf_header__set_feat(&session->header, HEADER_CPUDESC);
543 perf_header__set_feat(&session->header, HEADER_NRCPUS);
544 perf_header__set_feat(&session->header, HEADER_EVENT_DESC);
545 perf_header__set_feat(&session->header, HEADER_CMDLINE);
546 perf_header__set_feat(&session->header, HEADER_VERSION);
547 perf_header__set_feat(&session->header, HEADER_CPU_TOPOLOGY);
548 perf_header__set_feat(&session->header, HEADER_TOTAL_MEM);
549 perf_header__set_feat(&session->header, HEADER_NUMA_TOPOLOGY);
550 perf_header__set_feat(&session->header, HEADER_CPUID);
551
519 /* 512 kiB: default amount of unprivileged mlocked memory */ 552 /* 512 kiB: default amount of unprivileged mlocked memory */
520 if (mmap_pages == UINT_MAX) 553 if (mmap_pages == UINT_MAX)
521 mmap_pages = (512 * 1024) / page_size; 554 mmap_pages = (512 * 1024) / page_size;
@@ -674,6 +707,8 @@ static int __cmd_record(int argc, const char **argv)
674 } 707 }
675 } 708 }
676 709
710 perf_evlist__enable(evsel_list);
711
677 /* 712 /*
678 * Let the child rip 713 * Let the child rip
679 */ 714 */
@@ -682,7 +717,6 @@ static int __cmd_record(int argc, const char **argv)
682 717
683 for (;;) { 718 for (;;) {
684 int hits = samples; 719 int hits = samples;
685 int thread;
686 720
687 mmap_read_all(); 721 mmap_read_all();
688 722
@@ -693,19 +727,8 @@ static int __cmd_record(int argc, const char **argv)
693 waking++; 727 waking++;
694 } 728 }
695 729
696 if (done) { 730 if (done)
697 for (i = 0; i < evsel_list->cpus->nr; i++) { 731 perf_evlist__disable(evsel_list);
698 struct perf_evsel *pos;
699
700 list_for_each_entry(pos, &evsel_list->entries, node) {
701 for (thread = 0;
702 thread < evsel_list->threads->nr;
703 thread++)
704 ioctl(FD(pos, i, thread),
705 PERF_EVENT_IOC_DISABLE);
706 }
707 }
708 }
709 } 732 }
710 733
711 if (quiet || signr == SIGUSR1) 734 if (quiet || signr == SIGUSR1)
@@ -740,7 +763,7 @@ static bool force, append_file;
740const struct option record_options[] = { 763const struct option record_options[] = {
741 OPT_CALLBACK('e', "event", &evsel_list, "event", 764 OPT_CALLBACK('e', "event", &evsel_list, "event",
742 "event selector. use 'perf list' to list available events", 765 "event selector. use 'perf list' to list available events",
743 parse_events), 766 parse_events_option),
744 OPT_CALLBACK(0, "filter", &evsel_list, "filter", 767 OPT_CALLBACK(0, "filter", &evsel_list, "filter",
745 "event filter", parse_filter), 768 "event filter", parse_filter),
746 OPT_INTEGER('p', "pid", &target_pid, 769 OPT_INTEGER('p', "pid", &target_pid,
@@ -768,6 +791,8 @@ const struct option record_options[] = {
768 "child tasks do not inherit counters"), 791 "child tasks do not inherit counters"),
769 OPT_UINTEGER('F', "freq", &user_freq, "profile at this frequency"), 792 OPT_UINTEGER('F', "freq", &user_freq, "profile at this frequency"),
770 OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"), 793 OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"),
794 OPT_BOOLEAN(0, "group", &group,
795 "put the counters into a counter group"),
771 OPT_BOOLEAN('g', "call-graph", &call_graph, 796 OPT_BOOLEAN('g', "call-graph", &call_graph,
772 "do call-graph (stack chain/backtrace) recording"), 797 "do call-graph (stack chain/backtrace) recording"),
773 OPT_INCR('v', "verbose", &verbose, 798 OPT_INCR('v', "verbose", &verbose,
@@ -795,6 +820,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
795 int err = -ENOMEM; 820 int err = -ENOMEM;
796 struct perf_evsel *pos; 821 struct perf_evsel *pos;
797 822
823 perf_header__set_cmdline(argc, argv);
824
798 evsel_list = perf_evlist__new(NULL, NULL); 825 evsel_list = perf_evlist__new(NULL, NULL);
799 if (evsel_list == NULL) 826 if (evsel_list == NULL)
800 return -ENOMEM; 827 return -ENOMEM;
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 287a173523a7..4d7c8340c326 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -33,11 +33,14 @@
33#include "util/sort.h" 33#include "util/sort.h"
34#include "util/hist.h" 34#include "util/hist.h"
35 35
36#include <linux/bitmap.h>
37
36static char const *input_name = "perf.data"; 38static char const *input_name = "perf.data";
37 39
38static bool force, use_tui, use_stdio; 40static bool force, use_tui, use_stdio;
39static bool hide_unresolved; 41static bool hide_unresolved;
40static bool dont_use_callchains; 42static bool dont_use_callchains;
43static bool show_full_info;
41 44
42static bool show_threads; 45static bool show_threads;
43static struct perf_read_values show_threads_values; 46static struct perf_read_values show_threads_values;
@@ -45,9 +48,13 @@ static struct perf_read_values show_threads_values;
45static const char default_pretty_printing_style[] = "normal"; 48static const char default_pretty_printing_style[] = "normal";
46static const char *pretty_printing_style = default_pretty_printing_style; 49static const char *pretty_printing_style = default_pretty_printing_style;
47 50
48static char callchain_default_opt[] = "fractal,0.5"; 51static char callchain_default_opt[] = "fractal,0.5,callee";
52static bool inverted_callchain;
49static symbol_filter_t annotate_init; 53static symbol_filter_t annotate_init;
50 54
55static const char *cpu_list;
56static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
57
51static int perf_session__add_hist_entry(struct perf_session *session, 58static int perf_session__add_hist_entry(struct perf_session *session,
52 struct addr_location *al, 59 struct addr_location *al,
53 struct perf_sample *sample, 60 struct perf_sample *sample,
@@ -116,6 +123,9 @@ static int process_sample_event(union perf_event *event,
116 if (al.filtered || (hide_unresolved && al.sym == NULL)) 123 if (al.filtered || (hide_unresolved && al.sym == NULL))
117 return 0; 124 return 0;
118 125
126 if (cpu_list && !test_bit(sample->cpu, cpu_bitmap))
127 return 0;
128
119 if (al.map != NULL) 129 if (al.map != NULL)
120 al.map->dso->hit = 1; 130 al.map->dso->hit = 1;
121 131
@@ -153,23 +163,22 @@ static int perf_session__setup_sample_type(struct perf_session *self)
153{ 163{
154 if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) { 164 if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) {
155 if (sort__has_parent) { 165 if (sort__has_parent) {
156 fprintf(stderr, "selected --sort parent, but no" 166 ui__warning("Selected --sort parent, but no "
157 " callchain data. Did you call" 167 "callchain data. Did you call "
158 " perf record without -g?\n"); 168 "'perf record' without -g?\n");
159 return -EINVAL; 169 return -EINVAL;
160 } 170 }
161 if (symbol_conf.use_callchain) { 171 if (symbol_conf.use_callchain) {
162 fprintf(stderr, "selected -g but no callchain data." 172 ui__warning("Selected -g but no callchain data. Did "
163 " Did you call perf record without" 173 "you call 'perf record' without -g?\n");
164 " -g?\n");
165 return -1; 174 return -1;
166 } 175 }
167 } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE && 176 } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE &&
168 !symbol_conf.use_callchain) { 177 !symbol_conf.use_callchain) {
169 symbol_conf.use_callchain = true; 178 symbol_conf.use_callchain = true;
170 if (callchain_register_param(&callchain_param) < 0) { 179 if (callchain_register_param(&callchain_param) < 0) {
171 fprintf(stderr, "Can't register callchain" 180 ui__warning("Can't register callchain "
172 " params\n"); 181 "params.\n");
173 return -EINVAL; 182 return -EINVAL;
174 } 183 }
175 } 184 }
@@ -221,13 +230,10 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
221 230
222 list_for_each_entry(pos, &evlist->entries, node) { 231 list_for_each_entry(pos, &evlist->entries, node) {
223 struct hists *hists = &pos->hists; 232 struct hists *hists = &pos->hists;
224 const char *evname = NULL; 233 const char *evname = event_name(pos);
225
226 if (rb_first(&hists->entries) != rb_last(&hists->entries))
227 evname = event_name(pos);
228 234
229 hists__fprintf_nr_sample_events(hists, evname, stdout); 235 hists__fprintf_nr_sample_events(hists, evname, stdout);
230 hists__fprintf(hists, NULL, false, stdout); 236 hists__fprintf(hists, NULL, false, true, 0, 0, stdout);
231 fprintf(stdout, "\n\n"); 237 fprintf(stdout, "\n\n");
232 } 238 }
233 239
@@ -262,6 +268,15 @@ static int __cmd_report(void)
262 if (session == NULL) 268 if (session == NULL)
263 return -ENOMEM; 269 return -ENOMEM;
264 270
271 if (cpu_list) {
272 ret = perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap);
273 if (ret)
274 goto out_delete;
275 }
276
277 if (use_browser <= 0)
278 perf_session__fprintf_info(session, stdout, show_full_info);
279
265 if (show_threads) 280 if (show_threads)
266 perf_read_values_init(&show_threads_values); 281 perf_read_values_init(&show_threads_values);
267 282
@@ -316,9 +331,10 @@ static int __cmd_report(void)
316 goto out_delete; 331 goto out_delete;
317 } 332 }
318 333
319 if (use_browser > 0) 334 if (use_browser > 0) {
320 perf_evlist__tui_browse_hists(session->evlist, help); 335 perf_evlist__tui_browse_hists(session->evlist, help,
321 else 336 NULL, NULL, 0);
337 } else
322 perf_evlist__tty_browse_hists(session->evlist, help); 338 perf_evlist__tty_browse_hists(session->evlist, help);
323 339
324out_delete: 340out_delete:
@@ -386,13 +402,29 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
386 if (!tok) 402 if (!tok)
387 goto setup; 403 goto setup;
388 404
389 tok2 = strtok(NULL, ",");
390 callchain_param.min_percent = strtod(tok, &endptr); 405 callchain_param.min_percent = strtod(tok, &endptr);
391 if (tok == endptr) 406 if (tok == endptr)
392 return -1; 407 return -1;
393 408
394 if (tok2) 409 /* get the print limit */
410 tok2 = strtok(NULL, ",");
411 if (!tok2)
412 goto setup;
413
414 if (tok2[0] != 'c') {
395 callchain_param.print_limit = strtod(tok2, &endptr); 415 callchain_param.print_limit = strtod(tok2, &endptr);
416 tok2 = strtok(NULL, ",");
417 if (!tok2)
418 goto setup;
419 }
420
421 /* get the call chain order */
422 if (!strcmp(tok2, "caller"))
423 callchain_param.order = ORDER_CALLER;
424 else if (!strcmp(tok2, "callee"))
425 callchain_param.order = ORDER_CALLEE;
426 else
427 return -1;
396setup: 428setup:
397 if (callchain_register_param(&callchain_param) < 0) { 429 if (callchain_register_param(&callchain_param) < 0) {
398 fprintf(stderr, "Can't register callchain params\n"); 430 fprintf(stderr, "Can't register callchain params\n");
@@ -436,9 +468,10 @@ static const struct option options[] = {
436 "regex filter to identify parent, see: '--sort parent'"), 468 "regex filter to identify parent, see: '--sort parent'"),
437 OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other, 469 OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other,
438 "Only display entries with parent-match"), 470 "Only display entries with parent-match"),
439 OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent", 471 OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent, call_order",
440 "Display callchains using output_type (graph, flat, fractal, or none) and min percent threshold. " 472 "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold and callchain order. "
441 "Default: fractal,0.5", &parse_callchain_opt, callchain_default_opt), 473 "Default: fractal,0.5,callee", &parse_callchain_opt, callchain_default_opt),
474 OPT_BOOLEAN('G', "inverted", &inverted_callchain, "alias for inverted call graph"),
442 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", 475 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
443 "only consider symbols in these dsos"), 476 "only consider symbols in these dsos"),
444 OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]", 477 OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
@@ -455,6 +488,17 @@ static const struct option options[] = {
455 "Only display entries resolved to a symbol"), 488 "Only display entries resolved to a symbol"),
456 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", 489 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
457 "Look for files with symbols relative to this directory"), 490 "Look for files with symbols relative to this directory"),
491 OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"),
492 OPT_BOOLEAN('I', "show-info", &show_full_info,
493 "Display extended information about perf.data file"),
494 OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src,
495 "Interleave source code with assembly code (default)"),
496 OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw,
497 "Display raw encoding of assembly instructions (default)"),
498 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
499 "Specify disassembler style (e.g. -M intel for intel syntax)"),
500 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
501 "Show a column with the sum of periods"),
458 OPT_END() 502 OPT_END()
459}; 503};
460 504
@@ -467,6 +511,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
467 else if (use_tui) 511 else if (use_tui)
468 use_browser = 1; 512 use_browser = 1;
469 513
514 if (inverted_callchain)
515 callchain_param.order = ORDER_CALLER;
516
470 if (strcmp(input_name, "-") != 0) 517 if (strcmp(input_name, "-") != 0)
471 setup_browser(true); 518 setup_browser(true);
472 else 519 else
@@ -504,7 +551,14 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
504 if (parent_pattern != default_parent_pattern) { 551 if (parent_pattern != default_parent_pattern) {
505 if (sort_dimension__add("parent") < 0) 552 if (sort_dimension__add("parent") < 0)
506 return -1; 553 return -1;
507 sort_parent.elide = 1; 554
555 /*
556 * Only show the parent fields if we explicitly
557 * sort that way. If we only use parent machinery
558 * for filtering, we don't want it.
559 */
560 if (!strstr(sort_order, "parent"))
561 sort_parent.elide = 1;
508 } else 562 } else
509 symbol_conf.exclude_other = false; 563 symbol_conf.exclude_other = false;
510 564
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index dcfe8873c9a1..5177964943e7 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -1637,23 +1637,29 @@ static struct perf_event_ops event_ops = {
1637 .ordered_samples = true, 1637 .ordered_samples = true,
1638}; 1638};
1639 1639
1640static int read_events(void) 1640static void read_events(bool destroy, struct perf_session **psession)
1641{ 1641{
1642 int err = -EINVAL; 1642 int err = -EINVAL;
1643 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 1643 struct perf_session *session = perf_session__new(input_name, O_RDONLY,
1644 0, false, &event_ops); 1644 0, false, &event_ops);
1645 if (session == NULL) 1645 if (session == NULL)
1646 return -ENOMEM; 1646 die("No Memory");
1647 1647
1648 if (perf_session__has_traces(session, "record -R")) { 1648 if (perf_session__has_traces(session, "record -R")) {
1649 err = perf_session__process_events(session, &event_ops); 1649 err = perf_session__process_events(session, &event_ops);
1650 if (err)
1651 die("Failed to process events, error %d", err);
1652
1650 nr_events = session->hists.stats.nr_events[0]; 1653 nr_events = session->hists.stats.nr_events[0];
1651 nr_lost_events = session->hists.stats.total_lost; 1654 nr_lost_events = session->hists.stats.total_lost;
1652 nr_lost_chunks = session->hists.stats.nr_events[PERF_RECORD_LOST]; 1655 nr_lost_chunks = session->hists.stats.nr_events[PERF_RECORD_LOST];
1653 } 1656 }
1654 1657
1655 perf_session__delete(session); 1658 if (destroy)
1656 return err; 1659 perf_session__delete(session);
1660
1661 if (psession)
1662 *psession = session;
1657} 1663}
1658 1664
1659static void print_bad_events(void) 1665static void print_bad_events(void)
@@ -1689,9 +1695,10 @@ static void print_bad_events(void)
1689static void __cmd_lat(void) 1695static void __cmd_lat(void)
1690{ 1696{
1691 struct rb_node *next; 1697 struct rb_node *next;
1698 struct perf_session *session;
1692 1699
1693 setup_pager(); 1700 setup_pager();
1694 read_events(); 1701 read_events(false, &session);
1695 sort_lat(); 1702 sort_lat();
1696 1703
1697 printf("\n ---------------------------------------------------------------------------------------------------------------\n"); 1704 printf("\n ---------------------------------------------------------------------------------------------------------------\n");
@@ -1717,6 +1724,7 @@ static void __cmd_lat(void)
1717 print_bad_events(); 1724 print_bad_events();
1718 printf("\n"); 1725 printf("\n");
1719 1726
1727 perf_session__delete(session);
1720} 1728}
1721 1729
1722static struct trace_sched_handler map_ops = { 1730static struct trace_sched_handler map_ops = {
@@ -1731,7 +1739,7 @@ static void __cmd_map(void)
1731 max_cpu = sysconf(_SC_NPROCESSORS_CONF); 1739 max_cpu = sysconf(_SC_NPROCESSORS_CONF);
1732 1740
1733 setup_pager(); 1741 setup_pager();
1734 read_events(); 1742 read_events(true, NULL);
1735 print_bad_events(); 1743 print_bad_events();
1736} 1744}
1737 1745
@@ -1744,7 +1752,7 @@ static void __cmd_replay(void)
1744 1752
1745 test_calibrations(); 1753 test_calibrations();
1746 1754
1747 read_events(); 1755 read_events(true, NULL);
1748 1756
1749 printf("nr_run_events: %ld\n", nr_run_events); 1757 printf("nr_run_events: %ld\n", nr_run_events);
1750 printf("nr_sleep_events: %ld\n", nr_sleep_events); 1758 printf("nr_sleep_events: %ld\n", nr_sleep_events);
@@ -1769,7 +1777,7 @@ static void __cmd_replay(void)
1769 1777
1770 1778
1771static const char * const sched_usage[] = { 1779static const char * const sched_usage[] = {
1772 "perf sched [<options>] {record|latency|map|replay|trace}", 1780 "perf sched [<options>] {record|latency|map|replay|script}",
1773 NULL 1781 NULL
1774}; 1782};
1775 1783
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 22747de7234b..2f62a2952269 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -13,6 +13,7 @@
13#include "util/util.h" 13#include "util/util.h"
14#include "util/evlist.h" 14#include "util/evlist.h"
15#include "util/evsel.h" 15#include "util/evsel.h"
16#include <linux/bitmap.h>
16 17
17static char const *script_name; 18static char const *script_name;
18static char const *generate_script_lang; 19static char const *generate_script_lang;
@@ -21,6 +22,9 @@ static u64 last_timestamp;
21static u64 nr_unordered; 22static u64 nr_unordered;
22extern const struct option record_options[]; 23extern const struct option record_options[];
23static bool no_callchain; 24static bool no_callchain;
25static bool show_full_info;
26static const char *cpu_list;
27static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
24 28
25enum perf_output_field { 29enum perf_output_field {
26 PERF_OUTPUT_COMM = 1U << 0, 30 PERF_OUTPUT_COMM = 1U << 0,
@@ -30,7 +34,10 @@ enum perf_output_field {
30 PERF_OUTPUT_CPU = 1U << 4, 34 PERF_OUTPUT_CPU = 1U << 4,
31 PERF_OUTPUT_EVNAME = 1U << 5, 35 PERF_OUTPUT_EVNAME = 1U << 5,
32 PERF_OUTPUT_TRACE = 1U << 6, 36 PERF_OUTPUT_TRACE = 1U << 6,
33 PERF_OUTPUT_SYM = 1U << 7, 37 PERF_OUTPUT_IP = 1U << 7,
38 PERF_OUTPUT_SYM = 1U << 8,
39 PERF_OUTPUT_DSO = 1U << 9,
40 PERF_OUTPUT_ADDR = 1U << 10,
34}; 41};
35 42
36struct output_option { 43struct output_option {
@@ -44,7 +51,10 @@ struct output_option {
44 {.str = "cpu", .field = PERF_OUTPUT_CPU}, 51 {.str = "cpu", .field = PERF_OUTPUT_CPU},
45 {.str = "event", .field = PERF_OUTPUT_EVNAME}, 52 {.str = "event", .field = PERF_OUTPUT_EVNAME},
46 {.str = "trace", .field = PERF_OUTPUT_TRACE}, 53 {.str = "trace", .field = PERF_OUTPUT_TRACE},
54 {.str = "ip", .field = PERF_OUTPUT_IP},
47 {.str = "sym", .field = PERF_OUTPUT_SYM}, 55 {.str = "sym", .field = PERF_OUTPUT_SYM},
56 {.str = "dso", .field = PERF_OUTPUT_DSO},
57 {.str = "addr", .field = PERF_OUTPUT_ADDR},
48}; 58};
49 59
50/* default set to maintain compatibility with current format */ 60/* default set to maintain compatibility with current format */
@@ -60,7 +70,8 @@ static struct {
60 70
61 .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | 71 .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
62 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | 72 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
63 PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM, 73 PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
74 PERF_OUTPUT_SYM | PERF_OUTPUT_DSO,
64 75
65 .invalid_fields = PERF_OUTPUT_TRACE, 76 .invalid_fields = PERF_OUTPUT_TRACE,
66 }, 77 },
@@ -70,7 +81,8 @@ static struct {
70 81
71 .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | 82 .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
72 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | 83 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
73 PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM, 84 PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
85 PERF_OUTPUT_SYM | PERF_OUTPUT_DSO,
74 86
75 .invalid_fields = PERF_OUTPUT_TRACE, 87 .invalid_fields = PERF_OUTPUT_TRACE,
76 }, 88 },
@@ -88,7 +100,8 @@ static struct {
88 100
89 .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | 101 .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
90 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | 102 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
91 PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM, 103 PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
104 PERF_OUTPUT_SYM | PERF_OUTPUT_DSO,
92 105
93 .invalid_fields = PERF_OUTPUT_TRACE, 106 .invalid_fields = PERF_OUTPUT_TRACE,
94 }, 107 },
@@ -157,9 +170,9 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
157 !perf_session__has_traces(session, "record -R")) 170 !perf_session__has_traces(session, "record -R"))
158 return -EINVAL; 171 return -EINVAL;
159 172
160 if (PRINT_FIELD(SYM)) { 173 if (PRINT_FIELD(IP)) {
161 if (perf_event_attr__check_stype(attr, PERF_SAMPLE_IP, "IP", 174 if (perf_event_attr__check_stype(attr, PERF_SAMPLE_IP, "IP",
162 PERF_OUTPUT_SYM)) 175 PERF_OUTPUT_IP))
163 return -EINVAL; 176 return -EINVAL;
164 177
165 if (!no_callchain && 178 if (!no_callchain &&
@@ -167,6 +180,24 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
167 symbol_conf.use_callchain = false; 180 symbol_conf.use_callchain = false;
168 } 181 }
169 182
183 if (PRINT_FIELD(ADDR) &&
184 perf_event_attr__check_stype(attr, PERF_SAMPLE_ADDR, "ADDR",
185 PERF_OUTPUT_ADDR))
186 return -EINVAL;
187
188 if (PRINT_FIELD(SYM) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) {
189 pr_err("Display of symbols requested but neither sample IP nor "
190 "sample address\nis selected. Hence, no addresses to convert "
191 "to symbols.\n");
192 return -EINVAL;
193 }
194 if (PRINT_FIELD(DSO) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) {
195 pr_err("Display of DSO requested but neither sample IP nor "
196 "sample address\nis selected. Hence, no addresses to convert "
197 "to DSO.\n");
198 return -EINVAL;
199 }
200
170 if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) && 201 if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) &&
171 perf_event_attr__check_stype(attr, PERF_SAMPLE_TID, "TID", 202 perf_event_attr__check_stype(attr, PERF_SAMPLE_TID, "TID",
172 PERF_OUTPUT_TID|PERF_OUTPUT_PID)) 203 PERF_OUTPUT_TID|PERF_OUTPUT_PID))
@@ -230,7 +261,7 @@ static void print_sample_start(struct perf_sample *sample,
230 if (PRINT_FIELD(COMM)) { 261 if (PRINT_FIELD(COMM)) {
231 if (latency_format) 262 if (latency_format)
232 printf("%8.8s ", thread->comm); 263 printf("%8.8s ", thread->comm);
233 else if (PRINT_FIELD(SYM) && symbol_conf.use_callchain) 264 else if (PRINT_FIELD(IP) && symbol_conf.use_callchain)
234 printf("%s ", thread->comm); 265 printf("%s ", thread->comm);
235 else 266 else
236 printf("%16s ", thread->comm); 267 printf("%16s ", thread->comm);
@@ -271,6 +302,63 @@ static void print_sample_start(struct perf_sample *sample,
271 } 302 }
272} 303}
273 304
305static bool sample_addr_correlates_sym(struct perf_event_attr *attr)
306{
307 if ((attr->type == PERF_TYPE_SOFTWARE) &&
308 ((attr->config == PERF_COUNT_SW_PAGE_FAULTS) ||
309 (attr->config == PERF_COUNT_SW_PAGE_FAULTS_MIN) ||
310 (attr->config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)))
311 return true;
312
313 return false;
314}
315
316static void print_sample_addr(union perf_event *event,
317 struct perf_sample *sample,
318 struct perf_session *session,
319 struct thread *thread,
320 struct perf_event_attr *attr)
321{
322 struct addr_location al;
323 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
324 const char *symname, *dsoname;
325
326 printf("%16" PRIx64, sample->addr);
327
328 if (!sample_addr_correlates_sym(attr))
329 return;
330
331 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION,
332 event->ip.pid, sample->addr, &al);
333 if (!al.map)
334 thread__find_addr_map(thread, session, cpumode, MAP__VARIABLE,
335 event->ip.pid, sample->addr, &al);
336
337 al.cpu = sample->cpu;
338 al.sym = NULL;
339
340 if (al.map)
341 al.sym = map__find_symbol(al.map, al.addr, NULL);
342
343 if (PRINT_FIELD(SYM)) {
344 if (al.sym && al.sym->name)
345 symname = al.sym->name;
346 else
347 symname = "";
348
349 printf(" %16s", symname);
350 }
351
352 if (PRINT_FIELD(DSO)) {
353 if (al.map && al.map->dso && al.map->dso->name)
354 dsoname = al.map->dso->name;
355 else
356 dsoname = "";
357
358 printf(" (%s)", dsoname);
359 }
360}
361
274static void process_event(union perf_event *event __unused, 362static void process_event(union perf_event *event __unused,
275 struct perf_sample *sample, 363 struct perf_sample *sample,
276 struct perf_evsel *evsel, 364 struct perf_evsel *evsel,
@@ -288,12 +376,16 @@ static void process_event(union perf_event *event __unused,
288 print_trace_event(sample->cpu, sample->raw_data, 376 print_trace_event(sample->cpu, sample->raw_data,
289 sample->raw_size); 377 sample->raw_size);
290 378
291 if (PRINT_FIELD(SYM)) { 379 if (PRINT_FIELD(ADDR))
380 print_sample_addr(event, sample, session, thread, attr);
381
382 if (PRINT_FIELD(IP)) {
292 if (!symbol_conf.use_callchain) 383 if (!symbol_conf.use_callchain)
293 printf(" "); 384 printf(" ");
294 else 385 else
295 printf("\n"); 386 printf("\n");
296 perf_session__print_symbols(event, sample, session); 387 perf_session__print_ip(event, sample, session,
388 PRINT_FIELD(SYM), PRINT_FIELD(DSO));
297 } 389 }
298 390
299 printf("\n"); 391 printf("\n");
@@ -365,6 +457,10 @@ static int process_sample_event(union perf_event *event,
365 last_timestamp = sample->time; 457 last_timestamp = sample->time;
366 return 0; 458 return 0;
367 } 459 }
460
461 if (cpu_list && !test_bit(sample->cpu, cpu_bitmap))
462 return 0;
463
368 scripting_ops->process_event(event, sample, evsel, session, thread); 464 scripting_ops->process_event(event, sample, evsel, session, thread);
369 465
370 session->hists.stats.total_period += sample->period; 466 session->hists.stats.total_period += sample->period;
@@ -985,9 +1081,11 @@ static const struct option options[] = {
985 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", 1081 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
986 "Look for files with symbols relative to this directory"), 1082 "Look for files with symbols relative to this directory"),
987 OPT_CALLBACK('f', "fields", NULL, "str", 1083 OPT_CALLBACK('f', "fields", NULL, "str",
988 "comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace,raw. Fields: comm,tid,pid,time,cpu,event,trace,sym", 1084 "comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace,raw. Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,addr",
989 parse_output_fields), 1085 parse_output_fields),
990 1086 OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"),
1087 OPT_BOOLEAN('I', "show-info", &show_full_info,
1088 "display extended information from perf.data file"),
991 OPT_END() 1089 OPT_END()
992}; 1090};
993 1091
@@ -1167,6 +1265,13 @@ int cmd_script(int argc, const char **argv, const char *prefix __used)
1167 if (session == NULL) 1265 if (session == NULL)
1168 return -ENOMEM; 1266 return -ENOMEM;
1169 1267
1268 if (cpu_list) {
1269 if (perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap))
1270 return -1;
1271 }
1272
1273 perf_session__fprintf_info(session, stdout, show_full_info);
1274
1170 if (!no_callchain) 1275 if (!no_callchain)
1171 symbol_conf.use_callchain = true; 1276 symbol_conf.use_callchain = true;
1172 else 1277 else
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index a9f06715e44d..7d98676808d8 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -61,6 +61,8 @@
61#include <locale.h> 61#include <locale.h>
62 62
63#define DEFAULT_SEPARATOR " " 63#define DEFAULT_SEPARATOR " "
64#define CNTR_NOT_SUPPORTED "<not supported>"
65#define CNTR_NOT_COUNTED "<not counted>"
64 66
65static struct perf_event_attr default_attrs[] = { 67static struct perf_event_attr default_attrs[] = {
66 68
@@ -191,6 +193,10 @@ static int big_num_opt = -1;
191static const char *cpu_list; 193static const char *cpu_list;
192static const char *csv_sep = NULL; 194static const char *csv_sep = NULL;
193static bool csv_output = false; 195static bool csv_output = false;
196static bool group = false;
197static const char *output_name = NULL;
198static FILE *output = NULL;
199static int output_fd;
194 200
195static volatile int done = 0; 201static volatile int done = 0;
196 202
@@ -248,8 +254,13 @@ static double avg_stats(struct stats *stats)
248 */ 254 */
249static double stddev_stats(struct stats *stats) 255static double stddev_stats(struct stats *stats)
250{ 256{
251 double variance = stats->M2 / (stats->n - 1); 257 double variance, variance_mean;
252 double variance_mean = variance / stats->n; 258
259 if (!stats->n)
260 return 0.0;
261
262 variance = stats->M2 / (stats->n - 1);
263 variance_mean = variance / stats->n;
253 264
254 return sqrt(variance_mean); 265 return sqrt(variance_mean);
255} 266}
@@ -267,9 +278,14 @@ struct stats runtime_itlb_cache_stats[MAX_NR_CPUS];
267struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS]; 278struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS];
268struct stats walltime_nsecs_stats; 279struct stats walltime_nsecs_stats;
269 280
270static int create_perf_stat_counter(struct perf_evsel *evsel) 281static int create_perf_stat_counter(struct perf_evsel *evsel,
282 struct perf_evsel *first)
271{ 283{
272 struct perf_event_attr *attr = &evsel->attr; 284 struct perf_event_attr *attr = &evsel->attr;
285 struct xyarray *group_fd = NULL;
286
287 if (group && evsel != first)
288 group_fd = first->fd;
273 289
274 if (scale) 290 if (scale)
275 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | 291 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
@@ -278,14 +294,15 @@ static int create_perf_stat_counter(struct perf_evsel *evsel)
278 attr->inherit = !no_inherit; 294 attr->inherit = !no_inherit;
279 295
280 if (system_wide) 296 if (system_wide)
281 return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, false); 297 return perf_evsel__open_per_cpu(evsel, evsel_list->cpus,
282 298 group, group_fd);
283 if (target_pid == -1 && target_tid == -1) { 299 if (target_pid == -1 && target_tid == -1) {
284 attr->disabled = 1; 300 attr->disabled = 1;
285 attr->enable_on_exec = 1; 301 attr->enable_on_exec = 1;
286 } 302 }
287 303
288 return perf_evsel__open_per_thread(evsel, evsel_list->threads, false); 304 return perf_evsel__open_per_thread(evsel, evsel_list->threads,
305 group, group_fd);
289} 306}
290 307
291/* 308/*
@@ -349,7 +366,7 @@ static int read_counter_aggr(struct perf_evsel *counter)
349 update_stats(&ps->res_stats[i], count[i]); 366 update_stats(&ps->res_stats[i], count[i]);
350 367
351 if (verbose) { 368 if (verbose) {
352 fprintf(stderr, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n", 369 fprintf(output, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
353 event_name(counter), count[0], count[1], count[2]); 370 event_name(counter), count[0], count[1], count[2]);
354 } 371 }
355 372
@@ -385,7 +402,7 @@ static int read_counter(struct perf_evsel *counter)
385static int run_perf_stat(int argc __used, const char **argv) 402static int run_perf_stat(int argc __used, const char **argv)
386{ 403{
387 unsigned long long t0, t1; 404 unsigned long long t0, t1;
388 struct perf_evsel *counter; 405 struct perf_evsel *counter, *first;
389 int status = 0; 406 int status = 0;
390 int child_ready_pipe[2], go_pipe[2]; 407 int child_ready_pipe[2], go_pipe[2];
391 const bool forks = (argc > 0); 408 const bool forks = (argc > 0);
@@ -442,12 +459,15 @@ static int run_perf_stat(int argc __used, const char **argv)
442 close(child_ready_pipe[0]); 459 close(child_ready_pipe[0]);
443 } 460 }
444 461
462 first = list_entry(evsel_list->entries.next, struct perf_evsel, node);
463
445 list_for_each_entry(counter, &evsel_list->entries, node) { 464 list_for_each_entry(counter, &evsel_list->entries, node) {
446 if (create_perf_stat_counter(counter) < 0) { 465 if (create_perf_stat_counter(counter, first) < 0) {
447 if (errno == EINVAL || errno == ENOSYS || errno == ENOENT) { 466 if (errno == EINVAL || errno == ENOSYS || errno == ENOENT) {
448 if (verbose) 467 if (verbose)
449 ui__warning("%s event is not supported by the kernel.\n", 468 ui__warning("%s event is not supported by the kernel.\n",
450 event_name(counter)); 469 event_name(counter));
470 counter->supported = false;
451 continue; 471 continue;
452 } 472 }
453 473
@@ -466,6 +486,7 @@ static int run_perf_stat(int argc __used, const char **argv)
466 die("Not all events could be opened.\n"); 486 die("Not all events could be opened.\n");
467 return -1; 487 return -1;
468 } 488 }
489 counter->supported = true;
469 } 490 }
470 491
471 if (perf_evlist__set_filters(evsel_list)) { 492 if (perf_evlist__set_filters(evsel_list)) {
@@ -482,6 +503,8 @@ static int run_perf_stat(int argc __used, const char **argv)
482 if (forks) { 503 if (forks) {
483 close(go_pipe[1]); 504 close(go_pipe[1]);
484 wait(&status); 505 wait(&status);
506 if (WIFSIGNALED(status))
507 psignal(WTERMSIG(status), argv[0]);
485 } else { 508 } else {
486 while(!done) sleep(1); 509 while(!done) sleep(1);
487 } 510 }
@@ -513,7 +536,10 @@ static void print_noise_pct(double total, double avg)
513 if (avg) 536 if (avg)
514 pct = 100.0*total/avg; 537 pct = 100.0*total/avg;
515 538
516 fprintf(stderr, " ( +-%6.2f%% )", pct); 539 if (csv_output)
540 fprintf(output, "%s%.2f%%", csv_sep, pct);
541 else if (pct)
542 fprintf(output, " ( +-%6.2f%% )", pct);
517} 543}
518 544
519static void print_noise(struct perf_evsel *evsel, double avg) 545static void print_noise(struct perf_evsel *evsel, double avg)
@@ -538,16 +564,17 @@ static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg)
538 csv_output ? 0 : -4, 564 csv_output ? 0 : -4,
539 evsel_list->cpus->map[cpu], csv_sep); 565 evsel_list->cpus->map[cpu], csv_sep);
540 566
541 fprintf(stderr, fmt, cpustr, msecs, csv_sep, event_name(evsel)); 567 fprintf(output, fmt, cpustr, msecs, csv_sep, event_name(evsel));
542 568
543 if (evsel->cgrp) 569 if (evsel->cgrp)
544 fprintf(stderr, "%s%s", csv_sep, evsel->cgrp->name); 570 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
545 571
546 if (csv_output) 572 if (csv_output)
547 return; 573 return;
548 574
549 if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK)) 575 if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK))
550 fprintf(stderr, " # %8.3f CPUs utilized ", avg / avg_stats(&walltime_nsecs_stats)); 576 fprintf(output, " # %8.3f CPUs utilized ",
577 avg / avg_stats(&walltime_nsecs_stats));
551} 578}
552 579
553static void print_stalled_cycles_frontend(int cpu, struct perf_evsel *evsel __used, double avg) 580static void print_stalled_cycles_frontend(int cpu, struct perf_evsel *evsel __used, double avg)
@@ -568,9 +595,9 @@ static void print_stalled_cycles_frontend(int cpu, struct perf_evsel *evsel __us
568 else if (ratio > 10.0) 595 else if (ratio > 10.0)
569 color = PERF_COLOR_YELLOW; 596 color = PERF_COLOR_YELLOW;
570 597
571 fprintf(stderr, " # "); 598 fprintf(output, " # ");
572 color_fprintf(stderr, color, "%6.2f%%", ratio); 599 color_fprintf(output, color, "%6.2f%%", ratio);
573 fprintf(stderr, " frontend cycles idle "); 600 fprintf(output, " frontend cycles idle ");
574} 601}
575 602
576static void print_stalled_cycles_backend(int cpu, struct perf_evsel *evsel __used, double avg) 603static void print_stalled_cycles_backend(int cpu, struct perf_evsel *evsel __used, double avg)
@@ -591,9 +618,9 @@ static void print_stalled_cycles_backend(int cpu, struct perf_evsel *evsel __use
591 else if (ratio > 20.0) 618 else if (ratio > 20.0)
592 color = PERF_COLOR_YELLOW; 619 color = PERF_COLOR_YELLOW;
593 620
594 fprintf(stderr, " # "); 621 fprintf(output, " # ");
595 color_fprintf(stderr, color, "%6.2f%%", ratio); 622 color_fprintf(output, color, "%6.2f%%", ratio);
596 fprintf(stderr, " backend cycles idle "); 623 fprintf(output, " backend cycles idle ");
597} 624}
598 625
599static void print_branch_misses(int cpu, struct perf_evsel *evsel __used, double avg) 626static void print_branch_misses(int cpu, struct perf_evsel *evsel __used, double avg)
@@ -614,9 +641,9 @@ static void print_branch_misses(int cpu, struct perf_evsel *evsel __used, double
614 else if (ratio > 5.0) 641 else if (ratio > 5.0)
615 color = PERF_COLOR_YELLOW; 642 color = PERF_COLOR_YELLOW;
616 643
617 fprintf(stderr, " # "); 644 fprintf(output, " # ");
618 color_fprintf(stderr, color, "%6.2f%%", ratio); 645 color_fprintf(output, color, "%6.2f%%", ratio);
619 fprintf(stderr, " of all branches "); 646 fprintf(output, " of all branches ");
620} 647}
621 648
622static void print_l1_dcache_misses(int cpu, struct perf_evsel *evsel __used, double avg) 649static void print_l1_dcache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
@@ -637,9 +664,9 @@ static void print_l1_dcache_misses(int cpu, struct perf_evsel *evsel __used, dou
637 else if (ratio > 5.0) 664 else if (ratio > 5.0)
638 color = PERF_COLOR_YELLOW; 665 color = PERF_COLOR_YELLOW;
639 666
640 fprintf(stderr, " # "); 667 fprintf(output, " # ");
641 color_fprintf(stderr, color, "%6.2f%%", ratio); 668 color_fprintf(output, color, "%6.2f%%", ratio);
642 fprintf(stderr, " of all L1-dcache hits "); 669 fprintf(output, " of all L1-dcache hits ");
643} 670}
644 671
645static void print_l1_icache_misses(int cpu, struct perf_evsel *evsel __used, double avg) 672static void print_l1_icache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
@@ -660,9 +687,9 @@ static void print_l1_icache_misses(int cpu, struct perf_evsel *evsel __used, dou
660 else if (ratio > 5.0) 687 else if (ratio > 5.0)
661 color = PERF_COLOR_YELLOW; 688 color = PERF_COLOR_YELLOW;
662 689
663 fprintf(stderr, " # "); 690 fprintf(output, " # ");
664 color_fprintf(stderr, color, "%6.2f%%", ratio); 691 color_fprintf(output, color, "%6.2f%%", ratio);
665 fprintf(stderr, " of all L1-icache hits "); 692 fprintf(output, " of all L1-icache hits ");
666} 693}
667 694
668static void print_dtlb_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg) 695static void print_dtlb_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
@@ -683,9 +710,9 @@ static void print_dtlb_cache_misses(int cpu, struct perf_evsel *evsel __used, do
683 else if (ratio > 5.0) 710 else if (ratio > 5.0)
684 color = PERF_COLOR_YELLOW; 711 color = PERF_COLOR_YELLOW;
685 712
686 fprintf(stderr, " # "); 713 fprintf(output, " # ");
687 color_fprintf(stderr, color, "%6.2f%%", ratio); 714 color_fprintf(output, color, "%6.2f%%", ratio);
688 fprintf(stderr, " of all dTLB cache hits "); 715 fprintf(output, " of all dTLB cache hits ");
689} 716}
690 717
691static void print_itlb_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg) 718static void print_itlb_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
@@ -706,9 +733,9 @@ static void print_itlb_cache_misses(int cpu, struct perf_evsel *evsel __used, do
706 else if (ratio > 5.0) 733 else if (ratio > 5.0)
707 color = PERF_COLOR_YELLOW; 734 color = PERF_COLOR_YELLOW;
708 735
709 fprintf(stderr, " # "); 736 fprintf(output, " # ");
710 color_fprintf(stderr, color, "%6.2f%%", ratio); 737 color_fprintf(output, color, "%6.2f%%", ratio);
711 fprintf(stderr, " of all iTLB cache hits "); 738 fprintf(output, " of all iTLB cache hits ");
712} 739}
713 740
714static void print_ll_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg) 741static void print_ll_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
@@ -729,9 +756,9 @@ static void print_ll_cache_misses(int cpu, struct perf_evsel *evsel __used, doub
729 else if (ratio > 5.0) 756 else if (ratio > 5.0)
730 color = PERF_COLOR_YELLOW; 757 color = PERF_COLOR_YELLOW;
731 758
732 fprintf(stderr, " # "); 759 fprintf(output, " # ");
733 color_fprintf(stderr, color, "%6.2f%%", ratio); 760 color_fprintf(output, color, "%6.2f%%", ratio);
734 fprintf(stderr, " of all LL-cache hits "); 761 fprintf(output, " of all LL-cache hits ");
735} 762}
736 763
737static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) 764static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
@@ -754,10 +781,10 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
754 else 781 else
755 cpu = 0; 782 cpu = 0;
756 783
757 fprintf(stderr, fmt, cpustr, avg, csv_sep, event_name(evsel)); 784 fprintf(output, fmt, cpustr, avg, csv_sep, event_name(evsel));
758 785
759 if (evsel->cgrp) 786 if (evsel->cgrp)
760 fprintf(stderr, "%s%s", csv_sep, evsel->cgrp->name); 787 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
761 788
762 if (csv_output) 789 if (csv_output)
763 return; 790 return;
@@ -768,14 +795,14 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
768 if (total) 795 if (total)
769 ratio = avg / total; 796 ratio = avg / total;
770 797
771 fprintf(stderr, " # %5.2f insns per cycle ", ratio); 798 fprintf(output, " # %5.2f insns per cycle ", ratio);
772 799
773 total = avg_stats(&runtime_stalled_cycles_front_stats[cpu]); 800 total = avg_stats(&runtime_stalled_cycles_front_stats[cpu]);
774 total = max(total, avg_stats(&runtime_stalled_cycles_back_stats[cpu])); 801 total = max(total, avg_stats(&runtime_stalled_cycles_back_stats[cpu]));
775 802
776 if (total && avg) { 803 if (total && avg) {
777 ratio = total / avg; 804 ratio = total / avg;
778 fprintf(stderr, "\n # %5.2f stalled cycles per insn", ratio); 805 fprintf(output, "\n # %5.2f stalled cycles per insn", ratio);
779 } 806 }
780 807
781 } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) && 808 } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) &&
@@ -823,7 +850,7 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
823 if (total) 850 if (total)
824 ratio = avg * 100 / total; 851 ratio = avg * 100 / total;
825 852
826 fprintf(stderr, " # %8.3f %% of all cache refs ", ratio); 853 fprintf(output, " # %8.3f %% of all cache refs ", ratio);
827 854
828 } else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_FRONTEND)) { 855 } else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_FRONTEND)) {
829 print_stalled_cycles_frontend(cpu, evsel, avg); 856 print_stalled_cycles_frontend(cpu, evsel, avg);
@@ -835,16 +862,16 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
835 if (total) 862 if (total)
836 ratio = 1.0 * avg / total; 863 ratio = 1.0 * avg / total;
837 864
838 fprintf(stderr, " # %8.3f GHz ", ratio); 865 fprintf(output, " # %8.3f GHz ", ratio);
839 } else if (runtime_nsecs_stats[cpu].n != 0) { 866 } else if (runtime_nsecs_stats[cpu].n != 0) {
840 total = avg_stats(&runtime_nsecs_stats[cpu]); 867 total = avg_stats(&runtime_nsecs_stats[cpu]);
841 868
842 if (total) 869 if (total)
843 ratio = 1000.0 * avg / total; 870 ratio = 1000.0 * avg / total;
844 871
845 fprintf(stderr, " # %8.3f M/sec ", ratio); 872 fprintf(output, " # %8.3f M/sec ", ratio);
846 } else { 873 } else {
847 fprintf(stderr, " "); 874 fprintf(output, " ");
848 } 875 }
849} 876}
850 877
@@ -859,17 +886,17 @@ static void print_counter_aggr(struct perf_evsel *counter)
859 int scaled = counter->counts->scaled; 886 int scaled = counter->counts->scaled;
860 887
861 if (scaled == -1) { 888 if (scaled == -1) {
862 fprintf(stderr, "%*s%s%*s", 889 fprintf(output, "%*s%s%*s",
863 csv_output ? 0 : 18, 890 csv_output ? 0 : 18,
864 "<not counted>", 891 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
865 csv_sep, 892 csv_sep,
866 csv_output ? 0 : -24, 893 csv_output ? 0 : -24,
867 event_name(counter)); 894 event_name(counter));
868 895
869 if (counter->cgrp) 896 if (counter->cgrp)
870 fprintf(stderr, "%s%s", csv_sep, counter->cgrp->name); 897 fprintf(output, "%s%s", csv_sep, counter->cgrp->name);
871 898
872 fputc('\n', stderr); 899 fputc('\n', output);
873 return; 900 return;
874 } 901 }
875 902
@@ -878,22 +905,22 @@ static void print_counter_aggr(struct perf_evsel *counter)
878 else 905 else
879 abs_printout(-1, counter, avg); 906 abs_printout(-1, counter, avg);
880 907
908 print_noise(counter, avg);
909
881 if (csv_output) { 910 if (csv_output) {
882 fputc('\n', stderr); 911 fputc('\n', output);
883 return; 912 return;
884 } 913 }
885 914
886 print_noise(counter, avg);
887
888 if (scaled) { 915 if (scaled) {
889 double avg_enabled, avg_running; 916 double avg_enabled, avg_running;
890 917
891 avg_enabled = avg_stats(&ps->res_stats[1]); 918 avg_enabled = avg_stats(&ps->res_stats[1]);
892 avg_running = avg_stats(&ps->res_stats[2]); 919 avg_running = avg_stats(&ps->res_stats[2]);
893 920
894 fprintf(stderr, " [%5.2f%%]", 100 * avg_running / avg_enabled); 921 fprintf(output, " [%5.2f%%]", 100 * avg_running / avg_enabled);
895 } 922 }
896 fprintf(stderr, "\n"); 923 fprintf(output, "\n");
897} 924}
898 925
899/* 926/*
@@ -910,18 +937,20 @@ static void print_counter(struct perf_evsel *counter)
910 ena = counter->counts->cpu[cpu].ena; 937 ena = counter->counts->cpu[cpu].ena;
911 run = counter->counts->cpu[cpu].run; 938 run = counter->counts->cpu[cpu].run;
912 if (run == 0 || ena == 0) { 939 if (run == 0 || ena == 0) {
913 fprintf(stderr, "CPU%*d%s%*s%s%*s", 940 fprintf(output, "CPU%*d%s%*s%s%*s",
914 csv_output ? 0 : -4, 941 csv_output ? 0 : -4,
915 evsel_list->cpus->map[cpu], csv_sep, 942 evsel_list->cpus->map[cpu], csv_sep,
916 csv_output ? 0 : 18, 943 csv_output ? 0 : 18,
917 "<not counted>", csv_sep, 944 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
945 csv_sep,
918 csv_output ? 0 : -24, 946 csv_output ? 0 : -24,
919 event_name(counter)); 947 event_name(counter));
920 948
921 if (counter->cgrp) 949 if (counter->cgrp)
922 fprintf(stderr, "%s%s", csv_sep, counter->cgrp->name); 950 fprintf(output, "%s%s",
951 csv_sep, counter->cgrp->name);
923 952
924 fputc('\n', stderr); 953 fputc('\n', output);
925 continue; 954 continue;
926 } 955 }
927 956
@@ -934,9 +963,10 @@ static void print_counter(struct perf_evsel *counter)
934 print_noise(counter, 1.0); 963 print_noise(counter, 1.0);
935 964
936 if (run != ena) 965 if (run != ena)
937 fprintf(stderr, " (%.2f%%)", 100.0 * run / ena); 966 fprintf(output, " (%.2f%%)",
967 100.0 * run / ena);
938 } 968 }
939 fputc('\n', stderr); 969 fputc('\n', output);
940 } 970 }
941} 971}
942 972
@@ -948,21 +978,21 @@ static void print_stat(int argc, const char **argv)
948 fflush(stdout); 978 fflush(stdout);
949 979
950 if (!csv_output) { 980 if (!csv_output) {
951 fprintf(stderr, "\n"); 981 fprintf(output, "\n");
952 fprintf(stderr, " Performance counter stats for "); 982 fprintf(output, " Performance counter stats for ");
953 if(target_pid == -1 && target_tid == -1) { 983 if(target_pid == -1 && target_tid == -1) {
954 fprintf(stderr, "\'%s", argv[0]); 984 fprintf(output, "\'%s", argv[0]);
955 for (i = 1; i < argc; i++) 985 for (i = 1; i < argc; i++)
956 fprintf(stderr, " %s", argv[i]); 986 fprintf(output, " %s", argv[i]);
957 } else if (target_pid != -1) 987 } else if (target_pid != -1)
958 fprintf(stderr, "process id \'%d", target_pid); 988 fprintf(output, "process id \'%d", target_pid);
959 else 989 else
960 fprintf(stderr, "thread id \'%d", target_tid); 990 fprintf(output, "thread id \'%d", target_tid);
961 991
962 fprintf(stderr, "\'"); 992 fprintf(output, "\'");
963 if (run_count > 1) 993 if (run_count > 1)
964 fprintf(stderr, " (%d runs)", run_count); 994 fprintf(output, " (%d runs)", run_count);
965 fprintf(stderr, ":\n\n"); 995 fprintf(output, ":\n\n");
966 } 996 }
967 997
968 if (no_aggr) { 998 if (no_aggr) {
@@ -975,15 +1005,15 @@ static void print_stat(int argc, const char **argv)
975 1005
976 if (!csv_output) { 1006 if (!csv_output) {
977 if (!null_run) 1007 if (!null_run)
978 fprintf(stderr, "\n"); 1008 fprintf(output, "\n");
979 fprintf(stderr, " %17.9f seconds time elapsed", 1009 fprintf(output, " %17.9f seconds time elapsed",
980 avg_stats(&walltime_nsecs_stats)/1e9); 1010 avg_stats(&walltime_nsecs_stats)/1e9);
981 if (run_count > 1) { 1011 if (run_count > 1) {
982 fprintf(stderr, " "); 1012 fprintf(output, " ");
983 print_noise_pct(stddev_stats(&walltime_nsecs_stats), 1013 print_noise_pct(stddev_stats(&walltime_nsecs_stats),
984 avg_stats(&walltime_nsecs_stats)); 1014 avg_stats(&walltime_nsecs_stats));
985 } 1015 }
986 fprintf(stderr, "\n\n"); 1016 fprintf(output, "\n\n");
987 } 1017 }
988} 1018}
989 1019
@@ -1021,10 +1051,12 @@ static int stat__set_big_num(const struct option *opt __used,
1021 return 0; 1051 return 0;
1022} 1052}
1023 1053
1054static bool append_file;
1055
1024static const struct option options[] = { 1056static const struct option options[] = {
1025 OPT_CALLBACK('e', "event", &evsel_list, "event", 1057 OPT_CALLBACK('e', "event", &evsel_list, "event",
1026 "event selector. use 'perf list' to list available events", 1058 "event selector. use 'perf list' to list available events",
1027 parse_events), 1059 parse_events_option),
1028 OPT_CALLBACK(0, "filter", &evsel_list, "filter", 1060 OPT_CALLBACK(0, "filter", &evsel_list, "filter",
1029 "event filter", parse_filter), 1061 "event filter", parse_filter),
1030 OPT_BOOLEAN('i', "no-inherit", &no_inherit, 1062 OPT_BOOLEAN('i', "no-inherit", &no_inherit,
@@ -1035,6 +1067,8 @@ static const struct option options[] = {
1035 "stat events on existing thread id"), 1067 "stat events on existing thread id"),
1036 OPT_BOOLEAN('a', "all-cpus", &system_wide, 1068 OPT_BOOLEAN('a', "all-cpus", &system_wide,
1037 "system-wide collection from all CPUs"), 1069 "system-wide collection from all CPUs"),
1070 OPT_BOOLEAN('g', "group", &group,
1071 "put the counters into a counter group"),
1038 OPT_BOOLEAN('c', "scale", &scale, 1072 OPT_BOOLEAN('c', "scale", &scale,
1039 "scale/normalize counters"), 1073 "scale/normalize counters"),
1040 OPT_INCR('v', "verbose", &verbose, 1074 OPT_INCR('v', "verbose", &verbose,
@@ -1059,6 +1093,11 @@ static const struct option options[] = {
1059 OPT_CALLBACK('G', "cgroup", &evsel_list, "name", 1093 OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
1060 "monitor event in cgroup name only", 1094 "monitor event in cgroup name only",
1061 parse_cgroups), 1095 parse_cgroups),
1096 OPT_STRING('o', "output", &output_name, "file",
1097 "output file name"),
1098 OPT_BOOLEAN(0, "append", &append_file, "append to the output file"),
1099 OPT_INTEGER(0, "log-fd", &output_fd,
1100 "log output to fd, instead of stderr"),
1062 OPT_END() 1101 OPT_END()
1063}; 1102};
1064 1103
@@ -1130,6 +1169,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
1130{ 1169{
1131 struct perf_evsel *pos; 1170 struct perf_evsel *pos;
1132 int status = -ENOMEM; 1171 int status = -ENOMEM;
1172 const char *mode;
1133 1173
1134 setlocale(LC_ALL, ""); 1174 setlocale(LC_ALL, "");
1135 1175
@@ -1140,16 +1180,46 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
1140 argc = parse_options(argc, argv, options, stat_usage, 1180 argc = parse_options(argc, argv, options, stat_usage,
1141 PARSE_OPT_STOP_AT_NON_OPTION); 1181 PARSE_OPT_STOP_AT_NON_OPTION);
1142 1182
1143 if (csv_sep) 1183 output = stderr;
1184 if (output_name && strcmp(output_name, "-"))
1185 output = NULL;
1186
1187 if (output_name && output_fd) {
1188 fprintf(stderr, "cannot use both --output and --log-fd\n");
1189 usage_with_options(stat_usage, options);
1190 }
1191 if (!output) {
1192 struct timespec tm;
1193 mode = append_file ? "a" : "w";
1194
1195 output = fopen(output_name, mode);
1196 if (!output) {
1197 perror("failed to create output file");
1198 exit(-1);
1199 }
1200 clock_gettime(CLOCK_REALTIME, &tm);
1201 fprintf(output, "# started on %s\n", ctime(&tm.tv_sec));
1202 } else if (output_fd != 2) {
1203 mode = append_file ? "a" : "w";
1204 output = fdopen(output_fd, mode);
1205 if (!output) {
1206 perror("Failed opening logfd");
1207 return -errno;
1208 }
1209 }
1210
1211 if (csv_sep) {
1144 csv_output = true; 1212 csv_output = true;
1145 else 1213 if (!strcmp(csv_sep, "\\t"))
1214 csv_sep = "\t";
1215 } else
1146 csv_sep = DEFAULT_SEPARATOR; 1216 csv_sep = DEFAULT_SEPARATOR;
1147 1217
1148 /* 1218 /*
1149 * let the spreadsheet do the pretty-printing 1219 * let the spreadsheet do the pretty-printing
1150 */ 1220 */
1151 if (csv_output) { 1221 if (csv_output) {
1152 /* User explicitely passed -B? */ 1222 /* User explicitly passed -B? */
1153 if (big_num_opt == 1) { 1223 if (big_num_opt == 1) {
1154 fprintf(stderr, "-B option not supported with -x\n"); 1224 fprintf(stderr, "-B option not supported with -x\n");
1155 usage_with_options(stat_usage, options); 1225 usage_with_options(stat_usage, options);
@@ -1215,7 +1285,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
1215 status = 0; 1285 status = 0;
1216 for (run_idx = 0; run_idx < run_count; run_idx++) { 1286 for (run_idx = 0; run_idx < run_count; run_idx++) {
1217 if (run_count != 1 && verbose) 1287 if (run_count != 1 && verbose)
1218 fprintf(stderr, "[ perf stat: executing run #%d ... ]\n", run_idx + 1); 1288 fprintf(output, "[ perf stat: executing run #%d ... ]\n",
1289 run_idx + 1);
1219 1290
1220 if (sync_run) 1291 if (sync_run)
1221 sync(); 1292 sync();
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 2da9162262b0..831d1baeac37 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -12,6 +12,7 @@
12#include "util/parse-events.h" 12#include "util/parse-events.h"
13#include "util/symbol.h" 13#include "util/symbol.h"
14#include "util/thread_map.h" 14#include "util/thread_map.h"
15#include "../../include/linux/hw_breakpoint.h"
15 16
16static long page_size; 17static long page_size;
17 18
@@ -245,8 +246,8 @@ static int trace_event__id(const char *evname)
245 int err = -1, fd; 246 int err = -1, fd;
246 247
247 if (asprintf(&filename, 248 if (asprintf(&filename,
248 "/sys/kernel/debug/tracing/events/syscalls/%s/id", 249 "%s/syscalls/%s/id",
249 evname) < 0) 250 debugfs_path, evname) < 0)
250 return -1; 251 return -1;
251 252
252 fd = open(filename, O_RDONLY); 253 fd = open(filename, O_RDONLY);
@@ -290,7 +291,7 @@ static int test__open_syscall_event(void)
290 goto out_thread_map_delete; 291 goto out_thread_map_delete;
291 } 292 }
292 293
293 if (perf_evsel__open_per_thread(evsel, threads, false) < 0) { 294 if (perf_evsel__open_per_thread(evsel, threads, false, NULL) < 0) {
294 pr_debug("failed to open counter: %s, " 295 pr_debug("failed to open counter: %s, "
295 "tweak /proc/sys/kernel/perf_event_paranoid?\n", 296 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
296 strerror(errno)); 297 strerror(errno));
@@ -365,7 +366,7 @@ static int test__open_syscall_event_on_all_cpus(void)
365 goto out_thread_map_delete; 366 goto out_thread_map_delete;
366 } 367 }
367 368
368 if (perf_evsel__open(evsel, cpus, threads, false) < 0) { 369 if (perf_evsel__open(evsel, cpus, threads, false, NULL) < 0) {
369 pr_debug("failed to open counter: %s, " 370 pr_debug("failed to open counter: %s, "
370 "tweak /proc/sys/kernel/perf_event_paranoid?\n", 371 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
371 strerror(errno)); 372 strerror(errno));
@@ -530,7 +531,7 @@ static int test__basic_mmap(void)
530 531
531 perf_evlist__add(evlist, evsels[i]); 532 perf_evlist__add(evlist, evsels[i]);
532 533
533 if (perf_evsel__open(evsels[i], cpus, threads, false) < 0) { 534 if (perf_evsel__open(evsels[i], cpus, threads, false, NULL) < 0) {
534 pr_debug("failed to open counter: %s, " 535 pr_debug("failed to open counter: %s, "
535 "tweak /proc/sys/kernel/perf_event_paranoid?\n", 536 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
536 strerror(errno)); 537 strerror(errno));
@@ -560,7 +561,7 @@ static int test__basic_mmap(void)
560 } 561 }
561 562
562 err = perf_event__parse_sample(event, attr.sample_type, sample_size, 563 err = perf_event__parse_sample(event, attr.sample_type, sample_size,
563 false, &sample); 564 false, &sample, false);
564 if (err) { 565 if (err) {
565 pr_err("Can't parse sample, err = %d\n", err); 566 pr_err("Can't parse sample, err = %d\n", err);
566 goto out_munmap; 567 goto out_munmap;
@@ -600,6 +601,246 @@ out_free_threads:
600#undef nsyscalls 601#undef nsyscalls
601} 602}
602 603
604#define TEST_ASSERT_VAL(text, cond) \
605do { \
606 if (!cond) { \
607 pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
608 return -1; \
609 } \
610} while (0)
611
612static int test__checkevent_tracepoint(struct perf_evlist *evlist)
613{
614 struct perf_evsel *evsel = list_entry(evlist->entries.next,
615 struct perf_evsel, node);
616
617 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
618 TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
619 TEST_ASSERT_VAL("wrong sample_type",
620 (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) ==
621 evsel->attr.sample_type);
622 TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
623 return 0;
624}
625
626static int test__checkevent_tracepoint_multi(struct perf_evlist *evlist)
627{
628 struct perf_evsel *evsel;
629
630 TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1);
631
632 list_for_each_entry(evsel, &evlist->entries, node) {
633 TEST_ASSERT_VAL("wrong type",
634 PERF_TYPE_TRACEPOINT == evsel->attr.type);
635 TEST_ASSERT_VAL("wrong sample_type",
636 (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU)
637 == evsel->attr.sample_type);
638 TEST_ASSERT_VAL("wrong sample_period",
639 1 == evsel->attr.sample_period);
640 }
641 return 0;
642}
643
644static int test__checkevent_raw(struct perf_evlist *evlist)
645{
646 struct perf_evsel *evsel = list_entry(evlist->entries.next,
647 struct perf_evsel, node);
648
649 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
650 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
651 TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
652 return 0;
653}
654
655static int test__checkevent_numeric(struct perf_evlist *evlist)
656{
657 struct perf_evsel *evsel = list_entry(evlist->entries.next,
658 struct perf_evsel, node);
659
660 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
661 TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type);
662 TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
663 return 0;
664}
665
666static int test__checkevent_symbolic_name(struct perf_evlist *evlist)
667{
668 struct perf_evsel *evsel = list_entry(evlist->entries.next,
669 struct perf_evsel, node);
670
671 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
672 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
673 TEST_ASSERT_VAL("wrong config",
674 PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config);
675 return 0;
676}
677
678static int test__checkevent_symbolic_alias(struct perf_evlist *evlist)
679{
680 struct perf_evsel *evsel = list_entry(evlist->entries.next,
681 struct perf_evsel, node);
682
683 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
684 TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->attr.type);
685 TEST_ASSERT_VAL("wrong config",
686 PERF_COUNT_SW_PAGE_FAULTS == evsel->attr.config);
687 return 0;
688}
689
690static int test__checkevent_genhw(struct perf_evlist *evlist)
691{
692 struct perf_evsel *evsel = list_entry(evlist->entries.next,
693 struct perf_evsel, node);
694
695 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
696 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HW_CACHE == evsel->attr.type);
697 TEST_ASSERT_VAL("wrong config", (1 << 16) == evsel->attr.config);
698 return 0;
699}
700
701static int test__checkevent_breakpoint(struct perf_evlist *evlist)
702{
703 struct perf_evsel *evsel = list_entry(evlist->entries.next,
704 struct perf_evsel, node);
705
706 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
707 TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
708 TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
709 TEST_ASSERT_VAL("wrong bp_type", (HW_BREAKPOINT_R | HW_BREAKPOINT_W) ==
710 evsel->attr.bp_type);
711 TEST_ASSERT_VAL("wrong bp_len", HW_BREAKPOINT_LEN_4 ==
712 evsel->attr.bp_len);
713 return 0;
714}
715
716static int test__checkevent_breakpoint_x(struct perf_evlist *evlist)
717{
718 struct perf_evsel *evsel = list_entry(evlist->entries.next,
719 struct perf_evsel, node);
720
721 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
722 TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
723 TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
724 TEST_ASSERT_VAL("wrong bp_type",
725 HW_BREAKPOINT_X == evsel->attr.bp_type);
726 TEST_ASSERT_VAL("wrong bp_len", sizeof(long) == evsel->attr.bp_len);
727 return 0;
728}
729
730static int test__checkevent_breakpoint_r(struct perf_evlist *evlist)
731{
732 struct perf_evsel *evsel = list_entry(evlist->entries.next,
733 struct perf_evsel, node);
734
735 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
736 TEST_ASSERT_VAL("wrong type",
737 PERF_TYPE_BREAKPOINT == evsel->attr.type);
738 TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
739 TEST_ASSERT_VAL("wrong bp_type",
740 HW_BREAKPOINT_R == evsel->attr.bp_type);
741 TEST_ASSERT_VAL("wrong bp_len",
742 HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len);
743 return 0;
744}
745
746static int test__checkevent_breakpoint_w(struct perf_evlist *evlist)
747{
748 struct perf_evsel *evsel = list_entry(evlist->entries.next,
749 struct perf_evsel, node);
750
751 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
752 TEST_ASSERT_VAL("wrong type",
753 PERF_TYPE_BREAKPOINT == evsel->attr.type);
754 TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
755 TEST_ASSERT_VAL("wrong bp_type",
756 HW_BREAKPOINT_W == evsel->attr.bp_type);
757 TEST_ASSERT_VAL("wrong bp_len",
758 HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len);
759 return 0;
760}
761
762static struct test__event_st {
763 const char *name;
764 __u32 type;
765 int (*check)(struct perf_evlist *evlist);
766} test__events[] = {
767 {
768 .name = "syscalls:sys_enter_open",
769 .check = test__checkevent_tracepoint,
770 },
771 {
772 .name = "syscalls:*",
773 .check = test__checkevent_tracepoint_multi,
774 },
775 {
776 .name = "r1",
777 .check = test__checkevent_raw,
778 },
779 {
780 .name = "1:1",
781 .check = test__checkevent_numeric,
782 },
783 {
784 .name = "instructions",
785 .check = test__checkevent_symbolic_name,
786 },
787 {
788 .name = "faults",
789 .check = test__checkevent_symbolic_alias,
790 },
791 {
792 .name = "L1-dcache-load-miss",
793 .check = test__checkevent_genhw,
794 },
795 {
796 .name = "mem:0",
797 .check = test__checkevent_breakpoint,
798 },
799 {
800 .name = "mem:0:x",
801 .check = test__checkevent_breakpoint_x,
802 },
803 {
804 .name = "mem:0:r",
805 .check = test__checkevent_breakpoint_r,
806 },
807 {
808 .name = "mem:0:w",
809 .check = test__checkevent_breakpoint_w,
810 },
811};
812
813#define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st))
814
815static int test__parse_events(void)
816{
817 struct perf_evlist *evlist;
818 u_int i;
819 int ret = 0;
820
821 for (i = 0; i < TEST__EVENTS_CNT; i++) {
822 struct test__event_st *e = &test__events[i];
823
824 evlist = perf_evlist__new(NULL, NULL);
825 if (evlist == NULL)
826 break;
827
828 ret = parse_events(evlist, e->name, 0);
829 if (ret) {
830 pr_debug("failed to parse event '%s', err %d\n",
831 e->name, ret);
832 break;
833 }
834
835 ret = e->check(evlist);
836 if (ret)
837 break;
838
839 perf_evlist__delete(evlist);
840 }
841
842 return ret;
843}
603static struct test { 844static struct test {
604 const char *desc; 845 const char *desc;
605 int (*func)(void); 846 int (*func)(void);
@@ -621,6 +862,10 @@ static struct test {
621 .func = test__basic_mmap, 862 .func = test__basic_mmap,
622 }, 863 },
623 { 864 {
865 .desc = "parse events tests",
866 .func = test__parse_events,
867 },
868 {
624 .func = NULL, 869 .func = NULL,
625 }, 870 },
626}; 871};
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index f2f3f4937aa2..c9cdedb58134 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -5,6 +5,7 @@
5 * any workload, CPU or specific PID. 5 * any workload, CPU or specific PID.
6 * 6 *
7 * Copyright (C) 2008, Red Hat Inc, Ingo Molnar <mingo@redhat.com> 7 * Copyright (C) 2008, Red Hat Inc, Ingo Molnar <mingo@redhat.com>
8 * 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
8 * 9 *
9 * Improvements and fixes by: 10 * Improvements and fixes by:
10 * 11 *
@@ -36,6 +37,7 @@
36#include "util/parse-events.h" 37#include "util/parse-events.h"
37#include "util/cpumap.h" 38#include "util/cpumap.h"
38#include "util/xyarray.h" 39#include "util/xyarray.h"
40#include "util/sort.h"
39 41
40#include "util/debug.h" 42#include "util/debug.h"
41 43
@@ -65,12 +67,8 @@
65static struct perf_top top = { 67static struct perf_top top = {
66 .count_filter = 5, 68 .count_filter = 5,
67 .delay_secs = 2, 69 .delay_secs = 2,
68 .display_weighted = -1,
69 .target_pid = -1, 70 .target_pid = -1,
70 .target_tid = -1, 71 .target_tid = -1,
71 .active_symbols = LIST_HEAD_INIT(top.active_symbols),
72 .active_symbols_lock = PTHREAD_MUTEX_INITIALIZER,
73 .active_symbols_cond = PTHREAD_COND_INITIALIZER,
74 .freq = 1000, /* 1 KHz */ 72 .freq = 1000, /* 1 KHz */
75}; 73};
76 74
@@ -78,6 +76,12 @@ static bool system_wide = false;
78 76
79static bool use_tui, use_stdio; 77static bool use_tui, use_stdio;
80 78
79static bool sort_has_symbols;
80
81static bool dont_use_callchains;
82static char callchain_default_opt[] = "fractal,0.5,callee";
83
84
81static int default_interval = 0; 85static int default_interval = 0;
82 86
83static bool kptr_restrict_warned; 87static bool kptr_restrict_warned;
@@ -85,7 +89,7 @@ static bool vmlinux_warned;
85static bool inherit = false; 89static bool inherit = false;
86static int realtime_prio = 0; 90static int realtime_prio = 0;
87static bool group = false; 91static bool group = false;
88static unsigned int page_size; 92static bool sample_id_all_avail = true;
89static unsigned int mmap_pages = 128; 93static unsigned int mmap_pages = 128;
90 94
91static bool dump_symtab = false; 95static bool dump_symtab = false;
@@ -93,7 +97,6 @@ static bool dump_symtab = false;
93static struct winsize winsize; 97static struct winsize winsize;
94 98
95static const char *sym_filter = NULL; 99static const char *sym_filter = NULL;
96struct sym_entry *sym_filter_entry_sched = NULL;
97static int sym_pcnt_filter = 5; 100static int sym_pcnt_filter = 5;
98 101
99/* 102/*
@@ -136,18 +139,18 @@ static void sig_winch_handler(int sig __used)
136 update_print_entries(&winsize); 139 update_print_entries(&winsize);
137} 140}
138 141
139static int parse_source(struct sym_entry *syme) 142static int parse_source(struct hist_entry *he)
140{ 143{
141 struct symbol *sym; 144 struct symbol *sym;
142 struct annotation *notes; 145 struct annotation *notes;
143 struct map *map; 146 struct map *map;
144 int err = -1; 147 int err = -1;
145 148
146 if (!syme) 149 if (!he || !he->ms.sym)
147 return -1; 150 return -1;
148 151
149 sym = sym_entry__symbol(syme); 152 sym = he->ms.sym;
150 map = syme->map; 153 map = he->ms.map;
151 154
152 /* 155 /*
153 * We can't annotate with just /proc/kallsyms 156 * We can't annotate with just /proc/kallsyms
@@ -175,52 +178,63 @@ static int parse_source(struct sym_entry *syme)
175 return err; 178 return err;
176 } 179 }
177 180
178 err = symbol__annotate(sym, syme->map, 0); 181 err = symbol__annotate(sym, map, 0);
179 if (err == 0) { 182 if (err == 0) {
180out_assign: 183out_assign:
181 top.sym_filter_entry = syme; 184 top.sym_filter_entry = he;
182 } 185 }
183 186
184 pthread_mutex_unlock(&notes->lock); 187 pthread_mutex_unlock(&notes->lock);
185 return err; 188 return err;
186} 189}
187 190
188static void __zero_source_counters(struct sym_entry *syme) 191static void __zero_source_counters(struct hist_entry *he)
189{ 192{
190 struct symbol *sym = sym_entry__symbol(syme); 193 struct symbol *sym = he->ms.sym;
191 symbol__annotate_zero_histograms(sym); 194 symbol__annotate_zero_histograms(sym);
192} 195}
193 196
194static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip) 197static void record_precise_ip(struct hist_entry *he, int counter, u64 ip)
195{ 198{
196 struct annotation *notes; 199 struct annotation *notes;
197 struct symbol *sym; 200 struct symbol *sym;
198 201
199 if (syme != top.sym_filter_entry) 202 if (he == NULL || he->ms.sym == NULL ||
203 ((top.sym_filter_entry == NULL ||
204 top.sym_filter_entry->ms.sym != he->ms.sym) && use_browser != 1))
200 return; 205 return;
201 206
202 sym = sym_entry__symbol(syme); 207 sym = he->ms.sym;
203 notes = symbol__annotation(sym); 208 notes = symbol__annotation(sym);
204 209
205 if (pthread_mutex_trylock(&notes->lock)) 210 if (pthread_mutex_trylock(&notes->lock))
206 return; 211 return;
207 212
208 ip = syme->map->map_ip(syme->map, ip); 213 if (notes->src == NULL &&
209 symbol__inc_addr_samples(sym, syme->map, counter, ip); 214 symbol__alloc_hist(sym, top.evlist->nr_entries) < 0) {
215 pthread_mutex_unlock(&notes->lock);
216 pr_err("Not enough memory for annotating '%s' symbol!\n",
217 sym->name);
218 sleep(1);
219 return;
220 }
221
222 ip = he->ms.map->map_ip(he->ms.map, ip);
223 symbol__inc_addr_samples(sym, he->ms.map, counter, ip);
210 224
211 pthread_mutex_unlock(&notes->lock); 225 pthread_mutex_unlock(&notes->lock);
212} 226}
213 227
214static void show_details(struct sym_entry *syme) 228static void show_details(struct hist_entry *he)
215{ 229{
216 struct annotation *notes; 230 struct annotation *notes;
217 struct symbol *symbol; 231 struct symbol *symbol;
218 int more; 232 int more;
219 233
220 if (!syme) 234 if (!he)
221 return; 235 return;
222 236
223 symbol = sym_entry__symbol(syme); 237 symbol = he->ms.sym;
224 notes = symbol__annotation(symbol); 238 notes = symbol__annotation(symbol);
225 239
226 pthread_mutex_lock(&notes->lock); 240 pthread_mutex_lock(&notes->lock);
@@ -231,7 +245,7 @@ static void show_details(struct sym_entry *syme)
231 printf("Showing %s for %s\n", event_name(top.sym_evsel), symbol->name); 245 printf("Showing %s for %s\n", event_name(top.sym_evsel), symbol->name);
232 printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter); 246 printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter);
233 247
234 more = symbol__annotate_printf(symbol, syme->map, top.sym_evsel->idx, 248 more = symbol__annotate_printf(symbol, he->ms.map, top.sym_evsel->idx,
235 0, sym_pcnt_filter, top.print_entries, 4); 249 0, sym_pcnt_filter, top.print_entries, 4);
236 if (top.zero) 250 if (top.zero)
237 symbol__annotate_zero_histogram(symbol, top.sym_evsel->idx); 251 symbol__annotate_zero_histogram(symbol, top.sym_evsel->idx);
@@ -245,21 +259,28 @@ out_unlock:
245 259
246static const char CONSOLE_CLEAR[] = ""; 260static const char CONSOLE_CLEAR[] = "";
247 261
248static void __list_insert_active_sym(struct sym_entry *syme) 262static struct hist_entry *
263 perf_session__add_hist_entry(struct perf_session *session,
264 struct addr_location *al,
265 struct perf_sample *sample,
266 struct perf_evsel *evsel)
249{ 267{
250 list_add(&syme->node, &top.active_symbols); 268 struct hist_entry *he;
269
270 he = __hists__add_entry(&evsel->hists, al, NULL, sample->period);
271 if (he == NULL)
272 return NULL;
273
274 session->hists.stats.total_period += sample->period;
275 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
276 return he;
251} 277}
252 278
253static void print_sym_table(struct perf_session *session) 279static void print_sym_table(void)
254{ 280{
255 char bf[160]; 281 char bf[160];
256 int printed = 0; 282 int printed = 0;
257 struct rb_node *nd;
258 struct sym_entry *syme;
259 struct rb_root tmp = RB_ROOT;
260 const int win_width = winsize.ws_col - 1; 283 const int win_width = winsize.ws_col - 1;
261 int sym_width, dso_width, dso_short_width;
262 float sum_ksamples = perf_top__decay_samples(&top, &tmp);
263 284
264 puts(CONSOLE_CLEAR); 285 puts(CONSOLE_CLEAR);
265 286
@@ -270,10 +291,14 @@ static void print_sym_table(struct perf_session *session)
270 291
271 printf("%-*.*s\n", win_width, win_width, graph_dotted_line); 292 printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
272 293
273 if (session->hists.stats.total_lost != 0) { 294 if (top.sym_evsel->hists.stats.nr_lost_warned !=
274 color_fprintf(stdout, PERF_COLOR_RED, "WARNING:"); 295 top.sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]) {
275 printf(" LOST %" PRIu64 " events, Check IO/CPU overload\n", 296 top.sym_evsel->hists.stats.nr_lost_warned =
276 session->hists.stats.total_lost); 297 top.sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST];
298 color_fprintf(stdout, PERF_COLOR_RED,
299 "WARNING: LOST %d chunks, Check IO/CPU overload",
300 top.sym_evsel->hists.stats.nr_lost_warned);
301 ++printed;
277 } 302 }
278 303
279 if (top.sym_filter_entry) { 304 if (top.sym_filter_entry) {
@@ -281,58 +306,15 @@ static void print_sym_table(struct perf_session *session)
281 return; 306 return;
282 } 307 }
283 308
284 perf_top__find_widths(&top, &tmp, &dso_width, &dso_short_width, 309 hists__collapse_resort_threaded(&top.sym_evsel->hists);
285 &sym_width); 310 hists__output_resort_threaded(&top.sym_evsel->hists);
286 311 hists__decay_entries_threaded(&top.sym_evsel->hists,
287 if (sym_width + dso_width > winsize.ws_col - 29) { 312 top.hide_user_symbols,
288 dso_width = dso_short_width; 313 top.hide_kernel_symbols);
289 if (sym_width + dso_width > winsize.ws_col - 29) 314 hists__output_recalc_col_len(&top.sym_evsel->hists, winsize.ws_row - 3);
290 sym_width = winsize.ws_col - dso_width - 29;
291 }
292 putchar('\n'); 315 putchar('\n');
293 if (top.evlist->nr_entries == 1) 316 hists__fprintf(&top.sym_evsel->hists, NULL, false, false,
294 printf(" samples pcnt"); 317 winsize.ws_row - 4 - printed, win_width, stdout);
295 else
296 printf(" weight samples pcnt");
297
298 if (verbose)
299 printf(" RIP ");
300 printf(" %-*.*s DSO\n", sym_width, sym_width, "function");
301 printf(" %s _______ _____",
302 top.evlist->nr_entries == 1 ? " " : "______");
303 if (verbose)
304 printf(" ________________");
305 printf(" %-*.*s", sym_width, sym_width, graph_line);
306 printf(" %-*.*s", dso_width, dso_width, graph_line);
307 puts("\n");
308
309 for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
310 struct symbol *sym;
311 double pcnt;
312
313 syme = rb_entry(nd, struct sym_entry, rb_node);
314 sym = sym_entry__symbol(syme);
315 if (++printed > top.print_entries ||
316 (int)syme->snap_count < top.count_filter)
317 continue;
318
319 pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) /
320 sum_ksamples));
321
322 if (top.evlist->nr_entries == 1 || !top.display_weighted)
323 printf("%20.2f ", syme->weight);
324 else
325 printf("%9.1f %10ld ", syme->weight, syme->snap_count);
326
327 percent_color_fprintf(stdout, "%4.1f%%", pcnt);
328 if (verbose)
329 printf(" %016" PRIx64, sym->start);
330 printf(" %-*.*s", sym_width, sym_width, sym->name);
331 printf(" %-*.*s\n", dso_width, dso_width,
332 dso_width >= syme->map->dso->long_name_len ?
333 syme->map->dso->long_name :
334 syme->map->dso->short_name);
335 }
336} 318}
337 319
338static void prompt_integer(int *target, const char *msg) 320static void prompt_integer(int *target, const char *msg)
@@ -370,10 +352,11 @@ static void prompt_percent(int *target, const char *msg)
370 *target = tmp; 352 *target = tmp;
371} 353}
372 354
373static void prompt_symbol(struct sym_entry **target, const char *msg) 355static void prompt_symbol(struct hist_entry **target, const char *msg)
374{ 356{
375 char *buf = malloc(0), *p; 357 char *buf = malloc(0), *p;
376 struct sym_entry *syme = *target, *n, *found = NULL; 358 struct hist_entry *syme = *target, *n, *found = NULL;
359 struct rb_node *next;
377 size_t dummy = 0; 360 size_t dummy = 0;
378 361
379 /* zero counters of active symbol */ 362 /* zero counters of active symbol */
@@ -390,17 +373,14 @@ static void prompt_symbol(struct sym_entry **target, const char *msg)
390 if (p) 373 if (p)
391 *p = 0; 374 *p = 0;
392 375
393 pthread_mutex_lock(&top.active_symbols_lock); 376 next = rb_first(&top.sym_evsel->hists.entries);
394 syme = list_entry(top.active_symbols.next, struct sym_entry, node); 377 while (next) {
395 pthread_mutex_unlock(&top.active_symbols_lock); 378 n = rb_entry(next, struct hist_entry, rb_node);
396 379 if (n->ms.sym && !strcmp(buf, n->ms.sym->name)) {
397 list_for_each_entry_safe_from(syme, n, &top.active_symbols, node) { 380 found = n;
398 struct symbol *sym = sym_entry__symbol(syme);
399
400 if (!strcmp(buf, sym->name)) {
401 found = syme;
402 break; 381 break;
403 } 382 }
383 next = rb_next(&n->rb_node);
404 } 384 }
405 385
406 if (!found) { 386 if (!found) {
@@ -419,7 +399,7 @@ static void print_mapped_keys(void)
419 char *name = NULL; 399 char *name = NULL;
420 400
421 if (top.sym_filter_entry) { 401 if (top.sym_filter_entry) {
422 struct symbol *sym = sym_entry__symbol(top.sym_filter_entry); 402 struct symbol *sym = top.sym_filter_entry->ms.sym;
423 name = sym->name; 403 name = sym->name;
424 } 404 }
425 405
@@ -436,9 +416,6 @@ static void print_mapped_keys(void)
436 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); 416 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL");
437 fprintf(stdout, "\t[S] stop annotation.\n"); 417 fprintf(stdout, "\t[S] stop annotation.\n");
438 418
439 if (top.evlist->nr_entries > 1)
440 fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", top.display_weighted ? 1 : 0);
441
442 fprintf(stdout, 419 fprintf(stdout,
443 "\t[K] hide kernel_symbols symbols. \t(%s)\n", 420 "\t[K] hide kernel_symbols symbols. \t(%s)\n",
444 top.hide_kernel_symbols ? "yes" : "no"); 421 top.hide_kernel_symbols ? "yes" : "no");
@@ -465,7 +442,6 @@ static int key_mapped(int c)
465 case 'S': 442 case 'S':
466 return 1; 443 return 1;
467 case 'E': 444 case 'E':
468 case 'w':
469 return top.evlist->nr_entries > 1 ? 1 : 0; 445 return top.evlist->nr_entries > 1 ? 1 : 0;
470 default: 446 default:
471 break; 447 break;
@@ -474,7 +450,7 @@ static int key_mapped(int c)
474 return 0; 450 return 0;
475} 451}
476 452
477static void handle_keypress(struct perf_session *session, int c) 453static void handle_keypress(int c)
478{ 454{
479 if (!key_mapped(c)) { 455 if (!key_mapped(c)) {
480 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; 456 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
@@ -550,7 +526,7 @@ static void handle_keypress(struct perf_session *session, int c)
550 case 'Q': 526 case 'Q':
551 printf("exiting.\n"); 527 printf("exiting.\n");
552 if (dump_symtab) 528 if (dump_symtab)
553 perf_session__fprintf_dsos(session, stderr); 529 perf_session__fprintf_dsos(top.session, stderr);
554 exit(0); 530 exit(0);
555 case 's': 531 case 's':
556 prompt_symbol(&top.sym_filter_entry, "Enter details symbol"); 532 prompt_symbol(&top.sym_filter_entry, "Enter details symbol");
@@ -559,7 +535,7 @@ static void handle_keypress(struct perf_session *session, int c)
559 if (!top.sym_filter_entry) 535 if (!top.sym_filter_entry)
560 break; 536 break;
561 else { 537 else {
562 struct sym_entry *syme = top.sym_filter_entry; 538 struct hist_entry *syme = top.sym_filter_entry;
563 539
564 top.sym_filter_entry = NULL; 540 top.sym_filter_entry = NULL;
565 __zero_source_counters(syme); 541 __zero_source_counters(syme);
@@ -568,9 +544,6 @@ static void handle_keypress(struct perf_session *session, int c)
568 case 'U': 544 case 'U':
569 top.hide_user_symbols = !top.hide_user_symbols; 545 top.hide_user_symbols = !top.hide_user_symbols;
570 break; 546 break;
571 case 'w':
572 top.display_weighted = ~top.display_weighted;
573 break;
574 case 'z': 547 case 'z':
575 top.zero = !top.zero; 548 top.zero = !top.zero;
576 break; 549 break;
@@ -579,19 +552,30 @@ static void handle_keypress(struct perf_session *session, int c)
579 } 552 }
580} 553}
581 554
555static void perf_top__sort_new_samples(void *arg)
556{
557 struct perf_top *t = arg;
558 perf_top__reset_sample_counters(t);
559
560 if (t->evlist->selected != NULL)
561 t->sym_evsel = t->evlist->selected;
562
563 hists__collapse_resort_threaded(&t->sym_evsel->hists);
564 hists__output_resort_threaded(&t->sym_evsel->hists);
565 hists__decay_entries_threaded(&t->sym_evsel->hists,
566 top.hide_user_symbols,
567 top.hide_kernel_symbols);
568}
569
582static void *display_thread_tui(void *arg __used) 570static void *display_thread_tui(void *arg __used)
583{ 571{
584 int err = 0; 572 const char *help = "For a higher level overview, try: perf top --sort comm,dso";
585 pthread_mutex_lock(&top.active_symbols_lock); 573
586 while (list_empty(&top.active_symbols)) { 574 perf_top__sort_new_samples(&top);
587 err = pthread_cond_wait(&top.active_symbols_cond, 575 perf_evlist__tui_browse_hists(top.evlist, help,
588 &top.active_symbols_lock); 576 perf_top__sort_new_samples,
589 if (err) 577 &top, top.delay_secs);
590 break; 578
591 }
592 pthread_mutex_unlock(&top.active_symbols_lock);
593 if (!err)
594 perf_top__tui_browser(&top);
595 exit_browser(0); 579 exit_browser(0);
596 exit(0); 580 exit(0);
597 return NULL; 581 return NULL;
@@ -602,7 +586,6 @@ static void *display_thread(void *arg __used)
602 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; 586 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
603 struct termios tc, save; 587 struct termios tc, save;
604 int delay_msecs, c; 588 int delay_msecs, c;
605 struct perf_session *session = (struct perf_session *) arg;
606 589
607 tcgetattr(0, &save); 590 tcgetattr(0, &save);
608 tc = save; 591 tc = save;
@@ -610,20 +593,35 @@ static void *display_thread(void *arg __used)
610 tc.c_cc[VMIN] = 0; 593 tc.c_cc[VMIN] = 0;
611 tc.c_cc[VTIME] = 0; 594 tc.c_cc[VTIME] = 0;
612 595
596 pthread__unblock_sigwinch();
613repeat: 597repeat:
614 delay_msecs = top.delay_secs * 1000; 598 delay_msecs = top.delay_secs * 1000;
615 tcsetattr(0, TCSANOW, &tc); 599 tcsetattr(0, TCSANOW, &tc);
616 /* trash return*/ 600 /* trash return*/
617 getc(stdin); 601 getc(stdin);
618 602
619 do { 603 while (1) {
620 print_sym_table(session); 604 print_sym_table();
621 } while (!poll(&stdin_poll, 1, delay_msecs) == 1); 605 /*
622 606 * Either timeout expired or we got an EINTR due to SIGWINCH,
607 * refresh screen in both cases.
608 */
609 switch (poll(&stdin_poll, 1, delay_msecs)) {
610 case 0:
611 continue;
612 case -1:
613 if (errno == EINTR)
614 continue;
615 /* Fall trhu */
616 default:
617 goto process_hotkey;
618 }
619 }
620process_hotkey:
623 c = getc(stdin); 621 c = getc(stdin);
624 tcsetattr(0, TCSAFLUSH, &save); 622 tcsetattr(0, TCSAFLUSH, &save);
625 623
626 handle_keypress(session, c); 624 handle_keypress(c);
627 goto repeat; 625 goto repeat;
628 626
629 return NULL; 627 return NULL;
@@ -644,9 +642,8 @@ static const char *skip_symbols[] = {
644 NULL 642 NULL
645}; 643};
646 644
647static int symbol_filter(struct map *map, struct symbol *sym) 645static int symbol_filter(struct map *map __used, struct symbol *sym)
648{ 646{
649 struct sym_entry *syme;
650 const char *name = sym->name; 647 const char *name = sym->name;
651 int i; 648 int i;
652 649
@@ -666,16 +663,6 @@ static int symbol_filter(struct map *map, struct symbol *sym)
666 strstr(name, "_text_end")) 663 strstr(name, "_text_end"))
667 return 1; 664 return 1;
668 665
669 syme = symbol__priv(sym);
670 syme->map = map;
671 symbol__annotate_init(map, sym);
672
673 if (!top.sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) {
674 /* schedule initial sym_filter_entry setup */
675 sym_filter_entry_sched = syme;
676 sym_filter = NULL;
677 }
678
679 for (i = 0; skip_symbols[i]; i++) { 666 for (i = 0; skip_symbols[i]; i++) {
680 if (!strcmp(skip_symbols[i], name)) { 667 if (!strcmp(skip_symbols[i], name)) {
681 sym->ignore = true; 668 sym->ignore = true;
@@ -687,13 +674,15 @@ static int symbol_filter(struct map *map, struct symbol *sym)
687} 674}
688 675
689static void perf_event__process_sample(const union perf_event *event, 676static void perf_event__process_sample(const union perf_event *event,
677 struct perf_evsel *evsel,
690 struct perf_sample *sample, 678 struct perf_sample *sample,
691 struct perf_session *session) 679 struct perf_session *session)
692{ 680{
681 struct symbol *parent = NULL;
693 u64 ip = event->ip.ip; 682 u64 ip = event->ip.ip;
694 struct sym_entry *syme;
695 struct addr_location al; 683 struct addr_location al;
696 struct machine *machine; 684 struct machine *machine;
685 int err;
697 u8 origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 686 u8 origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
698 687
699 ++top.samples; 688 ++top.samples;
@@ -782,51 +771,43 @@ static void perf_event__process_sample(const union perf_event *event,
782 sleep(5); 771 sleep(5);
783 vmlinux_warned = true; 772 vmlinux_warned = true;
784 } 773 }
785
786 return;
787 } 774 }
788 775
789 /* let's see, whether we need to install initial sym_filter_entry */ 776 if (al.sym == NULL || !al.sym->ignore) {
790 if (sym_filter_entry_sched) { 777 struct hist_entry *he;
791 top.sym_filter_entry = sym_filter_entry_sched; 778
792 sym_filter_entry_sched = NULL; 779 if ((sort__has_parent || symbol_conf.use_callchain) &&
793 if (parse_source(top.sym_filter_entry) < 0) { 780 sample->callchain) {
794 struct symbol *sym = sym_entry__symbol(top.sym_filter_entry); 781 err = perf_session__resolve_callchain(session, al.thread,
795 782 sample->callchain, &parent);
796 pr_err("Can't annotate %s", sym->name); 783 if (err)
797 if (top.sym_filter_entry->map->dso->symtab_type == SYMTAB__KALLSYMS) { 784 return;
798 pr_err(": No vmlinux file was found in the path:\n");
799 machine__fprintf_vmlinux_path(machine, stderr);
800 } else
801 pr_err(".\n");
802 exit(1);
803 } 785 }
804 }
805 786
806 syme = symbol__priv(al.sym); 787 he = perf_session__add_hist_entry(session, &al, sample, evsel);
807 if (!al.sym->ignore) { 788 if (he == NULL) {
808 struct perf_evsel *evsel; 789 pr_err("Problem incrementing symbol period, skipping event\n");
790 return;
791 }
809 792
810 evsel = perf_evlist__id2evsel(top.evlist, sample->id); 793 if (symbol_conf.use_callchain) {
811 assert(evsel != NULL); 794 err = callchain_append(he->callchain, &session->callchain_cursor,
812 syme->count[evsel->idx]++; 795 sample->period);
813 record_precise_ip(syme, evsel->idx, ip); 796 if (err)
814 pthread_mutex_lock(&top.active_symbols_lock); 797 return;
815 if (list_empty(&syme->node) || !syme->node.next) {
816 static bool first = true;
817 __list_insert_active_sym(syme);
818 if (first) {
819 pthread_cond_broadcast(&top.active_symbols_cond);
820 first = false;
821 }
822 } 798 }
823 pthread_mutex_unlock(&top.active_symbols_lock); 799
800 if (sort_has_symbols)
801 record_precise_ip(he, evsel->idx, ip);
824 } 802 }
803
804 return;
825} 805}
826 806
827static void perf_session__mmap_read_idx(struct perf_session *self, int idx) 807static void perf_session__mmap_read_idx(struct perf_session *self, int idx)
828{ 808{
829 struct perf_sample sample; 809 struct perf_sample sample;
810 struct perf_evsel *evsel;
830 union perf_event *event; 811 union perf_event *event;
831 int ret; 812 int ret;
832 813
@@ -837,10 +818,16 @@ static void perf_session__mmap_read_idx(struct perf_session *self, int idx)
837 continue; 818 continue;
838 } 819 }
839 820
821 evsel = perf_evlist__id2evsel(self->evlist, sample.id);
822 assert(evsel != NULL);
823
840 if (event->header.type == PERF_RECORD_SAMPLE) 824 if (event->header.type == PERF_RECORD_SAMPLE)
841 perf_event__process_sample(event, &sample, self); 825 perf_event__process_sample(event, evsel, &sample, self);
842 else 826 else if (event->header.type < PERF_RECORD_MAX) {
827 hists__inc_nr_events(&evsel->hists, event->header.type);
843 perf_event__process(event, &sample, self); 828 perf_event__process(event, &sample, self);
829 } else
830 ++self->hists.stats.nr_unknown_events;
844 } 831 }
845} 832}
846 833
@@ -854,10 +841,16 @@ static void perf_session__mmap_read(struct perf_session *self)
854 841
855static void start_counters(struct perf_evlist *evlist) 842static void start_counters(struct perf_evlist *evlist)
856{ 843{
857 struct perf_evsel *counter; 844 struct perf_evsel *counter, *first;
845
846 first = list_entry(evlist->entries.next, struct perf_evsel, node);
858 847
859 list_for_each_entry(counter, &evlist->entries, node) { 848 list_for_each_entry(counter, &evlist->entries, node) {
860 struct perf_event_attr *attr = &counter->attr; 849 struct perf_event_attr *attr = &counter->attr;
850 struct xyarray *group_fd = NULL;
851
852 if (group && counter != first)
853 group_fd = first->fd;
861 854
862 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; 855 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
863 856
@@ -872,16 +865,29 @@ static void start_counters(struct perf_evlist *evlist)
872 attr->read_format |= PERF_FORMAT_ID; 865 attr->read_format |= PERF_FORMAT_ID;
873 } 866 }
874 867
868 if (symbol_conf.use_callchain)
869 attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
870
875 attr->mmap = 1; 871 attr->mmap = 1;
872 attr->comm = 1;
876 attr->inherit = inherit; 873 attr->inherit = inherit;
874retry_sample_id:
875 attr->sample_id_all = sample_id_all_avail ? 1 : 0;
877try_again: 876try_again:
878 if (perf_evsel__open(counter, top.evlist->cpus, 877 if (perf_evsel__open(counter, top.evlist->cpus,
879 top.evlist->threads, group) < 0) { 878 top.evlist->threads, group,
879 group_fd) < 0) {
880 int err = errno; 880 int err = errno;
881 881
882 if (err == EPERM || err == EACCES) { 882 if (err == EPERM || err == EACCES) {
883 ui__warning_paranoid(); 883 ui__error_paranoid();
884 goto out_err; 884 goto out_err;
885 } else if (err == EINVAL && sample_id_all_avail) {
886 /*
887 * Old kernel, no attr->sample_id_type_all field
888 */
889 sample_id_all_avail = false;
890 goto retry_sample_id;
885 } 891 }
886 /* 892 /*
887 * If it's cycles then fall back to hrtimer 893 * If it's cycles then fall back to hrtimer
@@ -927,35 +933,56 @@ out_err:
927 exit(0); 933 exit(0);
928} 934}
929 935
936static int setup_sample_type(void)
937{
938 if (!sort_has_symbols) {
939 if (symbol_conf.use_callchain) {
940 ui__warning("Selected -g but \"sym\" not present in --sort/-s.");
941 return -EINVAL;
942 }
943 } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE) {
944 if (callchain_register_param(&callchain_param) < 0) {
945 ui__warning("Can't register callchain params.\n");
946 return -EINVAL;
947 }
948 }
949
950 return 0;
951}
952
930static int __cmd_top(void) 953static int __cmd_top(void)
931{ 954{
932 pthread_t thread; 955 pthread_t thread;
933 int ret __used; 956 int ret;
934 /* 957 /*
935 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this 958 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this
936 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now. 959 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now.
937 */ 960 */
938 struct perf_session *session = perf_session__new(NULL, O_WRONLY, false, false, NULL); 961 top.session = perf_session__new(NULL, O_WRONLY, false, false, NULL);
939 if (session == NULL) 962 if (top.session == NULL)
940 return -ENOMEM; 963 return -ENOMEM;
941 964
965 ret = setup_sample_type();
966 if (ret)
967 goto out_delete;
968
942 if (top.target_tid != -1) 969 if (top.target_tid != -1)
943 perf_event__synthesize_thread_map(top.evlist->threads, 970 perf_event__synthesize_thread_map(top.evlist->threads,
944 perf_event__process, session); 971 perf_event__process, top.session);
945 else 972 else
946 perf_event__synthesize_threads(perf_event__process, session); 973 perf_event__synthesize_threads(perf_event__process, top.session);
947 974
948 start_counters(top.evlist); 975 start_counters(top.evlist);
949 session->evlist = top.evlist; 976 top.session->evlist = top.evlist;
950 perf_session__update_sample_type(session); 977 perf_session__update_sample_type(top.session);
951 978
952 /* Wait for a minimal set of events before starting the snapshot */ 979 /* Wait for a minimal set of events before starting the snapshot */
953 poll(top.evlist->pollfd, top.evlist->nr_fds, 100); 980 poll(top.evlist->pollfd, top.evlist->nr_fds, 100);
954 981
955 perf_session__mmap_read(session); 982 perf_session__mmap_read(top.session);
956 983
957 if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui : 984 if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui :
958 display_thread), session)) { 985 display_thread), NULL)) {
959 printf("Could not create display thread.\n"); 986 printf("Could not create display thread.\n");
960 exit(-1); 987 exit(-1);
961 } 988 }
@@ -973,12 +1000,96 @@ static int __cmd_top(void)
973 while (1) { 1000 while (1) {
974 u64 hits = top.samples; 1001 u64 hits = top.samples;
975 1002
976 perf_session__mmap_read(session); 1003 perf_session__mmap_read(top.session);
977 1004
978 if (hits == top.samples) 1005 if (hits == top.samples)
979 ret = poll(top.evlist->pollfd, top.evlist->nr_fds, 100); 1006 ret = poll(top.evlist->pollfd, top.evlist->nr_fds, 100);
980 } 1007 }
981 1008
1009out_delete:
1010 perf_session__delete(top.session);
1011 top.session = NULL;
1012
1013 return 0;
1014}
1015
1016static int
1017parse_callchain_opt(const struct option *opt __used, const char *arg,
1018 int unset)
1019{
1020 char *tok, *tok2;
1021 char *endptr;
1022
1023 /*
1024 * --no-call-graph
1025 */
1026 if (unset) {
1027 dont_use_callchains = true;
1028 return 0;
1029 }
1030
1031 symbol_conf.use_callchain = true;
1032
1033 if (!arg)
1034 return 0;
1035
1036 tok = strtok((char *)arg, ",");
1037 if (!tok)
1038 return -1;
1039
1040 /* get the output mode */
1041 if (!strncmp(tok, "graph", strlen(arg)))
1042 callchain_param.mode = CHAIN_GRAPH_ABS;
1043
1044 else if (!strncmp(tok, "flat", strlen(arg)))
1045 callchain_param.mode = CHAIN_FLAT;
1046
1047 else if (!strncmp(tok, "fractal", strlen(arg)))
1048 callchain_param.mode = CHAIN_GRAPH_REL;
1049
1050 else if (!strncmp(tok, "none", strlen(arg))) {
1051 callchain_param.mode = CHAIN_NONE;
1052 symbol_conf.use_callchain = false;
1053
1054 return 0;
1055 }
1056
1057 else
1058 return -1;
1059
1060 /* get the min percentage */
1061 tok = strtok(NULL, ",");
1062 if (!tok)
1063 goto setup;
1064
1065 callchain_param.min_percent = strtod(tok, &endptr);
1066 if (tok == endptr)
1067 return -1;
1068
1069 /* get the print limit */
1070 tok2 = strtok(NULL, ",");
1071 if (!tok2)
1072 goto setup;
1073
1074 if (tok2[0] != 'c') {
1075 callchain_param.print_limit = strtod(tok2, &endptr);
1076 tok2 = strtok(NULL, ",");
1077 if (!tok2)
1078 goto setup;
1079 }
1080
1081 /* get the call chain order */
1082 if (!strcmp(tok2, "caller"))
1083 callchain_param.order = ORDER_CALLER;
1084 else if (!strcmp(tok2, "callee"))
1085 callchain_param.order = ORDER_CALLEE;
1086 else
1087 return -1;
1088setup:
1089 if (callchain_register_param(&callchain_param) < 0) {
1090 fprintf(stderr, "Can't register callchain params\n");
1091 return -1;
1092 }
982 return 0; 1093 return 0;
983} 1094}
984 1095
@@ -990,7 +1101,7 @@ static const char * const top_usage[] = {
990static const struct option options[] = { 1101static const struct option options[] = {
991 OPT_CALLBACK('e', "event", &top.evlist, "event", 1102 OPT_CALLBACK('e', "event", &top.evlist, "event",
992 "event selector. use 'perf list' to list available events", 1103 "event selector. use 'perf list' to list available events",
993 parse_events), 1104 parse_events_option),
994 OPT_INTEGER('c', "count", &default_interval, 1105 OPT_INTEGER('c', "count", &default_interval,
995 "event period to sample"), 1106 "event period to sample"),
996 OPT_INTEGER('p', "pid", &top.target_pid, 1107 OPT_INTEGER('p', "pid", &top.target_pid,
@@ -1018,7 +1129,7 @@ static const struct option options[] = {
1018 "put the counters into a counter group"), 1129 "put the counters into a counter group"),
1019 OPT_BOOLEAN('i', "inherit", &inherit, 1130 OPT_BOOLEAN('i', "inherit", &inherit,
1020 "child tasks inherit counters"), 1131 "child tasks inherit counters"),
1021 OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name", 1132 OPT_STRING(0, "sym-annotate", &sym_filter, "symbol name",
1022 "symbol to annotate"), 1133 "symbol to annotate"),
1023 OPT_BOOLEAN('z', "zero", &top.zero, 1134 OPT_BOOLEAN('z', "zero", &top.zero,
1024 "zero history across updates"), 1135 "zero history across updates"),
@@ -1032,6 +1143,28 @@ static const struct option options[] = {
1032 OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"), 1143 OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"),
1033 OPT_INCR('v', "verbose", &verbose, 1144 OPT_INCR('v', "verbose", &verbose,
1034 "be more verbose (show counter open errors, etc)"), 1145 "be more verbose (show counter open errors, etc)"),
1146 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1147 "sort by key(s): pid, comm, dso, symbol, parent"),
1148 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
1149 "Show a column with the number of samples"),
1150 OPT_CALLBACK_DEFAULT('G', "call-graph", NULL, "output_type,min_percent, call_order",
1151 "Display callchains using output_type (graph, flat, fractal, or none), min percent threshold and callchain order. "
1152 "Default: fractal,0.5,callee", &parse_callchain_opt,
1153 callchain_default_opt),
1154 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
1155 "Show a column with the sum of periods"),
1156 OPT_STRING(0, "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
1157 "only consider symbols in these dsos"),
1158 OPT_STRING(0, "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
1159 "only consider symbols in these comms"),
1160 OPT_STRING(0, "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
1161 "only consider these symbols"),
1162 OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src,
1163 "Interleave source code with assembly code (default)"),
1164 OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw,
1165 "Display raw encoding of assembly instructions (default)"),
1166 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
1167 "Specify disassembler style (e.g. -M intel for intel syntax)"),
1035 OPT_END() 1168 OPT_END()
1036}; 1169};
1037 1170
@@ -1044,18 +1177,16 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1044 if (top.evlist == NULL) 1177 if (top.evlist == NULL)
1045 return -ENOMEM; 1178 return -ENOMEM;
1046 1179
1047 page_size = sysconf(_SC_PAGE_SIZE); 1180 symbol_conf.exclude_other = false;
1048 1181
1049 argc = parse_options(argc, argv, options, top_usage, 0); 1182 argc = parse_options(argc, argv, options, top_usage, 0);
1050 if (argc) 1183 if (argc)
1051 usage_with_options(top_usage, options); 1184 usage_with_options(top_usage, options);
1052 1185
1053 /* 1186 if (sort_order == default_sort_order)
1054 * XXX For now start disabled, only using TUI if explicitely asked for. 1187 sort_order = "dso,symbol";
1055 * Change that when handle_keys equivalent gets written, live annotation 1188
1056 * done, etc. 1189 setup_sorting(top_usage, options);
1057 */
1058 use_browser = 0;
1059 1190
1060 if (use_stdio) 1191 if (use_stdio)
1061 use_browser = 0; 1192 use_browser = 0;
@@ -1118,13 +1249,22 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1118 1249
1119 top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node); 1250 top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node);
1120 1251
1121 symbol_conf.priv_size = (sizeof(struct sym_entry) + sizeof(struct annotation) + 1252 symbol_conf.priv_size = sizeof(struct annotation);
1122 (top.evlist->nr_entries + 1) * sizeof(unsigned long));
1123 1253
1124 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); 1254 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
1125 if (symbol__init() < 0) 1255 if (symbol__init() < 0)
1126 return -1; 1256 return -1;
1127 1257
1258 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", stdout);
1259 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout);
1260 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);
1261
1262 /*
1263 * Avoid annotation data structures overhead when symbols aren't on the
1264 * sort list.
1265 */
1266 sort_has_symbols = sort_sym.list.next != NULL;
1267
1128 get_term_dimensions(&winsize); 1268 get_term_dimensions(&winsize);
1129 if (top.print_entries == 0) { 1269 if (top.print_entries == 0) {
1130 update_print_entries(&winsize); 1270 update_print_entries(&winsize);
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h
index 4702e2443a8e..b382bd551aac 100644
--- a/tools/perf/builtin.h
+++ b/tools/perf/builtin.h
@@ -4,7 +4,6 @@
4#include "util/util.h" 4#include "util/util.h"
5#include "util/strbuf.h" 5#include "util/strbuf.h"
6 6
7extern const char perf_version_string[];
8extern const char perf_usage_string[]; 7extern const char perf_usage_string[];
9extern const char perf_more_info_string[]; 8extern const char perf_more_info_string[];
10 9
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index ec635b7cc8ea..73d0cac8b67e 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -427,6 +427,24 @@ static void get_debugfs_mntpt(void)
427 debugfs_mntpt[0] = '\0'; 427 debugfs_mntpt[0] = '\0';
428} 428}
429 429
430static void pthread__block_sigwinch(void)
431{
432 sigset_t set;
433
434 sigemptyset(&set);
435 sigaddset(&set, SIGWINCH);
436 pthread_sigmask(SIG_BLOCK, &set, NULL);
437}
438
439void pthread__unblock_sigwinch(void)
440{
441 sigset_t set;
442
443 sigemptyset(&set);
444 sigaddset(&set, SIGWINCH);
445 pthread_sigmask(SIG_UNBLOCK, &set, NULL);
446}
447
430int main(int argc, const char **argv) 448int main(int argc, const char **argv)
431{ 449{
432 const char *cmd; 450 const char *cmd;
@@ -480,6 +498,12 @@ int main(int argc, const char **argv)
480 * time. 498 * time.
481 */ 499 */
482 setup_path(); 500 setup_path();
501 /*
502 * Block SIGWINCH notifications so that the thread that wants it can
503 * unblock and get syscalls like select interrupted instead of waiting
504 * forever while the signal goes to some other non interested thread.
505 */
506 pthread__block_sigwinch();
483 507
484 while (1) { 508 while (1) {
485 static int done_help; 509 static int done_help;
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index a5fc660c1f12..914c895510f7 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -9,18 +9,21 @@ void get_term_dimensions(struct winsize *ws);
9#include "../../arch/x86/include/asm/unistd.h" 9#include "../../arch/x86/include/asm/unistd.h"
10#define rmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory") 10#define rmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
11#define cpu_relax() asm volatile("rep; nop" ::: "memory"); 11#define cpu_relax() asm volatile("rep; nop" ::: "memory");
12#define CPUINFO_PROC "model name"
12#endif 13#endif
13 14
14#if defined(__x86_64__) 15#if defined(__x86_64__)
15#include "../../arch/x86/include/asm/unistd.h" 16#include "../../arch/x86/include/asm/unistd.h"
16#define rmb() asm volatile("lfence" ::: "memory") 17#define rmb() asm volatile("lfence" ::: "memory")
17#define cpu_relax() asm volatile("rep; nop" ::: "memory"); 18#define cpu_relax() asm volatile("rep; nop" ::: "memory");
19#define CPUINFO_PROC "model name"
18#endif 20#endif
19 21
20#ifdef __powerpc__ 22#ifdef __powerpc__
21#include "../../arch/powerpc/include/asm/unistd.h" 23#include "../../arch/powerpc/include/asm/unistd.h"
22#define rmb() asm volatile ("sync" ::: "memory") 24#define rmb() asm volatile ("sync" ::: "memory")
23#define cpu_relax() asm volatile ("" ::: "memory"); 25#define cpu_relax() asm volatile ("" ::: "memory");
26#define CPUINFO_PROC "cpu"
24#endif 27#endif
25 28
26#ifdef __s390__ 29#ifdef __s390__
@@ -37,30 +40,35 @@ void get_term_dimensions(struct winsize *ws);
37# define rmb() asm volatile("" ::: "memory") 40# define rmb() asm volatile("" ::: "memory")
38#endif 41#endif
39#define cpu_relax() asm volatile("" ::: "memory") 42#define cpu_relax() asm volatile("" ::: "memory")
43#define CPUINFO_PROC "cpu type"
40#endif 44#endif
41 45
42#ifdef __hppa__ 46#ifdef __hppa__
43#include "../../arch/parisc/include/asm/unistd.h" 47#include "../../arch/parisc/include/asm/unistd.h"
44#define rmb() asm volatile("" ::: "memory") 48#define rmb() asm volatile("" ::: "memory")
45#define cpu_relax() asm volatile("" ::: "memory"); 49#define cpu_relax() asm volatile("" ::: "memory");
50#define CPUINFO_PROC "cpu"
46#endif 51#endif
47 52
48#ifdef __sparc__ 53#ifdef __sparc__
49#include "../../arch/sparc/include/asm/unistd.h" 54#include "../../arch/sparc/include/asm/unistd.h"
50#define rmb() asm volatile("":::"memory") 55#define rmb() asm volatile("":::"memory")
51#define cpu_relax() asm volatile("":::"memory") 56#define cpu_relax() asm volatile("":::"memory")
57#define CPUINFO_PROC "cpu"
52#endif 58#endif
53 59
54#ifdef __alpha__ 60#ifdef __alpha__
55#include "../../arch/alpha/include/asm/unistd.h" 61#include "../../arch/alpha/include/asm/unistd.h"
56#define rmb() asm volatile("mb" ::: "memory") 62#define rmb() asm volatile("mb" ::: "memory")
57#define cpu_relax() asm volatile("" ::: "memory") 63#define cpu_relax() asm volatile("" ::: "memory")
64#define CPUINFO_PROC "cpu model"
58#endif 65#endif
59 66
60#ifdef __ia64__ 67#ifdef __ia64__
61#include "../../arch/ia64/include/asm/unistd.h" 68#include "../../arch/ia64/include/asm/unistd.h"
62#define rmb() asm volatile ("mf" ::: "memory") 69#define rmb() asm volatile ("mf" ::: "memory")
63#define cpu_relax() asm volatile ("hint @pause" ::: "memory") 70#define cpu_relax() asm volatile ("hint @pause" ::: "memory")
71#define CPUINFO_PROC "model name"
64#endif 72#endif
65 73
66#ifdef __arm__ 74#ifdef __arm__
@@ -71,6 +79,7 @@ void get_term_dimensions(struct winsize *ws);
71 */ 79 */
72#define rmb() ((void(*)(void))0xffff0fa0)() 80#define rmb() ((void(*)(void))0xffff0fa0)()
73#define cpu_relax() asm volatile("":::"memory") 81#define cpu_relax() asm volatile("":::"memory")
82#define CPUINFO_PROC "Processor"
74#endif 83#endif
75 84
76#ifdef __mips__ 85#ifdef __mips__
@@ -83,6 +92,7 @@ void get_term_dimensions(struct winsize *ws);
83 : /* no input */ \ 92 : /* no input */ \
84 : "memory") 93 : "memory")
85#define cpu_relax() asm volatile("" ::: "memory") 94#define cpu_relax() asm volatile("" ::: "memory")
95#define CPUINFO_PROC "cpu model"
86#endif 96#endif
87 97
88#include <time.h> 98#include <time.h>
@@ -171,5 +181,8 @@ struct ip_callchain {
171}; 181};
172 182
173extern bool perf_host, perf_guest; 183extern bool perf_host, perf_guest;
184extern const char perf_version_string[];
185
186void pthread__unblock_sigwinch(void);
174 187
175#endif 188#endif
diff --git a/tools/perf/scripts/python/bin/net_dropmonitor-record b/tools/perf/scripts/python/bin/net_dropmonitor-record
new file mode 100755
index 000000000000..423fb81dadae
--- /dev/null
+++ b/tools/perf/scripts/python/bin/net_dropmonitor-record
@@ -0,0 +1,2 @@
1#!/bin/bash
2perf record -e skb:kfree_skb $@
diff --git a/tools/perf/scripts/python/bin/net_dropmonitor-report b/tools/perf/scripts/python/bin/net_dropmonitor-report
new file mode 100755
index 000000000000..8d698f5a06aa
--- /dev/null
+++ b/tools/perf/scripts/python/bin/net_dropmonitor-report
@@ -0,0 +1,4 @@
1#!/bin/bash
2# description: display a table of dropped frames
3
4perf script -s "$PERF_EXEC_PATH"/scripts/python/net_dropmonitor.py $@
diff --git a/tools/perf/scripts/python/net_dropmonitor.py b/tools/perf/scripts/python/net_dropmonitor.py
new file mode 100755
index 000000000000..a4ffc9500023
--- /dev/null
+++ b/tools/perf/scripts/python/net_dropmonitor.py
@@ -0,0 +1,72 @@
1# Monitor the system for dropped packets and proudce a report of drop locations and counts
2
3import os
4import sys
5
6sys.path.append(os.environ['PERF_EXEC_PATH'] + \
7 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
8
9from perf_trace_context import *
10from Core import *
11from Util import *
12
13drop_log = {}
14kallsyms = []
15
16def get_kallsyms_table():
17 global kallsyms
18 try:
19 f = open("/proc/kallsyms", "r")
20 linecount = 0
21 for line in f:
22 linecount = linecount+1
23 f.seek(0)
24 except:
25 return
26
27
28 j = 0
29 for line in f:
30 loc = int(line.split()[0], 16)
31 name = line.split()[2]
32 j = j +1
33 if ((j % 100) == 0):
34 print "\r" + str(j) + "/" + str(linecount),
35 kallsyms.append({ 'loc': loc, 'name' : name})
36
37 print "\r" + str(j) + "/" + str(linecount)
38 kallsyms.sort()
39 return
40
41def get_sym(sloc):
42 loc = int(sloc)
43 for i in kallsyms:
44 if (i['loc'] >= loc):
45 return (i['name'], i['loc']-loc)
46 return (None, 0)
47
48def print_drop_table():
49 print "%25s %25s %25s" % ("LOCATION", "OFFSET", "COUNT")
50 for i in drop_log.keys():
51 (sym, off) = get_sym(i)
52 if sym == None:
53 sym = i
54 print "%25s %25s %25s" % (sym, off, drop_log[i])
55
56
57def trace_begin():
58 print "Starting trace (Ctrl-C to dump results)"
59
60def trace_end():
61 print "Gathering kallsyms data"
62 get_kallsyms_table()
63 print_drop_table()
64
65# called from perf, when it finds a correspoinding event
66def skb__kfree_skb(name, context, cpu, sec, nsec, pid, comm,
67 skbaddr, protocol, location):
68 slocation = str(location)
69 try:
70 drop_log[slocation] = drop_log[slocation] + 1
71 except:
72 drop_log[slocation] = 1
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index e01af2b1a469..119e996035c8 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -16,6 +16,8 @@
16#include "annotate.h" 16#include "annotate.h"
17#include <pthread.h> 17#include <pthread.h>
18 18
19const char *disassembler_style;
20
19int symbol__annotate_init(struct map *map __used, struct symbol *sym) 21int symbol__annotate_init(struct map *map __used, struct symbol *sym)
20{ 22{
21 struct annotation *notes = symbol__annotation(sym); 23 struct annotation *notes = symbol__annotation(sym);
@@ -308,9 +310,12 @@ fallback:
308 } 310 }
309 err = -ENOENT; 311 err = -ENOENT;
310 dso->annotate_warned = 1; 312 dso->annotate_warned = 1;
311 pr_err("Can't annotate %s: No vmlinux file%s was found in the " 313 pr_err("Can't annotate %s:\n\n"
312 "path.\nPlease use 'perf buildid-cache -av vmlinux' or " 314 "No vmlinux file%s\nwas found in the path.\n\n"
313 "--vmlinux vmlinux.\n", 315 "Please use:\n\n"
316 " perf buildid-cache -av vmlinux\n\n"
317 "or:\n\n"
318 " --vmlinux vmlinux",
314 sym->name, build_id_msg ?: ""); 319 sym->name, build_id_msg ?: "");
315 goto out_free_filename; 320 goto out_free_filename;
316 } 321 }
@@ -323,10 +328,15 @@ fallback:
323 dso, dso->long_name, sym, sym->name); 328 dso, dso->long_name, sym, sym->name);
324 329
325 snprintf(command, sizeof(command), 330 snprintf(command, sizeof(command),
326 "objdump --start-address=0x%016" PRIx64 331 "objdump %s%s --start-address=0x%016" PRIx64
327 " --stop-address=0x%016" PRIx64 " -dS -C %s|grep -v %s|expand", 332 " --stop-address=0x%016" PRIx64
333 " -d %s %s -C %s|grep -v %s|expand",
334 disassembler_style ? "-M " : "",
335 disassembler_style ? disassembler_style : "",
328 map__rip_2objdump(map, sym->start), 336 map__rip_2objdump(map, sym->start),
329 map__rip_2objdump(map, sym->end), 337 map__rip_2objdump(map, sym->end),
338 symbol_conf.annotate_asm_raw ? "" : "--no-show-raw",
339 symbol_conf.annotate_src ? "-S" : "",
330 symfs_filename, filename); 340 symfs_filename, filename);
331 341
332 pr_debug("Executing: %s\n", command); 342 pr_debug("Executing: %s\n", command);
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index c2c286896801..d9072523d342 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -91,13 +91,18 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
91#ifdef NO_NEWT_SUPPORT 91#ifdef NO_NEWT_SUPPORT
92static inline int symbol__tui_annotate(struct symbol *sym __used, 92static inline int symbol__tui_annotate(struct symbol *sym __used,
93 struct map *map __used, 93 struct map *map __used,
94 int evidx __used, int refresh __used) 94 int evidx __used,
95 void(*timer)(void *arg) __used,
96 void *arg __used, int delay_secs __used)
95{ 97{
96 return 0; 98 return 0;
97} 99}
98#else 100#else
99int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, 101int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
100 int refresh); 102 int nr_events, void(*timer)(void *arg), void *arg,
103 int delay_secs);
101#endif 104#endif
102 105
106extern const char *disassembler_style;
107
103#endif /* __PERF_ANNOTATE_H */ 108#endif /* __PERF_ANNOTATE_H */
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 1a79df9f739f..9b4ff16cac96 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -14,6 +14,11 @@ enum chain_mode {
14 CHAIN_GRAPH_REL 14 CHAIN_GRAPH_REL
15}; 15};
16 16
17enum chain_order {
18 ORDER_CALLER,
19 ORDER_CALLEE
20};
21
17struct callchain_node { 22struct callchain_node {
18 struct callchain_node *parent; 23 struct callchain_node *parent;
19 struct list_head siblings; 24 struct list_head siblings;
@@ -41,6 +46,7 @@ struct callchain_param {
41 u32 print_limit; 46 u32 print_limit;
42 double min_percent; 47 double min_percent;
43 sort_chain_func_t sort; 48 sort_chain_func_t sort;
49 enum chain_order order;
44}; 50};
45 51
46struct callchain_list { 52struct callchain_list {
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c
index e191eb9a667f..521c38a79190 100644
--- a/tools/perf/util/color.c
+++ b/tools/perf/util/color.c
@@ -200,7 +200,7 @@ static int __color_vfprintf(FILE *fp, const char *color, const char *fmt,
200 * Auto-detect: 200 * Auto-detect:
201 */ 201 */
202 if (perf_use_color_default < 0) { 202 if (perf_use_color_default < 0) {
203 if (isatty(1) || pager_in_use()) 203 if (isatty(fileno(fp)) || pager_in_use())
204 perf_use_color_default = 1; 204 perf_use_color_default = 1;
205 else 205 else
206 perf_use_color_default = 0; 206 perf_use_color_default = 0;
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index e02d78cae70f..80d9598db31a 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -341,7 +341,7 @@ const char *perf_config_dirname(const char *name, const char *value)
341 341
342static int perf_default_core_config(const char *var __used, const char *value __used) 342static int perf_default_core_config(const char *var __used, const char *value __used)
343{ 343{
344 /* Add other config variables here and to Documentation/config.txt. */ 344 /* Add other config variables here. */
345 return 0; 345 return 0;
346} 346}
347 347
@@ -350,7 +350,7 @@ int perf_default_config(const char *var, const char *value, void *dummy __used)
350 if (!prefixcmp(var, "core.")) 350 if (!prefixcmp(var, "core."))
351 return perf_default_core_config(var, value); 351 return perf_default_core_config(var, value);
352 352
353 /* Add other config variables here and to Documentation/config.txt. */ 353 /* Add other config variables here. */
354 return 0; 354 return 0;
355} 355}
356 356
@@ -399,7 +399,6 @@ static int perf_config_global(void)
399int perf_config(config_fn_t fn, void *data) 399int perf_config(config_fn_t fn, void *data)
400{ 400{
401 int ret = 0, found = 0; 401 int ret = 0, found = 0;
402 char *repo_config = NULL;
403 const char *home = NULL; 402 const char *home = NULL;
404 403
405 /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */ 404 /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */
@@ -414,19 +413,32 @@ int perf_config(config_fn_t fn, void *data)
414 home = getenv("HOME"); 413 home = getenv("HOME");
415 if (perf_config_global() && home) { 414 if (perf_config_global() && home) {
416 char *user_config = strdup(mkpath("%s/.perfconfig", home)); 415 char *user_config = strdup(mkpath("%s/.perfconfig", home));
417 if (!access(user_config, R_OK)) { 416 struct stat st;
418 ret += perf_config_from_file(fn, user_config, data); 417
419 found += 1; 418 if (user_config == NULL) {
419 warning("Not enough memory to process %s/.perfconfig, "
420 "ignoring it.", home);
421 goto out;
420 } 422 }
421 free(user_config);
422 }
423 423
424 repo_config = perf_pathdup("config"); 424 if (stat(user_config, &st) < 0)
425 if (!access(repo_config, R_OK)) { 425 goto out_free;
426 ret += perf_config_from_file(fn, repo_config, data); 426
427 if (st.st_uid && (st.st_uid != geteuid())) {
428 warning("File %s not owned by current user or root, "
429 "ignoring it.", user_config);
430 goto out_free;
431 }
432
433 if (!st.st_size)
434 goto out_free;
435
436 ret += perf_config_from_file(fn, user_config, data);
427 found += 1; 437 found += 1;
438out_free:
439 free(user_config);
428 } 440 }
429 free(repo_config); 441out:
430 if (found == 0) 442 if (found == 0)
431 return -1; 443 return -1;
432 return ret; 444 return ret;
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index 155749d74350..26817daa2961 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -47,19 +47,20 @@ int dump_printf(const char *fmt, ...)
47} 47}
48 48
49#ifdef NO_NEWT_SUPPORT 49#ifdef NO_NEWT_SUPPORT
50void ui__warning(const char *format, ...) 50int ui__warning(const char *format, ...)
51{ 51{
52 va_list args; 52 va_list args;
53 53
54 va_start(args, format); 54 va_start(args, format);
55 vfprintf(stderr, format, args); 55 vfprintf(stderr, format, args);
56 va_end(args); 56 va_end(args);
57 return 0;
57} 58}
58#endif 59#endif
59 60
60void ui__warning_paranoid(void) 61int ui__error_paranoid(void)
61{ 62{
62 ui__warning("Permission error - are you root?\n" 63 return ui__error("Permission error - are you root?\n"
63 "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n" 64 "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n"
64 " -1 - Not paranoid at all\n" 65 " -1 - Not paranoid at all\n"
65 " 0 - Disallow raw tracepoint access for unpriv\n" 66 " 0 - Disallow raw tracepoint access for unpriv\n"
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index fd53db47e3de..f2ce88d04f54 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -19,23 +19,18 @@ static inline int ui_helpline__show_help(const char *format __used, va_list ap _
19 return 0; 19 return 0;
20} 20}
21 21
22static inline struct ui_progress *ui_progress__new(const char *title __used, 22static inline void ui_progress__update(u64 curr __used, u64 total __used,
23 u64 total __used) 23 const char *title __used) {}
24{
25 return (struct ui_progress *)1;
26}
27
28static inline void ui_progress__update(struct ui_progress *self __used,
29 u64 curr __used) {}
30 24
31static inline void ui_progress__delete(struct ui_progress *self __used) {} 25#define ui__error(format, arg...) ui__warning(format, ##arg)
32#else 26#else
33extern char ui_helpline__last_msg[]; 27extern char ui_helpline__last_msg[];
34int ui_helpline__show_help(const char *format, va_list ap); 28int ui_helpline__show_help(const char *format, va_list ap);
35#include "ui/progress.h" 29#include "ui/progress.h"
30int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2)));
36#endif 31#endif
37 32
38void ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); 33int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2)));
39void ui__warning_paranoid(void); 34int ui__error_paranoid(void);
40 35
41#endif /* __PERF_DEBUG_H */ 36#endif /* __PERF_DEBUG_H */
diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c
new file mode 100644
index 000000000000..ee51e9b4dc09
--- /dev/null
+++ b/tools/perf/util/dwarf-aux.c
@@ -0,0 +1,843 @@
1/*
2 * dwarf-aux.c : libdw auxiliary interfaces
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 *
18 */
19
20#include <stdbool.h>
21#include "util.h"
22#include "debug.h"
23#include "dwarf-aux.h"
24
25/**
26 * cu_find_realpath - Find the realpath of the target file
27 * @cu_die: A DIE(dwarf information entry) of CU(compilation Unit)
28 * @fname: The tail filename of the target file
29 *
30 * Find the real(long) path of @fname in @cu_die.
31 */
32const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname)
33{
34 Dwarf_Files *files;
35 size_t nfiles, i;
36 const char *src = NULL;
37 int ret;
38
39 if (!fname)
40 return NULL;
41
42 ret = dwarf_getsrcfiles(cu_die, &files, &nfiles);
43 if (ret != 0)
44 return NULL;
45
46 for (i = 0; i < nfiles; i++) {
47 src = dwarf_filesrc(files, i, NULL, NULL);
48 if (strtailcmp(src, fname) == 0)
49 break;
50 }
51 if (i == nfiles)
52 return NULL;
53 return src;
54}
55
56/**
57 * cu_get_comp_dir - Get the path of compilation directory
58 * @cu_die: a CU DIE
59 *
60 * Get the path of compilation directory of given @cu_die.
61 * Since this depends on DW_AT_comp_dir, older gcc will not
62 * embedded it. In that case, this returns NULL.
63 */
64const char *cu_get_comp_dir(Dwarf_Die *cu_die)
65{
66 Dwarf_Attribute attr;
67 if (dwarf_attr(cu_die, DW_AT_comp_dir, &attr) == NULL)
68 return NULL;
69 return dwarf_formstring(&attr);
70}
71
72/**
73 * cu_find_lineinfo - Get a line number and file name for given address
74 * @cu_die: a CU DIE
75 * @addr: An address
76 * @fname: a pointer which returns the file name string
77 * @lineno: a pointer which returns the line number
78 *
79 * Find a line number and file name for @addr in @cu_die.
80 */
81int cu_find_lineinfo(Dwarf_Die *cu_die, unsigned long addr,
82 const char **fname, int *lineno)
83{
84 Dwarf_Line *line;
85 Dwarf_Addr laddr;
86
87 line = dwarf_getsrc_die(cu_die, (Dwarf_Addr)addr);
88 if (line && dwarf_lineaddr(line, &laddr) == 0 &&
89 addr == (unsigned long)laddr && dwarf_lineno(line, lineno) == 0) {
90 *fname = dwarf_linesrc(line, NULL, NULL);
91 if (!*fname)
92 /* line number is useless without filename */
93 *lineno = 0;
94 }
95
96 return *lineno ?: -ENOENT;
97}
98
99static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data);
100
101/**
102 * cu_walk_functions_at - Walk on function DIEs at given address
103 * @cu_die: A CU DIE
104 * @addr: An address
105 * @callback: A callback which called with found DIEs
106 * @data: A user data
107 *
108 * Walk on function DIEs at given @addr in @cu_die. Passed DIEs
109 * should be subprogram or inlined-subroutines.
110 */
111int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr,
112 int (*callback)(Dwarf_Die *, void *), void *data)
113{
114 Dwarf_Die die_mem;
115 Dwarf_Die *sc_die;
116 int ret = -ENOENT;
117
118 /* Inlined function could be recursive. Trace it until fail */
119 for (sc_die = die_find_realfunc(cu_die, addr, &die_mem);
120 sc_die != NULL;
121 sc_die = die_find_child(sc_die, __die_find_inline_cb, &addr,
122 &die_mem)) {
123 ret = callback(sc_die, data);
124 if (ret)
125 break;
126 }
127
128 return ret;
129
130}
131
132/**
133 * die_compare_name - Compare diename and tname
134 * @dw_die: a DIE
135 * @tname: a string of target name
136 *
137 * Compare the name of @dw_die and @tname. Return false if @dw_die has no name.
138 */
139bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
140{
141 const char *name;
142 name = dwarf_diename(dw_die);
143 return name ? (strcmp(tname, name) == 0) : false;
144}
145
146/**
147 * die_get_call_lineno - Get callsite line number of inline-function instance
148 * @in_die: a DIE of an inlined function instance
149 *
150 * Get call-site line number of @in_die. This means from where the inline
151 * function is called.
152 */
153int die_get_call_lineno(Dwarf_Die *in_die)
154{
155 Dwarf_Attribute attr;
156 Dwarf_Word ret;
157
158 if (!dwarf_attr(in_die, DW_AT_call_line, &attr))
159 return -ENOENT;
160
161 dwarf_formudata(&attr, &ret);
162 return (int)ret;
163}
164
165/**
166 * die_get_type - Get type DIE
167 * @vr_die: a DIE of a variable
168 * @die_mem: where to store a type DIE
169 *
170 * Get a DIE of the type of given variable (@vr_die), and store
171 * it to die_mem. Return NULL if fails to get a type DIE.
172 */
173Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
174{
175 Dwarf_Attribute attr;
176
177 if (dwarf_attr_integrate(vr_die, DW_AT_type, &attr) &&
178 dwarf_formref_die(&attr, die_mem))
179 return die_mem;
180 else
181 return NULL;
182}
183
184/* Get a type die, but skip qualifiers */
185static Dwarf_Die *__die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
186{
187 int tag;
188
189 do {
190 vr_die = die_get_type(vr_die, die_mem);
191 if (!vr_die)
192 break;
193 tag = dwarf_tag(vr_die);
194 } while (tag == DW_TAG_const_type ||
195 tag == DW_TAG_restrict_type ||
196 tag == DW_TAG_volatile_type ||
197 tag == DW_TAG_shared_type);
198
199 return vr_die;
200}
201
202/**
203 * die_get_real_type - Get a type die, but skip qualifiers and typedef
204 * @vr_die: a DIE of a variable
205 * @die_mem: where to store a type DIE
206 *
207 * Get a DIE of the type of given variable (@vr_die), and store
208 * it to die_mem. Return NULL if fails to get a type DIE.
209 * If the type is qualifiers (e.g. const) or typedef, this skips it
210 * and tries to find real type (structure or basic types, e.g. int).
211 */
212Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
213{
214 do {
215 vr_die = __die_get_real_type(vr_die, die_mem);
216 } while (vr_die && dwarf_tag(vr_die) == DW_TAG_typedef);
217
218 return vr_die;
219}
220
221/* Get attribute and translate it as a udata */
222static int die_get_attr_udata(Dwarf_Die *tp_die, unsigned int attr_name,
223 Dwarf_Word *result)
224{
225 Dwarf_Attribute attr;
226
227 if (dwarf_attr(tp_die, attr_name, &attr) == NULL ||
228 dwarf_formudata(&attr, result) != 0)
229 return -ENOENT;
230
231 return 0;
232}
233
234/* Get attribute and translate it as a sdata */
235static int die_get_attr_sdata(Dwarf_Die *tp_die, unsigned int attr_name,
236 Dwarf_Sword *result)
237{
238 Dwarf_Attribute attr;
239
240 if (dwarf_attr(tp_die, attr_name, &attr) == NULL ||
241 dwarf_formsdata(&attr, result) != 0)
242 return -ENOENT;
243
244 return 0;
245}
246
247/**
248 * die_is_signed_type - Check whether a type DIE is signed or not
249 * @tp_die: a DIE of a type
250 *
251 * Get the encoding of @tp_die and return true if the encoding
252 * is signed.
253 */
254bool die_is_signed_type(Dwarf_Die *tp_die)
255{
256 Dwarf_Word ret;
257
258 if (die_get_attr_udata(tp_die, DW_AT_encoding, &ret))
259 return false;
260
261 return (ret == DW_ATE_signed_char || ret == DW_ATE_signed ||
262 ret == DW_ATE_signed_fixed);
263}
264
265/**
266 * die_get_data_member_location - Get the data-member offset
267 * @mb_die: a DIE of a member of a data structure
268 * @offs: The offset of the member in the data structure
269 *
270 * Get the offset of @mb_die in the data structure including @mb_die, and
271 * stores result offset to @offs. If any error occurs this returns errno.
272 */
273int die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs)
274{
275 Dwarf_Attribute attr;
276 Dwarf_Op *expr;
277 size_t nexpr;
278 int ret;
279
280 if (dwarf_attr(mb_die, DW_AT_data_member_location, &attr) == NULL)
281 return -ENOENT;
282
283 if (dwarf_formudata(&attr, offs) != 0) {
284 /* DW_AT_data_member_location should be DW_OP_plus_uconst */
285 ret = dwarf_getlocation(&attr, &expr, &nexpr);
286 if (ret < 0 || nexpr == 0)
287 return -ENOENT;
288
289 if (expr[0].atom != DW_OP_plus_uconst || nexpr != 1) {
290 pr_debug("Unable to get offset:Unexpected OP %x (%zd)\n",
291 expr[0].atom, nexpr);
292 return -ENOTSUP;
293 }
294 *offs = (Dwarf_Word)expr[0].number;
295 }
296 return 0;
297}
298
299/* Get the call file index number in CU DIE */
300static int die_get_call_fileno(Dwarf_Die *in_die)
301{
302 Dwarf_Sword idx;
303
304 if (die_get_attr_sdata(in_die, DW_AT_call_file, &idx) == 0)
305 return (int)idx;
306 else
307 return -ENOENT;
308}
309
310/* Get the declared file index number in CU DIE */
311static int die_get_decl_fileno(Dwarf_Die *pdie)
312{
313 Dwarf_Sword idx;
314
315 if (die_get_attr_sdata(pdie, DW_AT_decl_file, &idx) == 0)
316 return (int)idx;
317 else
318 return -ENOENT;
319}
320
321/**
322 * die_get_call_file - Get callsite file name of inlined function instance
323 * @in_die: a DIE of an inlined function instance
324 *
325 * Get call-site file name of @in_die. This means from which file the inline
326 * function is called.
327 */
328const char *die_get_call_file(Dwarf_Die *in_die)
329{
330 Dwarf_Die cu_die;
331 Dwarf_Files *files;
332 int idx;
333
334 idx = die_get_call_fileno(in_die);
335 if (idx < 0 || !dwarf_diecu(in_die, &cu_die, NULL, NULL) ||
336 dwarf_getsrcfiles(&cu_die, &files, NULL) != 0)
337 return NULL;
338
339 return dwarf_filesrc(files, idx, NULL, NULL);
340}
341
342
343/**
344 * die_find_child - Generic DIE search function in DIE tree
345 * @rt_die: a root DIE
346 * @callback: a callback function
347 * @data: a user data passed to the callback function
348 * @die_mem: a buffer for result DIE
349 *
350 * Trace DIE tree from @rt_die and call @callback for each child DIE.
351 * If @callback returns DIE_FIND_CB_END, this stores the DIE into
352 * @die_mem and returns it. If @callback returns DIE_FIND_CB_CONTINUE,
353 * this continues to trace the tree. Optionally, @callback can return
354 * DIE_FIND_CB_CHILD and DIE_FIND_CB_SIBLING, those means trace only
355 * the children and trace only the siblings respectively.
356 * Returns NULL if @callback can't find any appropriate DIE.
357 */
358Dwarf_Die *die_find_child(Dwarf_Die *rt_die,
359 int (*callback)(Dwarf_Die *, void *),
360 void *data, Dwarf_Die *die_mem)
361{
362 Dwarf_Die child_die;
363 int ret;
364
365 ret = dwarf_child(rt_die, die_mem);
366 if (ret != 0)
367 return NULL;
368
369 do {
370 ret = callback(die_mem, data);
371 if (ret == DIE_FIND_CB_END)
372 return die_mem;
373
374 if ((ret & DIE_FIND_CB_CHILD) &&
375 die_find_child(die_mem, callback, data, &child_die)) {
376 memcpy(die_mem, &child_die, sizeof(Dwarf_Die));
377 return die_mem;
378 }
379 } while ((ret & DIE_FIND_CB_SIBLING) &&
380 dwarf_siblingof(die_mem, die_mem) == 0);
381
382 return NULL;
383}
384
385struct __addr_die_search_param {
386 Dwarf_Addr addr;
387 Dwarf_Die *die_mem;
388};
389
390/* die_find callback for non-inlined function search */
391static int __die_search_func_cb(Dwarf_Die *fn_die, void *data)
392{
393 struct __addr_die_search_param *ad = data;
394
395 if (dwarf_tag(fn_die) == DW_TAG_subprogram &&
396 dwarf_haspc(fn_die, ad->addr)) {
397 memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die));
398 return DWARF_CB_ABORT;
399 }
400 return DWARF_CB_OK;
401}
402
403/**
404 * die_find_realfunc - Search a non-inlined function at given address
405 * @cu_die: a CU DIE which including @addr
406 * @addr: target address
407 * @die_mem: a buffer for result DIE
408 *
409 * Search a non-inlined function DIE which includes @addr. Stores the
410 * DIE to @die_mem and returns it if found. Returns NULl if failed.
411 */
412Dwarf_Die *die_find_realfunc(Dwarf_Die *cu_die, Dwarf_Addr addr,
413 Dwarf_Die *die_mem)
414{
415 struct __addr_die_search_param ad;
416 ad.addr = addr;
417 ad.die_mem = die_mem;
418 /* dwarf_getscopes can't find subprogram. */
419 if (!dwarf_getfuncs(cu_die, __die_search_func_cb, &ad, 0))
420 return NULL;
421 else
422 return die_mem;
423}
424
425/* die_find callback for inline function search */
426static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data)
427{
428 Dwarf_Addr *addr = data;
429
430 if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine &&
431 dwarf_haspc(die_mem, *addr))
432 return DIE_FIND_CB_END;
433
434 return DIE_FIND_CB_CONTINUE;
435}
436
437/**
438 * die_find_inlinefunc - Search an inlined function at given address
439 * @cu_die: a CU DIE which including @addr
440 * @addr: target address
441 * @die_mem: a buffer for result DIE
442 *
443 * Search an inlined function DIE which includes @addr. Stores the
444 * DIE to @die_mem and returns it if found. Returns NULl if failed.
445 * If several inlined functions are expanded recursively, this trace
446 * it and returns deepest one.
447 */
448Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
449 Dwarf_Die *die_mem)
450{
451 Dwarf_Die tmp_die;
452
453 sp_die = die_find_child(sp_die, __die_find_inline_cb, &addr, &tmp_die);
454 if (!sp_die)
455 return NULL;
456
457 /* Inlined function could be recursive. Trace it until fail */
458 while (sp_die) {
459 memcpy(die_mem, sp_die, sizeof(Dwarf_Die));
460 sp_die = die_find_child(sp_die, __die_find_inline_cb, &addr,
461 &tmp_die);
462 }
463
464 return die_mem;
465}
466
467struct __instance_walk_param {
468 void *addr;
469 int (*callback)(Dwarf_Die *, void *);
470 void *data;
471 int retval;
472};
473
474static int __die_walk_instances_cb(Dwarf_Die *inst, void *data)
475{
476 struct __instance_walk_param *iwp = data;
477 Dwarf_Attribute attr_mem;
478 Dwarf_Die origin_mem;
479 Dwarf_Attribute *attr;
480 Dwarf_Die *origin;
481 int tmp;
482
483 attr = dwarf_attr(inst, DW_AT_abstract_origin, &attr_mem);
484 if (attr == NULL)
485 return DIE_FIND_CB_CONTINUE;
486
487 origin = dwarf_formref_die(attr, &origin_mem);
488 if (origin == NULL || origin->addr != iwp->addr)
489 return DIE_FIND_CB_CONTINUE;
490
491 /* Ignore redundant instances */
492 if (dwarf_tag(inst) == DW_TAG_inlined_subroutine) {
493 dwarf_decl_line(origin, &tmp);
494 if (die_get_call_lineno(inst) == tmp) {
495 tmp = die_get_decl_fileno(origin);
496 if (die_get_call_fileno(inst) == tmp)
497 return DIE_FIND_CB_CONTINUE;
498 }
499 }
500
501 iwp->retval = iwp->callback(inst, iwp->data);
502
503 return (iwp->retval) ? DIE_FIND_CB_END : DIE_FIND_CB_CONTINUE;
504}
505
506/**
507 * die_walk_instances - Walk on instances of given DIE
508 * @or_die: an abstract original DIE
509 * @callback: a callback function which is called with instance DIE
510 * @data: user data
511 *
512 * Walk on the instances of give @in_die. @in_die must be an inlined function
513 * declartion. This returns the return value of @callback if it returns
514 * non-zero value, or -ENOENT if there is no instance.
515 */
516int die_walk_instances(Dwarf_Die *or_die, int (*callback)(Dwarf_Die *, void *),
517 void *data)
518{
519 Dwarf_Die cu_die;
520 Dwarf_Die die_mem;
521 struct __instance_walk_param iwp = {
522 .addr = or_die->addr,
523 .callback = callback,
524 .data = data,
525 .retval = -ENOENT,
526 };
527
528 if (dwarf_diecu(or_die, &cu_die, NULL, NULL) == NULL)
529 return -ENOENT;
530
531 die_find_child(&cu_die, __die_walk_instances_cb, &iwp, &die_mem);
532
533 return iwp.retval;
534}
535
536/* Line walker internal parameters */
537struct __line_walk_param {
538 bool recursive;
539 line_walk_callback_t callback;
540 void *data;
541 int retval;
542};
543
544static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data)
545{
546 struct __line_walk_param *lw = data;
547 Dwarf_Addr addr = 0;
548 const char *fname;
549 int lineno;
550
551 if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) {
552 fname = die_get_call_file(in_die);
553 lineno = die_get_call_lineno(in_die);
554 if (fname && lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) {
555 lw->retval = lw->callback(fname, lineno, addr, lw->data);
556 if (lw->retval != 0)
557 return DIE_FIND_CB_END;
558 }
559 }
560 if (!lw->recursive)
561 /* Don't need to search recursively */
562 return DIE_FIND_CB_SIBLING;
563
564 if (addr) {
565 fname = dwarf_decl_file(in_die);
566 if (fname && dwarf_decl_line(in_die, &lineno) == 0) {
567 lw->retval = lw->callback(fname, lineno, addr, lw->data);
568 if (lw->retval != 0)
569 return DIE_FIND_CB_END;
570 }
571 }
572
573 /* Continue to search nested inlined function call-sites */
574 return DIE_FIND_CB_CONTINUE;
575}
576
577/* Walk on lines of blocks included in given DIE */
578static int __die_walk_funclines(Dwarf_Die *sp_die, bool recursive,
579 line_walk_callback_t callback, void *data)
580{
581 struct __line_walk_param lw = {
582 .recursive = recursive,
583 .callback = callback,
584 .data = data,
585 .retval = 0,
586 };
587 Dwarf_Die die_mem;
588 Dwarf_Addr addr;
589 const char *fname;
590 int lineno;
591
592 /* Handle function declaration line */
593 fname = dwarf_decl_file(sp_die);
594 if (fname && dwarf_decl_line(sp_die, &lineno) == 0 &&
595 dwarf_entrypc(sp_die, &addr) == 0) {
596 lw.retval = callback(fname, lineno, addr, data);
597 if (lw.retval != 0)
598 goto done;
599 }
600 die_find_child(sp_die, __die_walk_funclines_cb, &lw, &die_mem);
601done:
602 return lw.retval;
603}
604
605static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data)
606{
607 struct __line_walk_param *lw = data;
608
609 lw->retval = __die_walk_funclines(sp_die, true, lw->callback, lw->data);
610 if (lw->retval != 0)
611 return DWARF_CB_ABORT;
612
613 return DWARF_CB_OK;
614}
615
616/**
617 * die_walk_lines - Walk on lines inside given DIE
618 * @rt_die: a root DIE (CU, subprogram or inlined_subroutine)
619 * @callback: callback routine
620 * @data: user data
621 *
622 * Walk on all lines inside given @rt_die and call @callback on each line.
623 * If the @rt_die is a function, walk only on the lines inside the function,
624 * otherwise @rt_die must be a CU DIE.
625 * Note that this walks not only dwarf line list, but also function entries
626 * and inline call-site.
627 */
628int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data)
629{
630 Dwarf_Lines *lines;
631 Dwarf_Line *line;
632 Dwarf_Addr addr;
633 const char *fname;
634 int lineno, ret = 0;
635 Dwarf_Die die_mem, *cu_die;
636 size_t nlines, i;
637
638 /* Get the CU die */
639 if (dwarf_tag(rt_die) != DW_TAG_compile_unit)
640 cu_die = dwarf_diecu(rt_die, &die_mem, NULL, NULL);
641 else
642 cu_die = rt_die;
643 if (!cu_die) {
644 pr_debug2("Failed to get CU from given DIE.\n");
645 return -EINVAL;
646 }
647
648 /* Get lines list in the CU */
649 if (dwarf_getsrclines(cu_die, &lines, &nlines) != 0) {
650 pr_debug2("Failed to get source lines on this CU.\n");
651 return -ENOENT;
652 }
653 pr_debug2("Get %zd lines from this CU\n", nlines);
654
655 /* Walk on the lines on lines list */
656 for (i = 0; i < nlines; i++) {
657 line = dwarf_onesrcline(lines, i);
658 if (line == NULL ||
659 dwarf_lineno(line, &lineno) != 0 ||
660 dwarf_lineaddr(line, &addr) != 0) {
661 pr_debug2("Failed to get line info. "
662 "Possible error in debuginfo.\n");
663 continue;
664 }
665 /* Filter lines based on address */
666 if (rt_die != cu_die)
667 /*
668 * Address filtering
669 * The line is included in given function, and
670 * no inline block includes it.
671 */
672 if (!dwarf_haspc(rt_die, addr) ||
673 die_find_inlinefunc(rt_die, addr, &die_mem))
674 continue;
675 /* Get source line */
676 fname = dwarf_linesrc(line, NULL, NULL);
677
678 ret = callback(fname, lineno, addr, data);
679 if (ret != 0)
680 return ret;
681 }
682
683 /*
684 * Dwarf lines doesn't include function declarations and inlined
685 * subroutines. We have to check functions list or given function.
686 */
687 if (rt_die != cu_die)
688 /*
689 * Don't need walk functions recursively, because nested
690 * inlined functions don't have lines of the specified DIE.
691 */
692 ret = __die_walk_funclines(rt_die, false, callback, data);
693 else {
694 struct __line_walk_param param = {
695 .callback = callback,
696 .data = data,
697 .retval = 0,
698 };
699 dwarf_getfuncs(cu_die, __die_walk_culines_cb, &param, 0);
700 ret = param.retval;
701 }
702
703 return ret;
704}
705
706struct __find_variable_param {
707 const char *name;
708 Dwarf_Addr addr;
709};
710
711static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data)
712{
713 struct __find_variable_param *fvp = data;
714 int tag;
715
716 tag = dwarf_tag(die_mem);
717 if ((tag == DW_TAG_formal_parameter ||
718 tag == DW_TAG_variable) &&
719 die_compare_name(die_mem, fvp->name))
720 return DIE_FIND_CB_END;
721
722 if (dwarf_haspc(die_mem, fvp->addr))
723 return DIE_FIND_CB_CONTINUE;
724 else
725 return DIE_FIND_CB_SIBLING;
726}
727
728/**
729 * die_find_variable_at - Find a given name variable at given address
730 * @sp_die: a function DIE
731 * @name: variable name
732 * @addr: address
733 * @die_mem: a buffer for result DIE
734 *
735 * Find a variable DIE called @name at @addr in @sp_die.
736 */
737Dwarf_Die *die_find_variable_at(Dwarf_Die *sp_die, const char *name,
738 Dwarf_Addr addr, Dwarf_Die *die_mem)
739{
740 struct __find_variable_param fvp = { .name = name, .addr = addr};
741
742 return die_find_child(sp_die, __die_find_variable_cb, (void *)&fvp,
743 die_mem);
744}
745
746static int __die_find_member_cb(Dwarf_Die *die_mem, void *data)
747{
748 const char *name = data;
749
750 if ((dwarf_tag(die_mem) == DW_TAG_member) &&
751 die_compare_name(die_mem, name))
752 return DIE_FIND_CB_END;
753
754 return DIE_FIND_CB_SIBLING;
755}
756
757/**
758 * die_find_member - Find a given name member in a data structure
759 * @st_die: a data structure type DIE
760 * @name: member name
761 * @die_mem: a buffer for result DIE
762 *
763 * Find a member DIE called @name in @st_die.
764 */
765Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name,
766 Dwarf_Die *die_mem)
767{
768 return die_find_child(st_die, __die_find_member_cb, (void *)name,
769 die_mem);
770}
771
772/**
773 * die_get_typename - Get the name of given variable DIE
774 * @vr_die: a variable DIE
775 * @buf: a buffer for result type name
776 * @len: a max-length of @buf
777 *
778 * Get the name of @vr_die and stores it to @buf. Return the actual length
779 * of type name if succeeded. Return -E2BIG if @len is not enough long, and
780 * Return -ENOENT if failed to find type name.
781 * Note that the result will stores typedef name if possible, and stores
782 * "*(function_type)" if the type is a function pointer.
783 */
784int die_get_typename(Dwarf_Die *vr_die, char *buf, int len)
785{
786 Dwarf_Die type;
787 int tag, ret, ret2;
788 const char *tmp = "";
789
790 if (__die_get_real_type(vr_die, &type) == NULL)
791 return -ENOENT;
792
793 tag = dwarf_tag(&type);
794 if (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)
795 tmp = "*";
796 else if (tag == DW_TAG_subroutine_type) {
797 /* Function pointer */
798 ret = snprintf(buf, len, "(function_type)");
799 return (ret >= len) ? -E2BIG : ret;
800 } else {
801 if (!dwarf_diename(&type))
802 return -ENOENT;
803 if (tag == DW_TAG_union_type)
804 tmp = "union ";
805 else if (tag == DW_TAG_structure_type)
806 tmp = "struct ";
807 /* Write a base name */
808 ret = snprintf(buf, len, "%s%s", tmp, dwarf_diename(&type));
809 return (ret >= len) ? -E2BIG : ret;
810 }
811 ret = die_get_typename(&type, buf, len);
812 if (ret > 0) {
813 ret2 = snprintf(buf + ret, len - ret, "%s", tmp);
814 ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret;
815 }
816 return ret;
817}
818
819/**
820 * die_get_varname - Get the name and type of given variable DIE
821 * @vr_die: a variable DIE
822 * @buf: a buffer for type and variable name
823 * @len: the max-length of @buf
824 *
825 * Get the name and type of @vr_die and stores it in @buf as "type\tname".
826 */
827int die_get_varname(Dwarf_Die *vr_die, char *buf, int len)
828{
829 int ret, ret2;
830
831 ret = die_get_typename(vr_die, buf, len);
832 if (ret < 0) {
833 pr_debug("Failed to get type, make it unknown.\n");
834 ret = snprintf(buf, len, "(unknown_type)");
835 }
836 if (ret > 0) {
837 ret2 = snprintf(buf + ret, len - ret, "\t%s",
838 dwarf_diename(vr_die));
839 ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret;
840 }
841 return ret;
842}
843
diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h
new file mode 100644
index 000000000000..6ce1717784b7
--- /dev/null
+++ b/tools/perf/util/dwarf-aux.h
@@ -0,0 +1,111 @@
1#ifndef _DWARF_AUX_H
2#define _DWARF_AUX_H
3/*
4 * dwarf-aux.h : libdw auxiliary interfaces
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 *
20 */
21
22#include <dwarf.h>
23#include <elfutils/libdw.h>
24#include <elfutils/libdwfl.h>
25#include <elfutils/version.h>
26
27/* Find the realpath of the target file */
28extern const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname);
29
30/* Get DW_AT_comp_dir (should be NULL with older gcc) */
31extern const char *cu_get_comp_dir(Dwarf_Die *cu_die);
32
33/* Get a line number and file name for given address */
34extern int cu_find_lineinfo(Dwarf_Die *cudie, unsigned long addr,
35 const char **fname, int *lineno);
36
37/* Walk on funcitons at given address */
38extern int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr,
39 int (*callback)(Dwarf_Die *, void *), void *data);
40
41/* Compare diename and tname */
42extern bool die_compare_name(Dwarf_Die *dw_die, const char *tname);
43
44/* Get callsite line number of inline-function instance */
45extern int die_get_call_lineno(Dwarf_Die *in_die);
46
47/* Get callsite file name of inlined function instance */
48extern const char *die_get_call_file(Dwarf_Die *in_die);
49
50/* Get type die */
51extern Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem);
52
53/* Get a type die, but skip qualifiers and typedef */
54extern Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem);
55
56/* Check whether the DIE is signed or not */
57extern bool die_is_signed_type(Dwarf_Die *tp_die);
58
59/* Get data_member_location offset */
60extern int die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs);
61
62/* Return values for die_find_child() callbacks */
63enum {
64 DIE_FIND_CB_END = 0, /* End of Search */
65 DIE_FIND_CB_CHILD = 1, /* Search only children */
66 DIE_FIND_CB_SIBLING = 2, /* Search only siblings */
67 DIE_FIND_CB_CONTINUE = 3, /* Search children and siblings */
68};
69
70/* Search child DIEs */
71extern Dwarf_Die *die_find_child(Dwarf_Die *rt_die,
72 int (*callback)(Dwarf_Die *, void *),
73 void *data, Dwarf_Die *die_mem);
74
75/* Search a non-inlined function including given address */
76extern Dwarf_Die *die_find_realfunc(Dwarf_Die *cu_die, Dwarf_Addr addr,
77 Dwarf_Die *die_mem);
78
79/* Search an inlined function including given address */
80extern Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
81 Dwarf_Die *die_mem);
82
83/* Walk on the instances of given DIE */
84extern int die_walk_instances(Dwarf_Die *in_die,
85 int (*callback)(Dwarf_Die *, void *), void *data);
86
87/* Walker on lines (Note: line number will not be sorted) */
88typedef int (* line_walk_callback_t) (const char *fname, int lineno,
89 Dwarf_Addr addr, void *data);
90
91/*
92 * Walk on lines inside given DIE. If the DIE is a subprogram, walk only on
93 * the lines inside the subprogram, otherwise the DIE must be a CU DIE.
94 */
95extern int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback,
96 void *data);
97
98/* Find a variable called 'name' at given address */
99extern Dwarf_Die *die_find_variable_at(Dwarf_Die *sp_die, const char *name,
100 Dwarf_Addr addr, Dwarf_Die *die_mem);
101
102/* Find a member called 'name' */
103extern Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name,
104 Dwarf_Die *die_mem);
105
106/* Get the name of given variable DIE */
107extern int die_get_typename(Dwarf_Die *vr_die, char *buf, int len);
108
109/* Get the name and type of given variable DIE, stored as "type\tname" */
110extern int die_get_varname(Dwarf_Die *vr_die, char *buf, int len);
111#endif
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 3c1b8a632101..437f8ca679a0 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -169,12 +169,17 @@ static int perf_event__synthesize_mmap_events(union perf_event *event,
169 continue; 169 continue;
170 pbf += n + 3; 170 pbf += n + 3;
171 if (*pbf == 'x') { /* vm_exec */ 171 if (*pbf == 'x') { /* vm_exec */
172 char anonstr[] = "//anon\n";
172 char *execname = strchr(bf, '/'); 173 char *execname = strchr(bf, '/');
173 174
174 /* Catch VDSO */ 175 /* Catch VDSO */
175 if (execname == NULL) 176 if (execname == NULL)
176 execname = strstr(bf, "[vdso]"); 177 execname = strstr(bf, "[vdso]");
177 178
179 /* Catch anonymous mmaps */
180 if ((execname == NULL) && !strstr(bf, "["))
181 execname = anonstr;
182
178 if (execname == NULL) 183 if (execname == NULL)
179 continue; 184 continue;
180 185
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 1d7f66488a88..357a85b85248 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -186,6 +186,6 @@ const char *perf_event__name(unsigned int id);
186 186
187int perf_event__parse_sample(const union perf_event *event, u64 type, 187int perf_event__parse_sample(const union perf_event *event, u64 type,
188 int sample_size, bool sample_id_all, 188 int sample_size, bool sample_id_all,
189 struct perf_sample *sample); 189 struct perf_sample *sample, bool swapped);
190 190
191#endif /* __PERF_RECORD_H */ 191#endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index b021ea9265c3..fbb4b4ab9cc6 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -85,10 +85,45 @@ int perf_evlist__add_default(struct perf_evlist *evlist)
85 struct perf_evsel *evsel = perf_evsel__new(&attr, 0); 85 struct perf_evsel *evsel = perf_evsel__new(&attr, 0);
86 86
87 if (evsel == NULL) 87 if (evsel == NULL)
88 return -ENOMEM; 88 goto error;
89
90 /* use strdup() because free(evsel) assumes name is allocated */
91 evsel->name = strdup("cycles");
92 if (!evsel->name)
93 goto error_free;
89 94
90 perf_evlist__add(evlist, evsel); 95 perf_evlist__add(evlist, evsel);
91 return 0; 96 return 0;
97error_free:
98 perf_evsel__delete(evsel);
99error:
100 return -ENOMEM;
101}
102
103void perf_evlist__disable(struct perf_evlist *evlist)
104{
105 int cpu, thread;
106 struct perf_evsel *pos;
107
108 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
109 list_for_each_entry(pos, &evlist->entries, node) {
110 for (thread = 0; thread < evlist->threads->nr; thread++)
111 ioctl(FD(pos, cpu, thread), PERF_EVENT_IOC_DISABLE);
112 }
113 }
114}
115
116void perf_evlist__enable(struct perf_evlist *evlist)
117{
118 int cpu, thread;
119 struct perf_evsel *pos;
120
121 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
122 list_for_each_entry(pos, &evlist->entries, node) {
123 for (thread = 0; thread < evlist->threads->nr; thread++)
124 ioctl(FD(pos, cpu, thread), PERF_EVENT_IOC_ENABLE);
125 }
126 }
92} 127}
93 128
94int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) 129int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
@@ -498,3 +533,39 @@ bool perf_evlist__sample_id_all(const struct perf_evlist *evlist)
498 first = list_entry(evlist->entries.next, struct perf_evsel, node); 533 first = list_entry(evlist->entries.next, struct perf_evsel, node);
499 return first->attr.sample_id_all; 534 return first->attr.sample_id_all;
500} 535}
536
537void perf_evlist__set_selected(struct perf_evlist *evlist,
538 struct perf_evsel *evsel)
539{
540 evlist->selected = evsel;
541}
542
543int perf_evlist__open(struct perf_evlist *evlist, bool group)
544{
545 struct perf_evsel *evsel, *first;
546 int err, ncpus, nthreads;
547
548 first = list_entry(evlist->entries.next, struct perf_evsel, node);
549
550 list_for_each_entry(evsel, &evlist->entries, node) {
551 struct xyarray *group_fd = NULL;
552
553 if (group && evsel != first)
554 group_fd = first->fd;
555
556 err = perf_evsel__open(evsel, evlist->cpus, evlist->threads,
557 group, group_fd);
558 if (err < 0)
559 goto out_err;
560 }
561
562 return 0;
563out_err:
564 ncpus = evlist->cpus ? evlist->cpus->nr : 1;
565 nthreads = evlist->threads ? evlist->threads->nr : 1;
566
567 list_for_each_entry_reverse(evsel, &evlist->entries, node)
568 perf_evsel__close(evsel, ncpus, nthreads);
569
570 return err;
571}
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index b2b862374f37..1779ffef7828 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -25,6 +25,7 @@ struct perf_evlist {
25 struct pollfd *pollfd; 25 struct pollfd *pollfd;
26 struct thread_map *threads; 26 struct thread_map *threads;
27 struct cpu_map *cpus; 27 struct cpu_map *cpus;
28 struct perf_evsel *selected;
28}; 29};
29 30
30struct perf_evsel; 31struct perf_evsel;
@@ -49,10 +50,18 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id);
49 50
50union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx); 51union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx);
51 52
53int perf_evlist__open(struct perf_evlist *evlist, bool group);
54
52int perf_evlist__alloc_mmap(struct perf_evlist *evlist); 55int perf_evlist__alloc_mmap(struct perf_evlist *evlist);
53int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite); 56int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite);
54void perf_evlist__munmap(struct perf_evlist *evlist); 57void perf_evlist__munmap(struct perf_evlist *evlist);
55 58
59void perf_evlist__disable(struct perf_evlist *evlist);
60void perf_evlist__enable(struct perf_evlist *evlist);
61
62void perf_evlist__set_selected(struct perf_evlist *evlist,
63 struct perf_evsel *evsel);
64
56static inline void perf_evlist__set_maps(struct perf_evlist *evlist, 65static inline void perf_evlist__set_maps(struct perf_evlist *evlist,
57 struct cpu_map *cpus, 66 struct cpu_map *cpus,
58 struct thread_map *threads) 67 struct thread_map *threads)
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 0239eb87b232..e42626422587 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -7,6 +7,8 @@
7 * Released under the GPL v2. (and only v2, not any later version) 7 * Released under the GPL v2. (and only v2, not any later version)
8 */ 8 */
9 9
10#include <byteswap.h>
11#include "asm/bug.h"
10#include "evsel.h" 12#include "evsel.h"
11#include "evlist.h" 13#include "evlist.h"
12#include "util.h" 14#include "util.h"
@@ -14,6 +16,7 @@
14#include "thread_map.h" 16#include "thread_map.h"
15 17
16#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) 18#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
19#define GROUP_FD(group_fd, cpu) (*(int *)xyarray__entry(group_fd, cpu, 0))
17 20
18int __perf_evsel__sample_size(u64 sample_type) 21int __perf_evsel__sample_size(u64 sample_type)
19{ 22{
@@ -37,6 +40,7 @@ void perf_evsel__init(struct perf_evsel *evsel,
37 evsel->idx = idx; 40 evsel->idx = idx;
38 evsel->attr = *attr; 41 evsel->attr = *attr;
39 INIT_LIST_HEAD(&evsel->node); 42 INIT_LIST_HEAD(&evsel->node);
43 hists__init(&evsel->hists);
40} 44}
41 45
42struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) 46struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
@@ -201,15 +205,16 @@ int __perf_evsel__read(struct perf_evsel *evsel,
201} 205}
202 206
203static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, 207static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
204 struct thread_map *threads, bool group) 208 struct thread_map *threads, bool group,
209 struct xyarray *group_fds)
205{ 210{
206 int cpu, thread; 211 int cpu, thread;
207 unsigned long flags = 0; 212 unsigned long flags = 0;
208 int pid = -1; 213 int pid = -1, err;
209 214
210 if (evsel->fd == NULL && 215 if (evsel->fd == NULL &&
211 perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0) 216 perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0)
212 return -1; 217 return -ENOMEM;
213 218
214 if (evsel->cgrp) { 219 if (evsel->cgrp) {
215 flags = PERF_FLAG_PID_CGROUP; 220 flags = PERF_FLAG_PID_CGROUP;
@@ -217,7 +222,7 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
217 } 222 }
218 223
219 for (cpu = 0; cpu < cpus->nr; cpu++) { 224 for (cpu = 0; cpu < cpus->nr; cpu++) {
220 int group_fd = -1; 225 int group_fd = group_fds ? GROUP_FD(group_fds, cpu) : -1;
221 226
222 for (thread = 0; thread < threads->nr; thread++) { 227 for (thread = 0; thread < threads->nr; thread++) {
223 228
@@ -228,8 +233,10 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
228 pid, 233 pid,
229 cpus->map[cpu], 234 cpus->map[cpu],
230 group_fd, flags); 235 group_fd, flags);
231 if (FD(evsel, cpu, thread) < 0) 236 if (FD(evsel, cpu, thread) < 0) {
237 err = -errno;
232 goto out_close; 238 goto out_close;
239 }
233 240
234 if (group && group_fd == -1) 241 if (group && group_fd == -1)
235 group_fd = FD(evsel, cpu, thread); 242 group_fd = FD(evsel, cpu, thread);
@@ -246,7 +253,17 @@ out_close:
246 } 253 }
247 thread = threads->nr; 254 thread = threads->nr;
248 } while (--cpu >= 0); 255 } while (--cpu >= 0);
249 return -1; 256 return err;
257}
258
259void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads)
260{
261 if (evsel->fd == NULL)
262 return;
263
264 perf_evsel__close_fd(evsel, ncpus, nthreads);
265 perf_evsel__free_fd(evsel);
266 evsel->fd = NULL;
250} 267}
251 268
252static struct { 269static struct {
@@ -266,7 +283,8 @@ static struct {
266}; 283};
267 284
268int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, 285int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
269 struct thread_map *threads, bool group) 286 struct thread_map *threads, bool group,
287 struct xyarray *group_fd)
270{ 288{
271 if (cpus == NULL) { 289 if (cpus == NULL) {
272 /* Work around old compiler warnings about strict aliasing */ 290 /* Work around old compiler warnings about strict aliasing */
@@ -276,19 +294,23 @@ int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
276 if (threads == NULL) 294 if (threads == NULL)
277 threads = &empty_thread_map.map; 295 threads = &empty_thread_map.map;
278 296
279 return __perf_evsel__open(evsel, cpus, threads, group); 297 return __perf_evsel__open(evsel, cpus, threads, group, group_fd);
280} 298}
281 299
282int perf_evsel__open_per_cpu(struct perf_evsel *evsel, 300int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
283 struct cpu_map *cpus, bool group) 301 struct cpu_map *cpus, bool group,
302 struct xyarray *group_fd)
284{ 303{
285 return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group); 304 return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group,
305 group_fd);
286} 306}
287 307
288int perf_evsel__open_per_thread(struct perf_evsel *evsel, 308int perf_evsel__open_per_thread(struct perf_evsel *evsel,
289 struct thread_map *threads, bool group) 309 struct thread_map *threads, bool group,
310 struct xyarray *group_fd)
290{ 311{
291 return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group); 312 return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group,
313 group_fd);
292} 314}
293 315
294static int perf_event__parse_id_sample(const union perf_event *event, u64 type, 316static int perf_event__parse_id_sample(const union perf_event *event, u64 type,
@@ -342,10 +364,20 @@ static bool sample_overlap(const union perf_event *event,
342 364
343int perf_event__parse_sample(const union perf_event *event, u64 type, 365int perf_event__parse_sample(const union perf_event *event, u64 type,
344 int sample_size, bool sample_id_all, 366 int sample_size, bool sample_id_all,
345 struct perf_sample *data) 367 struct perf_sample *data, bool swapped)
346{ 368{
347 const u64 *array; 369 const u64 *array;
348 370
371 /*
372 * used for cross-endian analysis. See git commit 65014ab3
373 * for why this goofiness is needed.
374 */
375 union {
376 u64 val64;
377 u32 val32[2];
378 } u;
379
380
349 data->cpu = data->pid = data->tid = -1; 381 data->cpu = data->pid = data->tid = -1;
350 data->stream_id = data->id = data->time = -1ULL; 382 data->stream_id = data->id = data->time = -1ULL;
351 383
@@ -366,9 +398,16 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
366 } 398 }
367 399
368 if (type & PERF_SAMPLE_TID) { 400 if (type & PERF_SAMPLE_TID) {
369 u32 *p = (u32 *)array; 401 u.val64 = *array;
370 data->pid = p[0]; 402 if (swapped) {
371 data->tid = p[1]; 403 /* undo swap of u64, then swap on individual u32s */
404 u.val64 = bswap_64(u.val64);
405 u.val32[0] = bswap_32(u.val32[0]);
406 u.val32[1] = bswap_32(u.val32[1]);
407 }
408
409 data->pid = u.val32[0];
410 data->tid = u.val32[1];
372 array++; 411 array++;
373 } 412 }
374 413
@@ -377,6 +416,7 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
377 array++; 416 array++;
378 } 417 }
379 418
419 data->addr = 0;
380 if (type & PERF_SAMPLE_ADDR) { 420 if (type & PERF_SAMPLE_ADDR) {
381 data->addr = *array; 421 data->addr = *array;
382 array++; 422 array++;
@@ -394,8 +434,15 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
394 } 434 }
395 435
396 if (type & PERF_SAMPLE_CPU) { 436 if (type & PERF_SAMPLE_CPU) {
397 u32 *p = (u32 *)array; 437
398 data->cpu = *p; 438 u.val64 = *array;
439 if (swapped) {
440 /* undo swap of u64, then swap on individual u32s */
441 u.val64 = bswap_64(u.val64);
442 u.val32[0] = bswap_32(u.val32[0]);
443 }
444
445 data->cpu = u.val32[0];
399 array++; 446 array++;
400 } 447 }
401 448
@@ -422,18 +469,27 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
422 } 469 }
423 470
424 if (type & PERF_SAMPLE_RAW) { 471 if (type & PERF_SAMPLE_RAW) {
425 u32 *p = (u32 *)array; 472 const u64 *pdata;
473
474 u.val64 = *array;
475 if (WARN_ONCE(swapped,
476 "Endianness of raw data not corrected!\n")) {
477 /* undo swap of u64, then swap on individual u32s */
478 u.val64 = bswap_64(u.val64);
479 u.val32[0] = bswap_32(u.val32[0]);
480 u.val32[1] = bswap_32(u.val32[1]);
481 }
426 482
427 if (sample_overlap(event, array, sizeof(u32))) 483 if (sample_overlap(event, array, sizeof(u32)))
428 return -EFAULT; 484 return -EFAULT;
429 485
430 data->raw_size = *p; 486 data->raw_size = u.val32[0];
431 p++; 487 pdata = (void *) array + sizeof(u32);
432 488
433 if (sample_overlap(event, p, data->raw_size)) 489 if (sample_overlap(event, pdata, data->raw_size))
434 return -EFAULT; 490 return -EFAULT;
435 491
436 data->raw_data = p; 492 data->raw_data = (void *) pdata;
437 } 493 }
438 494
439 return 0; 495 return 0;
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 7e9366e4490b..b1d15e6f7ae3 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -61,6 +61,7 @@ struct perf_evsel {
61 off_t id_offset; 61 off_t id_offset;
62 }; 62 };
63 struct cgroup_sel *cgrp; 63 struct cgroup_sel *cgrp;
64 bool supported;
64}; 65};
65 66
66struct cpu_map; 67struct cpu_map;
@@ -81,11 +82,15 @@ void perf_evsel__free_id(struct perf_evsel *evsel);
81void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); 82void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
82 83
83int perf_evsel__open_per_cpu(struct perf_evsel *evsel, 84int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
84 struct cpu_map *cpus, bool group); 85 struct cpu_map *cpus, bool group,
86 struct xyarray *group_fds);
85int perf_evsel__open_per_thread(struct perf_evsel *evsel, 87int perf_evsel__open_per_thread(struct perf_evsel *evsel,
86 struct thread_map *threads, bool group); 88 struct thread_map *threads, bool group,
89 struct xyarray *group_fds);
87int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, 90int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
88 struct thread_map *threads, bool group); 91 struct thread_map *threads, bool group,
92 struct xyarray *group_fds);
93void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads);
89 94
90#define perf_evsel__match(evsel, t, c) \ 95#define perf_evsel__match(evsel, t, c) \
91 (evsel->attr.type == PERF_TYPE_##t && \ 96 (evsel->attr.type == PERF_TYPE_##t && \
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index afb0849fe530..bcd05d05b4f0 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1,5 +1,6 @@
1#define _FILE_OFFSET_BITS 64 1#define _FILE_OFFSET_BITS 64
2 2
3#include "util.h"
3#include <sys/types.h> 4#include <sys/types.h>
4#include <byteswap.h> 5#include <byteswap.h>
5#include <unistd.h> 6#include <unistd.h>
@@ -7,22 +8,29 @@
7#include <stdlib.h> 8#include <stdlib.h>
8#include <linux/list.h> 9#include <linux/list.h>
9#include <linux/kernel.h> 10#include <linux/kernel.h>
11#include <sys/utsname.h>
10 12
11#include "evlist.h" 13#include "evlist.h"
12#include "evsel.h" 14#include "evsel.h"
13#include "util.h"
14#include "header.h" 15#include "header.h"
15#include "../perf.h" 16#include "../perf.h"
16#include "trace-event.h" 17#include "trace-event.h"
17#include "session.h" 18#include "session.h"
18#include "symbol.h" 19#include "symbol.h"
19#include "debug.h" 20#include "debug.h"
21#include "cpumap.h"
20 22
21static bool no_buildid_cache = false; 23static bool no_buildid_cache = false;
22 24
23static int event_count; 25static int event_count;
24static struct perf_trace_event_type *events; 26static struct perf_trace_event_type *events;
25 27
28static u32 header_argc;
29static const char **header_argv;
30
31static int dsos__write_buildid_table(struct perf_header *header, int fd);
32static int perf_session__cache_build_ids(struct perf_session *session);
33
26int perf_header__push_event(u64 id, const char *name) 34int perf_header__push_event(u64 id, const char *name)
27{ 35{
28 if (strlen(name) > MAX_EVENT_NAME) 36 if (strlen(name) > MAX_EVENT_NAME)
@@ -110,6 +118,1020 @@ static int write_padded(int fd, const void *bf, size_t count,
110 return err; 118 return err;
111} 119}
112 120
121static int do_write_string(int fd, const char *str)
122{
123 u32 len, olen;
124 int ret;
125
126 olen = strlen(str) + 1;
127 len = ALIGN(olen, NAME_ALIGN);
128
129 /* write len, incl. \0 */
130 ret = do_write(fd, &len, sizeof(len));
131 if (ret < 0)
132 return ret;
133
134 return write_padded(fd, str, olen, len);
135}
136
137static char *do_read_string(int fd, struct perf_header *ph)
138{
139 ssize_t sz, ret;
140 u32 len;
141 char *buf;
142
143 sz = read(fd, &len, sizeof(len));
144 if (sz < (ssize_t)sizeof(len))
145 return NULL;
146
147 if (ph->needs_swap)
148 len = bswap_32(len);
149
150 buf = malloc(len);
151 if (!buf)
152 return NULL;
153
154 ret = read(fd, buf, len);
155 if (ret == (ssize_t)len) {
156 /*
157 * strings are padded by zeroes
158 * thus the actual strlen of buf
159 * may be less than len
160 */
161 return buf;
162 }
163
164 free(buf);
165 return NULL;
166}
167
168int
169perf_header__set_cmdline(int argc, const char **argv)
170{
171 int i;
172
173 header_argc = (u32)argc;
174
175 /* do not include NULL termination */
176 header_argv = calloc(argc, sizeof(char *));
177 if (!header_argv)
178 return -ENOMEM;
179
180 /*
181 * must copy argv contents because it gets moved
182 * around during option parsing
183 */
184 for (i = 0; i < argc ; i++)
185 header_argv[i] = argv[i];
186
187 return 0;
188}
189
190static int write_trace_info(int fd, struct perf_header *h __used,
191 struct perf_evlist *evlist)
192{
193 return read_tracing_data(fd, &evlist->entries);
194}
195
196
197static int write_build_id(int fd, struct perf_header *h,
198 struct perf_evlist *evlist __used)
199{
200 struct perf_session *session;
201 int err;
202
203 session = container_of(h, struct perf_session, header);
204
205 err = dsos__write_buildid_table(h, fd);
206 if (err < 0) {
207 pr_debug("failed to write buildid table\n");
208 return err;
209 }
210 if (!no_buildid_cache)
211 perf_session__cache_build_ids(session);
212
213 return 0;
214}
215
216static int write_hostname(int fd, struct perf_header *h __used,
217 struct perf_evlist *evlist __used)
218{
219 struct utsname uts;
220 int ret;
221
222 ret = uname(&uts);
223 if (ret < 0)
224 return -1;
225
226 return do_write_string(fd, uts.nodename);
227}
228
229static int write_osrelease(int fd, struct perf_header *h __used,
230 struct perf_evlist *evlist __used)
231{
232 struct utsname uts;
233 int ret;
234
235 ret = uname(&uts);
236 if (ret < 0)
237 return -1;
238
239 return do_write_string(fd, uts.release);
240}
241
242static int write_arch(int fd, struct perf_header *h __used,
243 struct perf_evlist *evlist __used)
244{
245 struct utsname uts;
246 int ret;
247
248 ret = uname(&uts);
249 if (ret < 0)
250 return -1;
251
252 return do_write_string(fd, uts.machine);
253}
254
255static int write_version(int fd, struct perf_header *h __used,
256 struct perf_evlist *evlist __used)
257{
258 return do_write_string(fd, perf_version_string);
259}
260
261static int write_cpudesc(int fd, struct perf_header *h __used,
262 struct perf_evlist *evlist __used)
263{
264#ifndef CPUINFO_PROC
265#define CPUINFO_PROC NULL
266#endif
267 FILE *file;
268 char *buf = NULL;
269 char *s, *p;
270 const char *search = CPUINFO_PROC;
271 size_t len = 0;
272 int ret = -1;
273
274 if (!search)
275 return -1;
276
277 file = fopen("/proc/cpuinfo", "r");
278 if (!file)
279 return -1;
280
281 while (getline(&buf, &len, file) > 0) {
282 ret = strncmp(buf, search, strlen(search));
283 if (!ret)
284 break;
285 }
286
287 if (ret)
288 goto done;
289
290 s = buf;
291
292 p = strchr(buf, ':');
293 if (p && *(p+1) == ' ' && *(p+2))
294 s = p + 2;
295 p = strchr(s, '\n');
296 if (p)
297 *p = '\0';
298
299 /* squash extra space characters (branding string) */
300 p = s;
301 while (*p) {
302 if (isspace(*p)) {
303 char *r = p + 1;
304 char *q = r;
305 *p = ' ';
306 while (*q && isspace(*q))
307 q++;
308 if (q != (p+1))
309 while ((*r++ = *q++));
310 }
311 p++;
312 }
313 ret = do_write_string(fd, s);
314done:
315 free(buf);
316 fclose(file);
317 return ret;
318}
319
320static int write_nrcpus(int fd, struct perf_header *h __used,
321 struct perf_evlist *evlist __used)
322{
323 long nr;
324 u32 nrc, nra;
325 int ret;
326
327 nr = sysconf(_SC_NPROCESSORS_CONF);
328 if (nr < 0)
329 return -1;
330
331 nrc = (u32)(nr & UINT_MAX);
332
333 nr = sysconf(_SC_NPROCESSORS_ONLN);
334 if (nr < 0)
335 return -1;
336
337 nra = (u32)(nr & UINT_MAX);
338
339 ret = do_write(fd, &nrc, sizeof(nrc));
340 if (ret < 0)
341 return ret;
342
343 return do_write(fd, &nra, sizeof(nra));
344}
345
346static int write_event_desc(int fd, struct perf_header *h __used,
347 struct perf_evlist *evlist)
348{
349 struct perf_evsel *attr;
350 u32 nre = 0, nri, sz;
351 int ret;
352
353 list_for_each_entry(attr, &evlist->entries, node)
354 nre++;
355
356 /*
357 * write number of events
358 */
359 ret = do_write(fd, &nre, sizeof(nre));
360 if (ret < 0)
361 return ret;
362
363 /*
364 * size of perf_event_attr struct
365 */
366 sz = (u32)sizeof(attr->attr);
367 ret = do_write(fd, &sz, sizeof(sz));
368 if (ret < 0)
369 return ret;
370
371 list_for_each_entry(attr, &evlist->entries, node) {
372
373 ret = do_write(fd, &attr->attr, sz);
374 if (ret < 0)
375 return ret;
376 /*
377 * write number of unique id per event
378 * there is one id per instance of an event
379 *
380 * copy into an nri to be independent of the
381 * type of ids,
382 */
383 nri = attr->ids;
384 ret = do_write(fd, &nri, sizeof(nri));
385 if (ret < 0)
386 return ret;
387
388 /*
389 * write event string as passed on cmdline
390 */
391 ret = do_write_string(fd, attr->name);
392 if (ret < 0)
393 return ret;
394 /*
395 * write unique ids for this event
396 */
397 ret = do_write(fd, attr->id, attr->ids * sizeof(u64));
398 if (ret < 0)
399 return ret;
400 }
401 return 0;
402}
403
404static int write_cmdline(int fd, struct perf_header *h __used,
405 struct perf_evlist *evlist __used)
406{
407 char buf[MAXPATHLEN];
408 char proc[32];
409 u32 i, n;
410 int ret;
411
412 /*
413 * actual atual path to perf binary
414 */
415 sprintf(proc, "/proc/%d/exe", getpid());
416 ret = readlink(proc, buf, sizeof(buf));
417 if (ret <= 0)
418 return -1;
419
420 /* readlink() does not add null termination */
421 buf[ret] = '\0';
422
423 /* account for binary path */
424 n = header_argc + 1;
425
426 ret = do_write(fd, &n, sizeof(n));
427 if (ret < 0)
428 return ret;
429
430 ret = do_write_string(fd, buf);
431 if (ret < 0)
432 return ret;
433
434 for (i = 0 ; i < header_argc; i++) {
435 ret = do_write_string(fd, header_argv[i]);
436 if (ret < 0)
437 return ret;
438 }
439 return 0;
440}
441
442#define CORE_SIB_FMT \
443 "/sys/devices/system/cpu/cpu%d/topology/core_siblings_list"
444#define THRD_SIB_FMT \
445 "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list"
446
447struct cpu_topo {
448 u32 core_sib;
449 u32 thread_sib;
450 char **core_siblings;
451 char **thread_siblings;
452};
453
454static int build_cpu_topo(struct cpu_topo *tp, int cpu)
455{
456 FILE *fp;
457 char filename[MAXPATHLEN];
458 char *buf = NULL, *p;
459 size_t len = 0;
460 u32 i = 0;
461 int ret = -1;
462
463 sprintf(filename, CORE_SIB_FMT, cpu);
464 fp = fopen(filename, "r");
465 if (!fp)
466 return -1;
467
468 if (getline(&buf, &len, fp) <= 0)
469 goto done;
470
471 fclose(fp);
472
473 p = strchr(buf, '\n');
474 if (p)
475 *p = '\0';
476
477 for (i = 0; i < tp->core_sib; i++) {
478 if (!strcmp(buf, tp->core_siblings[i]))
479 break;
480 }
481 if (i == tp->core_sib) {
482 tp->core_siblings[i] = buf;
483 tp->core_sib++;
484 buf = NULL;
485 len = 0;
486 }
487
488 sprintf(filename, THRD_SIB_FMT, cpu);
489 fp = fopen(filename, "r");
490 if (!fp)
491 goto done;
492
493 if (getline(&buf, &len, fp) <= 0)
494 goto done;
495
496 p = strchr(buf, '\n');
497 if (p)
498 *p = '\0';
499
500 for (i = 0; i < tp->thread_sib; i++) {
501 if (!strcmp(buf, tp->thread_siblings[i]))
502 break;
503 }
504 if (i == tp->thread_sib) {
505 tp->thread_siblings[i] = buf;
506 tp->thread_sib++;
507 buf = NULL;
508 }
509 ret = 0;
510done:
511 if(fp)
512 fclose(fp);
513 free(buf);
514 return ret;
515}
516
517static void free_cpu_topo(struct cpu_topo *tp)
518{
519 u32 i;
520
521 if (!tp)
522 return;
523
524 for (i = 0 ; i < tp->core_sib; i++)
525 free(tp->core_siblings[i]);
526
527 for (i = 0 ; i < tp->thread_sib; i++)
528 free(tp->thread_siblings[i]);
529
530 free(tp);
531}
532
533static struct cpu_topo *build_cpu_topology(void)
534{
535 struct cpu_topo *tp;
536 void *addr;
537 u32 nr, i;
538 size_t sz;
539 long ncpus;
540 int ret = -1;
541
542 ncpus = sysconf(_SC_NPROCESSORS_CONF);
543 if (ncpus < 0)
544 return NULL;
545
546 nr = (u32)(ncpus & UINT_MAX);
547
548 sz = nr * sizeof(char *);
549
550 addr = calloc(1, sizeof(*tp) + 2 * sz);
551 if (!addr)
552 return NULL;
553
554 tp = addr;
555
556 addr += sizeof(*tp);
557 tp->core_siblings = addr;
558 addr += sz;
559 tp->thread_siblings = addr;
560
561 for (i = 0; i < nr; i++) {
562 ret = build_cpu_topo(tp, i);
563 if (ret < 0)
564 break;
565 }
566 if (ret) {
567 free_cpu_topo(tp);
568 tp = NULL;
569 }
570 return tp;
571}
572
573static int write_cpu_topology(int fd, struct perf_header *h __used,
574 struct perf_evlist *evlist __used)
575{
576 struct cpu_topo *tp;
577 u32 i;
578 int ret;
579
580 tp = build_cpu_topology();
581 if (!tp)
582 return -1;
583
584 ret = do_write(fd, &tp->core_sib, sizeof(tp->core_sib));
585 if (ret < 0)
586 goto done;
587
588 for (i = 0; i < tp->core_sib; i++) {
589 ret = do_write_string(fd, tp->core_siblings[i]);
590 if (ret < 0)
591 goto done;
592 }
593 ret = do_write(fd, &tp->thread_sib, sizeof(tp->thread_sib));
594 if (ret < 0)
595 goto done;
596
597 for (i = 0; i < tp->thread_sib; i++) {
598 ret = do_write_string(fd, tp->thread_siblings[i]);
599 if (ret < 0)
600 break;
601 }
602done:
603 free_cpu_topo(tp);
604 return ret;
605}
606
607
608
609static int write_total_mem(int fd, struct perf_header *h __used,
610 struct perf_evlist *evlist __used)
611{
612 char *buf = NULL;
613 FILE *fp;
614 size_t len = 0;
615 int ret = -1, n;
616 uint64_t mem;
617
618 fp = fopen("/proc/meminfo", "r");
619 if (!fp)
620 return -1;
621
622 while (getline(&buf, &len, fp) > 0) {
623 ret = strncmp(buf, "MemTotal:", 9);
624 if (!ret)
625 break;
626 }
627 if (!ret) {
628 n = sscanf(buf, "%*s %"PRIu64, &mem);
629 if (n == 1)
630 ret = do_write(fd, &mem, sizeof(mem));
631 }
632 free(buf);
633 fclose(fp);
634 return ret;
635}
636
637static int write_topo_node(int fd, int node)
638{
639 char str[MAXPATHLEN];
640 char field[32];
641 char *buf = NULL, *p;
642 size_t len = 0;
643 FILE *fp;
644 u64 mem_total, mem_free, mem;
645 int ret = -1;
646
647 sprintf(str, "/sys/devices/system/node/node%d/meminfo", node);
648 fp = fopen(str, "r");
649 if (!fp)
650 return -1;
651
652 while (getline(&buf, &len, fp) > 0) {
653 /* skip over invalid lines */
654 if (!strchr(buf, ':'))
655 continue;
656 if (sscanf(buf, "%*s %*d %s %"PRIu64, field, &mem) != 2)
657 goto done;
658 if (!strcmp(field, "MemTotal:"))
659 mem_total = mem;
660 if (!strcmp(field, "MemFree:"))
661 mem_free = mem;
662 }
663
664 fclose(fp);
665
666 ret = do_write(fd, &mem_total, sizeof(u64));
667 if (ret)
668 goto done;
669
670 ret = do_write(fd, &mem_free, sizeof(u64));
671 if (ret)
672 goto done;
673
674 ret = -1;
675 sprintf(str, "/sys/devices/system/node/node%d/cpulist", node);
676
677 fp = fopen(str, "r");
678 if (!fp)
679 goto done;
680
681 if (getline(&buf, &len, fp) <= 0)
682 goto done;
683
684 p = strchr(buf, '\n');
685 if (p)
686 *p = '\0';
687
688 ret = do_write_string(fd, buf);
689done:
690 free(buf);
691 fclose(fp);
692 return ret;
693}
694
695static int write_numa_topology(int fd, struct perf_header *h __used,
696 struct perf_evlist *evlist __used)
697{
698 char *buf = NULL;
699 size_t len = 0;
700 FILE *fp;
701 struct cpu_map *node_map = NULL;
702 char *c;
703 u32 nr, i, j;
704 int ret = -1;
705
706 fp = fopen("/sys/devices/system/node/online", "r");
707 if (!fp)
708 return -1;
709
710 if (getline(&buf, &len, fp) <= 0)
711 goto done;
712
713 c = strchr(buf, '\n');
714 if (c)
715 *c = '\0';
716
717 node_map = cpu_map__new(buf);
718 if (!node_map)
719 goto done;
720
721 nr = (u32)node_map->nr;
722
723 ret = do_write(fd, &nr, sizeof(nr));
724 if (ret < 0)
725 goto done;
726
727 for (i = 0; i < nr; i++) {
728 j = (u32)node_map->map[i];
729 ret = do_write(fd, &j, sizeof(j));
730 if (ret < 0)
731 break;
732
733 ret = write_topo_node(fd, i);
734 if (ret < 0)
735 break;
736 }
737done:
738 free(buf);
739 fclose(fp);
740 free(node_map);
741 return ret;
742}
743
744/*
745 * default get_cpuid(): nothing gets recorded
746 * actual implementation must be in arch/$(ARCH)/util/header.c
747 */
748int __attribute__((weak)) get_cpuid(char *buffer __used, size_t sz __used)
749{
750 return -1;
751}
752
753static int write_cpuid(int fd, struct perf_header *h __used,
754 struct perf_evlist *evlist __used)
755{
756 char buffer[64];
757 int ret;
758
759 ret = get_cpuid(buffer, sizeof(buffer));
760 if (!ret)
761 goto write_it;
762
763 return -1;
764write_it:
765 return do_write_string(fd, buffer);
766}
767
768static void print_hostname(struct perf_header *ph, int fd, FILE *fp)
769{
770 char *str = do_read_string(fd, ph);
771 fprintf(fp, "# hostname : %s\n", str);
772 free(str);
773}
774
775static void print_osrelease(struct perf_header *ph, int fd, FILE *fp)
776{
777 char *str = do_read_string(fd, ph);
778 fprintf(fp, "# os release : %s\n", str);
779 free(str);
780}
781
782static void print_arch(struct perf_header *ph, int fd, FILE *fp)
783{
784 char *str = do_read_string(fd, ph);
785 fprintf(fp, "# arch : %s\n", str);
786 free(str);
787}
788
789static void print_cpudesc(struct perf_header *ph, int fd, FILE *fp)
790{
791 char *str = do_read_string(fd, ph);
792 fprintf(fp, "# cpudesc : %s\n", str);
793 free(str);
794}
795
796static void print_nrcpus(struct perf_header *ph, int fd, FILE *fp)
797{
798 ssize_t ret;
799 u32 nr;
800
801 ret = read(fd, &nr, sizeof(nr));
802 if (ret != (ssize_t)sizeof(nr))
803 nr = -1; /* interpreted as error */
804
805 if (ph->needs_swap)
806 nr = bswap_32(nr);
807
808 fprintf(fp, "# nrcpus online : %u\n", nr);
809
810 ret = read(fd, &nr, sizeof(nr));
811 if (ret != (ssize_t)sizeof(nr))
812 nr = -1; /* interpreted as error */
813
814 if (ph->needs_swap)
815 nr = bswap_32(nr);
816
817 fprintf(fp, "# nrcpus avail : %u\n", nr);
818}
819
820static void print_version(struct perf_header *ph, int fd, FILE *fp)
821{
822 char *str = do_read_string(fd, ph);
823 fprintf(fp, "# perf version : %s\n", str);
824 free(str);
825}
826
827static void print_cmdline(struct perf_header *ph, int fd, FILE *fp)
828{
829 ssize_t ret;
830 char *str;
831 u32 nr, i;
832
833 ret = read(fd, &nr, sizeof(nr));
834 if (ret != (ssize_t)sizeof(nr))
835 return;
836
837 if (ph->needs_swap)
838 nr = bswap_32(nr);
839
840 fprintf(fp, "# cmdline : ");
841
842 for (i = 0; i < nr; i++) {
843 str = do_read_string(fd, ph);
844 fprintf(fp, "%s ", str);
845 free(str);
846 }
847 fputc('\n', fp);
848}
849
850static void print_cpu_topology(struct perf_header *ph, int fd, FILE *fp)
851{
852 ssize_t ret;
853 u32 nr, i;
854 char *str;
855
856 ret = read(fd, &nr, sizeof(nr));
857 if (ret != (ssize_t)sizeof(nr))
858 return;
859
860 if (ph->needs_swap)
861 nr = bswap_32(nr);
862
863 for (i = 0; i < nr; i++) {
864 str = do_read_string(fd, ph);
865 fprintf(fp, "# sibling cores : %s\n", str);
866 free(str);
867 }
868
869 ret = read(fd, &nr, sizeof(nr));
870 if (ret != (ssize_t)sizeof(nr))
871 return;
872
873 if (ph->needs_swap)
874 nr = bswap_32(nr);
875
876 for (i = 0; i < nr; i++) {
877 str = do_read_string(fd, ph);
878 fprintf(fp, "# sibling threads : %s\n", str);
879 free(str);
880 }
881}
882
883static void print_event_desc(struct perf_header *ph, int fd, FILE *fp)
884{
885 struct perf_event_attr attr;
886 uint64_t id;
887 void *buf = NULL;
888 char *str;
889 u32 nre, sz, nr, i, j, msz;
890 int ret;
891
892 /* number of events */
893 ret = read(fd, &nre, sizeof(nre));
894 if (ret != (ssize_t)sizeof(nre))
895 goto error;
896
897 if (ph->needs_swap)
898 nre = bswap_32(nre);
899
900 ret = read(fd, &sz, sizeof(sz));
901 if (ret != (ssize_t)sizeof(sz))
902 goto error;
903
904 if (ph->needs_swap)
905 sz = bswap_32(sz);
906
907 /*
908 * ensure it is at least to our ABI rev
909 */
910 if (sz < (u32)sizeof(attr))
911 goto error;
912
913 memset(&attr, 0, sizeof(attr));
914
915 /* read entire region to sync up to next field */
916 buf = malloc(sz);
917 if (!buf)
918 goto error;
919
920 msz = sizeof(attr);
921 if (sz < msz)
922 msz = sz;
923
924 for (i = 0 ; i < nre; i++) {
925
926 ret = read(fd, buf, sz);
927 if (ret != (ssize_t)sz)
928 goto error;
929
930 if (ph->needs_swap)
931 perf_event__attr_swap(buf);
932
933 memcpy(&attr, buf, msz);
934
935 ret = read(fd, &nr, sizeof(nr));
936 if (ret != (ssize_t)sizeof(nr))
937 goto error;
938
939 if (ph->needs_swap)
940 nr = bswap_32(nr);
941
942 str = do_read_string(fd, ph);
943 fprintf(fp, "# event : name = %s, ", str);
944 free(str);
945
946 fprintf(fp, "type = %d, config = 0x%"PRIx64
947 ", config1 = 0x%"PRIx64", config2 = 0x%"PRIx64,
948 attr.type,
949 (u64)attr.config,
950 (u64)attr.config1,
951 (u64)attr.config2);
952
953 fprintf(fp, ", excl_usr = %d, excl_kern = %d",
954 attr.exclude_user,
955 attr.exclude_kernel);
956
957 if (nr)
958 fprintf(fp, ", id = {");
959
960 for (j = 0 ; j < nr; j++) {
961 ret = read(fd, &id, sizeof(id));
962 if (ret != (ssize_t)sizeof(id))
963 goto error;
964
965 if (ph->needs_swap)
966 id = bswap_64(id);
967
968 if (j)
969 fputc(',', fp);
970
971 fprintf(fp, " %"PRIu64, id);
972 }
973 if (nr && j == nr)
974 fprintf(fp, " }");
975 fputc('\n', fp);
976 }
977 free(buf);
978 return;
979error:
980 fprintf(fp, "# event desc: not available or unable to read\n");
981}
982
983static void print_total_mem(struct perf_header *h __used, int fd, FILE *fp)
984{
985 uint64_t mem;
986 ssize_t ret;
987
988 ret = read(fd, &mem, sizeof(mem));
989 if (ret != sizeof(mem))
990 goto error;
991
992 if (h->needs_swap)
993 mem = bswap_64(mem);
994
995 fprintf(fp, "# total memory : %"PRIu64" kB\n", mem);
996 return;
997error:
998 fprintf(fp, "# total memory : unknown\n");
999}
1000
1001static void print_numa_topology(struct perf_header *h __used, int fd, FILE *fp)
1002{
1003 ssize_t ret;
1004 u32 nr, c, i;
1005 char *str;
1006 uint64_t mem_total, mem_free;
1007
1008 /* nr nodes */
1009 ret = read(fd, &nr, sizeof(nr));
1010 if (ret != (ssize_t)sizeof(nr))
1011 goto error;
1012
1013 if (h->needs_swap)
1014 nr = bswap_32(nr);
1015
1016 for (i = 0; i < nr; i++) {
1017
1018 /* node number */
1019 ret = read(fd, &c, sizeof(c));
1020 if (ret != (ssize_t)sizeof(c))
1021 goto error;
1022
1023 if (h->needs_swap)
1024 c = bswap_32(c);
1025
1026 ret = read(fd, &mem_total, sizeof(u64));
1027 if (ret != sizeof(u64))
1028 goto error;
1029
1030 ret = read(fd, &mem_free, sizeof(u64));
1031 if (ret != sizeof(u64))
1032 goto error;
1033
1034 if (h->needs_swap) {
1035 mem_total = bswap_64(mem_total);
1036 mem_free = bswap_64(mem_free);
1037 }
1038
1039 fprintf(fp, "# node%u meminfo : total = %"PRIu64" kB,"
1040 " free = %"PRIu64" kB\n",
1041 c,
1042 mem_total,
1043 mem_free);
1044
1045 str = do_read_string(fd, h);
1046 fprintf(fp, "# node%u cpu list : %s\n", c, str);
1047 free(str);
1048 }
1049 return;
1050error:
1051 fprintf(fp, "# numa topology : not available\n");
1052}
1053
1054static void print_cpuid(struct perf_header *ph, int fd, FILE *fp)
1055{
1056 char *str = do_read_string(fd, ph);
1057 fprintf(fp, "# cpuid : %s\n", str);
1058 free(str);
1059}
1060
1061struct feature_ops {
1062 int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist);
1063 void (*print)(struct perf_header *h, int fd, FILE *fp);
1064 const char *name;
1065 bool full_only;
1066};
1067
1068#define FEAT_OPA(n, w, p) \
1069 [n] = { .name = #n, .write = w, .print = p }
1070#define FEAT_OPF(n, w, p) \
1071 [n] = { .name = #n, .write = w, .print = p, .full_only = true }
1072
1073static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
1074 FEAT_OPA(HEADER_TRACE_INFO, write_trace_info, NULL),
1075 FEAT_OPA(HEADER_BUILD_ID, write_build_id, NULL),
1076 FEAT_OPA(HEADER_HOSTNAME, write_hostname, print_hostname),
1077 FEAT_OPA(HEADER_OSRELEASE, write_osrelease, print_osrelease),
1078 FEAT_OPA(HEADER_VERSION, write_version, print_version),
1079 FEAT_OPA(HEADER_ARCH, write_arch, print_arch),
1080 FEAT_OPA(HEADER_NRCPUS, write_nrcpus, print_nrcpus),
1081 FEAT_OPA(HEADER_CPUDESC, write_cpudesc, print_cpudesc),
1082 FEAT_OPA(HEADER_CPUID, write_cpuid, print_cpuid),
1083 FEAT_OPA(HEADER_TOTAL_MEM, write_total_mem, print_total_mem),
1084 FEAT_OPA(HEADER_EVENT_DESC, write_event_desc, print_event_desc),
1085 FEAT_OPA(HEADER_CMDLINE, write_cmdline, print_cmdline),
1086 FEAT_OPF(HEADER_CPU_TOPOLOGY, write_cpu_topology, print_cpu_topology),
1087 FEAT_OPF(HEADER_NUMA_TOPOLOGY, write_numa_topology, print_numa_topology),
1088};
1089
1090struct header_print_data {
1091 FILE *fp;
1092 bool full; /* extended list of headers */
1093};
1094
1095static int perf_file_section__fprintf_info(struct perf_file_section *section,
1096 struct perf_header *ph,
1097 int feat, int fd, void *data)
1098{
1099 struct header_print_data *hd = data;
1100
1101 if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) {
1102 pr_debug("Failed to lseek to %" PRIu64 " offset for feature "
1103 "%d, continuing...\n", section->offset, feat);
1104 return 0;
1105 }
1106 if (feat < HEADER_TRACE_INFO || feat >= HEADER_LAST_FEATURE) {
1107 pr_warning("unknown feature %d\n", feat);
1108 return -1;
1109 }
1110 if (!feat_ops[feat].print)
1111 return 0;
1112
1113 if (!feat_ops[feat].full_only || hd->full)
1114 feat_ops[feat].print(ph, fd, hd->fp);
1115 else
1116 fprintf(hd->fp, "# %s info available, use -I to display\n",
1117 feat_ops[feat].name);
1118
1119 return 0;
1120}
1121
1122int perf_header__fprintf_info(struct perf_session *session, FILE *fp, bool full)
1123{
1124 struct header_print_data hd;
1125 struct perf_header *header = &session->header;
1126 int fd = session->fd;
1127 hd.fp = fp;
1128 hd.full = full;
1129
1130 perf_header__process_sections(header, fd, &hd,
1131 perf_file_section__fprintf_info);
1132 return 0;
1133}
1134
113#define dsos__for_each_with_build_id(pos, head) \ 1135#define dsos__for_each_with_build_id(pos, head) \
114 list_for_each_entry(pos, head, node) \ 1136 list_for_each_entry(pos, head, node) \
115 if (!pos->has_build_id) \ 1137 if (!pos->has_build_id) \
@@ -189,8 +1211,8 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
189 const char *name, bool is_kallsyms) 1211 const char *name, bool is_kallsyms)
190{ 1212{
191 const size_t size = PATH_MAX; 1213 const size_t size = PATH_MAX;
192 char *realname, *filename = malloc(size), 1214 char *realname, *filename = zalloc(size),
193 *linkname = malloc(size), *targetname; 1215 *linkname = zalloc(size), *targetname;
194 int len, err = -1; 1216 int len, err = -1;
195 1217
196 if (is_kallsyms) { 1218 if (is_kallsyms) {
@@ -254,8 +1276,8 @@ static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,
254int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir) 1276int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir)
255{ 1277{
256 const size_t size = PATH_MAX; 1278 const size_t size = PATH_MAX;
257 char *filename = malloc(size), 1279 char *filename = zalloc(size),
258 *linkname = malloc(size); 1280 *linkname = zalloc(size);
259 int err = -1; 1281 int err = -1;
260 1282
261 if (filename == NULL || linkname == NULL) 1283 if (filename == NULL || linkname == NULL)
@@ -267,7 +1289,7 @@ int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir)
267 if (access(linkname, F_OK)) 1289 if (access(linkname, F_OK))
268 goto out_free; 1290 goto out_free;
269 1291
270 if (readlink(linkname, filename, size) < 0) 1292 if (readlink(linkname, filename, size - 1) < 0)
271 goto out_free; 1293 goto out_free;
272 1294
273 if (unlink(linkname)) 1295 if (unlink(linkname))
@@ -356,15 +1378,41 @@ static bool perf_session__read_build_ids(struct perf_session *session, bool with
356 return ret; 1378 return ret;
357} 1379}
358 1380
1381static int do_write_feat(int fd, struct perf_header *h, int type,
1382 struct perf_file_section **p,
1383 struct perf_evlist *evlist)
1384{
1385 int err;
1386 int ret = 0;
1387
1388 if (perf_header__has_feat(h, type)) {
1389
1390 (*p)->offset = lseek(fd, 0, SEEK_CUR);
1391
1392 err = feat_ops[type].write(fd, h, evlist);
1393 if (err < 0) {
1394 pr_debug("failed to write feature %d\n", type);
1395
1396 /* undo anything written */
1397 lseek(fd, (*p)->offset, SEEK_SET);
1398
1399 return -1;
1400 }
1401 (*p)->size = lseek(fd, 0, SEEK_CUR) - (*p)->offset;
1402 (*p)++;
1403 }
1404 return ret;
1405}
1406
359static int perf_header__adds_write(struct perf_header *header, 1407static int perf_header__adds_write(struct perf_header *header,
360 struct perf_evlist *evlist, int fd) 1408 struct perf_evlist *evlist, int fd)
361{ 1409{
362 int nr_sections; 1410 int nr_sections;
363 struct perf_session *session; 1411 struct perf_session *session;
364 struct perf_file_section *feat_sec; 1412 struct perf_file_section *feat_sec, *p;
365 int sec_size; 1413 int sec_size;
366 u64 sec_start; 1414 u64 sec_start;
367 int idx = 0, err; 1415 int err;
368 1416
369 session = container_of(header, struct perf_session, header); 1417 session = container_of(header, struct perf_session, header);
370 1418
@@ -376,7 +1424,7 @@ static int perf_header__adds_write(struct perf_header *header,
376 if (!nr_sections) 1424 if (!nr_sections)
377 return 0; 1425 return 0;
378 1426
379 feat_sec = calloc(sizeof(*feat_sec), nr_sections); 1427 feat_sec = p = calloc(sizeof(*feat_sec), nr_sections);
380 if (feat_sec == NULL) 1428 if (feat_sec == NULL)
381 return -ENOMEM; 1429 return -ENOMEM;
382 1430
@@ -385,36 +1433,69 @@ static int perf_header__adds_write(struct perf_header *header,
385 sec_start = header->data_offset + header->data_size; 1433 sec_start = header->data_offset + header->data_size;
386 lseek(fd, sec_start + sec_size, SEEK_SET); 1434 lseek(fd, sec_start + sec_size, SEEK_SET);
387 1435
388 if (perf_header__has_feat(header, HEADER_TRACE_INFO)) { 1436 err = do_write_feat(fd, header, HEADER_TRACE_INFO, &p, evlist);
389 struct perf_file_section *trace_sec; 1437 if (err)
390 1438 goto out_free;
391 trace_sec = &feat_sec[idx++];
392 1439
393 /* Write trace info */ 1440 err = do_write_feat(fd, header, HEADER_BUILD_ID, &p, evlist);
394 trace_sec->offset = lseek(fd, 0, SEEK_CUR); 1441 if (err) {
395 read_tracing_data(fd, &evlist->entries); 1442 perf_header__clear_feat(header, HEADER_BUILD_ID);
396 trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset; 1443 goto out_free;
397 } 1444 }
398 1445
399 if (perf_header__has_feat(header, HEADER_BUILD_ID)) { 1446 err = do_write_feat(fd, header, HEADER_HOSTNAME, &p, evlist);
400 struct perf_file_section *buildid_sec; 1447 if (err)
1448 perf_header__clear_feat(header, HEADER_HOSTNAME);
401 1449
402 buildid_sec = &feat_sec[idx++]; 1450 err = do_write_feat(fd, header, HEADER_OSRELEASE, &p, evlist);
1451 if (err)
1452 perf_header__clear_feat(header, HEADER_OSRELEASE);
403 1453
404 /* Write build-ids */ 1454 err = do_write_feat(fd, header, HEADER_VERSION, &p, evlist);
405 buildid_sec->offset = lseek(fd, 0, SEEK_CUR); 1455 if (err)
406 err = dsos__write_buildid_table(header, fd); 1456 perf_header__clear_feat(header, HEADER_VERSION);
407 if (err < 0) { 1457
408 pr_debug("failed to write buildid table\n"); 1458 err = do_write_feat(fd, header, HEADER_ARCH, &p, evlist);
409 goto out_free; 1459 if (err)
410 } 1460 perf_header__clear_feat(header, HEADER_ARCH);
411 buildid_sec->size = lseek(fd, 0, SEEK_CUR) - 1461
412 buildid_sec->offset; 1462 err = do_write_feat(fd, header, HEADER_NRCPUS, &p, evlist);
413 if (!no_buildid_cache) 1463 if (err)
414 perf_session__cache_build_ids(session); 1464 perf_header__clear_feat(header, HEADER_NRCPUS);
415 } 1465
1466 err = do_write_feat(fd, header, HEADER_CPUDESC, &p, evlist);
1467 if (err)
1468 perf_header__clear_feat(header, HEADER_CPUDESC);
1469
1470 err = do_write_feat(fd, header, HEADER_CPUID, &p, evlist);
1471 if (err)
1472 perf_header__clear_feat(header, HEADER_CPUID);
1473
1474 err = do_write_feat(fd, header, HEADER_TOTAL_MEM, &p, evlist);
1475 if (err)
1476 perf_header__clear_feat(header, HEADER_TOTAL_MEM);
1477
1478 err = do_write_feat(fd, header, HEADER_CMDLINE, &p, evlist);
1479 if (err)
1480 perf_header__clear_feat(header, HEADER_CMDLINE);
1481
1482 err = do_write_feat(fd, header, HEADER_EVENT_DESC, &p, evlist);
1483 if (err)
1484 perf_header__clear_feat(header, HEADER_EVENT_DESC);
1485
1486 err = do_write_feat(fd, header, HEADER_CPU_TOPOLOGY, &p, evlist);
1487 if (err)
1488 perf_header__clear_feat(header, HEADER_CPU_TOPOLOGY);
1489
1490 err = do_write_feat(fd, header, HEADER_NUMA_TOPOLOGY, &p, evlist);
1491 if (err)
1492 perf_header__clear_feat(header, HEADER_NUMA_TOPOLOGY);
416 1493
417 lseek(fd, sec_start, SEEK_SET); 1494 lseek(fd, sec_start, SEEK_SET);
1495 /*
1496 * may write more than needed due to dropped feature, but
1497 * this is okay, reader will skip the mising entries
1498 */
418 err = do_write(fd, feat_sec, sec_size); 1499 err = do_write(fd, feat_sec, sec_size);
419 if (err < 0) 1500 if (err < 0)
420 pr_debug("failed to write feature section\n"); 1501 pr_debug("failed to write feature section\n");
@@ -554,9 +1635,10 @@ static int perf_header__getbuffer64(struct perf_header *header,
554} 1635}
555 1636
556int perf_header__process_sections(struct perf_header *header, int fd, 1637int perf_header__process_sections(struct perf_header *header, int fd,
1638 void *data,
557 int (*process)(struct perf_file_section *section, 1639 int (*process)(struct perf_file_section *section,
558 struct perf_header *ph, 1640 struct perf_header *ph,
559 int feat, int fd)) 1641 int feat, int fd, void *data))
560{ 1642{
561 struct perf_file_section *feat_sec; 1643 struct perf_file_section *feat_sec;
562 int nr_sections; 1644 int nr_sections;
@@ -584,7 +1666,7 @@ int perf_header__process_sections(struct perf_header *header, int fd,
584 if (perf_header__has_feat(header, feat)) { 1666 if (perf_header__has_feat(header, feat)) {
585 struct perf_file_section *sec = &feat_sec[idx++]; 1667 struct perf_file_section *sec = &feat_sec[idx++];
586 1668
587 err = process(sec, header, feat, fd); 1669 err = process(sec, header, feat, fd, data);
588 if (err < 0) 1670 if (err < 0)
589 break; 1671 break;
590 } 1672 }
@@ -621,21 +1703,41 @@ int perf_file_header__read(struct perf_file_header *header,
621 bitmap_zero(header->adds_features, HEADER_FEAT_BITS); 1703 bitmap_zero(header->adds_features, HEADER_FEAT_BITS);
622 else 1704 else
623 return -1; 1705 return -1;
1706 } else if (ph->needs_swap) {
1707 unsigned int i;
1708 /*
1709 * feature bitmap is declared as an array of unsigned longs --
1710 * not good since its size can differ between the host that
1711 * generated the data file and the host analyzing the file.
1712 *
1713 * We need to handle endianness, but we don't know the size of
1714 * the unsigned long where the file was generated. Take a best
1715 * guess at determining it: try 64-bit swap first (ie., file
1716 * created on a 64-bit host), and check if the hostname feature
1717 * bit is set (this feature bit is forced on as of fbe96f2).
1718 * If the bit is not, undo the 64-bit swap and try a 32-bit
1719 * swap. If the hostname bit is still not set (e.g., older data
1720 * file), punt and fallback to the original behavior --
1721 * clearing all feature bits and setting buildid.
1722 */
1723 for (i = 0; i < BITS_TO_LONGS(HEADER_FEAT_BITS); ++i)
1724 header->adds_features[i] = bswap_64(header->adds_features[i]);
1725
1726 if (!test_bit(HEADER_HOSTNAME, header->adds_features)) {
1727 for (i = 0; i < BITS_TO_LONGS(HEADER_FEAT_BITS); ++i) {
1728 header->adds_features[i] = bswap_64(header->adds_features[i]);
1729 header->adds_features[i] = bswap_32(header->adds_features[i]);
1730 }
1731 }
1732
1733 if (!test_bit(HEADER_HOSTNAME, header->adds_features)) {
1734 bitmap_zero(header->adds_features, HEADER_FEAT_BITS);
1735 set_bit(HEADER_BUILD_ID, header->adds_features);
1736 }
624 } 1737 }
625 1738
626 memcpy(&ph->adds_features, &header->adds_features, 1739 memcpy(&ph->adds_features, &header->adds_features,
627 sizeof(ph->adds_features)); 1740 sizeof(ph->adds_features));
628 /*
629 * FIXME: hack that assumes that if we need swap the perf.data file
630 * may be coming from an arch with a different word-size, ergo different
631 * DEFINE_BITMAP format, investigate more later, but for now its mostly
632 * safe to assume that we have a build-id section. Trace files probably
633 * have several other issues in this realm anyway...
634 */
635 if (ph->needs_swap) {
636 memset(&ph->adds_features, 0, sizeof(ph->adds_features));
637 perf_header__set_feat(ph, HEADER_BUILD_ID);
638 }
639 1741
640 ph->event_offset = header->event_types.offset; 1742 ph->event_offset = header->event_types.offset;
641 ph->event_size = header->event_types.size; 1743 ph->event_size = header->event_types.size;
@@ -726,7 +1828,16 @@ static int perf_header__read_build_ids_abi_quirk(struct perf_header *header,
726 return -1; 1828 return -1;
727 1829
728 bev.header = old_bev.header; 1830 bev.header = old_bev.header;
729 bev.pid = 0; 1831
1832 /*
1833 * As the pid is the missing value, we need to fill
1834 * it properly. The header.misc value give us nice hint.
1835 */
1836 bev.pid = HOST_KERNEL_ID;
1837 if (bev.header.misc == PERF_RECORD_MISC_GUEST_USER ||
1838 bev.header.misc == PERF_RECORD_MISC_GUEST_KERNEL)
1839 bev.pid = DEFAULT_GUEST_KERNEL_ID;
1840
730 memcpy(bev.build_id, old_bev.build_id, sizeof(bev.build_id)); 1841 memcpy(bev.build_id, old_bev.build_id, sizeof(bev.build_id));
731 __event_process_build_id(&bev, filename, session); 1842 __event_process_build_id(&bev, filename, session);
732 1843
@@ -787,7 +1898,7 @@ out:
787 1898
788static int perf_file_section__process(struct perf_file_section *section, 1899static int perf_file_section__process(struct perf_file_section *section,
789 struct perf_header *ph, 1900 struct perf_header *ph,
790 int feat, int fd) 1901 int feat, int fd, void *data __used)
791{ 1902{
792 if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) { 1903 if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) {
793 pr_debug("Failed to lseek to %" PRIu64 " offset for feature " 1904 pr_debug("Failed to lseek to %" PRIu64 " offset for feature "
@@ -804,6 +1915,21 @@ static int perf_file_section__process(struct perf_file_section *section,
804 if (perf_header__read_build_ids(ph, fd, section->offset, section->size)) 1915 if (perf_header__read_build_ids(ph, fd, section->offset, section->size))
805 pr_debug("Failed to read buildids, continuing...\n"); 1916 pr_debug("Failed to read buildids, continuing...\n");
806 break; 1917 break;
1918
1919 case HEADER_HOSTNAME:
1920 case HEADER_OSRELEASE:
1921 case HEADER_VERSION:
1922 case HEADER_ARCH:
1923 case HEADER_NRCPUS:
1924 case HEADER_CPUDESC:
1925 case HEADER_CPUID:
1926 case HEADER_TOTAL_MEM:
1927 case HEADER_CMDLINE:
1928 case HEADER_EVENT_DESC:
1929 case HEADER_CPU_TOPOLOGY:
1930 case HEADER_NUMA_TOPOLOGY:
1931 break;
1932
807 default: 1933 default:
808 pr_debug("unknown feature %d, continuing...\n", feat); 1934 pr_debug("unknown feature %d, continuing...\n", feat);
809 } 1935 }
@@ -877,9 +2003,12 @@ int perf_session__read_header(struct perf_session *session, int fd)
877 struct perf_evsel *evsel; 2003 struct perf_evsel *evsel;
878 off_t tmp; 2004 off_t tmp;
879 2005
880 if (perf_header__getbuffer64(header, fd, &f_attr, sizeof(f_attr))) 2006 if (readn(fd, &f_attr, sizeof(f_attr)) <= 0)
881 goto out_errno; 2007 goto out_errno;
882 2008
2009 if (header->needs_swap)
2010 perf_event__attr_swap(&f_attr.attr);
2011
883 tmp = lseek(fd, 0, SEEK_CUR); 2012 tmp = lseek(fd, 0, SEEK_CUR);
884 evsel = perf_evsel__new(&f_attr.attr, i); 2013 evsel = perf_evsel__new(&f_attr.attr, i);
885 2014
@@ -923,7 +2052,8 @@ int perf_session__read_header(struct perf_session *session, int fd)
923 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); 2052 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
924 } 2053 }
925 2054
926 perf_header__process_sections(header, fd, perf_file_section__process); 2055 perf_header__process_sections(header, fd, NULL,
2056 perf_file_section__process);
927 2057
928 lseek(fd, header->data_offset, SEEK_SET); 2058 lseek(fd, header->data_offset, SEEK_SET);
929 2059
@@ -1088,15 +2218,29 @@ int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist,
1088 struct perf_session *session __unused) 2218 struct perf_session *session __unused)
1089{ 2219{
1090 union perf_event ev; 2220 union perf_event ev;
2221 struct tracing_data *tdata;
1091 ssize_t size = 0, aligned_size = 0, padding; 2222 ssize_t size = 0, aligned_size = 0, padding;
1092 int err __used = 0; 2223 int err __used = 0;
1093 2224
2225 /*
2226 * We are going to store the size of the data followed
2227 * by the data contents. Since the fd descriptor is a pipe,
2228 * we cannot seek back to store the size of the data once
2229 * we know it. Instead we:
2230 *
2231 * - write the tracing data to the temp file
2232 * - get/write the data size to pipe
2233 * - write the tracing data from the temp file
2234 * to the pipe
2235 */
2236 tdata = tracing_data_get(&evlist->entries, fd, true);
2237 if (!tdata)
2238 return -1;
2239
1094 memset(&ev, 0, sizeof(ev)); 2240 memset(&ev, 0, sizeof(ev));
1095 2241
1096 ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA; 2242 ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA;
1097 size = read_tracing_data_size(fd, &evlist->entries); 2243 size = tdata->size;
1098 if (size <= 0)
1099 return size;
1100 aligned_size = ALIGN(size, sizeof(u64)); 2244 aligned_size = ALIGN(size, sizeof(u64));
1101 padding = aligned_size - size; 2245 padding = aligned_size - size;
1102 ev.tracing_data.header.size = sizeof(ev.tracing_data); 2246 ev.tracing_data.header.size = sizeof(ev.tracing_data);
@@ -1104,7 +2248,12 @@ int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist,
1104 2248
1105 process(&ev, NULL, session); 2249 process(&ev, NULL, session);
1106 2250
1107 err = read_tracing_data(fd, &evlist->entries); 2251 /*
2252 * The put function will copy all the tracing data
2253 * stored in temp file to the pipe.
2254 */
2255 tracing_data_put(tdata);
2256
1108 write_padded(fd, NULL, 0, padding); 2257 write_padded(fd, NULL, 0, padding);
1109 2258
1110 return aligned_size; 2259 return aligned_size;
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 1886256768a1..3d5a742f4a2a 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -12,6 +12,20 @@
12enum { 12enum {
13 HEADER_TRACE_INFO = 1, 13 HEADER_TRACE_INFO = 1,
14 HEADER_BUILD_ID, 14 HEADER_BUILD_ID,
15
16 HEADER_HOSTNAME,
17 HEADER_OSRELEASE,
18 HEADER_VERSION,
19 HEADER_ARCH,
20 HEADER_NRCPUS,
21 HEADER_CPUDESC,
22 HEADER_CPUID,
23 HEADER_TOTAL_MEM,
24 HEADER_CMDLINE,
25 HEADER_EVENT_DESC,
26 HEADER_CPU_TOPOLOGY,
27 HEADER_NUMA_TOPOLOGY,
28
15 HEADER_LAST_FEATURE, 29 HEADER_LAST_FEATURE,
16}; 30};
17 31
@@ -68,10 +82,15 @@ void perf_header__set_feat(struct perf_header *header, int feat);
68void perf_header__clear_feat(struct perf_header *header, int feat); 82void perf_header__clear_feat(struct perf_header *header, int feat);
69bool perf_header__has_feat(const struct perf_header *header, int feat); 83bool perf_header__has_feat(const struct perf_header *header, int feat);
70 84
85int perf_header__set_cmdline(int argc, const char **argv);
86
71int perf_header__process_sections(struct perf_header *header, int fd, 87int perf_header__process_sections(struct perf_header *header, int fd,
88 void *data,
72 int (*process)(struct perf_file_section *section, 89 int (*process)(struct perf_file_section *section,
73 struct perf_header *ph, 90 struct perf_header *ph,
74 int feat, int fd)); 91 int feat, int fd, void *data));
92
93int perf_header__fprintf_info(struct perf_session *s, FILE *fp, bool full);
75 94
76int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, 95int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
77 const char *name, bool is_kallsyms); 96 const char *name, bool is_kallsyms);
@@ -104,4 +123,10 @@ int perf_event__synthesize_build_id(struct dso *pos, u16 misc,
104 struct perf_session *session); 123 struct perf_session *session);
105int perf_event__process_build_id(union perf_event *event, 124int perf_event__process_build_id(union perf_event *event,
106 struct perf_session *session); 125 struct perf_session *session);
126
127/*
128 * arch specific callback
129 */
130int get_cpuid(char *buffer, size_t sz);
131
107#endif /* __PERF_HEADER_H */ 132#endif /* __PERF_HEADER_H */
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 627a02e03c57..a36a3fa81ffb 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -6,6 +6,11 @@
6#include "sort.h" 6#include "sort.h"
7#include <math.h> 7#include <math.h>
8 8
9static bool hists__filter_entry_by_dso(struct hists *hists,
10 struct hist_entry *he);
11static bool hists__filter_entry_by_thread(struct hists *hists,
12 struct hist_entry *he);
13
9enum hist_filter { 14enum hist_filter {
10 HIST_FILTER__DSO, 15 HIST_FILTER__DSO,
11 HIST_FILTER__THREAD, 16 HIST_FILTER__THREAD,
@@ -14,59 +19,60 @@ enum hist_filter {
14 19
15struct callchain_param callchain_param = { 20struct callchain_param callchain_param = {
16 .mode = CHAIN_GRAPH_REL, 21 .mode = CHAIN_GRAPH_REL,
17 .min_percent = 0.5 22 .min_percent = 0.5,
23 .order = ORDER_CALLEE
18}; 24};
19 25
20u16 hists__col_len(struct hists *self, enum hist_column col) 26u16 hists__col_len(struct hists *hists, enum hist_column col)
21{ 27{
22 return self->col_len[col]; 28 return hists->col_len[col];
23} 29}
24 30
25void hists__set_col_len(struct hists *self, enum hist_column col, u16 len) 31void hists__set_col_len(struct hists *hists, enum hist_column col, u16 len)
26{ 32{
27 self->col_len[col] = len; 33 hists->col_len[col] = len;
28} 34}
29 35
30bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len) 36bool hists__new_col_len(struct hists *hists, enum hist_column col, u16 len)
31{ 37{
32 if (len > hists__col_len(self, col)) { 38 if (len > hists__col_len(hists, col)) {
33 hists__set_col_len(self, col, len); 39 hists__set_col_len(hists, col, len);
34 return true; 40 return true;
35 } 41 }
36 return false; 42 return false;
37} 43}
38 44
39static void hists__reset_col_len(struct hists *self) 45static void hists__reset_col_len(struct hists *hists)
40{ 46{
41 enum hist_column col; 47 enum hist_column col;
42 48
43 for (col = 0; col < HISTC_NR_COLS; ++col) 49 for (col = 0; col < HISTC_NR_COLS; ++col)
44 hists__set_col_len(self, col, 0); 50 hists__set_col_len(hists, col, 0);
45} 51}
46 52
47static void hists__calc_col_len(struct hists *self, struct hist_entry *h) 53static void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
48{ 54{
49 u16 len; 55 u16 len;
50 56
51 if (h->ms.sym) 57 if (h->ms.sym)
52 hists__new_col_len(self, HISTC_SYMBOL, h->ms.sym->namelen); 58 hists__new_col_len(hists, HISTC_SYMBOL, h->ms.sym->namelen);
53 else { 59 else {
54 const unsigned int unresolved_col_width = BITS_PER_LONG / 4; 60 const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
55 61
56 if (hists__col_len(self, HISTC_DSO) < unresolved_col_width && 62 if (hists__col_len(hists, HISTC_DSO) < unresolved_col_width &&
57 !symbol_conf.col_width_list_str && !symbol_conf.field_sep && 63 !symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
58 !symbol_conf.dso_list) 64 !symbol_conf.dso_list)
59 hists__set_col_len(self, HISTC_DSO, 65 hists__set_col_len(hists, HISTC_DSO,
60 unresolved_col_width); 66 unresolved_col_width);
61 } 67 }
62 68
63 len = thread__comm_len(h->thread); 69 len = thread__comm_len(h->thread);
64 if (hists__new_col_len(self, HISTC_COMM, len)) 70 if (hists__new_col_len(hists, HISTC_COMM, len))
65 hists__set_col_len(self, HISTC_THREAD, len + 6); 71 hists__set_col_len(hists, HISTC_THREAD, len + 6);
66 72
67 if (h->ms.map) { 73 if (h->ms.map) {
68 len = dso__name_len(h->ms.map->dso); 74 len = dso__name_len(h->ms.map->dso);
69 hists__new_col_len(self, HISTC_DSO, len); 75 hists__new_col_len(hists, HISTC_DSO, len);
70 } 76 }
71} 77}
72 78
@@ -91,6 +97,67 @@ static void hist_entry__add_cpumode_period(struct hist_entry *self,
91 } 97 }
92} 98}
93 99
100static void hist_entry__decay(struct hist_entry *he)
101{
102 he->period = (he->period * 7) / 8;
103 he->nr_events = (he->nr_events * 7) / 8;
104}
105
106static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
107{
108 u64 prev_period = he->period;
109
110 if (prev_period == 0)
111 return true;
112
113 hist_entry__decay(he);
114
115 if (!he->filtered)
116 hists->stats.total_period -= prev_period - he->period;
117
118 return he->period == 0;
119}
120
121static void __hists__decay_entries(struct hists *hists, bool zap_user,
122 bool zap_kernel, bool threaded)
123{
124 struct rb_node *next = rb_first(&hists->entries);
125 struct hist_entry *n;
126
127 while (next) {
128 n = rb_entry(next, struct hist_entry, rb_node);
129 next = rb_next(&n->rb_node);
130 /*
131 * We may be annotating this, for instance, so keep it here in
132 * case some it gets new samples, we'll eventually free it when
133 * the user stops browsing and it agains gets fully decayed.
134 */
135 if (((zap_user && n->level == '.') ||
136 (zap_kernel && n->level != '.') ||
137 hists__decay_entry(hists, n)) &&
138 !n->used) {
139 rb_erase(&n->rb_node, &hists->entries);
140
141 if (sort__need_collapse || threaded)
142 rb_erase(&n->rb_node_in, &hists->entries_collapsed);
143
144 hist_entry__free(n);
145 --hists->nr_entries;
146 }
147 }
148}
149
150void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
151{
152 return __hists__decay_entries(hists, zap_user, zap_kernel, false);
153}
154
155void hists__decay_entries_threaded(struct hists *hists,
156 bool zap_user, bool zap_kernel)
157{
158 return __hists__decay_entries(hists, zap_user, zap_kernel, true);
159}
160
94/* 161/*
95 * histogram, sorted on item, collects periods 162 * histogram, sorted on item, collects periods
96 */ 163 */
@@ -112,11 +179,12 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
112 return self; 179 return self;
113} 180}
114 181
115static void hists__inc_nr_entries(struct hists *self, struct hist_entry *h) 182static void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h)
116{ 183{
117 if (!h->filtered) { 184 if (!h->filtered) {
118 hists__calc_col_len(self, h); 185 hists__calc_col_len(hists, h);
119 ++self->nr_entries; 186 ++hists->nr_entries;
187 hists->stats.total_period += h->period;
120 } 188 }
121} 189}
122 190
@@ -127,11 +195,11 @@ static u8 symbol__parent_filter(const struct symbol *parent)
127 return 0; 195 return 0;
128} 196}
129 197
130struct hist_entry *__hists__add_entry(struct hists *self, 198struct hist_entry *__hists__add_entry(struct hists *hists,
131 struct addr_location *al, 199 struct addr_location *al,
132 struct symbol *sym_parent, u64 period) 200 struct symbol *sym_parent, u64 period)
133{ 201{
134 struct rb_node **p = &self->entries.rb_node; 202 struct rb_node **p;
135 struct rb_node *parent = NULL; 203 struct rb_node *parent = NULL;
136 struct hist_entry *he; 204 struct hist_entry *he;
137 struct hist_entry entry = { 205 struct hist_entry entry = {
@@ -149,9 +217,13 @@ struct hist_entry *__hists__add_entry(struct hists *self,
149 }; 217 };
150 int cmp; 218 int cmp;
151 219
220 pthread_mutex_lock(&hists->lock);
221
222 p = &hists->entries_in->rb_node;
223
152 while (*p != NULL) { 224 while (*p != NULL) {
153 parent = *p; 225 parent = *p;
154 he = rb_entry(parent, struct hist_entry, rb_node); 226 he = rb_entry(parent, struct hist_entry, rb_node_in);
155 227
156 cmp = hist_entry__cmp(&entry, he); 228 cmp = hist_entry__cmp(&entry, he);
157 229
@@ -169,12 +241,14 @@ struct hist_entry *__hists__add_entry(struct hists *self,
169 241
170 he = hist_entry__new(&entry); 242 he = hist_entry__new(&entry);
171 if (!he) 243 if (!he)
172 return NULL; 244 goto out_unlock;
173 rb_link_node(&he->rb_node, parent, p); 245
174 rb_insert_color(&he->rb_node, &self->entries); 246 rb_link_node(&he->rb_node_in, parent, p);
175 hists__inc_nr_entries(self, he); 247 rb_insert_color(&he->rb_node_in, hists->entries_in);
176out: 248out:
177 hist_entry__add_cpumode_period(he, al->cpumode, period); 249 hist_entry__add_cpumode_period(he, al->cpumode, period);
250out_unlock:
251 pthread_mutex_unlock(&hists->lock);
178 return he; 252 return he;
179} 253}
180 254
@@ -221,7 +295,7 @@ void hist_entry__free(struct hist_entry *he)
221 * collapse the histogram 295 * collapse the histogram
222 */ 296 */
223 297
224static bool hists__collapse_insert_entry(struct hists *self, 298static bool hists__collapse_insert_entry(struct hists *hists,
225 struct rb_root *root, 299 struct rb_root *root,
226 struct hist_entry *he) 300 struct hist_entry *he)
227{ 301{
@@ -232,15 +306,16 @@ static bool hists__collapse_insert_entry(struct hists *self,
232 306
233 while (*p != NULL) { 307 while (*p != NULL) {
234 parent = *p; 308 parent = *p;
235 iter = rb_entry(parent, struct hist_entry, rb_node); 309 iter = rb_entry(parent, struct hist_entry, rb_node_in);
236 310
237 cmp = hist_entry__collapse(iter, he); 311 cmp = hist_entry__collapse(iter, he);
238 312
239 if (!cmp) { 313 if (!cmp) {
240 iter->period += he->period; 314 iter->period += he->period;
315 iter->nr_events += he->nr_events;
241 if (symbol_conf.use_callchain) { 316 if (symbol_conf.use_callchain) {
242 callchain_cursor_reset(&self->callchain_cursor); 317 callchain_cursor_reset(&hists->callchain_cursor);
243 callchain_merge(&self->callchain_cursor, iter->callchain, 318 callchain_merge(&hists->callchain_cursor, iter->callchain,
244 he->callchain); 319 he->callchain);
245 } 320 }
246 hist_entry__free(he); 321 hist_entry__free(he);
@@ -253,35 +328,68 @@ static bool hists__collapse_insert_entry(struct hists *self,
253 p = &(*p)->rb_right; 328 p = &(*p)->rb_right;
254 } 329 }
255 330
256 rb_link_node(&he->rb_node, parent, p); 331 rb_link_node(&he->rb_node_in, parent, p);
257 rb_insert_color(&he->rb_node, root); 332 rb_insert_color(&he->rb_node_in, root);
258 return true; 333 return true;
259} 334}
260 335
261void hists__collapse_resort(struct hists *self) 336static struct rb_root *hists__get_rotate_entries_in(struct hists *hists)
337{
338 struct rb_root *root;
339
340 pthread_mutex_lock(&hists->lock);
341
342 root = hists->entries_in;
343 if (++hists->entries_in > &hists->entries_in_array[1])
344 hists->entries_in = &hists->entries_in_array[0];
345
346 pthread_mutex_unlock(&hists->lock);
347
348 return root;
349}
350
351static void hists__apply_filters(struct hists *hists, struct hist_entry *he)
352{
353 hists__filter_entry_by_dso(hists, he);
354 hists__filter_entry_by_thread(hists, he);
355}
356
357static void __hists__collapse_resort(struct hists *hists, bool threaded)
262{ 358{
263 struct rb_root tmp; 359 struct rb_root *root;
264 struct rb_node *next; 360 struct rb_node *next;
265 struct hist_entry *n; 361 struct hist_entry *n;
266 362
267 if (!sort__need_collapse) 363 if (!sort__need_collapse && !threaded)
268 return; 364 return;
269 365
270 tmp = RB_ROOT; 366 root = hists__get_rotate_entries_in(hists);
271 next = rb_first(&self->entries); 367 next = rb_first(root);
272 self->nr_entries = 0;
273 hists__reset_col_len(self);
274 368
275 while (next) { 369 while (next) {
276 n = rb_entry(next, struct hist_entry, rb_node); 370 n = rb_entry(next, struct hist_entry, rb_node_in);
277 next = rb_next(&n->rb_node); 371 next = rb_next(&n->rb_node_in);
278 372
279 rb_erase(&n->rb_node, &self->entries); 373 rb_erase(&n->rb_node_in, root);
280 if (hists__collapse_insert_entry(self, &tmp, n)) 374 if (hists__collapse_insert_entry(hists, &hists->entries_collapsed, n)) {
281 hists__inc_nr_entries(self, n); 375 /*
376 * If it wasn't combined with one of the entries already
377 * collapsed, we need to apply the filters that may have
378 * been set by, say, the hist_browser.
379 */
380 hists__apply_filters(hists, n);
381 }
282 } 382 }
383}
384
385void hists__collapse_resort(struct hists *hists)
386{
387 return __hists__collapse_resort(hists, false);
388}
283 389
284 self->entries = tmp; 390void hists__collapse_resort_threaded(struct hists *hists)
391{
392 return __hists__collapse_resort(hists, true);
285} 393}
286 394
287/* 395/*
@@ -314,31 +422,44 @@ static void __hists__insert_output_entry(struct rb_root *entries,
314 rb_insert_color(&he->rb_node, entries); 422 rb_insert_color(&he->rb_node, entries);
315} 423}
316 424
317void hists__output_resort(struct hists *self) 425static void __hists__output_resort(struct hists *hists, bool threaded)
318{ 426{
319 struct rb_root tmp; 427 struct rb_root *root;
320 struct rb_node *next; 428 struct rb_node *next;
321 struct hist_entry *n; 429 struct hist_entry *n;
322 u64 min_callchain_hits; 430 u64 min_callchain_hits;
323 431
324 min_callchain_hits = self->stats.total_period * (callchain_param.min_percent / 100); 432 min_callchain_hits = hists->stats.total_period * (callchain_param.min_percent / 100);
433
434 if (sort__need_collapse || threaded)
435 root = &hists->entries_collapsed;
436 else
437 root = hists->entries_in;
325 438
326 tmp = RB_ROOT; 439 next = rb_first(root);
327 next = rb_first(&self->entries); 440 hists->entries = RB_ROOT;
328 441
329 self->nr_entries = 0; 442 hists->nr_entries = 0;
330 hists__reset_col_len(self); 443 hists->stats.total_period = 0;
444 hists__reset_col_len(hists);
331 445
332 while (next) { 446 while (next) {
333 n = rb_entry(next, struct hist_entry, rb_node); 447 n = rb_entry(next, struct hist_entry, rb_node_in);
334 next = rb_next(&n->rb_node); 448 next = rb_next(&n->rb_node_in);
335 449
336 rb_erase(&n->rb_node, &self->entries); 450 __hists__insert_output_entry(&hists->entries, n, min_callchain_hits);
337 __hists__insert_output_entry(&tmp, n, min_callchain_hits); 451 hists__inc_nr_entries(hists, n);
338 hists__inc_nr_entries(self, n);
339 } 452 }
453}
340 454
341 self->entries = tmp; 455void hists__output_resort(struct hists *hists)
456{
457 return __hists__output_resort(hists, false);
458}
459
460void hists__output_resort_threaded(struct hists *hists)
461{
462 return __hists__output_resort(hists, true);
342} 463}
343 464
344static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin) 465static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
@@ -593,12 +714,27 @@ static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
593 return ret; 714 return ret;
594} 715}
595 716
596int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size, 717void hists__output_recalc_col_len(struct hists *hists, int max_rows)
597 struct hists *hists, struct hists *pair_hists, 718{
598 bool show_displacement, long displacement, 719 struct rb_node *next = rb_first(&hists->entries);
599 bool color, u64 session_total) 720 struct hist_entry *n;
721 int row = 0;
722
723 hists__reset_col_len(hists);
724
725 while (next && row++ < max_rows) {
726 n = rb_entry(next, struct hist_entry, rb_node);
727 if (!n->filtered)
728 hists__calc_col_len(hists, n);
729 next = rb_next(&n->rb_node);
730 }
731}
732
733static int hist_entry__pcnt_snprintf(struct hist_entry *self, char *s,
734 size_t size, struct hists *pair_hists,
735 bool show_displacement, long displacement,
736 bool color, u64 session_total)
600{ 737{
601 struct sort_entry *se;
602 u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us; 738 u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us;
603 u64 nr_events; 739 u64 nr_events;
604 const char *sep = symbol_conf.field_sep; 740 const char *sep = symbol_conf.field_sep;
@@ -663,6 +799,13 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
663 ret += snprintf(s + ret, size - ret, "%11" PRIu64, nr_events); 799 ret += snprintf(s + ret, size - ret, "%11" PRIu64, nr_events);
664 } 800 }
665 801
802 if (symbol_conf.show_total_period) {
803 if (sep)
804 ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, period);
805 else
806 ret += snprintf(s + ret, size - ret, " %12" PRIu64, period);
807 }
808
666 if (pair_hists) { 809 if (pair_hists) {
667 char bf[32]; 810 char bf[32];
668 double old_percent = 0, new_percent = 0, diff; 811 double old_percent = 0, new_percent = 0, diff;
@@ -697,26 +840,42 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
697 } 840 }
698 } 841 }
699 842
843 return ret;
844}
845
846int hist_entry__snprintf(struct hist_entry *he, char *s, size_t size,
847 struct hists *hists)
848{
849 const char *sep = symbol_conf.field_sep;
850 struct sort_entry *se;
851 int ret = 0;
852
700 list_for_each_entry(se, &hist_entry__sort_list, list) { 853 list_for_each_entry(se, &hist_entry__sort_list, list) {
701 if (se->elide) 854 if (se->elide)
702 continue; 855 continue;
703 856
704 ret += snprintf(s + ret, size - ret, "%s", sep ?: " "); 857 ret += snprintf(s + ret, size - ret, "%s", sep ?: " ");
705 ret += se->se_snprintf(self, s + ret, size - ret, 858 ret += se->se_snprintf(he, s + ret, size - ret,
706 hists__col_len(hists, se->se_width_idx)); 859 hists__col_len(hists, se->se_width_idx));
707 } 860 }
708 861
709 return ret; 862 return ret;
710} 863}
711 864
712int hist_entry__fprintf(struct hist_entry *self, struct hists *hists, 865int hist_entry__fprintf(struct hist_entry *he, size_t size, struct hists *hists,
713 struct hists *pair_hists, bool show_displacement, 866 struct hists *pair_hists, bool show_displacement,
714 long displacement, FILE *fp, u64 session_total) 867 long displacement, FILE *fp, u64 session_total)
715{ 868{
716 char bf[512]; 869 char bf[512];
717 hist_entry__snprintf(self, bf, sizeof(bf), hists, pair_hists, 870 int ret;
718 show_displacement, displacement, 871
719 true, session_total); 872 if (size == 0 || size > sizeof(bf))
873 size = sizeof(bf);
874
875 ret = hist_entry__pcnt_snprintf(he, bf, size, pair_hists,
876 show_displacement, displacement,
877 true, session_total);
878 hist_entry__snprintf(he, bf + ret, size - ret, hists);
720 return fprintf(fp, "%s\n", bf); 879 return fprintf(fp, "%s\n", bf);
721} 880}
722 881
@@ -737,8 +896,9 @@ static size_t hist_entry__fprintf_callchain(struct hist_entry *self,
737 left_margin); 896 left_margin);
738} 897}
739 898
740size_t hists__fprintf(struct hists *self, struct hists *pair, 899size_t hists__fprintf(struct hists *hists, struct hists *pair,
741 bool show_displacement, FILE *fp) 900 bool show_displacement, bool show_header, int max_rows,
901 int max_cols, FILE *fp)
742{ 902{
743 struct sort_entry *se; 903 struct sort_entry *se;
744 struct rb_node *nd; 904 struct rb_node *nd;
@@ -748,9 +908,13 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
748 unsigned int width; 908 unsigned int width;
749 const char *sep = symbol_conf.field_sep; 909 const char *sep = symbol_conf.field_sep;
750 const char *col_width = symbol_conf.col_width_list_str; 910 const char *col_width = symbol_conf.col_width_list_str;
911 int nr_rows = 0;
751 912
752 init_rem_hits(); 913 init_rem_hits();
753 914
915 if (!show_header)
916 goto print_entries;
917
754 fprintf(fp, "# %s", pair ? "Baseline" : "Overhead"); 918 fprintf(fp, "# %s", pair ? "Baseline" : "Overhead");
755 919
756 if (symbol_conf.show_nr_samples) { 920 if (symbol_conf.show_nr_samples) {
@@ -760,6 +924,13 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
760 fputs(" Samples ", fp); 924 fputs(" Samples ", fp);
761 } 925 }
762 926
927 if (symbol_conf.show_total_period) {
928 if (sep)
929 ret += fprintf(fp, "%cPeriod", *sep);
930 else
931 ret += fprintf(fp, " Period ");
932 }
933
763 if (symbol_conf.show_cpu_utilization) { 934 if (symbol_conf.show_cpu_utilization) {
764 if (sep) { 935 if (sep) {
765 ret += fprintf(fp, "%csys", *sep); 936 ret += fprintf(fp, "%csys", *sep);
@@ -802,18 +973,21 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
802 width = strlen(se->se_header); 973 width = strlen(se->se_header);
803 if (symbol_conf.col_width_list_str) { 974 if (symbol_conf.col_width_list_str) {
804 if (col_width) { 975 if (col_width) {
805 hists__set_col_len(self, se->se_width_idx, 976 hists__set_col_len(hists, se->se_width_idx,
806 atoi(col_width)); 977 atoi(col_width));
807 col_width = strchr(col_width, ','); 978 col_width = strchr(col_width, ',');
808 if (col_width) 979 if (col_width)
809 ++col_width; 980 ++col_width;
810 } 981 }
811 } 982 }
812 if (!hists__new_col_len(self, se->se_width_idx, width)) 983 if (!hists__new_col_len(hists, se->se_width_idx, width))
813 width = hists__col_len(self, se->se_width_idx); 984 width = hists__col_len(hists, se->se_width_idx);
814 fprintf(fp, " %*s", width, se->se_header); 985 fprintf(fp, " %*s", width, se->se_header);
815 } 986 }
987
816 fprintf(fp, "\n"); 988 fprintf(fp, "\n");
989 if (max_rows && ++nr_rows >= max_rows)
990 goto out;
817 991
818 if (sep) 992 if (sep)
819 goto print_entries; 993 goto print_entries;
@@ -821,6 +995,8 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
821 fprintf(fp, "# ........"); 995 fprintf(fp, "# ........");
822 if (symbol_conf.show_nr_samples) 996 if (symbol_conf.show_nr_samples)
823 fprintf(fp, " .........."); 997 fprintf(fp, " ..........");
998 if (symbol_conf.show_total_period)
999 fprintf(fp, " ............");
824 if (pair) { 1000 if (pair) {
825 fprintf(fp, " .........."); 1001 fprintf(fp, " ..........");
826 if (show_displacement) 1002 if (show_displacement)
@@ -833,19 +1009,28 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
833 continue; 1009 continue;
834 1010
835 fprintf(fp, " "); 1011 fprintf(fp, " ");
836 width = hists__col_len(self, se->se_width_idx); 1012 width = hists__col_len(hists, se->se_width_idx);
837 if (width == 0) 1013 if (width == 0)
838 width = strlen(se->se_header); 1014 width = strlen(se->se_header);
839 for (i = 0; i < width; i++) 1015 for (i = 0; i < width; i++)
840 fprintf(fp, "."); 1016 fprintf(fp, ".");
841 } 1017 }
842 1018
843 fprintf(fp, "\n#\n"); 1019 fprintf(fp, "\n");
1020 if (max_rows && ++nr_rows >= max_rows)
1021 goto out;
1022
1023 fprintf(fp, "#\n");
1024 if (max_rows && ++nr_rows >= max_rows)
1025 goto out;
844 1026
845print_entries: 1027print_entries:
846 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { 1028 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
847 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1029 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
848 1030
1031 if (h->filtered)
1032 continue;
1033
849 if (show_displacement) { 1034 if (show_displacement) {
850 if (h->pair != NULL) 1035 if (h->pair != NULL)
851 displacement = ((long)h->pair->position - 1036 displacement = ((long)h->pair->position -
@@ -854,19 +1039,22 @@ print_entries:
854 displacement = 0; 1039 displacement = 0;
855 ++position; 1040 ++position;
856 } 1041 }
857 ret += hist_entry__fprintf(h, self, pair, show_displacement, 1042 ret += hist_entry__fprintf(h, max_cols, hists, pair, show_displacement,
858 displacement, fp, self->stats.total_period); 1043 displacement, fp, hists->stats.total_period);
859 1044
860 if (symbol_conf.use_callchain) 1045 if (symbol_conf.use_callchain)
861 ret += hist_entry__fprintf_callchain(h, self, fp, 1046 ret += hist_entry__fprintf_callchain(h, hists, fp,
862 self->stats.total_period); 1047 hists->stats.total_period);
1048 if (max_rows && ++nr_rows >= max_rows)
1049 goto out;
1050
863 if (h->ms.map == NULL && verbose > 1) { 1051 if (h->ms.map == NULL && verbose > 1) {
864 __map_groups__fprintf_maps(&h->thread->mg, 1052 __map_groups__fprintf_maps(&h->thread->mg,
865 MAP__FUNCTION, verbose, fp); 1053 MAP__FUNCTION, verbose, fp);
866 fprintf(fp, "%.10s end\n", graph_dotted_line); 1054 fprintf(fp, "%.10s end\n", graph_dotted_line);
867 } 1055 }
868 } 1056 }
869 1057out:
870 free(rem_sq_bracket); 1058 free(rem_sq_bracket);
871 1059
872 return ret; 1060 return ret;
@@ -875,7 +1063,7 @@ print_entries:
875/* 1063/*
876 * See hists__fprintf to match the column widths 1064 * See hists__fprintf to match the column widths
877 */ 1065 */
878unsigned int hists__sort_list_width(struct hists *self) 1066unsigned int hists__sort_list_width(struct hists *hists)
879{ 1067{
880 struct sort_entry *se; 1068 struct sort_entry *se;
881 int ret = 9; /* total % */ 1069 int ret = 9; /* total % */
@@ -892,9 +1080,12 @@ unsigned int hists__sort_list_width(struct hists *self)
892 if (symbol_conf.show_nr_samples) 1080 if (symbol_conf.show_nr_samples)
893 ret += 11; 1081 ret += 11;
894 1082
1083 if (symbol_conf.show_total_period)
1084 ret += 13;
1085
895 list_for_each_entry(se, &hist_entry__sort_list, list) 1086 list_for_each_entry(se, &hist_entry__sort_list, list)
896 if (!se->elide) 1087 if (!se->elide)
897 ret += 2 + hists__col_len(self, se->se_width_idx); 1088 ret += 2 + hists__col_len(hists, se->se_width_idx);
898 1089
899 if (verbose) /* Addr + origin */ 1090 if (verbose) /* Addr + origin */
900 ret += 3 + BITS_PER_LONG / 4; 1091 ret += 3 + BITS_PER_LONG / 4;
@@ -902,63 +1093,84 @@ unsigned int hists__sort_list_width(struct hists *self)
902 return ret; 1093 return ret;
903} 1094}
904 1095
905static void hists__remove_entry_filter(struct hists *self, struct hist_entry *h, 1096static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h,
906 enum hist_filter filter) 1097 enum hist_filter filter)
907{ 1098{
908 h->filtered &= ~(1 << filter); 1099 h->filtered &= ~(1 << filter);
909 if (h->filtered) 1100 if (h->filtered)
910 return; 1101 return;
911 1102
912 ++self->nr_entries; 1103 ++hists->nr_entries;
913 if (h->ms.unfolded) 1104 if (h->ms.unfolded)
914 self->nr_entries += h->nr_rows; 1105 hists->nr_entries += h->nr_rows;
915 h->row_offset = 0; 1106 h->row_offset = 0;
916 self->stats.total_period += h->period; 1107 hists->stats.total_period += h->period;
917 self->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events; 1108 hists->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events;
918 1109
919 hists__calc_col_len(self, h); 1110 hists__calc_col_len(hists, h);
920} 1111}
921 1112
922void hists__filter_by_dso(struct hists *self, const struct dso *dso) 1113
1114static bool hists__filter_entry_by_dso(struct hists *hists,
1115 struct hist_entry *he)
1116{
1117 if (hists->dso_filter != NULL &&
1118 (he->ms.map == NULL || he->ms.map->dso != hists->dso_filter)) {
1119 he->filtered |= (1 << HIST_FILTER__DSO);
1120 return true;
1121 }
1122
1123 return false;
1124}
1125
1126void hists__filter_by_dso(struct hists *hists)
923{ 1127{
924 struct rb_node *nd; 1128 struct rb_node *nd;
925 1129
926 self->nr_entries = self->stats.total_period = 0; 1130 hists->nr_entries = hists->stats.total_period = 0;
927 self->stats.nr_events[PERF_RECORD_SAMPLE] = 0; 1131 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
928 hists__reset_col_len(self); 1132 hists__reset_col_len(hists);
929 1133
930 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { 1134 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
931 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1135 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
932 1136
933 if (symbol_conf.exclude_other && !h->parent) 1137 if (symbol_conf.exclude_other && !h->parent)
934 continue; 1138 continue;
935 1139
936 if (dso != NULL && (h->ms.map == NULL || h->ms.map->dso != dso)) { 1140 if (hists__filter_entry_by_dso(hists, h))
937 h->filtered |= (1 << HIST_FILTER__DSO);
938 continue; 1141 continue;
939 }
940 1142
941 hists__remove_entry_filter(self, h, HIST_FILTER__DSO); 1143 hists__remove_entry_filter(hists, h, HIST_FILTER__DSO);
942 } 1144 }
943} 1145}
944 1146
945void hists__filter_by_thread(struct hists *self, const struct thread *thread) 1147static bool hists__filter_entry_by_thread(struct hists *hists,
1148 struct hist_entry *he)
1149{
1150 if (hists->thread_filter != NULL &&
1151 he->thread != hists->thread_filter) {
1152 he->filtered |= (1 << HIST_FILTER__THREAD);
1153 return true;
1154 }
1155
1156 return false;
1157}
1158
1159void hists__filter_by_thread(struct hists *hists)
946{ 1160{
947 struct rb_node *nd; 1161 struct rb_node *nd;
948 1162
949 self->nr_entries = self->stats.total_period = 0; 1163 hists->nr_entries = hists->stats.total_period = 0;
950 self->stats.nr_events[PERF_RECORD_SAMPLE] = 0; 1164 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
951 hists__reset_col_len(self); 1165 hists__reset_col_len(hists);
952 1166
953 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { 1167 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
954 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1168 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
955 1169
956 if (thread != NULL && h->thread != thread) { 1170 if (hists__filter_entry_by_thread(hists, h))
957 h->filtered |= (1 << HIST_FILTER__THREAD);
958 continue; 1171 continue;
959 }
960 1172
961 hists__remove_entry_filter(self, h, HIST_FILTER__THREAD); 1173 hists__remove_entry_filter(hists, h, HIST_FILTER__THREAD);
962 } 1174 }
963} 1175}
964 1176
@@ -972,13 +1184,13 @@ int hist_entry__annotate(struct hist_entry *he, size_t privsize)
972 return symbol__annotate(he->ms.sym, he->ms.map, privsize); 1184 return symbol__annotate(he->ms.sym, he->ms.map, privsize);
973} 1185}
974 1186
975void hists__inc_nr_events(struct hists *self, u32 type) 1187void hists__inc_nr_events(struct hists *hists, u32 type)
976{ 1188{
977 ++self->stats.nr_events[0]; 1189 ++hists->stats.nr_events[0];
978 ++self->stats.nr_events[type]; 1190 ++hists->stats.nr_events[type];
979} 1191}
980 1192
981size_t hists__fprintf_nr_events(struct hists *self, FILE *fp) 1193size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp)
982{ 1194{
983 int i; 1195 int i;
984 size_t ret = 0; 1196 size_t ret = 0;
@@ -986,7 +1198,7 @@ size_t hists__fprintf_nr_events(struct hists *self, FILE *fp)
986 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) { 1198 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
987 const char *name; 1199 const char *name;
988 1200
989 if (self->stats.nr_events[i] == 0) 1201 if (hists->stats.nr_events[i] == 0)
990 continue; 1202 continue;
991 1203
992 name = perf_event__name(i); 1204 name = perf_event__name(i);
@@ -994,8 +1206,18 @@ size_t hists__fprintf_nr_events(struct hists *self, FILE *fp)
994 continue; 1206 continue;
995 1207
996 ret += fprintf(fp, "%16s events: %10d\n", name, 1208 ret += fprintf(fp, "%16s events: %10d\n", name,
997 self->stats.nr_events[i]); 1209 hists->stats.nr_events[i]);
998 } 1210 }
999 1211
1000 return ret; 1212 return ret;
1001} 1213}
1214
1215void hists__init(struct hists *hists)
1216{
1217 memset(hists, 0, sizeof(*hists));
1218 hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT;
1219 hists->entries_in = &hists->entries_in_array[0];
1220 hists->entries_collapsed = RB_ROOT;
1221 hists->entries = RB_ROOT;
1222 pthread_mutex_init(&hists->lock, NULL);
1223}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 3beb97c4d822..c86c1d27bd1e 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -2,6 +2,7 @@
2#define __PERF_HIST_H 2#define __PERF_HIST_H
3 3
4#include <linux/types.h> 4#include <linux/types.h>
5#include <pthread.h>
5#include "callchain.h" 6#include "callchain.h"
6 7
7extern struct callchain_param callchain_param; 8extern struct callchain_param callchain_param;
@@ -27,6 +28,7 @@ struct events_stats {
27 u64 total_lost; 28 u64 total_lost;
28 u64 total_invalid_chains; 29 u64 total_invalid_chains;
29 u32 nr_events[PERF_RECORD_HEADER_MAX]; 30 u32 nr_events[PERF_RECORD_HEADER_MAX];
31 u32 nr_lost_warned;
30 u32 nr_unknown_events; 32 u32 nr_unknown_events;
31 u32 nr_invalid_chains; 33 u32 nr_invalid_chains;
32 u32 nr_unknown_id; 34 u32 nr_unknown_id;
@@ -42,9 +44,18 @@ enum hist_column {
42 HISTC_NR_COLS, /* Last entry */ 44 HISTC_NR_COLS, /* Last entry */
43}; 45};
44 46
47struct thread;
48struct dso;
49
45struct hists { 50struct hists {
51 struct rb_root entries_in_array[2];
52 struct rb_root *entries_in;
46 struct rb_root entries; 53 struct rb_root entries;
54 struct rb_root entries_collapsed;
47 u64 nr_entries; 55 u64 nr_entries;
56 const struct thread *thread_filter;
57 const struct dso *dso_filter;
58 pthread_mutex_t lock;
48 struct events_stats stats; 59 struct events_stats stats;
49 u64 event_stream; 60 u64 event_stream;
50 u16 col_len[HISTC_NR_COLS]; 61 u16 col_len[HISTC_NR_COLS];
@@ -52,34 +63,42 @@ struct hists {
52 struct callchain_cursor callchain_cursor; 63 struct callchain_cursor callchain_cursor;
53}; 64};
54 65
66void hists__init(struct hists *hists);
67
55struct hist_entry *__hists__add_entry(struct hists *self, 68struct hist_entry *__hists__add_entry(struct hists *self,
56 struct addr_location *al, 69 struct addr_location *al,
57 struct symbol *parent, u64 period); 70 struct symbol *parent, u64 period);
58extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *); 71extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);
59extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *); 72extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
60int hist_entry__fprintf(struct hist_entry *self, struct hists *hists, 73int hist_entry__fprintf(struct hist_entry *he, size_t size, struct hists *hists,
61 struct hists *pair_hists, bool show_displacement, 74 struct hists *pair_hists, bool show_displacement,
62 long displacement, FILE *fp, u64 total); 75 long displacement, FILE *fp, u64 session_total);
63int hist_entry__snprintf(struct hist_entry *self, char *bf, size_t size, 76int hist_entry__snprintf(struct hist_entry *self, char *bf, size_t size,
64 struct hists *hists, struct hists *pair_hists, 77 struct hists *hists);
65 bool show_displacement, long displacement,
66 bool color, u64 total);
67void hist_entry__free(struct hist_entry *); 78void hist_entry__free(struct hist_entry *);
68 79
69void hists__output_resort(struct hists *self); 80void hists__output_resort(struct hists *self);
81void hists__output_resort_threaded(struct hists *hists);
70void hists__collapse_resort(struct hists *self); 82void hists__collapse_resort(struct hists *self);
83void hists__collapse_resort_threaded(struct hists *hists);
84
85void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel);
86void hists__decay_entries_threaded(struct hists *hists, bool zap_user,
87 bool zap_kernel);
88void hists__output_recalc_col_len(struct hists *hists, int max_rows);
71 89
72void hists__inc_nr_events(struct hists *self, u32 type); 90void hists__inc_nr_events(struct hists *self, u32 type);
73size_t hists__fprintf_nr_events(struct hists *self, FILE *fp); 91size_t hists__fprintf_nr_events(struct hists *self, FILE *fp);
74 92
75size_t hists__fprintf(struct hists *self, struct hists *pair, 93size_t hists__fprintf(struct hists *self, struct hists *pair,
76 bool show_displacement, FILE *fp); 94 bool show_displacement, bool show_header,
95 int max_rows, int max_cols, FILE *fp);
77 96
78int hist_entry__inc_addr_samples(struct hist_entry *self, int evidx, u64 addr); 97int hist_entry__inc_addr_samples(struct hist_entry *self, int evidx, u64 addr);
79int hist_entry__annotate(struct hist_entry *self, size_t privsize); 98int hist_entry__annotate(struct hist_entry *self, size_t privsize);
80 99
81void hists__filter_by_dso(struct hists *self, const struct dso *dso); 100void hists__filter_by_dso(struct hists *hists);
82void hists__filter_by_thread(struct hists *self, const struct thread *thread); 101void hists__filter_by_thread(struct hists *hists);
83 102
84u16 hists__col_len(struct hists *self, enum hist_column col); 103u16 hists__col_len(struct hists *self, enum hist_column col);
85void hists__set_col_len(struct hists *self, enum hist_column col, u16 len); 104void hists__set_col_len(struct hists *self, enum hist_column col, u16 len);
@@ -90,26 +109,33 @@ struct perf_evlist;
90#ifdef NO_NEWT_SUPPORT 109#ifdef NO_NEWT_SUPPORT
91static inline 110static inline
92int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __used, 111int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __used,
93 const char *help __used) 112 const char *help __used,
113 void(*timer)(void *arg) __used,
114 void *arg __used,
115 int refresh __used)
94{ 116{
95 return 0; 117 return 0;
96} 118}
97 119
98static inline int hist_entry__tui_annotate(struct hist_entry *self __used, 120static inline int hist_entry__tui_annotate(struct hist_entry *self __used,
99 int evidx __used) 121 int evidx __used,
122 int nr_events __used,
123 void(*timer)(void *arg) __used,
124 void *arg __used,
125 int delay_secs __used)
100{ 126{
101 return 0; 127 return 0;
102} 128}
103#define KEY_LEFT -1 129#define K_LEFT -1
104#define KEY_RIGHT -2 130#define K_RIGHT -2
105#else 131#else
106#include <newt.h> 132#include "ui/keysyms.h"
107int hist_entry__tui_annotate(struct hist_entry *self, int evidx); 133int hist_entry__tui_annotate(struct hist_entry *he, int evidx, int nr_events,
108 134 void(*timer)(void *arg), void *arg, int delay_secs);
109#define KEY_LEFT NEWT_KEY_LEFT
110#define KEY_RIGHT NEWT_KEY_RIGHT
111 135
112int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help); 136int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
137 void(*timer)(void *arg), void *arg,
138 int refresh);
113#endif 139#endif
114 140
115unsigned int hists__sort_list_width(struct hists *self); 141unsigned int hists__sort_list_width(struct hists *self);
diff --git a/tools/perf/util/include/linux/compiler.h b/tools/perf/util/include/linux/compiler.h
index 791f9dd27ebf..547628e97f3d 100644
--- a/tools/perf/util/include/linux/compiler.h
+++ b/tools/perf/util/include/linux/compiler.h
@@ -5,7 +5,9 @@
5#define __always_inline inline 5#define __always_inline inline
6#endif 6#endif
7#define __user 7#define __user
8#ifndef __attribute_const__
8#define __attribute_const__ 9#define __attribute_const__
10#endif
9 11
10#define __used __attribute__((__unused__)) 12#define __used __attribute__((__unused__))
11 13
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index a16ecab5229d..78284b13e808 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -18,6 +18,13 @@ static inline int is_anon_memory(const char *filename)
18 return strcmp(filename, "//anon") == 0; 18 return strcmp(filename, "//anon") == 0;
19} 19}
20 20
21static inline int is_no_dso_memory(const char *filename)
22{
23 return !strcmp(filename, "[stack]") ||
24 !strcmp(filename, "[vdso]") ||
25 !strcmp(filename, "[heap]");
26}
27
21void map__init(struct map *self, enum map_type type, 28void map__init(struct map *self, enum map_type type,
22 u64 start, u64 end, u64 pgoff, struct dso *dso) 29 u64 start, u64 end, u64 pgoff, struct dso *dso)
23{ 30{
@@ -42,9 +49,10 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
42 if (self != NULL) { 49 if (self != NULL) {
43 char newfilename[PATH_MAX]; 50 char newfilename[PATH_MAX];
44 struct dso *dso; 51 struct dso *dso;
45 int anon; 52 int anon, no_dso;
46 53
47 anon = is_anon_memory(filename); 54 anon = is_anon_memory(filename);
55 no_dso = is_no_dso_memory(filename);
48 56
49 if (anon) { 57 if (anon) {
50 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid); 58 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid);
@@ -57,12 +65,16 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
57 65
58 map__init(self, type, start, start + len, pgoff, dso); 66 map__init(self, type, start, start + len, pgoff, dso);
59 67
60 if (anon) { 68 if (anon || no_dso) {
61set_identity:
62 self->map_ip = self->unmap_ip = identity__map_ip; 69 self->map_ip = self->unmap_ip = identity__map_ip;
63 } else if (strcmp(filename, "[vdso]") == 0) { 70
64 dso__set_loaded(dso, self->type); 71 /*
65 goto set_identity; 72 * Set memory without DSO as loaded. All map__find_*
73 * functions still return NULL, and we avoid the
74 * unnecessary map__load warning.
75 */
76 if (no_dso)
77 dso__set_loaded(dso, self->type);
66 } 78 }
67 } 79 }
68 return self; 80 return self;
@@ -127,8 +139,8 @@ int map__load(struct map *self, symbol_filter_t filter)
127 139
128 if (len > sizeof(DSO__DELETED) && 140 if (len > sizeof(DSO__DELETED) &&
129 strcmp(name + real_len + 1, DSO__DELETED) == 0) { 141 strcmp(name + real_len + 1, DSO__DELETED) == 0) {
130 pr_warning("%.*s was updated, restart the long " 142 pr_warning("%.*s was updated (is prelink enabled?). "
131 "running apps that use it!\n", 143 "Restart the long running apps that use it!\n",
132 (int)real_len, name); 144 (int)real_len, name);
133 } else { 145 } else {
134 pr_warning("no symbols found in %s, maybe install " 146 pr_warning("no symbols found in %s, maybe install "
@@ -220,55 +232,55 @@ u64 map__objdump_2ip(struct map *map, u64 addr)
220 return ip; 232 return ip;
221} 233}
222 234
223void map_groups__init(struct map_groups *self) 235void map_groups__init(struct map_groups *mg)
224{ 236{
225 int i; 237 int i;
226 for (i = 0; i < MAP__NR_TYPES; ++i) { 238 for (i = 0; i < MAP__NR_TYPES; ++i) {
227 self->maps[i] = RB_ROOT; 239 mg->maps[i] = RB_ROOT;
228 INIT_LIST_HEAD(&self->removed_maps[i]); 240 INIT_LIST_HEAD(&mg->removed_maps[i]);
229 } 241 }
230 self->machine = NULL; 242 mg->machine = NULL;
231} 243}
232 244
233static void maps__delete(struct rb_root *self) 245static void maps__delete(struct rb_root *maps)
234{ 246{
235 struct rb_node *next = rb_first(self); 247 struct rb_node *next = rb_first(maps);
236 248
237 while (next) { 249 while (next) {
238 struct map *pos = rb_entry(next, struct map, rb_node); 250 struct map *pos = rb_entry(next, struct map, rb_node);
239 251
240 next = rb_next(&pos->rb_node); 252 next = rb_next(&pos->rb_node);
241 rb_erase(&pos->rb_node, self); 253 rb_erase(&pos->rb_node, maps);
242 map__delete(pos); 254 map__delete(pos);
243 } 255 }
244} 256}
245 257
246static void maps__delete_removed(struct list_head *self) 258static void maps__delete_removed(struct list_head *maps)
247{ 259{
248 struct map *pos, *n; 260 struct map *pos, *n;
249 261
250 list_for_each_entry_safe(pos, n, self, node) { 262 list_for_each_entry_safe(pos, n, maps, node) {
251 list_del(&pos->node); 263 list_del(&pos->node);
252 map__delete(pos); 264 map__delete(pos);
253 } 265 }
254} 266}
255 267
256void map_groups__exit(struct map_groups *self) 268void map_groups__exit(struct map_groups *mg)
257{ 269{
258 int i; 270 int i;
259 271
260 for (i = 0; i < MAP__NR_TYPES; ++i) { 272 for (i = 0; i < MAP__NR_TYPES; ++i) {
261 maps__delete(&self->maps[i]); 273 maps__delete(&mg->maps[i]);
262 maps__delete_removed(&self->removed_maps[i]); 274 maps__delete_removed(&mg->removed_maps[i]);
263 } 275 }
264} 276}
265 277
266void map_groups__flush(struct map_groups *self) 278void map_groups__flush(struct map_groups *mg)
267{ 279{
268 int type; 280 int type;
269 281
270 for (type = 0; type < MAP__NR_TYPES; type++) { 282 for (type = 0; type < MAP__NR_TYPES; type++) {
271 struct rb_root *root = &self->maps[type]; 283 struct rb_root *root = &mg->maps[type];
272 struct rb_node *next = rb_first(root); 284 struct rb_node *next = rb_first(root);
273 285
274 while (next) { 286 while (next) {
@@ -280,17 +292,17 @@ void map_groups__flush(struct map_groups *self)
280 * instance in some hist_entry instances, so 292 * instance in some hist_entry instances, so
281 * just move them to a separate list. 293 * just move them to a separate list.
282 */ 294 */
283 list_add_tail(&pos->node, &self->removed_maps[pos->type]); 295 list_add_tail(&pos->node, &mg->removed_maps[pos->type]);
284 } 296 }
285 } 297 }
286} 298}
287 299
288struct symbol *map_groups__find_symbol(struct map_groups *self, 300struct symbol *map_groups__find_symbol(struct map_groups *mg,
289 enum map_type type, u64 addr, 301 enum map_type type, u64 addr,
290 struct map **mapp, 302 struct map **mapp,
291 symbol_filter_t filter) 303 symbol_filter_t filter)
292{ 304{
293 struct map *map = map_groups__find(self, type, addr); 305 struct map *map = map_groups__find(mg, type, addr);
294 306
295 if (map != NULL) { 307 if (map != NULL) {
296 if (mapp != NULL) 308 if (mapp != NULL)
@@ -301,7 +313,7 @@ struct symbol *map_groups__find_symbol(struct map_groups *self,
301 return NULL; 313 return NULL;
302} 314}
303 315
304struct symbol *map_groups__find_symbol_by_name(struct map_groups *self, 316struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg,
305 enum map_type type, 317 enum map_type type,
306 const char *name, 318 const char *name,
307 struct map **mapp, 319 struct map **mapp,
@@ -309,7 +321,7 @@ struct symbol *map_groups__find_symbol_by_name(struct map_groups *self,
309{ 321{
310 struct rb_node *nd; 322 struct rb_node *nd;
311 323
312 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { 324 for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) {
313 struct map *pos = rb_entry(nd, struct map, rb_node); 325 struct map *pos = rb_entry(nd, struct map, rb_node);
314 struct symbol *sym = map__find_symbol_by_name(pos, name, filter); 326 struct symbol *sym = map__find_symbol_by_name(pos, name, filter);
315 327
@@ -323,13 +335,13 @@ struct symbol *map_groups__find_symbol_by_name(struct map_groups *self,
323 return NULL; 335 return NULL;
324} 336}
325 337
326size_t __map_groups__fprintf_maps(struct map_groups *self, 338size_t __map_groups__fprintf_maps(struct map_groups *mg,
327 enum map_type type, int verbose, FILE *fp) 339 enum map_type type, int verbose, FILE *fp)
328{ 340{
329 size_t printed = fprintf(fp, "%s:\n", map_type__name[type]); 341 size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);
330 struct rb_node *nd; 342 struct rb_node *nd;
331 343
332 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { 344 for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) {
333 struct map *pos = rb_entry(nd, struct map, rb_node); 345 struct map *pos = rb_entry(nd, struct map, rb_node);
334 printed += fprintf(fp, "Map:"); 346 printed += fprintf(fp, "Map:");
335 printed += map__fprintf(pos, fp); 347 printed += map__fprintf(pos, fp);
@@ -342,22 +354,22 @@ size_t __map_groups__fprintf_maps(struct map_groups *self,
342 return printed; 354 return printed;
343} 355}
344 356
345size_t map_groups__fprintf_maps(struct map_groups *self, int verbose, FILE *fp) 357size_t map_groups__fprintf_maps(struct map_groups *mg, int verbose, FILE *fp)
346{ 358{
347 size_t printed = 0, i; 359 size_t printed = 0, i;
348 for (i = 0; i < MAP__NR_TYPES; ++i) 360 for (i = 0; i < MAP__NR_TYPES; ++i)
349 printed += __map_groups__fprintf_maps(self, i, verbose, fp); 361 printed += __map_groups__fprintf_maps(mg, i, verbose, fp);
350 return printed; 362 return printed;
351} 363}
352 364
353static size_t __map_groups__fprintf_removed_maps(struct map_groups *self, 365static size_t __map_groups__fprintf_removed_maps(struct map_groups *mg,
354 enum map_type type, 366 enum map_type type,
355 int verbose, FILE *fp) 367 int verbose, FILE *fp)
356{ 368{
357 struct map *pos; 369 struct map *pos;
358 size_t printed = 0; 370 size_t printed = 0;
359 371
360 list_for_each_entry(pos, &self->removed_maps[type], node) { 372 list_for_each_entry(pos, &mg->removed_maps[type], node) {
361 printed += fprintf(fp, "Map:"); 373 printed += fprintf(fp, "Map:");
362 printed += map__fprintf(pos, fp); 374 printed += map__fprintf(pos, fp);
363 if (verbose > 1) { 375 if (verbose > 1) {
@@ -368,26 +380,26 @@ static size_t __map_groups__fprintf_removed_maps(struct map_groups *self,
368 return printed; 380 return printed;
369} 381}
370 382
371static size_t map_groups__fprintf_removed_maps(struct map_groups *self, 383static size_t map_groups__fprintf_removed_maps(struct map_groups *mg,
372 int verbose, FILE *fp) 384 int verbose, FILE *fp)
373{ 385{
374 size_t printed = 0, i; 386 size_t printed = 0, i;
375 for (i = 0; i < MAP__NR_TYPES; ++i) 387 for (i = 0; i < MAP__NR_TYPES; ++i)
376 printed += __map_groups__fprintf_removed_maps(self, i, verbose, fp); 388 printed += __map_groups__fprintf_removed_maps(mg, i, verbose, fp);
377 return printed; 389 return printed;
378} 390}
379 391
380size_t map_groups__fprintf(struct map_groups *self, int verbose, FILE *fp) 392size_t map_groups__fprintf(struct map_groups *mg, int verbose, FILE *fp)
381{ 393{
382 size_t printed = map_groups__fprintf_maps(self, verbose, fp); 394 size_t printed = map_groups__fprintf_maps(mg, verbose, fp);
383 printed += fprintf(fp, "Removed maps:\n"); 395 printed += fprintf(fp, "Removed maps:\n");
384 return printed + map_groups__fprintf_removed_maps(self, verbose, fp); 396 return printed + map_groups__fprintf_removed_maps(mg, verbose, fp);
385} 397}
386 398
387int map_groups__fixup_overlappings(struct map_groups *self, struct map *map, 399int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map,
388 int verbose, FILE *fp) 400 int verbose, FILE *fp)
389{ 401{
390 struct rb_root *root = &self->maps[map->type]; 402 struct rb_root *root = &mg->maps[map->type];
391 struct rb_node *next = rb_first(root); 403 struct rb_node *next = rb_first(root);
392 int err = 0; 404 int err = 0;
393 405
@@ -418,7 +430,7 @@ int map_groups__fixup_overlappings(struct map_groups *self, struct map *map,
418 } 430 }
419 431
420 before->end = map->start - 1; 432 before->end = map->start - 1;
421 map_groups__insert(self, before); 433 map_groups__insert(mg, before);
422 if (verbose >= 2) 434 if (verbose >= 2)
423 map__fprintf(before, fp); 435 map__fprintf(before, fp);
424 } 436 }
@@ -432,7 +444,7 @@ int map_groups__fixup_overlappings(struct map_groups *self, struct map *map,
432 } 444 }
433 445
434 after->start = map->end + 1; 446 after->start = map->end + 1;
435 map_groups__insert(self, after); 447 map_groups__insert(mg, after);
436 if (verbose >= 2) 448 if (verbose >= 2)
437 map__fprintf(after, fp); 449 map__fprintf(after, fp);
438 } 450 }
@@ -441,7 +453,7 @@ move_map:
441 * If we have references, just move them to a separate list. 453 * If we have references, just move them to a separate list.
442 */ 454 */
443 if (pos->referenced) 455 if (pos->referenced)
444 list_add_tail(&pos->node, &self->removed_maps[map->type]); 456 list_add_tail(&pos->node, &mg->removed_maps[map->type]);
445 else 457 else
446 map__delete(pos); 458 map__delete(pos);
447 459
@@ -455,7 +467,7 @@ move_map:
455/* 467/*
456 * XXX This should not really _copy_ te maps, but refcount them. 468 * XXX This should not really _copy_ te maps, but refcount them.
457 */ 469 */
458int map_groups__clone(struct map_groups *self, 470int map_groups__clone(struct map_groups *mg,
459 struct map_groups *parent, enum map_type type) 471 struct map_groups *parent, enum map_type type)
460{ 472{
461 struct rb_node *nd; 473 struct rb_node *nd;
@@ -464,7 +476,7 @@ int map_groups__clone(struct map_groups *self,
464 struct map *new = map__clone(map); 476 struct map *new = map__clone(map);
465 if (new == NULL) 477 if (new == NULL)
466 return -ENOMEM; 478 return -ENOMEM;
467 map_groups__insert(self, new); 479 map_groups__insert(mg, new);
468 } 480 }
469 return 0; 481 return 0;
470} 482}
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index b397c0383728..890d85545d0f 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -123,17 +123,17 @@ void map__fixup_end(struct map *self);
123 123
124void map__reloc_vmlinux(struct map *self); 124void map__reloc_vmlinux(struct map *self);
125 125
126size_t __map_groups__fprintf_maps(struct map_groups *self, 126size_t __map_groups__fprintf_maps(struct map_groups *mg,
127 enum map_type type, int verbose, FILE *fp); 127 enum map_type type, int verbose, FILE *fp);
128void maps__insert(struct rb_root *maps, struct map *map); 128void maps__insert(struct rb_root *maps, struct map *map);
129void maps__remove(struct rb_root *self, struct map *map); 129void maps__remove(struct rb_root *maps, struct map *map);
130struct map *maps__find(struct rb_root *maps, u64 addr); 130struct map *maps__find(struct rb_root *maps, u64 addr);
131void map_groups__init(struct map_groups *self); 131void map_groups__init(struct map_groups *mg);
132void map_groups__exit(struct map_groups *self); 132void map_groups__exit(struct map_groups *mg);
133int map_groups__clone(struct map_groups *self, 133int map_groups__clone(struct map_groups *mg,
134 struct map_groups *parent, enum map_type type); 134 struct map_groups *parent, enum map_type type);
135size_t map_groups__fprintf(struct map_groups *self, int verbose, FILE *fp); 135size_t map_groups__fprintf(struct map_groups *mg, int verbose, FILE *fp);
136size_t map_groups__fprintf_maps(struct map_groups *self, int verbose, FILE *fp); 136size_t map_groups__fprintf_maps(struct map_groups *mg, int verbose, FILE *fp);
137 137
138typedef void (*machine__process_t)(struct machine *self, void *data); 138typedef void (*machine__process_t)(struct machine *self, void *data);
139 139
@@ -162,29 +162,29 @@ static inline bool machine__is_host(struct machine *self)
162 return self ? self->pid == HOST_KERNEL_ID : false; 162 return self ? self->pid == HOST_KERNEL_ID : false;
163} 163}
164 164
165static inline void map_groups__insert(struct map_groups *self, struct map *map) 165static inline void map_groups__insert(struct map_groups *mg, struct map *map)
166{ 166{
167 maps__insert(&self->maps[map->type], map); 167 maps__insert(&mg->maps[map->type], map);
168 map->groups = self; 168 map->groups = mg;
169} 169}
170 170
171static inline void map_groups__remove(struct map_groups *self, struct map *map) 171static inline void map_groups__remove(struct map_groups *mg, struct map *map)
172{ 172{
173 maps__remove(&self->maps[map->type], map); 173 maps__remove(&mg->maps[map->type], map);
174} 174}
175 175
176static inline struct map *map_groups__find(struct map_groups *self, 176static inline struct map *map_groups__find(struct map_groups *mg,
177 enum map_type type, u64 addr) 177 enum map_type type, u64 addr)
178{ 178{
179 return maps__find(&self->maps[type], addr); 179 return maps__find(&mg->maps[type], addr);
180} 180}
181 181
182struct symbol *map_groups__find_symbol(struct map_groups *self, 182struct symbol *map_groups__find_symbol(struct map_groups *mg,
183 enum map_type type, u64 addr, 183 enum map_type type, u64 addr,
184 struct map **mapp, 184 struct map **mapp,
185 symbol_filter_t filter); 185 symbol_filter_t filter);
186 186
187struct symbol *map_groups__find_symbol_by_name(struct map_groups *self, 187struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg,
188 enum map_type type, 188 enum map_type type,
189 const char *name, 189 const char *name,
190 struct map **mapp, 190 struct map **mapp,
@@ -208,11 +208,11 @@ struct symbol *machine__find_kernel_function(struct machine *self, u64 addr,
208} 208}
209 209
210static inline 210static inline
211struct symbol *map_groups__find_function_by_name(struct map_groups *self, 211struct symbol *map_groups__find_function_by_name(struct map_groups *mg,
212 const char *name, struct map **mapp, 212 const char *name, struct map **mapp,
213 symbol_filter_t filter) 213 symbol_filter_t filter)
214{ 214{
215 return map_groups__find_symbol_by_name(self, MAP__FUNCTION, name, mapp, filter); 215 return map_groups__find_symbol_by_name(mg, MAP__FUNCTION, name, mapp, filter);
216} 216}
217 217
218static inline 218static inline
@@ -225,13 +225,13 @@ struct symbol *machine__find_kernel_function_by_name(struct machine *self,
225 filter); 225 filter);
226} 226}
227 227
228int map_groups__fixup_overlappings(struct map_groups *self, struct map *map, 228int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map,
229 int verbose, FILE *fp); 229 int verbose, FILE *fp);
230 230
231struct map *map_groups__find_by_name(struct map_groups *self, 231struct map *map_groups__find_by_name(struct map_groups *mg,
232 enum map_type type, const char *name); 232 enum map_type type, const char *name);
233struct map *machine__new_module(struct machine *self, u64 start, const char *filename); 233struct map *machine__new_module(struct machine *self, u64 start, const char *filename);
234 234
235void map_groups__flush(struct map_groups *self); 235void map_groups__flush(struct map_groups *mg);
236 236
237#endif /* __PERF_MAP_H */ 237#endif /* __PERF_MAP_H */
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 41982c373faf..928918b796b2 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -86,22 +86,24 @@ static const char *sw_event_names[PERF_COUNT_SW_MAX] = {
86 86
87#define MAX_ALIASES 8 87#define MAX_ALIASES 8
88 88
89static const char *hw_cache[][MAX_ALIASES] = { 89static const char *hw_cache[PERF_COUNT_HW_CACHE_MAX][MAX_ALIASES] = {
90 { "L1-dcache", "l1-d", "l1d", "L1-data", }, 90 { "L1-dcache", "l1-d", "l1d", "L1-data", },
91 { "L1-icache", "l1-i", "l1i", "L1-instruction", }, 91 { "L1-icache", "l1-i", "l1i", "L1-instruction", },
92 { "LLC", "L2" }, 92 { "LLC", "L2", },
93 { "dTLB", "d-tlb", "Data-TLB", }, 93 { "dTLB", "d-tlb", "Data-TLB", },
94 { "iTLB", "i-tlb", "Instruction-TLB", }, 94 { "iTLB", "i-tlb", "Instruction-TLB", },
95 { "branch", "branches", "bpu", "btb", "bpc", }, 95 { "branch", "branches", "bpu", "btb", "bpc", },
96 { "node", },
96}; 97};
97 98
98static const char *hw_cache_op[][MAX_ALIASES] = { 99static const char *hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX][MAX_ALIASES] = {
99 { "load", "loads", "read", }, 100 { "load", "loads", "read", },
100 { "store", "stores", "write", }, 101 { "store", "stores", "write", },
101 { "prefetch", "prefetches", "speculative-read", "speculative-load", }, 102 { "prefetch", "prefetches", "speculative-read", "speculative-load", },
102}; 103};
103 104
104static const char *hw_cache_result[][MAX_ALIASES] = { 105static const char *hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX]
106 [MAX_ALIASES] = {
105 { "refs", "Reference", "ops", "access", }, 107 { "refs", "Reference", "ops", "access", },
106 { "misses", "miss", }, 108 { "misses", "miss", },
107}; 109};
@@ -124,6 +126,7 @@ static unsigned long hw_cache_stat[C(MAX)] = {
124 [C(DTLB)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH), 126 [C(DTLB)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
125 [C(ITLB)] = (CACHE_READ), 127 [C(ITLB)] = (CACHE_READ),
126 [C(BPU)] = (CACHE_READ), 128 [C(BPU)] = (CACHE_READ),
129 [C(NODE)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
127}; 130};
128 131
129#define for_each_subsystem(sys_dir, sys_dirent, sys_next) \ 132#define for_each_subsystem(sys_dir, sys_dirent, sys_next) \
@@ -393,7 +396,7 @@ parse_generic_hw_event(const char **str, struct perf_event_attr *attr)
393 PERF_COUNT_HW_CACHE_OP_MAX); 396 PERF_COUNT_HW_CACHE_OP_MAX);
394 if (cache_op >= 0) { 397 if (cache_op >= 0) {
395 if (!is_cache_op_valid(cache_type, cache_op)) 398 if (!is_cache_op_valid(cache_type, cache_op))
396 return 0; 399 return EVT_FAILED;
397 continue; 400 continue;
398 } 401 }
399 } 402 }
@@ -475,7 +478,7 @@ parse_single_tracepoint_event(char *sys_name,
475/* sys + ':' + event + ':' + flags*/ 478/* sys + ':' + event + ':' + flags*/
476#define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128) 479#define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128)
477static enum event_result 480static enum event_result
478parse_multiple_tracepoint_event(const struct option *opt, char *sys_name, 481parse_multiple_tracepoint_event(struct perf_evlist *evlist, char *sys_name,
479 const char *evt_exp, char *flags) 482 const char *evt_exp, char *flags)
480{ 483{
481 char evt_path[MAXPATHLEN]; 484 char evt_path[MAXPATHLEN];
@@ -509,7 +512,7 @@ parse_multiple_tracepoint_event(const struct option *opt, char *sys_name,
509 if (len < 0) 512 if (len < 0)
510 return EVT_FAILED; 513 return EVT_FAILED;
511 514
512 if (parse_events(opt, event_opt, 0)) 515 if (parse_events(evlist, event_opt, 0))
513 return EVT_FAILED; 516 return EVT_FAILED;
514 } 517 }
515 518
@@ -517,7 +520,7 @@ parse_multiple_tracepoint_event(const struct option *opt, char *sys_name,
517} 520}
518 521
519static enum event_result 522static enum event_result
520parse_tracepoint_event(const struct option *opt, const char **strp, 523parse_tracepoint_event(struct perf_evlist *evlist, const char **strp,
521 struct perf_event_attr *attr) 524 struct perf_event_attr *attr)
522{ 525{
523 const char *evt_name; 526 const char *evt_name;
@@ -557,8 +560,8 @@ parse_tracepoint_event(const struct option *opt, const char **strp,
557 return EVT_FAILED; 560 return EVT_FAILED;
558 if (strpbrk(evt_name, "*?")) { 561 if (strpbrk(evt_name, "*?")) {
559 *strp += strlen(sys_name) + evt_length + 1; /* 1 == the ':' */ 562 *strp += strlen(sys_name) + evt_length + 1; /* 1 == the ':' */
560 return parse_multiple_tracepoint_event(opt, sys_name, evt_name, 563 return parse_multiple_tracepoint_event(evlist, sys_name,
561 flags); 564 evt_name, flags);
562 } else { 565 } else {
563 return parse_single_tracepoint_event(sys_name, evt_name, 566 return parse_single_tracepoint_event(sys_name, evt_name,
564 evt_length, attr, strp); 567 evt_length, attr, strp);
@@ -694,7 +697,11 @@ parse_raw_event(const char **strp, struct perf_event_attr *attr)
694 return EVT_FAILED; 697 return EVT_FAILED;
695 n = hex2u64(str + 1, &config); 698 n = hex2u64(str + 1, &config);
696 if (n > 0) { 699 if (n > 0) {
697 *strp = str + n + 1; 700 const char *end = str + n + 1;
701 if (*end != '\0' && *end != ',' && *end != ':')
702 return EVT_FAILED;
703
704 *strp = end;
698 attr->type = PERF_TYPE_RAW; 705 attr->type = PERF_TYPE_RAW;
699 attr->config = config; 706 attr->config = config;
700 return EVT_HANDLED; 707 return EVT_HANDLED;
@@ -778,12 +785,12 @@ parse_event_modifier(const char **strp, struct perf_event_attr *attr)
778 * Symbolic names are (almost) exactly matched. 785 * Symbolic names are (almost) exactly matched.
779 */ 786 */
780static enum event_result 787static enum event_result
781parse_event_symbols(const struct option *opt, const char **str, 788parse_event_symbols(struct perf_evlist *evlist, const char **str,
782 struct perf_event_attr *attr) 789 struct perf_event_attr *attr)
783{ 790{
784 enum event_result ret; 791 enum event_result ret;
785 792
786 ret = parse_tracepoint_event(opt, str, attr); 793 ret = parse_tracepoint_event(evlist, str, attr);
787 if (ret != EVT_FAILED) 794 if (ret != EVT_FAILED)
788 goto modifier; 795 goto modifier;
789 796
@@ -822,9 +829,8 @@ modifier:
822 return ret; 829 return ret;
823} 830}
824 831
825int parse_events(const struct option *opt, const char *str, int unset __used) 832int parse_events(struct perf_evlist *evlist , const char *str, int unset __used)
826{ 833{
827 struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
828 struct perf_event_attr attr; 834 struct perf_event_attr attr;
829 enum event_result ret; 835 enum event_result ret;
830 const char *ostr; 836 const char *ostr;
@@ -832,7 +838,7 @@ int parse_events(const struct option *opt, const char *str, int unset __used)
832 for (;;) { 838 for (;;) {
833 ostr = str; 839 ostr = str;
834 memset(&attr, 0, sizeof(attr)); 840 memset(&attr, 0, sizeof(attr));
835 ret = parse_event_symbols(opt, &str, &attr); 841 ret = parse_event_symbols(evlist, &str, &attr);
836 if (ret == EVT_FAILED) 842 if (ret == EVT_FAILED)
837 return -1; 843 return -1;
838 844
@@ -863,6 +869,13 @@ int parse_events(const struct option *opt, const char *str, int unset __used)
863 return 0; 869 return 0;
864} 870}
865 871
872int parse_events_option(const struct option *opt, const char *str,
873 int unset __used)
874{
875 struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
876 return parse_events(evlist, str, unset);
877}
878
866int parse_filter(const struct option *opt, const char *str, 879int parse_filter(const struct option *opt, const char *str,
867 int unset __used) 880 int unset __used)
868{ 881{
@@ -1088,6 +1101,4 @@ void print_events(const char *event_glob)
1088 printf("\n"); 1101 printf("\n");
1089 1102
1090 print_tracepoint_events(NULL, NULL); 1103 print_tracepoint_events(NULL, NULL);
1091
1092 exit(129);
1093} 1104}
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 746d3fcbfc2a..2f8e375e038d 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -8,6 +8,7 @@
8 8
9struct list_head; 9struct list_head;
10struct perf_evsel; 10struct perf_evsel;
11struct perf_evlist;
11 12
12struct option; 13struct option;
13 14
@@ -24,7 +25,10 @@ const char *event_type(int type);
24const char *event_name(struct perf_evsel *event); 25const char *event_name(struct perf_evsel *event);
25extern const char *__event_name(int type, u64 config); 26extern const char *__event_name(int type, u64 config);
26 27
27extern int parse_events(const struct option *opt, const char *str, int unset); 28extern int parse_events_option(const struct option *opt, const char *str,
29 int unset);
30extern int parse_events(struct perf_evlist *evlist, const char *str,
31 int unset);
28extern int parse_filter(const struct option *opt, const char *str, int unset); 32extern int parse_filter(const struct option *opt, const char *str, int unset);
29 33
30#define EVENTS_HELP_MAX (128*1024) 34#define EVENTS_HELP_MAX (128*1024)
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index f0223166e761..eb25900e2211 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -117,6 +117,10 @@ static struct map *kernel_get_module_map(const char *module)
117 struct rb_node *nd; 117 struct rb_node *nd;
118 struct map_groups *grp = &machine.kmaps; 118 struct map_groups *grp = &machine.kmaps;
119 119
120 /* A file path -- this is an offline module */
121 if (module && strchr(module, '/'))
122 return machine__new_module(&machine, 0, module);
123
120 if (!module) 124 if (!module)
121 module = "kernel"; 125 module = "kernel";
122 126
@@ -170,16 +174,24 @@ const char *kernel_get_module_path(const char *module)
170} 174}
171 175
172#ifdef DWARF_SUPPORT 176#ifdef DWARF_SUPPORT
173static int open_vmlinux(const char *module) 177/* Open new debuginfo of given module */
178static struct debuginfo *open_debuginfo(const char *module)
174{ 179{
175 const char *path = kernel_get_module_path(module); 180 const char *path;
176 if (!path) { 181
177 pr_err("Failed to find path of %s module.\n", 182 /* A file path -- this is an offline module */
178 module ?: "kernel"); 183 if (module && strchr(module, '/'))
179 return -ENOENT; 184 path = module;
185 else {
186 path = kernel_get_module_path(module);
187
188 if (!path) {
189 pr_err("Failed to find path of %s module.\n",
190 module ?: "kernel");
191 return NULL;
192 }
180 } 193 }
181 pr_debug("Try to open %s\n", path); 194 return debuginfo__new(path);
182 return open(path, O_RDONLY);
183} 195}
184 196
185/* 197/*
@@ -193,13 +205,24 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
193 struct map *map; 205 struct map *map;
194 u64 addr; 206 u64 addr;
195 int ret = -ENOENT; 207 int ret = -ENOENT;
208 struct debuginfo *dinfo;
196 209
197 sym = __find_kernel_function_by_name(tp->symbol, &map); 210 sym = __find_kernel_function_by_name(tp->symbol, &map);
198 if (sym) { 211 if (sym) {
199 addr = map->unmap_ip(map, sym->start + tp->offset); 212 addr = map->unmap_ip(map, sym->start + tp->offset);
200 pr_debug("try to find %s+%ld@%" PRIx64 "\n", tp->symbol, 213 pr_debug("try to find %s+%ld@%" PRIx64 "\n", tp->symbol,
201 tp->offset, addr); 214 tp->offset, addr);
202 ret = find_perf_probe_point((unsigned long)addr, pp); 215
216 dinfo = debuginfo__new_online_kernel(addr);
217 if (dinfo) {
218 ret = debuginfo__find_probe_point(dinfo,
219 (unsigned long)addr, pp);
220 debuginfo__delete(dinfo);
221 } else {
222 pr_debug("Failed to open debuginfo at 0x%" PRIx64 "\n",
223 addr);
224 ret = -ENOENT;
225 }
203 } 226 }
204 if (ret <= 0) { 227 if (ret <= 0) {
205 pr_debug("Failed to find corresponding probes from " 228 pr_debug("Failed to find corresponding probes from "
@@ -214,30 +237,70 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
214 return 0; 237 return 0;
215} 238}
216 239
240static int add_module_to_probe_trace_events(struct probe_trace_event *tevs,
241 int ntevs, const char *module)
242{
243 int i, ret = 0;
244 char *tmp;
245
246 if (!module)
247 return 0;
248
249 tmp = strrchr(module, '/');
250 if (tmp) {
251 /* This is a module path -- get the module name */
252 module = strdup(tmp + 1);
253 if (!module)
254 return -ENOMEM;
255 tmp = strchr(module, '.');
256 if (tmp)
257 *tmp = '\0';
258 tmp = (char *)module; /* For free() */
259 }
260
261 for (i = 0; i < ntevs; i++) {
262 tevs[i].point.module = strdup(module);
263 if (!tevs[i].point.module) {
264 ret = -ENOMEM;
265 break;
266 }
267 }
268
269 if (tmp)
270 free(tmp);
271
272 return ret;
273}
274
217/* Try to find perf_probe_event with debuginfo */ 275/* Try to find perf_probe_event with debuginfo */
218static int try_to_find_probe_trace_events(struct perf_probe_event *pev, 276static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
219 struct probe_trace_event **tevs, 277 struct probe_trace_event **tevs,
220 int max_tevs, const char *module) 278 int max_tevs, const char *module)
221{ 279{
222 bool need_dwarf = perf_probe_event_need_dwarf(pev); 280 bool need_dwarf = perf_probe_event_need_dwarf(pev);
223 int fd, ntevs; 281 struct debuginfo *dinfo = open_debuginfo(module);
282 int ntevs, ret = 0;
224 283
225 fd = open_vmlinux(module); 284 if (!dinfo) {
226 if (fd < 0) {
227 if (need_dwarf) { 285 if (need_dwarf) {
228 pr_warning("Failed to open debuginfo file.\n"); 286 pr_warning("Failed to open debuginfo file.\n");
229 return fd; 287 return -ENOENT;
230 } 288 }
231 pr_debug("Could not open vmlinux. Try to use symbols.\n"); 289 pr_debug("Could not open debuginfo. Try to use symbols.\n");
232 return 0; 290 return 0;
233 } 291 }
234 292
235 /* Searching trace events corresponding to probe event */ 293 /* Searching trace events corresponding to a probe event */
236 ntevs = find_probe_trace_events(fd, pev, tevs, max_tevs); 294 ntevs = debuginfo__find_trace_events(dinfo, pev, tevs, max_tevs);
295
296 debuginfo__delete(dinfo);
237 297
238 if (ntevs > 0) { /* Succeeded to find trace events */ 298 if (ntevs > 0) { /* Succeeded to find trace events */
239 pr_debug("find %d probe_trace_events.\n", ntevs); 299 pr_debug("find %d probe_trace_events.\n", ntevs);
240 return ntevs; 300 if (module)
301 ret = add_module_to_probe_trace_events(*tevs, ntevs,
302 module);
303 return ret < 0 ? ret : ntevs;
241 } 304 }
242 305
243 if (ntevs == 0) { /* No error but failed to find probe point. */ 306 if (ntevs == 0) { /* No error but failed to find probe point. */
@@ -371,8 +434,9 @@ int show_line_range(struct line_range *lr, const char *module)
371{ 434{
372 int l = 1; 435 int l = 1;
373 struct line_node *ln; 436 struct line_node *ln;
437 struct debuginfo *dinfo;
374 FILE *fp; 438 FILE *fp;
375 int fd, ret; 439 int ret;
376 char *tmp; 440 char *tmp;
377 441
378 /* Search a line range */ 442 /* Search a line range */
@@ -380,13 +444,14 @@ int show_line_range(struct line_range *lr, const char *module)
380 if (ret < 0) 444 if (ret < 0)
381 return ret; 445 return ret;
382 446
383 fd = open_vmlinux(module); 447 dinfo = open_debuginfo(module);
384 if (fd < 0) { 448 if (!dinfo) {
385 pr_warning("Failed to open debuginfo file.\n"); 449 pr_warning("Failed to open debuginfo file.\n");
386 return fd; 450 return -ENOENT;
387 } 451 }
388 452
389 ret = find_line_range(fd, lr); 453 ret = debuginfo__find_line_range(dinfo, lr);
454 debuginfo__delete(dinfo);
390 if (ret == 0) { 455 if (ret == 0) {
391 pr_warning("Specified source line is not found.\n"); 456 pr_warning("Specified source line is not found.\n");
392 return -ENOENT; 457 return -ENOENT;
@@ -448,7 +513,8 @@ end:
448 return ret; 513 return ret;
449} 514}
450 515
451static int show_available_vars_at(int fd, struct perf_probe_event *pev, 516static int show_available_vars_at(struct debuginfo *dinfo,
517 struct perf_probe_event *pev,
452 int max_vls, struct strfilter *_filter, 518 int max_vls, struct strfilter *_filter,
453 bool externs) 519 bool externs)
454{ 520{
@@ -463,7 +529,8 @@ static int show_available_vars_at(int fd, struct perf_probe_event *pev,
463 return -EINVAL; 529 return -EINVAL;
464 pr_debug("Searching variables at %s\n", buf); 530 pr_debug("Searching variables at %s\n", buf);
465 531
466 ret = find_available_vars_at(fd, pev, &vls, max_vls, externs); 532 ret = debuginfo__find_available_vars_at(dinfo, pev, &vls,
533 max_vls, externs);
467 if (ret <= 0) { 534 if (ret <= 0) {
468 pr_err("Failed to find variables at %s (%d)\n", buf, ret); 535 pr_err("Failed to find variables at %s (%d)\n", buf, ret);
469 goto end; 536 goto end;
@@ -504,24 +571,26 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
504 int max_vls, const char *module, 571 int max_vls, const char *module,
505 struct strfilter *_filter, bool externs) 572 struct strfilter *_filter, bool externs)
506{ 573{
507 int i, fd, ret = 0; 574 int i, ret = 0;
575 struct debuginfo *dinfo;
508 576
509 ret = init_vmlinux(); 577 ret = init_vmlinux();
510 if (ret < 0) 578 if (ret < 0)
511 return ret; 579 return ret;
512 580
581 dinfo = open_debuginfo(module);
582 if (!dinfo) {
583 pr_warning("Failed to open debuginfo file.\n");
584 return -ENOENT;
585 }
586
513 setup_pager(); 587 setup_pager();
514 588
515 for (i = 0; i < npevs && ret >= 0; i++) { 589 for (i = 0; i < npevs && ret >= 0; i++)
516 fd = open_vmlinux(module); 590 ret = show_available_vars_at(dinfo, &pevs[i], max_vls, _filter,
517 if (fd < 0) {
518 pr_warning("Failed to open debug information file.\n");
519 ret = fd;
520 break;
521 }
522 ret = show_available_vars_at(fd, &pevs[i], max_vls, _filter,
523 externs); 591 externs);
524 } 592
593 debuginfo__delete(dinfo);
525 return ret; 594 return ret;
526} 595}
527 596
@@ -990,7 +1059,7 @@ bool perf_probe_event_need_dwarf(struct perf_probe_event *pev)
990 1059
991/* Parse probe_events event into struct probe_point */ 1060/* Parse probe_events event into struct probe_point */
992static int parse_probe_trace_command(const char *cmd, 1061static int parse_probe_trace_command(const char *cmd,
993 struct probe_trace_event *tev) 1062 struct probe_trace_event *tev)
994{ 1063{
995 struct probe_trace_point *tp = &tev->point; 1064 struct probe_trace_point *tp = &tev->point;
996 char pr; 1065 char pr;
@@ -1023,8 +1092,14 @@ static int parse_probe_trace_command(const char *cmd,
1023 1092
1024 tp->retprobe = (pr == 'r'); 1093 tp->retprobe = (pr == 'r');
1025 1094
1026 /* Scan function name and offset */ 1095 /* Scan module name(if there), function name and offset */
1027 ret = sscanf(argv[1], "%a[^+]+%lu", (float *)(void *)&tp->symbol, 1096 p = strchr(argv[1], ':');
1097 if (p) {
1098 tp->module = strndup(argv[1], p - argv[1]);
1099 p++;
1100 } else
1101 p = argv[1];
1102 ret = sscanf(p, "%a[^+]+%lu", (float *)(void *)&tp->symbol,
1028 &tp->offset); 1103 &tp->offset);
1029 if (ret == 1) 1104 if (ret == 1)
1030 tp->offset = 0; 1105 tp->offset = 0;
@@ -1269,9 +1344,10 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev)
1269 if (buf == NULL) 1344 if (buf == NULL)
1270 return NULL; 1345 return NULL;
1271 1346
1272 len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s+%lu", 1347 len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu",
1273 tp->retprobe ? 'r' : 'p', 1348 tp->retprobe ? 'r' : 'p',
1274 tev->group, tev->event, 1349 tev->group, tev->event,
1350 tp->module ?: "", tp->module ? ":" : "",
1275 tp->symbol, tp->offset); 1351 tp->symbol, tp->offset);
1276 if (len <= 0) 1352 if (len <= 0)
1277 goto error; 1353 goto error;
@@ -1378,6 +1454,8 @@ static void clear_probe_trace_event(struct probe_trace_event *tev)
1378 free(tev->group); 1454 free(tev->group);
1379 if (tev->point.symbol) 1455 if (tev->point.symbol)
1380 free(tev->point.symbol); 1456 free(tev->point.symbol);
1457 if (tev->point.module)
1458 free(tev->point.module);
1381 for (i = 0; i < tev->nargs; i++) { 1459 for (i = 0; i < tev->nargs; i++) {
1382 if (tev->args[i].name) 1460 if (tev->args[i].name)
1383 free(tev->args[i].name); 1461 free(tev->args[i].name);
@@ -1729,7 +1807,7 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
1729 /* Convert perf_probe_event with debuginfo */ 1807 /* Convert perf_probe_event with debuginfo */
1730 ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, module); 1808 ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, module);
1731 if (ret != 0) 1809 if (ret != 0)
1732 return ret; 1810 return ret; /* Found in debuginfo or got an error */
1733 1811
1734 /* Allocate trace event buffer */ 1812 /* Allocate trace event buffer */
1735 tev = *tevs = zalloc(sizeof(struct probe_trace_event)); 1813 tev = *tevs = zalloc(sizeof(struct probe_trace_event));
@@ -1742,6 +1820,15 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
1742 ret = -ENOMEM; 1820 ret = -ENOMEM;
1743 goto error; 1821 goto error;
1744 } 1822 }
1823
1824 if (module) {
1825 tev->point.module = strdup(module);
1826 if (tev->point.module == NULL) {
1827 ret = -ENOMEM;
1828 goto error;
1829 }
1830 }
1831
1745 tev->point.offset = pev->point.offset; 1832 tev->point.offset = pev->point.offset;
1746 tev->point.retprobe = pev->point.retprobe; 1833 tev->point.retprobe = pev->point.retprobe;
1747 tev->nargs = pev->nargs; 1834 tev->nargs = pev->nargs;
@@ -1869,8 +1956,10 @@ static int __del_trace_probe_event(int fd, struct str_node *ent)
1869 1956
1870 pr_debug("Writing event: %s\n", buf); 1957 pr_debug("Writing event: %s\n", buf);
1871 ret = write(fd, buf, strlen(buf)); 1958 ret = write(fd, buf, strlen(buf));
1872 if (ret < 0) 1959 if (ret < 0) {
1960 ret = -errno;
1873 goto error; 1961 goto error;
1962 }
1874 1963
1875 printf("Remove event: %s\n", ent->s); 1964 printf("Remove event: %s\n", ent->s);
1876 return 0; 1965 return 0;
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 3434fc9d79d5..a7dee835f49c 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -10,6 +10,7 @@ extern bool probe_event_dry_run;
10/* kprobe-tracer tracing point */ 10/* kprobe-tracer tracing point */
11struct probe_trace_point { 11struct probe_trace_point {
12 char *symbol; /* Base symbol */ 12 char *symbol; /* Base symbol */
13 char *module; /* Module name */
13 unsigned long offset; /* Offset from symbol */ 14 unsigned long offset; /* Offset from symbol */
14 bool retprobe; /* Return probe flag */ 15 bool retprobe; /* Return probe flag */
15}; 16};
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 3b9d0b800d5c..5d732621a462 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -43,21 +43,6 @@
43/* Kprobe tracer basic type is up to u64 */ 43/* Kprobe tracer basic type is up to u64 */
44#define MAX_BASIC_TYPE_BITS 64 44#define MAX_BASIC_TYPE_BITS 64
45 45
46/*
47 * Compare the tail of two strings.
48 * Return 0 if whole of either string is same as another's tail part.
49 */
50static int strtailcmp(const char *s1, const char *s2)
51{
52 int i1 = strlen(s1);
53 int i2 = strlen(s2);
54 while (--i1 >= 0 && --i2 >= 0) {
55 if (s1[i1] != s2[i2])
56 return s1[i1] - s2[i2];
57 }
58 return 0;
59}
60
61/* Line number list operations */ 46/* Line number list operations */
62 47
63/* Add a line to line number list */ 48/* Add a line to line number list */
@@ -131,29 +116,37 @@ static const Dwfl_Callbacks offline_callbacks = {
131}; 116};
132 117
133/* Get a Dwarf from offline image */ 118/* Get a Dwarf from offline image */
134static Dwarf *dwfl_init_offline_dwarf(int fd, Dwfl **dwflp, Dwarf_Addr *bias) 119static int debuginfo__init_offline_dwarf(struct debuginfo *self,
120 const char *path)
135{ 121{
136 Dwfl_Module *mod; 122 Dwfl_Module *mod;
137 Dwarf *dbg = NULL; 123 int fd;
138 124
139 if (!dwflp) 125 fd = open(path, O_RDONLY);
140 return NULL; 126 if (fd < 0)
127 return fd;
141 128
142 *dwflp = dwfl_begin(&offline_callbacks); 129 self->dwfl = dwfl_begin(&offline_callbacks);
143 if (!*dwflp) 130 if (!self->dwfl)
144 return NULL; 131 goto error;
145 132
146 mod = dwfl_report_offline(*dwflp, "", "", fd); 133 mod = dwfl_report_offline(self->dwfl, "", "", fd);
147 if (!mod) 134 if (!mod)
148 goto error; 135 goto error;
149 136
150 dbg = dwfl_module_getdwarf(mod, bias); 137 self->dbg = dwfl_module_getdwarf(mod, &self->bias);
151 if (!dbg) { 138 if (!self->dbg)
139 goto error;
140
141 return 0;
152error: 142error:
153 dwfl_end(*dwflp); 143 if (self->dwfl)
154 *dwflp = NULL; 144 dwfl_end(self->dwfl);
155 } 145 else
156 return dbg; 146 close(fd);
147 memset(self, 0, sizeof(*self));
148
149 return -ENOENT;
157} 150}
158 151
159#if _ELFUTILS_PREREQ(0, 148) 152#if _ELFUTILS_PREREQ(0, 148)
@@ -189,597 +182,81 @@ static const Dwfl_Callbacks kernel_callbacks = {
189}; 182};
190 183
191/* Get a Dwarf from live kernel image */ 184/* Get a Dwarf from live kernel image */
192static Dwarf *dwfl_init_live_kernel_dwarf(Dwarf_Addr addr, Dwfl **dwflp, 185static int debuginfo__init_online_kernel_dwarf(struct debuginfo *self,
193 Dwarf_Addr *bias) 186 Dwarf_Addr addr)
194{ 187{
195 Dwarf *dbg; 188 self->dwfl = dwfl_begin(&kernel_callbacks);
196 189 if (!self->dwfl)
197 if (!dwflp) 190 return -EINVAL;
198 return NULL;
199
200 *dwflp = dwfl_begin(&kernel_callbacks);
201 if (!*dwflp)
202 return NULL;
203 191
204 /* Load the kernel dwarves: Don't care the result here */ 192 /* Load the kernel dwarves: Don't care the result here */
205 dwfl_linux_kernel_report_kernel(*dwflp); 193 dwfl_linux_kernel_report_kernel(self->dwfl);
206 dwfl_linux_kernel_report_modules(*dwflp); 194 dwfl_linux_kernel_report_modules(self->dwfl);
207 195
208 dbg = dwfl_addrdwarf(*dwflp, addr, bias); 196 self->dbg = dwfl_addrdwarf(self->dwfl, addr, &self->bias);
209 /* Here, check whether we could get a real dwarf */ 197 /* Here, check whether we could get a real dwarf */
210 if (!dbg) { 198 if (!self->dbg) {
211 pr_debug("Failed to find kernel dwarf at %lx\n", 199 pr_debug("Failed to find kernel dwarf at %lx\n",
212 (unsigned long)addr); 200 (unsigned long)addr);
213 dwfl_end(*dwflp); 201 dwfl_end(self->dwfl);
214 *dwflp = NULL; 202 memset(self, 0, sizeof(*self));
203 return -ENOENT;
215 } 204 }
216 return dbg; 205
206 return 0;
217} 207}
218#else 208#else
219/* With older elfutils, this just support kernel module... */ 209/* With older elfutils, this just support kernel module... */
220static Dwarf *dwfl_init_live_kernel_dwarf(Dwarf_Addr addr __used, Dwfl **dwflp, 210static int debuginfo__init_online_kernel_dwarf(struct debuginfo *self,
221 Dwarf_Addr *bias) 211 Dwarf_Addr addr __used)
222{ 212{
223 int fd;
224 const char *path = kernel_get_module_path("kernel"); 213 const char *path = kernel_get_module_path("kernel");
225 214
226 if (!path) { 215 if (!path) {
227 pr_err("Failed to find vmlinux path\n"); 216 pr_err("Failed to find vmlinux path\n");
228 return NULL; 217 return -ENOENT;
229 } 218 }
230 219
231 pr_debug2("Use file %s for debuginfo\n", path); 220 pr_debug2("Use file %s for debuginfo\n", path);
232 fd = open(path, O_RDONLY); 221 return debuginfo__init_offline_dwarf(self, path);
233 if (fd < 0)
234 return NULL;
235
236 return dwfl_init_offline_dwarf(fd, dwflp, bias);
237} 222}
238#endif 223#endif
239 224
240/* Dwarf wrappers */ 225struct debuginfo *debuginfo__new(const char *path)
241
242/* Find the realpath of the target file. */
243static const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname)
244{ 226{
245 Dwarf_Files *files; 227 struct debuginfo *self = zalloc(sizeof(struct debuginfo));
246 size_t nfiles, i; 228 if (!self)
247 const char *src = NULL;
248 int ret;
249
250 if (!fname)
251 return NULL; 229 return NULL;
252 230
253 ret = dwarf_getsrcfiles(cu_die, &files, &nfiles); 231 if (debuginfo__init_offline_dwarf(self, path) < 0) {
254 if (ret != 0) 232 free(self);
255 return NULL; 233 self = NULL;
256
257 for (i = 0; i < nfiles; i++) {
258 src = dwarf_filesrc(files, i, NULL, NULL);
259 if (strtailcmp(src, fname) == 0)
260 break;
261 } 234 }
262 if (i == nfiles)
263 return NULL;
264 return src;
265}
266 235
267/* Get DW_AT_comp_dir (should be NULL with older gcc) */ 236 return self;
268static const char *cu_get_comp_dir(Dwarf_Die *cu_die)
269{
270 Dwarf_Attribute attr;
271 if (dwarf_attr(cu_die, DW_AT_comp_dir, &attr) == NULL)
272 return NULL;
273 return dwarf_formstring(&attr);
274} 237}
275 238
276/* Get a line number and file name for given address */ 239struct debuginfo *debuginfo__new_online_kernel(unsigned long addr)
277static int cu_find_lineinfo(Dwarf_Die *cudie, unsigned long addr,
278 const char **fname, int *lineno)
279{ 240{
280 Dwarf_Line *line; 241 struct debuginfo *self = zalloc(sizeof(struct debuginfo));
281 Dwarf_Addr laddr; 242 if (!self)
282
283 line = dwarf_getsrc_die(cudie, (Dwarf_Addr)addr);
284 if (line && dwarf_lineaddr(line, &laddr) == 0 &&
285 addr == (unsigned long)laddr && dwarf_lineno(line, lineno) == 0) {
286 *fname = dwarf_linesrc(line, NULL, NULL);
287 if (!*fname)
288 /* line number is useless without filename */
289 *lineno = 0;
290 }
291
292 return *lineno ?: -ENOENT;
293}
294
295/* Compare diename and tname */
296static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
297{
298 const char *name;
299 name = dwarf_diename(dw_die);
300 return name ? (strcmp(tname, name) == 0) : false;
301}
302
303/* Get callsite line number of inline-function instance */
304static int die_get_call_lineno(Dwarf_Die *in_die)
305{
306 Dwarf_Attribute attr;
307 Dwarf_Word ret;
308
309 if (!dwarf_attr(in_die, DW_AT_call_line, &attr))
310 return -ENOENT;
311
312 dwarf_formudata(&attr, &ret);
313 return (int)ret;
314}
315
316/* Get type die */
317static Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
318{
319 Dwarf_Attribute attr;
320
321 if (dwarf_attr_integrate(vr_die, DW_AT_type, &attr) &&
322 dwarf_formref_die(&attr, die_mem))
323 return die_mem;
324 else
325 return NULL; 243 return NULL;
326}
327
328/* Get a type die, but skip qualifiers */
329static Dwarf_Die *__die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
330{
331 int tag;
332
333 do {
334 vr_die = die_get_type(vr_die, die_mem);
335 if (!vr_die)
336 break;
337 tag = dwarf_tag(vr_die);
338 } while (tag == DW_TAG_const_type ||
339 tag == DW_TAG_restrict_type ||
340 tag == DW_TAG_volatile_type ||
341 tag == DW_TAG_shared_type);
342
343 return vr_die;
344}
345
346/* Get a type die, but skip qualifiers and typedef */
347static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
348{
349 do {
350 vr_die = __die_get_real_type(vr_die, die_mem);
351 } while (vr_die && dwarf_tag(vr_die) == DW_TAG_typedef);
352
353 return vr_die;
354}
355
356static int die_get_attr_udata(Dwarf_Die *tp_die, unsigned int attr_name,
357 Dwarf_Word *result)
358{
359 Dwarf_Attribute attr;
360
361 if (dwarf_attr(tp_die, attr_name, &attr) == NULL ||
362 dwarf_formudata(&attr, result) != 0)
363 return -ENOENT;
364
365 return 0;
366}
367 244
368static bool die_is_signed_type(Dwarf_Die *tp_die) 245 if (debuginfo__init_online_kernel_dwarf(self, (Dwarf_Addr)addr) < 0) {
369{ 246 free(self);
370 Dwarf_Word ret; 247 self = NULL;
371
372 if (die_get_attr_udata(tp_die, DW_AT_encoding, &ret))
373 return false;
374
375 return (ret == DW_ATE_signed_char || ret == DW_ATE_signed ||
376 ret == DW_ATE_signed_fixed);
377}
378
379static int die_get_byte_size(Dwarf_Die *tp_die)
380{
381 Dwarf_Word ret;
382
383 if (die_get_attr_udata(tp_die, DW_AT_byte_size, &ret))
384 return 0;
385
386 return (int)ret;
387}
388
389static int die_get_bit_size(Dwarf_Die *tp_die)
390{
391 Dwarf_Word ret;
392
393 if (die_get_attr_udata(tp_die, DW_AT_bit_size, &ret))
394 return 0;
395
396 return (int)ret;
397}
398
399static int die_get_bit_offset(Dwarf_Die *tp_die)
400{
401 Dwarf_Word ret;
402
403 if (die_get_attr_udata(tp_die, DW_AT_bit_offset, &ret))
404 return 0;
405
406 return (int)ret;
407}
408
409/* Get data_member_location offset */
410static int die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs)
411{
412 Dwarf_Attribute attr;
413 Dwarf_Op *expr;
414 size_t nexpr;
415 int ret;
416
417 if (dwarf_attr(mb_die, DW_AT_data_member_location, &attr) == NULL)
418 return -ENOENT;
419
420 if (dwarf_formudata(&attr, offs) != 0) {
421 /* DW_AT_data_member_location should be DW_OP_plus_uconst */
422 ret = dwarf_getlocation(&attr, &expr, &nexpr);
423 if (ret < 0 || nexpr == 0)
424 return -ENOENT;
425
426 if (expr[0].atom != DW_OP_plus_uconst || nexpr != 1) {
427 pr_debug("Unable to get offset:Unexpected OP %x (%zd)\n",
428 expr[0].atom, nexpr);
429 return -ENOTSUP;
430 }
431 *offs = (Dwarf_Word)expr[0].number;
432 }
433 return 0;
434}
435
436/* Return values for die_find callbacks */
437enum {
438 DIE_FIND_CB_FOUND = 0, /* End of Search */
439 DIE_FIND_CB_CHILD = 1, /* Search only children */
440 DIE_FIND_CB_SIBLING = 2, /* Search only siblings */
441 DIE_FIND_CB_CONTINUE = 3, /* Search children and siblings */
442};
443
444/* Search a child die */
445static Dwarf_Die *die_find_child(Dwarf_Die *rt_die,
446 int (*callback)(Dwarf_Die *, void *),
447 void *data, Dwarf_Die *die_mem)
448{
449 Dwarf_Die child_die;
450 int ret;
451
452 ret = dwarf_child(rt_die, die_mem);
453 if (ret != 0)
454 return NULL;
455
456 do {
457 ret = callback(die_mem, data);
458 if (ret == DIE_FIND_CB_FOUND)
459 return die_mem;
460
461 if ((ret & DIE_FIND_CB_CHILD) &&
462 die_find_child(die_mem, callback, data, &child_die)) {
463 memcpy(die_mem, &child_die, sizeof(Dwarf_Die));
464 return die_mem;
465 }
466 } while ((ret & DIE_FIND_CB_SIBLING) &&
467 dwarf_siblingof(die_mem, die_mem) == 0);
468
469 return NULL;
470}
471
472struct __addr_die_search_param {
473 Dwarf_Addr addr;
474 Dwarf_Die *die_mem;
475};
476
477static int __die_search_func_cb(Dwarf_Die *fn_die, void *data)
478{
479 struct __addr_die_search_param *ad = data;
480
481 if (dwarf_tag(fn_die) == DW_TAG_subprogram &&
482 dwarf_haspc(fn_die, ad->addr)) {
483 memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die));
484 return DWARF_CB_ABORT;
485 } 248 }
486 return DWARF_CB_OK;
487}
488 249
489/* Search a real subprogram including this line, */ 250 return self;
490static Dwarf_Die *die_find_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr,
491 Dwarf_Die *die_mem)
492{
493 struct __addr_die_search_param ad;
494 ad.addr = addr;
495 ad.die_mem = die_mem;
496 /* dwarf_getscopes can't find subprogram. */
497 if (!dwarf_getfuncs(cu_die, __die_search_func_cb, &ad, 0))
498 return NULL;
499 else
500 return die_mem;
501} 251}
502 252
503/* die_find callback for inline function search */ 253void debuginfo__delete(struct debuginfo *self)
504static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data)
505{ 254{
506 Dwarf_Addr *addr = data; 255 if (self) {
507 256 if (self->dwfl)
508 if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine && 257 dwfl_end(self->dwfl);
509 dwarf_haspc(die_mem, *addr)) 258 free(self);
510 return DIE_FIND_CB_FOUND;
511
512 return DIE_FIND_CB_CONTINUE;
513}
514
515/* Similar to dwarf_getfuncs, but returns inlined_subroutine if exists. */
516static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
517 Dwarf_Die *die_mem)
518{
519 Dwarf_Die tmp_die;
520
521 sp_die = die_find_child(sp_die, __die_find_inline_cb, &addr, &tmp_die);
522 if (!sp_die)
523 return NULL;
524
525 /* Inlined function could be recursive. Trace it until fail */
526 while (sp_die) {
527 memcpy(die_mem, sp_die, sizeof(Dwarf_Die));
528 sp_die = die_find_child(sp_die, __die_find_inline_cb, &addr,
529 &tmp_die);
530 }
531
532 return die_mem;
533}
534
535/* Walker on lines (Note: line number will not be sorted) */
536typedef int (* line_walk_handler_t) (const char *fname, int lineno,
537 Dwarf_Addr addr, void *data);
538
539struct __line_walk_param {
540 const char *fname;
541 line_walk_handler_t handler;
542 void *data;
543 int retval;
544};
545
546static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data)
547{
548 struct __line_walk_param *lw = data;
549 Dwarf_Addr addr;
550 int lineno;
551
552 if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) {
553 lineno = die_get_call_lineno(in_die);
554 if (lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) {
555 lw->retval = lw->handler(lw->fname, lineno, addr,
556 lw->data);
557 if (lw->retval != 0)
558 return DIE_FIND_CB_FOUND;
559 }
560 } 259 }
561 return DIE_FIND_CB_SIBLING;
562}
563
564/* Walk on lines of blocks included in given DIE */
565static int __die_walk_funclines(Dwarf_Die *sp_die,
566 line_walk_handler_t handler, void *data)
567{
568 struct __line_walk_param lw = {
569 .handler = handler,
570 .data = data,
571 .retval = 0,
572 };
573 Dwarf_Die die_mem;
574 Dwarf_Addr addr;
575 int lineno;
576
577 /* Handle function declaration line */
578 lw.fname = dwarf_decl_file(sp_die);
579 if (lw.fname && dwarf_decl_line(sp_die, &lineno) == 0 &&
580 dwarf_entrypc(sp_die, &addr) == 0) {
581 lw.retval = handler(lw.fname, lineno, addr, data);
582 if (lw.retval != 0)
583 goto done;
584 }
585 die_find_child(sp_die, __die_walk_funclines_cb, &lw, &die_mem);
586done:
587 return lw.retval;
588}
589
590static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data)
591{
592 struct __line_walk_param *lw = data;
593
594 lw->retval = __die_walk_funclines(sp_die, lw->handler, lw->data);
595 if (lw->retval != 0)
596 return DWARF_CB_ABORT;
597
598 return DWARF_CB_OK;
599}
600
601/*
602 * Walk on lines inside given PDIE. If the PDIE is subprogram, walk only on
603 * the lines inside the subprogram, otherwise PDIE must be a CU DIE.
604 */
605static int die_walk_lines(Dwarf_Die *pdie, line_walk_handler_t handler,
606 void *data)
607{
608 Dwarf_Lines *lines;
609 Dwarf_Line *line;
610 Dwarf_Addr addr;
611 const char *fname;
612 int lineno, ret = 0;
613 Dwarf_Die die_mem, *cu_die;
614 size_t nlines, i;
615
616 /* Get the CU die */
617 if (dwarf_tag(pdie) == DW_TAG_subprogram)
618 cu_die = dwarf_diecu(pdie, &die_mem, NULL, NULL);
619 else
620 cu_die = pdie;
621 if (!cu_die) {
622 pr_debug2("Failed to get CU from subprogram\n");
623 return -EINVAL;
624 }
625
626 /* Get lines list in the CU */
627 if (dwarf_getsrclines(cu_die, &lines, &nlines) != 0) {
628 pr_debug2("Failed to get source lines on this CU.\n");
629 return -ENOENT;
630 }
631 pr_debug2("Get %zd lines from this CU\n", nlines);
632
633 /* Walk on the lines on lines list */
634 for (i = 0; i < nlines; i++) {
635 line = dwarf_onesrcline(lines, i);
636 if (line == NULL ||
637 dwarf_lineno(line, &lineno) != 0 ||
638 dwarf_lineaddr(line, &addr) != 0) {
639 pr_debug2("Failed to get line info. "
640 "Possible error in debuginfo.\n");
641 continue;
642 }
643 /* Filter lines based on address */
644 if (pdie != cu_die)
645 /*
646 * Address filtering
647 * The line is included in given function, and
648 * no inline block includes it.
649 */
650 if (!dwarf_haspc(pdie, addr) ||
651 die_find_inlinefunc(pdie, addr, &die_mem))
652 continue;
653 /* Get source line */
654 fname = dwarf_linesrc(line, NULL, NULL);
655
656 ret = handler(fname, lineno, addr, data);
657 if (ret != 0)
658 return ret;
659 }
660
661 /*
662 * Dwarf lines doesn't include function declarations and inlined
663 * subroutines. We have to check functions list or given function.
664 */
665 if (pdie != cu_die)
666 ret = __die_walk_funclines(pdie, handler, data);
667 else {
668 struct __line_walk_param param = {
669 .handler = handler,
670 .data = data,
671 .retval = 0,
672 };
673 dwarf_getfuncs(cu_die, __die_walk_culines_cb, &param, 0);
674 ret = param.retval;
675 }
676
677 return ret;
678}
679
680struct __find_variable_param {
681 const char *name;
682 Dwarf_Addr addr;
683};
684
685static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data)
686{
687 struct __find_variable_param *fvp = data;
688 int tag;
689
690 tag = dwarf_tag(die_mem);
691 if ((tag == DW_TAG_formal_parameter ||
692 tag == DW_TAG_variable) &&
693 die_compare_name(die_mem, fvp->name))
694 return DIE_FIND_CB_FOUND;
695
696 if (dwarf_haspc(die_mem, fvp->addr))
697 return DIE_FIND_CB_CONTINUE;
698 else
699 return DIE_FIND_CB_SIBLING;
700}
701
702/* Find a variable called 'name' at given address */
703static Dwarf_Die *die_find_variable_at(Dwarf_Die *sp_die, const char *name,
704 Dwarf_Addr addr, Dwarf_Die *die_mem)
705{
706 struct __find_variable_param fvp = { .name = name, .addr = addr};
707
708 return die_find_child(sp_die, __die_find_variable_cb, (void *)&fvp,
709 die_mem);
710}
711
712static int __die_find_member_cb(Dwarf_Die *die_mem, void *data)
713{
714 const char *name = data;
715
716 if ((dwarf_tag(die_mem) == DW_TAG_member) &&
717 die_compare_name(die_mem, name))
718 return DIE_FIND_CB_FOUND;
719
720 return DIE_FIND_CB_SIBLING;
721}
722
723/* Find a member called 'name' */
724static Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name,
725 Dwarf_Die *die_mem)
726{
727 return die_find_child(st_die, __die_find_member_cb, (void *)name,
728 die_mem);
729}
730
731/* Get the name of given variable DIE */
732static int die_get_typename(Dwarf_Die *vr_die, char *buf, int len)
733{
734 Dwarf_Die type;
735 int tag, ret, ret2;
736 const char *tmp = "";
737
738 if (__die_get_real_type(vr_die, &type) == NULL)
739 return -ENOENT;
740
741 tag = dwarf_tag(&type);
742 if (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)
743 tmp = "*";
744 else if (tag == DW_TAG_subroutine_type) {
745 /* Function pointer */
746 ret = snprintf(buf, len, "(function_type)");
747 return (ret >= len) ? -E2BIG : ret;
748 } else {
749 if (!dwarf_diename(&type))
750 return -ENOENT;
751 if (tag == DW_TAG_union_type)
752 tmp = "union ";
753 else if (tag == DW_TAG_structure_type)
754 tmp = "struct ";
755 /* Write a base name */
756 ret = snprintf(buf, len, "%s%s", tmp, dwarf_diename(&type));
757 return (ret >= len) ? -E2BIG : ret;
758 }
759 ret = die_get_typename(&type, buf, len);
760 if (ret > 0) {
761 ret2 = snprintf(buf + ret, len - ret, "%s", tmp);
762 ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret;
763 }
764 return ret;
765}
766
767/* Get the name and type of given variable DIE, stored as "type\tname" */
768static int die_get_varname(Dwarf_Die *vr_die, char *buf, int len)
769{
770 int ret, ret2;
771
772 ret = die_get_typename(vr_die, buf, len);
773 if (ret < 0) {
774 pr_debug("Failed to get type, make it unknown.\n");
775 ret = snprintf(buf, len, "(unknown_type)");
776 }
777 if (ret > 0) {
778 ret2 = snprintf(buf + ret, len - ret, "\t%s",
779 dwarf_diename(vr_die));
780 ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret;
781 }
782 return ret;
783} 260}
784 261
785/* 262/*
@@ -897,6 +374,7 @@ static int convert_variable_type(Dwarf_Die *vr_die,
897 struct probe_trace_arg_ref **ref_ptr = &tvar->ref; 374 struct probe_trace_arg_ref **ref_ptr = &tvar->ref;
898 Dwarf_Die type; 375 Dwarf_Die type;
899 char buf[16]; 376 char buf[16];
377 int bsize, boffs, total;
900 int ret; 378 int ret;
901 379
902 /* TODO: check all types */ 380 /* TODO: check all types */
@@ -906,11 +384,15 @@ static int convert_variable_type(Dwarf_Die *vr_die,
906 return (tvar->type == NULL) ? -ENOMEM : 0; 384 return (tvar->type == NULL) ? -ENOMEM : 0;
907 } 385 }
908 386
909 if (die_get_bit_size(vr_die) != 0) { 387 bsize = dwarf_bitsize(vr_die);
388 if (bsize > 0) {
910 /* This is a bitfield */ 389 /* This is a bitfield */
911 ret = snprintf(buf, 16, "b%d@%d/%zd", die_get_bit_size(vr_die), 390 boffs = dwarf_bitoffset(vr_die);
912 die_get_bit_offset(vr_die), 391 total = dwarf_bytesize(vr_die);
913 BYTES_TO_BITS(die_get_byte_size(vr_die))); 392 if (boffs < 0 || total < 0)
393 return -ENOENT;
394 ret = snprintf(buf, 16, "b%d@%d/%zd", bsize, boffs,
395 BYTES_TO_BITS(total));
914 goto formatted; 396 goto formatted;
915 } 397 }
916 398
@@ -958,10 +440,11 @@ static int convert_variable_type(Dwarf_Die *vr_die,
958 return (tvar->type == NULL) ? -ENOMEM : 0; 440 return (tvar->type == NULL) ? -ENOMEM : 0;
959 } 441 }
960 442
961 ret = BYTES_TO_BITS(die_get_byte_size(&type)); 443 ret = dwarf_bytesize(&type);
962 if (!ret) 444 if (ret <= 0)
963 /* No size ... try to use default type */ 445 /* No size ... try to use default type */
964 return 0; 446 return 0;
447 ret = BYTES_TO_BITS(ret);
965 448
966 /* Check the bitwidth */ 449 /* Check the bitwidth */
967 if (ret > MAX_BASIC_TYPE_BITS) { 450 if (ret > MAX_BASIC_TYPE_BITS) {
@@ -1025,7 +508,7 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
1025 else 508 else
1026 *ref_ptr = ref; 509 *ref_ptr = ref;
1027 } 510 }
1028 ref->offset += die_get_byte_size(&type) * field->index; 511 ref->offset += dwarf_bytesize(&type) * field->index;
1029 if (!field->next) 512 if (!field->next)
1030 /* Save vr_die for converting types */ 513 /* Save vr_die for converting types */
1031 memcpy(die_mem, vr_die, sizeof(*die_mem)); 514 memcpy(die_mem, vr_die, sizeof(*die_mem));
@@ -1129,12 +612,12 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
1129 return ret; 612 return ret;
1130} 613}
1131 614
1132/* Find a variable in a subprogram die */ 615/* Find a variable in a scope DIE */
1133static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) 616static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf)
1134{ 617{
1135 Dwarf_Die vr_die, *scopes; 618 Dwarf_Die vr_die;
1136 char buf[32], *ptr; 619 char buf[32], *ptr;
1137 int ret, nscopes; 620 int ret = 0;
1138 621
1139 if (!is_c_varname(pf->pvar->var)) { 622 if (!is_c_varname(pf->pvar->var)) {
1140 /* Copy raw parameters */ 623 /* Copy raw parameters */
@@ -1169,30 +652,16 @@ static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
1169 if (pf->tvar->name == NULL) 652 if (pf->tvar->name == NULL)
1170 return -ENOMEM; 653 return -ENOMEM;
1171 654
1172 pr_debug("Searching '%s' variable in context.\n", 655 pr_debug("Searching '%s' variable in context.\n", pf->pvar->var);
1173 pf->pvar->var);
1174 /* Search child die for local variables and parameters. */ 656 /* Search child die for local variables and parameters. */
1175 if (die_find_variable_at(sp_die, pf->pvar->var, pf->addr, &vr_die)) 657 if (!die_find_variable_at(sc_die, pf->pvar->var, pf->addr, &vr_die)) {
1176 ret = convert_variable(&vr_die, pf); 658 /* Search again in global variables */
1177 else { 659 if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die))
1178 /* Search upper class */ 660 ret = -ENOENT;
1179 nscopes = dwarf_getscopes_die(sp_die, &scopes);
1180 while (nscopes-- > 1) {
1181 pr_debug("Searching variables in %s\n",
1182 dwarf_diename(&scopes[nscopes]));
1183 /* We should check this scope, so give dummy address */
1184 if (die_find_variable_at(&scopes[nscopes],
1185 pf->pvar->var, 0,
1186 &vr_die)) {
1187 ret = convert_variable(&vr_die, pf);
1188 goto found;
1189 }
1190 }
1191 if (scopes)
1192 free(scopes);
1193 ret = -ENOENT;
1194 } 661 }
1195found: 662 if (ret >= 0)
663 ret = convert_variable(&vr_die, pf);
664
1196 if (ret < 0) 665 if (ret < 0)
1197 pr_warning("Failed to find '%s' in this function.\n", 666 pr_warning("Failed to find '%s' in this function.\n",
1198 pf->pvar->var); 667 pf->pvar->var);
@@ -1235,27 +704,30 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr,
1235 return 0; 704 return 0;
1236} 705}
1237 706
1238/* Call probe_finder callback with real subprogram DIE */ 707/* Call probe_finder callback with scope DIE */
1239static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf) 708static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf)
1240{ 709{
1241 Dwarf_Die die_mem;
1242 Dwarf_Attribute fb_attr; 710 Dwarf_Attribute fb_attr;
1243 size_t nops; 711 size_t nops;
1244 int ret; 712 int ret;
1245 713
1246 /* If no real subprogram, find a real one */ 714 if (!sc_die) {
1247 if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) { 715 pr_err("Caller must pass a scope DIE. Program error.\n");
1248 sp_die = die_find_real_subprogram(&pf->cu_die, 716 return -EINVAL;
1249 pf->addr, &die_mem); 717 }
1250 if (!sp_die) { 718
719 /* If not a real subprogram, find a real one */
720 if (dwarf_tag(sc_die) != DW_TAG_subprogram) {
721 if (!die_find_realfunc(&pf->cu_die, pf->addr, &pf->sp_die)) {
1251 pr_warning("Failed to find probe point in any " 722 pr_warning("Failed to find probe point in any "
1252 "functions.\n"); 723 "functions.\n");
1253 return -ENOENT; 724 return -ENOENT;
1254 } 725 }
1255 } 726 } else
727 memcpy(&pf->sp_die, sc_die, sizeof(Dwarf_Die));
1256 728
1257 /* Get the frame base attribute/ops */ 729 /* Get the frame base attribute/ops from subprogram */
1258 dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr); 730 dwarf_attr(&pf->sp_die, DW_AT_frame_base, &fb_attr);
1259 ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1); 731 ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1);
1260 if (ret <= 0 || nops == 0) { 732 if (ret <= 0 || nops == 0) {
1261 pf->fb_ops = NULL; 733 pf->fb_ops = NULL;
@@ -1273,7 +745,7 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf)
1273 } 745 }
1274 746
1275 /* Call finder's callback handler */ 747 /* Call finder's callback handler */
1276 ret = pf->callback(sp_die, pf); 748 ret = pf->callback(sc_die, pf);
1277 749
1278 /* *pf->fb_ops will be cached in libdw. Don't free it. */ 750 /* *pf->fb_ops will be cached in libdw. Don't free it. */
1279 pf->fb_ops = NULL; 751 pf->fb_ops = NULL;
@@ -1281,17 +753,82 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf)
1281 return ret; 753 return ret;
1282} 754}
1283 755
756struct find_scope_param {
757 const char *function;
758 const char *file;
759 int line;
760 int diff;
761 Dwarf_Die *die_mem;
762 bool found;
763};
764
765static int find_best_scope_cb(Dwarf_Die *fn_die, void *data)
766{
767 struct find_scope_param *fsp = data;
768 const char *file;
769 int lno;
770
771 /* Skip if declared file name does not match */
772 if (fsp->file) {
773 file = dwarf_decl_file(fn_die);
774 if (!file || strcmp(fsp->file, file) != 0)
775 return 0;
776 }
777 /* If the function name is given, that's what user expects */
778 if (fsp->function) {
779 if (die_compare_name(fn_die, fsp->function)) {
780 memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die));
781 fsp->found = true;
782 return 1;
783 }
784 } else {
785 /* With the line number, find the nearest declared DIE */
786 dwarf_decl_line(fn_die, &lno);
787 if (lno < fsp->line && fsp->diff > fsp->line - lno) {
788 /* Keep a candidate and continue */
789 fsp->diff = fsp->line - lno;
790 memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die));
791 fsp->found = true;
792 }
793 }
794 return 0;
795}
796
797/* Find an appropriate scope fits to given conditions */
798static Dwarf_Die *find_best_scope(struct probe_finder *pf, Dwarf_Die *die_mem)
799{
800 struct find_scope_param fsp = {
801 .function = pf->pev->point.function,
802 .file = pf->fname,
803 .line = pf->lno,
804 .diff = INT_MAX,
805 .die_mem = die_mem,
806 .found = false,
807 };
808
809 cu_walk_functions_at(&pf->cu_die, pf->addr, find_best_scope_cb, &fsp);
810
811 return fsp.found ? die_mem : NULL;
812}
813
1284static int probe_point_line_walker(const char *fname, int lineno, 814static int probe_point_line_walker(const char *fname, int lineno,
1285 Dwarf_Addr addr, void *data) 815 Dwarf_Addr addr, void *data)
1286{ 816{
1287 struct probe_finder *pf = data; 817 struct probe_finder *pf = data;
818 Dwarf_Die *sc_die, die_mem;
1288 int ret; 819 int ret;
1289 820
1290 if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0) 821 if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0)
1291 return 0; 822 return 0;
1292 823
1293 pf->addr = addr; 824 pf->addr = addr;
1294 ret = call_probe_finder(NULL, pf); 825 sc_die = find_best_scope(pf, &die_mem);
826 if (!sc_die) {
827 pr_warning("Failed to find scope of probe point.\n");
828 return -ENOENT;
829 }
830
831 ret = call_probe_finder(sc_die, pf);
1295 832
1296 /* Continue if no error, because the line will be in inline function */ 833 /* Continue if no error, because the line will be in inline function */
1297 return ret < 0 ? ret : 0; 834 return ret < 0 ? ret : 0;
@@ -1345,6 +882,7 @@ static int probe_point_lazy_walker(const char *fname, int lineno,
1345 Dwarf_Addr addr, void *data) 882 Dwarf_Addr addr, void *data)
1346{ 883{
1347 struct probe_finder *pf = data; 884 struct probe_finder *pf = data;
885 Dwarf_Die *sc_die, die_mem;
1348 int ret; 886 int ret;
1349 887
1350 if (!line_list__has_line(&pf->lcache, lineno) || 888 if (!line_list__has_line(&pf->lcache, lineno) ||
@@ -1354,7 +892,14 @@ static int probe_point_lazy_walker(const char *fname, int lineno,
1354 pr_debug("Probe line found: line:%d addr:0x%llx\n", 892 pr_debug("Probe line found: line:%d addr:0x%llx\n",
1355 lineno, (unsigned long long)addr); 893 lineno, (unsigned long long)addr);
1356 pf->addr = addr; 894 pf->addr = addr;
1357 ret = call_probe_finder(NULL, pf); 895 pf->lno = lineno;
896 sc_die = find_best_scope(pf, &die_mem);
897 if (!sc_die) {
898 pr_warning("Failed to find scope of probe point.\n");
899 return -ENOENT;
900 }
901
902 ret = call_probe_finder(sc_die, pf);
1358 903
1359 /* 904 /*
1360 * Continue if no error, because the lazy pattern will match 905 * Continue if no error, because the lazy pattern will match
@@ -1379,42 +924,39 @@ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
1379 return die_walk_lines(sp_die, probe_point_lazy_walker, pf); 924 return die_walk_lines(sp_die, probe_point_lazy_walker, pf);
1380} 925}
1381 926
1382/* Callback parameter with return value */
1383struct dwarf_callback_param {
1384 void *data;
1385 int retval;
1386};
1387
1388static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) 927static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
1389{ 928{
1390 struct dwarf_callback_param *param = data; 929 struct probe_finder *pf = data;
1391 struct probe_finder *pf = param->data;
1392 struct perf_probe_point *pp = &pf->pev->point; 930 struct perf_probe_point *pp = &pf->pev->point;
1393 Dwarf_Addr addr; 931 Dwarf_Addr addr;
932 int ret;
1394 933
1395 if (pp->lazy_line) 934 if (pp->lazy_line)
1396 param->retval = find_probe_point_lazy(in_die, pf); 935 ret = find_probe_point_lazy(in_die, pf);
1397 else { 936 else {
1398 /* Get probe address */ 937 /* Get probe address */
1399 if (dwarf_entrypc(in_die, &addr) != 0) { 938 if (dwarf_entrypc(in_die, &addr) != 0) {
1400 pr_warning("Failed to get entry address of %s.\n", 939 pr_warning("Failed to get entry address of %s.\n",
1401 dwarf_diename(in_die)); 940 dwarf_diename(in_die));
1402 param->retval = -ENOENT; 941 return -ENOENT;
1403 return DWARF_CB_ABORT;
1404 } 942 }
1405 pf->addr = addr; 943 pf->addr = addr;
1406 pf->addr += pp->offset; 944 pf->addr += pp->offset;
1407 pr_debug("found inline addr: 0x%jx\n", 945 pr_debug("found inline addr: 0x%jx\n",
1408 (uintmax_t)pf->addr); 946 (uintmax_t)pf->addr);
1409 947
1410 param->retval = call_probe_finder(in_die, pf); 948 ret = call_probe_finder(in_die, pf);
1411 if (param->retval < 0)
1412 return DWARF_CB_ABORT;
1413 } 949 }
1414 950
1415 return DWARF_CB_OK; 951 return ret;
1416} 952}
1417 953
954/* Callback parameter with return value for libdw */
955struct dwarf_callback_param {
956 void *data;
957 int retval;
958};
959
1418/* Search function from function name */ 960/* Search function from function name */
1419static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) 961static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
1420{ 962{
@@ -1451,14 +993,10 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
1451 /* TODO: Check the address in this function */ 993 /* TODO: Check the address in this function */
1452 param->retval = call_probe_finder(sp_die, pf); 994 param->retval = call_probe_finder(sp_die, pf);
1453 } 995 }
1454 } else { 996 } else
1455 struct dwarf_callback_param _param = {.data = (void *)pf,
1456 .retval = 0};
1457 /* Inlined function: search instances */ 997 /* Inlined function: search instances */
1458 dwarf_func_inline_instances(sp_die, probe_point_inline_cb, 998 param->retval = die_walk_instances(sp_die,
1459 &_param); 999 probe_point_inline_cb, (void *)pf);
1460 param->retval = _param.retval;
1461 }
1462 1000
1463 return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */ 1001 return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */
1464} 1002}
@@ -1504,28 +1042,18 @@ static int pubname_search_cb(Dwarf *dbg, Dwarf_Global *gl, void *data)
1504} 1042}
1505 1043
1506/* Find probe points from debuginfo */ 1044/* Find probe points from debuginfo */
1507static int find_probes(int fd, struct probe_finder *pf) 1045static int debuginfo__find_probes(struct debuginfo *self,
1046 struct probe_finder *pf)
1508{ 1047{
1509 struct perf_probe_point *pp = &pf->pev->point; 1048 struct perf_probe_point *pp = &pf->pev->point;
1510 Dwarf_Off off, noff; 1049 Dwarf_Off off, noff;
1511 size_t cuhl; 1050 size_t cuhl;
1512 Dwarf_Die *diep; 1051 Dwarf_Die *diep;
1513 Dwarf *dbg = NULL;
1514 Dwfl *dwfl;
1515 Dwarf_Addr bias; /* Currently ignored */
1516 int ret = 0; 1052 int ret = 0;
1517 1053
1518 dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias);
1519 if (!dbg) {
1520 pr_warning("No debug information found in the vmlinux - "
1521 "please rebuild with CONFIG_DEBUG_INFO=y.\n");
1522 close(fd); /* Without dwfl_end(), fd isn't closed. */
1523 return -EBADF;
1524 }
1525
1526#if _ELFUTILS_PREREQ(0, 142) 1054#if _ELFUTILS_PREREQ(0, 142)
1527 /* Get the call frame information from this dwarf */ 1055 /* Get the call frame information from this dwarf */
1528 pf->cfi = dwarf_getcfi(dbg); 1056 pf->cfi = dwarf_getcfi(self->dbg);
1529#endif 1057#endif
1530 1058
1531 off = 0; 1059 off = 0;
@@ -1544,7 +1072,8 @@ static int find_probes(int fd, struct probe_finder *pf)
1544 .data = pf, 1072 .data = pf,
1545 }; 1073 };
1546 1074
1547 dwarf_getpubnames(dbg, pubname_search_cb, &pubname_param, 0); 1075 dwarf_getpubnames(self->dbg, pubname_search_cb,
1076 &pubname_param, 0);
1548 if (pubname_param.found) { 1077 if (pubname_param.found) {
1549 ret = probe_point_search_cb(&pf->sp_die, &probe_param); 1078 ret = probe_point_search_cb(&pf->sp_die, &probe_param);
1550 if (ret) 1079 if (ret)
@@ -1553,9 +1082,9 @@ static int find_probes(int fd, struct probe_finder *pf)
1553 } 1082 }
1554 1083
1555 /* Loop on CUs (Compilation Unit) */ 1084 /* Loop on CUs (Compilation Unit) */
1556 while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL)) { 1085 while (!dwarf_nextcu(self->dbg, off, &noff, &cuhl, NULL, NULL, NULL)) {
1557 /* Get the DIE(Debugging Information Entry) of this CU */ 1086 /* Get the DIE(Debugging Information Entry) of this CU */
1558 diep = dwarf_offdie(dbg, off + cuhl, &pf->cu_die); 1087 diep = dwarf_offdie(self->dbg, off + cuhl, &pf->cu_die);
1559 if (!diep) 1088 if (!diep)
1560 continue; 1089 continue;
1561 1090
@@ -1582,14 +1111,12 @@ static int find_probes(int fd, struct probe_finder *pf)
1582 1111
1583found: 1112found:
1584 line_list__free(&pf->lcache); 1113 line_list__free(&pf->lcache);
1585 if (dwfl)
1586 dwfl_end(dwfl);
1587 1114
1588 return ret; 1115 return ret;
1589} 1116}
1590 1117
1591/* Add a found probe point into trace event list */ 1118/* Add a found probe point into trace event list */
1592static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf) 1119static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
1593{ 1120{
1594 struct trace_event_finder *tf = 1121 struct trace_event_finder *tf =
1595 container_of(pf, struct trace_event_finder, pf); 1122 container_of(pf, struct trace_event_finder, pf);
@@ -1604,8 +1131,9 @@ static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf)
1604 } 1131 }
1605 tev = &tf->tevs[tf->ntevs++]; 1132 tev = &tf->tevs[tf->ntevs++];
1606 1133
1607 ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe, 1134 /* Trace point should be converted from subprogram DIE */
1608 &tev->point); 1135 ret = convert_to_trace_point(&pf->sp_die, pf->addr,
1136 pf->pev->point.retprobe, &tev->point);
1609 if (ret < 0) 1137 if (ret < 0)
1610 return ret; 1138 return ret;
1611 1139
@@ -1620,7 +1148,8 @@ static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf)
1620 for (i = 0; i < pf->pev->nargs; i++) { 1148 for (i = 0; i < pf->pev->nargs; i++) {
1621 pf->pvar = &pf->pev->args[i]; 1149 pf->pvar = &pf->pev->args[i];
1622 pf->tvar = &tev->args[i]; 1150 pf->tvar = &tev->args[i];
1623 ret = find_variable(sp_die, pf); 1151 /* Variable should be found from scope DIE */
1152 ret = find_variable(sc_die, pf);
1624 if (ret != 0) 1153 if (ret != 0)
1625 return ret; 1154 return ret;
1626 } 1155 }
@@ -1629,8 +1158,9 @@ static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf)
1629} 1158}
1630 1159
1631/* Find probe_trace_events specified by perf_probe_event from debuginfo */ 1160/* Find probe_trace_events specified by perf_probe_event from debuginfo */
1632int find_probe_trace_events(int fd, struct perf_probe_event *pev, 1161int debuginfo__find_trace_events(struct debuginfo *self,
1633 struct probe_trace_event **tevs, int max_tevs) 1162 struct perf_probe_event *pev,
1163 struct probe_trace_event **tevs, int max_tevs)
1634{ 1164{
1635 struct trace_event_finder tf = { 1165 struct trace_event_finder tf = {
1636 .pf = {.pev = pev, .callback = add_probe_trace_event}, 1166 .pf = {.pev = pev, .callback = add_probe_trace_event},
@@ -1645,7 +1175,7 @@ int find_probe_trace_events(int fd, struct perf_probe_event *pev,
1645 tf.tevs = *tevs; 1175 tf.tevs = *tevs;
1646 tf.ntevs = 0; 1176 tf.ntevs = 0;
1647 1177
1648 ret = find_probes(fd, &tf.pf); 1178 ret = debuginfo__find_probes(self, &tf.pf);
1649 if (ret < 0) { 1179 if (ret < 0) {
1650 free(*tevs); 1180 free(*tevs);
1651 *tevs = NULL; 1181 *tevs = NULL;
@@ -1687,13 +1217,13 @@ static int collect_variables_cb(Dwarf_Die *die_mem, void *data)
1687} 1217}
1688 1218
1689/* Add a found vars into available variables list */ 1219/* Add a found vars into available variables list */
1690static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf) 1220static int add_available_vars(Dwarf_Die *sc_die, struct probe_finder *pf)
1691{ 1221{
1692 struct available_var_finder *af = 1222 struct available_var_finder *af =
1693 container_of(pf, struct available_var_finder, pf); 1223 container_of(pf, struct available_var_finder, pf);
1694 struct variable_list *vl; 1224 struct variable_list *vl;
1695 Dwarf_Die die_mem, *scopes = NULL; 1225 Dwarf_Die die_mem;
1696 int ret, nscopes; 1226 int ret;
1697 1227
1698 /* Check number of tevs */ 1228 /* Check number of tevs */
1699 if (af->nvls == af->max_vls) { 1229 if (af->nvls == af->max_vls) {
@@ -1702,8 +1232,9 @@ static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf)
1702 } 1232 }
1703 vl = &af->vls[af->nvls++]; 1233 vl = &af->vls[af->nvls++];
1704 1234
1705 ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe, 1235 /* Trace point should be converted from subprogram DIE */
1706 &vl->point); 1236 ret = convert_to_trace_point(&pf->sp_die, pf->addr,
1237 pf->pev->point.retprobe, &vl->point);
1707 if (ret < 0) 1238 if (ret < 0)
1708 return ret; 1239 return ret;
1709 1240
@@ -1715,19 +1246,14 @@ static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf)
1715 if (vl->vars == NULL) 1246 if (vl->vars == NULL)
1716 return -ENOMEM; 1247 return -ENOMEM;
1717 af->child = true; 1248 af->child = true;
1718 die_find_child(sp_die, collect_variables_cb, (void *)af, &die_mem); 1249 die_find_child(sc_die, collect_variables_cb, (void *)af, &die_mem);
1719 1250
1720 /* Find external variables */ 1251 /* Find external variables */
1721 if (!af->externs) 1252 if (!af->externs)
1722 goto out; 1253 goto out;
1723 /* Don't need to search child DIE for externs. */ 1254 /* Don't need to search child DIE for externs. */
1724 af->child = false; 1255 af->child = false;
1725 nscopes = dwarf_getscopes_die(sp_die, &scopes); 1256 die_find_child(&pf->cu_die, collect_variables_cb, (void *)af, &die_mem);
1726 while (nscopes-- > 1)
1727 die_find_child(&scopes[nscopes], collect_variables_cb,
1728 (void *)af, &die_mem);
1729 if (scopes)
1730 free(scopes);
1731 1257
1732out: 1258out:
1733 if (strlist__empty(vl->vars)) { 1259 if (strlist__empty(vl->vars)) {
@@ -1739,9 +1265,10 @@ out:
1739} 1265}
1740 1266
1741/* Find available variables at given probe point */ 1267/* Find available variables at given probe point */
1742int find_available_vars_at(int fd, struct perf_probe_event *pev, 1268int debuginfo__find_available_vars_at(struct debuginfo *self,
1743 struct variable_list **vls, int max_vls, 1269 struct perf_probe_event *pev,
1744 bool externs) 1270 struct variable_list **vls,
1271 int max_vls, bool externs)
1745{ 1272{
1746 struct available_var_finder af = { 1273 struct available_var_finder af = {
1747 .pf = {.pev = pev, .callback = add_available_vars}, 1274 .pf = {.pev = pev, .callback = add_available_vars},
@@ -1756,7 +1283,7 @@ int find_available_vars_at(int fd, struct perf_probe_event *pev,
1756 af.vls = *vls; 1283 af.vls = *vls;
1757 af.nvls = 0; 1284 af.nvls = 0;
1758 1285
1759 ret = find_probes(fd, &af.pf); 1286 ret = debuginfo__find_probes(self, &af.pf);
1760 if (ret < 0) { 1287 if (ret < 0) {
1761 /* Free vlist for error */ 1288 /* Free vlist for error */
1762 while (af.nvls--) { 1289 while (af.nvls--) {
@@ -1774,28 +1301,19 @@ int find_available_vars_at(int fd, struct perf_probe_event *pev,
1774} 1301}
1775 1302
1776/* Reverse search */ 1303/* Reverse search */
1777int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt) 1304int debuginfo__find_probe_point(struct debuginfo *self, unsigned long addr,
1305 struct perf_probe_point *ppt)
1778{ 1306{
1779 Dwarf_Die cudie, spdie, indie; 1307 Dwarf_Die cudie, spdie, indie;
1780 Dwarf *dbg = NULL; 1308 Dwarf_Addr _addr, baseaddr;
1781 Dwfl *dwfl = NULL;
1782 Dwarf_Addr _addr, baseaddr, bias = 0;
1783 const char *fname = NULL, *func = NULL, *tmp; 1309 const char *fname = NULL, *func = NULL, *tmp;
1784 int baseline = 0, lineno = 0, ret = 0; 1310 int baseline = 0, lineno = 0, ret = 0;
1785 1311
1786 /* Open the live linux kernel */
1787 dbg = dwfl_init_live_kernel_dwarf(addr, &dwfl, &bias);
1788 if (!dbg) {
1789 pr_warning("No debug information found in the vmlinux - "
1790 "please rebuild with CONFIG_DEBUG_INFO=y.\n");
1791 ret = -EINVAL;
1792 goto end;
1793 }
1794
1795 /* Adjust address with bias */ 1312 /* Adjust address with bias */
1796 addr += bias; 1313 addr += self->bias;
1314
1797 /* Find cu die */ 1315 /* Find cu die */
1798 if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr - bias, &cudie)) { 1316 if (!dwarf_addrdie(self->dbg, (Dwarf_Addr)addr - self->bias, &cudie)) {
1799 pr_warning("Failed to find debug information for address %lx\n", 1317 pr_warning("Failed to find debug information for address %lx\n",
1800 addr); 1318 addr);
1801 ret = -EINVAL; 1319 ret = -EINVAL;
@@ -1807,7 +1325,7 @@ int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt)
1807 /* Don't care whether it failed or not */ 1325 /* Don't care whether it failed or not */
1808 1326
1809 /* Find a corresponding function (name, baseline and baseaddr) */ 1327 /* Find a corresponding function (name, baseline and baseaddr) */
1810 if (die_find_real_subprogram(&cudie, (Dwarf_Addr)addr, &spdie)) { 1328 if (die_find_realfunc(&cudie, (Dwarf_Addr)addr, &spdie)) {
1811 /* Get function entry information */ 1329 /* Get function entry information */
1812 tmp = dwarf_diename(&spdie); 1330 tmp = dwarf_diename(&spdie);
1813 if (!tmp || 1331 if (!tmp ||
@@ -1871,8 +1389,6 @@ post:
1871 } 1389 }
1872 } 1390 }
1873end: 1391end:
1874 if (dwfl)
1875 dwfl_end(dwfl);
1876 if (ret == 0 && (fname || func)) 1392 if (ret == 0 && (fname || func))
1877 ret = 1; /* Found a point */ 1393 ret = 1; /* Found a point */
1878 return ret; 1394 return ret;
@@ -1929,10 +1445,14 @@ static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
1929 1445
1930static int line_range_inline_cb(Dwarf_Die *in_die, void *data) 1446static int line_range_inline_cb(Dwarf_Die *in_die, void *data)
1931{ 1447{
1932 struct dwarf_callback_param *param = data; 1448 find_line_range_by_line(in_die, data);
1933 1449
1934 param->retval = find_line_range_by_line(in_die, param->data); 1450 /*
1935 return DWARF_CB_ABORT; /* No need to find other instances */ 1451 * We have to check all instances of inlined function, because
1452 * some execution paths can be optimized out depends on the
1453 * function argument of instances
1454 */
1455 return 0;
1936} 1456}
1937 1457
1938/* Search function from function name */ 1458/* Search function from function name */
@@ -1960,15 +1480,10 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
1960 pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e); 1480 pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e);
1961 lr->start = lf->lno_s; 1481 lr->start = lf->lno_s;
1962 lr->end = lf->lno_e; 1482 lr->end = lf->lno_e;
1963 if (dwarf_func_inline(sp_die)) { 1483 if (dwarf_func_inline(sp_die))
1964 struct dwarf_callback_param _param; 1484 param->retval = die_walk_instances(sp_die,
1965 _param.data = (void *)lf; 1485 line_range_inline_cb, lf);
1966 _param.retval = 0; 1486 else
1967 dwarf_func_inline_instances(sp_die,
1968 line_range_inline_cb,
1969 &_param);
1970 param->retval = _param.retval;
1971 } else
1972 param->retval = find_line_range_by_line(sp_die, lf); 1487 param->retval = find_line_range_by_line(sp_die, lf);
1973 return DWARF_CB_ABORT; 1488 return DWARF_CB_ABORT;
1974 } 1489 }
@@ -1982,26 +1497,15 @@ static int find_line_range_by_func(struct line_finder *lf)
1982 return param.retval; 1497 return param.retval;
1983} 1498}
1984 1499
1985int find_line_range(int fd, struct line_range *lr) 1500int debuginfo__find_line_range(struct debuginfo *self, struct line_range *lr)
1986{ 1501{
1987 struct line_finder lf = {.lr = lr, .found = 0}; 1502 struct line_finder lf = {.lr = lr, .found = 0};
1988 int ret = 0; 1503 int ret = 0;
1989 Dwarf_Off off = 0, noff; 1504 Dwarf_Off off = 0, noff;
1990 size_t cuhl; 1505 size_t cuhl;
1991 Dwarf_Die *diep; 1506 Dwarf_Die *diep;
1992 Dwarf *dbg = NULL;
1993 Dwfl *dwfl;
1994 Dwarf_Addr bias; /* Currently ignored */
1995 const char *comp_dir; 1507 const char *comp_dir;
1996 1508
1997 dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias);
1998 if (!dbg) {
1999 pr_warning("No debug information found in the vmlinux - "
2000 "please rebuild with CONFIG_DEBUG_INFO=y.\n");
2001 close(fd); /* Without dwfl_end(), fd isn't closed. */
2002 return -EBADF;
2003 }
2004
2005 /* Fastpath: lookup by function name from .debug_pubnames section */ 1509 /* Fastpath: lookup by function name from .debug_pubnames section */
2006 if (lr->function) { 1510 if (lr->function) {
2007 struct pubname_callback_param pubname_param = { 1511 struct pubname_callback_param pubname_param = {
@@ -2010,7 +1514,8 @@ int find_line_range(int fd, struct line_range *lr)
2010 struct dwarf_callback_param line_range_param = { 1514 struct dwarf_callback_param line_range_param = {
2011 .data = (void *)&lf, .retval = 0}; 1515 .data = (void *)&lf, .retval = 0};
2012 1516
2013 dwarf_getpubnames(dbg, pubname_search_cb, &pubname_param, 0); 1517 dwarf_getpubnames(self->dbg, pubname_search_cb,
1518 &pubname_param, 0);
2014 if (pubname_param.found) { 1519 if (pubname_param.found) {
2015 line_range_search_cb(&lf.sp_die, &line_range_param); 1520 line_range_search_cb(&lf.sp_die, &line_range_param);
2016 if (lf.found) 1521 if (lf.found)
@@ -2020,11 +1525,12 @@ int find_line_range(int fd, struct line_range *lr)
2020 1525
2021 /* Loop on CUs (Compilation Unit) */ 1526 /* Loop on CUs (Compilation Unit) */
2022 while (!lf.found && ret >= 0) { 1527 while (!lf.found && ret >= 0) {
2023 if (dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) != 0) 1528 if (dwarf_nextcu(self->dbg, off, &noff, &cuhl,
1529 NULL, NULL, NULL) != 0)
2024 break; 1530 break;
2025 1531
2026 /* Get the DIE(Debugging Information Entry) of this CU */ 1532 /* Get the DIE(Debugging Information Entry) of this CU */
2027 diep = dwarf_offdie(dbg, off + cuhl, &lf.cu_die); 1533 diep = dwarf_offdie(self->dbg, off + cuhl, &lf.cu_die);
2028 if (!diep) 1534 if (!diep)
2029 continue; 1535 continue;
2030 1536
@@ -2058,7 +1564,6 @@ found:
2058 } 1564 }
2059 1565
2060 pr_debug("path: %s\n", lr->path); 1566 pr_debug("path: %s\n", lr->path);
2061 dwfl_end(dwfl);
2062 return (ret < 0) ? ret : lf.found; 1567 return (ret < 0) ? ret : lf.found;
2063} 1568}
2064 1569
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index 605730a366db..1132c8f0ce89 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -16,33 +16,48 @@ static inline int is_c_varname(const char *name)
16} 16}
17 17
18#ifdef DWARF_SUPPORT 18#ifdef DWARF_SUPPORT
19
20#include "dwarf-aux.h"
21
22/* TODO: export debuginfo data structure even if no dwarf support */
23
24/* debug information structure */
25struct debuginfo {
26 Dwarf *dbg;
27 Dwfl *dwfl;
28 Dwarf_Addr bias;
29};
30
31extern struct debuginfo *debuginfo__new(const char *path);
32extern struct debuginfo *debuginfo__new_online_kernel(unsigned long addr);
33extern void debuginfo__delete(struct debuginfo *self);
34
19/* Find probe_trace_events specified by perf_probe_event from debuginfo */ 35/* Find probe_trace_events specified by perf_probe_event from debuginfo */
20extern int find_probe_trace_events(int fd, struct perf_probe_event *pev, 36extern int debuginfo__find_trace_events(struct debuginfo *self,
21 struct probe_trace_event **tevs, 37 struct perf_probe_event *pev,
22 int max_tevs); 38 struct probe_trace_event **tevs,
39 int max_tevs);
23 40
24/* Find a perf_probe_point from debuginfo */ 41/* Find a perf_probe_point from debuginfo */
25extern int find_perf_probe_point(unsigned long addr, 42extern int debuginfo__find_probe_point(struct debuginfo *self,
26 struct perf_probe_point *ppt); 43 unsigned long addr,
44 struct perf_probe_point *ppt);
27 45
28/* Find a line range */ 46/* Find a line range */
29extern int find_line_range(int fd, struct line_range *lr); 47extern int debuginfo__find_line_range(struct debuginfo *self,
48 struct line_range *lr);
30 49
31/* Find available variables */ 50/* Find available variables */
32extern int find_available_vars_at(int fd, struct perf_probe_event *pev, 51extern int debuginfo__find_available_vars_at(struct debuginfo *self,
33 struct variable_list **vls, int max_points, 52 struct perf_probe_event *pev,
34 bool externs); 53 struct variable_list **vls,
35 54 int max_points, bool externs);
36#include <dwarf.h>
37#include <elfutils/libdw.h>
38#include <elfutils/libdwfl.h>
39#include <elfutils/version.h>
40 55
41struct probe_finder { 56struct probe_finder {
42 struct perf_probe_event *pev; /* Target probe event */ 57 struct perf_probe_event *pev; /* Target probe event */
43 58
44 /* Callback when a probe point is found */ 59 /* Callback when a probe point is found */
45 int (*callback)(Dwarf_Die *sp_die, struct probe_finder *pf); 60 int (*callback)(Dwarf_Die *sc_die, struct probe_finder *pf);
46 61
47 /* For function searching */ 62 /* For function searching */
48 int lno; /* Line number */ 63 int lno; /* Line number */
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index a9ac0504aabd..9dd47a4f2596 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -187,16 +187,119 @@ static PyTypeObject pyrf_throttle_event__type = {
187 .tp_repr = (reprfunc)pyrf_throttle_event__repr, 187 .tp_repr = (reprfunc)pyrf_throttle_event__repr,
188}; 188};
189 189
190static char pyrf_lost_event__doc[] = PyDoc_STR("perf lost event object.");
191
192static PyMemberDef pyrf_lost_event__members[] = {
193 sample_members
194 member_def(lost_event, id, T_ULONGLONG, "event id"),
195 member_def(lost_event, lost, T_ULONGLONG, "number of lost events"),
196 { .name = NULL, },
197};
198
199static PyObject *pyrf_lost_event__repr(struct pyrf_event *pevent)
200{
201 PyObject *ret;
202 char *s;
203
204 if (asprintf(&s, "{ type: lost, id: %#" PRIx64 ", "
205 "lost: %#" PRIx64 " }",
206 pevent->event.lost.id, pevent->event.lost.lost) < 0) {
207 ret = PyErr_NoMemory();
208 } else {
209 ret = PyString_FromString(s);
210 free(s);
211 }
212 return ret;
213}
214
215static PyTypeObject pyrf_lost_event__type = {
216 PyVarObject_HEAD_INIT(NULL, 0)
217 .tp_name = "perf.lost_event",
218 .tp_basicsize = sizeof(struct pyrf_event),
219 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
220 .tp_doc = pyrf_lost_event__doc,
221 .tp_members = pyrf_lost_event__members,
222 .tp_repr = (reprfunc)pyrf_lost_event__repr,
223};
224
225static char pyrf_read_event__doc[] = PyDoc_STR("perf read event object.");
226
227static PyMemberDef pyrf_read_event__members[] = {
228 sample_members
229 member_def(read_event, pid, T_UINT, "event pid"),
230 member_def(read_event, tid, T_UINT, "event tid"),
231 { .name = NULL, },
232};
233
234static PyObject *pyrf_read_event__repr(struct pyrf_event *pevent)
235{
236 return PyString_FromFormat("{ type: read, pid: %u, tid: %u }",
237 pevent->event.read.pid,
238 pevent->event.read.tid);
239 /*
240 * FIXME: return the array of read values,
241 * making this method useful ;-)
242 */
243}
244
245static PyTypeObject pyrf_read_event__type = {
246 PyVarObject_HEAD_INIT(NULL, 0)
247 .tp_name = "perf.read_event",
248 .tp_basicsize = sizeof(struct pyrf_event),
249 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
250 .tp_doc = pyrf_read_event__doc,
251 .tp_members = pyrf_read_event__members,
252 .tp_repr = (reprfunc)pyrf_read_event__repr,
253};
254
255static char pyrf_sample_event__doc[] = PyDoc_STR("perf sample event object.");
256
257static PyMemberDef pyrf_sample_event__members[] = {
258 sample_members
259 member_def(perf_event_header, type, T_UINT, "event type"),
260 { .name = NULL, },
261};
262
263static PyObject *pyrf_sample_event__repr(struct pyrf_event *pevent)
264{
265 PyObject *ret;
266 char *s;
267
268 if (asprintf(&s, "{ type: sample }") < 0) {
269 ret = PyErr_NoMemory();
270 } else {
271 ret = PyString_FromString(s);
272 free(s);
273 }
274 return ret;
275}
276
277static PyTypeObject pyrf_sample_event__type = {
278 PyVarObject_HEAD_INIT(NULL, 0)
279 .tp_name = "perf.sample_event",
280 .tp_basicsize = sizeof(struct pyrf_event),
281 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
282 .tp_doc = pyrf_sample_event__doc,
283 .tp_members = pyrf_sample_event__members,
284 .tp_repr = (reprfunc)pyrf_sample_event__repr,
285};
286
190static int pyrf_event__setup_types(void) 287static int pyrf_event__setup_types(void)
191{ 288{
192 int err; 289 int err;
193 pyrf_mmap_event__type.tp_new = 290 pyrf_mmap_event__type.tp_new =
194 pyrf_task_event__type.tp_new = 291 pyrf_task_event__type.tp_new =
195 pyrf_comm_event__type.tp_new = 292 pyrf_comm_event__type.tp_new =
293 pyrf_lost_event__type.tp_new =
294 pyrf_read_event__type.tp_new =
295 pyrf_sample_event__type.tp_new =
196 pyrf_throttle_event__type.tp_new = PyType_GenericNew; 296 pyrf_throttle_event__type.tp_new = PyType_GenericNew;
197 err = PyType_Ready(&pyrf_mmap_event__type); 297 err = PyType_Ready(&pyrf_mmap_event__type);
198 if (err < 0) 298 if (err < 0)
199 goto out; 299 goto out;
300 err = PyType_Ready(&pyrf_lost_event__type);
301 if (err < 0)
302 goto out;
200 err = PyType_Ready(&pyrf_task_event__type); 303 err = PyType_Ready(&pyrf_task_event__type);
201 if (err < 0) 304 if (err < 0)
202 goto out; 305 goto out;
@@ -206,20 +309,26 @@ static int pyrf_event__setup_types(void)
206 err = PyType_Ready(&pyrf_throttle_event__type); 309 err = PyType_Ready(&pyrf_throttle_event__type);
207 if (err < 0) 310 if (err < 0)
208 goto out; 311 goto out;
312 err = PyType_Ready(&pyrf_read_event__type);
313 if (err < 0)
314 goto out;
315 err = PyType_Ready(&pyrf_sample_event__type);
316 if (err < 0)
317 goto out;
209out: 318out:
210 return err; 319 return err;
211} 320}
212 321
213static PyTypeObject *pyrf_event__type[] = { 322static PyTypeObject *pyrf_event__type[] = {
214 [PERF_RECORD_MMAP] = &pyrf_mmap_event__type, 323 [PERF_RECORD_MMAP] = &pyrf_mmap_event__type,
215 [PERF_RECORD_LOST] = &pyrf_mmap_event__type, 324 [PERF_RECORD_LOST] = &pyrf_lost_event__type,
216 [PERF_RECORD_COMM] = &pyrf_comm_event__type, 325 [PERF_RECORD_COMM] = &pyrf_comm_event__type,
217 [PERF_RECORD_EXIT] = &pyrf_task_event__type, 326 [PERF_RECORD_EXIT] = &pyrf_task_event__type,
218 [PERF_RECORD_THROTTLE] = &pyrf_throttle_event__type, 327 [PERF_RECORD_THROTTLE] = &pyrf_throttle_event__type,
219 [PERF_RECORD_UNTHROTTLE] = &pyrf_throttle_event__type, 328 [PERF_RECORD_UNTHROTTLE] = &pyrf_throttle_event__type,
220 [PERF_RECORD_FORK] = &pyrf_task_event__type, 329 [PERF_RECORD_FORK] = &pyrf_task_event__type,
221 [PERF_RECORD_READ] = &pyrf_mmap_event__type, 330 [PERF_RECORD_READ] = &pyrf_read_event__type,
222 [PERF_RECORD_SAMPLE] = &pyrf_mmap_event__type, 331 [PERF_RECORD_SAMPLE] = &pyrf_sample_event__type,
223}; 332};
224 333
225static PyObject *pyrf_event__new(union perf_event *event) 334static PyObject *pyrf_event__new(union perf_event *event)
@@ -247,7 +356,7 @@ struct pyrf_cpu_map {
247static int pyrf_cpu_map__init(struct pyrf_cpu_map *pcpus, 356static int pyrf_cpu_map__init(struct pyrf_cpu_map *pcpus,
248 PyObject *args, PyObject *kwargs) 357 PyObject *args, PyObject *kwargs)
249{ 358{
250 static char *kwlist[] = { "cpustr", NULL, NULL, }; 359 static char *kwlist[] = { "cpustr", NULL };
251 char *cpustr = NULL; 360 char *cpustr = NULL;
252 361
253 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|s", 362 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|s",
@@ -316,7 +425,7 @@ struct pyrf_thread_map {
316static int pyrf_thread_map__init(struct pyrf_thread_map *pthreads, 425static int pyrf_thread_map__init(struct pyrf_thread_map *pthreads,
317 PyObject *args, PyObject *kwargs) 426 PyObject *args, PyObject *kwargs)
318{ 427{
319 static char *kwlist[] = { "pid", "tid", NULL, NULL, }; 428 static char *kwlist[] = { "pid", "tid", NULL };
320 int pid = -1, tid = -1; 429 int pid = -1, tid = -1;
321 430
322 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii", 431 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii",
@@ -418,7 +527,9 @@ static int pyrf_evsel__init(struct pyrf_evsel *pevsel,
418 "wakeup_events", 527 "wakeup_events",
419 "bp_type", 528 "bp_type",
420 "bp_addr", 529 "bp_addr",
421 "bp_len", NULL, NULL, }; 530 "bp_len",
531 NULL
532 };
422 u64 sample_period = 0; 533 u64 sample_period = 0;
423 u32 disabled = 0, 534 u32 disabled = 0,
424 inherit = 0, 535 inherit = 0,
@@ -499,7 +610,7 @@ static PyObject *pyrf_evsel__open(struct pyrf_evsel *pevsel,
499 struct thread_map *threads = NULL; 610 struct thread_map *threads = NULL;
500 PyObject *pcpus = NULL, *pthreads = NULL; 611 PyObject *pcpus = NULL, *pthreads = NULL;
501 int group = 0, inherit = 0; 612 int group = 0, inherit = 0;
502 static char *kwlist[] = {"cpus", "threads", "group", "inherit", NULL, NULL}; 613 static char *kwlist[] = { "cpus", "threads", "group", "inherit", NULL };
503 614
504 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOii", kwlist, 615 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOii", kwlist,
505 &pcpus, &pthreads, &group, &inherit)) 616 &pcpus, &pthreads, &group, &inherit))
@@ -512,7 +623,11 @@ static PyObject *pyrf_evsel__open(struct pyrf_evsel *pevsel,
512 cpus = ((struct pyrf_cpu_map *)pcpus)->cpus; 623 cpus = ((struct pyrf_cpu_map *)pcpus)->cpus;
513 624
514 evsel->attr.inherit = inherit; 625 evsel->attr.inherit = inherit;
515 if (perf_evsel__open(evsel, cpus, threads, group) < 0) { 626 /*
627 * This will group just the fds for this single evsel, to group
628 * multiple events, use evlist.open().
629 */
630 if (perf_evsel__open(evsel, cpus, threads, group, NULL) < 0) {
516 PyErr_SetFromErrno(PyExc_OSError); 631 PyErr_SetFromErrno(PyExc_OSError);
517 return NULL; 632 return NULL;
518 } 633 }
@@ -582,8 +697,7 @@ static PyObject *pyrf_evlist__mmap(struct pyrf_evlist *pevlist,
582 PyObject *args, PyObject *kwargs) 697 PyObject *args, PyObject *kwargs)
583{ 698{
584 struct perf_evlist *evlist = &pevlist->evlist; 699 struct perf_evlist *evlist = &pevlist->evlist;
585 static char *kwlist[] = {"pages", "overwrite", 700 static char *kwlist[] = { "pages", "overwrite", NULL };
586 NULL, NULL};
587 int pages = 128, overwrite = false; 701 int pages = 128, overwrite = false;
588 702
589 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii", kwlist, 703 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii", kwlist,
@@ -603,7 +717,7 @@ static PyObject *pyrf_evlist__poll(struct pyrf_evlist *pevlist,
603 PyObject *args, PyObject *kwargs) 717 PyObject *args, PyObject *kwargs)
604{ 718{
605 struct perf_evlist *evlist = &pevlist->evlist; 719 struct perf_evlist *evlist = &pevlist->evlist;
606 static char *kwlist[] = {"timeout", NULL, NULL}; 720 static char *kwlist[] = { "timeout", NULL };
607 int timeout = -1, n; 721 int timeout = -1, n;
608 722
609 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i", kwlist, &timeout)) 723 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i", kwlist, &timeout))
@@ -674,7 +788,7 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
674 struct perf_evlist *evlist = &pevlist->evlist; 788 struct perf_evlist *evlist = &pevlist->evlist;
675 union perf_event *event; 789 union perf_event *event;
676 int sample_id_all = 1, cpu; 790 int sample_id_all = 1, cpu;
677 static char *kwlist[] = {"cpu", "sample_id_all", NULL, NULL}; 791 static char *kwlist[] = { "cpu", "sample_id_all", NULL };
678 int err; 792 int err;
679 793
680 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|i", kwlist, 794 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|i", kwlist,
@@ -693,7 +807,7 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
693 first = list_entry(evlist->entries.next, struct perf_evsel, node); 807 first = list_entry(evlist->entries.next, struct perf_evsel, node);
694 err = perf_event__parse_sample(event, first->attr.sample_type, 808 err = perf_event__parse_sample(event, first->attr.sample_type,
695 perf_evsel__sample_size(first), 809 perf_evsel__sample_size(first),
696 sample_id_all, &pevent->sample); 810 sample_id_all, &pevent->sample, false);
697 if (err) 811 if (err)
698 return PyErr_Format(PyExc_OSError, 812 return PyErr_Format(PyExc_OSError,
699 "perf: can't parse sample, err=%d", err); 813 "perf: can't parse sample, err=%d", err);
@@ -704,6 +818,25 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
704 return Py_None; 818 return Py_None;
705} 819}
706 820
821static PyObject *pyrf_evlist__open(struct pyrf_evlist *pevlist,
822 PyObject *args, PyObject *kwargs)
823{
824 struct perf_evlist *evlist = &pevlist->evlist;
825 int group = 0;
826 static char *kwlist[] = { "group", NULL };
827
828 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOii", kwlist, &group))
829 return NULL;
830
831 if (perf_evlist__open(evlist, group) < 0) {
832 PyErr_SetFromErrno(PyExc_OSError);
833 return NULL;
834 }
835
836 Py_INCREF(Py_None);
837 return Py_None;
838}
839
707static PyMethodDef pyrf_evlist__methods[] = { 840static PyMethodDef pyrf_evlist__methods[] = {
708 { 841 {
709 .ml_name = "mmap", 842 .ml_name = "mmap",
@@ -712,6 +845,12 @@ static PyMethodDef pyrf_evlist__methods[] = {
712 .ml_doc = PyDoc_STR("mmap the file descriptor table.") 845 .ml_doc = PyDoc_STR("mmap the file descriptor table.")
713 }, 846 },
714 { 847 {
848 .ml_name = "open",
849 .ml_meth = (PyCFunction)pyrf_evlist__open,
850 .ml_flags = METH_VARARGS | METH_KEYWORDS,
851 .ml_doc = PyDoc_STR("open the file descriptors.")
852 },
853 {
715 .ml_name = "poll", 854 .ml_name = "poll",
716 .ml_meth = (PyCFunction)pyrf_evlist__poll, 855 .ml_meth = (PyCFunction)pyrf_evlist__poll,
717 .ml_flags = METH_VARARGS | METH_KEYWORDS, 856 .ml_flags = METH_VARARGS | METH_KEYWORDS,
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index f5a8fbdd3f76..85c1e6b76f0a 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -12,6 +12,7 @@
12#include "session.h" 12#include "session.h"
13#include "sort.h" 13#include "sort.h"
14#include "util.h" 14#include "util.h"
15#include "cpumap.h"
15 16
16static int perf_session__open(struct perf_session *self, bool force) 17static int perf_session__open(struct perf_session *self, bool force)
17{ 18{
@@ -247,9 +248,14 @@ int perf_session__resolve_callchain(struct perf_session *self,
247 callchain_cursor_reset(&self->callchain_cursor); 248 callchain_cursor_reset(&self->callchain_cursor);
248 249
249 for (i = 0; i < chain->nr; i++) { 250 for (i = 0; i < chain->nr; i++) {
250 u64 ip = chain->ips[i]; 251 u64 ip;
251 struct addr_location al; 252 struct addr_location al;
252 253
254 if (callchain_param.order == ORDER_CALLEE)
255 ip = chain->ips[i];
256 else
257 ip = chain->ips[chain->nr - i - 1];
258
253 if (ip >= PERF_CONTEXT_MAX) { 259 if (ip >= PERF_CONTEXT_MAX) {
254 switch (ip) { 260 switch (ip) {
255 case PERF_CONTEXT_HV: 261 case PERF_CONTEXT_HV:
@@ -407,20 +413,26 @@ static void perf_event__read_swap(union perf_event *event)
407 event->read.id = bswap_64(event->read.id); 413 event->read.id = bswap_64(event->read.id);
408} 414}
409 415
410static void perf_event__attr_swap(union perf_event *event) 416/* exported for swapping attributes in file header */
417void perf_event__attr_swap(struct perf_event_attr *attr)
418{
419 attr->type = bswap_32(attr->type);
420 attr->size = bswap_32(attr->size);
421 attr->config = bswap_64(attr->config);
422 attr->sample_period = bswap_64(attr->sample_period);
423 attr->sample_type = bswap_64(attr->sample_type);
424 attr->read_format = bswap_64(attr->read_format);
425 attr->wakeup_events = bswap_32(attr->wakeup_events);
426 attr->bp_type = bswap_32(attr->bp_type);
427 attr->bp_addr = bswap_64(attr->bp_addr);
428 attr->bp_len = bswap_64(attr->bp_len);
429}
430
431static void perf_event__hdr_attr_swap(union perf_event *event)
411{ 432{
412 size_t size; 433 size_t size;
413 434
414 event->attr.attr.type = bswap_32(event->attr.attr.type); 435 perf_event__attr_swap(&event->attr.attr);
415 event->attr.attr.size = bswap_32(event->attr.attr.size);
416 event->attr.attr.config = bswap_64(event->attr.attr.config);
417 event->attr.attr.sample_period = bswap_64(event->attr.attr.sample_period);
418 event->attr.attr.sample_type = bswap_64(event->attr.attr.sample_type);
419 event->attr.attr.read_format = bswap_64(event->attr.attr.read_format);
420 event->attr.attr.wakeup_events = bswap_32(event->attr.attr.wakeup_events);
421 event->attr.attr.bp_type = bswap_32(event->attr.attr.bp_type);
422 event->attr.attr.bp_addr = bswap_64(event->attr.attr.bp_addr);
423 event->attr.attr.bp_len = bswap_64(event->attr.attr.bp_len);
424 436
425 size = event->header.size; 437 size = event->header.size;
426 size -= (void *)&event->attr.id - (void *)event; 438 size -= (void *)&event->attr.id - (void *)event;
@@ -448,7 +460,7 @@ static perf_event__swap_op perf_event__swap_ops[] = {
448 [PERF_RECORD_LOST] = perf_event__all64_swap, 460 [PERF_RECORD_LOST] = perf_event__all64_swap,
449 [PERF_RECORD_READ] = perf_event__read_swap, 461 [PERF_RECORD_READ] = perf_event__read_swap,
450 [PERF_RECORD_SAMPLE] = perf_event__all64_swap, 462 [PERF_RECORD_SAMPLE] = perf_event__all64_swap,
451 [PERF_RECORD_HEADER_ATTR] = perf_event__attr_swap, 463 [PERF_RECORD_HEADER_ATTR] = perf_event__hdr_attr_swap,
452 [PERF_RECORD_HEADER_EVENT_TYPE] = perf_event__event_type_swap, 464 [PERF_RECORD_HEADER_EVENT_TYPE] = perf_event__event_type_swap,
453 [PERF_RECORD_HEADER_TRACING_DATA] = perf_event__tracing_data_swap, 465 [PERF_RECORD_HEADER_TRACING_DATA] = perf_event__tracing_data_swap,
454 [PERF_RECORD_HEADER_BUILD_ID] = NULL, 466 [PERF_RECORD_HEADER_BUILD_ID] = NULL,
@@ -490,6 +502,7 @@ static void flush_sample_queue(struct perf_session *s,
490 struct perf_sample sample; 502 struct perf_sample sample;
491 u64 limit = os->next_flush; 503 u64 limit = os->next_flush;
492 u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL; 504 u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL;
505 unsigned idx = 0, progress_next = os->nr_samples / 16;
493 int ret; 506 int ret;
494 507
495 if (!ops->ordered_samples || !limit) 508 if (!ops->ordered_samples || !limit)
@@ -509,6 +522,11 @@ static void flush_sample_queue(struct perf_session *s,
509 os->last_flush = iter->timestamp; 522 os->last_flush = iter->timestamp;
510 list_del(&iter->list); 523 list_del(&iter->list);
511 list_add(&iter->list, &os->sample_cache); 524 list_add(&iter->list, &os->sample_cache);
525 if (++idx >= progress_next) {
526 progress_next += os->nr_samples / 16;
527 ui_progress__update(idx, os->nr_samples,
528 "Processing time ordered events...");
529 }
512 } 530 }
513 531
514 if (list_empty(head)) { 532 if (list_empty(head)) {
@@ -517,6 +535,8 @@ static void flush_sample_queue(struct perf_session *s,
517 os->last_sample = 535 os->last_sample =
518 list_entry(head->prev, struct sample_queue, list); 536 list_entry(head->prev, struct sample_queue, list);
519 } 537 }
538
539 os->nr_samples = 0;
520} 540}
521 541
522/* 542/*
@@ -576,6 +596,7 @@ static void __queue_event(struct sample_queue *new, struct perf_session *s)
576 u64 timestamp = new->timestamp; 596 u64 timestamp = new->timestamp;
577 struct list_head *p; 597 struct list_head *p;
578 598
599 ++os->nr_samples;
579 os->last_sample = new; 600 os->last_sample = new;
580 601
581 if (!sample) { 602 if (!sample) {
@@ -708,9 +729,9 @@ static void dump_sample(struct perf_session *session, union perf_event *event,
708 if (!dump_trace) 729 if (!dump_trace)
709 return; 730 return;
710 731
711 printf("(IP, %d): %d/%d: %#" PRIx64 " period: %" PRIu64 "\n", 732 printf("(IP, %d): %d/%d: %#" PRIx64 " period: %" PRIu64 " addr: %#" PRIx64 "\n",
712 event->header.misc, sample->pid, sample->tid, sample->ip, 733 event->header.misc, sample->pid, sample->tid, sample->ip,
713 sample->period); 734 sample->period, sample->addr);
714 735
715 if (session->sample_type & PERF_SAMPLE_CALLCHAIN) 736 if (session->sample_type & PERF_SAMPLE_CALLCHAIN)
716 callchain__printf(sample); 737 callchain__printf(sample);
@@ -726,10 +747,27 @@ static int perf_session_deliver_event(struct perf_session *session,
726 747
727 dump_event(session, event, file_offset, sample); 748 dump_event(session, event, file_offset, sample);
728 749
750 evsel = perf_evlist__id2evsel(session->evlist, sample->id);
751 if (evsel != NULL && event->header.type != PERF_RECORD_SAMPLE) {
752 /*
753 * XXX We're leaving PERF_RECORD_SAMPLE unnacounted here
754 * because the tools right now may apply filters, discarding
755 * some of the samples. For consistency, in the future we
756 * should have something like nr_filtered_samples and remove
757 * the sample->period from total_sample_period, etc, KISS for
758 * now tho.
759 *
760 * Also testing against NULL allows us to handle files without
761 * attr.sample_id_all and/or without PERF_SAMPLE_ID. In the
762 * future probably it'll be a good idea to restrict event
763 * processing via perf_session to files with both set.
764 */
765 hists__inc_nr_events(&evsel->hists, event->header.type);
766 }
767
729 switch (event->header.type) { 768 switch (event->header.type) {
730 case PERF_RECORD_SAMPLE: 769 case PERF_RECORD_SAMPLE:
731 dump_sample(session, event, sample); 770 dump_sample(session, event, sample);
732 evsel = perf_evlist__id2evsel(session->evlist, sample->id);
733 if (evsel == NULL) { 771 if (evsel == NULL) {
734 ++session->hists.stats.nr_unknown_id; 772 ++session->hists.stats.nr_unknown_id;
735 return -1; 773 return -1;
@@ -862,11 +900,11 @@ static void perf_session__warn_about_errors(const struct perf_session *session,
862 const struct perf_event_ops *ops) 900 const struct perf_event_ops *ops)
863{ 901{
864 if (ops->lost == perf_event__process_lost && 902 if (ops->lost == perf_event__process_lost &&
865 session->hists.stats.total_lost != 0) { 903 session->hists.stats.nr_events[PERF_RECORD_LOST] != 0) {
866 ui__warning("Processed %" PRIu64 " events and LOST %" PRIu64 904 ui__warning("Processed %d events and lost %d chunks!\n\n"
867 "!\n\nCheck IO/CPU overload!\n\n", 905 "Check IO/CPU overload!\n\n",
868 session->hists.stats.total_period, 906 session->hists.stats.nr_events[0],
869 session->hists.stats.total_lost); 907 session->hists.stats.nr_events[PERF_RECORD_LOST]);
870 } 908 }
871 909
872 if (session->hists.stats.nr_unknown_events != 0) { 910 if (session->hists.stats.nr_unknown_events != 0) {
@@ -1000,7 +1038,6 @@ int __perf_session__process_events(struct perf_session *session,
1000{ 1038{
1001 u64 head, page_offset, file_offset, file_pos, progress_next; 1039 u64 head, page_offset, file_offset, file_pos, progress_next;
1002 int err, mmap_prot, mmap_flags, map_idx = 0; 1040 int err, mmap_prot, mmap_flags, map_idx = 0;
1003 struct ui_progress *progress;
1004 size_t page_size, mmap_size; 1041 size_t page_size, mmap_size;
1005 char *buf, *mmaps[8]; 1042 char *buf, *mmaps[8];
1006 union perf_event *event; 1043 union perf_event *event;
@@ -1018,9 +1055,6 @@ int __perf_session__process_events(struct perf_session *session,
1018 file_size = data_offset + data_size; 1055 file_size = data_offset + data_size;
1019 1056
1020 progress_next = file_size / 16; 1057 progress_next = file_size / 16;
1021 progress = ui_progress__new("Processing events...", file_size);
1022 if (progress == NULL)
1023 return -1;
1024 1058
1025 mmap_size = session->mmap_window; 1059 mmap_size = session->mmap_window;
1026 if (mmap_size > file_size) 1060 if (mmap_size > file_size)
@@ -1083,7 +1117,8 @@ more:
1083 1117
1084 if (file_pos >= progress_next) { 1118 if (file_pos >= progress_next) {
1085 progress_next += file_size / 16; 1119 progress_next += file_size / 16;
1086 ui_progress__update(progress, file_pos); 1120 ui_progress__update(file_pos, file_size,
1121 "Processing events...");
1087 } 1122 }
1088 1123
1089 if (file_pos < file_size) 1124 if (file_pos < file_size)
@@ -1094,7 +1129,6 @@ more:
1094 session->ordered_samples.next_flush = ULLONG_MAX; 1129 session->ordered_samples.next_flush = ULLONG_MAX;
1095 flush_sample_queue(session, ops); 1130 flush_sample_queue(session, ops);
1096out_err: 1131out_err:
1097 ui_progress__delete(progress);
1098 perf_session__warn_about_errors(session, ops); 1132 perf_session__warn_about_errors(session, ops);
1099 perf_session_free_sample_buffers(session); 1133 perf_session_free_sample_buffers(session);
1100 return err; 1134 return err;
@@ -1202,9 +1236,10 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
1202 return NULL; 1236 return NULL;
1203} 1237}
1204 1238
1205void perf_session__print_symbols(union perf_event *event, 1239void perf_session__print_ip(union perf_event *event,
1206 struct perf_sample *sample, 1240 struct perf_sample *sample,
1207 struct perf_session *session) 1241 struct perf_session *session,
1242 int print_sym, int print_dso)
1208{ 1243{
1209 struct addr_location al; 1244 struct addr_location al;
1210 const char *symname, *dsoname; 1245 const char *symname, *dsoname;
@@ -1233,32 +1268,102 @@ void perf_session__print_symbols(union perf_event *event,
1233 if (!node) 1268 if (!node)
1234 break; 1269 break;
1235 1270
1236 if (node->sym && node->sym->name) 1271 printf("\t%16" PRIx64, node->ip);
1237 symname = node->sym->name; 1272 if (print_sym) {
1273 if (node->sym && node->sym->name)
1274 symname = node->sym->name;
1275 else
1276 symname = "";
1277
1278 printf(" %s", symname);
1279 }
1280 if (print_dso) {
1281 if (node->map && node->map->dso && node->map->dso->name)
1282 dsoname = node->map->dso->name;
1283 else
1284 dsoname = "";
1285
1286 printf(" (%s)", dsoname);
1287 }
1288 printf("\n");
1289
1290 callchain_cursor_advance(cursor);
1291 }
1292
1293 } else {
1294 printf("%16" PRIx64, sample->ip);
1295 if (print_sym) {
1296 if (al.sym && al.sym->name)
1297 symname = al.sym->name;
1238 else 1298 else
1239 symname = ""; 1299 symname = "";
1240 1300
1241 if (node->map && node->map->dso && node->map->dso->name) 1301 printf(" %s", symname);
1242 dsoname = node->map->dso->name; 1302 }
1303
1304 if (print_dso) {
1305 if (al.map && al.map->dso && al.map->dso->name)
1306 dsoname = al.map->dso->name;
1243 else 1307 else
1244 dsoname = ""; 1308 dsoname = "";
1245 1309
1246 printf("\t%16" PRIx64 " %s (%s)\n", node->ip, symname, dsoname); 1310 printf(" (%s)", dsoname);
1311 }
1312 }
1313}
1247 1314
1248 callchain_cursor_advance(cursor); 1315int perf_session__cpu_bitmap(struct perf_session *session,
1316 const char *cpu_list, unsigned long *cpu_bitmap)
1317{
1318 int i;
1319 struct cpu_map *map;
1320
1321 for (i = 0; i < PERF_TYPE_MAX; ++i) {
1322 struct perf_evsel *evsel;
1323
1324 evsel = perf_session__find_first_evtype(session, i);
1325 if (!evsel)
1326 continue;
1327
1328 if (!(evsel->attr.sample_type & PERF_SAMPLE_CPU)) {
1329 pr_err("File does not contain CPU events. "
1330 "Remove -c option to proceed.\n");
1331 return -1;
1249 } 1332 }
1333 }
1250 1334
1251 } else { 1335 map = cpu_map__new(cpu_list);
1252 if (al.sym && al.sym->name)
1253 symname = al.sym->name;
1254 else
1255 symname = "";
1256 1336
1257 if (al.map && al.map->dso && al.map->dso->name) 1337 for (i = 0; i < map->nr; i++) {
1258 dsoname = al.map->dso->name; 1338 int cpu = map->map[i];
1259 else
1260 dsoname = "";
1261 1339
1262 printf("%16" PRIx64 " %s (%s)", al.addr, symname, dsoname); 1340 if (cpu >= MAX_NR_CPUS) {
1341 pr_err("Requested CPU %d too large. "
1342 "Consider raising MAX_NR_CPUS\n", cpu);
1343 return -1;
1344 }
1345
1346 set_bit(cpu, cpu_bitmap);
1263 } 1347 }
1348
1349 return 0;
1350}
1351
1352void perf_session__fprintf_info(struct perf_session *session, FILE *fp,
1353 bool full)
1354{
1355 struct stat st;
1356 int ret;
1357
1358 if (session == NULL || fp == NULL)
1359 return;
1360
1361 ret = fstat(session->fd, &st);
1362 if (ret == -1)
1363 return;
1364
1365 fprintf(fp, "# ========\n");
1366 fprintf(fp, "# captured on: %s", ctime(&st.st_ctime));
1367 perf_header__fprintf_info(session, fp, full);
1368 fprintf(fp, "# ========\n#\n");
1264} 1369}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 66d4e1490879..6e393c98eb34 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -23,6 +23,7 @@ struct ordered_samples {
23 struct sample_queue *sample_buffer; 23 struct sample_queue *sample_buffer;
24 struct sample_queue *last_sample; 24 struct sample_queue *last_sample;
25 int sample_buffer_idx; 25 int sample_buffer_idx;
26 unsigned int nr_samples;
26}; 27};
27 28
28struct perf_session { 29struct perf_session {
@@ -112,6 +113,7 @@ int perf_session__set_kallsyms_ref_reloc_sym(struct map **maps,
112 u64 addr); 113 u64 addr);
113 114
114void mem_bswap_64(void *src, int byte_size); 115void mem_bswap_64(void *src, int byte_size);
116void perf_event__attr_swap(struct perf_event_attr *attr);
115 117
116int perf_session__create_kernel_maps(struct perf_session *self); 118int perf_session__create_kernel_maps(struct perf_session *self);
117 119
@@ -161,14 +163,20 @@ static inline int perf_session__parse_sample(struct perf_session *session,
161{ 163{
162 return perf_event__parse_sample(event, session->sample_type, 164 return perf_event__parse_sample(event, session->sample_type,
163 session->sample_size, 165 session->sample_size,
164 session->sample_id_all, sample); 166 session->sample_id_all, sample,
167 session->header.needs_swap);
165} 168}
166 169
167struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, 170struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
168 unsigned int type); 171 unsigned int type);
169 172
170void perf_session__print_symbols(union perf_event *event, 173void perf_session__print_ip(union perf_event *event,
171 struct perf_sample *sample, 174 struct perf_sample *sample,
172 struct perf_session *session); 175 struct perf_session *session,
176 int print_sym, int print_dso);
173 177
178int perf_session__cpu_bitmap(struct perf_session *session,
179 const char *cpu_list, unsigned long *cpu_bitmap);
180
181void perf_session__fprintf_info(struct perf_session *s, FILE *fp, bool full);
174#endif /* __PERF_SESSION_H */ 182#endif /* __PERF_SESSION_H */
diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py
index bbc982f5dd8b..95d370074928 100644
--- a/tools/perf/util/setup.py
+++ b/tools/perf/util/setup.py
@@ -3,9 +3,27 @@
3from distutils.core import setup, Extension 3from distutils.core import setup, Extension
4from os import getenv 4from os import getenv
5 5
6from distutils.command.build_ext import build_ext as _build_ext
7from distutils.command.install_lib import install_lib as _install_lib
8
9class build_ext(_build_ext):
10 def finalize_options(self):
11 _build_ext.finalize_options(self)
12 self.build_lib = build_lib
13 self.build_temp = build_tmp
14
15class install_lib(_install_lib):
16 def finalize_options(self):
17 _install_lib.finalize_options(self)
18 self.build_dir = build_lib
19
20
6cflags = ['-fno-strict-aliasing', '-Wno-write-strings'] 21cflags = ['-fno-strict-aliasing', '-Wno-write-strings']
7cflags += getenv('CFLAGS', '').split() 22cflags += getenv('CFLAGS', '').split()
8 23
24build_lib = getenv('PYTHON_EXTBUILD_LIB')
25build_tmp = getenv('PYTHON_EXTBUILD_TMP')
26
9perf = Extension('perf', 27perf = Extension('perf',
10 sources = ['util/python.c', 'util/ctype.c', 'util/evlist.c', 28 sources = ['util/python.c', 'util/ctype.c', 'util/evlist.c',
11 'util/evsel.c', 'util/cpumap.c', 'util/thread_map.c', 29 'util/evsel.c', 'util/cpumap.c', 'util/thread_map.c',
@@ -21,4 +39,5 @@ setup(name='perf',
21 author_email='acme@redhat.com', 39 author_email='acme@redhat.com',
22 license='GPLv2', 40 license='GPLv2',
23 url='http://perf.wiki.kernel.org', 41 url='http://perf.wiki.kernel.org',
24 ext_modules=[perf]) 42 ext_modules=[perf],
43 cmdclass={'build_ext': build_ext, 'install_lib': install_lib})
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index f44fa541d56e..16da30d8d765 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -15,95 +15,6 @@ char * field_sep;
15 15
16LIST_HEAD(hist_entry__sort_list); 16LIST_HEAD(hist_entry__sort_list);
17 17
18static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf,
19 size_t size, unsigned int width);
20static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf,
21 size_t size, unsigned int width);
22static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf,
23 size_t size, unsigned int width);
24static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
25 size_t size, unsigned int width);
26static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf,
27 size_t size, unsigned int width);
28static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf,
29 size_t size, unsigned int width);
30
31struct sort_entry sort_thread = {
32 .se_header = "Command: Pid",
33 .se_cmp = sort__thread_cmp,
34 .se_snprintf = hist_entry__thread_snprintf,
35 .se_width_idx = HISTC_THREAD,
36};
37
38struct sort_entry sort_comm = {
39 .se_header = "Command",
40 .se_cmp = sort__comm_cmp,
41 .se_collapse = sort__comm_collapse,
42 .se_snprintf = hist_entry__comm_snprintf,
43 .se_width_idx = HISTC_COMM,
44};
45
46struct sort_entry sort_dso = {
47 .se_header = "Shared Object",
48 .se_cmp = sort__dso_cmp,
49 .se_snprintf = hist_entry__dso_snprintf,
50 .se_width_idx = HISTC_DSO,
51};
52
53struct sort_entry sort_sym = {
54 .se_header = "Symbol",
55 .se_cmp = sort__sym_cmp,
56 .se_snprintf = hist_entry__sym_snprintf,
57 .se_width_idx = HISTC_SYMBOL,
58};
59
60struct sort_entry sort_parent = {
61 .se_header = "Parent symbol",
62 .se_cmp = sort__parent_cmp,
63 .se_snprintf = hist_entry__parent_snprintf,
64 .se_width_idx = HISTC_PARENT,
65};
66
67struct sort_entry sort_cpu = {
68 .se_header = "CPU",
69 .se_cmp = sort__cpu_cmp,
70 .se_snprintf = hist_entry__cpu_snprintf,
71 .se_width_idx = HISTC_CPU,
72};
73
74struct sort_dimension {
75 const char *name;
76 struct sort_entry *entry;
77 int taken;
78};
79
80static struct sort_dimension sort_dimensions[] = {
81 { .name = "pid", .entry = &sort_thread, },
82 { .name = "comm", .entry = &sort_comm, },
83 { .name = "dso", .entry = &sort_dso, },
84 { .name = "symbol", .entry = &sort_sym, },
85 { .name = "parent", .entry = &sort_parent, },
86 { .name = "cpu", .entry = &sort_cpu, },
87};
88
89int64_t cmp_null(void *l, void *r)
90{
91 if (!l && !r)
92 return 0;
93 else if (!l)
94 return -1;
95 else
96 return 1;
97}
98
99/* --sort pid */
100
101int64_t
102sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
103{
104 return right->thread->pid - left->thread->pid;
105}
106
107static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...) 18static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
108{ 19{
109 int n; 20 int n;
@@ -125,6 +36,24 @@ static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
125 return n; 36 return n;
126} 37}
127 38
39static int64_t cmp_null(void *l, void *r)
40{
41 if (!l && !r)
42 return 0;
43 else if (!l)
44 return -1;
45 else
46 return 1;
47}
48
49/* --sort pid */
50
51static int64_t
52sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
53{
54 return right->thread->pid - left->thread->pid;
55}
56
128static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf, 57static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf,
129 size_t size, unsigned int width) 58 size_t size, unsigned int width)
130{ 59{
@@ -132,15 +61,50 @@ static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf,
132 self->thread->comm ?: "", self->thread->pid); 61 self->thread->comm ?: "", self->thread->pid);
133} 62}
134 63
64struct sort_entry sort_thread = {
65 .se_header = "Command: Pid",
66 .se_cmp = sort__thread_cmp,
67 .se_snprintf = hist_entry__thread_snprintf,
68 .se_width_idx = HISTC_THREAD,
69};
70
71/* --sort comm */
72
73static int64_t
74sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
75{
76 return right->thread->pid - left->thread->pid;
77}
78
79static int64_t
80sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
81{
82 char *comm_l = left->thread->comm;
83 char *comm_r = right->thread->comm;
84
85 if (!comm_l || !comm_r)
86 return cmp_null(comm_l, comm_r);
87
88 return strcmp(comm_l, comm_r);
89}
90
135static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf, 91static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf,
136 size_t size, unsigned int width) 92 size_t size, unsigned int width)
137{ 93{
138 return repsep_snprintf(bf, size, "%*s", width, self->thread->comm); 94 return repsep_snprintf(bf, size, "%*s", width, self->thread->comm);
139} 95}
140 96
97struct sort_entry sort_comm = {
98 .se_header = "Command",
99 .se_cmp = sort__comm_cmp,
100 .se_collapse = sort__comm_collapse,
101 .se_snprintf = hist_entry__comm_snprintf,
102 .se_width_idx = HISTC_COMM,
103};
104
141/* --sort dso */ 105/* --sort dso */
142 106
143int64_t 107static int64_t
144sort__dso_cmp(struct hist_entry *left, struct hist_entry *right) 108sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
145{ 109{
146 struct dso *dso_l = left->ms.map ? left->ms.map->dso : NULL; 110 struct dso *dso_l = left->ms.map ? left->ms.map->dso : NULL;
@@ -173,18 +137,31 @@ static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf,
173 return repsep_snprintf(bf, size, "%-*s", width, "[unknown]"); 137 return repsep_snprintf(bf, size, "%-*s", width, "[unknown]");
174} 138}
175 139
140struct sort_entry sort_dso = {
141 .se_header = "Shared Object",
142 .se_cmp = sort__dso_cmp,
143 .se_snprintf = hist_entry__dso_snprintf,
144 .se_width_idx = HISTC_DSO,
145};
146
176/* --sort symbol */ 147/* --sort symbol */
177 148
178int64_t 149static int64_t
179sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) 150sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
180{ 151{
181 u64 ip_l, ip_r; 152 u64 ip_l, ip_r;
182 153
154 if (!left->ms.sym && !right->ms.sym)
155 return right->level - left->level;
156
157 if (!left->ms.sym || !right->ms.sym)
158 return cmp_null(left->ms.sym, right->ms.sym);
159
183 if (left->ms.sym == right->ms.sym) 160 if (left->ms.sym == right->ms.sym)
184 return 0; 161 return 0;
185 162
186 ip_l = left->ms.sym ? left->ms.sym->start : left->ip; 163 ip_l = left->ms.sym->start;
187 ip_r = right->ms.sym ? right->ms.sym->start : right->ip; 164 ip_r = right->ms.sym->start;
188 165
189 return (int64_t)(ip_r - ip_l); 166 return (int64_t)(ip_r - ip_l);
190} 167}
@@ -200,7 +177,9 @@ static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
200 BITS_PER_LONG / 4, self->ip, o); 177 BITS_PER_LONG / 4, self->ip, o);
201 } 178 }
202 179
203 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", self->level); 180 if (!sort_dso.elide)
181 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", self->level);
182
204 if (self->ms.sym) 183 if (self->ms.sym)
205 ret += repsep_snprintf(bf + ret, size - ret, "%s", 184 ret += repsep_snprintf(bf + ret, size - ret, "%s",
206 self->ms.sym->name); 185 self->ms.sym->name);
@@ -211,29 +190,16 @@ static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
211 return ret; 190 return ret;
212} 191}
213 192
214/* --sort comm */ 193struct sort_entry sort_sym = {
215 194 .se_header = "Symbol",
216int64_t 195 .se_cmp = sort__sym_cmp,
217sort__comm_cmp(struct hist_entry *left, struct hist_entry *right) 196 .se_snprintf = hist_entry__sym_snprintf,
218{ 197 .se_width_idx = HISTC_SYMBOL,
219 return right->thread->pid - left->thread->pid; 198};
220}
221
222int64_t
223sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
224{
225 char *comm_l = left->thread->comm;
226 char *comm_r = right->thread->comm;
227
228 if (!comm_l || !comm_r)
229 return cmp_null(comm_l, comm_r);
230
231 return strcmp(comm_l, comm_r);
232}
233 199
234/* --sort parent */ 200/* --sort parent */
235 201
236int64_t 202static int64_t
237sort__parent_cmp(struct hist_entry *left, struct hist_entry *right) 203sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
238{ 204{
239 struct symbol *sym_l = left->parent; 205 struct symbol *sym_l = left->parent;
@@ -252,9 +218,16 @@ static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf,
252 self->parent ? self->parent->name : "[other]"); 218 self->parent ? self->parent->name : "[other]");
253} 219}
254 220
221struct sort_entry sort_parent = {
222 .se_header = "Parent symbol",
223 .se_cmp = sort__parent_cmp,
224 .se_snprintf = hist_entry__parent_snprintf,
225 .se_width_idx = HISTC_PARENT,
226};
227
255/* --sort cpu */ 228/* --sort cpu */
256 229
257int64_t 230static int64_t
258sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right) 231sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
259{ 232{
260 return right->cpu - left->cpu; 233 return right->cpu - left->cpu;
@@ -266,6 +239,28 @@ static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf,
266 return repsep_snprintf(bf, size, "%-*d", width, self->cpu); 239 return repsep_snprintf(bf, size, "%-*d", width, self->cpu);
267} 240}
268 241
242struct sort_entry sort_cpu = {
243 .se_header = "CPU",
244 .se_cmp = sort__cpu_cmp,
245 .se_snprintf = hist_entry__cpu_snprintf,
246 .se_width_idx = HISTC_CPU,
247};
248
249struct sort_dimension {
250 const char *name;
251 struct sort_entry *entry;
252 int taken;
253};
254
255static struct sort_dimension sort_dimensions[] = {
256 { .name = "pid", .entry = &sort_thread, },
257 { .name = "comm", .entry = &sort_comm, },
258 { .name = "dso", .entry = &sort_dso, },
259 { .name = "symbol", .entry = &sort_sym, },
260 { .name = "parent", .entry = &sort_parent, },
261 { .name = "cpu", .entry = &sort_cpu, },
262};
263
269int sort_dimension__add(const char *tok) 264int sort_dimension__add(const char *tok)
270{ 265{
271 unsigned int i; 266 unsigned int i;
@@ -273,15 +268,9 @@ int sort_dimension__add(const char *tok)
273 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) { 268 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
274 struct sort_dimension *sd = &sort_dimensions[i]; 269 struct sort_dimension *sd = &sort_dimensions[i];
275 270
276 if (sd->taken)
277 continue;
278
279 if (strncasecmp(tok, sd->name, strlen(tok))) 271 if (strncasecmp(tok, sd->name, strlen(tok)))
280 continue; 272 continue;
281 273
282 if (sd->entry->se_collapse)
283 sort__need_collapse = 1;
284
285 if (sd->entry == &sort_parent) { 274 if (sd->entry == &sort_parent) {
286 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED); 275 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
287 if (ret) { 276 if (ret) {
@@ -294,6 +283,12 @@ int sort_dimension__add(const char *tok)
294 sort__has_parent = 1; 283 sort__has_parent = 1;
295 } 284 }
296 285
286 if (sd->taken)
287 return 0;
288
289 if (sd->entry->se_collapse)
290 sort__need_collapse = 1;
291
297 if (list_empty(&hist_entry__sort_list)) { 292 if (list_empty(&hist_entry__sort_list)) {
298 if (!strcmp(sd->name, "pid")) 293 if (!strcmp(sd->name, "pid"))
299 sort__first_dimension = SORT_PID; 294 sort__first_dimension = SORT_PID;
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 0b91053a7d11..3f67ae395752 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -45,6 +45,7 @@ extern enum sort_type sort__first_dimension;
45 * @nr_rows - rows expanded in callchain, recalculated on folding/unfolding 45 * @nr_rows - rows expanded in callchain, recalculated on folding/unfolding
46 */ 46 */
47struct hist_entry { 47struct hist_entry {
48 struct rb_node rb_node_in;
48 struct rb_node rb_node; 49 struct rb_node rb_node;
49 u64 period; 50 u64 period;
50 u64 period_sys; 51 u64 period_sys;
@@ -63,6 +64,7 @@ struct hist_entry {
63 64
64 bool init_have_children; 65 bool init_have_children;
65 char level; 66 char level;
67 bool used;
66 u8 filtered; 68 u8 filtered;
67 struct symbol *parent; 69 struct symbol *parent;
68 union { 70 union {
@@ -103,20 +105,6 @@ extern struct sort_entry sort_thread;
103extern struct list_head hist_entry__sort_list; 105extern struct list_head hist_entry__sort_list;
104 106
105void setup_sorting(const char * const usagestr[], const struct option *opts); 107void setup_sorting(const char * const usagestr[], const struct option *opts);
106
107extern size_t sort__thread_print(FILE *, struct hist_entry *, unsigned int);
108extern size_t sort__comm_print(FILE *, struct hist_entry *, unsigned int);
109extern size_t sort__dso_print(FILE *, struct hist_entry *, unsigned int);
110extern size_t sort__sym_print(FILE *, struct hist_entry *, unsigned int __used);
111extern int64_t cmp_null(void *, void *);
112extern int64_t sort__thread_cmp(struct hist_entry *, struct hist_entry *);
113extern int64_t sort__comm_cmp(struct hist_entry *, struct hist_entry *);
114extern int64_t sort__comm_collapse(struct hist_entry *, struct hist_entry *);
115extern int64_t sort__dso_cmp(struct hist_entry *, struct hist_entry *);
116extern int64_t sort__sym_cmp(struct hist_entry *, struct hist_entry *);
117extern int64_t sort__parent_cmp(struct hist_entry *, struct hist_entry *);
118int64_t sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right);
119extern size_t sort__parent_print(FILE *, struct hist_entry *, unsigned int);
120extern int sort_dimension__add(const char *); 108extern int sort_dimension__add(const char *);
121void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list, 109void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
122 const char *list_name, FILE *fp); 110 const char *list_name, FILE *fp);
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index b9a985dadd08..d5836382ff2c 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -294,3 +294,22 @@ bool strlazymatch(const char *str, const char *pat)
294{ 294{
295 return __match_glob(str, pat, true); 295 return __match_glob(str, pat, true);
296} 296}
297
298/**
299 * strtailcmp - Compare the tail of two strings
300 * @s1: 1st string to be compared
301 * @s2: 2nd string to be compared
302 *
303 * Return 0 if whole of either string is same as another's tail part.
304 */
305int strtailcmp(const char *s1, const char *s2)
306{
307 int i1 = strlen(s1);
308 int i2 = strlen(s2);
309 while (--i1 >= 0 && --i2 >= 0) {
310 if (s1[i1] != s2[i2])
311 return s1[i1] - s2[i2];
312 }
313 return 0;
314}
315
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index eec196329fd9..632b50c7bc26 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -24,7 +24,7 @@
24#include <sys/utsname.h> 24#include <sys/utsname.h>
25 25
26#ifndef KSYM_NAME_LEN 26#ifndef KSYM_NAME_LEN
27#define KSYM_NAME_LEN 128 27#define KSYM_NAME_LEN 256
28#endif 28#endif
29 29
30#ifndef NT_GNU_BUILD_ID 30#ifndef NT_GNU_BUILD_ID
@@ -46,6 +46,7 @@ struct symbol_conf symbol_conf = {
46 .exclude_other = true, 46 .exclude_other = true,
47 .use_modules = true, 47 .use_modules = true,
48 .try_vmlinux_path = true, 48 .try_vmlinux_path = true,
49 .annotate_src = true,
49 .symfs = "", 50 .symfs = "",
50}; 51};
51 52
@@ -74,16 +75,104 @@ static void dso__set_sorted_by_name(struct dso *dso, enum map_type type)
74 75
75bool symbol_type__is_a(char symbol_type, enum map_type map_type) 76bool symbol_type__is_a(char symbol_type, enum map_type map_type)
76{ 77{
78 symbol_type = toupper(symbol_type);
79
77 switch (map_type) { 80 switch (map_type) {
78 case MAP__FUNCTION: 81 case MAP__FUNCTION:
79 return symbol_type == 'T' || symbol_type == 'W'; 82 return symbol_type == 'T' || symbol_type == 'W';
80 case MAP__VARIABLE: 83 case MAP__VARIABLE:
81 return symbol_type == 'D' || symbol_type == 'd'; 84 return symbol_type == 'D';
82 default: 85 default:
83 return false; 86 return false;
84 } 87 }
85} 88}
86 89
90static int prefix_underscores_count(const char *str)
91{
92 const char *tail = str;
93
94 while (*tail == '_')
95 tail++;
96
97 return tail - str;
98}
99
100#define SYMBOL_A 0
101#define SYMBOL_B 1
102
103static int choose_best_symbol(struct symbol *syma, struct symbol *symb)
104{
105 s64 a;
106 s64 b;
107
108 /* Prefer a symbol with non zero length */
109 a = syma->end - syma->start;
110 b = symb->end - symb->start;
111 if ((b == 0) && (a > 0))
112 return SYMBOL_A;
113 else if ((a == 0) && (b > 0))
114 return SYMBOL_B;
115
116 /* Prefer a non weak symbol over a weak one */
117 a = syma->binding == STB_WEAK;
118 b = symb->binding == STB_WEAK;
119 if (b && !a)
120 return SYMBOL_A;
121 if (a && !b)
122 return SYMBOL_B;
123
124 /* Prefer a global symbol over a non global one */
125 a = syma->binding == STB_GLOBAL;
126 b = symb->binding == STB_GLOBAL;
127 if (a && !b)
128 return SYMBOL_A;
129 if (b && !a)
130 return SYMBOL_B;
131
132 /* Prefer a symbol with less underscores */
133 a = prefix_underscores_count(syma->name);
134 b = prefix_underscores_count(symb->name);
135 if (b > a)
136 return SYMBOL_A;
137 else if (a > b)
138 return SYMBOL_B;
139
140 /* If all else fails, choose the symbol with the longest name */
141 if (strlen(syma->name) >= strlen(symb->name))
142 return SYMBOL_A;
143 else
144 return SYMBOL_B;
145}
146
147static void symbols__fixup_duplicate(struct rb_root *symbols)
148{
149 struct rb_node *nd;
150 struct symbol *curr, *next;
151
152 nd = rb_first(symbols);
153
154 while (nd) {
155 curr = rb_entry(nd, struct symbol, rb_node);
156again:
157 nd = rb_next(&curr->rb_node);
158 next = rb_entry(nd, struct symbol, rb_node);
159
160 if (!nd)
161 break;
162
163 if (curr->start != next->start)
164 continue;
165
166 if (choose_best_symbol(curr, next) == SYMBOL_A) {
167 rb_erase(&next->rb_node, symbols);
168 goto again;
169 } else {
170 nd = rb_next(&curr->rb_node);
171 rb_erase(&curr->rb_node, symbols);
172 }
173 }
174}
175
87static void symbols__fixup_end(struct rb_root *symbols) 176static void symbols__fixup_end(struct rb_root *symbols)
88{ 177{
89 struct rb_node *nd, *prevnd = rb_first(symbols); 178 struct rb_node *nd, *prevnd = rb_first(symbols);
@@ -438,18 +527,11 @@ int kallsyms__parse(const char *filename, void *arg,
438 char *line = NULL; 527 char *line = NULL;
439 size_t n; 528 size_t n;
440 int err = -1; 529 int err = -1;
441 u64 prev_start = 0;
442 char prev_symbol_type = 0;
443 char *prev_symbol_name;
444 FILE *file = fopen(filename, "r"); 530 FILE *file = fopen(filename, "r");
445 531
446 if (file == NULL) 532 if (file == NULL)
447 goto out_failure; 533 goto out_failure;
448 534
449 prev_symbol_name = malloc(KSYM_NAME_LEN);
450 if (prev_symbol_name == NULL)
451 goto out_close;
452
453 err = 0; 535 err = 0;
454 536
455 while (!feof(file)) { 537 while (!feof(file)) {
@@ -470,7 +552,7 @@ int kallsyms__parse(const char *filename, void *arg,
470 if (len + 2 >= line_len) 552 if (len + 2 >= line_len)
471 continue; 553 continue;
472 554
473 symbol_type = toupper(line[len]); 555 symbol_type = line[len];
474 len += 2; 556 len += 2;
475 symbol_name = line + len; 557 symbol_name = line + len;
476 len = line_len - len; 558 len = line_len - len;
@@ -480,24 +562,18 @@ int kallsyms__parse(const char *filename, void *arg,
480 break; 562 break;
481 } 563 }
482 564
483 if (prev_symbol_type) { 565 /*
484 u64 end = start; 566 * module symbols are not sorted so we add all
485 if (end != prev_start) 567 * symbols with zero length and rely on
486 --end; 568 * symbols__fixup_end() to fix it up.
487 err = process_symbol(arg, prev_symbol_name, 569 */
488 prev_symbol_type, prev_start, end); 570 err = process_symbol(arg, symbol_name,
489 if (err) 571 symbol_type, start, start);
490 break; 572 if (err)
491 } 573 break;
492
493 memcpy(prev_symbol_name, symbol_name, len + 1);
494 prev_symbol_type = symbol_type;
495 prev_start = start;
496 } 574 }
497 575
498 free(prev_symbol_name);
499 free(line); 576 free(line);
500out_close:
501 fclose(file); 577 fclose(file);
502 return err; 578 return err;
503 579
@@ -703,6 +779,9 @@ int dso__load_kallsyms(struct dso *dso, const char *filename,
703 if (dso__load_all_kallsyms(dso, filename, map) < 0) 779 if (dso__load_all_kallsyms(dso, filename, map) < 0)
704 return -1; 780 return -1;
705 781
782 symbols__fixup_duplicate(&dso->symbols[map->type]);
783 symbols__fixup_end(&dso->symbols[map->type]);
784
706 if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 785 if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
707 dso->symtab_type = SYMTAB__GUEST_KALLSYMS; 786 dso->symtab_type = SYMTAB__GUEST_KALLSYMS;
708 else 787 else
@@ -1092,8 +1171,7 @@ static int dso__load_sym(struct dso *dso, struct map *map, const char *name,
1092 if (dso->has_build_id) { 1171 if (dso->has_build_id) {
1093 u8 build_id[BUILD_ID_SIZE]; 1172 u8 build_id[BUILD_ID_SIZE];
1094 1173
1095 if (elf_read_build_id(elf, build_id, 1174 if (elf_read_build_id(elf, build_id, BUILD_ID_SIZE) < 0)
1096 BUILD_ID_SIZE) != BUILD_ID_SIZE)
1097 goto out_elf_end; 1175 goto out_elf_end;
1098 1176
1099 if (!dso__build_id_equal(dso, build_id)) 1177 if (!dso__build_id_equal(dso, build_id))
@@ -1111,6 +1189,8 @@ static int dso__load_sym(struct dso *dso, struct map *map, const char *name,
1111 } 1189 }
1112 1190
1113 opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx); 1191 opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx);
1192 if (opdshdr.sh_type != SHT_PROGBITS)
1193 opdsec = NULL;
1114 if (opdsec) 1194 if (opdsec)
1115 opddata = elf_rawdata(opdsec, NULL); 1195 opddata = elf_rawdata(opdsec, NULL);
1116 1196
@@ -1276,6 +1356,7 @@ new_symbol:
1276 * For misannotated, zeroed, ASM function sizes. 1356 * For misannotated, zeroed, ASM function sizes.
1277 */ 1357 */
1278 if (nr > 0) { 1358 if (nr > 0) {
1359 symbols__fixup_duplicate(&dso->symbols[map->type]);
1279 symbols__fixup_end(&dso->symbols[map->type]); 1360 symbols__fixup_end(&dso->symbols[map->type]);
1280 if (kmap) { 1361 if (kmap) {
1281 /* 1362 /*
@@ -1362,8 +1443,8 @@ static int elf_read_build_id(Elf *elf, void *bf, size_t size)
1362 ptr = data->d_buf; 1443 ptr = data->d_buf;
1363 while (ptr < (data->d_buf + data->d_size)) { 1444 while (ptr < (data->d_buf + data->d_size)) {
1364 GElf_Nhdr *nhdr = ptr; 1445 GElf_Nhdr *nhdr = ptr;
1365 int namesz = NOTE_ALIGN(nhdr->n_namesz), 1446 size_t namesz = NOTE_ALIGN(nhdr->n_namesz),
1366 descsz = NOTE_ALIGN(nhdr->n_descsz); 1447 descsz = NOTE_ALIGN(nhdr->n_descsz);
1367 const char *name; 1448 const char *name;
1368 1449
1369 ptr += sizeof(*nhdr); 1450 ptr += sizeof(*nhdr);
@@ -1372,8 +1453,10 @@ static int elf_read_build_id(Elf *elf, void *bf, size_t size)
1372 if (nhdr->n_type == NT_GNU_BUILD_ID && 1453 if (nhdr->n_type == NT_GNU_BUILD_ID &&
1373 nhdr->n_namesz == sizeof("GNU")) { 1454 nhdr->n_namesz == sizeof("GNU")) {
1374 if (memcmp(name, "GNU", sizeof("GNU")) == 0) { 1455 if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
1375 memcpy(bf, ptr, BUILD_ID_SIZE); 1456 size_t sz = min(size, descsz);
1376 err = BUILD_ID_SIZE; 1457 memcpy(bf, ptr, sz);
1458 memset(bf + sz, 0, size - sz);
1459 err = descsz;
1377 break; 1460 break;
1378 } 1461 }
1379 } 1462 }
@@ -1425,7 +1508,7 @@ int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
1425 while (1) { 1508 while (1) {
1426 char bf[BUFSIZ]; 1509 char bf[BUFSIZ];
1427 GElf_Nhdr nhdr; 1510 GElf_Nhdr nhdr;
1428 int namesz, descsz; 1511 size_t namesz, descsz;
1429 1512
1430 if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr)) 1513 if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
1431 break; 1514 break;
@@ -1434,15 +1517,16 @@ int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
1434 descsz = NOTE_ALIGN(nhdr.n_descsz); 1517 descsz = NOTE_ALIGN(nhdr.n_descsz);
1435 if (nhdr.n_type == NT_GNU_BUILD_ID && 1518 if (nhdr.n_type == NT_GNU_BUILD_ID &&
1436 nhdr.n_namesz == sizeof("GNU")) { 1519 nhdr.n_namesz == sizeof("GNU")) {
1437 if (read(fd, bf, namesz) != namesz) 1520 if (read(fd, bf, namesz) != (ssize_t)namesz)
1438 break; 1521 break;
1439 if (memcmp(bf, "GNU", sizeof("GNU")) == 0) { 1522 if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
1440 if (read(fd, build_id, 1523 size_t sz = min(descsz, size);
1441 BUILD_ID_SIZE) == BUILD_ID_SIZE) { 1524 if (read(fd, build_id, sz) == (ssize_t)sz) {
1525 memset(build_id + sz, 0, size - sz);
1442 err = 0; 1526 err = 0;
1443 break; 1527 break;
1444 } 1528 }
1445 } else if (read(fd, bf, descsz) != descsz) 1529 } else if (read(fd, bf, descsz) != (ssize_t)descsz)
1446 break; 1530 break;
1447 } else { 1531 } else {
1448 int n = namesz + descsz; 1532 int n = namesz + descsz;
@@ -1504,6 +1588,17 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
1504 dso->adjust_symbols = 0; 1588 dso->adjust_symbols = 0;
1505 1589
1506 if (strncmp(dso->name, "/tmp/perf-", 10) == 0) { 1590 if (strncmp(dso->name, "/tmp/perf-", 10) == 0) {
1591 struct stat st;
1592
1593 if (lstat(dso->name, &st) < 0)
1594 return -1;
1595
1596 if (st.st_uid && (st.st_uid != geteuid())) {
1597 pr_warning("File %s not owned by current user or root, "
1598 "ignoring it.\n", dso->name);
1599 return -1;
1600 }
1601
1507 ret = dso__load_perf_map(dso, map, filter); 1602 ret = dso__load_perf_map(dso, map, filter);
1508 dso->symtab_type = ret > 0 ? SYMTAB__JAVA_JIT : 1603 dso->symtab_type = ret > 0 ? SYMTAB__JAVA_JIT :
1509 SYMTAB__NOT_FOUND; 1604 SYMTAB__NOT_FOUND;
@@ -2170,27 +2265,22 @@ size_t machines__fprintf_dsos_buildid(struct rb_root *machines,
2170 return ret; 2265 return ret;
2171} 2266}
2172 2267
2173struct dso *dso__new_kernel(const char *name) 2268static struct dso*
2269dso__kernel_findnew(struct machine *machine, const char *name,
2270 const char *short_name, int dso_type)
2174{ 2271{
2175 struct dso *dso = dso__new(name ?: "[kernel.kallsyms]"); 2272 /*
2176 2273 * The kernel dso could be created by build_id processing.
2177 if (dso != NULL) { 2274 */
2178 dso__set_short_name(dso, "[kernel]"); 2275 struct dso *dso = __dsos__findnew(&machine->kernel_dsos, name);
2179 dso->kernel = DSO_TYPE_KERNEL;
2180 }
2181
2182 return dso;
2183}
2184 2276
2185static struct dso *dso__new_guest_kernel(struct machine *machine, 2277 /*
2186 const char *name) 2278 * We need to run this in all cases, since during the build_id
2187{ 2279 * processing we had no idea this was the kernel dso.
2188 char bf[PATH_MAX]; 2280 */
2189 struct dso *dso = dso__new(name ?: machine__mmap_name(machine, bf,
2190 sizeof(bf)));
2191 if (dso != NULL) { 2281 if (dso != NULL) {
2192 dso__set_short_name(dso, "[guest.kernel]"); 2282 dso__set_short_name(dso, short_name);
2193 dso->kernel = DSO_TYPE_GUEST_KERNEL; 2283 dso->kernel = dso_type;
2194 } 2284 }
2195 2285
2196 return dso; 2286 return dso;
@@ -2208,24 +2298,36 @@ void dso__read_running_kernel_build_id(struct dso *dso, struct machine *machine)
2208 dso->has_build_id = true; 2298 dso->has_build_id = true;
2209} 2299}
2210 2300
2211static struct dso *machine__create_kernel(struct machine *machine) 2301static struct dso *machine__get_kernel(struct machine *machine)
2212{ 2302{
2213 const char *vmlinux_name = NULL; 2303 const char *vmlinux_name = NULL;
2214 struct dso *kernel; 2304 struct dso *kernel;
2215 2305
2216 if (machine__is_host(machine)) { 2306 if (machine__is_host(machine)) {
2217 vmlinux_name = symbol_conf.vmlinux_name; 2307 vmlinux_name = symbol_conf.vmlinux_name;
2218 kernel = dso__new_kernel(vmlinux_name); 2308 if (!vmlinux_name)
2309 vmlinux_name = "[kernel.kallsyms]";
2310
2311 kernel = dso__kernel_findnew(machine, vmlinux_name,
2312 "[kernel]",
2313 DSO_TYPE_KERNEL);
2219 } else { 2314 } else {
2315 char bf[PATH_MAX];
2316
2220 if (machine__is_default_guest(machine)) 2317 if (machine__is_default_guest(machine))
2221 vmlinux_name = symbol_conf.default_guest_vmlinux_name; 2318 vmlinux_name = symbol_conf.default_guest_vmlinux_name;
2222 kernel = dso__new_guest_kernel(machine, vmlinux_name); 2319 if (!vmlinux_name)
2320 vmlinux_name = machine__mmap_name(machine, bf,
2321 sizeof(bf));
2322
2323 kernel = dso__kernel_findnew(machine, vmlinux_name,
2324 "[guest.kernel]",
2325 DSO_TYPE_GUEST_KERNEL);
2223 } 2326 }
2224 2327
2225 if (kernel != NULL) { 2328 if (kernel != NULL && (!kernel->has_build_id))
2226 dso__read_running_kernel_build_id(kernel, machine); 2329 dso__read_running_kernel_build_id(kernel, machine);
2227 dsos__add(&machine->kernel_dsos, kernel); 2330
2228 }
2229 return kernel; 2331 return kernel;
2230} 2332}
2231 2333
@@ -2329,7 +2431,7 @@ void machine__destroy_kernel_maps(struct machine *machine)
2329 2431
2330int machine__create_kernel_maps(struct machine *machine) 2432int machine__create_kernel_maps(struct machine *machine)
2331{ 2433{
2332 struct dso *kernel = machine__create_kernel(machine); 2434 struct dso *kernel = machine__get_kernel(machine);
2333 2435
2334 if (kernel == NULL || 2436 if (kernel == NULL ||
2335 __machine__create_kernel_maps(machine, kernel) < 0) 2437 __machine__create_kernel_maps(machine, kernel) < 0)
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 325ee36a9d29..29f8d742e92f 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -72,11 +72,14 @@ struct symbol_conf {
72 use_modules, 72 use_modules,
73 sort_by_name, 73 sort_by_name,
74 show_nr_samples, 74 show_nr_samples,
75 show_total_period,
75 use_callchain, 76 use_callchain,
76 exclude_other, 77 exclude_other,
77 show_cpu_utilization, 78 show_cpu_utilization,
78 initialized, 79 initialized,
79 kptr_restrict; 80 kptr_restrict,
81 annotate_asm_raw,
82 annotate_src;
80 const char *vmlinux_name, 83 const char *vmlinux_name,
81 *kallsyms_name, 84 *kallsyms_name,
82 *source_prefix, 85 *source_prefix,
@@ -155,7 +158,6 @@ struct dso {
155}; 158};
156 159
157struct dso *dso__new(const char *name); 160struct dso *dso__new(const char *name);
158struct dso *dso__new_kernel(const char *name);
159void dso__delete(struct dso *dso); 161void dso__delete(struct dso *dso);
160 162
161int dso__name_len(const struct dso *dso); 163int dso__name_len(const struct dso *dso);
diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c
index a11f60735a18..500471dffa4f 100644
--- a/tools/perf/util/top.c
+++ b/tools/perf/util/top.c
@@ -15,52 +15,6 @@
15#include "top.h" 15#include "top.h"
16#include <inttypes.h> 16#include <inttypes.h>
17 17
18/*
19 * Ordering weight: count-1 * count-2 * ... / count-n
20 */
21static double sym_weight(const struct sym_entry *sym, struct perf_top *top)
22{
23 double weight = sym->snap_count;
24 int counter;
25
26 if (!top->display_weighted)
27 return weight;
28
29 for (counter = 1; counter < top->evlist->nr_entries - 1; counter++)
30 weight *= sym->count[counter];
31
32 weight /= (sym->count[counter] + 1);
33
34 return weight;
35}
36
37static void perf_top__remove_active_sym(struct perf_top *top, struct sym_entry *syme)
38{
39 pthread_mutex_lock(&top->active_symbols_lock);
40 list_del_init(&syme->node);
41 pthread_mutex_unlock(&top->active_symbols_lock);
42}
43
44static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se)
45{
46 struct rb_node **p = &tree->rb_node;
47 struct rb_node *parent = NULL;
48 struct sym_entry *iter;
49
50 while (*p != NULL) {
51 parent = *p;
52 iter = rb_entry(parent, struct sym_entry, rb_node);
53
54 if (se->weight > iter->weight)
55 p = &(*p)->rb_left;
56 else
57 p = &(*p)->rb_right;
58 }
59
60 rb_link_node(&se->rb_node, parent, p);
61 rb_insert_color(&se->rb_node, tree);
62}
63
64#define SNPRINTF(buf, size, fmt, args...) \ 18#define SNPRINTF(buf, size, fmt, args...) \
65({ \ 19({ \
66 size_t r = snprintf(buf, size, fmt, ## args); \ 20 size_t r = snprintf(buf, size, fmt, ## args); \
@@ -69,7 +23,6 @@ static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se)
69 23
70size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) 24size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
71{ 25{
72 struct perf_evsel *counter;
73 float samples_per_sec = top->samples / top->delay_secs; 26 float samples_per_sec = top->samples / top->delay_secs;
74 float ksamples_per_sec = top->kernel_samples / top->delay_secs; 27 float ksamples_per_sec = top->kernel_samples / top->delay_secs;
75 float esamples_percent = (100.0 * top->exact_samples) / top->samples; 28 float esamples_percent = (100.0 * top->exact_samples) / top->samples;
@@ -104,7 +57,7 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
104 esamples_percent); 57 esamples_percent);
105 } 58 }
106 59
107 if (top->evlist->nr_entries == 1 || !top->display_weighted) { 60 if (top->evlist->nr_entries == 1) {
108 struct perf_evsel *first; 61 struct perf_evsel *first;
109 first = list_entry(top->evlist->entries.next, struct perf_evsel, node); 62 first = list_entry(top->evlist->entries.next, struct perf_evsel, node);
110 ret += SNPRINTF(bf + ret, size - ret, "%" PRIu64 "%s ", 63 ret += SNPRINTF(bf + ret, size - ret, "%" PRIu64 "%s ",
@@ -112,27 +65,7 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
112 top->freq ? "Hz" : ""); 65 top->freq ? "Hz" : "");
113 } 66 }
114 67
115 if (!top->display_weighted) { 68 ret += SNPRINTF(bf + ret, size - ret, "%s", event_name(top->sym_evsel));
116 ret += SNPRINTF(bf + ret, size - ret, "%s",
117 event_name(top->sym_evsel));
118 } else {
119 /*
120 * Don't let events eat all the space. Leaving 30 bytes
121 * for the rest should be enough.
122 */
123 size_t last_pos = size - 30;
124
125 list_for_each_entry(counter, &top->evlist->entries, node) {
126 ret += SNPRINTF(bf + ret, size - ret, "%s%s",
127 counter->idx ? "/" : "",
128 event_name(counter));
129 if (ret > last_pos) {
130 sprintf(bf + last_pos - 3, "..");
131 ret = last_pos - 1;
132 break;
133 }
134 }
135 }
136 69
137 ret += SNPRINTF(bf + ret, size - ret, "], "); 70 ret += SNPRINTF(bf + ret, size - ret, "], ");
138 71
@@ -166,73 +99,3 @@ void perf_top__reset_sample_counters(struct perf_top *top)
166 top->exact_samples = top->guest_kernel_samples = 99 top->exact_samples = top->guest_kernel_samples =
167 top->guest_us_samples = 0; 100 top->guest_us_samples = 0;
168} 101}
169
170float perf_top__decay_samples(struct perf_top *top, struct rb_root *root)
171{
172 struct sym_entry *syme, *n;
173 float sum_ksamples = 0.0;
174 int snap = !top->display_weighted ? top->sym_evsel->idx : 0, j;
175
176 /* Sort the active symbols */
177 pthread_mutex_lock(&top->active_symbols_lock);
178 syme = list_entry(top->active_symbols.next, struct sym_entry, node);
179 pthread_mutex_unlock(&top->active_symbols_lock);
180
181 top->rb_entries = 0;
182 list_for_each_entry_safe_from(syme, n, &top->active_symbols, node) {
183 syme->snap_count = syme->count[snap];
184 if (syme->snap_count != 0) {
185
186 if ((top->hide_user_symbols &&
187 syme->map->dso->kernel == DSO_TYPE_USER) ||
188 (top->hide_kernel_symbols &&
189 syme->map->dso->kernel == DSO_TYPE_KERNEL)) {
190 perf_top__remove_active_sym(top, syme);
191 continue;
192 }
193 syme->weight = sym_weight(syme, top);
194
195 if ((int)syme->snap_count >= top->count_filter) {
196 rb_insert_active_sym(root, syme);
197 ++top->rb_entries;
198 }
199 sum_ksamples += syme->snap_count;
200
201 for (j = 0; j < top->evlist->nr_entries; j++)
202 syme->count[j] = top->zero ? 0 : syme->count[j] * 7 / 8;
203 } else
204 perf_top__remove_active_sym(top, syme);
205 }
206
207 return sum_ksamples;
208}
209
210/*
211 * Find the longest symbol name that will be displayed
212 */
213void perf_top__find_widths(struct perf_top *top, struct rb_root *root,
214 int *dso_width, int *dso_short_width, int *sym_width)
215{
216 struct rb_node *nd;
217 int printed = 0;
218
219 *sym_width = *dso_width = *dso_short_width = 0;
220
221 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
222 struct sym_entry *syme = rb_entry(nd, struct sym_entry, rb_node);
223 struct symbol *sym = sym_entry__symbol(syme);
224
225 if (++printed > top->print_entries ||
226 (int)syme->snap_count < top->count_filter)
227 continue;
228
229 if (syme->map->dso->long_name_len > *dso_width)
230 *dso_width = syme->map->dso->long_name_len;
231
232 if (syme->map->dso->short_name_len > *dso_short_width)
233 *dso_short_width = syme->map->dso->short_name_len;
234
235 if (sym->namelen > *sym_width)
236 *sym_width = sym->namelen;
237 }
238}
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index bfbf95bcc603..399650967958 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -4,26 +4,10 @@
4#include "types.h" 4#include "types.h"
5#include "../perf.h" 5#include "../perf.h"
6#include <stddef.h> 6#include <stddef.h>
7#include <pthread.h>
8#include <linux/list.h>
9#include <linux/rbtree.h>
10 7
11struct perf_evlist; 8struct perf_evlist;
12struct perf_evsel; 9struct perf_evsel;
13 10struct perf_session;
14struct sym_entry {
15 struct rb_node rb_node;
16 struct list_head node;
17 unsigned long snap_count;
18 double weight;
19 struct map *map;
20 unsigned long count[0];
21};
22
23static inline struct symbol *sym_entry__symbol(struct sym_entry *self)
24{
25 return ((void *)self) + symbol_conf.priv_size;
26}
27 11
28struct perf_top { 12struct perf_top {
29 struct perf_evlist *evlist; 13 struct perf_evlist *evlist;
@@ -31,34 +15,20 @@ struct perf_top {
31 * Symbols will be added here in perf_event__process_sample and will 15 * Symbols will be added here in perf_event__process_sample and will
32 * get out after decayed. 16 * get out after decayed.
33 */ 17 */
34 struct list_head active_symbols;
35 pthread_mutex_t active_symbols_lock;
36 pthread_cond_t active_symbols_cond;
37 u64 samples; 18 u64 samples;
38 u64 kernel_samples, us_samples; 19 u64 kernel_samples, us_samples;
39 u64 exact_samples; 20 u64 exact_samples;
40 u64 guest_us_samples, guest_kernel_samples; 21 u64 guest_us_samples, guest_kernel_samples;
41 int print_entries, count_filter, delay_secs; 22 int print_entries, count_filter, delay_secs;
42 int display_weighted, freq, rb_entries; 23 int freq;
43 pid_t target_pid, target_tid; 24 pid_t target_pid, target_tid;
44 bool hide_kernel_symbols, hide_user_symbols, zero; 25 bool hide_kernel_symbols, hide_user_symbols, zero;
45 const char *cpu_list; 26 const char *cpu_list;
46 struct sym_entry *sym_filter_entry; 27 struct hist_entry *sym_filter_entry;
47 struct perf_evsel *sym_evsel; 28 struct perf_evsel *sym_evsel;
29 struct perf_session *session;
48}; 30};
49 31
50size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size); 32size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size);
51void perf_top__reset_sample_counters(struct perf_top *top); 33void perf_top__reset_sample_counters(struct perf_top *top);
52float perf_top__decay_samples(struct perf_top *top, struct rb_root *root);
53void perf_top__find_widths(struct perf_top *top, struct rb_root *root,
54 int *dso_width, int *dso_short_width, int *sym_width);
55
56#ifdef NO_NEWT_SUPPORT
57static inline int perf_top__tui_browser(struct perf_top *top __used)
58{
59 return 0;
60}
61#else
62int perf_top__tui_browser(struct perf_top *top);
63#endif
64#endif /* __PERF_TOP_H */ 34#endif /* __PERF_TOP_H */
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index 35729f4c40cb..d2655f08bcc0 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -80,7 +80,7 @@ static void die(const char *fmt, ...)
80 int ret = errno; 80 int ret = errno;
81 81
82 if (errno) 82 if (errno)
83 perror("trace-cmd"); 83 perror("perf");
84 else 84 else
85 ret = -1; 85 ret = -1;
86 86
@@ -183,106 +183,60 @@ int bigendian(void)
183 return *ptr == 0x01020304; 183 return *ptr == 0x01020304;
184} 184}
185 185
186static unsigned long long copy_file_fd(int fd) 186/* unfortunately, you can not stat debugfs or proc files for size */
187static void record_file(const char *file, size_t hdr_sz)
187{ 188{
188 unsigned long long size = 0; 189 unsigned long long size = 0;
189 char buf[BUFSIZ]; 190 char buf[BUFSIZ], *sizep;
190 int r; 191 off_t hdr_pos = lseek(output_fd, 0, SEEK_CUR);
191 192 int r, fd;
192 do {
193 r = read(fd, buf, BUFSIZ);
194 if (r > 0) {
195 size += r;
196 write_or_die(buf, r);
197 }
198 } while (r > 0);
199
200 return size;
201}
202
203static unsigned long long copy_file(const char *file)
204{
205 unsigned long long size = 0;
206 int fd;
207 193
208 fd = open(file, O_RDONLY); 194 fd = open(file, O_RDONLY);
209 if (fd < 0) 195 if (fd < 0)
210 die("Can't read '%s'", file); 196 die("Can't read '%s'", file);
211 size = copy_file_fd(fd);
212 close(fd);
213
214 return size;
215}
216 197
217static unsigned long get_size_fd(int fd) 198 /* put in zeros for file size, then fill true size later */
218{ 199 if (hdr_sz)
219 unsigned long long size = 0; 200 write_or_die(&size, hdr_sz);
220 char buf[BUFSIZ];
221 int r;
222 201
223 do { 202 do {
224 r = read(fd, buf, BUFSIZ); 203 r = read(fd, buf, BUFSIZ);
225 if (r > 0) 204 if (r > 0) {
226 size += r; 205 size += r;
206 write_or_die(buf, r);
207 }
227 } while (r > 0); 208 } while (r > 0);
228
229 lseek(fd, 0, SEEK_SET);
230
231 return size;
232}
233
234static unsigned long get_size(const char *file)
235{
236 unsigned long long size = 0;
237 int fd;
238
239 fd = open(file, O_RDONLY);
240 if (fd < 0)
241 die("Can't read '%s'", file);
242 size = get_size_fd(fd);
243 close(fd); 209 close(fd);
244 210
245 return size; 211 /* ugh, handle big-endian hdr_size == 4 */
212 sizep = (char*)&size;
213 if (bigendian())
214 sizep += sizeof(u64) - hdr_sz;
215
216 if (hdr_sz && pwrite(output_fd, sizep, hdr_sz, hdr_pos) < 0)
217 die("writing to %s", output_file);
246} 218}
247 219
248static void read_header_files(void) 220static void read_header_files(void)
249{ 221{
250 unsigned long long size, check_size;
251 char *path; 222 char *path;
252 int fd; 223 struct stat st;
253 224
254 path = get_tracing_file("events/header_page"); 225 path = get_tracing_file("events/header_page");
255 fd = open(path, O_RDONLY); 226 if (stat(path, &st) < 0)
256 if (fd < 0)
257 die("can't read '%s'", path); 227 die("can't read '%s'", path);
258 228
259 /* unfortunately, you can not stat debugfs files for size */
260 size = get_size_fd(fd);
261
262 write_or_die("header_page", 12); 229 write_or_die("header_page", 12);
263 write_or_die(&size, 8); 230 record_file(path, 8);
264 check_size = copy_file_fd(fd);
265 close(fd);
266
267 if (size != check_size)
268 die("wrong size for '%s' size=%lld read=%lld",
269 path, size, check_size);
270 put_tracing_file(path); 231 put_tracing_file(path);
271 232
272 path = get_tracing_file("events/header_event"); 233 path = get_tracing_file("events/header_event");
273 fd = open(path, O_RDONLY); 234 if (stat(path, &st) < 0)
274 if (fd < 0)
275 die("can't read '%s'", path); 235 die("can't read '%s'", path);
276 236
277 size = get_size_fd(fd);
278
279 write_or_die("header_event", 13); 237 write_or_die("header_event", 13);
280 write_or_die(&size, 8); 238 record_file(path, 8);
281 check_size = copy_file_fd(fd);
282 if (size != check_size)
283 die("wrong size for '%s'", path);
284 put_tracing_file(path); 239 put_tracing_file(path);
285 close(fd);
286} 240}
287 241
288static bool name_in_tp_list(char *sys, struct tracepoint_path *tps) 242static bool name_in_tp_list(char *sys, struct tracepoint_path *tps)
@@ -298,7 +252,6 @@ static bool name_in_tp_list(char *sys, struct tracepoint_path *tps)
298 252
299static void copy_event_system(const char *sys, struct tracepoint_path *tps) 253static void copy_event_system(const char *sys, struct tracepoint_path *tps)
300{ 254{
301 unsigned long long size, check_size;
302 struct dirent *dent; 255 struct dirent *dent;
303 struct stat st; 256 struct stat st;
304 char *format; 257 char *format;
@@ -338,14 +291,8 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps)
338 sprintf(format, "%s/%s/format", sys, dent->d_name); 291 sprintf(format, "%s/%s/format", sys, dent->d_name);
339 ret = stat(format, &st); 292 ret = stat(format, &st);
340 293
341 if (ret >= 0) { 294 if (ret >= 0)
342 /* unfortunately, you can not stat debugfs files for size */ 295 record_file(format, 8);
343 size = get_size(format);
344 write_or_die(&size, 8);
345 check_size = copy_file(format);
346 if (size != check_size)
347 die("error in size of file '%s'", format);
348 }
349 296
350 free(format); 297 free(format);
351 } 298 }
@@ -426,7 +373,7 @@ static void read_event_files(struct tracepoint_path *tps)
426 373
427static void read_proc_kallsyms(void) 374static void read_proc_kallsyms(void)
428{ 375{
429 unsigned int size, check_size; 376 unsigned int size;
430 const char *path = "/proc/kallsyms"; 377 const char *path = "/proc/kallsyms";
431 struct stat st; 378 struct stat st;
432 int ret; 379 int ret;
@@ -438,17 +385,12 @@ static void read_proc_kallsyms(void)
438 write_or_die(&size, 4); 385 write_or_die(&size, 4);
439 return; 386 return;
440 } 387 }
441 size = get_size(path); 388 record_file(path, 4);
442 write_or_die(&size, 4);
443 check_size = copy_file(path);
444 if (size != check_size)
445 die("error in size of file '%s'", path);
446
447} 389}
448 390
449static void read_ftrace_printk(void) 391static void read_ftrace_printk(void)
450{ 392{
451 unsigned int size, check_size; 393 unsigned int size;
452 char *path; 394 char *path;
453 struct stat st; 395 struct stat st;
454 int ret; 396 int ret;
@@ -461,11 +403,8 @@ static void read_ftrace_printk(void)
461 write_or_die(&size, 4); 403 write_or_die(&size, 4);
462 goto out; 404 goto out;
463 } 405 }
464 size = get_size(path); 406 record_file(path, 4);
465 write_or_die(&size, 4); 407
466 check_size = copy_file(path);
467 if (size != check_size)
468 die("error in size of file '%s'", path);
469out: 408out:
470 put_tracing_file(path); 409 put_tracing_file(path);
471} 410}
@@ -490,6 +429,19 @@ get_tracepoints_path(struct list_head *pattrs)
490 return nr_tracepoints > 0 ? path.next : NULL; 429 return nr_tracepoints > 0 ? path.next : NULL;
491} 430}
492 431
432static void
433put_tracepoints_path(struct tracepoint_path *tps)
434{
435 while (tps) {
436 struct tracepoint_path *t = tps;
437
438 tps = tps->next;
439 free(t->name);
440 free(t->system);
441 free(t);
442 }
443}
444
493bool have_tracepoints(struct list_head *pattrs) 445bool have_tracepoints(struct list_head *pattrs)
494{ 446{
495 struct perf_evsel *pos; 447 struct perf_evsel *pos;
@@ -501,19 +453,11 @@ bool have_tracepoints(struct list_head *pattrs)
501 return false; 453 return false;
502} 454}
503 455
504int read_tracing_data(int fd, struct list_head *pattrs) 456static void tracing_data_header(void)
505{ 457{
506 char buf[BUFSIZ]; 458 char buf[20];
507 struct tracepoint_path *tps = get_tracepoints_path(pattrs);
508
509 /*
510 * What? No tracepoints? No sense writing anything here, bail out.
511 */
512 if (tps == NULL)
513 return -1;
514
515 output_fd = fd;
516 459
460 /* just guessing this is someone's birthday.. ;) */
517 buf[0] = 23; 461 buf[0] = 23;
518 buf[1] = 8; 462 buf[1] = 8;
519 buf[2] = 68; 463 buf[2] = 68;
@@ -538,28 +482,86 @@ int read_tracing_data(int fd, struct list_head *pattrs)
538 /* save page_size */ 482 /* save page_size */
539 page_size = sysconf(_SC_PAGESIZE); 483 page_size = sysconf(_SC_PAGESIZE);
540 write_or_die(&page_size, 4); 484 write_or_die(&page_size, 4);
485}
486
487struct tracing_data *tracing_data_get(struct list_head *pattrs,
488 int fd, bool temp)
489{
490 struct tracepoint_path *tps;
491 struct tracing_data *tdata;
492
493 output_fd = fd;
541 494
495 tps = get_tracepoints_path(pattrs);
496 if (!tps)
497 return NULL;
498
499 tdata = malloc_or_die(sizeof(*tdata));
500 tdata->temp = temp;
501 tdata->size = 0;
502
503 if (temp) {
504 int temp_fd;
505
506 snprintf(tdata->temp_file, sizeof(tdata->temp_file),
507 "/tmp/perf-XXXXXX");
508 if (!mkstemp(tdata->temp_file))
509 die("Can't make temp file");
510
511 temp_fd = open(tdata->temp_file, O_RDWR);
512 if (temp_fd < 0)
513 die("Can't read '%s'", tdata->temp_file);
514
515 /*
516 * Set the temp file the default output, so all the
517 * tracing data are stored into it.
518 */
519 output_fd = temp_fd;
520 }
521
522 tracing_data_header();
542 read_header_files(); 523 read_header_files();
543 read_ftrace_files(tps); 524 read_ftrace_files(tps);
544 read_event_files(tps); 525 read_event_files(tps);
545 read_proc_kallsyms(); 526 read_proc_kallsyms();
546 read_ftrace_printk(); 527 read_ftrace_printk();
547 528
548 return 0; 529 /*
530 * All tracing data are stored by now, we can restore
531 * the default output file in case we used temp file.
532 */
533 if (temp) {
534 tdata->size = lseek(output_fd, 0, SEEK_CUR);
535 close(output_fd);
536 output_fd = fd;
537 }
538
539 put_tracepoints_path(tps);
540 return tdata;
549} 541}
550 542
551ssize_t read_tracing_data_size(int fd, struct list_head *pattrs) 543void tracing_data_put(struct tracing_data *tdata)
552{ 544{
553 ssize_t size; 545 if (tdata->temp) {
554 int err = 0; 546 record_file(tdata->temp_file, 0);
547 unlink(tdata->temp_file);
548 }
549
550 free(tdata);
551}
555 552
556 calc_data_size = 1; 553int read_tracing_data(int fd, struct list_head *pattrs)
557 err = read_tracing_data(fd, pattrs); 554{
558 size = calc_data_size - 1; 555 struct tracing_data *tdata;
559 calc_data_size = 0;
560 556
561 if (err < 0) 557 /*
562 return err; 558 * We work over the real file, so we can write data
559 * directly, no temp file is needed.
560 */
561 tdata = tracing_data_get(pattrs, fd, false);
562 if (!tdata)
563 return -ENOMEM;
563 564
564 return size; 565 tracing_data_put(tdata);
566 return 0;
565} 567}
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index f674dda3363b..a84100817649 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -263,7 +263,18 @@ void *raw_field_ptr(struct event *event, const char *name, void *data);
263unsigned long long eval_flag(const char *flag); 263unsigned long long eval_flag(const char *flag);
264 264
265int read_tracing_data(int fd, struct list_head *pattrs); 265int read_tracing_data(int fd, struct list_head *pattrs);
266ssize_t read_tracing_data_size(int fd, struct list_head *pattrs); 266
267struct tracing_data {
268 /* size is only valid if temp is 'true' */
269 ssize_t size;
270 bool temp;
271 char temp_file[50];
272};
273
274struct tracing_data *tracing_data_get(struct list_head *pattrs,
275 int fd, bool temp);
276void tracing_data_put(struct tracing_data *tdata);
277
267 278
268/* taken from kernel/trace/trace.h */ 279/* taken from kernel/trace/trace.h */
269enum trace_flag_type { 280enum trace_flag_type {
diff --git a/tools/perf/util/ui/browser.c b/tools/perf/util/ui/browser.c
index 611219f80680..556829124b02 100644
--- a/tools/perf/util/ui/browser.c
+++ b/tools/perf/util/ui/browser.c
@@ -1,5 +1,10 @@
1#include "../util.h"
2#include "../cache.h"
3#include "../../perf.h"
1#include "libslang.h" 4#include "libslang.h"
5#include <newt.h>
2#include "ui.h" 6#include "ui.h"
7#include "util.h"
3#include <linux/compiler.h> 8#include <linux/compiler.h>
4#include <linux/list.h> 9#include <linux/list.h>
5#include <linux/rbtree.h> 10#include <linux/rbtree.h>
@@ -7,13 +12,13 @@
7#include <sys/ttydefaults.h> 12#include <sys/ttydefaults.h>
8#include "browser.h" 13#include "browser.h"
9#include "helpline.h" 14#include "helpline.h"
15#include "keysyms.h"
10#include "../color.h" 16#include "../color.h"
11#include "../util.h"
12#include <stdio.h>
13 17
14static int ui_browser__percent_color(double percent, bool current) 18static int ui_browser__percent_color(struct ui_browser *browser,
19 double percent, bool current)
15{ 20{
16 if (current) 21 if (current && (!browser->use_navkeypressed || browser->navkeypressed))
17 return HE_COLORSET_SELECTED; 22 return HE_COLORSET_SELECTED;
18 if (percent >= MIN_RED) 23 if (percent >= MIN_RED)
19 return HE_COLORSET_TOP; 24 return HE_COLORSET_TOP;
@@ -30,7 +35,7 @@ void ui_browser__set_color(struct ui_browser *self __used, int color)
30void ui_browser__set_percent_color(struct ui_browser *self, 35void ui_browser__set_percent_color(struct ui_browser *self,
31 double percent, bool current) 36 double percent, bool current)
32{ 37{
33 int color = ui_browser__percent_color(percent, current); 38 int color = ui_browser__percent_color(self, percent, current);
34 ui_browser__set_color(self, color); 39 ui_browser__set_color(self, color);
35} 40}
36 41
@@ -39,31 +44,62 @@ void ui_browser__gotorc(struct ui_browser *self, int y, int x)
39 SLsmg_gotorc(self->y + y, self->x + x); 44 SLsmg_gotorc(self->y + y, self->x + x);
40} 45}
41 46
47static struct list_head *
48ui_browser__list_head_filter_entries(struct ui_browser *browser,
49 struct list_head *pos)
50{
51 do {
52 if (!browser->filter || !browser->filter(browser, pos))
53 return pos;
54 pos = pos->next;
55 } while (pos != browser->entries);
56
57 return NULL;
58}
59
60static struct list_head *
61ui_browser__list_head_filter_prev_entries(struct ui_browser *browser,
62 struct list_head *pos)
63{
64 do {
65 if (!browser->filter || !browser->filter(browser, pos))
66 return pos;
67 pos = pos->prev;
68 } while (pos != browser->entries);
69
70 return NULL;
71}
72
42void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence) 73void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence)
43{ 74{
44 struct list_head *head = self->entries; 75 struct list_head *head = self->entries;
45 struct list_head *pos; 76 struct list_head *pos;
46 77
78 if (self->nr_entries == 0)
79 return;
80
47 switch (whence) { 81 switch (whence) {
48 case SEEK_SET: 82 case SEEK_SET:
49 pos = head->next; 83 pos = ui_browser__list_head_filter_entries(self, head->next);
50 break; 84 break;
51 case SEEK_CUR: 85 case SEEK_CUR:
52 pos = self->top; 86 pos = self->top;
53 break; 87 break;
54 case SEEK_END: 88 case SEEK_END:
55 pos = head->prev; 89 pos = ui_browser__list_head_filter_prev_entries(self, head->prev);
56 break; 90 break;
57 default: 91 default:
58 return; 92 return;
59 } 93 }
60 94
95 assert(pos != NULL);
96
61 if (offset > 0) { 97 if (offset > 0) {
62 while (offset-- != 0) 98 while (offset-- != 0)
63 pos = pos->next; 99 pos = ui_browser__list_head_filter_entries(self, pos->next);
64 } else { 100 } else {
65 while (offset++ != 0) 101 while (offset++ != 0)
66 pos = pos->prev; 102 pos = ui_browser__list_head_filter_prev_entries(self, pos->prev);
67 } 103 }
68 104
69 self->top = pos; 105 self->top = pos;
@@ -127,41 +163,76 @@ bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row)
127 163
128void ui_browser__refresh_dimensions(struct ui_browser *self) 164void ui_browser__refresh_dimensions(struct ui_browser *self)
129{ 165{
130 int cols, rows; 166 self->width = SLtt_Screen_Cols - 1;
131 newtGetScreenSize(&cols, &rows); 167 self->height = SLtt_Screen_Rows - 2;
132
133 self->width = cols - 1;
134 self->height = rows - 2;
135 self->y = 1; 168 self->y = 1;
136 self->x = 0; 169 self->x = 0;
137} 170}
138 171
139void ui_browser__reset_index(struct ui_browser *self) 172void ui_browser__handle_resize(struct ui_browser *browser)
140{ 173{
141 self->index = self->top_idx = 0; 174 ui__refresh_dimensions(false);
142 self->seek(self, 0, SEEK_SET); 175 ui_browser__show(browser, browser->title, ui_helpline__current);
176 ui_browser__refresh(browser);
143} 177}
144 178
145void ui_browser__add_exit_key(struct ui_browser *self, int key) 179int ui_browser__warning(struct ui_browser *browser, int timeout,
180 const char *format, ...)
146{ 181{
147 newtFormAddHotKey(self->form, key); 182 va_list args;
183 char *text;
184 int key = 0, err;
185
186 va_start(args, format);
187 err = vasprintf(&text, format, args);
188 va_end(args);
189
190 if (err < 0) {
191 va_start(args, format);
192 ui_helpline__vpush(format, args);
193 va_end(args);
194 } else {
195 while ((key == ui__question_window("Warning!", text,
196 "Press any key...",
197 timeout)) == K_RESIZE)
198 ui_browser__handle_resize(browser);
199 free(text);
200 }
201
202 return key;
148} 203}
149 204
150void ui_browser__add_exit_keys(struct ui_browser *self, int keys[]) 205int ui_browser__help_window(struct ui_browser *browser, const char *text)
151{ 206{
152 int i = 0; 207 int key;
153 208
154 while (keys[i] && i < 64) { 209 while ((key = ui__help_window(text)) == K_RESIZE)
155 ui_browser__add_exit_key(self, keys[i]); 210 ui_browser__handle_resize(browser);
156 ++i; 211
157 } 212 return key;
213}
214
215bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text)
216{
217 int key;
218
219 while ((key = ui__dialog_yesno(text)) == K_RESIZE)
220 ui_browser__handle_resize(browser);
221
222 return key == K_ENTER || toupper(key) == 'Y';
223}
224
225void ui_browser__reset_index(struct ui_browser *self)
226{
227 self->index = self->top_idx = 0;
228 self->seek(self, 0, SEEK_SET);
158} 229}
159 230
160void __ui_browser__show_title(struct ui_browser *browser, const char *title) 231void __ui_browser__show_title(struct ui_browser *browser, const char *title)
161{ 232{
162 SLsmg_gotorc(0, 0); 233 SLsmg_gotorc(0, 0);
163 ui_browser__set_color(browser, NEWT_COLORSET_ROOT); 234 ui_browser__set_color(browser, NEWT_COLORSET_ROOT);
164 slsmg_write_nstring(title, browser->width); 235 slsmg_write_nstring(title, browser->width + 1);
165} 236}
166 237
167void ui_browser__show_title(struct ui_browser *browser, const char *title) 238void ui_browser__show_title(struct ui_browser *browser, const char *title)
@@ -174,78 +245,145 @@ void ui_browser__show_title(struct ui_browser *browser, const char *title)
174int ui_browser__show(struct ui_browser *self, const char *title, 245int ui_browser__show(struct ui_browser *self, const char *title,
175 const char *helpline, ...) 246 const char *helpline, ...)
176{ 247{
248 int err;
177 va_list ap; 249 va_list ap;
178 int keys[] = { NEWT_KEY_UP, NEWT_KEY_DOWN, NEWT_KEY_PGUP,
179 NEWT_KEY_PGDN, NEWT_KEY_HOME, NEWT_KEY_END, ' ',
180 NEWT_KEY_LEFT, NEWT_KEY_ESCAPE, 'q', CTRL('c'), 0 };
181
182 if (self->form != NULL)
183 newtFormDestroy(self->form);
184 250
185 ui_browser__refresh_dimensions(self); 251 ui_browser__refresh_dimensions(self);
186 self->form = newtForm(NULL, NULL, 0);
187 if (self->form == NULL)
188 return -1;
189
190 self->sb = newtVerticalScrollbar(self->width, 1, self->height,
191 HE_COLORSET_NORMAL,
192 HE_COLORSET_SELECTED);
193 if (self->sb == NULL)
194 return -1;
195 252
196 pthread_mutex_lock(&ui__lock); 253 pthread_mutex_lock(&ui__lock);
197 __ui_browser__show_title(self, title); 254 __ui_browser__show_title(self, title);
198 255
199 ui_browser__add_exit_keys(self, keys); 256 self->title = title;
200 newtFormAddComponent(self->form, self->sb); 257 free(self->helpline);
258 self->helpline = NULL;
201 259
202 va_start(ap, helpline); 260 va_start(ap, helpline);
203 ui_helpline__vpush(helpline, ap); 261 err = vasprintf(&self->helpline, helpline, ap);
204 va_end(ap); 262 va_end(ap);
263 if (err > 0)
264 ui_helpline__push(self->helpline);
205 pthread_mutex_unlock(&ui__lock); 265 pthread_mutex_unlock(&ui__lock);
206 return 0; 266 return err ? 0 : -1;
207} 267}
208 268
209void ui_browser__hide(struct ui_browser *self) 269void ui_browser__hide(struct ui_browser *browser __used)
210{ 270{
211 pthread_mutex_lock(&ui__lock); 271 pthread_mutex_lock(&ui__lock);
212 newtFormDestroy(self->form);
213 self->form = NULL;
214 ui_helpline__pop(); 272 ui_helpline__pop();
215 pthread_mutex_unlock(&ui__lock); 273 pthread_mutex_unlock(&ui__lock);
216} 274}
217 275
218int ui_browser__refresh(struct ui_browser *self) 276static void ui_browser__scrollbar_set(struct ui_browser *browser)
277{
278 int height = browser->height, h = 0, pct = 0,
279 col = browser->width,
280 row = browser->y - 1;
281
282 if (browser->nr_entries > 1) {
283 pct = ((browser->index * (browser->height - 1)) /
284 (browser->nr_entries - 1));
285 }
286
287 SLsmg_set_char_set(1);
288
289 while (h < height) {
290 ui_browser__gotorc(browser, row++, col);
291 SLsmg_write_char(h == pct ? SLSMG_DIAMOND_CHAR : SLSMG_CKBRD_CHAR);
292 ++h;
293 }
294
295 SLsmg_set_char_set(0);
296}
297
298static int __ui_browser__refresh(struct ui_browser *browser)
219{ 299{
220 int row; 300 int row;
301 int width = browser->width;
302
303 row = browser->refresh(browser);
304 ui_browser__set_color(browser, HE_COLORSET_NORMAL);
305
306 if (!browser->use_navkeypressed || browser->navkeypressed)
307 ui_browser__scrollbar_set(browser);
308 else
309 width += 1;
310
311 SLsmg_fill_region(browser->y + row, browser->x,
312 browser->height - row, width, ' ');
313
314 return 0;
315}
221 316
317int ui_browser__refresh(struct ui_browser *browser)
318{
222 pthread_mutex_lock(&ui__lock); 319 pthread_mutex_lock(&ui__lock);
223 newtScrollbarSet(self->sb, self->index, self->nr_entries - 1); 320 __ui_browser__refresh(browser);
224 row = self->refresh(self);
225 ui_browser__set_color(self, HE_COLORSET_NORMAL);
226 SLsmg_fill_region(self->y + row, self->x,
227 self->height - row, self->width, ' ');
228 pthread_mutex_unlock(&ui__lock); 321 pthread_mutex_unlock(&ui__lock);
229 322
230 return 0; 323 return 0;
231} 324}
232 325
233int ui_browser__run(struct ui_browser *self) 326/*
327 * Here we're updating nr_entries _after_ we started browsing, i.e. we have to
328 * forget about any reference to any entry in the underlying data structure,
329 * that is why we do a SEEK_SET. Think about 'perf top' in the hists browser
330 * after an output_resort and hist decay.
331 */
332void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries)
234{ 333{
235 struct newtExitStruct es; 334 off_t offset = nr_entries - browser->nr_entries;
335
336 browser->nr_entries = nr_entries;
236 337
237 if (ui_browser__refresh(self) < 0) 338 if (offset < 0) {
238 return -1; 339 if (browser->top_idx < (u64)-offset)
340 offset = -browser->top_idx;
341
342 browser->index += offset;
343 browser->top_idx += offset;
344 }
345
346 browser->top = NULL;
347 browser->seek(browser, browser->top_idx, SEEK_SET);
348}
349
350int ui_browser__run(struct ui_browser *self, int delay_secs)
351{
352 int err, key;
239 353
240 while (1) { 354 while (1) {
241 off_t offset; 355 off_t offset;
242 356
243 newtFormRun(self->form, &es); 357 pthread_mutex_lock(&ui__lock);
244 358 err = __ui_browser__refresh(self);
245 if (es.reason != NEWT_EXIT_HOTKEY) 359 SLsmg_refresh();
360 pthread_mutex_unlock(&ui__lock);
361 if (err < 0)
246 break; 362 break;
247 switch (es.u.key) { 363
248 case NEWT_KEY_DOWN: 364 key = ui__getch(delay_secs);
365
366 if (key == K_RESIZE) {
367 ui__refresh_dimensions(false);
368 ui_browser__refresh_dimensions(self);
369 __ui_browser__show_title(self, self->title);
370 ui_helpline__puts(self->helpline);
371 continue;
372 }
373
374 if (self->use_navkeypressed && !self->navkeypressed) {
375 if (key == K_DOWN || key == K_UP ||
376 key == K_PGDN || key == K_PGUP ||
377 key == K_HOME || key == K_END ||
378 key == ' ') {
379 self->navkeypressed = true;
380 continue;
381 } else
382 return key;
383 }
384
385 switch (key) {
386 case K_DOWN:
249 if (self->index == self->nr_entries - 1) 387 if (self->index == self->nr_entries - 1)
250 break; 388 break;
251 ++self->index; 389 ++self->index;
@@ -254,7 +392,7 @@ int ui_browser__run(struct ui_browser *self)
254 self->seek(self, +1, SEEK_CUR); 392 self->seek(self, +1, SEEK_CUR);
255 } 393 }
256 break; 394 break;
257 case NEWT_KEY_UP: 395 case K_UP:
258 if (self->index == 0) 396 if (self->index == 0)
259 break; 397 break;
260 --self->index; 398 --self->index;
@@ -263,7 +401,7 @@ int ui_browser__run(struct ui_browser *self)
263 self->seek(self, -1, SEEK_CUR); 401 self->seek(self, -1, SEEK_CUR);
264 } 402 }
265 break; 403 break;
266 case NEWT_KEY_PGDN: 404 case K_PGDN:
267 case ' ': 405 case ' ':
268 if (self->top_idx + self->height > self->nr_entries - 1) 406 if (self->top_idx + self->height > self->nr_entries - 1)
269 break; 407 break;
@@ -275,7 +413,7 @@ int ui_browser__run(struct ui_browser *self)
275 self->top_idx += offset; 413 self->top_idx += offset;
276 self->seek(self, +offset, SEEK_CUR); 414 self->seek(self, +offset, SEEK_CUR);
277 break; 415 break;
278 case NEWT_KEY_PGUP: 416 case K_PGUP:
279 if (self->top_idx == 0) 417 if (self->top_idx == 0)
280 break; 418 break;
281 419
@@ -288,10 +426,10 @@ int ui_browser__run(struct ui_browser *self)
288 self->top_idx -= offset; 426 self->top_idx -= offset;
289 self->seek(self, -offset, SEEK_CUR); 427 self->seek(self, -offset, SEEK_CUR);
290 break; 428 break;
291 case NEWT_KEY_HOME: 429 case K_HOME:
292 ui_browser__reset_index(self); 430 ui_browser__reset_index(self);
293 break; 431 break;
294 case NEWT_KEY_END: 432 case K_END:
295 offset = self->height - 1; 433 offset = self->height - 1;
296 if (offset >= self->nr_entries) 434 if (offset >= self->nr_entries)
297 offset = self->nr_entries - 1; 435 offset = self->nr_entries - 1;
@@ -301,10 +439,8 @@ int ui_browser__run(struct ui_browser *self)
301 self->seek(self, -offset, SEEK_END); 439 self->seek(self, -offset, SEEK_END);
302 break; 440 break;
303 default: 441 default:
304 return es.u.key; 442 return key;
305 } 443 }
306 if (ui_browser__refresh(self) < 0)
307 return -1;
308 } 444 }
309 return -1; 445 return -1;
310} 446}
@@ -316,41 +452,146 @@ unsigned int ui_browser__list_head_refresh(struct ui_browser *self)
316 int row = 0; 452 int row = 0;
317 453
318 if (self->top == NULL || self->top == self->entries) 454 if (self->top == NULL || self->top == self->entries)
319 self->top = head->next; 455 self->top = ui_browser__list_head_filter_entries(self, head->next);
320 456
321 pos = self->top; 457 pos = self->top;
322 458
323 list_for_each_from(pos, head) { 459 list_for_each_from(pos, head) {
324 ui_browser__gotorc(self, row, 0); 460 if (!self->filter || !self->filter(self, pos)) {
325 self->write(self, pos, row); 461 ui_browser__gotorc(self, row, 0);
326 if (++row == self->height) 462 self->write(self, pos, row);
327 break; 463 if (++row == self->height)
464 break;
465 }
328 } 466 }
329 467
330 return row; 468 return row;
331} 469}
332 470
333static struct newtPercentTreeColors { 471static struct ui_browser__colorset {
334 const char *topColorFg, *topColorBg; 472 const char *name, *fg, *bg;
335 const char *mediumColorFg, *mediumColorBg; 473 int colorset;
336 const char *normalColorFg, *normalColorBg; 474} ui_browser__colorsets[] = {
337 const char *selColorFg, *selColorBg; 475 {
338 const char *codeColorFg, *codeColorBg; 476 .colorset = HE_COLORSET_TOP,
339} defaultPercentTreeColors = { 477 .name = "top",
340 "red", "lightgray", 478 .fg = "red",
341 "green", "lightgray", 479 .bg = "default",
342 "black", "lightgray", 480 },
343 "lightgray", "magenta", 481 {
344 "blue", "lightgray", 482 .colorset = HE_COLORSET_MEDIUM,
483 .name = "medium",
484 .fg = "green",
485 .bg = "default",
486 },
487 {
488 .colorset = HE_COLORSET_NORMAL,
489 .name = "normal",
490 .fg = "default",
491 .bg = "default",
492 },
493 {
494 .colorset = HE_COLORSET_SELECTED,
495 .name = "selected",
496 .fg = "black",
497 .bg = "lightgray",
498 },
499 {
500 .colorset = HE_COLORSET_CODE,
501 .name = "code",
502 .fg = "blue",
503 .bg = "default",
504 },
505 {
506 .name = NULL,
507 }
345}; 508};
346 509
510
511static int ui_browser__color_config(const char *var, const char *value,
512 void *data __used)
513{
514 char *fg = NULL, *bg;
515 int i;
516
517 /* same dir for all commands */
518 if (prefixcmp(var, "colors.") != 0)
519 return 0;
520
521 for (i = 0; ui_browser__colorsets[i].name != NULL; ++i) {
522 const char *name = var + 7;
523
524 if (strcmp(ui_browser__colorsets[i].name, name) != 0)
525 continue;
526
527 fg = strdup(value);
528 if (fg == NULL)
529 break;
530
531 bg = strchr(fg, ',');
532 if (bg == NULL)
533 break;
534
535 *bg = '\0';
536 while (isspace(*++bg));
537 ui_browser__colorsets[i].bg = bg;
538 ui_browser__colorsets[i].fg = fg;
539 return 0;
540 }
541
542 free(fg);
543 return -1;
544}
545
546void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence)
547{
548 switch (whence) {
549 case SEEK_SET:
550 browser->top = browser->entries;
551 break;
552 case SEEK_CUR:
553 browser->top = browser->top + browser->top_idx + offset;
554 break;
555 case SEEK_END:
556 browser->top = browser->top + browser->nr_entries + offset;
557 break;
558 default:
559 return;
560 }
561}
562
563unsigned int ui_browser__argv_refresh(struct ui_browser *browser)
564{
565 unsigned int row = 0, idx = browser->top_idx;
566 char **pos;
567
568 if (browser->top == NULL)
569 browser->top = browser->entries;
570
571 pos = (char **)browser->top;
572 while (idx < browser->nr_entries) {
573 if (!browser->filter || !browser->filter(browser, *pos)) {
574 ui_browser__gotorc(browser, row, 0);
575 browser->write(browser, pos, row);
576 if (++row == browser->height)
577 break;
578 }
579
580 ++idx;
581 ++pos;
582 }
583
584 return row;
585}
586
347void ui_browser__init(void) 587void ui_browser__init(void)
348{ 588{
349 struct newtPercentTreeColors *c = &defaultPercentTreeColors; 589 int i = 0;
590
591 perf_config(ui_browser__color_config, NULL);
350 592
351 sltt_set_color(HE_COLORSET_TOP, NULL, c->topColorFg, c->topColorBg); 593 while (ui_browser__colorsets[i].name) {
352 sltt_set_color(HE_COLORSET_MEDIUM, NULL, c->mediumColorFg, c->mediumColorBg); 594 struct ui_browser__colorset *c = &ui_browser__colorsets[i++];
353 sltt_set_color(HE_COLORSET_NORMAL, NULL, c->normalColorFg, c->normalColorBg); 595 sltt_set_color(c->colorset, c->name, c->fg, c->bg);
354 sltt_set_color(HE_COLORSET_SELECTED, NULL, c->selColorFg, c->selColorBg); 596 }
355 sltt_set_color(HE_COLORSET_CODE, NULL, c->codeColorFg, c->codeColorBg);
356} 597}
diff --git a/tools/perf/util/ui/browser.h b/tools/perf/util/ui/browser.h
index fc63dda10910..84d761b730c1 100644
--- a/tools/perf/util/ui/browser.h
+++ b/tools/perf/util/ui/browser.h
@@ -2,7 +2,6 @@
2#define _PERF_UI_BROWSER_H_ 1 2#define _PERF_UI_BROWSER_H_ 1
3 3
4#include <stdbool.h> 4#include <stdbool.h>
5#include <newt.h>
6#include <sys/types.h> 5#include <sys/types.h>
7#include "../types.h" 6#include "../types.h"
8 7
@@ -13,15 +12,19 @@
13#define HE_COLORSET_CODE 54 12#define HE_COLORSET_CODE 54
14 13
15struct ui_browser { 14struct ui_browser {
16 newtComponent form, sb;
17 u64 index, top_idx; 15 u64 index, top_idx;
18 void *top, *entries; 16 void *top, *entries;
19 u16 y, x, width, height; 17 u16 y, x, width, height;
20 void *priv; 18 void *priv;
19 const char *title;
20 char *helpline;
21 unsigned int (*refresh)(struct ui_browser *self); 21 unsigned int (*refresh)(struct ui_browser *self);
22 void (*write)(struct ui_browser *self, void *entry, int row); 22 void (*write)(struct ui_browser *self, void *entry, int row);
23 void (*seek)(struct ui_browser *self, off_t offset, int whence); 23 void (*seek)(struct ui_browser *self, off_t offset, int whence);
24 bool (*filter)(struct ui_browser *self, void *entry);
24 u32 nr_entries; 25 u32 nr_entries;
26 bool navkeypressed;
27 bool use_navkeypressed;
25}; 28};
26 29
27void ui_browser__set_color(struct ui_browser *self, int color); 30void ui_browser__set_color(struct ui_browser *self, int color);
@@ -32,15 +35,23 @@ void ui_browser__refresh_dimensions(struct ui_browser *self);
32void ui_browser__reset_index(struct ui_browser *self); 35void ui_browser__reset_index(struct ui_browser *self);
33 36
34void ui_browser__gotorc(struct ui_browser *self, int y, int x); 37void ui_browser__gotorc(struct ui_browser *self, int y, int x);
35void ui_browser__add_exit_key(struct ui_browser *self, int key);
36void ui_browser__add_exit_keys(struct ui_browser *self, int keys[]);
37void __ui_browser__show_title(struct ui_browser *browser, const char *title); 38void __ui_browser__show_title(struct ui_browser *browser, const char *title);
38void ui_browser__show_title(struct ui_browser *browser, const char *title); 39void ui_browser__show_title(struct ui_browser *browser, const char *title);
39int ui_browser__show(struct ui_browser *self, const char *title, 40int ui_browser__show(struct ui_browser *self, const char *title,
40 const char *helpline, ...); 41 const char *helpline, ...);
41void ui_browser__hide(struct ui_browser *self); 42void ui_browser__hide(struct ui_browser *self);
42int ui_browser__refresh(struct ui_browser *self); 43int ui_browser__refresh(struct ui_browser *self);
43int ui_browser__run(struct ui_browser *self); 44int ui_browser__run(struct ui_browser *browser, int delay_secs);
45void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries);
46void ui_browser__handle_resize(struct ui_browser *browser);
47
48int ui_browser__warning(struct ui_browser *browser, int timeout,
49 const char *format, ...);
50int ui_browser__help_window(struct ui_browser *browser, const char *text);
51bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text);
52
53void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence);
54unsigned int ui_browser__argv_refresh(struct ui_browser *browser);
44 55
45void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence); 56void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence);
46unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self); 57unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self);
diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c
index 0229723aceb3..0575905d1205 100644
--- a/tools/perf/util/ui/browsers/annotate.c
+++ b/tools/perf/util/ui/browsers/annotate.c
@@ -1,31 +1,31 @@
1#include "../../util.h"
1#include "../browser.h" 2#include "../browser.h"
2#include "../helpline.h" 3#include "../helpline.h"
3#include "../libslang.h" 4#include "../libslang.h"
5#include "../ui.h"
6#include "../util.h"
4#include "../../annotate.h" 7#include "../../annotate.h"
5#include "../../hist.h" 8#include "../../hist.h"
6#include "../../sort.h" 9#include "../../sort.h"
7#include "../../symbol.h" 10#include "../../symbol.h"
8#include <pthread.h> 11#include <pthread.h>
9 12#include <newt.h>
10static void ui__error_window(const char *fmt, ...)
11{
12 va_list ap;
13
14 va_start(ap, fmt);
15 newtWinMessagev((char *)"Error", (char *)"Ok", (char *)fmt, ap);
16 va_end(ap);
17}
18 13
19struct annotate_browser { 14struct annotate_browser {
20 struct ui_browser b; 15 struct ui_browser b;
21 struct rb_root entries; 16 struct rb_root entries;
22 struct rb_node *curr_hot; 17 struct rb_node *curr_hot;
18 struct objdump_line *selection;
19 int nr_asm_entries;
20 int nr_entries;
21 bool hide_src_code;
23}; 22};
24 23
25struct objdump_line_rb_node { 24struct objdump_line_rb_node {
26 struct rb_node rb_node; 25 struct rb_node rb_node;
27 double percent; 26 double percent;
28 u32 idx; 27 u32 idx;
28 int idx_asm;
29}; 29};
30 30
31static inline 31static inline
@@ -34,9 +34,22 @@ struct objdump_line_rb_node *objdump_line__rb(struct objdump_line *self)
34 return (struct objdump_line_rb_node *)(self + 1); 34 return (struct objdump_line_rb_node *)(self + 1);
35} 35}
36 36
37static bool objdump_line__filter(struct ui_browser *browser, void *entry)
38{
39 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
40
41 if (ab->hide_src_code) {
42 struct objdump_line *ol = list_entry(entry, struct objdump_line, node);
43 return ol->offset == -1;
44 }
45
46 return false;
47}
48
37static void annotate_browser__write(struct ui_browser *self, void *entry, int row) 49static void annotate_browser__write(struct ui_browser *self, void *entry, int row)
38{ 50{
39 struct objdump_line *ol = rb_entry(entry, struct objdump_line, node); 51 struct annotate_browser *ab = container_of(self, struct annotate_browser, b);
52 struct objdump_line *ol = list_entry(entry, struct objdump_line, node);
40 bool current_entry = ui_browser__is_current_entry(self, row); 53 bool current_entry = ui_browser__is_current_entry(self, row);
41 int width = self->width; 54 int width = self->width;
42 55
@@ -51,6 +64,11 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro
51 64
52 SLsmg_write_char(':'); 65 SLsmg_write_char(':');
53 slsmg_write_nstring(" ", 8); 66 slsmg_write_nstring(" ", 8);
67
68 /* The scroll bar isn't being used */
69 if (!self->navkeypressed)
70 width += 1;
71
54 if (!*ol->line) 72 if (!*ol->line)
55 slsmg_write_nstring(" ", width - 18); 73 slsmg_write_nstring(" ", width - 18);
56 else 74 else
@@ -58,6 +76,8 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro
58 76
59 if (!current_entry) 77 if (!current_entry)
60 ui_browser__set_color(self, HE_COLORSET_CODE); 78 ui_browser__set_color(self, HE_COLORSET_CODE);
79 else
80 ab->selection = ol;
61} 81}
62 82
63static double objdump_line__calc_percent(struct objdump_line *self, 83static double objdump_line__calc_percent(struct objdump_line *self,
@@ -141,7 +161,8 @@ static void annotate_browser__set_top(struct annotate_browser *self,
141static void annotate_browser__calc_percent(struct annotate_browser *browser, 161static void annotate_browser__calc_percent(struct annotate_browser *browser,
142 int evidx) 162 int evidx)
143{ 163{
144 struct symbol *sym = browser->b.priv; 164 struct map_symbol *ms = browser->b.priv;
165 struct symbol *sym = ms->sym;
145 struct annotation *notes = symbol__annotation(sym); 166 struct annotation *notes = symbol__annotation(sym);
146 struct objdump_line *pos; 167 struct objdump_line *pos;
147 168
@@ -163,25 +184,60 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser,
163 browser->curr_hot = rb_last(&browser->entries); 184 browser->curr_hot = rb_last(&browser->entries);
164} 185}
165 186
187static bool annotate_browser__toggle_source(struct annotate_browser *browser)
188{
189 struct objdump_line *ol;
190 struct objdump_line_rb_node *olrb;
191 off_t offset = browser->b.index - browser->b.top_idx;
192
193 browser->b.seek(&browser->b, offset, SEEK_CUR);
194 ol = list_entry(browser->b.top, struct objdump_line, node);
195 olrb = objdump_line__rb(ol);
196
197 if (browser->hide_src_code) {
198 if (olrb->idx_asm < offset)
199 offset = olrb->idx;
200
201 browser->b.nr_entries = browser->nr_entries;
202 browser->hide_src_code = false;
203 browser->b.seek(&browser->b, -offset, SEEK_CUR);
204 browser->b.top_idx = olrb->idx - offset;
205 browser->b.index = olrb->idx;
206 } else {
207 if (olrb->idx_asm < 0) {
208 ui_helpline__puts("Only available for assembly lines.");
209 browser->b.seek(&browser->b, -offset, SEEK_CUR);
210 return false;
211 }
212
213 if (olrb->idx_asm < offset)
214 offset = olrb->idx_asm;
215
216 browser->b.nr_entries = browser->nr_asm_entries;
217 browser->hide_src_code = true;
218 browser->b.seek(&browser->b, -offset, SEEK_CUR);
219 browser->b.top_idx = olrb->idx_asm - offset;
220 browser->b.index = olrb->idx_asm;
221 }
222
223 return true;
224}
225
166static int annotate_browser__run(struct annotate_browser *self, int evidx, 226static int annotate_browser__run(struct annotate_browser *self, int evidx,
167 int refresh) 227 int nr_events, void(*timer)(void *arg),
228 void *arg, int delay_secs)
168{ 229{
169 struct rb_node *nd = NULL; 230 struct rb_node *nd = NULL;
170 struct symbol *sym = self->b.priv; 231 struct map_symbol *ms = self->b.priv;
171 /* 232 struct symbol *sym = ms->sym;
172 * RIGHT To allow builtin-annotate to cycle thru multiple symbols by 233 const char *help = "<-, ESC: exit, TAB/shift+TAB: cycle hottest lines, "
173 * examining the exit key for this function. 234 "H: Hottest, -> Line action, S -> Toggle source "
174 */ 235 "code view";
175 int exit_keys[] = { 'H', NEWT_KEY_TAB, NEWT_KEY_UNTAB,
176 NEWT_KEY_RIGHT, 0 };
177 int key; 236 int key;
178 237
179 if (ui_browser__show(&self->b, sym->name, 238 if (ui_browser__show(&self->b, sym->name, help) < 0)
180 "<-, -> or ESC: exit, TAB/shift+TAB: "
181 "cycle hottest lines, H: Hottest") < 0)
182 return -1; 239 return -1;
183 240
184 ui_browser__add_exit_keys(&self->b, exit_keys);
185 annotate_browser__calc_percent(self, evidx); 241 annotate_browser__calc_percent(self, evidx);
186 242
187 if (self->curr_hot) 243 if (self->curr_hot)
@@ -189,13 +245,10 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
189 245
190 nd = self->curr_hot; 246 nd = self->curr_hot;
191 247
192 if (refresh != 0)
193 newtFormSetTimer(self->b.form, refresh);
194
195 while (1) { 248 while (1) {
196 key = ui_browser__run(&self->b); 249 key = ui_browser__run(&self->b, delay_secs);
197 250
198 if (refresh != 0) { 251 if (delay_secs != 0) {
199 annotate_browser__calc_percent(self, evidx); 252 annotate_browser__calc_percent(self, evidx);
200 /* 253 /*
201 * Current line focus got out of the list of most active 254 * Current line focus got out of the list of most active
@@ -207,15 +260,14 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
207 } 260 }
208 261
209 switch (key) { 262 switch (key) {
210 case -1: 263 case K_TIMER:
211 /* 264 if (timer != NULL)
212 * FIXME we need to check if it was 265 timer(arg);
213 * es.reason == NEWT_EXIT_TIMER 266
214 */ 267 if (delay_secs != 0)
215 if (refresh != 0)
216 symbol__annotate_decay_histogram(sym, evidx); 268 symbol__annotate_decay_histogram(sym, evidx);
217 continue; 269 continue;
218 case NEWT_KEY_TAB: 270 case K_TAB:
219 if (nd != NULL) { 271 if (nd != NULL) {
220 nd = rb_prev(nd); 272 nd = rb_prev(nd);
221 if (nd == NULL) 273 if (nd == NULL)
@@ -223,7 +275,7 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
223 } else 275 } else
224 nd = self->curr_hot; 276 nd = self->curr_hot;
225 break; 277 break;
226 case NEWT_KEY_UNTAB: 278 case K_UNTAB:
227 if (nd != NULL) 279 if (nd != NULL)
228 nd = rb_next(nd); 280 nd = rb_next(nd);
229 if (nd == NULL) 281 if (nd == NULL)
@@ -234,8 +286,68 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
234 case 'H': 286 case 'H':
235 nd = self->curr_hot; 287 nd = self->curr_hot;
236 break; 288 break;
237 default: 289 case 'S':
290 if (annotate_browser__toggle_source(self))
291 ui_helpline__puts(help);
292 continue;
293 case K_ENTER:
294 case K_RIGHT:
295 if (self->selection == NULL) {
296 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
297 continue;
298 }
299
300 if (self->selection->offset == -1) {
301 ui_helpline__puts("Actions are only available for assembly lines.");
302 continue;
303 } else {
304 char *s = strstr(self->selection->line, "callq ");
305 struct annotation *notes;
306 struct symbol *target;
307 u64 ip;
308
309 if (s == NULL) {
310 ui_helpline__puts("Actions are only available for the 'callq' instruction.");
311 continue;
312 }
313
314 s = strchr(s, ' ');
315 if (s++ == NULL) {
316 ui_helpline__puts("Invallid callq instruction.");
317 continue;
318 }
319
320 ip = strtoull(s, NULL, 16);
321 ip = ms->map->map_ip(ms->map, ip);
322 target = map__find_symbol(ms->map, ip, NULL);
323 if (target == NULL) {
324 ui_helpline__puts("The called function was not found.");
325 continue;
326 }
327
328 notes = symbol__annotation(target);
329 pthread_mutex_lock(&notes->lock);
330
331 if (notes->src == NULL &&
332 symbol__alloc_hist(target, nr_events) < 0) {
333 pthread_mutex_unlock(&notes->lock);
334 ui__warning("Not enough memory for annotating '%s' symbol!\n",
335 target->name);
336 continue;
337 }
338
339 pthread_mutex_unlock(&notes->lock);
340 symbol__tui_annotate(target, ms->map, evidx, nr_events,
341 timer, arg, delay_secs);
342 }
343 continue;
344 case K_LEFT:
345 case K_ESC:
346 case 'q':
347 case CTRL('c'):
238 goto out; 348 goto out;
349 default:
350 continue;
239 } 351 }
240 352
241 if (nd != NULL) 353 if (nd != NULL)
@@ -246,22 +358,31 @@ out:
246 return key; 358 return key;
247} 359}
248 360
249int hist_entry__tui_annotate(struct hist_entry *he, int evidx) 361int hist_entry__tui_annotate(struct hist_entry *he, int evidx, int nr_events,
362 void(*timer)(void *arg), void *arg, int delay_secs)
250{ 363{
251 return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, 0); 364 return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, nr_events,
365 timer, arg, delay_secs);
252} 366}
253 367
254int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, 368int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
255 int refresh) 369 int nr_events, void(*timer)(void *arg), void *arg,
370 int delay_secs)
256{ 371{
257 struct objdump_line *pos, *n; 372 struct objdump_line *pos, *n;
258 struct annotation *notes; 373 struct annotation *notes;
374 struct map_symbol ms = {
375 .map = map,
376 .sym = sym,
377 };
259 struct annotate_browser browser = { 378 struct annotate_browser browser = {
260 .b = { 379 .b = {
261 .refresh = ui_browser__list_head_refresh, 380 .refresh = ui_browser__list_head_refresh,
262 .seek = ui_browser__list_head_seek, 381 .seek = ui_browser__list_head_seek,
263 .write = annotate_browser__write, 382 .write = annotate_browser__write,
264 .priv = sym, 383 .filter = objdump_line__filter,
384 .priv = &ms,
385 .use_navkeypressed = true,
265 }, 386 },
266 }; 387 };
267 int ret; 388 int ret;
@@ -273,7 +394,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
273 return -1; 394 return -1;
274 395
275 if (symbol__annotate(sym, map, sizeof(struct objdump_line_rb_node)) < 0) { 396 if (symbol__annotate(sym, map, sizeof(struct objdump_line_rb_node)) < 0) {
276 ui__error_window(ui_helpline__last_msg); 397 ui__error("%s", ui_helpline__last_msg);
277 return -1; 398 return -1;
278 } 399 }
279 400
@@ -288,12 +409,18 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
288 if (browser.b.width < line_len) 409 if (browser.b.width < line_len)
289 browser.b.width = line_len; 410 browser.b.width = line_len;
290 rbpos = objdump_line__rb(pos); 411 rbpos = objdump_line__rb(pos);
291 rbpos->idx = browser.b.nr_entries++; 412 rbpos->idx = browser.nr_entries++;
413 if (pos->offset != -1)
414 rbpos->idx_asm = browser.nr_asm_entries++;
415 else
416 rbpos->idx_asm = -1;
292 } 417 }
293 418
419 browser.b.nr_entries = browser.nr_entries;
294 browser.b.entries = &notes->src->source, 420 browser.b.entries = &notes->src->source,
295 browser.b.width += 18; /* Percentage */ 421 browser.b.width += 18; /* Percentage */
296 ret = annotate_browser__run(&browser, evidx, refresh); 422 ret = annotate_browser__run(&browser, evidx, nr_events,
423 timer, arg, delay_secs);
297 list_for_each_entry_safe(pos, n, &notes->src->source, node) { 424 list_for_each_entry_safe(pos, n, &notes->src->source, node) {
298 list_del(&pos->node); 425 list_del(&pos->node);
299 objdump_line__free(pos); 426 objdump_line__free(pos);
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c
index 5d767c622dfc..d0c94b459685 100644
--- a/tools/perf/util/ui/browsers/hists.c
+++ b/tools/perf/util/ui/browsers/hists.c
@@ -17,6 +17,7 @@
17#include "../browser.h" 17#include "../browser.h"
18#include "../helpline.h" 18#include "../helpline.h"
19#include "../util.h" 19#include "../util.h"
20#include "../ui.h"
20#include "map.h" 21#include "map.h"
21 22
22struct hist_browser { 23struct hist_browser {
@@ -24,8 +25,12 @@ struct hist_browser {
24 struct hists *hists; 25 struct hists *hists;
25 struct hist_entry *he_selection; 26 struct hist_entry *he_selection;
26 struct map_symbol *selection; 27 struct map_symbol *selection;
28 bool has_symbols;
27}; 29};
28 30
31static int hists__browser_title(struct hists *self, char *bf, size_t size,
32 const char *ev_name);
33
29static void hist_browser__refresh_dimensions(struct hist_browser *self) 34static void hist_browser__refresh_dimensions(struct hist_browser *self)
30{ 35{
31 /* 3 == +/- toggle symbol before actual hist_entry rendering */ 36 /* 3 == +/- toggle symbol before actual hist_entry rendering */
@@ -290,28 +295,49 @@ static void hist_browser__set_folding(struct hist_browser *self, bool unfold)
290 ui_browser__reset_index(&self->b); 295 ui_browser__reset_index(&self->b);
291} 296}
292 297
293static int hist_browser__run(struct hist_browser *self, const char *title) 298static void ui_browser__warn_lost_events(struct ui_browser *browser)
299{
300 ui_browser__warning(browser, 4,
301 "Events are being lost, check IO/CPU overload!\n\n"
302 "You may want to run 'perf' using a RT scheduler policy:\n\n"
303 " perf top -r 80\n\n"
304 "Or reduce the sampling frequency.");
305}
306
307static int hist_browser__run(struct hist_browser *self, const char *ev_name,
308 void(*timer)(void *arg), void *arg, int delay_secs)
294{ 309{
295 int key; 310 int key;
296 int exit_keys[] = { 'a', '?', 'h', 'C', 'd', 'D', 'E', 't', 311 char title[160];
297 NEWT_KEY_ENTER, NEWT_KEY_RIGHT, NEWT_KEY_LEFT,
298 NEWT_KEY_TAB, NEWT_KEY_UNTAB, 0, };
299 312
300 self->b.entries = &self->hists->entries; 313 self->b.entries = &self->hists->entries;
301 self->b.nr_entries = self->hists->nr_entries; 314 self->b.nr_entries = self->hists->nr_entries;
302 315
303 hist_browser__refresh_dimensions(self); 316 hist_browser__refresh_dimensions(self);
317 hists__browser_title(self->hists, title, sizeof(title), ev_name);
304 318
305 if (ui_browser__show(&self->b, title, 319 if (ui_browser__show(&self->b, title,
306 "Press '?' for help on key bindings") < 0) 320 "Press '?' for help on key bindings") < 0)
307 return -1; 321 return -1;
308 322
309 ui_browser__add_exit_keys(&self->b, exit_keys);
310
311 while (1) { 323 while (1) {
312 key = ui_browser__run(&self->b); 324 key = ui_browser__run(&self->b, delay_secs);
313 325
314 switch (key) { 326 switch (key) {
327 case K_TIMER:
328 timer(arg);
329 ui_browser__update_nr_entries(&self->b, self->hists->nr_entries);
330
331 if (self->hists->stats.nr_lost_warned !=
332 self->hists->stats.nr_events[PERF_RECORD_LOST]) {
333 self->hists->stats.nr_lost_warned =
334 self->hists->stats.nr_events[PERF_RECORD_LOST];
335 ui_browser__warn_lost_events(&self->b);
336 }
337
338 hists__browser_title(self->hists, title, sizeof(title), ev_name);
339 ui_browser__show_title(&self->b, title);
340 continue;
315 case 'D': { /* Debug */ 341 case 'D': { /* Debug */
316 static int seq; 342 static int seq;
317 struct hist_entry *h = rb_entry(self->b.top, 343 struct hist_entry *h = rb_entry(self->b.top,
@@ -334,7 +360,7 @@ static int hist_browser__run(struct hist_browser *self, const char *title)
334 /* Expand the whole world. */ 360 /* Expand the whole world. */
335 hist_browser__set_folding(self, true); 361 hist_browser__set_folding(self, true);
336 break; 362 break;
337 case NEWT_KEY_ENTER: 363 case K_ENTER:
338 if (hist_browser__toggle_fold(self)) 364 if (hist_browser__toggle_fold(self))
339 break; 365 break;
340 /* fall thru */ 366 /* fall thru */
@@ -532,7 +558,7 @@ static int hist_browser__show_entry(struct hist_browser *self,
532 char s[256]; 558 char s[256];
533 double percent; 559 double percent;
534 int printed = 0; 560 int printed = 0;
535 int color, width = self->b.width; 561 int width = self->b.width - 6; /* The percentage */
536 char folded_sign = ' '; 562 char folded_sign = ' ';
537 bool current_entry = ui_browser__is_current_entry(&self->b, row); 563 bool current_entry = ui_browser__is_current_entry(&self->b, row);
538 off_t row_offset = entry->row_offset; 564 off_t row_offset = entry->row_offset;
@@ -548,26 +574,35 @@ static int hist_browser__show_entry(struct hist_browser *self,
548 } 574 }
549 575
550 if (row_offset == 0) { 576 if (row_offset == 0) {
551 hist_entry__snprintf(entry, s, sizeof(s), self->hists, NULL, false, 577 hist_entry__snprintf(entry, s, sizeof(s), self->hists);
552 0, false, self->hists->stats.total_period);
553 percent = (entry->period * 100.0) / self->hists->stats.total_period; 578 percent = (entry->period * 100.0) / self->hists->stats.total_period;
554 579
555 color = HE_COLORSET_SELECTED; 580 ui_browser__set_percent_color(&self->b, percent, current_entry);
556 if (!current_entry) {
557 if (percent >= MIN_RED)
558 color = HE_COLORSET_TOP;
559 else if (percent >= MIN_GREEN)
560 color = HE_COLORSET_MEDIUM;
561 else
562 color = HE_COLORSET_NORMAL;
563 }
564
565 ui_browser__set_color(&self->b, color);
566 ui_browser__gotorc(&self->b, row, 0); 581 ui_browser__gotorc(&self->b, row, 0);
567 if (symbol_conf.use_callchain) { 582 if (symbol_conf.use_callchain) {
568 slsmg_printf("%c ", folded_sign); 583 slsmg_printf("%c ", folded_sign);
569 width -= 2; 584 width -= 2;
570 } 585 }
586
587 slsmg_printf(" %5.2f%%", percent);
588
589 /* The scroll bar isn't being used */
590 if (!self->b.navkeypressed)
591 width += 1;
592
593 if (!current_entry || !self->b.navkeypressed)
594 ui_browser__set_color(&self->b, HE_COLORSET_NORMAL);
595
596 if (symbol_conf.show_nr_samples) {
597 slsmg_printf(" %11u", entry->nr_events);
598 width -= 12;
599 }
600
601 if (symbol_conf.show_total_period) {
602 slsmg_printf(" %12" PRIu64, entry->period);
603 width -= 13;
604 }
605
571 slsmg_write_nstring(s, width); 606 slsmg_write_nstring(s, width);
572 ++row; 607 ++row;
573 ++printed; 608 ++printed;
@@ -585,14 +620,23 @@ static int hist_browser__show_entry(struct hist_browser *self,
585 return printed; 620 return printed;
586} 621}
587 622
623static void ui_browser__hists_init_top(struct ui_browser *browser)
624{
625 if (browser->top == NULL) {
626 struct hist_browser *hb;
627
628 hb = container_of(browser, struct hist_browser, b);
629 browser->top = rb_first(&hb->hists->entries);
630 }
631}
632
588static unsigned int hist_browser__refresh(struct ui_browser *self) 633static unsigned int hist_browser__refresh(struct ui_browser *self)
589{ 634{
590 unsigned row = 0; 635 unsigned row = 0;
591 struct rb_node *nd; 636 struct rb_node *nd;
592 struct hist_browser *hb = container_of(self, struct hist_browser, b); 637 struct hist_browser *hb = container_of(self, struct hist_browser, b);
593 638
594 if (self->top == NULL) 639 ui_browser__hists_init_top(self);
595 self->top = rb_first(&hb->hists->entries);
596 640
597 for (nd = self->top; nd; nd = rb_next(nd)) { 641 for (nd = self->top; nd; nd = rb_next(nd)) {
598 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 642 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
@@ -644,6 +688,8 @@ static void ui_browser__hists_seek(struct ui_browser *self,
644 if (self->nr_entries == 0) 688 if (self->nr_entries == 0)
645 return; 689 return;
646 690
691 ui_browser__hists_init_top(self);
692
647 switch (whence) { 693 switch (whence) {
648 case SEEK_SET: 694 case SEEK_SET:
649 nd = hists__filter_entries(rb_first(self->entries)); 695 nd = hists__filter_entries(rb_first(self->entries));
@@ -761,6 +807,8 @@ static struct hist_browser *hist_browser__new(struct hists *hists)
761 self->hists = hists; 807 self->hists = hists;
762 self->b.refresh = hist_browser__refresh; 808 self->b.refresh = hist_browser__refresh;
763 self->b.seek = ui_browser__hists_seek; 809 self->b.seek = ui_browser__hists_seek;
810 self->b.use_navkeypressed = true,
811 self->has_symbols = sort_sym.list.next != NULL;
764 } 812 }
765 813
766 return self; 814 return self;
@@ -782,11 +830,12 @@ static struct thread *hist_browser__selected_thread(struct hist_browser *self)
782} 830}
783 831
784static int hists__browser_title(struct hists *self, char *bf, size_t size, 832static int hists__browser_title(struct hists *self, char *bf, size_t size,
785 const char *ev_name, const struct dso *dso, 833 const char *ev_name)
786 const struct thread *thread)
787{ 834{
788 char unit; 835 char unit;
789 int printed; 836 int printed;
837 const struct dso *dso = self->dso_filter;
838 const struct thread *thread = self->thread_filter;
790 unsigned long nr_events = self->stats.nr_events[PERF_RECORD_SAMPLE]; 839 unsigned long nr_events = self->stats.nr_events[PERF_RECORD_SAMPLE];
791 840
792 nr_events = convert_unit(nr_events, &unit); 841 nr_events = convert_unit(nr_events, &unit);
@@ -803,16 +852,15 @@ static int hists__browser_title(struct hists *self, char *bf, size_t size,
803 return printed; 852 return printed;
804} 853}
805 854
806static int perf_evsel__hists_browse(struct perf_evsel *evsel, 855static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
807 const char *helpline, const char *ev_name, 856 const char *helpline, const char *ev_name,
808 bool left_exits) 857 bool left_exits,
858 void(*timer)(void *arg), void *arg,
859 int delay_secs)
809{ 860{
810 struct hists *self = &evsel->hists; 861 struct hists *self = &evsel->hists;
811 struct hist_browser *browser = hist_browser__new(self); 862 struct hist_browser *browser = hist_browser__new(self);
812 struct pstack *fstack; 863 struct pstack *fstack;
813 const struct thread *thread_filter = NULL;
814 const struct dso *dso_filter = NULL;
815 char msg[160];
816 int key = -1; 864 int key = -1;
817 865
818 if (browser == NULL) 866 if (browser == NULL)
@@ -824,8 +872,6 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
824 872
825 ui_helpline__push(helpline); 873 ui_helpline__push(helpline);
826 874
827 hists__browser_title(self, msg, sizeof(msg), ev_name,
828 dso_filter, thread_filter);
829 while (1) { 875 while (1) {
830 const struct thread *thread = NULL; 876 const struct thread *thread = NULL;
831 const struct dso *dso = NULL; 877 const struct dso *dso = NULL;
@@ -834,7 +880,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
834 annotate = -2, zoom_dso = -2, zoom_thread = -2, 880 annotate = -2, zoom_dso = -2, zoom_thread = -2,
835 browse_map = -2; 881 browse_map = -2;
836 882
837 key = hist_browser__run(browser, msg); 883 key = hist_browser__run(browser, ev_name, timer, arg, delay_secs);
838 884
839 if (browser->he_selection != NULL) { 885 if (browser->he_selection != NULL) {
840 thread = hist_browser__selected_thread(browser); 886 thread = hist_browser__selected_thread(browser);
@@ -842,14 +888,23 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
842 } 888 }
843 889
844 switch (key) { 890 switch (key) {
845 case NEWT_KEY_TAB: 891 case K_TAB:
846 case NEWT_KEY_UNTAB: 892 case K_UNTAB:
893 if (nr_events == 1)
894 continue;
847 /* 895 /*
848 * Exit the browser, let hists__browser_tree 896 * Exit the browser, let hists__browser_tree
849 * go to the next or previous 897 * go to the next or previous
850 */ 898 */
851 goto out_free_stack; 899 goto out_free_stack;
852 case 'a': 900 case 'a':
901 if (!browser->has_symbols) {
902 ui_browser__warning(&browser->b, delay_secs * 2,
903 "Annotation is only available for symbolic views, "
904 "include \"sym\" in --sort to use it.");
905 continue;
906 }
907
853 if (browser->selection == NULL || 908 if (browser->selection == NULL ||
854 browser->selection->sym == NULL || 909 browser->selection->sym == NULL ||
855 browser->selection->map->dso->annotate_warned) 910 browser->selection->map->dso->annotate_warned)
@@ -859,25 +914,30 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
859 goto zoom_dso; 914 goto zoom_dso;
860 case 't': 915 case 't':
861 goto zoom_thread; 916 goto zoom_thread;
862 case NEWT_KEY_F1: 917 case K_F1:
863 case 'h': 918 case 'h':
864 case '?': 919 case '?':
865 ui__help_window("-> Zoom into DSO/Threads & Annotate current symbol\n" 920 ui_browser__help_window(&browser->b,
866 "<- Zoom out\n" 921 "h/?/F1 Show this window\n"
867 "a Annotate current symbol\n" 922 "UP/DOWN/PGUP\n"
868 "h/?/F1 Show this window\n" 923 "PGDN/SPACE Navigate\n"
869 "C Collapse all callchains\n" 924 "q/ESC/CTRL+C Exit browser\n\n"
870 "E Expand all callchains\n" 925 "For multiple event sessions:\n\n"
871 "d Zoom into current DSO\n" 926 "TAB/UNTAB Switch events\n\n"
872 "t Zoom into current Thread\n" 927 "For symbolic views (--sort has sym):\n\n"
873 "TAB/UNTAB Switch events\n" 928 "-> Zoom into DSO/Threads & Annotate current symbol\n"
874 "q/CTRL+C Exit browser"); 929 "<- Zoom out\n"
930 "a Annotate current symbol\n"
931 "C Collapse all callchains\n"
932 "E Expand all callchains\n"
933 "d Zoom into current DSO\n"
934 "t Zoom into current Thread");
875 continue; 935 continue;
876 case NEWT_KEY_ENTER: 936 case K_ENTER:
877 case NEWT_KEY_RIGHT: 937 case K_RIGHT:
878 /* menu */ 938 /* menu */
879 break; 939 break;
880 case NEWT_KEY_LEFT: { 940 case K_LEFT: {
881 const void *top; 941 const void *top;
882 942
883 if (pstack__empty(fstack)) { 943 if (pstack__empty(fstack)) {
@@ -889,21 +949,28 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
889 continue; 949 continue;
890 } 950 }
891 top = pstack__pop(fstack); 951 top = pstack__pop(fstack);
892 if (top == &dso_filter) 952 if (top == &browser->hists->dso_filter)
893 goto zoom_out_dso; 953 goto zoom_out_dso;
894 if (top == &thread_filter) 954 if (top == &browser->hists->thread_filter)
895 goto zoom_out_thread; 955 goto zoom_out_thread;
896 continue; 956 continue;
897 } 957 }
898 case NEWT_KEY_ESCAPE: 958 case K_ESC:
899 if (!left_exits && 959 if (!left_exits &&
900 !ui__dialog_yesno("Do you really want to exit?")) 960 !ui_browser__dialog_yesno(&browser->b,
961 "Do you really want to exit?"))
901 continue; 962 continue;
902 /* Fall thru */ 963 /* Fall thru */
903 default: 964 case 'q':
965 case CTRL('c'):
904 goto out_free_stack; 966 goto out_free_stack;
967 default:
968 continue;
905 } 969 }
906 970
971 if (!browser->has_symbols)
972 goto add_exit_option;
973
907 if (browser->selection != NULL && 974 if (browser->selection != NULL &&
908 browser->selection->sym != NULL && 975 browser->selection->sym != NULL &&
909 !browser->selection->map->dso->annotate_warned && 976 !browser->selection->map->dso->annotate_warned &&
@@ -913,14 +980,14 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
913 980
914 if (thread != NULL && 981 if (thread != NULL &&
915 asprintf(&options[nr_options], "Zoom %s %s(%d) thread", 982 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
916 (thread_filter ? "out of" : "into"), 983 (browser->hists->thread_filter ? "out of" : "into"),
917 (thread->comm_set ? thread->comm : ""), 984 (thread->comm_set ? thread->comm : ""),
918 thread->pid) > 0) 985 thread->pid) > 0)
919 zoom_thread = nr_options++; 986 zoom_thread = nr_options++;
920 987
921 if (dso != NULL && 988 if (dso != NULL &&
922 asprintf(&options[nr_options], "Zoom %s %s DSO", 989 asprintf(&options[nr_options], "Zoom %s %s DSO",
923 (dso_filter ? "out of" : "into"), 990 (browser->hists->dso_filter ? "out of" : "into"),
924 (dso->kernel ? "the Kernel" : dso->short_name)) > 0) 991 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
925 zoom_dso = nr_options++; 992 zoom_dso = nr_options++;
926 993
@@ -928,7 +995,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
928 browser->selection->map != NULL && 995 browser->selection->map != NULL &&
929 asprintf(&options[nr_options], "Browse map details") > 0) 996 asprintf(&options[nr_options], "Browse map details") > 0)
930 browse_map = nr_options++; 997 browse_map = nr_options++;
931 998add_exit_option:
932 options[nr_options++] = (char *)"Exit"; 999 options[nr_options++] = (char *)"Exit";
933 1000
934 choice = ui__popup_menu(nr_options, options); 1001 choice = ui__popup_menu(nr_options, options);
@@ -944,50 +1011,59 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
944 1011
945 if (choice == annotate) { 1012 if (choice == annotate) {
946 struct hist_entry *he; 1013 struct hist_entry *he;
1014 int err;
947do_annotate: 1015do_annotate:
948 he = hist_browser__selected_entry(browser); 1016 he = hist_browser__selected_entry(browser);
949 if (he == NULL) 1017 if (he == NULL)
950 continue; 1018 continue;
951 1019 /*
952 hist_entry__tui_annotate(he, evsel->idx); 1020 * Don't let this be freed, say, by hists__decay_entry.
1021 */
1022 he->used = true;
1023 err = hist_entry__tui_annotate(he, evsel->idx, nr_events,
1024 timer, arg, delay_secs);
1025 he->used = false;
1026 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
1027 if (err)
1028 ui_browser__handle_resize(&browser->b);
953 } else if (choice == browse_map) 1029 } else if (choice == browse_map)
954 map__browse(browser->selection->map); 1030 map__browse(browser->selection->map);
955 else if (choice == zoom_dso) { 1031 else if (choice == zoom_dso) {
956zoom_dso: 1032zoom_dso:
957 if (dso_filter) { 1033 if (browser->hists->dso_filter) {
958 pstack__remove(fstack, &dso_filter); 1034 pstack__remove(fstack, &browser->hists->dso_filter);
959zoom_out_dso: 1035zoom_out_dso:
960 ui_helpline__pop(); 1036 ui_helpline__pop();
961 dso_filter = NULL; 1037 browser->hists->dso_filter = NULL;
1038 sort_dso.elide = false;
962 } else { 1039 } else {
963 if (dso == NULL) 1040 if (dso == NULL)
964 continue; 1041 continue;
965 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"", 1042 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
966 dso->kernel ? "the Kernel" : dso->short_name); 1043 dso->kernel ? "the Kernel" : dso->short_name);
967 dso_filter = dso; 1044 browser->hists->dso_filter = dso;
968 pstack__push(fstack, &dso_filter); 1045 sort_dso.elide = true;
1046 pstack__push(fstack, &browser->hists->dso_filter);
969 } 1047 }
970 hists__filter_by_dso(self, dso_filter); 1048 hists__filter_by_dso(self);
971 hists__browser_title(self, msg, sizeof(msg), ev_name,
972 dso_filter, thread_filter);
973 hist_browser__reset(browser); 1049 hist_browser__reset(browser);
974 } else if (choice == zoom_thread) { 1050 } else if (choice == zoom_thread) {
975zoom_thread: 1051zoom_thread:
976 if (thread_filter) { 1052 if (browser->hists->thread_filter) {
977 pstack__remove(fstack, &thread_filter); 1053 pstack__remove(fstack, &browser->hists->thread_filter);
978zoom_out_thread: 1054zoom_out_thread:
979 ui_helpline__pop(); 1055 ui_helpline__pop();
980 thread_filter = NULL; 1056 browser->hists->thread_filter = NULL;
1057 sort_thread.elide = false;
981 } else { 1058 } else {
982 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"", 1059 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
983 thread->comm_set ? thread->comm : "", 1060 thread->comm_set ? thread->comm : "",
984 thread->pid); 1061 thread->pid);
985 thread_filter = thread; 1062 browser->hists->thread_filter = thread;
986 pstack__push(fstack, &thread_filter); 1063 sort_thread.elide = true;
1064 pstack__push(fstack, &browser->hists->thread_filter);
987 } 1065 }
988 hists__filter_by_thread(self, thread_filter); 1066 hists__filter_by_thread(self);
989 hists__browser_title(self, msg, sizeof(msg), ev_name,
990 dso_filter, thread_filter);
991 hist_browser__reset(browser); 1067 hist_browser__reset(browser);
992 } 1068 }
993 } 1069 }
@@ -1001,6 +1077,7 @@ out:
1001struct perf_evsel_menu { 1077struct perf_evsel_menu {
1002 struct ui_browser b; 1078 struct ui_browser b;
1003 struct perf_evsel *selection; 1079 struct perf_evsel *selection;
1080 bool lost_events, lost_events_warned;
1004}; 1081};
1005 1082
1006static void perf_evsel_menu__write(struct ui_browser *browser, 1083static void perf_evsel_menu__write(struct ui_browser *browser,
@@ -1013,22 +1090,38 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
1013 unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE]; 1090 unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1014 const char *ev_name = event_name(evsel); 1091 const char *ev_name = event_name(evsel);
1015 char bf[256], unit; 1092 char bf[256], unit;
1093 const char *warn = " ";
1094 size_t printed;
1016 1095
1017 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : 1096 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
1018 HE_COLORSET_NORMAL); 1097 HE_COLORSET_NORMAL);
1019 1098
1020 nr_events = convert_unit(nr_events, &unit); 1099 nr_events = convert_unit(nr_events, &unit);
1021 snprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events, 1100 printed = snprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
1022 unit, unit == ' ' ? "" : " ", ev_name); 1101 unit, unit == ' ' ? "" : " ", ev_name);
1023 slsmg_write_nstring(bf, browser->width); 1102 slsmg_printf("%s", bf);
1103
1104 nr_events = evsel->hists.stats.nr_events[PERF_RECORD_LOST];
1105 if (nr_events != 0) {
1106 menu->lost_events = true;
1107 if (!current_entry)
1108 ui_browser__set_color(browser, HE_COLORSET_TOP);
1109 nr_events = convert_unit(nr_events, &unit);
1110 snprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!", nr_events,
1111 unit, unit == ' ' ? "" : " ");
1112 warn = bf;
1113 }
1114
1115 slsmg_write_nstring(warn, browser->width - printed);
1024 1116
1025 if (current_entry) 1117 if (current_entry)
1026 menu->selection = evsel; 1118 menu->selection = evsel;
1027} 1119}
1028 1120
1029static int perf_evsel_menu__run(struct perf_evsel_menu *menu, const char *help) 1121static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1122 int nr_events, const char *help,
1123 void(*timer)(void *arg), void *arg, int delay_secs)
1030{ 1124{
1031 int exit_keys[] = { NEWT_KEY_ENTER, NEWT_KEY_RIGHT, 0, };
1032 struct perf_evlist *evlist = menu->b.priv; 1125 struct perf_evlist *evlist = menu->b.priv;
1033 struct perf_evsel *pos; 1126 struct perf_evsel *pos;
1034 const char *ev_name, *title = "Available samples"; 1127 const char *ev_name, *title = "Available samples";
@@ -1038,50 +1131,72 @@ static int perf_evsel_menu__run(struct perf_evsel_menu *menu, const char *help)
1038 "ESC: exit, ENTER|->: Browse histograms") < 0) 1131 "ESC: exit, ENTER|->: Browse histograms") < 0)
1039 return -1; 1132 return -1;
1040 1133
1041 ui_browser__add_exit_keys(&menu->b, exit_keys);
1042
1043 while (1) { 1134 while (1) {
1044 key = ui_browser__run(&menu->b); 1135 key = ui_browser__run(&menu->b, delay_secs);
1045 1136
1046 switch (key) { 1137 switch (key) {
1047 case NEWT_KEY_RIGHT: 1138 case K_TIMER:
1048 case NEWT_KEY_ENTER: 1139 timer(arg);
1140
1141 if (!menu->lost_events_warned && menu->lost_events) {
1142 ui_browser__warn_lost_events(&menu->b);
1143 menu->lost_events_warned = true;
1144 }
1145 continue;
1146 case K_RIGHT:
1147 case K_ENTER:
1049 if (!menu->selection) 1148 if (!menu->selection)
1050 continue; 1149 continue;
1051 pos = menu->selection; 1150 pos = menu->selection;
1052browse_hists: 1151browse_hists:
1152 perf_evlist__set_selected(evlist, pos);
1153 /*
1154 * Give the calling tool a chance to populate the non
1155 * default evsel resorted hists tree.
1156 */
1157 if (timer)
1158 timer(arg);
1053 ev_name = event_name(pos); 1159 ev_name = event_name(pos);
1054 key = perf_evsel__hists_browse(pos, help, ev_name, true); 1160 key = perf_evsel__hists_browse(pos, nr_events, help,
1161 ev_name, true, timer,
1162 arg, delay_secs);
1055 ui_browser__show_title(&menu->b, title); 1163 ui_browser__show_title(&menu->b, title);
1056 break; 1164 switch (key) {
1057 case NEWT_KEY_LEFT: 1165 case K_TAB:
1166 if (pos->node.next == &evlist->entries)
1167 pos = list_entry(evlist->entries.next, struct perf_evsel, node);
1168 else
1169 pos = list_entry(pos->node.next, struct perf_evsel, node);
1170 goto browse_hists;
1171 case K_UNTAB:
1172 if (pos->node.prev == &evlist->entries)
1173 pos = list_entry(evlist->entries.prev, struct perf_evsel, node);
1174 else
1175 pos = list_entry(pos->node.prev, struct perf_evsel, node);
1176 goto browse_hists;
1177 case K_ESC:
1178 if (!ui_browser__dialog_yesno(&menu->b,
1179 "Do you really want to exit?"))
1180 continue;
1181 /* Fall thru */
1182 case 'q':
1183 case CTRL('c'):
1184 goto out;
1185 default:
1186 continue;
1187 }
1188 case K_LEFT:
1058 continue; 1189 continue;
1059 case NEWT_KEY_ESCAPE: 1190 case K_ESC:
1060 if (!ui__dialog_yesno("Do you really want to exit?")) 1191 if (!ui_browser__dialog_yesno(&menu->b,
1192 "Do you really want to exit?"))
1061 continue; 1193 continue;
1062 /* Fall thru */ 1194 /* Fall thru */
1063 default:
1064 goto out;
1065 }
1066
1067 switch (key) {
1068 case NEWT_KEY_TAB:
1069 if (pos->node.next == &evlist->entries)
1070 pos = list_entry(evlist->entries.next, struct perf_evsel, node);
1071 else
1072 pos = list_entry(pos->node.next, struct perf_evsel, node);
1073 goto browse_hists;
1074 case NEWT_KEY_UNTAB:
1075 if (pos->node.prev == &evlist->entries)
1076 pos = list_entry(evlist->entries.prev, struct perf_evsel, node);
1077 else
1078 pos = list_entry(pos->node.prev, struct perf_evsel, node);
1079 goto browse_hists;
1080 case 'q': 1195 case 'q':
1081 case CTRL('c'): 1196 case CTRL('c'):
1082 goto out; 1197 goto out;
1083 default: 1198 default:
1084 break; 1199 continue;
1085 } 1200 }
1086 } 1201 }
1087 1202
@@ -1091,7 +1206,9 @@ out:
1091} 1206}
1092 1207
1093static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, 1208static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
1094 const char *help) 1209 const char *help,
1210 void(*timer)(void *arg), void *arg,
1211 int delay_secs)
1095{ 1212{
1096 struct perf_evsel *pos; 1213 struct perf_evsel *pos;
1097 struct perf_evsel_menu menu = { 1214 struct perf_evsel_menu menu = {
@@ -1121,18 +1238,24 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
1121 pos->name = strdup(ev_name); 1238 pos->name = strdup(ev_name);
1122 } 1239 }
1123 1240
1124 return perf_evsel_menu__run(&menu, help); 1241 return perf_evsel_menu__run(&menu, evlist->nr_entries, help, timer,
1242 arg, delay_secs);
1125} 1243}
1126 1244
1127int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help) 1245int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
1246 void(*timer)(void *arg), void *arg,
1247 int delay_secs)
1128{ 1248{
1129 1249
1130 if (evlist->nr_entries == 1) { 1250 if (evlist->nr_entries == 1) {
1131 struct perf_evsel *first = list_entry(evlist->entries.next, 1251 struct perf_evsel *first = list_entry(evlist->entries.next,
1132 struct perf_evsel, node); 1252 struct perf_evsel, node);
1133 const char *ev_name = event_name(first); 1253 const char *ev_name = event_name(first);
1134 return perf_evsel__hists_browse(first, help, ev_name, false); 1254 return perf_evsel__hists_browse(first, evlist->nr_entries, help,
1255 ev_name, false, timer, arg,
1256 delay_secs);
1135 } 1257 }
1136 1258
1137 return __perf_evlist__tui_browse_hists(evlist, help); 1259 return __perf_evlist__tui_browse_hists(evlist, help,
1260 timer, arg, delay_secs);
1138} 1261}
diff --git a/tools/perf/util/ui/browsers/map.c b/tools/perf/util/ui/browsers/map.c
index 8462bffe20bc..6905bcc8be2d 100644
--- a/tools/perf/util/ui/browsers/map.c
+++ b/tools/perf/util/ui/browsers/map.c
@@ -1,5 +1,6 @@
1#include "../libslang.h" 1#include "../libslang.h"
2#include <elf.h> 2#include <elf.h>
3#include <newt.h>
3#include <inttypes.h> 4#include <inttypes.h>
4#include <sys/ttydefaults.h> 5#include <sys/ttydefaults.h>
5#include <ctype.h> 6#include <ctype.h>
@@ -108,11 +109,8 @@ static int map_browser__run(struct map_browser *self)
108 verbose ? "" : "restart with -v to use") < 0) 109 verbose ? "" : "restart with -v to use") < 0)
109 return -1; 110 return -1;
110 111
111 if (verbose)
112 ui_browser__add_exit_key(&self->b, '/');
113
114 while (1) { 112 while (1) {
115 key = ui_browser__run(&self->b); 113 key = ui_browser__run(&self->b, 0);
116 114
117 if (verbose && key == '/') 115 if (verbose && key == '/')
118 map_browser__search(self); 116 map_browser__search(self);
diff --git a/tools/perf/util/ui/browsers/top.c b/tools/perf/util/ui/browsers/top.c
deleted file mode 100644
index 5a06538532af..000000000000
--- a/tools/perf/util/ui/browsers/top.c
+++ /dev/null
@@ -1,213 +0,0 @@
1/*
2 * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
3 *
4 * Parts came from builtin-{top,stat,record}.c, see those files for further
5 * copyright notes.
6 *
7 * Released under the GPL v2. (and only v2, not any later version)
8 */
9#include "../browser.h"
10#include "../../annotate.h"
11#include "../helpline.h"
12#include "../libslang.h"
13#include "../util.h"
14#include "../../evlist.h"
15#include "../../hist.h"
16#include "../../sort.h"
17#include "../../symbol.h"
18#include "../../top.h"
19
20struct perf_top_browser {
21 struct ui_browser b;
22 struct rb_root root;
23 struct sym_entry *selection;
24 float sum_ksamples;
25 int dso_width;
26 int dso_short_width;
27 int sym_width;
28};
29
30static void perf_top_browser__write(struct ui_browser *browser, void *entry, int row)
31{
32 struct perf_top_browser *top_browser = container_of(browser, struct perf_top_browser, b);
33 struct sym_entry *syme = rb_entry(entry, struct sym_entry, rb_node);
34 bool current_entry = ui_browser__is_current_entry(browser, row);
35 struct symbol *symbol = sym_entry__symbol(syme);
36 struct perf_top *top = browser->priv;
37 int width = browser->width;
38 double pcnt;
39
40 pcnt = 100.0 - (100.0 * ((top_browser->sum_ksamples - syme->snap_count) /
41 top_browser->sum_ksamples));
42 ui_browser__set_percent_color(browser, pcnt, current_entry);
43
44 if (top->evlist->nr_entries == 1 || !top->display_weighted) {
45 slsmg_printf("%20.2f ", syme->weight);
46 width -= 24;
47 } else {
48 slsmg_printf("%9.1f %10ld ", syme->weight, syme->snap_count);
49 width -= 23;
50 }
51
52 slsmg_printf("%4.1f%%", pcnt);
53 width -= 7;
54
55 if (verbose) {
56 slsmg_printf(" %016" PRIx64, symbol->start);
57 width -= 17;
58 }
59
60 slsmg_printf(" %-*.*s ", top_browser->sym_width, top_browser->sym_width,
61 symbol->name);
62 width -= top_browser->sym_width;
63 slsmg_write_nstring(width >= syme->map->dso->long_name_len ?
64 syme->map->dso->long_name :
65 syme->map->dso->short_name, width);
66
67 if (current_entry)
68 top_browser->selection = syme;
69}
70
71static void perf_top_browser__update_rb_tree(struct perf_top_browser *browser)
72{
73 struct perf_top *top = browser->b.priv;
74 u64 top_idx = browser->b.top_idx;
75
76 browser->root = RB_ROOT;
77 browser->b.top = NULL;
78 browser->sum_ksamples = perf_top__decay_samples(top, &browser->root);
79 /*
80 * No active symbols
81 */
82 if (top->rb_entries == 0)
83 return;
84
85 perf_top__find_widths(top, &browser->root, &browser->dso_width,
86 &browser->dso_short_width,
87 &browser->sym_width);
88 if (browser->sym_width + browser->dso_width > browser->b.width - 29) {
89 browser->dso_width = browser->dso_short_width;
90 if (browser->sym_width + browser->dso_width > browser->b.width - 29)
91 browser->sym_width = browser->b.width - browser->dso_width - 29;
92 }
93
94 /*
95 * Adjust the ui_browser indexes since the entries in the browser->root
96 * rb_tree may have changed, then seek it from start, so that we get a
97 * possible new top of the screen.
98 */
99 browser->b.nr_entries = top->rb_entries;
100
101 if (top_idx >= browser->b.nr_entries) {
102 if (browser->b.height >= browser->b.nr_entries)
103 top_idx = browser->b.nr_entries - browser->b.height;
104 else
105 top_idx = 0;
106 }
107
108 if (browser->b.index >= top_idx + browser->b.height)
109 browser->b.index = top_idx + browser->b.index - browser->b.top_idx;
110
111 if (browser->b.index >= browser->b.nr_entries)
112 browser->b.index = browser->b.nr_entries - 1;
113
114 browser->b.top_idx = top_idx;
115 browser->b.seek(&browser->b, top_idx, SEEK_SET);
116}
117
118static void perf_top_browser__annotate(struct perf_top_browser *browser)
119{
120 struct sym_entry *syme = browser->selection;
121 struct symbol *sym = sym_entry__symbol(syme);
122 struct annotation *notes = symbol__annotation(sym);
123 struct perf_top *top = browser->b.priv;
124
125 if (notes->src != NULL)
126 goto do_annotation;
127
128 pthread_mutex_lock(&notes->lock);
129
130 top->sym_filter_entry = NULL;
131
132 if (symbol__alloc_hist(sym, top->evlist->nr_entries) < 0) {
133 pr_err("Not enough memory for annotating '%s' symbol!\n",
134 sym->name);
135 pthread_mutex_unlock(&notes->lock);
136 return;
137 }
138
139 top->sym_filter_entry = syme;
140
141 pthread_mutex_unlock(&notes->lock);
142do_annotation:
143 symbol__tui_annotate(sym, syme->map, 0, top->delay_secs * 1000);
144}
145
146static int perf_top_browser__run(struct perf_top_browser *browser)
147{
148 int key;
149 char title[160];
150 struct perf_top *top = browser->b.priv;
151 int delay_msecs = top->delay_secs * 1000;
152 int exit_keys[] = { 'a', NEWT_KEY_ENTER, NEWT_KEY_RIGHT, 0, };
153
154 perf_top_browser__update_rb_tree(browser);
155 perf_top__header_snprintf(top, title, sizeof(title));
156 perf_top__reset_sample_counters(top);
157
158 if (ui_browser__show(&browser->b, title,
159 "ESC: exit, ENTER|->|a: Live Annotate") < 0)
160 return -1;
161
162 newtFormSetTimer(browser->b.form, delay_msecs);
163 ui_browser__add_exit_keys(&browser->b, exit_keys);
164
165 while (1) {
166 key = ui_browser__run(&browser->b);
167
168 switch (key) {
169 case -1:
170 /* FIXME we need to check if it was es.reason == NEWT_EXIT_TIMER */
171 perf_top_browser__update_rb_tree(browser);
172 perf_top__header_snprintf(top, title, sizeof(title));
173 perf_top__reset_sample_counters(top);
174 ui_browser__set_color(&browser->b, NEWT_COLORSET_ROOT);
175 SLsmg_gotorc(0, 0);
176 slsmg_write_nstring(title, browser->b.width);
177 break;
178 case 'a':
179 case NEWT_KEY_RIGHT:
180 case NEWT_KEY_ENTER:
181 if (browser->selection)
182 perf_top_browser__annotate(browser);
183 break;
184 case NEWT_KEY_LEFT:
185 continue;
186 case NEWT_KEY_ESCAPE:
187 if (!ui__dialog_yesno("Do you really want to exit?"))
188 continue;
189 /* Fall thru */
190 default:
191 goto out;
192 }
193 }
194out:
195 ui_browser__hide(&browser->b);
196 return key;
197}
198
199int perf_top__tui_browser(struct perf_top *top)
200{
201 struct perf_top_browser browser = {
202 .b = {
203 .entries = &browser.root,
204 .refresh = ui_browser__rb_tree_refresh,
205 .seek = ui_browser__rb_tree_seek,
206 .write = perf_top_browser__write,
207 .priv = top,
208 },
209 };
210
211 ui_helpline__push("Press <- or ESC to exit");
212 return perf_top_browser__run(&browser);
213}
diff --git a/tools/perf/util/ui/helpline.c b/tools/perf/util/ui/helpline.c
index f36d2ff509ed..6ef3c5691762 100644
--- a/tools/perf/util/ui/helpline.c
+++ b/tools/perf/util/ui/helpline.c
@@ -1,20 +1,28 @@
1#define _GNU_SOURCE 1#define _GNU_SOURCE
2#include <stdio.h> 2#include <stdio.h>
3#include <stdlib.h> 3#include <stdlib.h>
4#include <newt.h> 4#include <string.h>
5 5
6#include "../debug.h" 6#include "../debug.h"
7#include "helpline.h" 7#include "helpline.h"
8#include "ui.h" 8#include "ui.h"
9#include "libslang.h"
9 10
10void ui_helpline__pop(void) 11void ui_helpline__pop(void)
11{ 12{
12 newtPopHelpLine();
13} 13}
14 14
15char ui_helpline__current[512];
16
15void ui_helpline__push(const char *msg) 17void ui_helpline__push(const char *msg)
16{ 18{
17 newtPushHelpLine(msg); 19 const size_t sz = sizeof(ui_helpline__current);
20
21 SLsmg_gotorc(SLtt_Screen_Rows - 1, 0);
22 SLsmg_set_color(0);
23 SLsmg_write_nstring((char *)msg, SLtt_Screen_Cols);
24 SLsmg_refresh();
25 strncpy(ui_helpline__current, msg, sz)[sz - 1] = '\0';
18} 26}
19 27
20void ui_helpline__vpush(const char *fmt, va_list ap) 28void ui_helpline__vpush(const char *fmt, va_list ap)
@@ -63,7 +71,7 @@ int ui_helpline__show_help(const char *format, va_list ap)
63 71
64 if (ui_helpline__last_msg[backlog - 1] == '\n') { 72 if (ui_helpline__last_msg[backlog - 1] == '\n') {
65 ui_helpline__puts(ui_helpline__last_msg); 73 ui_helpline__puts(ui_helpline__last_msg);
66 newtRefresh(); 74 SLsmg_refresh();
67 backlog = 0; 75 backlog = 0;
68 } 76 }
69 pthread_mutex_unlock(&ui__lock); 77 pthread_mutex_unlock(&ui__lock);
diff --git a/tools/perf/util/ui/helpline.h b/tools/perf/util/ui/helpline.h
index ab6028d0c401..7bab6b34e35e 100644
--- a/tools/perf/util/ui/helpline.h
+++ b/tools/perf/util/ui/helpline.h
@@ -1,6 +1,9 @@
1#ifndef _PERF_UI_HELPLINE_H_ 1#ifndef _PERF_UI_HELPLINE_H_
2#define _PERF_UI_HELPLINE_H_ 1 2#define _PERF_UI_HELPLINE_H_ 1
3 3
4#include <stdio.h>
5#include <stdarg.h>
6
4void ui_helpline__init(void); 7void ui_helpline__init(void);
5void ui_helpline__pop(void); 8void ui_helpline__pop(void);
6void ui_helpline__push(const char *msg); 9void ui_helpline__push(const char *msg);
@@ -8,4 +11,6 @@ void ui_helpline__vpush(const char *fmt, va_list ap);
8void ui_helpline__fpush(const char *fmt, ...); 11void ui_helpline__fpush(const char *fmt, ...);
9void ui_helpline__puts(const char *msg); 12void ui_helpline__puts(const char *msg);
10 13
14extern char ui_helpline__current[];
15
11#endif /* _PERF_UI_HELPLINE_H_ */ 16#endif /* _PERF_UI_HELPLINE_H_ */
diff --git a/tools/perf/util/ui/keysyms.h b/tools/perf/util/ui/keysyms.h
new file mode 100644
index 000000000000..3458b1985761
--- /dev/null
+++ b/tools/perf/util/ui/keysyms.h
@@ -0,0 +1,25 @@
1#ifndef _PERF_KEYSYMS_H_
2#define _PERF_KEYSYMS_H_ 1
3
4#include "libslang.h"
5
6#define K_DOWN SL_KEY_DOWN
7#define K_END SL_KEY_END
8#define K_ENTER '\r'
9#define K_ESC 033
10#define K_F1 SL_KEY_F(1)
11#define K_HOME SL_KEY_HOME
12#define K_LEFT SL_KEY_LEFT
13#define K_PGDN SL_KEY_NPAGE
14#define K_PGUP SL_KEY_PPAGE
15#define K_RIGHT SL_KEY_RIGHT
16#define K_TAB '\t'
17#define K_UNTAB SL_KEY_UNTAB
18#define K_UP SL_KEY_UP
19
20/* Not really keys */
21#define K_TIMER -1
22#define K_ERROR -2
23#define K_RESIZE -3
24
25#endif /* _PERF_KEYSYMS_H_ */
diff --git a/tools/perf/util/ui/libslang.h b/tools/perf/util/ui/libslang.h
index 2b63e1c9b181..4d54b6450f5b 100644
--- a/tools/perf/util/ui/libslang.h
+++ b/tools/perf/util/ui/libslang.h
@@ -24,4 +24,6 @@
24#define sltt_set_color SLtt_set_color 24#define sltt_set_color SLtt_set_color
25#endif 25#endif
26 26
27#define SL_KEY_UNTAB 0x1000
28
27#endif /* _PERF_UI_SLANG_H_ */ 29#endif /* _PERF_UI_SLANG_H_ */
diff --git a/tools/perf/util/ui/progress.c b/tools/perf/util/ui/progress.c
index d7fc399d36b3..295e366b6311 100644
--- a/tools/perf/util/ui/progress.c
+++ b/tools/perf/util/ui/progress.c
@@ -1,60 +1,29 @@
1#include <stdlib.h>
2#include <newt.h>
3#include "../cache.h" 1#include "../cache.h"
4#include "progress.h" 2#include "progress.h"
3#include "libslang.h"
4#include "ui.h"
5#include "browser.h"
5 6
6struct ui_progress { 7void ui_progress__update(u64 curr, u64 total, const char *title)
7 newtComponent form, scale;
8};
9
10struct ui_progress *ui_progress__new(const char *title, u64 total)
11{
12 struct ui_progress *self = malloc(sizeof(*self));
13
14 if (self != NULL) {
15 int cols;
16
17 if (use_browser <= 0)
18 return self;
19 newtGetScreenSize(&cols, NULL);
20 cols -= 4;
21 newtCenteredWindow(cols, 1, title);
22 self->form = newtForm(NULL, NULL, 0);
23 if (self->form == NULL)
24 goto out_free_self;
25 self->scale = newtScale(0, 0, cols, total);
26 if (self->scale == NULL)
27 goto out_free_form;
28 newtFormAddComponent(self->form, self->scale);
29 newtRefresh();
30 }
31
32 return self;
33
34out_free_form:
35 newtFormDestroy(self->form);
36out_free_self:
37 free(self);
38 return NULL;
39}
40
41void ui_progress__update(struct ui_progress *self, u64 curr)
42{ 8{
9 int bar, y;
43 /* 10 /*
44 * FIXME: We should have a per UI backend way of showing progress, 11 * FIXME: We should have a per UI backend way of showing progress,
45 * stdio will just show a percentage as NN%, etc. 12 * stdio will just show a percentage as NN%, etc.
46 */ 13 */
47 if (use_browser <= 0) 14 if (use_browser <= 0)
48 return; 15 return;
49 newtScaleSet(self->scale, curr);
50 newtRefresh();
51}
52 16
53void ui_progress__delete(struct ui_progress *self) 17 ui__refresh_dimensions(true);
54{ 18 pthread_mutex_lock(&ui__lock);
55 if (use_browser > 0) { 19 y = SLtt_Screen_Rows / 2 - 2;
56 newtFormDestroy(self->form); 20 SLsmg_set_color(0);
57 newtPopWindow(); 21 SLsmg_draw_box(y, 0, 3, SLtt_Screen_Cols);
58 } 22 SLsmg_gotorc(y++, 1);
59 free(self); 23 SLsmg_write_string((char *)title);
24 SLsmg_set_color(HE_COLORSET_SELECTED);
25 bar = ((SLtt_Screen_Cols - 2) * curr) / total;
26 SLsmg_fill_region(y, 1, 1, bar, ' ');
27 SLsmg_refresh();
28 pthread_mutex_unlock(&ui__lock);
60} 29}
diff --git a/tools/perf/util/ui/progress.h b/tools/perf/util/ui/progress.h
index a3820a0beb5b..d9c205b59aa1 100644
--- a/tools/perf/util/ui/progress.h
+++ b/tools/perf/util/ui/progress.h
@@ -1,11 +1,8 @@
1#ifndef _PERF_UI_PROGRESS_H_ 1#ifndef _PERF_UI_PROGRESS_H_
2#define _PERF_UI_PROGRESS_H_ 1 2#define _PERF_UI_PROGRESS_H_ 1
3 3
4struct ui_progress; 4#include <../types.h>
5 5
6struct ui_progress *ui_progress__new(const char *title, u64 total); 6void ui_progress__update(u64 curr, u64 total, const char *title);
7void ui_progress__delete(struct ui_progress *self);
8
9void ui_progress__update(struct ui_progress *self, u64 curr);
10 7
11#endif 8#endif
diff --git a/tools/perf/util/ui/setup.c b/tools/perf/util/ui/setup.c
index ee46d671db59..85a69faa09aa 100644
--- a/tools/perf/util/ui/setup.c
+++ b/tools/perf/util/ui/setup.c
@@ -7,9 +7,85 @@
7#include "browser.h" 7#include "browser.h"
8#include "helpline.h" 8#include "helpline.h"
9#include "ui.h" 9#include "ui.h"
10#include "util.h"
11#include "libslang.h"
12#include "keysyms.h"
10 13
11pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER; 14pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER;
12 15
16static volatile int ui__need_resize;
17
18void ui__refresh_dimensions(bool force)
19{
20 if (force || ui__need_resize) {
21 ui__need_resize = 0;
22 pthread_mutex_lock(&ui__lock);
23 SLtt_get_screen_size();
24 SLsmg_reinit_smg();
25 pthread_mutex_unlock(&ui__lock);
26 }
27}
28
29static void ui__sigwinch(int sig __used)
30{
31 ui__need_resize = 1;
32}
33
34static void ui__setup_sigwinch(void)
35{
36 static bool done;
37
38 if (done)
39 return;
40
41 done = true;
42 pthread__unblock_sigwinch();
43 signal(SIGWINCH, ui__sigwinch);
44}
45
46int ui__getch(int delay_secs)
47{
48 struct timeval timeout, *ptimeout = delay_secs ? &timeout : NULL;
49 fd_set read_set;
50 int err, key;
51
52 ui__setup_sigwinch();
53
54 FD_ZERO(&read_set);
55 FD_SET(0, &read_set);
56
57 if (delay_secs) {
58 timeout.tv_sec = delay_secs;
59 timeout.tv_usec = 0;
60 }
61
62 err = select(1, &read_set, NULL, NULL, ptimeout);
63
64 if (err == 0)
65 return K_TIMER;
66
67 if (err == -1) {
68 if (errno == EINTR)
69 return K_RESIZE;
70 return K_ERROR;
71 }
72
73 key = SLang_getkey();
74 if (key != K_ESC)
75 return key;
76
77 FD_ZERO(&read_set);
78 FD_SET(0, &read_set);
79 timeout.tv_sec = 0;
80 timeout.tv_usec = 20;
81 err = select(1, &read_set, NULL, NULL, &timeout);
82 if (err == 0)
83 return K_ESC;
84
85 SLang_ungetkey(key);
86 return SLkp_getkey();
87}
88
13static void newt_suspend(void *d __used) 89static void newt_suspend(void *d __used)
14{ 90{
15 newtSuspend(); 91 newtSuspend();
@@ -17,6 +93,33 @@ static void newt_suspend(void *d __used)
17 newtResume(); 93 newtResume();
18} 94}
19 95
96static int ui__init(void)
97{
98 int err = SLkp_init();
99
100 if (err < 0)
101 goto out;
102
103 SLkp_define_keysym((char *)"^(kB)", SL_KEY_UNTAB);
104out:
105 return err;
106}
107
108static void ui__exit(void)
109{
110 SLtt_set_cursor_visibility(1);
111 SLsmg_refresh();
112 SLsmg_reset_smg();
113 SLang_reset_tty();
114}
115
116static void ui__signal(int sig)
117{
118 ui__exit();
119 psignal(sig, "perf");
120 exit(0);
121}
122
20void setup_browser(bool fallback_to_pager) 123void setup_browser(bool fallback_to_pager)
21{ 124{
22 if (!isatty(1) || !use_browser || dump_trace) { 125 if (!isatty(1) || !use_browser || dump_trace) {
@@ -28,19 +131,25 @@ void setup_browser(bool fallback_to_pager)
28 131
29 use_browser = 1; 132 use_browser = 1;
30 newtInit(); 133 newtInit();
31 newtCls(); 134 ui__init();
32 newtSetSuspendCallback(newt_suspend, NULL); 135 newtSetSuspendCallback(newt_suspend, NULL);
33 ui_helpline__init(); 136 ui_helpline__init();
34 ui_browser__init(); 137 ui_browser__init();
138
139 signal(SIGSEGV, ui__signal);
140 signal(SIGFPE, ui__signal);
141 signal(SIGINT, ui__signal);
142 signal(SIGQUIT, ui__signal);
143 signal(SIGTERM, ui__signal);
35} 144}
36 145
37void exit_browser(bool wait_for_ok) 146void exit_browser(bool wait_for_ok)
38{ 147{
39 if (use_browser > 0) { 148 if (use_browser > 0) {
40 if (wait_for_ok) { 149 if (wait_for_ok)
41 char title[] = "Fatal Error", ok[] = "Ok"; 150 ui__question_window("Fatal Error",
42 newtWinMessage(title, ok, ui_helpline__last_msg); 151 ui_helpline__last_msg,
43 } 152 "Press any key...", 0);
44 newtFinished(); 153 ui__exit();
45 } 154 }
46} 155}
diff --git a/tools/perf/util/ui/ui.h b/tools/perf/util/ui/ui.h
index d264e059c829..7b67045479f6 100644
--- a/tools/perf/util/ui/ui.h
+++ b/tools/perf/util/ui/ui.h
@@ -2,7 +2,10 @@
2#define _PERF_UI_H_ 1 2#define _PERF_UI_H_ 1
3 3
4#include <pthread.h> 4#include <pthread.h>
5#include <stdbool.h>
5 6
6extern pthread_mutex_t ui__lock; 7extern pthread_mutex_t ui__lock;
7 8
9void ui__refresh_dimensions(bool force);
10
8#endif /* _PERF_UI_H_ */ 11#endif /* _PERF_UI_H_ */
diff --git a/tools/perf/util/ui/util.c b/tools/perf/util/ui/util.c
index fdf1fc8f08bc..45daa7c41dad 100644
--- a/tools/perf/util/ui/util.c
+++ b/tools/perf/util/ui/util.c
@@ -1,6 +1,5 @@
1#include <newt.h> 1#include "../util.h"
2#include <signal.h> 2#include <signal.h>
3#include <stdio.h>
4#include <stdbool.h> 3#include <stdbool.h>
5#include <string.h> 4#include <string.h>
6#include <sys/ttydefaults.h> 5#include <sys/ttydefaults.h>
@@ -8,72 +7,75 @@
8#include "../cache.h" 7#include "../cache.h"
9#include "../debug.h" 8#include "../debug.h"
10#include "browser.h" 9#include "browser.h"
10#include "keysyms.h"
11#include "helpline.h" 11#include "helpline.h"
12#include "ui.h" 12#include "ui.h"
13#include "util.h" 13#include "util.h"
14#include "libslang.h"
14 15
15static void newt_form__set_exit_keys(newtComponent self) 16static void ui_browser__argv_write(struct ui_browser *browser,
17 void *entry, int row)
16{ 18{
17 newtFormAddHotKey(self, NEWT_KEY_LEFT); 19 char **arg = entry;
18 newtFormAddHotKey(self, NEWT_KEY_ESCAPE); 20 bool current_entry = ui_browser__is_current_entry(browser, row);
19 newtFormAddHotKey(self, 'Q');
20 newtFormAddHotKey(self, 'q');
21 newtFormAddHotKey(self, CTRL('c'));
22}
23 21
24static newtComponent newt_form__new(void) 22 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
25{ 23 HE_COLORSET_NORMAL);
26 newtComponent self = newtForm(NULL, NULL, 0); 24 slsmg_write_nstring(*arg, browser->width);
27 if (self)
28 newt_form__set_exit_keys(self);
29 return self;
30} 25}
31 26
32int ui__popup_menu(int argc, char * const argv[]) 27static int popup_menu__run(struct ui_browser *menu)
33{ 28{
34 struct newtExitStruct es; 29 int key;
35 int i, rc = -1, max_len = 5;
36 newtComponent listbox, form = newt_form__new();
37 30
38 if (form == NULL) 31 if (ui_browser__show(menu, " ", "ESC: exit, ENTER|->: Select option") < 0)
39 return -1; 32 return -1;
40 33
41 listbox = newtListbox(0, 0, argc, NEWT_FLAG_RETURNEXIT); 34 while (1) {
42 if (listbox == NULL) 35 key = ui_browser__run(menu, 0);
43 goto out_destroy_form;
44 36
45 newtFormAddComponent(form, listbox); 37 switch (key) {
38 case K_RIGHT:
39 case K_ENTER:
40 key = menu->index;
41 break;
42 case K_LEFT:
43 case K_ESC:
44 case 'q':
45 case CTRL('c'):
46 key = -1;
47 break;
48 default:
49 continue;
50 }
46 51
47 for (i = 0; i < argc; ++i) { 52 break;
48 int len = strlen(argv[i]);
49 if (len > max_len)
50 max_len = len;
51 if (newtListboxAddEntry(listbox, argv[i], (void *)(long)i))
52 goto out_destroy_form;
53 } 53 }
54 54
55 newtCenteredWindow(max_len, argc, NULL); 55 ui_browser__hide(menu);
56 newtFormRun(form, &es); 56 return key;
57 rc = newtListboxGetCurrent(listbox) - NULL;
58 if (es.reason == NEWT_EXIT_HOTKEY)
59 rc = -1;
60 newtPopWindow();
61out_destroy_form:
62 newtFormDestroy(form);
63 return rc;
64} 57}
65 58
66int ui__help_window(const char *text) 59int ui__popup_menu(int argc, char * const argv[])
67{ 60{
68 struct newtExitStruct es; 61 struct ui_browser menu = {
69 newtComponent tb, form = newt_form__new(); 62 .entries = (void *)argv,
70 int rc = -1; 63 .refresh = ui_browser__argv_refresh,
64 .seek = ui_browser__argv_seek,
65 .write = ui_browser__argv_write,
66 .nr_entries = argc,
67 };
68
69 return popup_menu__run(&menu);
70}
71
72int ui__question_window(const char *title, const char *text,
73 const char *exit_msg, int delay_secs)
74{
75 int x, y;
71 int max_len = 0, nr_lines = 0; 76 int max_len = 0, nr_lines = 0;
72 const char *t; 77 const char *t;
73 78
74 if (form == NULL)
75 return -1;
76
77 t = text; 79 t = text;
78 while (1) { 80 while (1) {
79 const char *sep = strchr(t, '\n'); 81 const char *sep = strchr(t, '\n');
@@ -90,41 +92,77 @@ int ui__help_window(const char *text)
90 t = sep + 1; 92 t = sep + 1;
91 } 93 }
92 94
93 tb = newtTextbox(0, 0, max_len, nr_lines, 0); 95 max_len += 2;
94 if (tb == NULL) 96 nr_lines += 4;
95 goto out_destroy_form; 97 y = SLtt_Screen_Rows / 2 - nr_lines / 2,
96 98 x = SLtt_Screen_Cols / 2 - max_len / 2;
97 newtTextboxSetText(tb, text); 99
98 newtFormAddComponent(form, tb); 100 SLsmg_set_color(0);
99 newtCenteredWindow(max_len, nr_lines, NULL); 101 SLsmg_draw_box(y, x++, nr_lines, max_len);
100 newtFormRun(form, &es); 102 if (title) {
101 newtPopWindow(); 103 SLsmg_gotorc(y, x + 1);
102 rc = 0; 104 SLsmg_write_string((char *)title);
103out_destroy_form: 105 }
104 newtFormDestroy(form); 106 SLsmg_gotorc(++y, x);
105 return rc; 107 nr_lines -= 2;
108 max_len -= 2;
109 SLsmg_write_wrapped_string((unsigned char *)text, y, x,
110 nr_lines, max_len, 1);
111 SLsmg_gotorc(y + nr_lines - 2, x);
112 SLsmg_write_nstring((char *)" ", max_len);
113 SLsmg_gotorc(y + nr_lines - 1, x);
114 SLsmg_write_nstring((char *)exit_msg, max_len);
115 SLsmg_refresh();
116 return ui__getch(delay_secs);
106} 117}
107 118
108static const char yes[] = "Yes", no[] = "No", 119int ui__help_window(const char *text)
109 warning_str[] = "Warning!", ok[] = "Ok"; 120{
121 return ui__question_window("Help", text, "Press any key...", 0);
122}
110 123
111bool ui__dialog_yesno(const char *msg) 124int ui__dialog_yesno(const char *msg)
112{ 125{
113 /* newtWinChoice should really be accepting const char pointers... */ 126 return ui__question_window(NULL, msg, "Enter: Yes, ESC: No", 0);
114 return newtWinChoice(NULL, (char *)yes, (char *)no, (char *)msg) == 1;
115} 127}
116 128
117void ui__warning(const char *format, ...) 129int __ui__warning(const char *title, const char *format, va_list args)
118{ 130{
119 va_list args; 131 char *s;
132
133 if (use_browser > 0 && vasprintf(&s, format, args) > 0) {
134 int key;
120 135
121 va_start(args, format);
122 if (use_browser > 0) {
123 pthread_mutex_lock(&ui__lock); 136 pthread_mutex_lock(&ui__lock);
124 newtWinMessagev((char *)warning_str, (char *)ok, 137 key = ui__question_window(title, s, "Press any key...", 0);
125 (char *)format, args);
126 pthread_mutex_unlock(&ui__lock); 138 pthread_mutex_unlock(&ui__lock);
127 } else 139 free(s);
128 vfprintf(stderr, format, args); 140 return key;
141 }
142
143 fprintf(stderr, "%s:\n", title);
144 vfprintf(stderr, format, args);
145 return K_ESC;
146}
147
148int ui__warning(const char *format, ...)
149{
150 int key;
151 va_list args;
152
153 va_start(args, format);
154 key = __ui__warning("Warning", format, args);
155 va_end(args);
156 return key;
157}
158
159int ui__error(const char *format, ...)
160{
161 int key;
162 va_list args;
163
164 va_start(args, format);
165 key = __ui__warning("Error", format, args);
129 va_end(args); 166 va_end(args);
167 return key;
130} 168}
diff --git a/tools/perf/util/ui/util.h b/tools/perf/util/ui/util.h
index afcbc1d99531..2d1738bd71c8 100644
--- a/tools/perf/util/ui/util.h
+++ b/tools/perf/util/ui/util.h
@@ -1,10 +1,14 @@
1#ifndef _PERF_UI_UTIL_H_ 1#ifndef _PERF_UI_UTIL_H_
2#define _PERF_UI_UTIL_H_ 1 2#define _PERF_UI_UTIL_H_ 1
3 3
4#include <stdbool.h> 4#include <stdarg.h>
5 5
6int ui__getch(int delay_secs);
6int ui__popup_menu(int argc, char * const argv[]); 7int ui__popup_menu(int argc, char * const argv[]);
7int ui__help_window(const char *text); 8int ui__help_window(const char *text);
8bool ui__dialog_yesno(const char *msg); 9int ui__dialog_yesno(const char *msg);
10int ui__question_window(const char *title, const char *text,
11 const char *exit_msg, int delay_secs);
12int __ui__warning(const char *title, const char *format, va_list args);
9 13
10#endif /* _PERF_UI_UTIL_H_ */ 14#endif /* _PERF_UI_UTIL_H_ */
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index fc784284ac8b..0128906bac88 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -238,6 +238,7 @@ char **argv_split(const char *str, int *argcp);
238void argv_free(char **argv); 238void argv_free(char **argv);
239bool strglobmatch(const char *str, const char *pat); 239bool strglobmatch(const char *str, const char *pat);
240bool strlazymatch(const char *str, const char *pat); 240bool strlazymatch(const char *str, const char *pat);
241int strtailcmp(const char *s1, const char *s2);
241unsigned long convert_unit(unsigned long value, char *unit); 242unsigned long convert_unit(unsigned long value, char *unit);
242int readn(int fd, void *buf, size_t size); 243int readn(int fd, void *buf, size_t size);
243 244