aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/Documentation/perf-bench.txt4
-rw-r--r--tools/perf/Documentation/perf-inject.txt3
-rw-r--r--tools/perf/Documentation/perf-kvm.txt16
-rw-r--r--tools/perf/Documentation/perf-timechart.txt38
-rw-r--r--tools/perf/Documentation/perf-trace.txt46
-rw-r--r--tools/perf/Documentation/perf.txt10
-rw-r--r--tools/perf/MANIFEST3
-rw-r--r--tools/perf/Makefile.perf4
-rw-r--r--tools/perf/arch/powerpc/Makefile1
-rw-r--r--tools/perf/arch/powerpc/util/header.c4
-rw-r--r--tools/perf/arch/powerpc/util/skip-callchain-idx.c266
-rw-r--r--tools/perf/arch/s390/Makefile3
-rw-r--r--tools/perf/arch/s390/util/header.c28
-rw-r--r--tools/perf/arch/s390/util/kvm-stat.c105
-rw-r--r--tools/perf/arch/x86/Makefile2
-rw-r--r--tools/perf/arch/x86/tests/dwarf-unwind.c1
-rw-r--r--tools/perf/arch/x86/util/kvm-stat.c156
-rw-r--r--tools/perf/arch/x86/util/tsc.c31
-rw-r--r--tools/perf/arch/x86/util/tsc.h3
-rw-r--r--tools/perf/arch/x86/util/unwind-libunwind.c1
-rw-r--r--tools/perf/bench/bench.h1
-rw-r--r--tools/perf/bench/futex-requeue.c10
-rw-r--r--tools/perf/bench/futex-wake.c12
-rw-r--r--tools/perf/bench/mem-memcpy.c9
-rw-r--r--tools/perf/bench/mem-memset.c9
-rw-r--r--tools/perf/bench/sched-messaging.c47
-rw-r--r--tools/perf/builtin-bench.c7
-rw-r--r--tools/perf/builtin-buildid-cache.c8
-rw-r--r--tools/perf/builtin-evlist.c1
-rw-r--r--tools/perf/builtin-help.c1
-rw-r--r--tools/perf/builtin-inject.c5
-rw-r--r--tools/perf/builtin-kvm.c414
-rw-r--r--tools/perf/builtin-record.c7
-rw-r--r--tools/perf/builtin-sched.c16
-rw-r--r--tools/perf/builtin-script.c60
-rw-r--r--tools/perf/builtin-stat.c2
-rw-r--r--tools/perf/builtin-timechart.c694
-rw-r--r--tools/perf/builtin-trace.c266
-rw-r--r--tools/perf/config/Makefile14
-rw-r--r--tools/perf/config/feature-checks/Makefile4
-rw-r--r--tools/perf/config/feature-checks/test-all.c5
-rw-r--r--tools/perf/config/feature-checks/test-sync-compare-and-swap.c14
-rw-r--r--tools/perf/perf-sys.h1
-rw-r--r--tools/perf/perf.c13
-rw-r--r--tools/perf/scripts/perl/bin/failed-syscalls-record3
-rw-r--r--tools/perf/scripts/perl/failed-syscalls.pl5
-rw-r--r--tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py3
-rw-r--r--tools/perf/scripts/python/bin/failed-syscalls-by-pid-record3
-rw-r--r--tools/perf/scripts/python/bin/sctop-record3
-rw-r--r--tools/perf/scripts/python/bin/syscall-counts-by-pid-record3
-rw-r--r--tools/perf/scripts/python/bin/syscall-counts-record3
-rw-r--r--tools/perf/scripts/python/check-perf-trace.py4
-rw-r--r--tools/perf/scripts/python/failed-syscalls-by-pid.py7
-rw-r--r--tools/perf/scripts/python/futex-contention.py4
-rwxr-xr-xtools/perf/scripts/python/net_dropmonitor.py2
-rw-r--r--tools/perf/scripts/python/netdev-times.py26
-rw-r--r--tools/perf/scripts/python/sched-migration.py41
-rw-r--r--tools/perf/scripts/python/sctop.py7
-rw-r--r--tools/perf/scripts/python/syscall-counts-by-pid.py7
-rw-r--r--tools/perf/scripts/python/syscall-counts.py7
-rw-r--r--tools/perf/tests/attr/base-record3
-rw-r--r--tools/perf/tests/attr/base-stat3
-rw-r--r--tools/perf/tests/bp_signal.c4
-rw-r--r--tools/perf/tests/bp_signal_overflow.c4
-rw-r--r--tools/perf/tests/dso-data.c1
-rw-r--r--tools/perf/tests/evsel-roundtrip-name.c1
-rw-r--r--tools/perf/tests/evsel-tp-sched.c1
-rw-r--r--tools/perf/tests/open-syscall-tp-fields.c1
-rw-r--r--tools/perf/tests/parse-events.c1
-rw-r--r--tools/perf/tests/parse-no-sample-id-all.c1
-rw-r--r--tools/perf/tests/perf-time-to-tsc.c12
-rw-r--r--tools/perf/tests/rdpmc.c4
-rw-r--r--tools/perf/tests/sample-parsing.c1
-rw-r--r--tools/perf/tests/thread-mg-share.c1
-rw-r--r--tools/perf/ui/browser.c39
-rw-r--r--tools/perf/ui/browser.h3
-rw-r--r--tools/perf/ui/browsers/hists.c153
-rw-r--r--tools/perf/ui/stdio/hist.c2
-rw-r--r--tools/perf/util/callchain.c2
-rw-r--r--tools/perf/util/callchain.h13
-rw-r--r--tools/perf/util/cloexec.c57
-rw-r--r--tools/perf/util/cloexec.h6
-rw-r--r--tools/perf/util/config.c13
-rw-r--r--tools/perf/util/data.c3
-rw-r--r--tools/perf/util/debug.c56
-rw-r--r--tools/perf/util/debug.h22
-rw-r--r--tools/perf/util/dso.c71
-rw-r--r--tools/perf/util/dso.h26
-rw-r--r--tools/perf/util/event.c52
-rw-r--r--tools/perf/util/event.h10
-rw-r--r--tools/perf/util/evlist.c51
-rw-r--r--tools/perf/util/evsel.c26
-rw-r--r--tools/perf/util/evsel.h2
-rw-r--r--tools/perf/util/header.c51
-rw-r--r--tools/perf/util/header.h2
-rw-r--r--tools/perf/util/include/linux/kernel.h21
-rw-r--r--tools/perf/util/kvm-stat.h140
-rw-r--r--tools/perf/util/machine.c139
-rw-r--r--tools/perf/util/machine.h8
-rw-r--r--tools/perf/util/map.c47
-rw-r--r--tools/perf/util/map.h15
-rw-r--r--tools/perf/util/parse-options.h5
-rw-r--r--tools/perf/util/probe-finder.c1
-rw-r--r--tools/perf/util/pstack.c1
-rw-r--r--tools/perf/util/python.c4
-rw-r--r--tools/perf/util/record.c27
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c1
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c197
-rw-r--r--tools/perf/util/session.c39
-rw-r--r--tools/perf/util/session.h3
-rw-r--r--tools/perf/util/sort.c2
-rw-r--r--tools/perf/util/svghelper.c168
-rw-r--r--tools/perf/util/svghelper.h6
-rw-r--r--tools/perf/util/symbol-elf.c41
-rw-r--r--tools/perf/util/symbol-minimal.c43
-rw-r--r--tools/perf/util/symbol.c21
-rw-r--r--tools/perf/util/symbol.h9
-rw-r--r--tools/perf/util/thread.c13
-rw-r--r--tools/perf/util/thread.h1
-rw-r--r--tools/perf/util/trace-event-info.c13
-rw-r--r--tools/perf/util/trace-event-read.c2
-rw-r--r--tools/perf/util/tsc.c30
-rw-r--r--tools/perf/util/tsc.h12
-rw-r--r--tools/perf/util/unwind-libdw.c1
-rw-r--r--tools/perf/util/unwind-libunwind.c1
-rw-r--r--tools/perf/util/util.c10
-rw-r--r--tools/perf/util/vdso.c97
-rw-r--r--tools/perf/util/vdso.h13
128 files changed, 3450 insertions, 852 deletions
diff --git a/tools/perf/Documentation/perf-bench.txt b/tools/perf/Documentation/perf-bench.txt
index 4464ad770d51..f6480cbf309b 100644
--- a/tools/perf/Documentation/perf-bench.txt
+++ b/tools/perf/Documentation/perf-bench.txt
@@ -16,6 +16,10 @@ This 'perf bench' command is a general framework for benchmark suites.
16 16
17COMMON OPTIONS 17COMMON OPTIONS
18-------------- 18--------------
19-r::
20--repeat=::
21Specify amount of times to repeat the run (default 10).
22
19-f:: 23-f::
20--format=:: 24--format=::
21Specify format style. 25Specify format style.
diff --git a/tools/perf/Documentation/perf-inject.txt b/tools/perf/Documentation/perf-inject.txt
index a00a34276c54..dc7442cf3d7f 100644
--- a/tools/perf/Documentation/perf-inject.txt
+++ b/tools/perf/Documentation/perf-inject.txt
@@ -41,6 +41,9 @@ OPTIONS
41 tasks slept. sched_switch contains a callchain where a task slept and 41 tasks slept. sched_switch contains a callchain where a task slept and
42 sched_stat contains a timeslice how long a task slept. 42 sched_stat contains a timeslice how long a task slept.
43 43
44--kallsyms=<file>::
45 kallsyms pathname
46
44SEE ALSO 47SEE ALSO
45-------- 48--------
46linkperf:perf-record[1], linkperf:perf-report[1], linkperf:perf-archive[1] 49linkperf:perf-record[1], linkperf:perf-report[1], linkperf:perf-archive[1]
diff --git a/tools/perf/Documentation/perf-kvm.txt b/tools/perf/Documentation/perf-kvm.txt
index 52276a6d2b75..6e689dc89a2f 100644
--- a/tools/perf/Documentation/perf-kvm.txt
+++ b/tools/perf/Documentation/perf-kvm.txt
@@ -51,9 +51,9 @@ There are a couple of variants of perf kvm:
51 'perf kvm stat <command>' to run a command and gather performance counter 51 'perf kvm stat <command>' to run a command and gather performance counter
52 statistics. 52 statistics.
53 Especially, perf 'kvm stat record/report' generates a statistical analysis 53 Especially, perf 'kvm stat record/report' generates a statistical analysis
54 of KVM events. Currently, vmexit, mmio and ioport events are supported. 54 of KVM events. Currently, vmexit, mmio (x86 only) and ioport (x86 only)
55 'perf kvm stat record <command>' records kvm events and the events between 55 events are supported. 'perf kvm stat record <command>' records kvm events
56 start and end <command>. 56 and the events between start and end <command>.
57 And this command produces a file which contains tracing results of kvm 57 And this command produces a file which contains tracing results of kvm
58 events. 58 events.
59 59
@@ -103,8 +103,8 @@ STAT REPORT OPTIONS
103 analyze events which occures on this vcpu. (default: all vcpus) 103 analyze events which occures on this vcpu. (default: all vcpus)
104 104
105--event=<value>:: 105--event=<value>::
106 event to be analyzed. Possible values: vmexit, mmio, ioport. 106 event to be analyzed. Possible values: vmexit, mmio (x86 only),
107 (default: vmexit) 107 ioport (x86 only). (default: vmexit)
108-k:: 108-k::
109--key=<value>:: 109--key=<value>::
110 Sorting key. Possible values: sample (default, sort by samples 110 Sorting key. Possible values: sample (default, sort by samples
@@ -138,7 +138,8 @@ STAT LIVE OPTIONS
138 138
139 139
140--event=<value>:: 140--event=<value>::
141 event to be analyzed. Possible values: vmexit, mmio, ioport. 141 event to be analyzed. Possible values: vmexit,
142 mmio (x86 only), ioport (x86 only).
142 (default: vmexit) 143 (default: vmexit)
143 144
144-k:: 145-k::
@@ -147,7 +148,8 @@ STAT LIVE OPTIONS
147 number), time (sort by average time). 148 number), time (sort by average time).
148 149
149--duration=<value>:: 150--duration=<value>::
150 Show events other than HLT that take longer than duration usecs. 151 Show events other than HLT (x86 only) or Wait state (s390 only)
152 that take longer than duration usecs.
151 153
152SEE ALSO 154SEE ALSO
153-------- 155--------
diff --git a/tools/perf/Documentation/perf-timechart.txt b/tools/perf/Documentation/perf-timechart.txt
index 5e0f986dff38..df98d1c82688 100644
--- a/tools/perf/Documentation/perf-timechart.txt
+++ b/tools/perf/Documentation/perf-timechart.txt
@@ -15,10 +15,20 @@ DESCRIPTION
15There are two variants of perf timechart: 15There are two variants of perf timechart:
16 16
17 'perf timechart record <command>' to record the system level events 17 'perf timechart record <command>' to record the system level events
18 of an arbitrary workload. 18 of an arbitrary workload. By default timechart records only scheduler
19 and CPU events (task switches, running times, CPU power states, etc),
20 but it's possible to record IO (disk, network) activity using -I argument.
19 21
20 'perf timechart' to turn a trace into a Scalable Vector Graphics file, 22 'perf timechart' to turn a trace into a Scalable Vector Graphics file,
21 that can be viewed with popular SVG viewers such as 'Inkscape'. 23 that can be viewed with popular SVG viewers such as 'Inkscape'. Depending
24 on the events in the perf.data file, timechart will contain scheduler/cpu
25 events or IO events.
26
27 In IO mode, every bar has two charts: upper and lower.
28 Upper bar shows incoming events (disk reads, ingress network packets).
29 Lower bar shows outgoing events (disk writes, egress network packets).
30 There are also poll bars which show how much time application spent
31 in poll/epoll/select syscalls.
22 32
23TIMECHART OPTIONS 33TIMECHART OPTIONS
24----------------- 34-----------------
@@ -54,6 +64,19 @@ TIMECHART OPTIONS
54 duration or tasks with given name. If number is given it's interpreted 64 duration or tasks with given name. If number is given it's interpreted
55 as number of nanoseconds. If non-numeric string is given it's 65 as number of nanoseconds. If non-numeric string is given it's
56 interpreted as task name. 66 interpreted as task name.
67--io-skip-eagain::
68 Don't draw EAGAIN IO events.
69--io-min-time=<nsecs>::
70 Draw small events as if they lasted min-time. Useful when you need
71 to see very small and fast IO. It's possible to specify ms or us
72 suffix to specify time in milliseconds or microseconds.
73 Default value is 1ms.
74--io-merge-dist=<nsecs>::
75 Merge events that are merge-dist nanoseconds apart.
76 Reduces number of figures on the SVG and makes it more render-friendly.
77 It's possible to specify ms or us suffix to specify time in
78 milliseconds or microseconds.
79 Default value is 1us.
57 80
58RECORD OPTIONS 81RECORD OPTIONS
59-------------- 82--------------
@@ -63,6 +86,9 @@ RECORD OPTIONS
63-T:: 86-T::
64--tasks-only:: 87--tasks-only::
65 Record only tasks-related events 88 Record only tasks-related events
89-I::
90--io-only::
91 Record only io-related events
66-g:: 92-g::
67--callchain:: 93--callchain::
68 Do call-graph (stack chain/backtrace) recording 94 Do call-graph (stack chain/backtrace) recording
@@ -87,6 +113,14 @@ Record system-wide timechart:
87 113
88 $ perf timechart --highlight gcc 114 $ perf timechart --highlight gcc
89 115
116Record system-wide IO events:
117
118 $ perf timechart record -I
119
120 then generate timechart:
121
122 $ perf timechart
123
90SEE ALSO 124SEE ALSO
91-------- 125--------
92linkperf:perf-record[1] 126linkperf:perf-record[1]
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt
index fae38d9a44a4..02aac831bdd9 100644
--- a/tools/perf/Documentation/perf-trace.txt
+++ b/tools/perf/Documentation/perf-trace.txt
@@ -107,6 +107,52 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs.
107 Show tool stats such as number of times fd->pathname was discovered thru 107 Show tool stats such as number of times fd->pathname was discovered thru
108 hooking the open syscall return + vfs_getname or via reading /proc/pid/fd, etc. 108 hooking the open syscall return + vfs_getname or via reading /proc/pid/fd, etc.
109 109
110-F=[all|min|maj]::
111--pf=[all|min|maj]::
112 Trace pagefaults. Optionally, you can specify whether you want minor,
113 major or all pagefaults. Default value is maj.
114
115--syscalls::
116 Trace system calls. This options is enabled by default.
117
118PAGEFAULTS
119----------
120
121When tracing pagefaults, the format of the trace is as follows:
122
123<min|maj>fault [<ip.symbol>+<ip.offset>] => <addr.dso@addr.offset> (<map type><addr level>).
124
125- min/maj indicates whether fault event is minor or major;
126- ip.symbol shows symbol for instruction pointer (the code that generated the
127 fault); if no debug symbols available, perf trace will print raw IP;
128- addr.dso shows DSO for the faulted address;
129- map type is either 'd' for non-executable maps or 'x' for executable maps;
130- addr level is either 'k' for kernel dso or '.' for user dso.
131
132For symbols resolution you may need to install debugging symbols.
133
134Please be aware that duration is currently always 0 and doesn't reflect actual
135time it took for fault to be handled!
136
137When --verbose specified, perf trace tries to print all available information
138for both IP and fault address in the form of dso@symbol+offset.
139
140EXAMPLES
141--------
142
143Trace only major pagefaults:
144
145 $ perf trace --no-syscalls -F
146
147Trace syscalls, major and minor pagefaults:
148
149 $ perf trace -F all
150
151 1416.547 ( 0.000 ms): python/20235 majfault [CRYPTO_push_info_+0x0] => /lib/x86_64-linux-gnu/libcrypto.so.1.0.0@0x61be0 (x.)
152
153 As you can see, there was major pagefault in python process, from
154 CRYPTO_push_info_ routine which faulted somewhere in libcrypto.so.
155
110SEE ALSO 156SEE ALSO
111-------- 157--------
112linkperf:perf-record[1], linkperf:perf-script[1] 158linkperf:perf-record[1], linkperf:perf-script[1]
diff --git a/tools/perf/Documentation/perf.txt b/tools/perf/Documentation/perf.txt
index 0eeb247dc7d2..d240bb2e5b22 100644
--- a/tools/perf/Documentation/perf.txt
+++ b/tools/perf/Documentation/perf.txt
@@ -8,7 +8,15 @@ perf - Performance analysis tools for Linux
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf' [--version] [--help] COMMAND [ARGS] 11'perf' [--version] [--help] [OPTIONS] COMMAND [ARGS]
12
13OPTIONS
14-------
15--debug::
16 Setup debug variable (just verbose for now) in value
17 range (0, 10). Use like:
18 --debug verbose # sets verbose = 1
19 --debug verbose=2 # sets verbose = 2
12 20
13DESCRIPTION 21DESCRIPTION
14----------- 22-----------
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST
index 45da209b6ed3..344c4d3d0a4a 100644
--- a/tools/perf/MANIFEST
+++ b/tools/perf/MANIFEST
@@ -37,3 +37,6 @@ arch/x86/include/asm/kvm_host.h
37arch/x86/include/uapi/asm/svm.h 37arch/x86/include/uapi/asm/svm.h
38arch/x86/include/uapi/asm/vmx.h 38arch/x86/include/uapi/asm/vmx.h
39arch/x86/include/uapi/asm/kvm.h 39arch/x86/include/uapi/asm/kvm.h
40arch/x86/include/uapi/asm/kvm_perf.h
41arch/s390/include/uapi/asm/sie.h
42arch/s390/include/uapi/asm/kvm_perf.h
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 9670a16fa577..2240974b7745 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -295,11 +295,13 @@ LIB_H += util/intlist.h
295LIB_H += util/perf_regs.h 295LIB_H += util/perf_regs.h
296LIB_H += util/unwind.h 296LIB_H += util/unwind.h
297LIB_H += util/vdso.h 297LIB_H += util/vdso.h
298LIB_H += util/tsc.h
298LIB_H += ui/helpline.h 299LIB_H += ui/helpline.h
299LIB_H += ui/progress.h 300LIB_H += ui/progress.h
300LIB_H += ui/util.h 301LIB_H += ui/util.h
301LIB_H += ui/ui.h 302LIB_H += ui/ui.h
302LIB_H += util/data.h 303LIB_H += util/data.h
304LIB_H += util/kvm-stat.h
303 305
304LIB_OBJS += $(OUTPUT)util/abspath.o 306LIB_OBJS += $(OUTPUT)util/abspath.o
305LIB_OBJS += $(OUTPUT)util/alias.o 307LIB_OBJS += $(OUTPUT)util/alias.o
@@ -373,6 +375,8 @@ LIB_OBJS += $(OUTPUT)util/stat.o
373LIB_OBJS += $(OUTPUT)util/record.o 375LIB_OBJS += $(OUTPUT)util/record.o
374LIB_OBJS += $(OUTPUT)util/srcline.o 376LIB_OBJS += $(OUTPUT)util/srcline.o
375LIB_OBJS += $(OUTPUT)util/data.o 377LIB_OBJS += $(OUTPUT)util/data.o
378LIB_OBJS += $(OUTPUT)util/tsc.o
379LIB_OBJS += $(OUTPUT)util/cloexec.o
376 380
377LIB_OBJS += $(OUTPUT)ui/setup.o 381LIB_OBJS += $(OUTPUT)ui/setup.o
378LIB_OBJS += $(OUTPUT)ui/helpline.o 382LIB_OBJS += $(OUTPUT)ui/helpline.o
diff --git a/tools/perf/arch/powerpc/Makefile b/tools/perf/arch/powerpc/Makefile
index 744e629797be..b92219b1900d 100644
--- a/tools/perf/arch/powerpc/Makefile
+++ b/tools/perf/arch/powerpc/Makefile
@@ -3,3 +3,4 @@ PERF_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 5LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
6LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/skip-callchain-idx.o
diff --git a/tools/perf/arch/powerpc/util/header.c b/tools/perf/arch/powerpc/util/header.c
index 2f7073d107fd..6c1b8a75db09 100644
--- a/tools/perf/arch/powerpc/util/header.c
+++ b/tools/perf/arch/powerpc/util/header.c
@@ -5,9 +5,7 @@
5#include <string.h> 5#include <string.h>
6 6
7#include "../../util/header.h" 7#include "../../util/header.h"
8 8#include "../../util/util.h"
9#define __stringify_1(x) #x
10#define __stringify(x) __stringify_1(x)
11 9
12#define mfspr(rn) ({unsigned long rval; \ 10#define mfspr(rn) ({unsigned long rval; \
13 asm volatile("mfspr %0," __stringify(rn) \ 11 asm volatile("mfspr %0," __stringify(rn) \
diff --git a/tools/perf/arch/powerpc/util/skip-callchain-idx.c b/tools/perf/arch/powerpc/util/skip-callchain-idx.c
new file mode 100644
index 000000000000..a7c23a4b3778
--- /dev/null
+++ b/tools/perf/arch/powerpc/util/skip-callchain-idx.c
@@ -0,0 +1,266 @@
1/*
2 * Use DWARF Debug information to skip unnecessary callchain entries.
3 *
4 * Copyright (C) 2014 Sukadev Bhattiprolu, IBM Corporation.
5 * Copyright (C) 2014 Ulrich Weigand, IBM Corporation.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 */
12#include <inttypes.h>
13#include <dwarf.h>
14#include <elfutils/libdwfl.h>
15
16#include "util/thread.h"
17#include "util/callchain.h"
18
19/*
20 * When saving the callchain on Power, the kernel conservatively saves
21 * excess entries in the callchain. A few of these entries are needed
22 * in some cases but not others. If the unnecessary entries are not
23 * ignored, we end up with duplicate arcs in the call-graphs. Use
24 * DWARF debug information to skip over any unnecessary callchain
25 * entries.
26 *
27 * See function header for arch_adjust_callchain() below for more details.
28 *
29 * The libdwfl code in this file is based on code from elfutils
30 * (libdwfl/argp-std.c, libdwfl/tests/addrcfi.c, etc).
31 */
32static char *debuginfo_path;
33
34static const Dwfl_Callbacks offline_callbacks = {
35 .debuginfo_path = &debuginfo_path,
36 .find_debuginfo = dwfl_standard_find_debuginfo,
37 .section_address = dwfl_offline_section_address,
38};
39
40
41/*
42 * Use the DWARF expression for the Call-frame-address and determine
43 * if return address is in LR and if a new frame was allocated.
44 */
45static int check_return_reg(int ra_regno, Dwarf_Frame *frame)
46{
47 Dwarf_Op ops_mem[2];
48 Dwarf_Op dummy;
49 Dwarf_Op *ops = &dummy;
50 size_t nops;
51 int result;
52
53 result = dwarf_frame_register(frame, ra_regno, ops_mem, &ops, &nops);
54 if (result < 0) {
55 pr_debug("dwarf_frame_register() %s\n", dwarf_errmsg(-1));
56 return -1;
57 }
58
59 /*
60 * Check if return address is on the stack.
61 */
62 if (nops != 0 || ops != NULL)
63 return 0;
64
65 /*
66 * Return address is in LR. Check if a frame was allocated
67 * but not-yet used.
68 */
69 result = dwarf_frame_cfa(frame, &ops, &nops);
70 if (result < 0) {
71 pr_debug("dwarf_frame_cfa() returns %d, %s\n", result,
72 dwarf_errmsg(-1));
73 return -1;
74 }
75
76 /*
77 * If call frame address is in r1, no new frame was allocated.
78 */
79 if (nops == 1 && ops[0].atom == DW_OP_bregx && ops[0].number == 1 &&
80 ops[0].number2 == 0)
81 return 1;
82
83 /*
84 * A new frame was allocated but has not yet been used.
85 */
86 return 2;
87}
88
89/*
90 * Get the DWARF frame from the .eh_frame section.
91 */
92static Dwarf_Frame *get_eh_frame(Dwfl_Module *mod, Dwarf_Addr pc)
93{
94 int result;
95 Dwarf_Addr bias;
96 Dwarf_CFI *cfi;
97 Dwarf_Frame *frame;
98
99 cfi = dwfl_module_eh_cfi(mod, &bias);
100 if (!cfi) {
101 pr_debug("%s(): no CFI - %s\n", __func__, dwfl_errmsg(-1));
102 return NULL;
103 }
104
105 result = dwarf_cfi_addrframe(cfi, pc, &frame);
106 if (result) {
107 pr_debug("%s(): %s\n", __func__, dwfl_errmsg(-1));
108 return NULL;
109 }
110
111 return frame;
112}
113
114/*
115 * Get the DWARF frame from the .debug_frame section.
116 */
117static Dwarf_Frame *get_dwarf_frame(Dwfl_Module *mod, Dwarf_Addr pc)
118{
119 Dwarf_CFI *cfi;
120 Dwarf_Addr bias;
121 Dwarf_Frame *frame;
122 int result;
123
124 cfi = dwfl_module_dwarf_cfi(mod, &bias);
125 if (!cfi) {
126 pr_debug("%s(): no CFI - %s\n", __func__, dwfl_errmsg(-1));
127 return NULL;
128 }
129
130 result = dwarf_cfi_addrframe(cfi, pc, &frame);
131 if (result) {
132 pr_debug("%s(): %s\n", __func__, dwfl_errmsg(-1));
133 return NULL;
134 }
135
136 return frame;
137}
138
139/*
140 * Return:
141 * 0 if return address for the program counter @pc is on stack
142 * 1 if return address is in LR and no new stack frame was allocated
143 * 2 if return address is in LR and a new frame was allocated (but not
144 * yet used)
145 * -1 in case of errors
146 */
147static int check_return_addr(const char *exec_file, Dwarf_Addr pc)
148{
149 int rc = -1;
150 Dwfl *dwfl;
151 Dwfl_Module *mod;
152 Dwarf_Frame *frame;
153 int ra_regno;
154 Dwarf_Addr start = pc;
155 Dwarf_Addr end = pc;
156 bool signalp;
157
158 dwfl = dwfl_begin(&offline_callbacks);
159 if (!dwfl) {
160 pr_debug("dwfl_begin() failed: %s\n", dwarf_errmsg(-1));
161 return -1;
162 }
163
164 if (dwfl_report_offline(dwfl, "", exec_file, -1) == NULL) {
165 pr_debug("dwfl_report_offline() failed %s\n", dwarf_errmsg(-1));
166 goto out;
167 }
168
169 mod = dwfl_addrmodule(dwfl, pc);
170 if (!mod) {
171 pr_debug("dwfl_addrmodule() failed, %s\n", dwarf_errmsg(-1));
172 goto out;
173 }
174
175 /*
176 * To work with split debug info files (eg: glibc), check both
177 * .eh_frame and .debug_frame sections of the ELF header.
178 */
179 frame = get_eh_frame(mod, pc);
180 if (!frame) {
181 frame = get_dwarf_frame(mod, pc);
182 if (!frame)
183 goto out;
184 }
185
186 ra_regno = dwarf_frame_info(frame, &start, &end, &signalp);
187 if (ra_regno < 0) {
188 pr_debug("Return address register unavailable: %s\n",
189 dwarf_errmsg(-1));
190 goto out;
191 }
192
193 rc = check_return_reg(ra_regno, frame);
194
195out:
196 dwfl_end(dwfl);
197 return rc;
198}
199
200/*
201 * The callchain saved by the kernel always includes the link register (LR).
202 *
203 * 0: PERF_CONTEXT_USER
204 * 1: Program counter (Next instruction pointer)
205 * 2: LR value
206 * 3: Caller's caller
207 * 4: ...
208 *
209 * The value in LR is only needed when it holds a return address. If the
210 * return address is on the stack, we should ignore the LR value.
211 *
212 * Further, when the return address is in the LR, if a new frame was just
213 * allocated but the LR was not saved into it, then the LR contains the
214 * caller, slot 4: contains the caller's caller and the contents of slot 3:
215 * (chain->ips[3]) is undefined and must be ignored.
216 *
217 * Use DWARF debug information to determine if any entries need to be skipped.
218 *
219 * Return:
220 * index: of callchain entry that needs to be ignored (if any)
221 * -1 if no entry needs to be ignored or in case of errors
222 */
223int arch_skip_callchain_idx(struct machine *machine, struct thread *thread,
224 struct ip_callchain *chain)
225{
226 struct addr_location al;
227 struct dso *dso = NULL;
228 int rc;
229 u64 ip;
230 u64 skip_slot = -1;
231
232 if (chain->nr < 3)
233 return skip_slot;
234
235 ip = chain->ips[2];
236
237 thread__find_addr_location(thread, machine, PERF_RECORD_MISC_USER,
238 MAP__FUNCTION, ip, &al);
239
240 if (al.map)
241 dso = al.map->dso;
242
243 if (!dso) {
244 pr_debug("%" PRIx64 " dso is NULL\n", ip);
245 return skip_slot;
246 }
247
248 rc = check_return_addr(dso->long_name, ip);
249
250 pr_debug("DSO %s, nr %" PRIx64 ", ip 0x%" PRIx64 "rc %d\n",
251 dso->long_name, chain->nr, ip, rc);
252
253 if (rc == 0) {
254 /*
255 * Return address on stack. Ignore LR value in callchain
256 */
257 skip_slot = 2;
258 } else if (rc == 2) {
259 /*
260 * New frame allocated but return address still in LR.
261 * Ignore the caller's caller entry in callchain.
262 */
263 skip_slot = 3;
264 }
265 return skip_slot;
266}
diff --git a/tools/perf/arch/s390/Makefile b/tools/perf/arch/s390/Makefile
index 15130b50dfe3..798ac7379c5f 100644
--- a/tools/perf/arch/s390/Makefile
+++ b/tools/perf/arch/s390/Makefile
@@ -2,3 +2,6 @@ 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
6HAVE_KVM_STAT_SUPPORT := 1
7LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/kvm-stat.o
diff --git a/tools/perf/arch/s390/util/header.c b/tools/perf/arch/s390/util/header.c
new file mode 100644
index 000000000000..9fa6c3e5782c
--- /dev/null
+++ b/tools/perf/arch/s390/util/header.c
@@ -0,0 +1,28 @@
1/*
2 * Implementation of get_cpuid().
3 *
4 * Copyright 2014 IBM Corp.
5 * Author(s): Alexander Yarygin <yarygin@linux.vnet.ibm.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License (version 2 only)
9 * as published by the Free Software Foundation.
10 */
11
12#include <sys/types.h>
13#include <unistd.h>
14#include <stdio.h>
15#include <string.h>
16
17#include "../../util/header.h"
18
19int get_cpuid(char *buffer, size_t sz)
20{
21 const char *cpuid = "IBM/S390";
22
23 if (strlen(cpuid) + 1 > sz)
24 return -1;
25
26 strcpy(buffer, cpuid);
27 return 0;
28}
diff --git a/tools/perf/arch/s390/util/kvm-stat.c b/tools/perf/arch/s390/util/kvm-stat.c
new file mode 100644
index 000000000000..a5dbc07ec9dc
--- /dev/null
+++ b/tools/perf/arch/s390/util/kvm-stat.c
@@ -0,0 +1,105 @@
1/*
2 * Arch specific functions for perf kvm stat.
3 *
4 * Copyright 2014 IBM Corp.
5 * Author(s): Alexander Yarygin <yarygin@linux.vnet.ibm.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License (version 2 only)
9 * as published by the Free Software Foundation.
10 */
11
12#include "../../util/kvm-stat.h"
13#include <asm/kvm_perf.h>
14
15define_exit_reasons_table(sie_exit_reasons, sie_intercept_code);
16define_exit_reasons_table(sie_icpt_insn_codes, icpt_insn_codes);
17define_exit_reasons_table(sie_sigp_order_codes, sigp_order_codes);
18define_exit_reasons_table(sie_diagnose_codes, diagnose_codes);
19define_exit_reasons_table(sie_icpt_prog_codes, icpt_prog_codes);
20
21static void event_icpt_insn_get_key(struct perf_evsel *evsel,
22 struct perf_sample *sample,
23 struct event_key *key)
24{
25 unsigned long insn;
26
27 insn = perf_evsel__intval(evsel, sample, "instruction");
28 key->key = icpt_insn_decoder(insn);
29 key->exit_reasons = sie_icpt_insn_codes;
30}
31
32static void event_sigp_get_key(struct perf_evsel *evsel,
33 struct perf_sample *sample,
34 struct event_key *key)
35{
36 key->key = perf_evsel__intval(evsel, sample, "order_code");
37 key->exit_reasons = sie_sigp_order_codes;
38}
39
40static void event_diag_get_key(struct perf_evsel *evsel,
41 struct perf_sample *sample,
42 struct event_key *key)
43{
44 key->key = perf_evsel__intval(evsel, sample, "code");
45 key->exit_reasons = sie_diagnose_codes;
46}
47
48static void event_icpt_prog_get_key(struct perf_evsel *evsel,
49 struct perf_sample *sample,
50 struct event_key *key)
51{
52 key->key = perf_evsel__intval(evsel, sample, "code");
53 key->exit_reasons = sie_icpt_prog_codes;
54}
55
56static struct child_event_ops child_events[] = {
57 { .name = "kvm:kvm_s390_intercept_instruction",
58 .get_key = event_icpt_insn_get_key },
59 { .name = "kvm:kvm_s390_handle_sigp",
60 .get_key = event_sigp_get_key },
61 { .name = "kvm:kvm_s390_handle_diag",
62 .get_key = event_diag_get_key },
63 { .name = "kvm:kvm_s390_intercept_prog",
64 .get_key = event_icpt_prog_get_key },
65 { NULL, NULL },
66};
67
68static struct kvm_events_ops exit_events = {
69 .is_begin_event = exit_event_begin,
70 .is_end_event = exit_event_end,
71 .child_ops = child_events,
72 .decode_key = exit_event_decode_key,
73 .name = "VM-EXIT"
74};
75
76const char * const kvm_events_tp[] = {
77 "kvm:kvm_s390_sie_enter",
78 "kvm:kvm_s390_sie_exit",
79 "kvm:kvm_s390_intercept_instruction",
80 "kvm:kvm_s390_handle_sigp",
81 "kvm:kvm_s390_handle_diag",
82 "kvm:kvm_s390_intercept_prog",
83 NULL,
84};
85
86struct kvm_reg_events_ops kvm_reg_events_ops[] = {
87 { .name = "vmexit", .ops = &exit_events },
88 { NULL, NULL },
89};
90
91const char * const kvm_skip_events[] = {
92 "Wait state",
93 NULL,
94};
95
96int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid)
97{
98 if (strstr(cpuid, "IBM/S390")) {
99 kvm->exit_reasons = sie_exit_reasons;
100 kvm->exit_reasons_isa = "SIE";
101 } else
102 return -ENOTSUP;
103
104 return 0;
105}
diff --git a/tools/perf/arch/x86/Makefile b/tools/perf/arch/x86/Makefile
index 1641542e3636..9b21881db52f 100644
--- a/tools/perf/arch/x86/Makefile
+++ b/tools/perf/arch/x86/Makefile
@@ -15,3 +15,5 @@ endif
15LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o 15LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
16LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/tsc.o 16LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/tsc.o
17LIB_H += arch/$(ARCH)/util/tsc.h 17LIB_H += arch/$(ARCH)/util/tsc.h
18HAVE_KVM_STAT_SUPPORT := 1
19LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/kvm-stat.o
diff --git a/tools/perf/arch/x86/tests/dwarf-unwind.c b/tools/perf/arch/x86/tests/dwarf-unwind.c
index 9f89f899ccc7..d8bbf7ad1681 100644
--- a/tools/perf/arch/x86/tests/dwarf-unwind.c
+++ b/tools/perf/arch/x86/tests/dwarf-unwind.c
@@ -3,6 +3,7 @@
3#include "thread.h" 3#include "thread.h"
4#include "map.h" 4#include "map.h"
5#include "event.h" 5#include "event.h"
6#include "debug.h"
6#include "tests/tests.h" 7#include "tests/tests.h"
7 8
8#define STACK_SIZE 8192 9#define STACK_SIZE 8192
diff --git a/tools/perf/arch/x86/util/kvm-stat.c b/tools/perf/arch/x86/util/kvm-stat.c
new file mode 100644
index 000000000000..14e4e668fad7
--- /dev/null
+++ b/tools/perf/arch/x86/util/kvm-stat.c
@@ -0,0 +1,156 @@
1#include "../../util/kvm-stat.h"
2#include <asm/kvm_perf.h>
3
4define_exit_reasons_table(vmx_exit_reasons, VMX_EXIT_REASONS);
5define_exit_reasons_table(svm_exit_reasons, SVM_EXIT_REASONS);
6
7static struct kvm_events_ops exit_events = {
8 .is_begin_event = exit_event_begin,
9 .is_end_event = exit_event_end,
10 .decode_key = exit_event_decode_key,
11 .name = "VM-EXIT"
12};
13
14/*
15 * For the mmio events, we treat:
16 * the time of MMIO write: kvm_mmio(KVM_TRACE_MMIO_WRITE...) -> kvm_entry
17 * the time of MMIO read: kvm_exit -> kvm_mmio(KVM_TRACE_MMIO_READ...).
18 */
19static void mmio_event_get_key(struct perf_evsel *evsel, struct perf_sample *sample,
20 struct event_key *key)
21{
22 key->key = perf_evsel__intval(evsel, sample, "gpa");
23 key->info = perf_evsel__intval(evsel, sample, "type");
24}
25
26#define KVM_TRACE_MMIO_READ_UNSATISFIED 0
27#define KVM_TRACE_MMIO_READ 1
28#define KVM_TRACE_MMIO_WRITE 2
29
30static bool mmio_event_begin(struct perf_evsel *evsel,
31 struct perf_sample *sample, struct event_key *key)
32{
33 /* MMIO read begin event in kernel. */
34 if (kvm_exit_event(evsel))
35 return true;
36
37 /* MMIO write begin event in kernel. */
38 if (!strcmp(evsel->name, "kvm:kvm_mmio") &&
39 perf_evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_WRITE) {
40 mmio_event_get_key(evsel, sample, key);
41 return true;
42 }
43
44 return false;
45}
46
47static bool mmio_event_end(struct perf_evsel *evsel, struct perf_sample *sample,
48 struct event_key *key)
49{
50 /* MMIO write end event in kernel. */
51 if (kvm_entry_event(evsel))
52 return true;
53
54 /* MMIO read end event in kernel.*/
55 if (!strcmp(evsel->name, "kvm:kvm_mmio") &&
56 perf_evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_READ) {
57 mmio_event_get_key(evsel, sample, key);
58 return true;
59 }
60
61 return false;
62}
63
64static void mmio_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
65 struct event_key *key,
66 char *decode)
67{
68 scnprintf(decode, DECODE_STR_LEN, "%#lx:%s",
69 (unsigned long)key->key,
70 key->info == KVM_TRACE_MMIO_WRITE ? "W" : "R");
71}
72
73static struct kvm_events_ops mmio_events = {
74 .is_begin_event = mmio_event_begin,
75 .is_end_event = mmio_event_end,
76 .decode_key = mmio_event_decode_key,
77 .name = "MMIO Access"
78};
79
80 /* The time of emulation pio access is from kvm_pio to kvm_entry. */
81static void ioport_event_get_key(struct perf_evsel *evsel,
82 struct perf_sample *sample,
83 struct event_key *key)
84{
85 key->key = perf_evsel__intval(evsel, sample, "port");
86 key->info = perf_evsel__intval(evsel, sample, "rw");
87}
88
89static bool ioport_event_begin(struct perf_evsel *evsel,
90 struct perf_sample *sample,
91 struct event_key *key)
92{
93 if (!strcmp(evsel->name, "kvm:kvm_pio")) {
94 ioport_event_get_key(evsel, sample, key);
95 return true;
96 }
97
98 return false;
99}
100
101static bool ioport_event_end(struct perf_evsel *evsel,
102 struct perf_sample *sample __maybe_unused,
103 struct event_key *key __maybe_unused)
104{
105 return kvm_entry_event(evsel);
106}
107
108static void ioport_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
109 struct event_key *key,
110 char *decode)
111{
112 scnprintf(decode, DECODE_STR_LEN, "%#llx:%s",
113 (unsigned long long)key->key,
114 key->info ? "POUT" : "PIN");
115}
116
117static struct kvm_events_ops ioport_events = {
118 .is_begin_event = ioport_event_begin,
119 .is_end_event = ioport_event_end,
120 .decode_key = ioport_event_decode_key,
121 .name = "IO Port Access"
122};
123
124const char * const kvm_events_tp[] = {
125 "kvm:kvm_entry",
126 "kvm:kvm_exit",
127 "kvm:kvm_mmio",
128 "kvm:kvm_pio",
129 NULL,
130};
131
132struct kvm_reg_events_ops kvm_reg_events_ops[] = {
133 { .name = "vmexit", .ops = &exit_events },
134 { .name = "mmio", .ops = &mmio_events },
135 { .name = "ioport", .ops = &ioport_events },
136 { NULL, NULL },
137};
138
139const char * const kvm_skip_events[] = {
140 "HLT",
141 NULL,
142};
143
144int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid)
145{
146 if (strstr(cpuid, "Intel")) {
147 kvm->exit_reasons = vmx_exit_reasons;
148 kvm->exit_reasons_isa = "VMX";
149 } else if (strstr(cpuid, "AMD")) {
150 kvm->exit_reasons = svm_exit_reasons;
151 kvm->exit_reasons_isa = "SVM";
152 } else
153 return -ENOTSUP;
154
155 return 0;
156}
diff --git a/tools/perf/arch/x86/util/tsc.c b/tools/perf/arch/x86/util/tsc.c
index 40021fa3129b..fd2868490d00 100644
--- a/tools/perf/arch/x86/util/tsc.c
+++ b/tools/perf/arch/x86/util/tsc.c
@@ -6,29 +6,9 @@
6#include "../../perf.h" 6#include "../../perf.h"
7#include <linux/types.h> 7#include <linux/types.h>
8#include "../../util/debug.h" 8#include "../../util/debug.h"
9#include "../../util/tsc.h"
9#include "tsc.h" 10#include "tsc.h"
10 11
11u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc)
12{
13 u64 t, quot, rem;
14
15 t = ns - tc->time_zero;
16 quot = t / tc->time_mult;
17 rem = t % tc->time_mult;
18 return (quot << tc->time_shift) +
19 (rem << tc->time_shift) / tc->time_mult;
20}
21
22u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc)
23{
24 u64 quot, rem;
25
26 quot = cyc >> tc->time_shift;
27 rem = cyc & ((1 << tc->time_shift) - 1);
28 return tc->time_zero + quot * tc->time_mult +
29 ((rem * tc->time_mult) >> tc->time_shift);
30}
31
32int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc, 12int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
33 struct perf_tsc_conversion *tc) 13 struct perf_tsc_conversion *tc)
34{ 14{
@@ -57,3 +37,12 @@ int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
57 37
58 return 0; 38 return 0;
59} 39}
40
41u64 rdtsc(void)
42{
43 unsigned int low, high;
44
45 asm volatile("rdtsc" : "=a" (low), "=d" (high));
46
47 return low | ((u64)high) << 32;
48}
diff --git a/tools/perf/arch/x86/util/tsc.h b/tools/perf/arch/x86/util/tsc.h
index 2affe0366b59..2edc4d31065c 100644
--- a/tools/perf/arch/x86/util/tsc.h
+++ b/tools/perf/arch/x86/util/tsc.h
@@ -14,7 +14,4 @@ struct perf_event_mmap_page;
14int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc, 14int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
15 struct perf_tsc_conversion *tc); 15 struct perf_tsc_conversion *tc);
16 16
17u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc);
18u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc);
19
20#endif /* TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ */ 17#endif /* TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ */
diff --git a/tools/perf/arch/x86/util/unwind-libunwind.c b/tools/perf/arch/x86/util/unwind-libunwind.c
index 3261f68c6a7c..db25e93d989c 100644
--- a/tools/perf/arch/x86/util/unwind-libunwind.c
+++ b/tools/perf/arch/x86/util/unwind-libunwind.c
@@ -3,6 +3,7 @@
3#include <libunwind.h> 3#include <libunwind.h>
4#include "perf_regs.h" 4#include "perf_regs.h"
5#include "../../util/unwind.h" 5#include "../../util/unwind.h"
6#include "../../util/debug.h"
6 7
7#ifdef HAVE_ARCH_X86_64_SUPPORT 8#ifdef HAVE_ARCH_X86_64_SUPPORT
8int libunwind__arch_reg_id(int regnum) 9int libunwind__arch_reg_id(int regnum)
diff --git a/tools/perf/bench/bench.h b/tools/perf/bench/bench.h
index eba46709b279..3c4dd44d45cb 100644
--- a/tools/perf/bench/bench.h
+++ b/tools/perf/bench/bench.h
@@ -43,5 +43,6 @@ extern int bench_futex_requeue(int argc, const char **argv, const char *prefix);
43#define BENCH_FORMAT_UNKNOWN -1 43#define BENCH_FORMAT_UNKNOWN -1
44 44
45extern int bench_format; 45extern int bench_format;
46extern unsigned int bench_repeat;
46 47
47#endif 48#endif
diff --git a/tools/perf/bench/futex-requeue.c b/tools/perf/bench/futex-requeue.c
index a16255876f1d..732403bfd31a 100644
--- a/tools/perf/bench/futex-requeue.c
+++ b/tools/perf/bench/futex-requeue.c
@@ -29,13 +29,6 @@ static u_int32_t futex1 = 0, futex2 = 0;
29 */ 29 */
30static unsigned int nrequeue = 1; 30static unsigned int nrequeue = 1;
31 31
32/*
33 * There can be significant variance from run to run,
34 * the more repeats, the more exact the overall avg and
35 * the better idea of the futex latency.
36 */
37static unsigned int repeat = 10;
38
39static pthread_t *worker; 32static pthread_t *worker;
40static bool done = 0, silent = 0; 33static bool done = 0, silent = 0;
41static pthread_mutex_t thread_lock; 34static pthread_mutex_t thread_lock;
@@ -46,7 +39,6 @@ static unsigned int ncpus, threads_starting, nthreads = 0;
46static const struct option options[] = { 39static const struct option options[] = {
47 OPT_UINTEGER('t', "threads", &nthreads, "Specify amount of threads"), 40 OPT_UINTEGER('t', "threads", &nthreads, "Specify amount of threads"),
48 OPT_UINTEGER('q', "nrequeue", &nrequeue, "Specify amount of threads to requeue at once"), 41 OPT_UINTEGER('q', "nrequeue", &nrequeue, "Specify amount of threads to requeue at once"),
49 OPT_UINTEGER('r', "repeat", &repeat, "Specify amount of times to repeat the run"),
50 OPT_BOOLEAN( 's', "silent", &silent, "Silent mode: do not display data/details"), 42 OPT_BOOLEAN( 's', "silent", &silent, "Silent mode: do not display data/details"),
51 OPT_END() 43 OPT_END()
52}; 44};
@@ -146,7 +138,7 @@ int bench_futex_requeue(int argc, const char **argv,
146 pthread_cond_init(&thread_parent, NULL); 138 pthread_cond_init(&thread_parent, NULL);
147 pthread_cond_init(&thread_worker, NULL); 139 pthread_cond_init(&thread_worker, NULL);
148 140
149 for (j = 0; j < repeat && !done; j++) { 141 for (j = 0; j < bench_repeat && !done; j++) {
150 unsigned int nrequeued = 0; 142 unsigned int nrequeued = 0;
151 struct timeval start, end, runtime; 143 struct timeval start, end, runtime;
152 144
diff --git a/tools/perf/bench/futex-wake.c b/tools/perf/bench/futex-wake.c
index d096169b161e..50022cbce87e 100644
--- a/tools/perf/bench/futex-wake.c
+++ b/tools/perf/bench/futex-wake.c
@@ -30,15 +30,8 @@ static u_int32_t futex1 = 0;
30 */ 30 */
31static unsigned int nwakes = 1; 31static unsigned int nwakes = 1;
32 32
33/*
34 * There can be significant variance from run to run,
35 * the more repeats, the more exact the overall avg and
36 * the better idea of the futex latency.
37 */
38static unsigned int repeat = 10;
39
40pthread_t *worker; 33pthread_t *worker;
41static bool done = 0, silent = 0; 34static bool done = false, silent = false;
42static pthread_mutex_t thread_lock; 35static pthread_mutex_t thread_lock;
43static pthread_cond_t thread_parent, thread_worker; 36static pthread_cond_t thread_parent, thread_worker;
44static struct stats waketime_stats, wakeup_stats; 37static struct stats waketime_stats, wakeup_stats;
@@ -47,7 +40,6 @@ static unsigned int ncpus, threads_starting, nthreads = 0;
47static const struct option options[] = { 40static const struct option options[] = {
48 OPT_UINTEGER('t', "threads", &nthreads, "Specify amount of threads"), 41 OPT_UINTEGER('t', "threads", &nthreads, "Specify amount of threads"),
49 OPT_UINTEGER('w', "nwakes", &nwakes, "Specify amount of threads to wake at once"), 42 OPT_UINTEGER('w', "nwakes", &nwakes, "Specify amount of threads to wake at once"),
50 OPT_UINTEGER('r', "repeat", &repeat, "Specify amount of times to repeat the run"),
51 OPT_BOOLEAN( 's', "silent", &silent, "Silent mode: do not display data/details"), 43 OPT_BOOLEAN( 's', "silent", &silent, "Silent mode: do not display data/details"),
52 OPT_END() 44 OPT_END()
53}; 45};
@@ -149,7 +141,7 @@ int bench_futex_wake(int argc, const char **argv,
149 pthread_cond_init(&thread_parent, NULL); 141 pthread_cond_init(&thread_parent, NULL);
150 pthread_cond_init(&thread_worker, NULL); 142 pthread_cond_init(&thread_worker, NULL);
151 143
152 for (j = 0; j < repeat && !done; j++) { 144 for (j = 0; j < bench_repeat && !done; j++) {
153 unsigned int nwoken = 0; 145 unsigned int nwoken = 0;
154 struct timeval start, end, runtime; 146 struct timeval start, end, runtime;
155 147
diff --git a/tools/perf/bench/mem-memcpy.c b/tools/perf/bench/mem-memcpy.c
index 5ce71d3b72cf..2465141b554b 100644
--- a/tools/perf/bench/mem-memcpy.c
+++ b/tools/perf/bench/mem-memcpy.c
@@ -10,6 +10,7 @@
10#include "../util/util.h" 10#include "../util/util.h"
11#include "../util/parse-options.h" 11#include "../util/parse-options.h"
12#include "../util/header.h" 12#include "../util/header.h"
13#include "../util/cloexec.h"
13#include "bench.h" 14#include "bench.h"
14#include "mem-memcpy-arch.h" 15#include "mem-memcpy-arch.h"
15 16
@@ -83,7 +84,8 @@ static struct perf_event_attr cycle_attr = {
83 84
84static void init_cycle(void) 85static void init_cycle(void)
85{ 86{
86 cycle_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1, 0); 87 cycle_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1,
88 perf_event_open_cloexec_flag());
87 89
88 if (cycle_fd < 0 && errno == ENOSYS) 90 if (cycle_fd < 0 && errno == ENOSYS)
89 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); 91 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
@@ -189,6 +191,11 @@ int bench_mem_memcpy(int argc, const char **argv,
189 argc = parse_options(argc, argv, options, 191 argc = parse_options(argc, argv, options,
190 bench_mem_memcpy_usage, 0); 192 bench_mem_memcpy_usage, 0);
191 193
194 if (no_prefault && only_prefault) {
195 fprintf(stderr, "Invalid options: -o and -n are mutually exclusive\n");
196 return 1;
197 }
198
192 if (use_cycle) 199 if (use_cycle)
193 init_cycle(); 200 init_cycle();
194 201
diff --git a/tools/perf/bench/mem-memset.c b/tools/perf/bench/mem-memset.c
index 9af79d2b18e5..75fc3e65fb2a 100644
--- a/tools/perf/bench/mem-memset.c
+++ b/tools/perf/bench/mem-memset.c
@@ -10,6 +10,7 @@
10#include "../util/util.h" 10#include "../util/util.h"
11#include "../util/parse-options.h" 11#include "../util/parse-options.h"
12#include "../util/header.h" 12#include "../util/header.h"
13#include "../util/cloexec.h"
13#include "bench.h" 14#include "bench.h"
14#include "mem-memset-arch.h" 15#include "mem-memset-arch.h"
15 16
@@ -83,7 +84,8 @@ static struct perf_event_attr cycle_attr = {
83 84
84static void init_cycle(void) 85static void init_cycle(void)
85{ 86{
86 cycle_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1, 0); 87 cycle_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1,
88 perf_event_open_cloexec_flag());
87 89
88 if (cycle_fd < 0 && errno == ENOSYS) 90 if (cycle_fd < 0 && errno == ENOSYS)
89 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); 91 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
@@ -181,6 +183,11 @@ int bench_mem_memset(int argc, const char **argv,
181 argc = parse_options(argc, argv, options, 183 argc = parse_options(argc, argv, options,
182 bench_mem_memset_usage, 0); 184 bench_mem_memset_usage, 0);
183 185
186 if (no_prefault && only_prefault) {
187 fprintf(stderr, "Invalid options: -o and -n are mutually exclusive\n");
188 return 1;
189 }
190
184 if (use_cycle) 191 if (use_cycle)
185 init_cycle(); 192 init_cycle();
186 193
diff --git a/tools/perf/bench/sched-messaging.c b/tools/perf/bench/sched-messaging.c
index cc1190a0849b..52a56599a543 100644
--- a/tools/perf/bench/sched-messaging.c
+++ b/tools/perf/bench/sched-messaging.c
@@ -28,6 +28,7 @@
28#include <sys/time.h> 28#include <sys/time.h>
29#include <sys/poll.h> 29#include <sys/poll.h>
30#include <limits.h> 30#include <limits.h>
31#include <err.h>
31 32
32#define DATASIZE 100 33#define DATASIZE 100
33 34
@@ -50,12 +51,6 @@ struct receiver_context {
50 int wakefd; 51 int wakefd;
51}; 52};
52 53
53static void barf(const char *msg)
54{
55 fprintf(stderr, "%s (error: %s)\n", msg, strerror(errno));
56 exit(1);
57}
58
59static void fdpair(int fds[2]) 54static void fdpair(int fds[2])
60{ 55{
61 if (use_pipes) { 56 if (use_pipes) {
@@ -66,7 +61,7 @@ static void fdpair(int fds[2])
66 return; 61 return;
67 } 62 }
68 63
69 barf(use_pipes ? "pipe()" : "socketpair()"); 64 err(EXIT_FAILURE, use_pipes ? "pipe()" : "socketpair()");
70} 65}
71 66
72/* Block until we're ready to go */ 67/* Block until we're ready to go */
@@ -77,11 +72,11 @@ static void ready(int ready_out, int wakefd)
77 72
78 /* Tell them we're ready. */ 73 /* Tell them we're ready. */
79 if (write(ready_out, &dummy, 1) != 1) 74 if (write(ready_out, &dummy, 1) != 1)
80 barf("CLIENT: ready write"); 75 err(EXIT_FAILURE, "CLIENT: ready write");
81 76
82 /* Wait for "GO" signal */ 77 /* Wait for "GO" signal */
83 if (poll(&pollfd, 1, -1) != 1) 78 if (poll(&pollfd, 1, -1) != 1)
84 barf("poll"); 79 err(EXIT_FAILURE, "poll");
85} 80}
86 81
87/* Sender sprays loops messages down each file descriptor */ 82/* Sender sprays loops messages down each file descriptor */
@@ -101,7 +96,7 @@ again:
101 ret = write(ctx->out_fds[j], data + done, 96 ret = write(ctx->out_fds[j], data + done,
102 sizeof(data)-done); 97 sizeof(data)-done);
103 if (ret < 0) 98 if (ret < 0)
104 barf("SENDER: write"); 99 err(EXIT_FAILURE, "SENDER: write");
105 done += ret; 100 done += ret;
106 if (done < DATASIZE) 101 if (done < DATASIZE)
107 goto again; 102 goto again;
@@ -131,7 +126,7 @@ static void *receiver(struct receiver_context* ctx)
131again: 126again:
132 ret = read(ctx->in_fds[0], data + done, DATASIZE - done); 127 ret = read(ctx->in_fds[0], data + done, DATASIZE - done);
133 if (ret < 0) 128 if (ret < 0)
134 barf("SERVER: read"); 129 err(EXIT_FAILURE, "SERVER: read");
135 done += ret; 130 done += ret;
136 if (done < DATASIZE) 131 if (done < DATASIZE)
137 goto again; 132 goto again;
@@ -144,14 +139,14 @@ static pthread_t create_worker(void *ctx, void *(*func)(void *))
144{ 139{
145 pthread_attr_t attr; 140 pthread_attr_t attr;
146 pthread_t childid; 141 pthread_t childid;
147 int err; 142 int ret;
148 143
149 if (!thread_mode) { 144 if (!thread_mode) {
150 /* process mode */ 145 /* process mode */
151 /* Fork the receiver. */ 146 /* Fork the receiver. */
152 switch (fork()) { 147 switch (fork()) {
153 case -1: 148 case -1:
154 barf("fork()"); 149 err(EXIT_FAILURE, "fork()");
155 break; 150 break;
156 case 0: 151 case 0:
157 (*func) (ctx); 152 (*func) (ctx);
@@ -165,19 +160,17 @@ static pthread_t create_worker(void *ctx, void *(*func)(void *))
165 } 160 }
166 161
167 if (pthread_attr_init(&attr) != 0) 162 if (pthread_attr_init(&attr) != 0)
168 barf("pthread_attr_init:"); 163 err(EXIT_FAILURE, "pthread_attr_init:");
169 164
170#ifndef __ia64__ 165#ifndef __ia64__
171 if (pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN) != 0) 166 if (pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN) != 0)
172 barf("pthread_attr_setstacksize"); 167 err(EXIT_FAILURE, "pthread_attr_setstacksize");
173#endif 168#endif
174 169
175 err = pthread_create(&childid, &attr, func, ctx); 170 ret = pthread_create(&childid, &attr, func, ctx);
176 if (err != 0) { 171 if (ret != 0)
177 fprintf(stderr, "pthread_create failed: %s (%d)\n", 172 err(EXIT_FAILURE, "pthread_create failed");
178 strerror(err), err); 173
179 exit(-1);
180 }
181 return childid; 174 return childid;
182} 175}
183 176
@@ -207,14 +200,14 @@ static unsigned int group(pthread_t *pth,
207 + num_fds * sizeof(int)); 200 + num_fds * sizeof(int));
208 201
209 if (!snd_ctx) 202 if (!snd_ctx)
210 barf("malloc()"); 203 err(EXIT_FAILURE, "malloc()");
211 204
212 for (i = 0; i < num_fds; i++) { 205 for (i = 0; i < num_fds; i++) {
213 int fds[2]; 206 int fds[2];
214 struct receiver_context *ctx = malloc(sizeof(*ctx)); 207 struct receiver_context *ctx = malloc(sizeof(*ctx));
215 208
216 if (!ctx) 209 if (!ctx)
217 barf("malloc()"); 210 err(EXIT_FAILURE, "malloc()");
218 211
219 212
220 /* Create the pipe between client and server */ 213 /* Create the pipe between client and server */
@@ -281,7 +274,7 @@ int bench_sched_messaging(int argc, const char **argv,
281 274
282 pth_tab = malloc(num_fds * 2 * num_groups * sizeof(pthread_t)); 275 pth_tab = malloc(num_fds * 2 * num_groups * sizeof(pthread_t));
283 if (!pth_tab) 276 if (!pth_tab)
284 barf("main:malloc()"); 277 err(EXIT_FAILURE, "main:malloc()");
285 278
286 fdpair(readyfds); 279 fdpair(readyfds);
287 fdpair(wakefds); 280 fdpair(wakefds);
@@ -294,13 +287,13 @@ int bench_sched_messaging(int argc, const char **argv,
294 /* Wait for everyone to be ready */ 287 /* Wait for everyone to be ready */
295 for (i = 0; i < total_children; i++) 288 for (i = 0; i < total_children; i++)
296 if (read(readyfds[0], &dummy, 1) != 1) 289 if (read(readyfds[0], &dummy, 1) != 1)
297 barf("Reading for readyfds"); 290 err(EXIT_FAILURE, "Reading for readyfds");
298 291
299 gettimeofday(&start, NULL); 292 gettimeofday(&start, NULL);
300 293
301 /* Kick them off */ 294 /* Kick them off */
302 if (write(wakefds[1], &dummy, 1) != 1) 295 if (write(wakefds[1], &dummy, 1) != 1)
303 barf("Writing to start them"); 296 err(EXIT_FAILURE, "Writing to start them");
304 297
305 /* Reap them all */ 298 /* Reap them all */
306 for (i = 0; i < total_children; i++) 299 for (i = 0; i < total_children; i++)
@@ -332,5 +325,7 @@ int bench_sched_messaging(int argc, const char **argv,
332 break; 325 break;
333 } 326 }
334 327
328 free(pth_tab);
329
335 return 0; 330 return 0;
336} 331}
diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c
index 1e6e77710545..b9a56fa83330 100644
--- a/tools/perf/builtin-bench.c
+++ b/tools/perf/builtin-bench.c
@@ -104,9 +104,11 @@ static const char *bench_format_str;
104 104
105/* Output/formatting style, exported to benchmark modules: */ 105/* Output/formatting style, exported to benchmark modules: */
106int bench_format = BENCH_FORMAT_DEFAULT; 106int bench_format = BENCH_FORMAT_DEFAULT;
107unsigned int bench_repeat = 10; /* default number of times to repeat the run */
107 108
108static const struct option bench_options[] = { 109static const struct option bench_options[] = {
109 OPT_STRING('f', "format", &bench_format_str, "default", "Specify format style"), 110 OPT_STRING('f', "format", &bench_format_str, "default", "Specify format style"),
111 OPT_UINTEGER('r', "repeat", &bench_repeat, "Specify amount of times to repeat the run"),
110 OPT_END() 112 OPT_END()
111}; 113};
112 114
@@ -226,6 +228,11 @@ int cmd_bench(int argc, const char **argv, const char *prefix __maybe_unused)
226 goto end; 228 goto end;
227 } 229 }
228 230
231 if (bench_repeat == 0) {
232 printf("Invalid repeat option: Must specify a positive value\n");
233 goto end;
234 }
235
229 if (argc < 1) { 236 if (argc < 1) {
230 print_usage(); 237 print_usage();
231 goto end; 238 goto end;
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c
index b22dbb16f877..2a2c78f80876 100644
--- a/tools/perf/builtin-buildid-cache.c
+++ b/tools/perf/builtin-buildid-cache.c
@@ -125,7 +125,8 @@ static int build_id_cache__kcore_existing(const char *from_dir, char *to_dir,
125 return ret; 125 return ret;
126} 126}
127 127
128static int build_id_cache__add_kcore(const char *filename, const char *debugdir) 128static int build_id_cache__add_kcore(const char *filename, const char *debugdir,
129 bool force)
129{ 130{
130 char dir[32], sbuildid[BUILD_ID_SIZE * 2 + 1]; 131 char dir[32], sbuildid[BUILD_ID_SIZE * 2 + 1];
131 char from_dir[PATH_MAX], to_dir[PATH_MAX]; 132 char from_dir[PATH_MAX], to_dir[PATH_MAX];
@@ -144,7 +145,8 @@ static int build_id_cache__add_kcore(const char *filename, const char *debugdir)
144 scnprintf(to_dir, sizeof(to_dir), "%s/[kernel.kcore]/%s", 145 scnprintf(to_dir, sizeof(to_dir), "%s/[kernel.kcore]/%s",
145 debugdir, sbuildid); 146 debugdir, sbuildid);
146 147
147 if (!build_id_cache__kcore_existing(from_dir, to_dir, sizeof(to_dir))) { 148 if (!force &&
149 !build_id_cache__kcore_existing(from_dir, to_dir, sizeof(to_dir))) {
148 pr_debug("same kcore found in %s\n", to_dir); 150 pr_debug("same kcore found in %s\n", to_dir);
149 return 0; 151 return 0;
150 } 152 }
@@ -389,7 +391,7 @@ int cmd_buildid_cache(int argc, const char **argv,
389 } 391 }
390 392
391 if (kcore_filename && 393 if (kcore_filename &&
392 build_id_cache__add_kcore(kcore_filename, debugdir)) 394 build_id_cache__add_kcore(kcore_filename, debugdir, force))
393 pr_warning("Couldn't add %s\n", kcore_filename); 395 pr_warning("Couldn't add %s\n", kcore_filename);
394 396
395 return ret; 397 return ret;
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c
index c99e0de7e54a..66e12f55c052 100644
--- a/tools/perf/builtin-evlist.c
+++ b/tools/perf/builtin-evlist.c
@@ -15,6 +15,7 @@
15#include "util/parse-options.h" 15#include "util/parse-options.h"
16#include "util/session.h" 16#include "util/session.h"
17#include "util/data.h" 17#include "util/data.h"
18#include "util/debug.h"
18 19
19static int __cmd_evlist(const char *file_name, struct perf_attr_details *details) 20static int __cmd_evlist(const char *file_name, struct perf_attr_details *details)
20{ 21{
diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c
index 178b88ae3d2f..0384d930480b 100644
--- a/tools/perf/builtin-help.c
+++ b/tools/perf/builtin-help.c
@@ -11,6 +11,7 @@
11#include "util/parse-options.h" 11#include "util/parse-options.h"
12#include "util/run-command.h" 12#include "util/run-command.h"
13#include "util/help.h" 13#include "util/help.h"
14#include "util/debug.h"
14 15
15static struct man_viewer_list { 16static struct man_viewer_list {
16 struct man_viewer_list *next; 17 struct man_viewer_list *next;
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 16c7c11ad06e..9a02807387d6 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -389,6 +389,9 @@ static int __cmd_inject(struct perf_inject *inject)
389 ret = perf_session__process_events(session, &inject->tool); 389 ret = perf_session__process_events(session, &inject->tool);
390 390
391 if (!file_out->is_pipe) { 391 if (!file_out->is_pipe) {
392 if (inject->build_ids)
393 perf_header__set_feat(&session->header,
394 HEADER_BUILD_ID);
392 session->header.data_size = inject->bytes_written; 395 session->header.data_size = inject->bytes_written;
393 perf_session__write_header(session, session->evlist, file_out->fd, true); 396 perf_session__write_header(session, session->evlist, file_out->fd, true);
394 } 397 }
@@ -436,6 +439,8 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
436 "where and how long tasks slept"), 439 "where and how long tasks slept"),
437 OPT_INCR('v', "verbose", &verbose, 440 OPT_INCR('v', "verbose", &verbose,
438 "be more verbose (show build ids, etc)"), 441 "be more verbose (show build ids, etc)"),
442 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file",
443 "kallsyms pathname"),
439 OPT_END() 444 OPT_END()
440 }; 445 };
441 const char * const inject_usage[] = { 446 const char * const inject_usage[] = {
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index 0f1e5a2f6ad7..43367eb00510 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -29,114 +29,25 @@
29#include <pthread.h> 29#include <pthread.h>
30#include <math.h> 30#include <math.h>
31 31
32#if defined(__i386__) || defined(__x86_64__) 32#ifdef HAVE_KVM_STAT_SUPPORT
33#include <asm/svm.h> 33#include <asm/kvm_perf.h>
34#include <asm/vmx.h> 34#include "util/kvm-stat.h"
35#include <asm/kvm.h>
36
37struct event_key {
38 #define INVALID_KEY (~0ULL)
39 u64 key;
40 int info;
41};
42
43struct kvm_event_stats {
44 u64 time;
45 struct stats stats;
46};
47
48struct kvm_event {
49 struct list_head hash_entry;
50 struct rb_node rb;
51
52 struct event_key key;
53
54 struct kvm_event_stats total;
55
56 #define DEFAULT_VCPU_NUM 8
57 int max_vcpu;
58 struct kvm_event_stats *vcpu;
59};
60
61typedef int (*key_cmp_fun)(struct kvm_event*, struct kvm_event*, int);
62
63struct kvm_event_key {
64 const char *name;
65 key_cmp_fun key;
66};
67
68
69struct perf_kvm_stat;
70
71struct kvm_events_ops {
72 bool (*is_begin_event)(struct perf_evsel *evsel,
73 struct perf_sample *sample,
74 struct event_key *key);
75 bool (*is_end_event)(struct perf_evsel *evsel,
76 struct perf_sample *sample, struct event_key *key);
77 void (*decode_key)(struct perf_kvm_stat *kvm, struct event_key *key,
78 char decode[20]);
79 const char *name;
80};
81
82struct exit_reasons_table {
83 unsigned long exit_code;
84 const char *reason;
85};
86 35
87#define EVENTS_BITS 12 36void exit_event_get_key(struct perf_evsel *evsel,
88#define EVENTS_CACHE_SIZE (1UL << EVENTS_BITS) 37 struct perf_sample *sample,
89 38 struct event_key *key)
90struct perf_kvm_stat {
91 struct perf_tool tool;
92 struct record_opts opts;
93 struct perf_evlist *evlist;
94 struct perf_session *session;
95
96 const char *file_name;
97 const char *report_event;
98 const char *sort_key;
99 int trace_vcpu;
100
101 struct exit_reasons_table *exit_reasons;
102 int exit_reasons_size;
103 const char *exit_reasons_isa;
104
105 struct kvm_events_ops *events_ops;
106 key_cmp_fun compare;
107 struct list_head kvm_events_cache[EVENTS_CACHE_SIZE];
108
109 u64 total_time;
110 u64 total_count;
111 u64 lost_events;
112 u64 duration;
113
114 const char *pid_str;
115 struct intlist *pid_list;
116
117 struct rb_root result;
118
119 int timerfd;
120 unsigned int display_time;
121 bool live;
122};
123
124
125static void exit_event_get_key(struct perf_evsel *evsel,
126 struct perf_sample *sample,
127 struct event_key *key)
128{ 39{
129 key->info = 0; 40 key->info = 0;
130 key->key = perf_evsel__intval(evsel, sample, "exit_reason"); 41 key->key = perf_evsel__intval(evsel, sample, KVM_EXIT_REASON);
131} 42}
132 43
133static bool kvm_exit_event(struct perf_evsel *evsel) 44bool kvm_exit_event(struct perf_evsel *evsel)
134{ 45{
135 return !strcmp(evsel->name, "kvm:kvm_exit"); 46 return !strcmp(evsel->name, KVM_EXIT_TRACE);
136} 47}
137 48
138static bool exit_event_begin(struct perf_evsel *evsel, 49bool exit_event_begin(struct perf_evsel *evsel,
139 struct perf_sample *sample, struct event_key *key) 50 struct perf_sample *sample, struct event_key *key)
140{ 51{
141 if (kvm_exit_event(evsel)) { 52 if (kvm_exit_event(evsel)) {
142 exit_event_get_key(evsel, sample, key); 53 exit_event_get_key(evsel, sample, key);
@@ -146,32 +57,23 @@ static bool exit_event_begin(struct perf_evsel *evsel,
146 return false; 57 return false;
147} 58}
148 59
149static bool kvm_entry_event(struct perf_evsel *evsel) 60bool kvm_entry_event(struct perf_evsel *evsel)
150{ 61{
151 return !strcmp(evsel->name, "kvm:kvm_entry"); 62 return !strcmp(evsel->name, KVM_ENTRY_TRACE);
152} 63}
153 64
154static bool exit_event_end(struct perf_evsel *evsel, 65bool exit_event_end(struct perf_evsel *evsel,
155 struct perf_sample *sample __maybe_unused, 66 struct perf_sample *sample __maybe_unused,
156 struct event_key *key __maybe_unused) 67 struct event_key *key __maybe_unused)
157{ 68{
158 return kvm_entry_event(evsel); 69 return kvm_entry_event(evsel);
159} 70}
160 71
161static struct exit_reasons_table vmx_exit_reasons[] = { 72static const char *get_exit_reason(struct perf_kvm_stat *kvm,
162 VMX_EXIT_REASONS 73 struct exit_reasons_table *tbl,
163}; 74 u64 exit_code)
164
165static struct exit_reasons_table svm_exit_reasons[] = {
166 SVM_EXIT_REASONS
167};
168
169static const char *get_exit_reason(struct perf_kvm_stat *kvm, u64 exit_code)
170{ 75{
171 int i = kvm->exit_reasons_size; 76 while (tbl->reason != NULL) {
172 struct exit_reasons_table *tbl = kvm->exit_reasons;
173
174 while (i--) {
175 if (tbl->exit_code == exit_code) 77 if (tbl->exit_code == exit_code)
176 return tbl->reason; 78 return tbl->reason;
177 tbl++; 79 tbl++;
@@ -182,148 +84,30 @@ static const char *get_exit_reason(struct perf_kvm_stat *kvm, u64 exit_code)
182 return "UNKNOWN"; 84 return "UNKNOWN";
183} 85}
184 86
185static void exit_event_decode_key(struct perf_kvm_stat *kvm, 87void exit_event_decode_key(struct perf_kvm_stat *kvm,
186 struct event_key *key, 88 struct event_key *key,
187 char decode[20]) 89 char *decode)
188{ 90{
189 const char *exit_reason = get_exit_reason(kvm, key->key); 91 const char *exit_reason = get_exit_reason(kvm, key->exit_reasons,
92 key->key);
190 93
191 scnprintf(decode, 20, "%s", exit_reason); 94 scnprintf(decode, DECODE_STR_LEN, "%s", exit_reason);
192} 95}
193 96
194static struct kvm_events_ops exit_events = { 97static bool register_kvm_events_ops(struct perf_kvm_stat *kvm)
195 .is_begin_event = exit_event_begin,
196 .is_end_event = exit_event_end,
197 .decode_key = exit_event_decode_key,
198 .name = "VM-EXIT"
199};
200
201/*
202 * For the mmio events, we treat:
203 * the time of MMIO write: kvm_mmio(KVM_TRACE_MMIO_WRITE...) -> kvm_entry
204 * the time of MMIO read: kvm_exit -> kvm_mmio(KVM_TRACE_MMIO_READ...).
205 */
206static void mmio_event_get_key(struct perf_evsel *evsel, struct perf_sample *sample,
207 struct event_key *key)
208{
209 key->key = perf_evsel__intval(evsel, sample, "gpa");
210 key->info = perf_evsel__intval(evsel, sample, "type");
211}
212
213#define KVM_TRACE_MMIO_READ_UNSATISFIED 0
214#define KVM_TRACE_MMIO_READ 1
215#define KVM_TRACE_MMIO_WRITE 2
216
217static bool mmio_event_begin(struct perf_evsel *evsel,
218 struct perf_sample *sample, struct event_key *key)
219{
220 /* MMIO read begin event in kernel. */
221 if (kvm_exit_event(evsel))
222 return true;
223
224 /* MMIO write begin event in kernel. */
225 if (!strcmp(evsel->name, "kvm:kvm_mmio") &&
226 perf_evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_WRITE) {
227 mmio_event_get_key(evsel, sample, key);
228 return true;
229 }
230
231 return false;
232}
233
234static bool mmio_event_end(struct perf_evsel *evsel, struct perf_sample *sample,
235 struct event_key *key)
236{
237 /* MMIO write end event in kernel. */
238 if (kvm_entry_event(evsel))
239 return true;
240
241 /* MMIO read end event in kernel.*/
242 if (!strcmp(evsel->name, "kvm:kvm_mmio") &&
243 perf_evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_READ) {
244 mmio_event_get_key(evsel, sample, key);
245 return true;
246 }
247
248 return false;
249}
250
251static void mmio_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
252 struct event_key *key,
253 char decode[20])
254{
255 scnprintf(decode, 20, "%#lx:%s", (unsigned long)key->key,
256 key->info == KVM_TRACE_MMIO_WRITE ? "W" : "R");
257}
258
259static struct kvm_events_ops mmio_events = {
260 .is_begin_event = mmio_event_begin,
261 .is_end_event = mmio_event_end,
262 .decode_key = mmio_event_decode_key,
263 .name = "MMIO Access"
264};
265
266 /* The time of emulation pio access is from kvm_pio to kvm_entry. */
267static void ioport_event_get_key(struct perf_evsel *evsel,
268 struct perf_sample *sample,
269 struct event_key *key)
270{ 98{
271 key->key = perf_evsel__intval(evsel, sample, "port"); 99 struct kvm_reg_events_ops *events_ops = kvm_reg_events_ops;
272 key->info = perf_evsel__intval(evsel, sample, "rw");
273}
274 100
275static bool ioport_event_begin(struct perf_evsel *evsel, 101 for (events_ops = kvm_reg_events_ops; events_ops->name; events_ops++) {
276 struct perf_sample *sample, 102 if (!strcmp(events_ops->name, kvm->report_event)) {
277 struct event_key *key) 103 kvm->events_ops = events_ops->ops;
278{ 104 return true;
279 if (!strcmp(evsel->name, "kvm:kvm_pio")) { 105 }
280 ioport_event_get_key(evsel, sample, key);
281 return true;
282 } 106 }
283 107
284 return false; 108 return false;
285} 109}
286 110
287static bool ioport_event_end(struct perf_evsel *evsel,
288 struct perf_sample *sample __maybe_unused,
289 struct event_key *key __maybe_unused)
290{
291 return kvm_entry_event(evsel);
292}
293
294static void ioport_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
295 struct event_key *key,
296 char decode[20])
297{
298 scnprintf(decode, 20, "%#llx:%s", (unsigned long long)key->key,
299 key->info ? "POUT" : "PIN");
300}
301
302static struct kvm_events_ops ioport_events = {
303 .is_begin_event = ioport_event_begin,
304 .is_end_event = ioport_event_end,
305 .decode_key = ioport_event_decode_key,
306 .name = "IO Port Access"
307};
308
309static bool register_kvm_events_ops(struct perf_kvm_stat *kvm)
310{
311 bool ret = true;
312
313 if (!strcmp(kvm->report_event, "vmexit"))
314 kvm->events_ops = &exit_events;
315 else if (!strcmp(kvm->report_event, "mmio"))
316 kvm->events_ops = &mmio_events;
317 else if (!strcmp(kvm->report_event, "ioport"))
318 kvm->events_ops = &ioport_events;
319 else {
320 pr_err("Unknown report event:%s\n", kvm->report_event);
321 ret = false;
322 }
323
324 return ret;
325}
326
327struct vcpu_event_record { 111struct vcpu_event_record {
328 int vcpu_id; 112 int vcpu_id;
329 u64 start_time; 113 u64 start_time;
@@ -477,6 +261,54 @@ static bool update_kvm_event(struct kvm_event *event, int vcpu_id,
477 return true; 261 return true;
478} 262}
479 263
264static bool is_child_event(struct perf_kvm_stat *kvm,
265 struct perf_evsel *evsel,
266 struct perf_sample *sample,
267 struct event_key *key)
268{
269 struct child_event_ops *child_ops;
270
271 child_ops = kvm->events_ops->child_ops;
272
273 if (!child_ops)
274 return false;
275
276 for (; child_ops->name; child_ops++) {
277 if (!strcmp(evsel->name, child_ops->name)) {
278 child_ops->get_key(evsel, sample, key);
279 return true;
280 }
281 }
282
283 return false;
284}
285
286static bool handle_child_event(struct perf_kvm_stat *kvm,
287 struct vcpu_event_record *vcpu_record,
288 struct event_key *key,
289 struct perf_sample *sample __maybe_unused)
290{
291 struct kvm_event *event = NULL;
292
293 if (key->key != INVALID_KEY)
294 event = find_create_kvm_event(kvm, key);
295
296 vcpu_record->last_event = event;
297
298 return true;
299}
300
301static bool skip_event(const char *event)
302{
303 const char * const *skip_events;
304
305 for (skip_events = kvm_skip_events; *skip_events; skip_events++)
306 if (!strcmp(event, *skip_events))
307 return true;
308
309 return false;
310}
311
480static bool handle_end_event(struct perf_kvm_stat *kvm, 312static bool handle_end_event(struct perf_kvm_stat *kvm,
481 struct vcpu_event_record *vcpu_record, 313 struct vcpu_event_record *vcpu_record,
482 struct event_key *key, 314 struct event_key *key,
@@ -525,10 +357,10 @@ static bool handle_end_event(struct perf_kvm_stat *kvm,
525 time_diff = sample->time - time_begin; 357 time_diff = sample->time - time_begin;
526 358
527 if (kvm->duration && time_diff > kvm->duration) { 359 if (kvm->duration && time_diff > kvm->duration) {
528 char decode[32]; 360 char decode[DECODE_STR_LEN];
529 361
530 kvm->events_ops->decode_key(kvm, &event->key, decode); 362 kvm->events_ops->decode_key(kvm, &event->key, decode);
531 if (strcmp(decode, "HLT")) { 363 if (!skip_event(decode)) {
532 pr_info("%" PRIu64 " VM %d, vcpu %d: %s event took %" PRIu64 "usec\n", 364 pr_info("%" PRIu64 " VM %d, vcpu %d: %s event took %" PRIu64 "usec\n",
533 sample->time, sample->pid, vcpu_record->vcpu_id, 365 sample->time, sample->pid, vcpu_record->vcpu_id,
534 decode, time_diff/1000); 366 decode, time_diff/1000);
@@ -553,7 +385,7 @@ struct vcpu_event_record *per_vcpu_record(struct thread *thread,
553 return NULL; 385 return NULL;
554 } 386 }
555 387
556 vcpu_record->vcpu_id = perf_evsel__intval(evsel, sample, "vcpu_id"); 388 vcpu_record->vcpu_id = perf_evsel__intval(evsel, sample, VCPU_ID);
557 thread->priv = vcpu_record; 389 thread->priv = vcpu_record;
558 } 390 }
559 391
@@ -566,7 +398,8 @@ static bool handle_kvm_event(struct perf_kvm_stat *kvm,
566 struct perf_sample *sample) 398 struct perf_sample *sample)
567{ 399{
568 struct vcpu_event_record *vcpu_record; 400 struct vcpu_event_record *vcpu_record;
569 struct event_key key = {.key = INVALID_KEY}; 401 struct event_key key = { .key = INVALID_KEY,
402 .exit_reasons = kvm->exit_reasons };
570 403
571 vcpu_record = per_vcpu_record(thread, evsel, sample); 404 vcpu_record = per_vcpu_record(thread, evsel, sample);
572 if (!vcpu_record) 405 if (!vcpu_record)
@@ -580,6 +413,9 @@ static bool handle_kvm_event(struct perf_kvm_stat *kvm,
580 if (kvm->events_ops->is_begin_event(evsel, sample, &key)) 413 if (kvm->events_ops->is_begin_event(evsel, sample, &key))
581 return handle_begin_event(kvm, vcpu_record, &key, sample->time); 414 return handle_begin_event(kvm, vcpu_record, &key, sample->time);
582 415
416 if (is_child_event(kvm, evsel, sample, &key))
417 return handle_child_event(kvm, vcpu_record, &key, sample);
418
583 if (kvm->events_ops->is_end_event(evsel, sample, &key)) 419 if (kvm->events_ops->is_end_event(evsel, sample, &key))
584 return handle_end_event(kvm, vcpu_record, &key, sample); 420 return handle_end_event(kvm, vcpu_record, &key, sample);
585 421
@@ -740,7 +576,7 @@ static void show_timeofday(void)
740 576
741static void print_result(struct perf_kvm_stat *kvm) 577static void print_result(struct perf_kvm_stat *kvm)
742{ 578{
743 char decode[20]; 579 char decode[DECODE_STR_LEN];
744 struct kvm_event *event; 580 struct kvm_event *event;
745 int vcpu = kvm->trace_vcpu; 581 int vcpu = kvm->trace_vcpu;
746 582
@@ -751,7 +587,7 @@ static void print_result(struct perf_kvm_stat *kvm)
751 587
752 pr_info("\n\n"); 588 pr_info("\n\n");
753 print_vcpu_info(kvm); 589 print_vcpu_info(kvm);
754 pr_info("%20s ", kvm->events_ops->name); 590 pr_info("%*s ", DECODE_STR_LEN, kvm->events_ops->name);
755 pr_info("%10s ", "Samples"); 591 pr_info("%10s ", "Samples");
756 pr_info("%9s ", "Samples%"); 592 pr_info("%9s ", "Samples%");
757 593
@@ -770,7 +606,7 @@ static void print_result(struct perf_kvm_stat *kvm)
770 min = get_event_min(event, vcpu); 606 min = get_event_min(event, vcpu);
771 607
772 kvm->events_ops->decode_key(kvm, &event->key, decode); 608 kvm->events_ops->decode_key(kvm, &event->key, decode);
773 pr_info("%20s ", decode); 609 pr_info("%*s ", DECODE_STR_LEN, decode);
774 pr_info("%10llu ", (unsigned long long)ecount); 610 pr_info("%10llu ", (unsigned long long)ecount);
775 pr_info("%8.2f%% ", (double)ecount / kvm->total_count * 100); 611 pr_info("%8.2f%% ", (double)ecount / kvm->total_count * 100);
776 pr_info("%8.2f%% ", (double)etime / kvm->total_time * 100); 612 pr_info("%8.2f%% ", (double)etime / kvm->total_time * 100);
@@ -839,34 +675,28 @@ static int process_sample_event(struct perf_tool *tool,
839static int cpu_isa_config(struct perf_kvm_stat *kvm) 675static int cpu_isa_config(struct perf_kvm_stat *kvm)
840{ 676{
841 char buf[64], *cpuid; 677 char buf[64], *cpuid;
842 int err, isa; 678 int err;
843 679
844 if (kvm->live) { 680 if (kvm->live) {
845 err = get_cpuid(buf, sizeof(buf)); 681 err = get_cpuid(buf, sizeof(buf));
846 if (err != 0) { 682 if (err != 0) {
847 pr_err("Failed to look up CPU type (Intel or AMD)\n"); 683 pr_err("Failed to look up CPU type\n");
848 return err; 684 return err;
849 } 685 }
850 cpuid = buf; 686 cpuid = buf;
851 } else 687 } else
852 cpuid = kvm->session->header.env.cpuid; 688 cpuid = kvm->session->header.env.cpuid;
853 689
854 if (strstr(cpuid, "Intel")) 690 if (!cpuid) {
855 isa = 1; 691 pr_err("Failed to look up CPU type\n");
856 else if (strstr(cpuid, "AMD")) 692 return -EINVAL;
857 isa = 0;
858 else {
859 pr_err("CPU %s is not supported.\n", cpuid);
860 return -ENOTSUP;
861 } 693 }
862 694
863 if (isa == 1) { 695 err = cpu_isa_init(kvm, cpuid);
864 kvm->exit_reasons = vmx_exit_reasons; 696 if (err == -ENOTSUP)
865 kvm->exit_reasons_size = ARRAY_SIZE(vmx_exit_reasons); 697 pr_err("CPU %s is not supported.\n", cpuid);
866 kvm->exit_reasons_isa = "VMX";
867 }
868 698
869 return 0; 699 return err;
870} 700}
871 701
872static bool verify_vcpu(int vcpu) 702static bool verify_vcpu(int vcpu)
@@ -1300,13 +1130,6 @@ exit:
1300 return ret; 1130 return ret;
1301} 1131}
1302 1132
1303static const char * const kvm_events_tp[] = {
1304 "kvm:kvm_entry",
1305 "kvm:kvm_exit",
1306 "kvm:kvm_mmio",
1307 "kvm:kvm_pio",
1308};
1309
1310#define STRDUP_FAIL_EXIT(s) \ 1133#define STRDUP_FAIL_EXIT(s) \
1311 ({ char *_p; \ 1134 ({ char *_p; \
1312 _p = strdup(s); \ 1135 _p = strdup(s); \
@@ -1318,7 +1141,7 @@ static const char * const kvm_events_tp[] = {
1318static int 1141static int
1319kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv) 1142kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv)
1320{ 1143{
1321 unsigned int rec_argc, i, j; 1144 unsigned int rec_argc, i, j, events_tp_size;
1322 const char **rec_argv; 1145 const char **rec_argv;
1323 const char * const record_args[] = { 1146 const char * const record_args[] = {
1324 "record", 1147 "record",
@@ -1326,9 +1149,14 @@ kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv)
1326 "-m", "1024", 1149 "-m", "1024",
1327 "-c", "1", 1150 "-c", "1",
1328 }; 1151 };
1152 const char * const *events_tp;
1153 events_tp_size = 0;
1154
1155 for (events_tp = kvm_events_tp; *events_tp; events_tp++)
1156 events_tp_size++;
1329 1157
1330 rec_argc = ARRAY_SIZE(record_args) + argc + 2 + 1158 rec_argc = ARRAY_SIZE(record_args) + argc + 2 +
1331 2 * ARRAY_SIZE(kvm_events_tp); 1159 2 * events_tp_size;
1332 rec_argv = calloc(rec_argc + 1, sizeof(char *)); 1160 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1333 1161
1334 if (rec_argv == NULL) 1162 if (rec_argv == NULL)
@@ -1337,7 +1165,7 @@ kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv)
1337 for (i = 0; i < ARRAY_SIZE(record_args); i++) 1165 for (i = 0; i < ARRAY_SIZE(record_args); i++)
1338 rec_argv[i] = STRDUP_FAIL_EXIT(record_args[i]); 1166 rec_argv[i] = STRDUP_FAIL_EXIT(record_args[i]);
1339 1167
1340 for (j = 0; j < ARRAY_SIZE(kvm_events_tp); j++) { 1168 for (j = 0; j < events_tp_size; j++) {
1341 rec_argv[i++] = "-e"; 1169 rec_argv[i++] = "-e";
1342 rec_argv[i++] = STRDUP_FAIL_EXIT(kvm_events_tp[j]); 1170 rec_argv[i++] = STRDUP_FAIL_EXIT(kvm_events_tp[j]);
1343 } 1171 }
@@ -1356,7 +1184,8 @@ kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv)
1356{ 1184{
1357 const struct option kvm_events_report_options[] = { 1185 const struct option kvm_events_report_options[] = {
1358 OPT_STRING(0, "event", &kvm->report_event, "report event", 1186 OPT_STRING(0, "event", &kvm->report_event, "report event",
1359 "event for reporting: vmexit, mmio, ioport"), 1187 "event for reporting: vmexit, "
1188 "mmio (x86 only), ioport (x86 only)"),
1360 OPT_INTEGER(0, "vcpu", &kvm->trace_vcpu, 1189 OPT_INTEGER(0, "vcpu", &kvm->trace_vcpu,
1361 "vcpu id to report"), 1190 "vcpu id to report"),
1362 OPT_STRING('k', "key", &kvm->sort_key, "sort-key", 1191 OPT_STRING('k', "key", &kvm->sort_key, "sort-key",
@@ -1391,16 +1220,16 @@ static struct perf_evlist *kvm_live_event_list(void)
1391{ 1220{
1392 struct perf_evlist *evlist; 1221 struct perf_evlist *evlist;
1393 char *tp, *name, *sys; 1222 char *tp, *name, *sys;
1394 unsigned int j;
1395 int err = -1; 1223 int err = -1;
1224 const char * const *events_tp;
1396 1225
1397 evlist = perf_evlist__new(); 1226 evlist = perf_evlist__new();
1398 if (evlist == NULL) 1227 if (evlist == NULL)
1399 return NULL; 1228 return NULL;
1400 1229
1401 for (j = 0; j < ARRAY_SIZE(kvm_events_tp); j++) { 1230 for (events_tp = kvm_events_tp; *events_tp; events_tp++) {
1402 1231
1403 tp = strdup(kvm_events_tp[j]); 1232 tp = strdup(*events_tp);
1404 if (tp == NULL) 1233 if (tp == NULL)
1405 goto out; 1234 goto out;
1406 1235
@@ -1409,7 +1238,7 @@ static struct perf_evlist *kvm_live_event_list(void)
1409 name = strchr(tp, ':'); 1238 name = strchr(tp, ':');
1410 if (name == NULL) { 1239 if (name == NULL) {
1411 pr_err("Error parsing %s tracepoint: subsystem delimiter not found\n", 1240 pr_err("Error parsing %s tracepoint: subsystem delimiter not found\n",
1412 kvm_events_tp[j]); 1241 *events_tp);
1413 free(tp); 1242 free(tp);
1414 goto out; 1243 goto out;
1415 } 1244 }
@@ -1417,7 +1246,7 @@ static struct perf_evlist *kvm_live_event_list(void)
1417 name++; 1246 name++;
1418 1247
1419 if (perf_evlist__add_newtp(evlist, sys, name, NULL)) { 1248 if (perf_evlist__add_newtp(evlist, sys, name, NULL)) {
1420 pr_err("Failed to add %s tracepoint to the list\n", kvm_events_tp[j]); 1249 pr_err("Failed to add %s tracepoint to the list\n", *events_tp);
1421 free(tp); 1250 free(tp);
1422 goto out; 1251 goto out;
1423 } 1252 }
@@ -1462,7 +1291,9 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
1462 "key for sorting: sample(sort by samples number)" 1291 "key for sorting: sample(sort by samples number)"
1463 " time (sort by avg time)"), 1292 " time (sort by avg time)"),
1464 OPT_U64(0, "duration", &kvm->duration, 1293 OPT_U64(0, "duration", &kvm->duration,
1465 "show events other than HALT that take longer than duration usecs"), 1294 "show events other than"
1295 " HLT (x86 only) or Wait state (s390 only)"
1296 " that take longer than duration usecs"),
1466 OPT_END() 1297 OPT_END()
1467 }; 1298 };
1468 const char * const live_usage[] = { 1299 const char * const live_usage[] = {
@@ -1585,9 +1416,6 @@ static int kvm_cmd_stat(const char *file_name, int argc, const char **argv)
1585 .report_event = "vmexit", 1416 .report_event = "vmexit",
1586 .sort_key = "sample", 1417 .sort_key = "sample",
1587 1418
1588 .exit_reasons = svm_exit_reasons,
1589 .exit_reasons_size = ARRAY_SIZE(svm_exit_reasons),
1590 .exit_reasons_isa = "SVM",
1591 }; 1419 };
1592 1420
1593 if (argc == 1) { 1421 if (argc == 1) {
@@ -1609,7 +1437,7 @@ static int kvm_cmd_stat(const char *file_name, int argc, const char **argv)
1609perf_stat: 1437perf_stat:
1610 return cmd_stat(argc, argv, NULL); 1438 return cmd_stat(argc, argv, NULL);
1611} 1439}
1612#endif 1440#endif /* HAVE_KVM_STAT_SUPPORT */
1613 1441
1614static int __cmd_record(const char *file_name, int argc, const char **argv) 1442static int __cmd_record(const char *file_name, int argc, const char **argv)
1615{ 1443{
@@ -1726,7 +1554,7 @@ int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused)
1726 return cmd_top(argc, argv, NULL); 1554 return cmd_top(argc, argv, NULL);
1727 else if (!strncmp(argv[0], "buildid-list", 12)) 1555 else if (!strncmp(argv[0], "buildid-list", 12))
1728 return __cmd_buildid_list(file_name, argc, argv); 1556 return __cmd_buildid_list(file_name, argc, argv);
1729#if defined(__i386__) || defined(__x86_64__) 1557#ifdef HAVE_KVM_STAT_SUPPORT
1730 else if (!strncmp(argv[0], "stat", 4)) 1558 else if (!strncmp(argv[0], "stat", 4))
1731 return kvm_cmd_stat(file_name, argc, argv); 1559 return kvm_cmd_stat(file_name, argc, argv);
1732#endif 1560#endif
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 378b85b731a7..4869050e7194 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -238,6 +238,7 @@ static struct perf_event_header finished_round_event = {
238 238
239static int record__mmap_read_all(struct record *rec) 239static int record__mmap_read_all(struct record *rec)
240{ 240{
241 u64 bytes_written = rec->bytes_written;
241 int i; 242 int i;
242 int rc = 0; 243 int rc = 0;
243 244
@@ -250,7 +251,11 @@ static int record__mmap_read_all(struct record *rec)
250 } 251 }
251 } 252 }
252 253
253 if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA)) 254 /*
255 * Mark the round finished in case we wrote
256 * at least one event.
257 */
258 if (bytes_written != rec->bytes_written)
254 rc = record__write(rec, &finished_round_event, sizeof(finished_round_event)); 259 rc = record__write(rec, &finished_round_event, sizeof(finished_round_event));
255 260
256out: 261out:
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index c38d06c04775..f83c08c0dd87 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -10,6 +10,7 @@
10#include "util/header.h" 10#include "util/header.h"
11#include "util/session.h" 11#include "util/session.h"
12#include "util/tool.h" 12#include "util/tool.h"
13#include "util/cloexec.h"
13 14
14#include "util/parse-options.h" 15#include "util/parse-options.h"
15#include "util/trace-event.h" 16#include "util/trace-event.h"
@@ -434,7 +435,8 @@ static int self_open_counters(void)
434 attr.type = PERF_TYPE_SOFTWARE; 435 attr.type = PERF_TYPE_SOFTWARE;
435 attr.config = PERF_COUNT_SW_TASK_CLOCK; 436 attr.config = PERF_COUNT_SW_TASK_CLOCK;
436 437
437 fd = sys_perf_event_open(&attr, 0, -1, -1, 0); 438 fd = sys_perf_event_open(&attr, 0, -1, -1,
439 perf_event_open_cloexec_flag());
438 440
439 if (fd < 0) 441 if (fd < 0)
440 pr_err("Error: sys_perf_event_open() syscall returned " 442 pr_err("Error: sys_perf_event_open() syscall returned "
@@ -935,8 +937,8 @@ static int latency_switch_event(struct perf_sched *sched,
935 return -1; 937 return -1;
936 } 938 }
937 939
938 sched_out = machine__findnew_thread(machine, 0, prev_pid); 940 sched_out = machine__findnew_thread(machine, -1, prev_pid);
939 sched_in = machine__findnew_thread(machine, 0, next_pid); 941 sched_in = machine__findnew_thread(machine, -1, next_pid);
940 942
941 out_events = thread_atoms_search(&sched->atom_root, sched_out, &sched->cmp_pid); 943 out_events = thread_atoms_search(&sched->atom_root, sched_out, &sched->cmp_pid);
942 if (!out_events) { 944 if (!out_events) {
@@ -979,7 +981,7 @@ static int latency_runtime_event(struct perf_sched *sched,
979{ 981{
980 const u32 pid = perf_evsel__intval(evsel, sample, "pid"); 982 const u32 pid = perf_evsel__intval(evsel, sample, "pid");
981 const u64 runtime = perf_evsel__intval(evsel, sample, "runtime"); 983 const u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
982 struct thread *thread = machine__findnew_thread(machine, 0, pid); 984 struct thread *thread = machine__findnew_thread(machine, -1, pid);
983 struct work_atoms *atoms = thread_atoms_search(&sched->atom_root, thread, &sched->cmp_pid); 985 struct work_atoms *atoms = thread_atoms_search(&sched->atom_root, thread, &sched->cmp_pid);
984 u64 timestamp = sample->time; 986 u64 timestamp = sample->time;
985 int cpu = sample->cpu; 987 int cpu = sample->cpu;
@@ -1012,7 +1014,7 @@ static int latency_wakeup_event(struct perf_sched *sched,
1012 struct thread *wakee; 1014 struct thread *wakee;
1013 u64 timestamp = sample->time; 1015 u64 timestamp = sample->time;
1014 1016
1015 wakee = machine__findnew_thread(machine, 0, pid); 1017 wakee = machine__findnew_thread(machine, -1, pid);
1016 atoms = thread_atoms_search(&sched->atom_root, wakee, &sched->cmp_pid); 1018 atoms = thread_atoms_search(&sched->atom_root, wakee, &sched->cmp_pid);
1017 if (!atoms) { 1019 if (!atoms) {
1018 if (thread_atoms_insert(sched, wakee)) 1020 if (thread_atoms_insert(sched, wakee))
@@ -1072,7 +1074,7 @@ static int latency_migrate_task_event(struct perf_sched *sched,
1072 if (sched->profile_cpu == -1) 1074 if (sched->profile_cpu == -1)
1073 return 0; 1075 return 0;
1074 1076
1075 migrant = machine__findnew_thread(machine, 0, pid); 1077 migrant = machine__findnew_thread(machine, -1, pid);
1076 atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid); 1078 atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid);
1077 if (!atoms) { 1079 if (!atoms) {
1078 if (thread_atoms_insert(sched, migrant)) 1080 if (thread_atoms_insert(sched, migrant))
@@ -1290,7 +1292,7 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,
1290 return -1; 1292 return -1;
1291 } 1293 }
1292 1294
1293 sched_in = machine__findnew_thread(machine, 0, next_pid); 1295 sched_in = machine__findnew_thread(machine, -1, next_pid);
1294 1296
1295 sched->curr_thread[this_cpu] = sched_in; 1297 sched->curr_thread[this_cpu] = sched_in;
1296 1298
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 9e9c91f5b7fa..f57035b89c15 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -358,27 +358,6 @@ static void print_sample_start(struct perf_sample *sample,
358 } 358 }
359} 359}
360 360
361static bool is_bts_event(struct perf_event_attr *attr)
362{
363 return ((attr->type == PERF_TYPE_HARDWARE) &&
364 (attr->config & PERF_COUNT_HW_BRANCH_INSTRUCTIONS) &&
365 (attr->sample_period == 1));
366}
367
368static bool sample_addr_correlates_sym(struct perf_event_attr *attr)
369{
370 if ((attr->type == PERF_TYPE_SOFTWARE) &&
371 ((attr->config == PERF_COUNT_SW_PAGE_FAULTS) ||
372 (attr->config == PERF_COUNT_SW_PAGE_FAULTS_MIN) ||
373 (attr->config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)))
374 return true;
375
376 if (is_bts_event(attr))
377 return true;
378
379 return false;
380}
381
382static void print_sample_addr(union perf_event *event, 361static void print_sample_addr(union perf_event *event,
383 struct perf_sample *sample, 362 struct perf_sample *sample,
384 struct machine *machine, 363 struct machine *machine,
@@ -386,24 +365,13 @@ static void print_sample_addr(union perf_event *event,
386 struct perf_event_attr *attr) 365 struct perf_event_attr *attr)
387{ 366{
388 struct addr_location al; 367 struct addr_location al;
389 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
390 368
391 printf("%16" PRIx64, sample->addr); 369 printf("%16" PRIx64, sample->addr);
392 370
393 if (!sample_addr_correlates_sym(attr)) 371 if (!sample_addr_correlates_sym(attr))
394 return; 372 return;
395 373
396 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, 374 perf_event__preprocess_sample_addr(event, sample, machine, thread, &al);
397 sample->addr, &al);
398 if (!al.map)
399 thread__find_addr_map(thread, machine, cpumode, MAP__VARIABLE,
400 sample->addr, &al);
401
402 al.cpu = sample->cpu;
403 al.sym = NULL;
404
405 if (al.map)
406 al.sym = map__find_symbol(al.map, al.addr, NULL);
407 375
408 if (PRINT_FIELD(SYM)) { 376 if (PRINT_FIELD(SYM)) {
409 printf(" "); 377 printf(" ");
@@ -427,25 +395,35 @@ static void print_sample_bts(union perf_event *event,
427 struct addr_location *al) 395 struct addr_location *al)
428{ 396{
429 struct perf_event_attr *attr = &evsel->attr; 397 struct perf_event_attr *attr = &evsel->attr;
398 bool print_srcline_last = false;
430 399
431 /* print branch_from information */ 400 /* print branch_from information */
432 if (PRINT_FIELD(IP)) { 401 if (PRINT_FIELD(IP)) {
433 if (!symbol_conf.use_callchain) 402 unsigned int print_opts = output[attr->type].print_ip_opts;
434 printf(" "); 403
435 else 404 if (symbol_conf.use_callchain && sample->callchain) {
436 printf("\n"); 405 printf("\n");
437 perf_evsel__print_ip(evsel, sample, al, 406 } else {
438 output[attr->type].print_ip_opts, 407 printf(" ");
408 if (print_opts & PRINT_IP_OPT_SRCLINE) {
409 print_srcline_last = true;
410 print_opts &= ~PRINT_IP_OPT_SRCLINE;
411 }
412 }
413 perf_evsel__print_ip(evsel, sample, al, print_opts,
439 PERF_MAX_STACK_DEPTH); 414 PERF_MAX_STACK_DEPTH);
440 } 415 }
441 416
442 printf(" => ");
443
444 /* print branch_to information */ 417 /* print branch_to information */
445 if (PRINT_FIELD(ADDR) || 418 if (PRINT_FIELD(ADDR) ||
446 ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) && 419 ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) &&
447 !output[attr->type].user_set)) 420 !output[attr->type].user_set)) {
421 printf(" => ");
448 print_sample_addr(event, sample, al->machine, thread, attr); 422 print_sample_addr(event, sample, al->machine, thread, attr);
423 }
424
425 if (print_srcline_last)
426 map__fprintf_srcline(al->map, al->addr, "\n ", stdout);
449 427
450 printf("\n"); 428 printf("\n");
451} 429}
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 65a151e36067..3e80aa10cfd8 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -184,7 +184,7 @@ static void perf_evsel__reset_stat_priv(struct perf_evsel *evsel)
184static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel) 184static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel)
185{ 185{
186 evsel->priv = zalloc(sizeof(struct perf_stat)); 186 evsel->priv = zalloc(sizeof(struct perf_stat));
187 if (evsel == NULL) 187 if (evsel->priv == NULL)
188 return -ENOMEM; 188 return -ENOMEM;
189 perf_evsel__reset_stat_priv(evsel); 189 perf_evsel__reset_stat_priv(evsel);
190 return 0; 190 return 0;
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 74db2568b867..2f1a5220c090 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -37,6 +37,7 @@
37#include "util/svghelper.h" 37#include "util/svghelper.h"
38#include "util/tool.h" 38#include "util/tool.h"
39#include "util/data.h" 39#include "util/data.h"
40#include "util/debug.h"
40 41
41#define SUPPORT_OLD_POWER_EVENTS 1 42#define SUPPORT_OLD_POWER_EVENTS 1
42#define PWR_EVENT_EXIT -1 43#define PWR_EVENT_EXIT -1
@@ -60,10 +61,17 @@ struct timechart {
60 tasks_only, 61 tasks_only,
61 with_backtrace, 62 with_backtrace,
62 topology; 63 topology;
64 /* IO related settings */
65 u64 io_events;
66 bool io_only,
67 skip_eagain;
68 u64 min_time,
69 merge_dist;
63}; 70};
64 71
65struct per_pidcomm; 72struct per_pidcomm;
66struct cpu_sample; 73struct cpu_sample;
74struct io_sample;
67 75
68/* 76/*
69 * Datastructure layout: 77 * Datastructure layout:
@@ -84,6 +92,7 @@ struct per_pid {
84 u64 start_time; 92 u64 start_time;
85 u64 end_time; 93 u64 end_time;
86 u64 total_time; 94 u64 total_time;
95 u64 total_bytes;
87 int display; 96 int display;
88 97
89 struct per_pidcomm *all; 98 struct per_pidcomm *all;
@@ -97,6 +106,8 @@ struct per_pidcomm {
97 u64 start_time; 106 u64 start_time;
98 u64 end_time; 107 u64 end_time;
99 u64 total_time; 108 u64 total_time;
109 u64 max_bytes;
110 u64 total_bytes;
100 111
101 int Y; 112 int Y;
102 int display; 113 int display;
@@ -107,6 +118,7 @@ struct per_pidcomm {
107 char *comm; 118 char *comm;
108 119
109 struct cpu_sample *samples; 120 struct cpu_sample *samples;
121 struct io_sample *io_samples;
110}; 122};
111 123
112struct sample_wrapper { 124struct sample_wrapper {
@@ -131,6 +143,27 @@ struct cpu_sample {
131 const char *backtrace; 143 const char *backtrace;
132}; 144};
133 145
146enum {
147 IOTYPE_READ,
148 IOTYPE_WRITE,
149 IOTYPE_SYNC,
150 IOTYPE_TX,
151 IOTYPE_RX,
152 IOTYPE_POLL,
153};
154
155struct io_sample {
156 struct io_sample *next;
157
158 u64 start_time;
159 u64 end_time;
160 u64 bytes;
161 int type;
162 int fd;
163 int err;
164 int merges;
165};
166
134#define CSTATE 1 167#define CSTATE 1
135#define PSTATE 2 168#define PSTATE 2
136 169
@@ -213,7 +246,7 @@ static void pid_fork(struct timechart *tchart, int pid, int ppid, u64 timestamp)
213 pid_set_comm(tchart, pid, pp->current->comm); 246 pid_set_comm(tchart, pid, pp->current->comm);
214 247
215 p->start_time = timestamp; 248 p->start_time = timestamp;
216 if (p->current) { 249 if (p->current && !p->current->start_time) {
217 p->current->start_time = timestamp; 250 p->current->start_time = timestamp;
218 p->current->state_since = timestamp; 251 p->current->state_since = timestamp;
219 } 252 }
@@ -682,6 +715,249 @@ static void end_sample_processing(struct timechart *tchart)
682 } 715 }
683} 716}
684 717
718static int pid_begin_io_sample(struct timechart *tchart, int pid, int type,
719 u64 start, int fd)
720{
721 struct per_pid *p = find_create_pid(tchart, pid);
722 struct per_pidcomm *c = p->current;
723 struct io_sample *sample;
724 struct io_sample *prev;
725
726 if (!c) {
727 c = zalloc(sizeof(*c));
728 if (!c)
729 return -ENOMEM;
730 p->current = c;
731 c->next = p->all;
732 p->all = c;
733 }
734
735 prev = c->io_samples;
736
737 if (prev && prev->start_time && !prev->end_time) {
738 pr_warning("Skip invalid start event: "
739 "previous event already started!\n");
740
741 /* remove previous event that has been started,
742 * we are not sure we will ever get an end for it */
743 c->io_samples = prev->next;
744 free(prev);
745 return 0;
746 }
747
748 sample = zalloc(sizeof(*sample));
749 if (!sample)
750 return -ENOMEM;
751 sample->start_time = start;
752 sample->type = type;
753 sample->fd = fd;
754 sample->next = c->io_samples;
755 c->io_samples = sample;
756
757 if (c->start_time == 0 || c->start_time > start)
758 c->start_time = start;
759
760 return 0;
761}
762
763static int pid_end_io_sample(struct timechart *tchart, int pid, int type,
764 u64 end, long ret)
765{
766 struct per_pid *p = find_create_pid(tchart, pid);
767 struct per_pidcomm *c = p->current;
768 struct io_sample *sample, *prev;
769
770 if (!c) {
771 pr_warning("Invalid pidcomm!\n");
772 return -1;
773 }
774
775 sample = c->io_samples;
776
777 if (!sample) /* skip partially captured events */
778 return 0;
779
780 if (sample->end_time) {
781 pr_warning("Skip invalid end event: "
782 "previous event already ended!\n");
783 return 0;
784 }
785
786 if (sample->type != type) {
787 pr_warning("Skip invalid end event: invalid event type!\n");
788 return 0;
789 }
790
791 sample->end_time = end;
792 prev = sample->next;
793
794 /* we want to be able to see small and fast transfers, so make them
795 * at least min_time long, but don't overlap them */
796 if (sample->end_time - sample->start_time < tchart->min_time)
797 sample->end_time = sample->start_time + tchart->min_time;
798 if (prev && sample->start_time < prev->end_time) {
799 if (prev->err) /* try to make errors more visible */
800 sample->start_time = prev->end_time;
801 else
802 prev->end_time = sample->start_time;
803 }
804
805 if (ret < 0) {
806 sample->err = ret;
807 } else if (type == IOTYPE_READ || type == IOTYPE_WRITE ||
808 type == IOTYPE_TX || type == IOTYPE_RX) {
809
810 if ((u64)ret > c->max_bytes)
811 c->max_bytes = ret;
812
813 c->total_bytes += ret;
814 p->total_bytes += ret;
815 sample->bytes = ret;
816 }
817
818 /* merge two requests to make svg smaller and render-friendly */
819 if (prev &&
820 prev->type == sample->type &&
821 prev->err == sample->err &&
822 prev->fd == sample->fd &&
823 prev->end_time + tchart->merge_dist >= sample->start_time) {
824
825 sample->bytes += prev->bytes;
826 sample->merges += prev->merges + 1;
827
828 sample->start_time = prev->start_time;
829 sample->next = prev->next;
830 free(prev);
831
832 if (!sample->err && sample->bytes > c->max_bytes)
833 c->max_bytes = sample->bytes;
834 }
835
836 tchart->io_events++;
837
838 return 0;
839}
840
841static int
842process_enter_read(struct timechart *tchart,
843 struct perf_evsel *evsel,
844 struct perf_sample *sample)
845{
846 long fd = perf_evsel__intval(evsel, sample, "fd");
847 return pid_begin_io_sample(tchart, sample->tid, IOTYPE_READ,
848 sample->time, fd);
849}
850
851static int
852process_exit_read(struct timechart *tchart,
853 struct perf_evsel *evsel,
854 struct perf_sample *sample)
855{
856 long ret = perf_evsel__intval(evsel, sample, "ret");
857 return pid_end_io_sample(tchart, sample->tid, IOTYPE_READ,
858 sample->time, ret);
859}
860
861static int
862process_enter_write(struct timechart *tchart,
863 struct perf_evsel *evsel,
864 struct perf_sample *sample)
865{
866 long fd = perf_evsel__intval(evsel, sample, "fd");
867 return pid_begin_io_sample(tchart, sample->tid, IOTYPE_WRITE,
868 sample->time, fd);
869}
870
871static int
872process_exit_write(struct timechart *tchart,
873 struct perf_evsel *evsel,
874 struct perf_sample *sample)
875{
876 long ret = perf_evsel__intval(evsel, sample, "ret");
877 return pid_end_io_sample(tchart, sample->tid, IOTYPE_WRITE,
878 sample->time, ret);
879}
880
881static int
882process_enter_sync(struct timechart *tchart,
883 struct perf_evsel *evsel,
884 struct perf_sample *sample)
885{
886 long fd = perf_evsel__intval(evsel, sample, "fd");
887 return pid_begin_io_sample(tchart, sample->tid, IOTYPE_SYNC,
888 sample->time, fd);
889}
890
891static int
892process_exit_sync(struct timechart *tchart,
893 struct perf_evsel *evsel,
894 struct perf_sample *sample)
895{
896 long ret = perf_evsel__intval(evsel, sample, "ret");
897 return pid_end_io_sample(tchart, sample->tid, IOTYPE_SYNC,
898 sample->time, ret);
899}
900
901static int
902process_enter_tx(struct timechart *tchart,
903 struct perf_evsel *evsel,
904 struct perf_sample *sample)
905{
906 long fd = perf_evsel__intval(evsel, sample, "fd");
907 return pid_begin_io_sample(tchart, sample->tid, IOTYPE_TX,
908 sample->time, fd);
909}
910
911static int
912process_exit_tx(struct timechart *tchart,
913 struct perf_evsel *evsel,
914 struct perf_sample *sample)
915{
916 long ret = perf_evsel__intval(evsel, sample, "ret");
917 return pid_end_io_sample(tchart, sample->tid, IOTYPE_TX,
918 sample->time, ret);
919}
920
921static int
922process_enter_rx(struct timechart *tchart,
923 struct perf_evsel *evsel,
924 struct perf_sample *sample)
925{
926 long fd = perf_evsel__intval(evsel, sample, "fd");
927 return pid_begin_io_sample(tchart, sample->tid, IOTYPE_RX,
928 sample->time, fd);
929}
930
931static int
932process_exit_rx(struct timechart *tchart,
933 struct perf_evsel *evsel,
934 struct perf_sample *sample)
935{
936 long ret = perf_evsel__intval(evsel, sample, "ret");
937 return pid_end_io_sample(tchart, sample->tid, IOTYPE_RX,
938 sample->time, ret);
939}
940
941static int
942process_enter_poll(struct timechart *tchart,
943 struct perf_evsel *evsel,
944 struct perf_sample *sample)
945{
946 long fd = perf_evsel__intval(evsel, sample, "fd");
947 return pid_begin_io_sample(tchart, sample->tid, IOTYPE_POLL,
948 sample->time, fd);
949}
950
951static int
952process_exit_poll(struct timechart *tchart,
953 struct perf_evsel *evsel,
954 struct perf_sample *sample)
955{
956 long ret = perf_evsel__intval(evsel, sample, "ret");
957 return pid_end_io_sample(tchart, sample->tid, IOTYPE_POLL,
958 sample->time, ret);
959}
960
685/* 961/*
686 * Sort the pid datastructure 962 * Sort the pid datastructure
687 */ 963 */
@@ -852,6 +1128,121 @@ static void draw_cpu_usage(struct timechart *tchart)
852 } 1128 }
853} 1129}
854 1130
1131static void draw_io_bars(struct timechart *tchart)
1132{
1133 const char *suf;
1134 double bytes;
1135 char comm[256];
1136 struct per_pid *p;
1137 struct per_pidcomm *c;
1138 struct io_sample *sample;
1139 int Y = 1;
1140
1141 p = tchart->all_data;
1142 while (p) {
1143 c = p->all;
1144 while (c) {
1145 if (!c->display) {
1146 c->Y = 0;
1147 c = c->next;
1148 continue;
1149 }
1150
1151 svg_box(Y, c->start_time, c->end_time, "process3");
1152 sample = c->io_samples;
1153 for (sample = c->io_samples; sample; sample = sample->next) {
1154 double h = (double)sample->bytes / c->max_bytes;
1155
1156 if (tchart->skip_eagain &&
1157 sample->err == -EAGAIN)
1158 continue;
1159
1160 if (sample->err)
1161 h = 1;
1162
1163 if (sample->type == IOTYPE_SYNC)
1164 svg_fbox(Y,
1165 sample->start_time,
1166 sample->end_time,
1167 1,
1168 sample->err ? "error" : "sync",
1169 sample->fd,
1170 sample->err,
1171 sample->merges);
1172 else if (sample->type == IOTYPE_POLL)
1173 svg_fbox(Y,
1174 sample->start_time,
1175 sample->end_time,
1176 1,
1177 sample->err ? "error" : "poll",
1178 sample->fd,
1179 sample->err,
1180 sample->merges);
1181 else if (sample->type == IOTYPE_READ)
1182 svg_ubox(Y,
1183 sample->start_time,
1184 sample->end_time,
1185 h,
1186 sample->err ? "error" : "disk",
1187 sample->fd,
1188 sample->err,
1189 sample->merges);
1190 else if (sample->type == IOTYPE_WRITE)
1191 svg_lbox(Y,
1192 sample->start_time,
1193 sample->end_time,
1194 h,
1195 sample->err ? "error" : "disk",
1196 sample->fd,
1197 sample->err,
1198 sample->merges);
1199 else if (sample->type == IOTYPE_RX)
1200 svg_ubox(Y,
1201 sample->start_time,
1202 sample->end_time,
1203 h,
1204 sample->err ? "error" : "net",
1205 sample->fd,
1206 sample->err,
1207 sample->merges);
1208 else if (sample->type == IOTYPE_TX)
1209 svg_lbox(Y,
1210 sample->start_time,
1211 sample->end_time,
1212 h,
1213 sample->err ? "error" : "net",
1214 sample->fd,
1215 sample->err,
1216 sample->merges);
1217 }
1218
1219 suf = "";
1220 bytes = c->total_bytes;
1221 if (bytes > 1024) {
1222 bytes = bytes / 1024;
1223 suf = "K";
1224 }
1225 if (bytes > 1024) {
1226 bytes = bytes / 1024;
1227 suf = "M";
1228 }
1229 if (bytes > 1024) {
1230 bytes = bytes / 1024;
1231 suf = "G";
1232 }
1233
1234
1235 sprintf(comm, "%s:%i (%3.1f %sbytes)", c->comm ?: "", p->pid, bytes, suf);
1236 svg_text(Y, c->start_time, comm);
1237
1238 c->Y = Y;
1239 Y++;
1240 c = c->next;
1241 }
1242 p = p->next;
1243 }
1244}
1245
855static void draw_process_bars(struct timechart *tchart) 1246static void draw_process_bars(struct timechart *tchart)
856{ 1247{
857 struct per_pid *p; 1248 struct per_pid *p;
@@ -987,9 +1378,6 @@ static int determine_display_tasks(struct timechart *tchart, u64 threshold)
987 struct per_pidcomm *c; 1378 struct per_pidcomm *c;
988 int count = 0; 1379 int count = 0;
989 1380
990 if (process_filter)
991 return determine_display_tasks_filtered(tchart);
992
993 p = tchart->all_data; 1381 p = tchart->all_data;
994 while (p) { 1382 while (p) {
995 p->display = 0; 1383 p->display = 0;
@@ -1025,15 +1413,46 @@ static int determine_display_tasks(struct timechart *tchart, u64 threshold)
1025 return count; 1413 return count;
1026} 1414}
1027 1415
1416static int determine_display_io_tasks(struct timechart *timechart, u64 threshold)
1417{
1418 struct per_pid *p;
1419 struct per_pidcomm *c;
1420 int count = 0;
1421
1422 p = timechart->all_data;
1423 while (p) {
1424 /* no exit marker, task kept running to the end */
1425 if (p->end_time == 0)
1426 p->end_time = timechart->last_time;
1028 1427
1428 c = p->all;
1029 1429
1430 while (c) {
1431 c->display = 0;
1432
1433 if (c->total_bytes >= threshold) {
1434 c->display = 1;
1435 count++;
1436 }
1437
1438 if (c->end_time == 0)
1439 c->end_time = timechart->last_time;
1440
1441 c = c->next;
1442 }
1443 p = p->next;
1444 }
1445 return count;
1446}
1447
1448#define BYTES_THRESH (1 * 1024 * 1024)
1030#define TIME_THRESH 10000000 1449#define TIME_THRESH 10000000
1031 1450
1032static void write_svg_file(struct timechart *tchart, const char *filename) 1451static void write_svg_file(struct timechart *tchart, const char *filename)
1033{ 1452{
1034 u64 i; 1453 u64 i;
1035 int count; 1454 int count;
1036 int thresh = TIME_THRESH; 1455 int thresh = tchart->io_events ? BYTES_THRESH : TIME_THRESH;
1037 1456
1038 if (tchart->power_only) 1457 if (tchart->power_only)
1039 tchart->proc_num = 0; 1458 tchart->proc_num = 0;
@@ -1041,28 +1460,43 @@ static void write_svg_file(struct timechart *tchart, const char *filename)
1041 /* We'd like to show at least proc_num tasks; 1460 /* We'd like to show at least proc_num tasks;
1042 * be less picky if we have fewer */ 1461 * be less picky if we have fewer */
1043 do { 1462 do {
1044 count = determine_display_tasks(tchart, thresh); 1463 if (process_filter)
1464 count = determine_display_tasks_filtered(tchart);
1465 else if (tchart->io_events)
1466 count = determine_display_io_tasks(tchart, thresh);
1467 else
1468 count = determine_display_tasks(tchart, thresh);
1045 thresh /= 10; 1469 thresh /= 10;
1046 } while (!process_filter && thresh && count < tchart->proc_num); 1470 } while (!process_filter && thresh && count < tchart->proc_num);
1047 1471
1048 if (!tchart->proc_num) 1472 if (!tchart->proc_num)
1049 count = 0; 1473 count = 0;
1050 1474
1051 open_svg(filename, tchart->numcpus, count, tchart->first_time, tchart->last_time); 1475 if (tchart->io_events) {
1476 open_svg(filename, 0, count, tchart->first_time, tchart->last_time);
1052 1477
1053 svg_time_grid(); 1478 svg_time_grid(0.5);
1054 svg_legenda(); 1479 svg_io_legenda();
1480
1481 draw_io_bars(tchart);
1482 } else {
1483 open_svg(filename, tchart->numcpus, count, tchart->first_time, tchart->last_time);
1055 1484
1056 for (i = 0; i < tchart->numcpus; i++) 1485 svg_time_grid(0);
1057 svg_cpu_box(i, tchart->max_freq, tchart->turbo_frequency);
1058 1486
1059 draw_cpu_usage(tchart); 1487 svg_legenda();
1060 if (tchart->proc_num) 1488
1061 draw_process_bars(tchart); 1489 for (i = 0; i < tchart->numcpus; i++)
1062 if (!tchart->tasks_only) 1490 svg_cpu_box(i, tchart->max_freq, tchart->turbo_frequency);
1063 draw_c_p_states(tchart); 1491
1064 if (tchart->proc_num) 1492 draw_cpu_usage(tchart);
1065 draw_wakeups(tchart); 1493 if (tchart->proc_num)
1494 draw_process_bars(tchart);
1495 if (!tchart->tasks_only)
1496 draw_c_p_states(tchart);
1497 if (tchart->proc_num)
1498 draw_wakeups(tchart);
1499 }
1066 1500
1067 svg_close(); 1501 svg_close();
1068} 1502}
@@ -1110,6 +1544,56 @@ static int __cmd_timechart(struct timechart *tchart, const char *output_name)
1110 { "power:power_end", process_sample_power_end }, 1544 { "power:power_end", process_sample_power_end },
1111 { "power:power_frequency", process_sample_power_frequency }, 1545 { "power:power_frequency", process_sample_power_frequency },
1112#endif 1546#endif
1547
1548 { "syscalls:sys_enter_read", process_enter_read },
1549 { "syscalls:sys_enter_pread64", process_enter_read },
1550 { "syscalls:sys_enter_readv", process_enter_read },
1551 { "syscalls:sys_enter_preadv", process_enter_read },
1552 { "syscalls:sys_enter_write", process_enter_write },
1553 { "syscalls:sys_enter_pwrite64", process_enter_write },
1554 { "syscalls:sys_enter_writev", process_enter_write },
1555 { "syscalls:sys_enter_pwritev", process_enter_write },
1556 { "syscalls:sys_enter_sync", process_enter_sync },
1557 { "syscalls:sys_enter_sync_file_range", process_enter_sync },
1558 { "syscalls:sys_enter_fsync", process_enter_sync },
1559 { "syscalls:sys_enter_msync", process_enter_sync },
1560 { "syscalls:sys_enter_recvfrom", process_enter_rx },
1561 { "syscalls:sys_enter_recvmmsg", process_enter_rx },
1562 { "syscalls:sys_enter_recvmsg", process_enter_rx },
1563 { "syscalls:sys_enter_sendto", process_enter_tx },
1564 { "syscalls:sys_enter_sendmsg", process_enter_tx },
1565 { "syscalls:sys_enter_sendmmsg", process_enter_tx },
1566 { "syscalls:sys_enter_epoll_pwait", process_enter_poll },
1567 { "syscalls:sys_enter_epoll_wait", process_enter_poll },
1568 { "syscalls:sys_enter_poll", process_enter_poll },
1569 { "syscalls:sys_enter_ppoll", process_enter_poll },
1570 { "syscalls:sys_enter_pselect6", process_enter_poll },
1571 { "syscalls:sys_enter_select", process_enter_poll },
1572
1573 { "syscalls:sys_exit_read", process_exit_read },
1574 { "syscalls:sys_exit_pread64", process_exit_read },
1575 { "syscalls:sys_exit_readv", process_exit_read },
1576 { "syscalls:sys_exit_preadv", process_exit_read },
1577 { "syscalls:sys_exit_write", process_exit_write },
1578 { "syscalls:sys_exit_pwrite64", process_exit_write },
1579 { "syscalls:sys_exit_writev", process_exit_write },
1580 { "syscalls:sys_exit_pwritev", process_exit_write },
1581 { "syscalls:sys_exit_sync", process_exit_sync },
1582 { "syscalls:sys_exit_sync_file_range", process_exit_sync },
1583 { "syscalls:sys_exit_fsync", process_exit_sync },
1584 { "syscalls:sys_exit_msync", process_exit_sync },
1585 { "syscalls:sys_exit_recvfrom", process_exit_rx },
1586 { "syscalls:sys_exit_recvmmsg", process_exit_rx },
1587 { "syscalls:sys_exit_recvmsg", process_exit_rx },
1588 { "syscalls:sys_exit_sendto", process_exit_tx },
1589 { "syscalls:sys_exit_sendmsg", process_exit_tx },
1590 { "syscalls:sys_exit_sendmmsg", process_exit_tx },
1591 { "syscalls:sys_exit_epoll_pwait", process_exit_poll },
1592 { "syscalls:sys_exit_epoll_wait", process_exit_poll },
1593 { "syscalls:sys_exit_poll", process_exit_poll },
1594 { "syscalls:sys_exit_ppoll", process_exit_poll },
1595 { "syscalls:sys_exit_pselect6", process_exit_poll },
1596 { "syscalls:sys_exit_select", process_exit_poll },
1113 }; 1597 };
1114 struct perf_data_file file = { 1598 struct perf_data_file file = {
1115 .path = input_name, 1599 .path = input_name,
@@ -1154,6 +1638,139 @@ out_delete:
1154 return ret; 1638 return ret;
1155} 1639}
1156 1640
1641static int timechart__io_record(int argc, const char **argv)
1642{
1643 unsigned int rec_argc, i;
1644 const char **rec_argv;
1645 const char **p;
1646 char *filter = NULL;
1647
1648 const char * const common_args[] = {
1649 "record", "-a", "-R", "-c", "1",
1650 };
1651 unsigned int common_args_nr = ARRAY_SIZE(common_args);
1652
1653 const char * const disk_events[] = {
1654 "syscalls:sys_enter_read",
1655 "syscalls:sys_enter_pread64",
1656 "syscalls:sys_enter_readv",
1657 "syscalls:sys_enter_preadv",
1658 "syscalls:sys_enter_write",
1659 "syscalls:sys_enter_pwrite64",
1660 "syscalls:sys_enter_writev",
1661 "syscalls:sys_enter_pwritev",
1662 "syscalls:sys_enter_sync",
1663 "syscalls:sys_enter_sync_file_range",
1664 "syscalls:sys_enter_fsync",
1665 "syscalls:sys_enter_msync",
1666
1667 "syscalls:sys_exit_read",
1668 "syscalls:sys_exit_pread64",
1669 "syscalls:sys_exit_readv",
1670 "syscalls:sys_exit_preadv",
1671 "syscalls:sys_exit_write",
1672 "syscalls:sys_exit_pwrite64",
1673 "syscalls:sys_exit_writev",
1674 "syscalls:sys_exit_pwritev",
1675 "syscalls:sys_exit_sync",
1676 "syscalls:sys_exit_sync_file_range",
1677 "syscalls:sys_exit_fsync",
1678 "syscalls:sys_exit_msync",
1679 };
1680 unsigned int disk_events_nr = ARRAY_SIZE(disk_events);
1681
1682 const char * const net_events[] = {
1683 "syscalls:sys_enter_recvfrom",
1684 "syscalls:sys_enter_recvmmsg",
1685 "syscalls:sys_enter_recvmsg",
1686 "syscalls:sys_enter_sendto",
1687 "syscalls:sys_enter_sendmsg",
1688 "syscalls:sys_enter_sendmmsg",
1689
1690 "syscalls:sys_exit_recvfrom",
1691 "syscalls:sys_exit_recvmmsg",
1692 "syscalls:sys_exit_recvmsg",
1693 "syscalls:sys_exit_sendto",
1694 "syscalls:sys_exit_sendmsg",
1695 "syscalls:sys_exit_sendmmsg",
1696 };
1697 unsigned int net_events_nr = ARRAY_SIZE(net_events);
1698
1699 const char * const poll_events[] = {
1700 "syscalls:sys_enter_epoll_pwait",
1701 "syscalls:sys_enter_epoll_wait",
1702 "syscalls:sys_enter_poll",
1703 "syscalls:sys_enter_ppoll",
1704 "syscalls:sys_enter_pselect6",
1705 "syscalls:sys_enter_select",
1706
1707 "syscalls:sys_exit_epoll_pwait",
1708 "syscalls:sys_exit_epoll_wait",
1709 "syscalls:sys_exit_poll",
1710 "syscalls:sys_exit_ppoll",
1711 "syscalls:sys_exit_pselect6",
1712 "syscalls:sys_exit_select",
1713 };
1714 unsigned int poll_events_nr = ARRAY_SIZE(poll_events);
1715
1716 rec_argc = common_args_nr +
1717 disk_events_nr * 4 +
1718 net_events_nr * 4 +
1719 poll_events_nr * 4 +
1720 argc;
1721 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1722
1723 if (rec_argv == NULL)
1724 return -ENOMEM;
1725
1726 if (asprintf(&filter, "common_pid != %d", getpid()) < 0)
1727 return -ENOMEM;
1728
1729 p = rec_argv;
1730 for (i = 0; i < common_args_nr; i++)
1731 *p++ = strdup(common_args[i]);
1732
1733 for (i = 0; i < disk_events_nr; i++) {
1734 if (!is_valid_tracepoint(disk_events[i])) {
1735 rec_argc -= 4;
1736 continue;
1737 }
1738
1739 *p++ = "-e";
1740 *p++ = strdup(disk_events[i]);
1741 *p++ = "--filter";
1742 *p++ = filter;
1743 }
1744 for (i = 0; i < net_events_nr; i++) {
1745 if (!is_valid_tracepoint(net_events[i])) {
1746 rec_argc -= 4;
1747 continue;
1748 }
1749
1750 *p++ = "-e";
1751 *p++ = strdup(net_events[i]);
1752 *p++ = "--filter";
1753 *p++ = filter;
1754 }
1755 for (i = 0; i < poll_events_nr; i++) {
1756 if (!is_valid_tracepoint(poll_events[i])) {
1757 rec_argc -= 4;
1758 continue;
1759 }
1760
1761 *p++ = "-e";
1762 *p++ = strdup(poll_events[i]);
1763 *p++ = "--filter";
1764 *p++ = filter;
1765 }
1766
1767 for (i = 0; i < (unsigned int)argc; i++)
1768 *p++ = argv[i];
1769
1770 return cmd_record(rec_argc, rec_argv, NULL);
1771}
1772
1773
1157static int timechart__record(struct timechart *tchart, int argc, const char **argv) 1774static int timechart__record(struct timechart *tchart, int argc, const char **argv)
1158{ 1775{
1159 unsigned int rec_argc, i, j; 1776 unsigned int rec_argc, i, j;
@@ -1270,6 +1887,30 @@ parse_highlight(const struct option *opt __maybe_unused, const char *arg,
1270 return 0; 1887 return 0;
1271} 1888}
1272 1889
1890static int
1891parse_time(const struct option *opt, const char *arg, int __maybe_unused unset)
1892{
1893 char unit = 'n';
1894 u64 *value = opt->value;
1895
1896 if (sscanf(arg, "%" PRIu64 "%cs", value, &unit) > 0) {
1897 switch (unit) {
1898 case 'm':
1899 *value *= 1000000;
1900 break;
1901 case 'u':
1902 *value *= 1000;
1903 break;
1904 case 'n':
1905 break;
1906 default:
1907 return -1;
1908 }
1909 }
1910
1911 return 0;
1912}
1913
1273int cmd_timechart(int argc, const char **argv, 1914int cmd_timechart(int argc, const char **argv,
1274 const char *prefix __maybe_unused) 1915 const char *prefix __maybe_unused)
1275{ 1916{
@@ -1282,6 +1923,8 @@ int cmd_timechart(int argc, const char **argv,
1282 .ordered_samples = true, 1923 .ordered_samples = true,
1283 }, 1924 },
1284 .proc_num = 15, 1925 .proc_num = 15,
1926 .min_time = 1000000,
1927 .merge_dist = 1000,
1285 }; 1928 };
1286 const char *output_name = "output.svg"; 1929 const char *output_name = "output.svg";
1287 const struct option timechart_options[] = { 1930 const struct option timechart_options[] = {
@@ -1303,6 +1946,14 @@ int cmd_timechart(int argc, const char **argv,
1303 "min. number of tasks to print"), 1946 "min. number of tasks to print"),
1304 OPT_BOOLEAN('t', "topology", &tchart.topology, 1947 OPT_BOOLEAN('t', "topology", &tchart.topology,
1305 "sort CPUs according to topology"), 1948 "sort CPUs according to topology"),
1949 OPT_BOOLEAN(0, "io-skip-eagain", &tchart.skip_eagain,
1950 "skip EAGAIN errors"),
1951 OPT_CALLBACK(0, "io-min-time", &tchart.min_time, "time",
1952 "all IO faster than min-time will visually appear longer",
1953 parse_time),
1954 OPT_CALLBACK(0, "io-merge-dist", &tchart.merge_dist, "time",
1955 "merge events that are merge-dist us apart",
1956 parse_time),
1306 OPT_END() 1957 OPT_END()
1307 }; 1958 };
1308 const char * const timechart_usage[] = { 1959 const char * const timechart_usage[] = {
@@ -1314,6 +1965,8 @@ int cmd_timechart(int argc, const char **argv,
1314 OPT_BOOLEAN('P', "power-only", &tchart.power_only, "output power data only"), 1965 OPT_BOOLEAN('P', "power-only", &tchart.power_only, "output power data only"),
1315 OPT_BOOLEAN('T', "tasks-only", &tchart.tasks_only, 1966 OPT_BOOLEAN('T', "tasks-only", &tchart.tasks_only,
1316 "output processes data only"), 1967 "output processes data only"),
1968 OPT_BOOLEAN('I', "io-only", &tchart.io_only,
1969 "record only IO data"),
1317 OPT_BOOLEAN('g', "callchain", &tchart.with_backtrace, "record callchain"), 1970 OPT_BOOLEAN('g', "callchain", &tchart.with_backtrace, "record callchain"),
1318 OPT_END() 1971 OPT_END()
1319 }; 1972 };
@@ -1340,7 +1993,10 @@ int cmd_timechart(int argc, const char **argv,
1340 return -1; 1993 return -1;
1341 } 1994 }
1342 1995
1343 return timechart__record(&tchart, argc, argv); 1996 if (tchart.io_only)
1997 return timechart__io_record(argc, argv);
1998 else
1999 return timechart__record(&tchart, argc, argv);
1344 } else if (argc) 2000 } else if (argc)
1345 usage_with_options(timechart_usage, timechart_options); 2001 usage_with_options(timechart_usage, timechart_options);
1346 2002
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index f954c26de231..a6c375224f46 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -1108,6 +1108,7 @@ struct syscall {
1108 struct event_format *tp_format; 1108 struct event_format *tp_format;
1109 const char *name; 1109 const char *name;
1110 bool filtered; 1110 bool filtered;
1111 bool is_exit;
1111 struct syscall_fmt *fmt; 1112 struct syscall_fmt *fmt;
1112 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg); 1113 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
1113 void **arg_parm; 1114 void **arg_parm;
@@ -1132,6 +1133,7 @@ struct thread_trace {
1132 u64 exit_time; 1133 u64 exit_time;
1133 bool entry_pending; 1134 bool entry_pending;
1134 unsigned long nr_events; 1135 unsigned long nr_events;
1136 unsigned long pfmaj, pfmin;
1135 char *entry_str; 1137 char *entry_str;
1136 double runtime_ms; 1138 double runtime_ms;
1137 struct { 1139 struct {
@@ -1177,6 +1179,9 @@ fail:
1177 return NULL; 1179 return NULL;
1178} 1180}
1179 1181
1182#define TRACE_PFMAJ (1 << 0)
1183#define TRACE_PFMIN (1 << 1)
1184
1180struct trace { 1185struct trace {
1181 struct perf_tool tool; 1186 struct perf_tool tool;
1182 struct { 1187 struct {
@@ -1211,6 +1216,8 @@ struct trace {
1211 bool summary_only; 1216 bool summary_only;
1212 bool show_comm; 1217 bool show_comm;
1213 bool show_tool_stats; 1218 bool show_tool_stats;
1219 bool trace_syscalls;
1220 int trace_pgfaults;
1214}; 1221};
1215 1222
1216static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname) 1223static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
@@ -1276,11 +1283,11 @@ static const char *thread__fd_path(struct thread *thread, int fd,
1276 if (fd < 0) 1283 if (fd < 0)
1277 return NULL; 1284 return NULL;
1278 1285
1279 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) 1286 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
1280 if (!trace->live) 1287 if (!trace->live)
1281 return NULL; 1288 return NULL;
1282 ++trace->stats.proc_getname; 1289 ++trace->stats.proc_getname;
1283 if (thread__read_fd_path(thread, fd)) { 1290 if (thread__read_fd_path(thread, fd))
1284 return NULL; 1291 return NULL;
1285 } 1292 }
1286 1293
@@ -1473,6 +1480,8 @@ static int trace__read_syscall_info(struct trace *trace, int id)
1473 if (sc->tp_format == NULL) 1480 if (sc->tp_format == NULL)
1474 return -1; 1481 return -1;
1475 1482
1483 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1484
1476 return syscall__set_arg_fmts(sc); 1485 return syscall__set_arg_fmts(sc);
1477} 1486}
1478 1487
@@ -1535,6 +1544,7 @@ static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
1535} 1544}
1536 1545
1537typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel, 1546typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
1547 union perf_event *event,
1538 struct perf_sample *sample); 1548 struct perf_sample *sample);
1539 1549
1540static struct syscall *trace__syscall_info(struct trace *trace, 1550static struct syscall *trace__syscall_info(struct trace *trace,
@@ -1607,6 +1617,7 @@ static void thread__update_stats(struct thread_trace *ttrace,
1607} 1617}
1608 1618
1609static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel, 1619static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1620 union perf_event *event __maybe_unused,
1610 struct perf_sample *sample) 1621 struct perf_sample *sample)
1611{ 1622{
1612 char *msg; 1623 char *msg;
@@ -1629,7 +1640,6 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1629 return -1; 1640 return -1;
1630 1641
1631 args = perf_evsel__sc_tp_ptr(evsel, args, sample); 1642 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
1632 ttrace = thread->priv;
1633 1643
1634 if (ttrace->entry_str == NULL) { 1644 if (ttrace->entry_str == NULL) {
1635 ttrace->entry_str = malloc(1024); 1645 ttrace->entry_str = malloc(1024);
@@ -1644,7 +1654,7 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1644 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed, 1654 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed,
1645 args, trace, thread); 1655 args, trace, thread);
1646 1656
1647 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) { 1657 if (sc->is_exit) {
1648 if (!trace->duration_filter && !trace->summary_only) { 1658 if (!trace->duration_filter && !trace->summary_only) {
1649 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output); 1659 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1650 fprintf(trace->output, "%-70s\n", ttrace->entry_str); 1660 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
@@ -1656,6 +1666,7 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1656} 1666}
1657 1667
1658static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, 1668static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1669 union perf_event *event __maybe_unused,
1659 struct perf_sample *sample) 1670 struct perf_sample *sample)
1660{ 1671{
1661 int ret; 1672 int ret;
@@ -1687,8 +1698,6 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1687 ++trace->stats.vfs_getname; 1698 ++trace->stats.vfs_getname;
1688 } 1699 }
1689 1700
1690 ttrace = thread->priv;
1691
1692 ttrace->exit_time = sample->time; 1701 ttrace->exit_time = sample->time;
1693 1702
1694 if (ttrace->entry_time) { 1703 if (ttrace->entry_time) {
@@ -1735,6 +1744,7 @@ out:
1735} 1744}
1736 1745
1737static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel, 1746static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
1747 union perf_event *event __maybe_unused,
1738 struct perf_sample *sample) 1748 struct perf_sample *sample)
1739{ 1749{
1740 trace->last_vfs_getname = perf_evsel__rawptr(evsel, sample, "pathname"); 1750 trace->last_vfs_getname = perf_evsel__rawptr(evsel, sample, "pathname");
@@ -1742,6 +1752,7 @@ static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
1742} 1752}
1743 1753
1744static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel, 1754static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
1755 union perf_event *event __maybe_unused,
1745 struct perf_sample *sample) 1756 struct perf_sample *sample)
1746{ 1757{
1747 u64 runtime = perf_evsel__intval(evsel, sample, "runtime"); 1758 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
@@ -1768,6 +1779,80 @@ out_dump:
1768 return 0; 1779 return 0;
1769} 1780}
1770 1781
1782static void print_location(FILE *f, struct perf_sample *sample,
1783 struct addr_location *al,
1784 bool print_dso, bool print_sym)
1785{
1786
1787 if ((verbose || print_dso) && al->map)
1788 fprintf(f, "%s@", al->map->dso->long_name);
1789
1790 if ((verbose || print_sym) && al->sym)
1791 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
1792 al->addr - al->sym->start);
1793 else if (al->map)
1794 fprintf(f, "0x%" PRIx64, al->addr);
1795 else
1796 fprintf(f, "0x%" PRIx64, sample->addr);
1797}
1798
1799static int trace__pgfault(struct trace *trace,
1800 struct perf_evsel *evsel,
1801 union perf_event *event,
1802 struct perf_sample *sample)
1803{
1804 struct thread *thread;
1805 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
1806 struct addr_location al;
1807 char map_type = 'd';
1808 struct thread_trace *ttrace;
1809
1810 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1811 ttrace = thread__trace(thread, trace->output);
1812 if (ttrace == NULL)
1813 return -1;
1814
1815 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
1816 ttrace->pfmaj++;
1817 else
1818 ttrace->pfmin++;
1819
1820 if (trace->summary_only)
1821 return 0;
1822
1823 thread__find_addr_location(thread, trace->host, cpumode, MAP__FUNCTION,
1824 sample->ip, &al);
1825
1826 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
1827
1828 fprintf(trace->output, "%sfault [",
1829 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
1830 "maj" : "min");
1831
1832 print_location(trace->output, sample, &al, false, true);
1833
1834 fprintf(trace->output, "] => ");
1835
1836 thread__find_addr_location(thread, trace->host, cpumode, MAP__VARIABLE,
1837 sample->addr, &al);
1838
1839 if (!al.map) {
1840 thread__find_addr_location(thread, trace->host, cpumode,
1841 MAP__FUNCTION, sample->addr, &al);
1842
1843 if (al.map)
1844 map_type = 'x';
1845 else
1846 map_type = '?';
1847 }
1848
1849 print_location(trace->output, sample, &al, true, false);
1850
1851 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
1852
1853 return 0;
1854}
1855
1771static bool skip_sample(struct trace *trace, struct perf_sample *sample) 1856static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1772{ 1857{
1773 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) || 1858 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
@@ -1781,7 +1866,7 @@ static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1781} 1866}
1782 1867
1783static int trace__process_sample(struct perf_tool *tool, 1868static int trace__process_sample(struct perf_tool *tool,
1784 union perf_event *event __maybe_unused, 1869 union perf_event *event,
1785 struct perf_sample *sample, 1870 struct perf_sample *sample,
1786 struct perf_evsel *evsel, 1871 struct perf_evsel *evsel,
1787 struct machine *machine __maybe_unused) 1872 struct machine *machine __maybe_unused)
@@ -1799,7 +1884,7 @@ static int trace__process_sample(struct perf_tool *tool,
1799 1884
1800 if (handler) { 1885 if (handler) {
1801 ++trace->nr_events; 1886 ++trace->nr_events;
1802 handler(trace, evsel, sample); 1887 handler(trace, evsel, event, sample);
1803 } 1888 }
1804 1889
1805 return err; 1890 return err;
@@ -1826,7 +1911,7 @@ static int parse_target_str(struct trace *trace)
1826 return 0; 1911 return 0;
1827} 1912}
1828 1913
1829static int trace__record(int argc, const char **argv) 1914static int trace__record(struct trace *trace, int argc, const char **argv)
1830{ 1915{
1831 unsigned int rec_argc, i, j; 1916 unsigned int rec_argc, i, j;
1832 const char **rec_argv; 1917 const char **rec_argv;
@@ -1835,34 +1920,54 @@ static int trace__record(int argc, const char **argv)
1835 "-R", 1920 "-R",
1836 "-m", "1024", 1921 "-m", "1024",
1837 "-c", "1", 1922 "-c", "1",
1838 "-e",
1839 }; 1923 };
1840 1924
1925 const char * const sc_args[] = { "-e", };
1926 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
1927 const char * const majpf_args[] = { "-e", "major-faults" };
1928 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
1929 const char * const minpf_args[] = { "-e", "minor-faults" };
1930 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
1931
1841 /* +1 is for the event string below */ 1932 /* +1 is for the event string below */
1842 rec_argc = ARRAY_SIZE(record_args) + 1 + argc; 1933 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
1934 majpf_args_nr + minpf_args_nr + argc;
1843 rec_argv = calloc(rec_argc + 1, sizeof(char *)); 1935 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1844 1936
1845 if (rec_argv == NULL) 1937 if (rec_argv == NULL)
1846 return -ENOMEM; 1938 return -ENOMEM;
1847 1939
1940 j = 0;
1848 for (i = 0; i < ARRAY_SIZE(record_args); i++) 1941 for (i = 0; i < ARRAY_SIZE(record_args); i++)
1849 rec_argv[i] = record_args[i]; 1942 rec_argv[j++] = record_args[i];
1850 1943
1851 /* event string may be different for older kernels - e.g., RHEL6 */ 1944 if (trace->trace_syscalls) {
1852 if (is_valid_tracepoint("raw_syscalls:sys_enter")) 1945 for (i = 0; i < sc_args_nr; i++)
1853 rec_argv[i] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit"; 1946 rec_argv[j++] = sc_args[i];
1854 else if (is_valid_tracepoint("syscalls:sys_enter")) 1947
1855 rec_argv[i] = "syscalls:sys_enter,syscalls:sys_exit"; 1948 /* event string may be different for older kernels - e.g., RHEL6 */
1856 else { 1949 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
1857 pr_err("Neither raw_syscalls nor syscalls events exist.\n"); 1950 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
1858 return -1; 1951 else if (is_valid_tracepoint("syscalls:sys_enter"))
1952 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
1953 else {
1954 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
1955 return -1;
1956 }
1859 } 1957 }
1860 i++;
1861 1958
1862 for (j = 0; j < (unsigned int)argc; j++, i++) 1959 if (trace->trace_pgfaults & TRACE_PFMAJ)
1863 rec_argv[i] = argv[j]; 1960 for (i = 0; i < majpf_args_nr; i++)
1961 rec_argv[j++] = majpf_args[i];
1962
1963 if (trace->trace_pgfaults & TRACE_PFMIN)
1964 for (i = 0; i < minpf_args_nr; i++)
1965 rec_argv[j++] = minpf_args[i];
1966
1967 for (i = 0; i < (unsigned int)argc; i++)
1968 rec_argv[j++] = argv[i];
1864 1969
1865 return cmd_record(i, rec_argv, NULL); 1970 return cmd_record(j, rec_argv, NULL);
1866} 1971}
1867 1972
1868static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp); 1973static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
@@ -1882,6 +1987,30 @@ static void perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
1882 perf_evlist__add(evlist, evsel); 1987 perf_evlist__add(evlist, evsel);
1883} 1988}
1884 1989
1990static int perf_evlist__add_pgfault(struct perf_evlist *evlist,
1991 u64 config)
1992{
1993 struct perf_evsel *evsel;
1994 struct perf_event_attr attr = {
1995 .type = PERF_TYPE_SOFTWARE,
1996 .mmap_data = 1,
1997 };
1998
1999 attr.config = config;
2000 attr.sample_period = 1;
2001
2002 event_attr_init(&attr);
2003
2004 evsel = perf_evsel__new(&attr);
2005 if (!evsel)
2006 return -ENOMEM;
2007
2008 evsel->handler = trace__pgfault;
2009 perf_evlist__add(evlist, evsel);
2010
2011 return 0;
2012}
2013
1885static int trace__run(struct trace *trace, int argc, const char **argv) 2014static int trace__run(struct trace *trace, int argc, const char **argv)
1886{ 2015{
1887 struct perf_evlist *evlist = perf_evlist__new(); 2016 struct perf_evlist *evlist = perf_evlist__new();
@@ -1897,10 +2026,21 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
1897 goto out; 2026 goto out;
1898 } 2027 }
1899 2028
1900 if (perf_evlist__add_syscall_newtp(evlist, trace__sys_enter, trace__sys_exit)) 2029 if (trace->trace_syscalls &&
2030 perf_evlist__add_syscall_newtp(evlist, trace__sys_enter,
2031 trace__sys_exit))
1901 goto out_error_tp; 2032 goto out_error_tp;
1902 2033
1903 perf_evlist__add_vfs_getname(evlist); 2034 if (trace->trace_syscalls)
2035 perf_evlist__add_vfs_getname(evlist);
2036
2037 if ((trace->trace_pgfaults & TRACE_PFMAJ) &&
2038 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ))
2039 goto out_error_tp;
2040
2041 if ((trace->trace_pgfaults & TRACE_PFMIN) &&
2042 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN))
2043 goto out_error_tp;
1904 2044
1905 if (trace->sched && 2045 if (trace->sched &&
1906 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime", 2046 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
@@ -1982,7 +2122,8 @@ again:
1982 goto next_event; 2122 goto next_event;
1983 } 2123 }
1984 2124
1985 if (sample.raw_data == NULL) { 2125 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2126 sample.raw_data == NULL) {
1986 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n", 2127 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
1987 perf_evsel__name(evsel), sample.tid, 2128 perf_evsel__name(evsel), sample.tid,
1988 sample.cpu, sample.raw_size); 2129 sample.cpu, sample.raw_size);
@@ -1990,7 +2131,7 @@ again:
1990 } 2131 }
1991 2132
1992 handler = evsel->handler; 2133 handler = evsel->handler;
1993 handler(trace, evsel, &sample); 2134 handler(trace, evsel, event, &sample);
1994next_event: 2135next_event:
1995 perf_evlist__mmap_consume(evlist, i); 2136 perf_evlist__mmap_consume(evlist, i);
1996 2137
@@ -2093,13 +2234,10 @@ static int trace__replay(struct trace *trace)
2093 if (evsel == NULL) 2234 if (evsel == NULL)
2094 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, 2235 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2095 "syscalls:sys_enter"); 2236 "syscalls:sys_enter");
2096 if (evsel == NULL) {
2097 pr_err("Data file does not have raw_syscalls:sys_enter event\n");
2098 goto out;
2099 }
2100 2237
2101 if (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 || 2238 if (evsel &&
2102 perf_evsel__init_sc_tp_ptr_field(evsel, args)) { 2239 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2240 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
2103 pr_err("Error during initialize raw_syscalls:sys_enter event\n"); 2241 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2104 goto out; 2242 goto out;
2105 } 2243 }
@@ -2109,15 +2247,19 @@ static int trace__replay(struct trace *trace)
2109 if (evsel == NULL) 2247 if (evsel == NULL)
2110 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, 2248 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2111 "syscalls:sys_exit"); 2249 "syscalls:sys_exit");
2112 if (evsel == NULL) { 2250 if (evsel &&
2113 pr_err("Data file does not have raw_syscalls:sys_exit event\n"); 2251 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2252 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
2253 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
2114 goto out; 2254 goto out;
2115 } 2255 }
2116 2256
2117 if (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 || 2257 evlist__for_each(session->evlist, evsel) {
2118 perf_evsel__init_sc_tp_uint_field(evsel, ret)) { 2258 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2119 pr_err("Error during initialize raw_syscalls:sys_exit event\n"); 2259 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2120 goto out; 2260 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2261 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2262 evsel->handler = trace__pgfault;
2121 } 2263 }
2122 2264
2123 err = parse_target_str(trace); 2265 err = parse_target_str(trace);
@@ -2217,6 +2359,10 @@ static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2217 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid); 2359 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
2218 printed += fprintf(fp, "%lu events, ", ttrace->nr_events); 2360 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
2219 printed += fprintf(fp, "%.1f%%", ratio); 2361 printed += fprintf(fp, "%.1f%%", ratio);
2362 if (ttrace->pfmaj)
2363 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2364 if (ttrace->pfmin)
2365 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
2220 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms); 2366 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2221 printed += thread__dump_stats(ttrace, trace, fp); 2367 printed += thread__dump_stats(ttrace, trace, fp);
2222 2368
@@ -2264,6 +2410,23 @@ static int trace__open_output(struct trace *trace, const char *filename)
2264 return trace->output == NULL ? -errno : 0; 2410 return trace->output == NULL ? -errno : 0;
2265} 2411}
2266 2412
2413static int parse_pagefaults(const struct option *opt, const char *str,
2414 int unset __maybe_unused)
2415{
2416 int *trace_pgfaults = opt->value;
2417
2418 if (strcmp(str, "all") == 0)
2419 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2420 else if (strcmp(str, "maj") == 0)
2421 *trace_pgfaults |= TRACE_PFMAJ;
2422 else if (strcmp(str, "min") == 0)
2423 *trace_pgfaults |= TRACE_PFMIN;
2424 else
2425 return -1;
2426
2427 return 0;
2428}
2429
2267int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) 2430int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2268{ 2431{
2269 const char * const trace_usage[] = { 2432 const char * const trace_usage[] = {
@@ -2293,6 +2456,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2293 }, 2456 },
2294 .output = stdout, 2457 .output = stdout,
2295 .show_comm = true, 2458 .show_comm = true,
2459 .trace_syscalls = true,
2296 }; 2460 };
2297 const char *output_name = NULL; 2461 const char *output_name = NULL;
2298 const char *ev_qualifier_str = NULL; 2462 const char *ev_qualifier_str = NULL;
@@ -2330,20 +2494,34 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2330 "Show only syscall summary with statistics"), 2494 "Show only syscall summary with statistics"),
2331 OPT_BOOLEAN('S', "with-summary", &trace.summary, 2495 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2332 "Show all syscalls and summary with statistics"), 2496 "Show all syscalls and summary with statistics"),
2497 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
2498 "Trace pagefaults", parse_pagefaults, "maj"),
2499 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
2333 OPT_END() 2500 OPT_END()
2334 }; 2501 };
2335 int err; 2502 int err;
2336 char bf[BUFSIZ]; 2503 char bf[BUFSIZ];
2337 2504
2338 if ((argc > 1) && (strcmp(argv[1], "record") == 0)) 2505 argc = parse_options(argc, argv, trace_options, trace_usage,
2339 return trace__record(argc-2, &argv[2]); 2506 PARSE_OPT_STOP_AT_NON_OPTION);
2340 2507
2341 argc = parse_options(argc, argv, trace_options, trace_usage, 0); 2508 if (trace.trace_pgfaults) {
2509 trace.opts.sample_address = true;
2510 trace.opts.sample_time = true;
2511 }
2512
2513 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
2514 return trace__record(&trace, argc-1, &argv[1]);
2342 2515
2343 /* summary_only implies summary option, but don't overwrite summary if set */ 2516 /* summary_only implies summary option, but don't overwrite summary if set */
2344 if (trace.summary_only) 2517 if (trace.summary_only)
2345 trace.summary = trace.summary_only; 2518 trace.summary = trace.summary_only;
2346 2519
2520 if (!trace.trace_syscalls && !trace.trace_pgfaults) {
2521 pr_err("Please specify something to trace.\n");
2522 return -1;
2523 }
2524
2347 if (output_name != NULL) { 2525 if (output_name != NULL) {
2348 err = trace__open_output(&trace, output_name); 2526 err = trace__open_output(&trace, output_name);
2349 if (err < 0) { 2527 if (err < 0) {
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index f30ac5e5d271..1f67aa02d240 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -48,6 +48,10 @@ ifneq ($(ARCH),$(filter $(ARCH),x86 arm))
48 NO_LIBDW_DWARF_UNWIND := 1 48 NO_LIBDW_DWARF_UNWIND := 1
49endif 49endif
50 50
51ifeq ($(ARCH),powerpc)
52 CFLAGS += -DHAVE_SKIP_CALLCHAIN_IDX
53endif
54
51ifeq ($(LIBUNWIND_LIBS),) 55ifeq ($(LIBUNWIND_LIBS),)
52 NO_LIBUNWIND := 1 56 NO_LIBUNWIND := 1
53else 57else
@@ -160,6 +164,7 @@ CORE_FEATURE_TESTS = \
160 backtrace \ 164 backtrace \
161 dwarf \ 165 dwarf \
162 fortify-source \ 166 fortify-source \
167 sync-compare-and-swap \
163 glibc \ 168 glibc \
164 gtk2 \ 169 gtk2 \
165 gtk2-infobar \ 170 gtk2-infobar \
@@ -195,6 +200,7 @@ LIB_FEATURE_TESTS = \
195VF_FEATURE_TESTS = \ 200VF_FEATURE_TESTS = \
196 backtrace \ 201 backtrace \
197 fortify-source \ 202 fortify-source \
203 sync-compare-and-swap \
198 gtk2-infobar \ 204 gtk2-infobar \
199 libelf-getphdrnum \ 205 libelf-getphdrnum \
200 libelf-mmap \ 206 libelf-mmap \
@@ -268,6 +274,10 @@ CFLAGS += -I$(LIB_INCLUDE)
268 274
269CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE 275CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
270 276
277ifeq ($(feature-sync-compare-and-swap), 1)
278 CFLAGS += -DHAVE_SYNC_COMPARE_AND_SWAP_SUPPORT
279endif
280
271ifndef NO_BIONIC 281ifndef NO_BIONIC
272 $(call feature_check,bionic) 282 $(call feature_check,bionic)
273 ifeq ($(feature-bionic), 1) 283 ifeq ($(feature-bionic), 1)
@@ -590,6 +600,10 @@ ifndef NO_LIBNUMA
590 endif 600 endif
591endif 601endif
592 602
603ifdef HAVE_KVM_STAT_SUPPORT
604 CFLAGS += -DHAVE_KVM_STAT_SUPPORT
605endif
606
593# Among the variables below, these: 607# Among the variables below, these:
594# perfexecdir 608# perfexecdir
595# template_dir 609# template_dir
diff --git a/tools/perf/config/feature-checks/Makefile b/tools/perf/config/feature-checks/Makefile
index 64c84e5f0514..6088f8d8a434 100644
--- a/tools/perf/config/feature-checks/Makefile
+++ b/tools/perf/config/feature-checks/Makefile
@@ -5,6 +5,7 @@ FILES= \
5 test-bionic.bin \ 5 test-bionic.bin \
6 test-dwarf.bin \ 6 test-dwarf.bin \
7 test-fortify-source.bin \ 7 test-fortify-source.bin \
8 test-sync-compare-and-swap.bin \
8 test-glibc.bin \ 9 test-glibc.bin \
9 test-gtk2.bin \ 10 test-gtk2.bin \
10 test-gtk2-infobar.bin \ 11 test-gtk2-infobar.bin \
@@ -141,6 +142,9 @@ test-timerfd.bin:
141test-libdw-dwarf-unwind.bin: 142test-libdw-dwarf-unwind.bin:
142 $(BUILD) 143 $(BUILD)
143 144
145test-sync-compare-and-swap.bin:
146 $(BUILD) -Werror
147
144-include *.d 148-include *.d
145 149
146############################### 150###############################
diff --git a/tools/perf/config/feature-checks/test-all.c b/tools/perf/config/feature-checks/test-all.c
index fe5c1e5c952f..a7d022e161c0 100644
--- a/tools/perf/config/feature-checks/test-all.c
+++ b/tools/perf/config/feature-checks/test-all.c
@@ -89,6 +89,10 @@
89# include "test-libdw-dwarf-unwind.c" 89# include "test-libdw-dwarf-unwind.c"
90#undef main 90#undef main
91 91
92#define main main_test_sync_compare_and_swap
93# include "test-sync-compare-and-swap.c"
94#undef main
95
92int main(int argc, char *argv[]) 96int main(int argc, char *argv[])
93{ 97{
94 main_test_libpython(); 98 main_test_libpython();
@@ -111,6 +115,7 @@ int main(int argc, char *argv[])
111 main_test_timerfd(); 115 main_test_timerfd();
112 main_test_stackprotector_all(); 116 main_test_stackprotector_all();
113 main_test_libdw_dwarf_unwind(); 117 main_test_libdw_dwarf_unwind();
118 main_test_sync_compare_and_swap(argc, argv);
114 119
115 return 0; 120 return 0;
116} 121}
diff --git a/tools/perf/config/feature-checks/test-sync-compare-and-swap.c b/tools/perf/config/feature-checks/test-sync-compare-and-swap.c
new file mode 100644
index 000000000000..c34d4ca4af56
--- /dev/null
+++ b/tools/perf/config/feature-checks/test-sync-compare-and-swap.c
@@ -0,0 +1,14 @@
1#include <stdint.h>
2
3volatile uint64_t x;
4
5int main(int argc, char *argv[])
6{
7 uint64_t old, new = argc;
8
9 argv = argv;
10 do {
11 old = __sync_val_compare_and_swap(&x, 0, 0);
12 } while (!__sync_bool_compare_and_swap(&x, old, new));
13 return old == new;
14}
diff --git a/tools/perf/perf-sys.h b/tools/perf/perf-sys.h
index 5268a1481d23..937e4324ad94 100644
--- a/tools/perf/perf-sys.h
+++ b/tools/perf/perf-sys.h
@@ -54,6 +54,7 @@
54#define mb() asm volatile("bcr 15,0" ::: "memory") 54#define mb() asm volatile("bcr 15,0" ::: "memory")
55#define wmb() asm volatile("bcr 15,0" ::: "memory") 55#define wmb() asm volatile("bcr 15,0" ::: "memory")
56#define rmb() asm volatile("bcr 15,0" ::: "memory") 56#define rmb() asm volatile("bcr 15,0" ::: "memory")
57#define CPUINFO_PROC "vendor_id"
57#endif 58#endif
58 59
59#ifdef __sh__ 60#ifdef __sh__
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 95c58fc15284..2282d41879a2 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -13,11 +13,12 @@
13#include "util/quote.h" 13#include "util/quote.h"
14#include "util/run-command.h" 14#include "util/run-command.h"
15#include "util/parse-events.h" 15#include "util/parse-events.h"
16#include "util/debug.h"
16#include <api/fs/debugfs.h> 17#include <api/fs/debugfs.h>
17#include <pthread.h> 18#include <pthread.h>
18 19
19const char perf_usage_string[] = 20const char perf_usage_string[] =
20 "perf [--version] [--help] COMMAND [ARGS]"; 21 "perf [--version] [--help] [OPTIONS] COMMAND [ARGS]";
21 22
22const char perf_more_info_string[] = 23const char perf_more_info_string[] =
23 "See 'perf help COMMAND' for more information on a specific command."; 24 "See 'perf help COMMAND' for more information on a specific command.";
@@ -212,6 +213,16 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
212 printf("%s ", p->cmd); 213 printf("%s ", p->cmd);
213 } 214 }
214 exit(0); 215 exit(0);
216 } else if (!strcmp(cmd, "--debug")) {
217 if (*argc < 2) {
218 fprintf(stderr, "No variable specified for --debug.\n");
219 usage(perf_usage_string);
220 }
221 if (perf_debug_option((*argv)[1]))
222 usage(perf_usage_string);
223
224 (*argv)++;
225 (*argc)--;
215 } else { 226 } else {
216 fprintf(stderr, "Unknown option: %s\n", cmd); 227 fprintf(stderr, "Unknown option: %s\n", cmd);
217 usage(perf_usage_string); 228 usage(perf_usage_string);
diff --git a/tools/perf/scripts/perl/bin/failed-syscalls-record b/tools/perf/scripts/perl/bin/failed-syscalls-record
index 8104895a7b67..74685f318379 100644
--- a/tools/perf/scripts/perl/bin/failed-syscalls-record
+++ b/tools/perf/scripts/perl/bin/failed-syscalls-record
@@ -1,2 +1,3 @@
1#!/bin/bash 1#!/bin/bash
2perf record -e raw_syscalls:sys_exit $@ 2(perf record -e raw_syscalls:sys_exit $@ || \
3 perf record -e syscalls:sys_exit $@) 2> /dev/null
diff --git a/tools/perf/scripts/perl/failed-syscalls.pl b/tools/perf/scripts/perl/failed-syscalls.pl
index 94bc25a347eb..55e7ae4c5c88 100644
--- a/tools/perf/scripts/perl/failed-syscalls.pl
+++ b/tools/perf/scripts/perl/failed-syscalls.pl
@@ -26,6 +26,11 @@ sub raw_syscalls::sys_exit
26 } 26 }
27} 27}
28 28
29sub syscalls::sys_exit
30{
31 raw_syscalls::sys_exit(@_)
32}
33
29sub trace_end 34sub trace_end
30{ 35{
31 printf("\nfailed syscalls by comm:\n\n"); 36 printf("\nfailed syscalls by comm:\n\n");
diff --git a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py
index de7211e4fa47..38dfb720fb6f 100644
--- a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py
+++ b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py
@@ -107,12 +107,13 @@ def taskState(state):
107 107
108class EventHeaders: 108class EventHeaders:
109 def __init__(self, common_cpu, common_secs, common_nsecs, 109 def __init__(self, common_cpu, common_secs, common_nsecs,
110 common_pid, common_comm): 110 common_pid, common_comm, common_callchain):
111 self.cpu = common_cpu 111 self.cpu = common_cpu
112 self.secs = common_secs 112 self.secs = common_secs
113 self.nsecs = common_nsecs 113 self.nsecs = common_nsecs
114 self.pid = common_pid 114 self.pid = common_pid
115 self.comm = common_comm 115 self.comm = common_comm
116 self.callchain = common_callchain
116 117
117 def ts(self): 118 def ts(self):
118 return (self.secs * (10 ** 9)) + self.nsecs 119 return (self.secs * (10 ** 9)) + self.nsecs
diff --git a/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record b/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record
index 8104895a7b67..74685f318379 100644
--- a/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record
+++ b/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record
@@ -1,2 +1,3 @@
1#!/bin/bash 1#!/bin/bash
2perf record -e raw_syscalls:sys_exit $@ 2(perf record -e raw_syscalls:sys_exit $@ || \
3 perf record -e syscalls:sys_exit $@) 2> /dev/null
diff --git a/tools/perf/scripts/python/bin/sctop-record b/tools/perf/scripts/python/bin/sctop-record
index 4efbfaa7f6a5..d6940841e54f 100644
--- a/tools/perf/scripts/python/bin/sctop-record
+++ b/tools/perf/scripts/python/bin/sctop-record
@@ -1,2 +1,3 @@
1#!/bin/bash 1#!/bin/bash
2perf record -e raw_syscalls:sys_enter $@ 2(perf record -e raw_syscalls:sys_enter $@ || \
3 perf record -e syscalls:sys_enter $@) 2> /dev/null
diff --git a/tools/perf/scripts/python/bin/syscall-counts-by-pid-record b/tools/perf/scripts/python/bin/syscall-counts-by-pid-record
index 4efbfaa7f6a5..d6940841e54f 100644
--- a/tools/perf/scripts/python/bin/syscall-counts-by-pid-record
+++ b/tools/perf/scripts/python/bin/syscall-counts-by-pid-record
@@ -1,2 +1,3 @@
1#!/bin/bash 1#!/bin/bash
2perf record -e raw_syscalls:sys_enter $@ 2(perf record -e raw_syscalls:sys_enter $@ || \
3 perf record -e syscalls:sys_enter $@) 2> /dev/null
diff --git a/tools/perf/scripts/python/bin/syscall-counts-record b/tools/perf/scripts/python/bin/syscall-counts-record
index 4efbfaa7f6a5..d6940841e54f 100644
--- a/tools/perf/scripts/python/bin/syscall-counts-record
+++ b/tools/perf/scripts/python/bin/syscall-counts-record
@@ -1,2 +1,3 @@
1#!/bin/bash 1#!/bin/bash
2perf record -e raw_syscalls:sys_enter $@ 2(perf record -e raw_syscalls:sys_enter $@ || \
3 perf record -e syscalls:sys_enter $@) 2> /dev/null
diff --git a/tools/perf/scripts/python/check-perf-trace.py b/tools/perf/scripts/python/check-perf-trace.py
index 4647a7694cf6..334599c6032c 100644
--- a/tools/perf/scripts/python/check-perf-trace.py
+++ b/tools/perf/scripts/python/check-perf-trace.py
@@ -27,7 +27,7 @@ def trace_end():
27 27
28def irq__softirq_entry(event_name, context, common_cpu, 28def irq__softirq_entry(event_name, context, common_cpu,
29 common_secs, common_nsecs, common_pid, common_comm, 29 common_secs, common_nsecs, common_pid, common_comm,
30 vec): 30 common_callchain, vec):
31 print_header(event_name, common_cpu, common_secs, common_nsecs, 31 print_header(event_name, common_cpu, common_secs, common_nsecs,
32 common_pid, common_comm) 32 common_pid, common_comm)
33 33
@@ -38,7 +38,7 @@ def irq__softirq_entry(event_name, context, common_cpu,
38 38
39def kmem__kmalloc(event_name, context, common_cpu, 39def kmem__kmalloc(event_name, context, common_cpu,
40 common_secs, common_nsecs, common_pid, common_comm, 40 common_secs, common_nsecs, common_pid, common_comm,
41 call_site, ptr, bytes_req, bytes_alloc, 41 common_callchain, call_site, ptr, bytes_req, bytes_alloc,
42 gfp_flags): 42 gfp_flags):
43 print_header(event_name, common_cpu, common_secs, common_nsecs, 43 print_header(event_name, common_cpu, common_secs, common_nsecs,
44 common_pid, common_comm) 44 common_pid, common_comm)
diff --git a/tools/perf/scripts/python/failed-syscalls-by-pid.py b/tools/perf/scripts/python/failed-syscalls-by-pid.py
index 85805fac4116..cafeff3d74db 100644
--- a/tools/perf/scripts/python/failed-syscalls-by-pid.py
+++ b/tools/perf/scripts/python/failed-syscalls-by-pid.py
@@ -39,7 +39,7 @@ def trace_end():
39 39
40def raw_syscalls__sys_exit(event_name, context, common_cpu, 40def raw_syscalls__sys_exit(event_name, context, common_cpu,
41 common_secs, common_nsecs, common_pid, common_comm, 41 common_secs, common_nsecs, common_pid, common_comm,
42 id, ret): 42 common_callchain, id, ret):
43 if (for_comm and common_comm != for_comm) or \ 43 if (for_comm and common_comm != for_comm) or \
44 (for_pid and common_pid != for_pid ): 44 (for_pid and common_pid != for_pid ):
45 return 45 return
@@ -50,6 +50,11 @@ def raw_syscalls__sys_exit(event_name, context, common_cpu,
50 except TypeError: 50 except TypeError:
51 syscalls[common_comm][common_pid][id][ret] = 1 51 syscalls[common_comm][common_pid][id][ret] = 1
52 52
53def syscalls__sys_exit(event_name, context, common_cpu,
54 common_secs, common_nsecs, common_pid, common_comm,
55 id, ret):
56 raw_syscalls__sys_exit(**locals())
57
53def print_error_totals(): 58def print_error_totals():
54 if for_comm is not None: 59 if for_comm is not None:
55 print "\nsyscall errors for %s:\n\n" % (for_comm), 60 print "\nsyscall errors for %s:\n\n" % (for_comm),
diff --git a/tools/perf/scripts/python/futex-contention.py b/tools/perf/scripts/python/futex-contention.py
index 11e70a388d41..0f5cf437b602 100644
--- a/tools/perf/scripts/python/futex-contention.py
+++ b/tools/perf/scripts/python/futex-contention.py
@@ -21,7 +21,7 @@ thread_blocktime = {}
21lock_waits = {} # long-lived stats on (tid,lock) blockage elapsed time 21lock_waits = {} # long-lived stats on (tid,lock) blockage elapsed time
22process_names = {} # long-lived pid-to-execname mapping 22process_names = {} # long-lived pid-to-execname mapping
23 23
24def syscalls__sys_enter_futex(event, ctxt, cpu, s, ns, tid, comm, 24def syscalls__sys_enter_futex(event, ctxt, cpu, s, ns, tid, comm, callchain,
25 nr, uaddr, op, val, utime, uaddr2, val3): 25 nr, uaddr, op, val, utime, uaddr2, val3):
26 cmd = op & FUTEX_CMD_MASK 26 cmd = op & FUTEX_CMD_MASK
27 if cmd != FUTEX_WAIT: 27 if cmd != FUTEX_WAIT:
@@ -31,7 +31,7 @@ def syscalls__sys_enter_futex(event, ctxt, cpu, s, ns, tid, comm,
31 thread_thislock[tid] = uaddr 31 thread_thislock[tid] = uaddr
32 thread_blocktime[tid] = nsecs(s, ns) 32 thread_blocktime[tid] = nsecs(s, ns)
33 33
34def syscalls__sys_exit_futex(event, ctxt, cpu, s, ns, tid, comm, 34def syscalls__sys_exit_futex(event, ctxt, cpu, s, ns, tid, comm, callchain,
35 nr, ret): 35 nr, ret):
36 if thread_blocktime.has_key(tid): 36 if thread_blocktime.has_key(tid):
37 elapsed = nsecs(s, ns) - thread_blocktime[tid] 37 elapsed = nsecs(s, ns) - thread_blocktime[tid]
diff --git a/tools/perf/scripts/python/net_dropmonitor.py b/tools/perf/scripts/python/net_dropmonitor.py
index b5740599aabd..0b6ce8c253e8 100755
--- a/tools/perf/scripts/python/net_dropmonitor.py
+++ b/tools/perf/scripts/python/net_dropmonitor.py
@@ -66,7 +66,7 @@ def trace_end():
66 print_drop_table() 66 print_drop_table()
67 67
68# called from perf, when it finds a correspoinding event 68# called from perf, when it finds a correspoinding event
69def skb__kfree_skb(name, context, cpu, sec, nsec, pid, comm, 69def skb__kfree_skb(name, context, cpu, sec, nsec, pid, comm, callchain,
70 skbaddr, location, protocol): 70 skbaddr, location, protocol):
71 slocation = str(location) 71 slocation = str(location)
72 try: 72 try:
diff --git a/tools/perf/scripts/python/netdev-times.py b/tools/perf/scripts/python/netdev-times.py
index 9aa0a32972e8..4d21ef2d601d 100644
--- a/tools/perf/scripts/python/netdev-times.py
+++ b/tools/perf/scripts/python/netdev-times.py
@@ -224,75 +224,75 @@ def trace_end():
224 (len(rx_skb_list), of_count_rx_skb_list) 224 (len(rx_skb_list), of_count_rx_skb_list)
225 225
226# called from perf, when it finds a correspoinding event 226# called from perf, when it finds a correspoinding event
227def irq__softirq_entry(name, context, cpu, sec, nsec, pid, comm, vec): 227def irq__softirq_entry(name, context, cpu, sec, nsec, pid, comm, callchain, vec):
228 if symbol_str("irq__softirq_entry", "vec", vec) != "NET_RX": 228 if symbol_str("irq__softirq_entry", "vec", vec) != "NET_RX":
229 return 229 return
230 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, vec) 230 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, vec)
231 all_event_list.append(event_info) 231 all_event_list.append(event_info)
232 232
233def irq__softirq_exit(name, context, cpu, sec, nsec, pid, comm, vec): 233def irq__softirq_exit(name, context, cpu, sec, nsec, pid, comm, callchain, vec):
234 if symbol_str("irq__softirq_entry", "vec", vec) != "NET_RX": 234 if symbol_str("irq__softirq_entry", "vec", vec) != "NET_RX":
235 return 235 return
236 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, vec) 236 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, vec)
237 all_event_list.append(event_info) 237 all_event_list.append(event_info)
238 238
239def irq__softirq_raise(name, context, cpu, sec, nsec, pid, comm, vec): 239def irq__softirq_raise(name, context, cpu, sec, nsec, pid, comm, callchain, vec):
240 if symbol_str("irq__softirq_entry", "vec", vec) != "NET_RX": 240 if symbol_str("irq__softirq_entry", "vec", vec) != "NET_RX":
241 return 241 return
242 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, vec) 242 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, vec)
243 all_event_list.append(event_info) 243 all_event_list.append(event_info)
244 244
245def irq__irq_handler_entry(name, context, cpu, sec, nsec, pid, comm, 245def irq__irq_handler_entry(name, context, cpu, sec, nsec, pid, comm,
246 irq, irq_name): 246 callchain, irq, irq_name):
247 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, 247 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
248 irq, irq_name) 248 irq, irq_name)
249 all_event_list.append(event_info) 249 all_event_list.append(event_info)
250 250
251def irq__irq_handler_exit(name, context, cpu, sec, nsec, pid, comm, irq, ret): 251def irq__irq_handler_exit(name, context, cpu, sec, nsec, pid, comm, callchain, irq, ret):
252 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, irq, ret) 252 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, irq, ret)
253 all_event_list.append(event_info) 253 all_event_list.append(event_info)
254 254
255def napi__napi_poll(name, context, cpu, sec, nsec, pid, comm, napi, dev_name): 255def napi__napi_poll(name, context, cpu, sec, nsec, pid, comm, callchain, napi, dev_name):
256 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, 256 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
257 napi, dev_name) 257 napi, dev_name)
258 all_event_list.append(event_info) 258 all_event_list.append(event_info)
259 259
260def net__netif_receive_skb(name, context, cpu, sec, nsec, pid, comm, skbaddr, 260def net__netif_receive_skb(name, context, cpu, sec, nsec, pid, comm, callchain, skbaddr,
261 skblen, dev_name): 261 skblen, dev_name):
262 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, 262 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
263 skbaddr, skblen, dev_name) 263 skbaddr, skblen, dev_name)
264 all_event_list.append(event_info) 264 all_event_list.append(event_info)
265 265
266def net__netif_rx(name, context, cpu, sec, nsec, pid, comm, skbaddr, 266def net__netif_rx(name, context, cpu, sec, nsec, pid, comm, callchain, skbaddr,
267 skblen, dev_name): 267 skblen, dev_name):
268 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, 268 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
269 skbaddr, skblen, dev_name) 269 skbaddr, skblen, dev_name)
270 all_event_list.append(event_info) 270 all_event_list.append(event_info)
271 271
272def net__net_dev_queue(name, context, cpu, sec, nsec, pid, comm, 272def net__net_dev_queue(name, context, cpu, sec, nsec, pid, comm, callchain,
273 skbaddr, skblen, dev_name): 273 skbaddr, skblen, dev_name):
274 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, 274 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
275 skbaddr, skblen, dev_name) 275 skbaddr, skblen, dev_name)
276 all_event_list.append(event_info) 276 all_event_list.append(event_info)
277 277
278def net__net_dev_xmit(name, context, cpu, sec, nsec, pid, comm, 278def net__net_dev_xmit(name, context, cpu, sec, nsec, pid, comm, callchain,
279 skbaddr, skblen, rc, dev_name): 279 skbaddr, skblen, rc, dev_name):
280 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, 280 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
281 skbaddr, skblen, rc ,dev_name) 281 skbaddr, skblen, rc ,dev_name)
282 all_event_list.append(event_info) 282 all_event_list.append(event_info)
283 283
284def skb__kfree_skb(name, context, cpu, sec, nsec, pid, comm, 284def skb__kfree_skb(name, context, cpu, sec, nsec, pid, comm, callchain,
285 skbaddr, protocol, location): 285 skbaddr, protocol, location):
286 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, 286 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
287 skbaddr, protocol, location) 287 skbaddr, protocol, location)
288 all_event_list.append(event_info) 288 all_event_list.append(event_info)
289 289
290def skb__consume_skb(name, context, cpu, sec, nsec, pid, comm, skbaddr): 290def skb__consume_skb(name, context, cpu, sec, nsec, pid, comm, callchain, skbaddr):
291 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, 291 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
292 skbaddr) 292 skbaddr)
293 all_event_list.append(event_info) 293 all_event_list.append(event_info)
294 294
295def skb__skb_copy_datagram_iovec(name, context, cpu, sec, nsec, pid, comm, 295def skb__skb_copy_datagram_iovec(name, context, cpu, sec, nsec, pid, comm, callchain,
296 skbaddr, skblen): 296 skbaddr, skblen):
297 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, 297 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
298 skbaddr, skblen) 298 skbaddr, skblen)
diff --git a/tools/perf/scripts/python/sched-migration.py b/tools/perf/scripts/python/sched-migration.py
index 74d55ec08aed..de66cb3b72c9 100644
--- a/tools/perf/scripts/python/sched-migration.py
+++ b/tools/perf/scripts/python/sched-migration.py
@@ -369,93 +369,92 @@ def trace_end():
369 369
370def sched__sched_stat_runtime(event_name, context, common_cpu, 370def sched__sched_stat_runtime(event_name, context, common_cpu,
371 common_secs, common_nsecs, common_pid, common_comm, 371 common_secs, common_nsecs, common_pid, common_comm,
372 comm, pid, runtime, vruntime): 372 common_callchain, comm, pid, runtime, vruntime):
373 pass 373 pass
374 374
375def sched__sched_stat_iowait(event_name, context, common_cpu, 375def sched__sched_stat_iowait(event_name, context, common_cpu,
376 common_secs, common_nsecs, common_pid, common_comm, 376 common_secs, common_nsecs, common_pid, common_comm,
377 comm, pid, delay): 377 common_callchain, comm, pid, delay):
378 pass 378 pass
379 379
380def sched__sched_stat_sleep(event_name, context, common_cpu, 380def sched__sched_stat_sleep(event_name, context, common_cpu,
381 common_secs, common_nsecs, common_pid, common_comm, 381 common_secs, common_nsecs, common_pid, common_comm,
382 comm, pid, delay): 382 common_callchain, comm, pid, delay):
383 pass 383 pass
384 384
385def sched__sched_stat_wait(event_name, context, common_cpu, 385def sched__sched_stat_wait(event_name, context, common_cpu,
386 common_secs, common_nsecs, common_pid, common_comm, 386 common_secs, common_nsecs, common_pid, common_comm,
387 comm, pid, delay): 387 common_callchain, comm, pid, delay):
388 pass 388 pass
389 389
390def sched__sched_process_fork(event_name, context, common_cpu, 390def sched__sched_process_fork(event_name, context, common_cpu,
391 common_secs, common_nsecs, common_pid, common_comm, 391 common_secs, common_nsecs, common_pid, common_comm,
392 parent_comm, parent_pid, child_comm, child_pid): 392 common_callchain, parent_comm, parent_pid, child_comm, child_pid):
393 pass 393 pass
394 394
395def sched__sched_process_wait(event_name, context, common_cpu, 395def sched__sched_process_wait(event_name, context, common_cpu,
396 common_secs, common_nsecs, common_pid, common_comm, 396 common_secs, common_nsecs, common_pid, common_comm,
397 comm, pid, prio): 397 common_callchain, comm, pid, prio):
398 pass 398 pass
399 399
400def sched__sched_process_exit(event_name, context, common_cpu, 400def sched__sched_process_exit(event_name, context, common_cpu,
401 common_secs, common_nsecs, common_pid, common_comm, 401 common_secs, common_nsecs, common_pid, common_comm,
402 comm, pid, prio): 402 common_callchain, comm, pid, prio):
403 pass 403 pass
404 404
405def sched__sched_process_free(event_name, context, common_cpu, 405def sched__sched_process_free(event_name, context, common_cpu,
406 common_secs, common_nsecs, common_pid, common_comm, 406 common_secs, common_nsecs, common_pid, common_comm,
407 comm, pid, prio): 407 common_callchain, comm, pid, prio):
408 pass 408 pass
409 409
410def sched__sched_migrate_task(event_name, context, common_cpu, 410def sched__sched_migrate_task(event_name, context, common_cpu,
411 common_secs, common_nsecs, common_pid, common_comm, 411 common_secs, common_nsecs, common_pid, common_comm,
412 comm, pid, prio, orig_cpu, 412 common_callchain, comm, pid, prio, orig_cpu,
413 dest_cpu): 413 dest_cpu):
414 headers = EventHeaders(common_cpu, common_secs, common_nsecs, 414 headers = EventHeaders(common_cpu, common_secs, common_nsecs,
415 common_pid, common_comm) 415 common_pid, common_comm, common_callchain)
416 parser.migrate(headers, pid, prio, orig_cpu, dest_cpu) 416 parser.migrate(headers, pid, prio, orig_cpu, dest_cpu)
417 417
418def sched__sched_switch(event_name, context, common_cpu, 418def sched__sched_switch(event_name, context, common_cpu,
419 common_secs, common_nsecs, common_pid, common_comm, 419 common_secs, common_nsecs, common_pid, common_comm, common_callchain,
420 prev_comm, prev_pid, prev_prio, prev_state, 420 prev_comm, prev_pid, prev_prio, prev_state,
421 next_comm, next_pid, next_prio): 421 next_comm, next_pid, next_prio):
422 422
423 headers = EventHeaders(common_cpu, common_secs, common_nsecs, 423 headers = EventHeaders(common_cpu, common_secs, common_nsecs,
424 common_pid, common_comm) 424 common_pid, common_comm, common_callchain)
425 parser.sched_switch(headers, prev_comm, prev_pid, prev_prio, prev_state, 425 parser.sched_switch(headers, prev_comm, prev_pid, prev_prio, prev_state,
426 next_comm, next_pid, next_prio) 426 next_comm, next_pid, next_prio)
427 427
428def sched__sched_wakeup_new(event_name, context, common_cpu, 428def sched__sched_wakeup_new(event_name, context, common_cpu,
429 common_secs, common_nsecs, common_pid, common_comm, 429 common_secs, common_nsecs, common_pid, common_comm,
430 comm, pid, prio, success, 430 common_callchain, comm, pid, prio, success,
431 target_cpu): 431 target_cpu):
432 headers = EventHeaders(common_cpu, common_secs, common_nsecs, 432 headers = EventHeaders(common_cpu, common_secs, common_nsecs,
433 common_pid, common_comm) 433 common_pid, common_comm, common_callchain)
434 parser.wake_up(headers, comm, pid, success, target_cpu, 1) 434 parser.wake_up(headers, comm, pid, success, target_cpu, 1)
435 435
436def sched__sched_wakeup(event_name, context, common_cpu, 436def sched__sched_wakeup(event_name, context, common_cpu,
437 common_secs, common_nsecs, common_pid, common_comm, 437 common_secs, common_nsecs, common_pid, common_comm,
438 comm, pid, prio, success, 438 common_callchain, comm, pid, prio, success,
439 target_cpu): 439 target_cpu):
440 headers = EventHeaders(common_cpu, common_secs, common_nsecs, 440 headers = EventHeaders(common_cpu, common_secs, common_nsecs,
441 common_pid, common_comm) 441 common_pid, common_comm, common_callchain)
442 parser.wake_up(headers, comm, pid, success, target_cpu, 0) 442 parser.wake_up(headers, comm, pid, success, target_cpu, 0)
443 443
444def sched__sched_wait_task(event_name, context, common_cpu, 444def sched__sched_wait_task(event_name, context, common_cpu,
445 common_secs, common_nsecs, common_pid, common_comm, 445 common_secs, common_nsecs, common_pid, common_comm,
446 comm, pid, prio): 446 common_callchain, comm, pid, prio):
447 pass 447 pass
448 448
449def sched__sched_kthread_stop_ret(event_name, context, common_cpu, 449def sched__sched_kthread_stop_ret(event_name, context, common_cpu,
450 common_secs, common_nsecs, common_pid, common_comm, 450 common_secs, common_nsecs, common_pid, common_comm,
451 ret): 451 common_callchain, ret):
452 pass 452 pass
453 453
454def sched__sched_kthread_stop(event_name, context, common_cpu, 454def sched__sched_kthread_stop(event_name, context, common_cpu,
455 common_secs, common_nsecs, common_pid, common_comm, 455 common_secs, common_nsecs, common_pid, common_comm,
456 comm, pid): 456 common_callchain, comm, pid):
457 pass 457 pass
458 458
459def trace_unhandled(event_name, context, common_cpu, common_secs, common_nsecs, 459def trace_unhandled(event_name, context, event_fields_dict):
460 common_pid, common_comm):
461 pass 460 pass
diff --git a/tools/perf/scripts/python/sctop.py b/tools/perf/scripts/python/sctop.py
index 42c267e292fa..61621b93affb 100644
--- a/tools/perf/scripts/python/sctop.py
+++ b/tools/perf/scripts/python/sctop.py
@@ -44,7 +44,7 @@ def trace_begin():
44 44
45def raw_syscalls__sys_enter(event_name, context, common_cpu, 45def raw_syscalls__sys_enter(event_name, context, common_cpu,
46 common_secs, common_nsecs, common_pid, common_comm, 46 common_secs, common_nsecs, common_pid, common_comm,
47 id, args): 47 common_callchain, id, args):
48 if for_comm is not None: 48 if for_comm is not None:
49 if common_comm != for_comm: 49 if common_comm != for_comm:
50 return 50 return
@@ -53,6 +53,11 @@ def raw_syscalls__sys_enter(event_name, context, common_cpu,
53 except TypeError: 53 except TypeError:
54 syscalls[id] = 1 54 syscalls[id] = 1
55 55
56def syscalls__sys_enter(event_name, context, common_cpu,
57 common_secs, common_nsecs, common_pid, common_comm,
58 id, args):
59 raw_syscalls__sys_enter(**locals())
60
56def print_syscall_totals(interval): 61def print_syscall_totals(interval):
57 while 1: 62 while 1:
58 clear_term() 63 clear_term()
diff --git a/tools/perf/scripts/python/syscall-counts-by-pid.py b/tools/perf/scripts/python/syscall-counts-by-pid.py
index c64d1c55d745..daf314cc5dd3 100644
--- a/tools/perf/scripts/python/syscall-counts-by-pid.py
+++ b/tools/perf/scripts/python/syscall-counts-by-pid.py
@@ -38,7 +38,7 @@ def trace_end():
38 38
39def raw_syscalls__sys_enter(event_name, context, common_cpu, 39def raw_syscalls__sys_enter(event_name, context, common_cpu,
40 common_secs, common_nsecs, common_pid, common_comm, 40 common_secs, common_nsecs, common_pid, common_comm,
41 id, args): 41 common_callchain, id, args):
42 42
43 if (for_comm and common_comm != for_comm) or \ 43 if (for_comm and common_comm != for_comm) or \
44 (for_pid and common_pid != for_pid ): 44 (for_pid and common_pid != for_pid ):
@@ -48,6 +48,11 @@ def raw_syscalls__sys_enter(event_name, context, common_cpu,
48 except TypeError: 48 except TypeError:
49 syscalls[common_comm][common_pid][id] = 1 49 syscalls[common_comm][common_pid][id] = 1
50 50
51def syscalls__sys_enter(event_name, context, common_cpu,
52 common_secs, common_nsecs, common_pid, common_comm,
53 id, args):
54 raw_syscalls__sys_enter(**locals())
55
51def print_syscall_totals(): 56def print_syscall_totals():
52 if for_comm is not None: 57 if for_comm is not None:
53 print "\nsyscall events for %s:\n\n" % (for_comm), 58 print "\nsyscall events for %s:\n\n" % (for_comm),
diff --git a/tools/perf/scripts/python/syscall-counts.py b/tools/perf/scripts/python/syscall-counts.py
index b435d3f188e8..e66a7730aeb5 100644
--- a/tools/perf/scripts/python/syscall-counts.py
+++ b/tools/perf/scripts/python/syscall-counts.py
@@ -35,7 +35,7 @@ def trace_end():
35 35
36def raw_syscalls__sys_enter(event_name, context, common_cpu, 36def raw_syscalls__sys_enter(event_name, context, common_cpu,
37 common_secs, common_nsecs, common_pid, common_comm, 37 common_secs, common_nsecs, common_pid, common_comm,
38 id, args): 38 common_callchain, id, args):
39 if for_comm is not None: 39 if for_comm is not None:
40 if common_comm != for_comm: 40 if common_comm != for_comm:
41 return 41 return
@@ -44,6 +44,11 @@ def raw_syscalls__sys_enter(event_name, context, common_cpu,
44 except TypeError: 44 except TypeError:
45 syscalls[id] = 1 45 syscalls[id] = 1
46 46
47def syscalls__sys_enter(event_name, context, common_cpu,
48 common_secs, common_nsecs, common_pid, common_comm,
49 id, args):
50 raw_syscalls__sys_enter(**locals())
51
47def print_syscall_totals(): 52def print_syscall_totals():
48 if for_comm is not None: 53 if for_comm is not None:
49 print "\nsyscall events for %s:\n\n" % (for_comm), 54 print "\nsyscall events for %s:\n\n" % (for_comm),
diff --git a/tools/perf/tests/attr/base-record b/tools/perf/tests/attr/base-record
index e9bd6391f2ae..f710b92ccff6 100644
--- a/tools/perf/tests/attr/base-record
+++ b/tools/perf/tests/attr/base-record
@@ -1,7 +1,8 @@
1[event] 1[event]
2fd=1 2fd=1
3group_fd=-1 3group_fd=-1
4flags=0 4# 0 or PERF_FLAG_FD_CLOEXEC flag
5flags=0|8
5cpu=* 6cpu=*
6type=0|1 7type=0|1
7size=96 8size=96
diff --git a/tools/perf/tests/attr/base-stat b/tools/perf/tests/attr/base-stat
index 91cd48b399f3..dc3ada2470c0 100644
--- a/tools/perf/tests/attr/base-stat
+++ b/tools/perf/tests/attr/base-stat
@@ -1,7 +1,8 @@
1[event] 1[event]
2fd=1 2fd=1
3group_fd=-1 3group_fd=-1
4flags=0 4# 0 or PERF_FLAG_FD_CLOEXEC flag
5flags=0|8
5cpu=* 6cpu=*
6type=0 7type=0
7size=96 8size=96
diff --git a/tools/perf/tests/bp_signal.c b/tools/perf/tests/bp_signal.c
index aba095489193..a02b035fd5aa 100644
--- a/tools/perf/tests/bp_signal.c
+++ b/tools/perf/tests/bp_signal.c
@@ -25,6 +25,7 @@
25#include "tests.h" 25#include "tests.h"
26#include "debug.h" 26#include "debug.h"
27#include "perf.h" 27#include "perf.h"
28#include "cloexec.h"
28 29
29static int fd1; 30static int fd1;
30static int fd2; 31static int fd2;
@@ -78,7 +79,8 @@ static int bp_event(void *fn, int setup_signal)
78 pe.exclude_kernel = 1; 79 pe.exclude_kernel = 1;
79 pe.exclude_hv = 1; 80 pe.exclude_hv = 1;
80 81
81 fd = sys_perf_event_open(&pe, 0, -1, -1, 0); 82 fd = sys_perf_event_open(&pe, 0, -1, -1,
83 perf_event_open_cloexec_flag());
82 if (fd < 0) { 84 if (fd < 0) {
83 pr_debug("failed opening event %llx\n", pe.config); 85 pr_debug("failed opening event %llx\n", pe.config);
84 return TEST_FAIL; 86 return TEST_FAIL;
diff --git a/tools/perf/tests/bp_signal_overflow.c b/tools/perf/tests/bp_signal_overflow.c
index 44ac82179708..e76537724491 100644
--- a/tools/perf/tests/bp_signal_overflow.c
+++ b/tools/perf/tests/bp_signal_overflow.c
@@ -24,6 +24,7 @@
24#include "tests.h" 24#include "tests.h"
25#include "debug.h" 25#include "debug.h"
26#include "perf.h" 26#include "perf.h"
27#include "cloexec.h"
27 28
28static int overflows; 29static int overflows;
29 30
@@ -91,7 +92,8 @@ int test__bp_signal_overflow(void)
91 pe.exclude_kernel = 1; 92 pe.exclude_kernel = 1;
92 pe.exclude_hv = 1; 93 pe.exclude_hv = 1;
93 94
94 fd = sys_perf_event_open(&pe, 0, -1, -1, 0); 95 fd = sys_perf_event_open(&pe, 0, -1, -1,
96 perf_event_open_cloexec_flag());
95 if (fd < 0) { 97 if (fd < 0) {
96 pr_debug("failed opening event %llx\n", pe.config); 98 pr_debug("failed opening event %llx\n", pe.config);
97 return TEST_FAIL; 99 return TEST_FAIL;
diff --git a/tools/perf/tests/dso-data.c b/tools/perf/tests/dso-data.c
index 630808cd7cc2..caaf37f079b1 100644
--- a/tools/perf/tests/dso-data.c
+++ b/tools/perf/tests/dso-data.c
@@ -10,6 +10,7 @@
10#include "machine.h" 10#include "machine.h"
11#include "symbol.h" 11#include "symbol.h"
12#include "tests.h" 12#include "tests.h"
13#include "debug.h"
13 14
14static char *test_file(int size) 15static char *test_file(int size)
15{ 16{
diff --git a/tools/perf/tests/evsel-roundtrip-name.c b/tools/perf/tests/evsel-roundtrip-name.c
index 465cdbc345cf..b8d8341b383e 100644
--- a/tools/perf/tests/evsel-roundtrip-name.c
+++ b/tools/perf/tests/evsel-roundtrip-name.c
@@ -2,6 +2,7 @@
2#include "evsel.h" 2#include "evsel.h"
3#include "parse-events.h" 3#include "parse-events.h"
4#include "tests.h" 4#include "tests.h"
5#include "debug.h"
5 6
6static int perf_evsel__roundtrip_cache_name_test(void) 7static int perf_evsel__roundtrip_cache_name_test(void)
7{ 8{
diff --git a/tools/perf/tests/evsel-tp-sched.c b/tools/perf/tests/evsel-tp-sched.c
index 35d7fdb2328d..52162425c969 100644
--- a/tools/perf/tests/evsel-tp-sched.c
+++ b/tools/perf/tests/evsel-tp-sched.c
@@ -1,6 +1,7 @@
1#include <traceevent/event-parse.h> 1#include <traceevent/event-parse.h>
2#include "evsel.h" 2#include "evsel.h"
3#include "tests.h" 3#include "tests.h"
4#include "debug.h"
4 5
5static int perf_evsel__test_field(struct perf_evsel *evsel, const char *name, 6static int perf_evsel__test_field(struct perf_evsel *evsel, const char *name,
6 int size, bool should_be_signed) 7 int size, bool should_be_signed)
diff --git a/tools/perf/tests/open-syscall-tp-fields.c b/tools/perf/tests/open-syscall-tp-fields.c
index c505ef2af245..0785b64ffd6c 100644
--- a/tools/perf/tests/open-syscall-tp-fields.c
+++ b/tools/perf/tests/open-syscall-tp-fields.c
@@ -3,6 +3,7 @@
3#include "evsel.h" 3#include "evsel.h"
4#include "thread_map.h" 4#include "thread_map.h"
5#include "tests.h" 5#include "tests.h"
6#include "debug.h"
6 7
7int test__syscall_open_tp_fields(void) 8int test__syscall_open_tp_fields(void)
8{ 9{
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
index deba66955f8c..5941927a4b7f 100644
--- a/tools/perf/tests/parse-events.c
+++ b/tools/perf/tests/parse-events.c
@@ -5,6 +5,7 @@
5#include <api/fs/fs.h> 5#include <api/fs/fs.h>
6#include <api/fs/debugfs.h> 6#include <api/fs/debugfs.h>
7#include "tests.h" 7#include "tests.h"
8#include "debug.h"
8#include <linux/hw_breakpoint.h> 9#include <linux/hw_breakpoint.h>
9 10
10#define PERF_TP_SAMPLE_TYPE (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | \ 11#define PERF_TP_SAMPLE_TYPE (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | \
diff --git a/tools/perf/tests/parse-no-sample-id-all.c b/tools/perf/tests/parse-no-sample-id-all.c
index 905019f9b740..2c63ea658541 100644
--- a/tools/perf/tests/parse-no-sample-id-all.c
+++ b/tools/perf/tests/parse-no-sample-id-all.c
@@ -7,6 +7,7 @@
7#include "evlist.h" 7#include "evlist.h"
8#include "header.h" 8#include "header.h"
9#include "util.h" 9#include "util.h"
10#include "debug.h"
10 11
11static int process_event(struct perf_evlist **pevlist, union perf_event *event) 12static int process_event(struct perf_evlist **pevlist, union perf_event *event)
12{ 13{
diff --git a/tools/perf/tests/perf-time-to-tsc.c b/tools/perf/tests/perf-time-to-tsc.c
index 3b7cd4d32dcb..f238442b238a 100644
--- a/tools/perf/tests/perf-time-to-tsc.c
+++ b/tools/perf/tests/perf-time-to-tsc.c
@@ -8,10 +8,9 @@
8#include "evsel.h" 8#include "evsel.h"
9#include "thread_map.h" 9#include "thread_map.h"
10#include "cpumap.h" 10#include "cpumap.h"
11#include "tsc.h"
11#include "tests.h" 12#include "tests.h"
12 13
13#include "../arch/x86/util/tsc.h"
14
15#define CHECK__(x) { \ 14#define CHECK__(x) { \
16 while ((x) < 0) { \ 15 while ((x) < 0) { \
17 pr_debug(#x " failed!\n"); \ 16 pr_debug(#x " failed!\n"); \
@@ -26,15 +25,6 @@
26 } \ 25 } \
27} 26}
28 27
29static u64 rdtsc(void)
30{
31 unsigned int low, high;
32
33 asm volatile("rdtsc" : "=a" (low), "=d" (high));
34
35 return low | ((u64)high) << 32;
36}
37
38/** 28/**
39 * test__perf_time_to_tsc - test converting perf time to TSC. 29 * test__perf_time_to_tsc - test converting perf time to TSC.
40 * 30 *
diff --git a/tools/perf/tests/rdpmc.c b/tools/perf/tests/rdpmc.c
index e59143fd9e71..c04d1f268576 100644
--- a/tools/perf/tests/rdpmc.c
+++ b/tools/perf/tests/rdpmc.c
@@ -6,6 +6,7 @@
6#include "perf.h" 6#include "perf.h"
7#include "debug.h" 7#include "debug.h"
8#include "tests.h" 8#include "tests.h"
9#include "cloexec.h"
9 10
10#if defined(__x86_64__) || defined(__i386__) 11#if defined(__x86_64__) || defined(__i386__)
11 12
@@ -104,7 +105,8 @@ static int __test__rdpmc(void)
104 sa.sa_sigaction = segfault_handler; 105 sa.sa_sigaction = segfault_handler;
105 sigaction(SIGSEGV, &sa, NULL); 106 sigaction(SIGSEGV, &sa, NULL);
106 107
107 fd = sys_perf_event_open(&attr, 0, -1, -1, 0); 108 fd = sys_perf_event_open(&attr, 0, -1, -1,
109 perf_event_open_cloexec_flag());
108 if (fd < 0) { 110 if (fd < 0) {
109 pr_err("Error: sys_perf_event_open() syscall returned " 111 pr_err("Error: sys_perf_event_open() syscall returned "
110 "with %d (%s)\n", fd, strerror(errno)); 112 "with %d (%s)\n", fd, strerror(errno));
diff --git a/tools/perf/tests/sample-parsing.c b/tools/perf/tests/sample-parsing.c
index 7ae8d17db3d9..ca292f9a4ae2 100644
--- a/tools/perf/tests/sample-parsing.c
+++ b/tools/perf/tests/sample-parsing.c
@@ -4,6 +4,7 @@
4#include "util.h" 4#include "util.h"
5#include "event.h" 5#include "event.h"
6#include "evsel.h" 6#include "evsel.h"
7#include "debug.h"
7 8
8#include "tests.h" 9#include "tests.h"
9 10
diff --git a/tools/perf/tests/thread-mg-share.c b/tools/perf/tests/thread-mg-share.c
index 2b2e0dbe114f..b028499dd3cf 100644
--- a/tools/perf/tests/thread-mg-share.c
+++ b/tools/perf/tests/thread-mg-share.c
@@ -2,6 +2,7 @@
2#include "machine.h" 2#include "machine.h"
3#include "thread.h" 3#include "thread.h"
4#include "map.h" 4#include "map.h"
5#include "debug.h"
5 6
6int test__thread_mg_share(void) 7int test__thread_mg_share(void)
7{ 8{
diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c
index 3ccf6e14f89b..6680fa5cb9dd 100644
--- a/tools/perf/ui/browser.c
+++ b/tools/perf/ui/browser.c
@@ -150,7 +150,7 @@ unsigned int ui_browser__rb_tree_refresh(struct ui_browser *browser)
150 while (nd != NULL) { 150 while (nd != NULL) {
151 ui_browser__gotorc(browser, row, 0); 151 ui_browser__gotorc(browser, row, 0);
152 browser->write(browser, nd, row); 152 browser->write(browser, nd, row);
153 if (++row == browser->height) 153 if (++row == browser->rows)
154 break; 154 break;
155 nd = rb_next(nd); 155 nd = rb_next(nd);
156 } 156 }
@@ -166,7 +166,7 @@ bool ui_browser__is_current_entry(struct ui_browser *browser, unsigned row)
166void ui_browser__refresh_dimensions(struct ui_browser *browser) 166void ui_browser__refresh_dimensions(struct ui_browser *browser)
167{ 167{
168 browser->width = SLtt_Screen_Cols - 1; 168 browser->width = SLtt_Screen_Cols - 1;
169 browser->height = SLtt_Screen_Rows - 2; 169 browser->height = browser->rows = SLtt_Screen_Rows - 2;
170 browser->y = 1; 170 browser->y = 1;
171 browser->x = 0; 171 browser->x = 0;
172} 172}
@@ -250,7 +250,10 @@ int ui_browser__show(struct ui_browser *browser, const char *title,
250 int err; 250 int err;
251 va_list ap; 251 va_list ap;
252 252
253 ui_browser__refresh_dimensions(browser); 253 if (browser->refresh_dimensions == NULL)
254 browser->refresh_dimensions = ui_browser__refresh_dimensions;
255
256 browser->refresh_dimensions(browser);
254 257
255 pthread_mutex_lock(&ui__lock); 258 pthread_mutex_lock(&ui__lock);
256 __ui_browser__show_title(browser, title); 259 __ui_browser__show_title(browser, title);
@@ -279,7 +282,7 @@ static void ui_browser__scrollbar_set(struct ui_browser *browser)
279{ 282{
280 int height = browser->height, h = 0, pct = 0, 283 int height = browser->height, h = 0, pct = 0,
281 col = browser->width, 284 col = browser->width,
282 row = browser->y - 1; 285 row = 0;
283 286
284 if (browser->nr_entries > 1) { 287 if (browser->nr_entries > 1) {
285 pct = ((browser->index * (browser->height - 1)) / 288 pct = ((browser->index * (browser->height - 1)) /
@@ -367,7 +370,7 @@ int ui_browser__run(struct ui_browser *browser, int delay_secs)
367 370
368 if (key == K_RESIZE) { 371 if (key == K_RESIZE) {
369 ui__refresh_dimensions(false); 372 ui__refresh_dimensions(false);
370 ui_browser__refresh_dimensions(browser); 373 browser->refresh_dimensions(browser);
371 __ui_browser__show_title(browser, browser->title); 374 __ui_browser__show_title(browser, browser->title);
372 ui_helpline__puts(browser->helpline); 375 ui_helpline__puts(browser->helpline);
373 continue; 376 continue;
@@ -389,7 +392,7 @@ int ui_browser__run(struct ui_browser *browser, int delay_secs)
389 if (browser->index == browser->nr_entries - 1) 392 if (browser->index == browser->nr_entries - 1)
390 break; 393 break;
391 ++browser->index; 394 ++browser->index;
392 if (browser->index == browser->top_idx + browser->height) { 395 if (browser->index == browser->top_idx + browser->rows) {
393 ++browser->top_idx; 396 ++browser->top_idx;
394 browser->seek(browser, +1, SEEK_CUR); 397 browser->seek(browser, +1, SEEK_CUR);
395 } 398 }
@@ -405,10 +408,10 @@ int ui_browser__run(struct ui_browser *browser, int delay_secs)
405 break; 408 break;
406 case K_PGDN: 409 case K_PGDN:
407 case ' ': 410 case ' ':
408 if (browser->top_idx + browser->height > browser->nr_entries - 1) 411 if (browser->top_idx + browser->rows > browser->nr_entries - 1)
409 break; 412 break;
410 413
411 offset = browser->height; 414 offset = browser->rows;
412 if (browser->index + offset > browser->nr_entries - 1) 415 if (browser->index + offset > browser->nr_entries - 1)
413 offset = browser->nr_entries - 1 - browser->index; 416 offset = browser->nr_entries - 1 - browser->index;
414 browser->index += offset; 417 browser->index += offset;
@@ -419,10 +422,10 @@ int ui_browser__run(struct ui_browser *browser, int delay_secs)
419 if (browser->top_idx == 0) 422 if (browser->top_idx == 0)
420 break; 423 break;
421 424
422 if (browser->top_idx < browser->height) 425 if (browser->top_idx < browser->rows)
423 offset = browser->top_idx; 426 offset = browser->top_idx;
424 else 427 else
425 offset = browser->height; 428 offset = browser->rows;
426 429
427 browser->index -= offset; 430 browser->index -= offset;
428 browser->top_idx -= offset; 431 browser->top_idx -= offset;
@@ -432,7 +435,7 @@ int ui_browser__run(struct ui_browser *browser, int delay_secs)
432 ui_browser__reset_index(browser); 435 ui_browser__reset_index(browser);
433 break; 436 break;
434 case K_END: 437 case K_END:
435 offset = browser->height - 1; 438 offset = browser->rows - 1;
436 if (offset >= browser->nr_entries) 439 if (offset >= browser->nr_entries)
437 offset = browser->nr_entries - 1; 440 offset = browser->nr_entries - 1;
438 441
@@ -462,7 +465,7 @@ unsigned int ui_browser__list_head_refresh(struct ui_browser *browser)
462 if (!browser->filter || !browser->filter(browser, pos)) { 465 if (!browser->filter || !browser->filter(browser, pos)) {
463 ui_browser__gotorc(browser, row, 0); 466 ui_browser__gotorc(browser, row, 0);
464 browser->write(browser, pos, row); 467 browser->write(browser, pos, row);
465 if (++row == browser->height) 468 if (++row == browser->rows)
466 break; 469 break;
467 } 470 }
468 } 471 }
@@ -587,7 +590,7 @@ unsigned int ui_browser__argv_refresh(struct ui_browser *browser)
587 if (!browser->filter || !browser->filter(browser, *pos)) { 590 if (!browser->filter || !browser->filter(browser, *pos)) {
588 ui_browser__gotorc(browser, row, 0); 591 ui_browser__gotorc(browser, row, 0);
589 browser->write(browser, pos, row); 592 browser->write(browser, pos, row);
590 if (++row == browser->height) 593 if (++row == browser->rows)
591 break; 594 break;
592 } 595 }
593 596
@@ -623,7 +626,7 @@ static void __ui_browser__line_arrow_up(struct ui_browser *browser,
623 626
624 SLsmg_set_char_set(1); 627 SLsmg_set_char_set(1);
625 628
626 if (start < browser->top_idx + browser->height) { 629 if (start < browser->top_idx + browser->rows) {
627 row = start - browser->top_idx; 630 row = start - browser->top_idx;
628 ui_browser__gotorc(browser, row, column); 631 ui_browser__gotorc(browser, row, column);
629 SLsmg_write_char(SLSMG_LLCORN_CHAR); 632 SLsmg_write_char(SLSMG_LLCORN_CHAR);
@@ -633,7 +636,7 @@ static void __ui_browser__line_arrow_up(struct ui_browser *browser,
633 if (row-- == 0) 636 if (row-- == 0)
634 goto out; 637 goto out;
635 } else 638 } else
636 row = browser->height - 1; 639 row = browser->rows - 1;
637 640
638 if (end > browser->top_idx) 641 if (end > browser->top_idx)
639 end_row = end - browser->top_idx; 642 end_row = end - browser->top_idx;
@@ -675,8 +678,8 @@ static void __ui_browser__line_arrow_down(struct ui_browser *browser,
675 } else 678 } else
676 row = 0; 679 row = 0;
677 680
678 if (end >= browser->top_idx + browser->height) 681 if (end >= browser->top_idx + browser->rows)
679 end_row = browser->height - 1; 682 end_row = browser->rows - 1;
680 else 683 else
681 end_row = end - browser->top_idx; 684 end_row = end - browser->top_idx;
682 685
@@ -684,7 +687,7 @@ static void __ui_browser__line_arrow_down(struct ui_browser *browser,
684 SLsmg_draw_vline(end_row - row + 1); 687 SLsmg_draw_vline(end_row - row + 1);
685 688
686 ui_browser__gotorc(browser, end_row, column); 689 ui_browser__gotorc(browser, end_row, column);
687 if (end < browser->top_idx + browser->height) { 690 if (end < browser->top_idx + browser->rows) {
688 SLsmg_write_char(SLSMG_LLCORN_CHAR); 691 SLsmg_write_char(SLSMG_LLCORN_CHAR);
689 ui_browser__gotorc(browser, end_row, column + 1); 692 ui_browser__gotorc(browser, end_row, column + 1);
690 SLsmg_write_char(SLSMG_HLINE_CHAR); 693 SLsmg_write_char(SLSMG_HLINE_CHAR);
diff --git a/tools/perf/ui/browser.h b/tools/perf/ui/browser.h
index 03d4d6295f10..92ae72113965 100644
--- a/tools/perf/ui/browser.h
+++ b/tools/perf/ui/browser.h
@@ -14,11 +14,12 @@
14struct ui_browser { 14struct ui_browser {
15 u64 index, top_idx; 15 u64 index, top_idx;
16 void *top, *entries; 16 void *top, *entries;
17 u16 y, x, width, height; 17 u16 y, x, width, height, rows;
18 int current_color; 18 int current_color;
19 void *priv; 19 void *priv;
20 const char *title; 20 const char *title;
21 char *helpline; 21 char *helpline;
22 void (*refresh_dimensions)(struct ui_browser *browser);
22 unsigned int (*refresh)(struct ui_browser *browser); 23 unsigned int (*refresh)(struct ui_browser *browser);
23 void (*write)(struct ui_browser *browser, void *entry, int row); 24 void (*write)(struct ui_browser *browser, void *entry, int row);
24 void (*seek)(struct ui_browser *browser, off_t offset, int whence); 25 void (*seek)(struct ui_browser *browser, off_t offset, int whence);
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index 04a229aa5c0f..a94b11fc5e00 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -26,6 +26,7 @@ struct hist_browser {
26 struct map_symbol *selection; 26 struct map_symbol *selection;
27 int print_seq; 27 int print_seq;
28 bool show_dso; 28 bool show_dso;
29 bool show_headers;
29 float min_pcnt; 30 float min_pcnt;
30 u64 nr_non_filtered_entries; 31 u64 nr_non_filtered_entries;
31 u64 nr_callchain_rows; 32 u64 nr_callchain_rows;
@@ -33,8 +34,7 @@ struct hist_browser {
33 34
34extern void hist_browser__init_hpp(void); 35extern void hist_browser__init_hpp(void);
35 36
36static int hists__browser_title(struct hists *hists, char *bf, size_t size, 37static int hists__browser_title(struct hists *hists, char *bf, size_t size);
37 const char *ev_name);
38static void hist_browser__update_nr_entries(struct hist_browser *hb); 38static void hist_browser__update_nr_entries(struct hist_browser *hb);
39 39
40static struct rb_node *hists__filter_entries(struct rb_node *nd, 40static struct rb_node *hists__filter_entries(struct rb_node *nd,
@@ -57,11 +57,42 @@ static u32 hist_browser__nr_entries(struct hist_browser *hb)
57 return nr_entries + hb->nr_callchain_rows; 57 return nr_entries + hb->nr_callchain_rows;
58} 58}
59 59
60static void hist_browser__refresh_dimensions(struct hist_browser *browser) 60static void hist_browser__update_rows(struct hist_browser *hb)
61{ 61{
62 struct ui_browser *browser = &hb->b;
63 u16 header_offset = hb->show_headers ? 1 : 0, index_row;
64
65 browser->rows = browser->height - header_offset;
66 /*
67 * Verify if we were at the last line and that line isn't
68 * visibe because we now show the header line(s).
69 */
70 index_row = browser->index - browser->top_idx;
71 if (index_row >= browser->rows)
72 browser->index -= index_row - browser->rows + 1;
73}
74
75static void hist_browser__refresh_dimensions(struct ui_browser *browser)
76{
77 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
78
62 /* 3 == +/- toggle symbol before actual hist_entry rendering */ 79 /* 3 == +/- toggle symbol before actual hist_entry rendering */
63 browser->b.width = 3 + (hists__sort_list_width(browser->hists) + 80 browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]"));
64 sizeof("[k]")); 81 /*
82 * FIXME: Just keeping existing behaviour, but this really should be
83 * before updating browser->width, as it will invalidate the
84 * calculation above. Fix this and the fallout in another
85 * changeset.
86 */
87 ui_browser__refresh_dimensions(browser);
88 hist_browser__update_rows(hb);
89}
90
91static void hist_browser__gotorc(struct hist_browser *browser, int row, int column)
92{
93 u16 header_offset = browser->show_headers ? 1 : 0;
94
95 ui_browser__gotorc(&browser->b, row + header_offset, column);
65} 96}
66 97
67static void hist_browser__reset(struct hist_browser *browser) 98static void hist_browser__reset(struct hist_browser *browser)
@@ -74,7 +105,7 @@ static void hist_browser__reset(struct hist_browser *browser)
74 105
75 hist_browser__update_nr_entries(browser); 106 hist_browser__update_nr_entries(browser);
76 browser->b.nr_entries = hist_browser__nr_entries(browser); 107 browser->b.nr_entries = hist_browser__nr_entries(browser);
77 hist_browser__refresh_dimensions(browser); 108 hist_browser__refresh_dimensions(&browser->b);
78 ui_browser__reset_index(&browser->b); 109 ui_browser__reset_index(&browser->b);
79} 110}
80 111
@@ -346,7 +377,7 @@ static void ui_browser__warn_lost_events(struct ui_browser *browser)
346 "Or reduce the sampling frequency."); 377 "Or reduce the sampling frequency.");
347} 378}
348 379
349static int hist_browser__run(struct hist_browser *browser, const char *ev_name, 380static int hist_browser__run(struct hist_browser *browser,
350 struct hist_browser_timer *hbt) 381 struct hist_browser_timer *hbt)
351{ 382{
352 int key; 383 int key;
@@ -356,8 +387,7 @@ static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
356 browser->b.entries = &browser->hists->entries; 387 browser->b.entries = &browser->hists->entries;
357 browser->b.nr_entries = hist_browser__nr_entries(browser); 388 browser->b.nr_entries = hist_browser__nr_entries(browser);
358 389
359 hist_browser__refresh_dimensions(browser); 390 hists__browser_title(browser->hists, title, sizeof(title));
360 hists__browser_title(browser->hists, title, sizeof(title), ev_name);
361 391
362 if (ui_browser__show(&browser->b, title, 392 if (ui_browser__show(&browser->b, title,
363 "Press '?' for help on key bindings") < 0) 393 "Press '?' for help on key bindings") < 0)
@@ -384,7 +414,7 @@ static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
384 ui_browser__warn_lost_events(&browser->b); 414 ui_browser__warn_lost_events(&browser->b);
385 } 415 }
386 416
387 hists__browser_title(browser->hists, title, sizeof(title), ev_name); 417 hists__browser_title(browser->hists, title, sizeof(title));
388 ui_browser__show_title(&browser->b, title); 418 ui_browser__show_title(&browser->b, title);
389 continue; 419 continue;
390 } 420 }
@@ -393,10 +423,10 @@ static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
393 struct hist_entry *h = rb_entry(browser->b.top, 423 struct hist_entry *h = rb_entry(browser->b.top,
394 struct hist_entry, rb_node); 424 struct hist_entry, rb_node);
395 ui_helpline__pop(); 425 ui_helpline__pop();
396 ui_helpline__fpush("%d: nr_ent=(%d,%d), height=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d", 426 ui_helpline__fpush("%d: nr_ent=(%d,%d), rows=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d",
397 seq++, browser->b.nr_entries, 427 seq++, browser->b.nr_entries,
398 browser->hists->nr_entries, 428 browser->hists->nr_entries,
399 browser->b.height, 429 browser->b.rows,
400 browser->b.index, 430 browser->b.index,
401 browser->b.top_idx, 431 browser->b.top_idx,
402 h->row_offset, h->nr_rows); 432 h->row_offset, h->nr_rows);
@@ -410,6 +440,10 @@ static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
410 /* Expand the whole world. */ 440 /* Expand the whole world. */
411 hist_browser__set_folding(browser, true); 441 hist_browser__set_folding(browser, true);
412 break; 442 break;
443 case 'H':
444 browser->show_headers = !browser->show_headers;
445 hist_browser__update_rows(browser);
446 break;
413 case K_ENTER: 447 case K_ENTER:
414 if (hist_browser__toggle_fold(browser)) 448 if (hist_browser__toggle_fold(browser))
415 break; 449 break;
@@ -509,13 +543,13 @@ static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browse
509 } 543 }
510 544
511 ui_browser__set_color(&browser->b, color); 545 ui_browser__set_color(&browser->b, color);
512 ui_browser__gotorc(&browser->b, row, 0); 546 hist_browser__gotorc(browser, row, 0);
513 slsmg_write_nstring(" ", offset + extra_offset); 547 slsmg_write_nstring(" ", offset + extra_offset);
514 slsmg_printf("%c ", folded_sign); 548 slsmg_printf("%c ", folded_sign);
515 slsmg_write_nstring(str, width); 549 slsmg_write_nstring(str, width);
516 free(alloc_str); 550 free(alloc_str);
517 551
518 if (++row == browser->b.height) 552 if (++row == browser->b.rows)
519 goto out; 553 goto out;
520do_next: 554do_next:
521 if (folded_sign == '+') 555 if (folded_sign == '+')
@@ -528,7 +562,7 @@ do_next:
528 new_level, row, row_offset, 562 new_level, row, row_offset,
529 is_current_entry); 563 is_current_entry);
530 } 564 }
531 if (row == browser->b.height) 565 if (row == browser->b.rows)
532 goto out; 566 goto out;
533 node = next; 567 node = next;
534 } 568 }
@@ -568,13 +602,13 @@ static int hist_browser__show_callchain_node(struct hist_browser *browser,
568 602
569 s = callchain_list__sym_name(chain, bf, sizeof(bf), 603 s = callchain_list__sym_name(chain, bf, sizeof(bf),
570 browser->show_dso); 604 browser->show_dso);
571 ui_browser__gotorc(&browser->b, row, 0); 605 hist_browser__gotorc(browser, row, 0);
572 ui_browser__set_color(&browser->b, color); 606 ui_browser__set_color(&browser->b, color);
573 slsmg_write_nstring(" ", offset); 607 slsmg_write_nstring(" ", offset);
574 slsmg_printf("%c ", folded_sign); 608 slsmg_printf("%c ", folded_sign);
575 slsmg_write_nstring(s, width - 2); 609 slsmg_write_nstring(s, width - 2);
576 610
577 if (++row == browser->b.height) 611 if (++row == browser->b.rows)
578 goto out; 612 goto out;
579 } 613 }
580 614
@@ -603,7 +637,7 @@ static int hist_browser__show_callchain(struct hist_browser *browser,
603 row += hist_browser__show_callchain_node(browser, node, level, 637 row += hist_browser__show_callchain_node(browser, node, level,
604 row, row_offset, 638 row, row_offset,
605 is_current_entry); 639 is_current_entry);
606 if (row == browser->b.height) 640 if (row == browser->b.rows)
607 break; 641 break;
608 } 642 }
609 643
@@ -733,7 +767,7 @@ static int hist_browser__show_entry(struct hist_browser *browser,
733 .ptr = &arg, 767 .ptr = &arg,
734 }; 768 };
735 769
736 ui_browser__gotorc(&browser->b, row, 0); 770 hist_browser__gotorc(browser, row, 0);
737 771
738 perf_hpp__for_each_format(fmt) { 772 perf_hpp__for_each_format(fmt) {
739 if (perf_hpp__should_skip(fmt)) 773 if (perf_hpp__should_skip(fmt))
@@ -777,7 +811,7 @@ static int hist_browser__show_entry(struct hist_browser *browser,
777 } else 811 } else
778 --row_offset; 812 --row_offset;
779 813
780 if (folded_sign == '-' && row != browser->b.height) { 814 if (folded_sign == '-' && row != browser->b.rows) {
781 printed += hist_browser__show_callchain(browser, &entry->sorted_chain, 815 printed += hist_browser__show_callchain(browser, &entry->sorted_chain,
782 1, row, &row_offset, 816 1, row, &row_offset,
783 &current_entry); 817 &current_entry);
@@ -788,6 +822,56 @@ static int hist_browser__show_entry(struct hist_browser *browser,
788 return printed; 822 return printed;
789} 823}
790 824
825static int advance_hpp_check(struct perf_hpp *hpp, int inc)
826{
827 advance_hpp(hpp, inc);
828 return hpp->size <= 0;
829}
830
831static int hists__scnprintf_headers(char *buf, size_t size, struct hists *hists)
832{
833 struct perf_hpp dummy_hpp = {
834 .buf = buf,
835 .size = size,
836 };
837 struct perf_hpp_fmt *fmt;
838 size_t ret = 0;
839
840 if (symbol_conf.use_callchain) {
841 ret = scnprintf(buf, size, " ");
842 if (advance_hpp_check(&dummy_hpp, ret))
843 return ret;
844 }
845
846 perf_hpp__for_each_format(fmt) {
847 if (perf_hpp__should_skip(fmt))
848 continue;
849
850 /* We need to add the length of the columns header. */
851 perf_hpp__reset_width(fmt, hists);
852
853 ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
854 if (advance_hpp_check(&dummy_hpp, ret))
855 break;
856
857 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
858 if (advance_hpp_check(&dummy_hpp, ret))
859 break;
860 }
861
862 return ret;
863}
864
865static void hist_browser__show_headers(struct hist_browser *browser)
866{
867 char headers[1024];
868
869 hists__scnprintf_headers(headers, sizeof(headers), browser->hists);
870 ui_browser__gotorc(&browser->b, 0, 0);
871 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
872 slsmg_write_nstring(headers, browser->b.width + 1);
873}
874
791static void ui_browser__hists_init_top(struct ui_browser *browser) 875static void ui_browser__hists_init_top(struct ui_browser *browser)
792{ 876{
793 if (browser->top == NULL) { 877 if (browser->top == NULL) {
@@ -801,9 +885,15 @@ static void ui_browser__hists_init_top(struct ui_browser *browser)
801static unsigned int hist_browser__refresh(struct ui_browser *browser) 885static unsigned int hist_browser__refresh(struct ui_browser *browser)
802{ 886{
803 unsigned row = 0; 887 unsigned row = 0;
888 u16 header_offset = 0;
804 struct rb_node *nd; 889 struct rb_node *nd;
805 struct hist_browser *hb = container_of(browser, struct hist_browser, b); 890 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
806 891
892 if (hb->show_headers) {
893 hist_browser__show_headers(hb);
894 header_offset = 1;
895 }
896
807 ui_browser__hists_init_top(browser); 897 ui_browser__hists_init_top(browser);
808 898
809 for (nd = browser->top; nd; nd = rb_next(nd)) { 899 for (nd = browser->top; nd; nd = rb_next(nd)) {
@@ -818,11 +908,11 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)
818 continue; 908 continue;
819 909
820 row += hist_browser__show_entry(hb, h, row); 910 row += hist_browser__show_entry(hb, h, row);
821 if (row == browser->height) 911 if (row == browser->rows)
822 break; 912 break;
823 } 913 }
824 914
825 return row; 915 return row + header_offset;
826} 916}
827 917
828static struct rb_node *hists__filter_entries(struct rb_node *nd, 918static struct rb_node *hists__filter_entries(struct rb_node *nd,
@@ -1191,8 +1281,10 @@ static struct hist_browser *hist_browser__new(struct hists *hists)
1191 if (browser) { 1281 if (browser) {
1192 browser->hists = hists; 1282 browser->hists = hists;
1193 browser->b.refresh = hist_browser__refresh; 1283 browser->b.refresh = hist_browser__refresh;
1284 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
1194 browser->b.seek = ui_browser__hists_seek; 1285 browser->b.seek = ui_browser__hists_seek;
1195 browser->b.use_navkeypressed = true; 1286 browser->b.use_navkeypressed = true;
1287 browser->show_headers = symbol_conf.show_hist_headers;
1196 } 1288 }
1197 1289
1198 return browser; 1290 return browser;
@@ -1213,8 +1305,7 @@ static struct thread *hist_browser__selected_thread(struct hist_browser *browser
1213 return browser->he_selection->thread; 1305 return browser->he_selection->thread;
1214} 1306}
1215 1307
1216static int hists__browser_title(struct hists *hists, char *bf, size_t size, 1308static int hists__browser_title(struct hists *hists, char *bf, size_t size)
1217 const char *ev_name)
1218{ 1309{
1219 char unit; 1310 char unit;
1220 int printed; 1311 int printed;
@@ -1223,6 +1314,7 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size,
1223 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE]; 1314 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1224 u64 nr_events = hists->stats.total_period; 1315 u64 nr_events = hists->stats.total_period;
1225 struct perf_evsel *evsel = hists_to_evsel(hists); 1316 struct perf_evsel *evsel = hists_to_evsel(hists);
1317 const char *ev_name = perf_evsel__name(evsel);
1226 char buf[512]; 1318 char buf[512];
1227 size_t buflen = sizeof(buf); 1319 size_t buflen = sizeof(buf);
1228 1320
@@ -1390,7 +1482,7 @@ static void hist_browser__update_nr_entries(struct hist_browser *hb)
1390} 1482}
1391 1483
1392static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, 1484static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1393 const char *helpline, const char *ev_name, 1485 const char *helpline,
1394 bool left_exits, 1486 bool left_exits,
1395 struct hist_browser_timer *hbt, 1487 struct hist_browser_timer *hbt,
1396 float min_pcnt, 1488 float min_pcnt,
@@ -1422,6 +1514,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1422 "d Zoom into current DSO\n" \ 1514 "d Zoom into current DSO\n" \
1423 "E Expand all callchains\n" \ 1515 "E Expand all callchains\n" \
1424 "F Toggle percentage of filtered entries\n" \ 1516 "F Toggle percentage of filtered entries\n" \
1517 "H Display column headers\n" \
1425 1518
1426 /* help messages are sorted by lexical order of the hotkey */ 1519 /* help messages are sorted by lexical order of the hotkey */
1427 const char report_help[] = HIST_BROWSER_HELP_COMMON 1520 const char report_help[] = HIST_BROWSER_HELP_COMMON
@@ -1465,7 +1558,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1465 1558
1466 nr_options = 0; 1559 nr_options = 0;
1467 1560
1468 key = hist_browser__run(browser, ev_name, hbt); 1561 key = hist_browser__run(browser, hbt);
1469 1562
1470 if (browser->he_selection != NULL) { 1563 if (browser->he_selection != NULL) {
1471 thread = hist_browser__selected_thread(browser); 1564 thread = hist_browser__selected_thread(browser);
@@ -1843,7 +1936,7 @@ static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1843{ 1936{
1844 struct perf_evlist *evlist = menu->b.priv; 1937 struct perf_evlist *evlist = menu->b.priv;
1845 struct perf_evsel *pos; 1938 struct perf_evsel *pos;
1846 const char *ev_name, *title = "Available samples"; 1939 const char *title = "Available samples";
1847 int delay_secs = hbt ? hbt->refresh : 0; 1940 int delay_secs = hbt ? hbt->refresh : 0;
1848 int key; 1941 int key;
1849 1942
@@ -1876,9 +1969,8 @@ browse_hists:
1876 */ 1969 */
1877 if (hbt) 1970 if (hbt)
1878 hbt->timer(hbt->arg); 1971 hbt->timer(hbt->arg);
1879 ev_name = perf_evsel__name(pos);
1880 key = perf_evsel__hists_browse(pos, nr_events, help, 1972 key = perf_evsel__hists_browse(pos, nr_events, help,
1881 ev_name, true, hbt, 1973 true, hbt,
1882 menu->min_pcnt, 1974 menu->min_pcnt,
1883 menu->env); 1975 menu->env);
1884 ui_browser__show_title(&menu->b, title); 1976 ui_browser__show_title(&menu->b, title);
@@ -1982,10 +2074,9 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
1982single_entry: 2074single_entry:
1983 if (nr_entries == 1) { 2075 if (nr_entries == 1) {
1984 struct perf_evsel *first = perf_evlist__first(evlist); 2076 struct perf_evsel *first = perf_evlist__first(evlist);
1985 const char *ev_name = perf_evsel__name(first);
1986 2077
1987 return perf_evsel__hists_browse(first, nr_entries, help, 2078 return perf_evsel__hists_browse(first, nr_entries, help,
1988 ev_name, false, hbt, min_pcnt, 2079 false, hbt, min_pcnt,
1989 env); 2080 env);
1990 } 2081 }
1991 2082
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index 90122abd3721..40af0acb4fe9 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -479,7 +479,7 @@ print_entries:
479 479
480 if (h->ms.map == NULL && verbose > 1) { 480 if (h->ms.map == NULL && verbose > 1) {
481 __map_groups__fprintf_maps(h->thread->mg, 481 __map_groups__fprintf_maps(h->thread->mg,
482 MAP__FUNCTION, verbose, fp); 482 MAP__FUNCTION, fp);
483 fprintf(fp, "%.10s end\n", graph_dotted_line); 483 fprintf(fp, "%.10s end\n", graph_dotted_line);
484 } 484 }
485 } 485 }
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 48b6d3f50012..437ee09727e6 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -626,7 +626,7 @@ int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent
626 626
627int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample) 627int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample)
628{ 628{
629 if (!symbol_conf.use_callchain) 629 if (!symbol_conf.use_callchain || sample->callchain == NULL)
630 return 0; 630 return 0;
631 return callchain_append(he->callchain, &callchain_cursor, sample->period); 631 return callchain_append(he->callchain, &callchain_cursor, sample->period);
632} 632}
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 8f84423a75da..da43619d6173 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -176,4 +176,17 @@ static inline void callchain_cursor_snapshot(struct callchain_cursor *dest,
176 dest->first = src->curr; 176 dest->first = src->curr;
177 dest->nr -= src->pos; 177 dest->nr -= src->pos;
178} 178}
179
180#ifdef HAVE_SKIP_CALLCHAIN_IDX
181extern int arch_skip_callchain_idx(struct machine *machine,
182 struct thread *thread, struct ip_callchain *chain);
183#else
184static inline int arch_skip_callchain_idx(struct machine *machine __maybe_unused,
185 struct thread *thread __maybe_unused,
186 struct ip_callchain *chain __maybe_unused)
187{
188 return -1;
189}
190#endif
191
179#endif /* __PERF_CALLCHAIN_H */ 192#endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/cloexec.c b/tools/perf/util/cloexec.c
new file mode 100644
index 000000000000..c5d05ec17220
--- /dev/null
+++ b/tools/perf/util/cloexec.c
@@ -0,0 +1,57 @@
1#include "util.h"
2#include "../perf.h"
3#include "cloexec.h"
4#include "asm/bug.h"
5
6static unsigned long flag = PERF_FLAG_FD_CLOEXEC;
7
8static int perf_flag_probe(void)
9{
10 /* use 'safest' configuration as used in perf_evsel__fallback() */
11 struct perf_event_attr attr = {
12 .type = PERF_COUNT_SW_CPU_CLOCK,
13 .config = PERF_COUNT_SW_CPU_CLOCK,
14 };
15 int fd;
16 int err;
17
18 /* check cloexec flag */
19 fd = sys_perf_event_open(&attr, 0, -1, -1,
20 PERF_FLAG_FD_CLOEXEC);
21 err = errno;
22
23 if (fd >= 0) {
24 close(fd);
25 return 1;
26 }
27
28 WARN_ONCE(err != EINVAL,
29 "perf_event_open(..., PERF_FLAG_FD_CLOEXEC) failed with unexpected error %d (%s)\n",
30 err, strerror(err));
31
32 /* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */
33 fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
34 err = errno;
35
36 if (WARN_ONCE(fd < 0,
37 "perf_event_open(..., 0) failed unexpectedly with error %d (%s)\n",
38 err, strerror(err)))
39 return -1;
40
41 close(fd);
42
43 return 0;
44}
45
46unsigned long perf_event_open_cloexec_flag(void)
47{
48 static bool probed;
49
50 if (!probed) {
51 if (perf_flag_probe() <= 0)
52 flag = 0;
53 probed = true;
54 }
55
56 return flag;
57}
diff --git a/tools/perf/util/cloexec.h b/tools/perf/util/cloexec.h
new file mode 100644
index 000000000000..94a5a7d829d5
--- /dev/null
+++ b/tools/perf/util/cloexec.h
@@ -0,0 +1,6 @@
1#ifndef __PERF_CLOEXEC_H
2#define __PERF_CLOEXEC_H
3
4unsigned long perf_event_open_cloexec_flag(void);
5
6#endif /* __PERF_CLOEXEC_H */
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index 24519e14ac56..1e5e2e5af6b1 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -350,6 +350,16 @@ static int perf_default_core_config(const char *var __maybe_unused,
350 return 0; 350 return 0;
351} 351}
352 352
353static int perf_ui_config(const char *var, const char *value)
354{
355 /* Add other config variables here. */
356 if (!strcmp(var, "ui.show-headers")) {
357 symbol_conf.show_hist_headers = perf_config_bool(var, value);
358 return 0;
359 }
360 return 0;
361}
362
353int perf_default_config(const char *var, const char *value, 363int perf_default_config(const char *var, const char *value,
354 void *dummy __maybe_unused) 364 void *dummy __maybe_unused)
355{ 365{
@@ -359,6 +369,9 @@ int perf_default_config(const char *var, const char *value,
359 if (!prefixcmp(var, "hist.")) 369 if (!prefixcmp(var, "hist."))
360 return perf_hist_config(var, value); 370 return perf_hist_config(var, value);
361 371
372 if (!prefixcmp(var, "ui."))
373 return perf_ui_config(var, value);
374
362 /* Add other config variables here. */ 375 /* Add other config variables here. */
363 return 0; 376 return 0;
364} 377}
diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c
index 55de44ecebef..29d720cf5844 100644
--- a/tools/perf/util/data.c
+++ b/tools/perf/util/data.c
@@ -7,6 +7,7 @@
7 7
8#include "data.h" 8#include "data.h"
9#include "util.h" 9#include "util.h"
10#include "debug.h"
10 11
11static bool check_pipe(struct perf_data_file *file) 12static bool check_pipe(struct perf_data_file *file)
12{ 13{
@@ -65,7 +66,7 @@ static int open_file_read(struct perf_data_file *file)
65 goto out_close; 66 goto out_close;
66 67
67 if (!file->force && st.st_uid && (st.st_uid != geteuid())) { 68 if (!file->force && st.st_uid && (st.st_uid != geteuid())) {
68 pr_err("file %s not owned by current user or root\n", 69 pr_err("File %s not owned by current user or root (use -f to override)\n",
69 file->path); 70 file->path);
70 goto out_close; 71 goto out_close;
71 } 72 }
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index 299b55586502..71d419362634 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -16,11 +16,11 @@
16int verbose; 16int verbose;
17bool dump_trace = false, quiet = false; 17bool dump_trace = false, quiet = false;
18 18
19static int _eprintf(int level, const char *fmt, va_list args) 19static int _eprintf(int level, int var, const char *fmt, va_list args)
20{ 20{
21 int ret = 0; 21 int ret = 0;
22 22
23 if (verbose >= level) { 23 if (var >= level) {
24 if (use_browser >= 1) 24 if (use_browser >= 1)
25 ui_helpline__vshow(fmt, args); 25 ui_helpline__vshow(fmt, args);
26 else 26 else
@@ -30,13 +30,13 @@ static int _eprintf(int level, const char *fmt, va_list args)
30 return ret; 30 return ret;
31} 31}
32 32
33int eprintf(int level, const char *fmt, ...) 33int eprintf(int level, int var, const char *fmt, ...)
34{ 34{
35 va_list args; 35 va_list args;
36 int ret; 36 int ret;
37 37
38 va_start(args, fmt); 38 va_start(args, fmt);
39 ret = _eprintf(level, fmt, args); 39 ret = _eprintf(level, var, fmt, args);
40 va_end(args); 40 va_end(args);
41 41
42 return ret; 42 return ret;
@@ -51,9 +51,9 @@ void pr_stat(const char *fmt, ...)
51 va_list args; 51 va_list args;
52 52
53 va_start(args, fmt); 53 va_start(args, fmt);
54 _eprintf(1, fmt, args); 54 _eprintf(1, verbose, fmt, args);
55 va_end(args); 55 va_end(args);
56 eprintf(1, "\n"); 56 eprintf(1, verbose, "\n");
57} 57}
58 58
59int dump_printf(const char *fmt, ...) 59int dump_printf(const char *fmt, ...)
@@ -105,3 +105,47 @@ void trace_event(union perf_event *event)
105 } 105 }
106 printf(".\n"); 106 printf(".\n");
107} 107}
108
109static struct debug_variable {
110 const char *name;
111 int *ptr;
112} debug_variables[] = {
113 { .name = "verbose", .ptr = &verbose },
114 { .name = NULL, }
115};
116
117int perf_debug_option(const char *str)
118{
119 struct debug_variable *var = &debug_variables[0];
120 char *vstr, *s = strdup(str);
121 int v = 1;
122
123 vstr = strchr(s, '=');
124 if (vstr)
125 *vstr++ = 0;
126
127 while (var->name) {
128 if (!strcmp(s, var->name))
129 break;
130 var++;
131 }
132
133 if (!var->name) {
134 pr_err("Unknown debug variable name '%s'\n", s);
135 free(s);
136 return -1;
137 }
138
139 if (vstr) {
140 v = atoi(vstr);
141 /*
142 * Allow only values in range (0, 10),
143 * otherwise set 0.
144 */
145 v = (v < 0) || (v > 10) ? 0 : v;
146 }
147
148 *var->ptr = v;
149 free(s);
150 return 0;
151}
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index 443694c36b03..89fb6b0f7ab2 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -11,6 +11,24 @@
11extern int verbose; 11extern int verbose;
12extern bool quiet, dump_trace; 12extern bool quiet, dump_trace;
13 13
14#ifndef pr_fmt
15#define pr_fmt(fmt) fmt
16#endif
17
18#define pr_err(fmt, ...) \
19 eprintf(0, verbose, pr_fmt(fmt), ##__VA_ARGS__)
20#define pr_warning(fmt, ...) \
21 eprintf(0, verbose, pr_fmt(fmt), ##__VA_ARGS__)
22#define pr_info(fmt, ...) \
23 eprintf(0, verbose, pr_fmt(fmt), ##__VA_ARGS__)
24#define pr_debug(fmt, ...) \
25 eprintf(1, verbose, pr_fmt(fmt), ##__VA_ARGS__)
26#define pr_debugN(n, fmt, ...) \
27 eprintf(n, verbose, pr_fmt(fmt), ##__VA_ARGS__)
28#define pr_debug2(fmt, ...) pr_debugN(2, pr_fmt(fmt), ##__VA_ARGS__)
29#define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__)
30#define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__)
31
14int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); 32int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
15void trace_event(union perf_event *event); 33void trace_event(union perf_event *event);
16 34
@@ -19,4 +37,8 @@ int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2)));
19 37
20void pr_stat(const char *fmt, ...); 38void pr_stat(const char *fmt, ...);
21 39
40int eprintf(int level, int var, const char *fmt, ...) __attribute__((format(printf, 3, 4)));
41
42int perf_debug_option(const char *str);
43
22#endif /* __PERF_DEBUG_H */ 44#endif /* __PERF_DEBUG_H */
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index 819f10414f08..90d02c661dd4 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -216,7 +216,7 @@ static int open_dso(struct dso *dso, struct machine *machine)
216{ 216{
217 int fd = __open_dso(dso, machine); 217 int fd = __open_dso(dso, machine);
218 218
219 if (fd > 0) { 219 if (fd >= 0) {
220 dso__list_add(dso); 220 dso__list_add(dso);
221 /* 221 /*
222 * Check if we crossed the allowed number 222 * Check if we crossed the allowed number
@@ -331,26 +331,44 @@ int dso__data_fd(struct dso *dso, struct machine *machine)
331 }; 331 };
332 int i = 0; 332 int i = 0;
333 333
334 if (dso->data.status == DSO_DATA_STATUS_ERROR)
335 return -1;
336
334 if (dso->data.fd >= 0) 337 if (dso->data.fd >= 0)
335 return dso->data.fd; 338 goto out;
336 339
337 if (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND) { 340 if (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND) {
338 dso->data.fd = open_dso(dso, machine); 341 dso->data.fd = open_dso(dso, machine);
339 return dso->data.fd; 342 goto out;
340 } 343 }
341 344
342 do { 345 do {
343 int fd;
344
345 dso->binary_type = binary_type_data[i++]; 346 dso->binary_type = binary_type_data[i++];
346 347
347 fd = open_dso(dso, machine); 348 dso->data.fd = open_dso(dso, machine);
348 if (fd >= 0) 349 if (dso->data.fd >= 0)
349 return dso->data.fd = fd; 350 goto out;
350 351
351 } while (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND); 352 } while (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND);
353out:
354 if (dso->data.fd >= 0)
355 dso->data.status = DSO_DATA_STATUS_OK;
356 else
357 dso->data.status = DSO_DATA_STATUS_ERROR;
352 358
353 return -EINVAL; 359 return dso->data.fd;
360}
361
362bool dso__data_status_seen(struct dso *dso, enum dso_data_status_seen by)
363{
364 u32 flag = 1 << by;
365
366 if (dso->data.status_seen & flag)
367 return true;
368
369 dso->data.status_seen |= flag;
370
371 return false;
354} 372}
355 373
356static void 374static void
@@ -526,6 +544,28 @@ static int data_file_size(struct dso *dso)
526 return 0; 544 return 0;
527} 545}
528 546
547/**
548 * dso__data_size - Return dso data size
549 * @dso: dso object
550 * @machine: machine object
551 *
552 * Return: dso data size
553 */
554off_t dso__data_size(struct dso *dso, struct machine *machine)
555{
556 int fd;
557
558 fd = dso__data_fd(dso, machine);
559 if (fd < 0)
560 return fd;
561
562 if (data_file_size(dso))
563 return -1;
564
565 /* For now just estimate dso data size is close to file size */
566 return dso->data.file_size;
567}
568
529static ssize_t data_read_offset(struct dso *dso, u64 offset, 569static ssize_t data_read_offset(struct dso *dso, u64 offset,
530 u8 *data, ssize_t size) 570 u8 *data, ssize_t size)
531{ 571{
@@ -701,8 +741,10 @@ struct dso *dso__new(const char *name)
701 dso->symbols[i] = dso->symbol_names[i] = RB_ROOT; 741 dso->symbols[i] = dso->symbol_names[i] = RB_ROOT;
702 dso->data.cache = RB_ROOT; 742 dso->data.cache = RB_ROOT;
703 dso->data.fd = -1; 743 dso->data.fd = -1;
744 dso->data.status = DSO_DATA_STATUS_UNKNOWN;
704 dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND; 745 dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND;
705 dso->binary_type = DSO_BINARY_TYPE__NOT_FOUND; 746 dso->binary_type = DSO_BINARY_TYPE__NOT_FOUND;
747 dso->is_64_bit = (sizeof(void *) == 8);
706 dso->loaded = 0; 748 dso->loaded = 0;
707 dso->rel = 0; 749 dso->rel = 0;
708 dso->sorted_by_name = 0; 750 dso->sorted_by_name = 0;
@@ -898,3 +940,14 @@ size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp)
898 940
899 return ret; 941 return ret;
900} 942}
943
944enum dso_type dso__type(struct dso *dso, struct machine *machine)
945{
946 int fd;
947
948 fd = dso__data_fd(dso, machine);
949 if (fd < 0)
950 return DSO__TYPE_UNKNOWN;
951
952 return dso__type_fd(fd);
953}
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index ad553ba257bf..5e463c0964d4 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -5,6 +5,7 @@
5#include <linux/rbtree.h> 5#include <linux/rbtree.h>
6#include <stdbool.h> 6#include <stdbool.h>
7#include <linux/types.h> 7#include <linux/types.h>
8#include <linux/bitops.h>
8#include "map.h" 9#include "map.h"
9#include "build-id.h" 10#include "build-id.h"
10 11
@@ -40,6 +41,23 @@ enum dso_swap_type {
40 DSO_SWAP__YES, 41 DSO_SWAP__YES,
41}; 42};
42 43
44enum dso_data_status {
45 DSO_DATA_STATUS_ERROR = -1,
46 DSO_DATA_STATUS_UNKNOWN = 0,
47 DSO_DATA_STATUS_OK = 1,
48};
49
50enum dso_data_status_seen {
51 DSO_DATA_STATUS_SEEN_ITRACE,
52};
53
54enum dso_type {
55 DSO__TYPE_UNKNOWN,
56 DSO__TYPE_64BIT,
57 DSO__TYPE_32BIT,
58 DSO__TYPE_X32BIT,
59};
60
43#define DSO__SWAP(dso, type, val) \ 61#define DSO__SWAP(dso, type, val) \
44({ \ 62({ \
45 type ____r = val; \ 63 type ____r = val; \
@@ -90,6 +108,7 @@ struct dso {
90 u8 annotate_warned:1; 108 u8 annotate_warned:1;
91 u8 short_name_allocated:1; 109 u8 short_name_allocated:1;
92 u8 long_name_allocated:1; 110 u8 long_name_allocated:1;
111 u8 is_64_bit:1;
93 u8 sorted_by_name; 112 u8 sorted_by_name;
94 u8 loaded; 113 u8 loaded;
95 u8 rel; 114 u8 rel;
@@ -103,6 +122,8 @@ struct dso {
103 struct { 122 struct {
104 struct rb_root cache; 123 struct rb_root cache;
105 int fd; 124 int fd;
125 int status;
126 u32 status_seen;
106 size_t file_size; 127 size_t file_size;
107 struct list_head open_entry; 128 struct list_head open_entry;
108 } data; 129 } data;
@@ -153,6 +174,7 @@ int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type t
153 * The dso__data_* external interface provides following functions: 174 * The dso__data_* external interface provides following functions:
154 * dso__data_fd 175 * dso__data_fd
155 * dso__data_close 176 * dso__data_close
177 * dso__data_size
156 * dso__data_read_offset 178 * dso__data_read_offset
157 * dso__data_read_addr 179 * dso__data_read_addr
158 * 180 *
@@ -190,11 +212,13 @@ int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type t
190int dso__data_fd(struct dso *dso, struct machine *machine); 212int dso__data_fd(struct dso *dso, struct machine *machine);
191void dso__data_close(struct dso *dso); 213void dso__data_close(struct dso *dso);
192 214
215off_t dso__data_size(struct dso *dso, struct machine *machine);
193ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, 216ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
194 u64 offset, u8 *data, ssize_t size); 217 u64 offset, u8 *data, ssize_t size);
195ssize_t dso__data_read_addr(struct dso *dso, struct map *map, 218ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
196 struct machine *machine, u64 addr, 219 struct machine *machine, u64 addr,
197 u8 *data, ssize_t size); 220 u8 *data, ssize_t size);
221bool dso__data_status_seen(struct dso *dso, enum dso_data_status_seen by);
198 222
199struct map *dso__new_map(const char *name); 223struct map *dso__new_map(const char *name);
200struct dso *dso__kernel_findnew(struct machine *machine, const char *name, 224struct dso *dso__kernel_findnew(struct machine *machine, const char *name,
@@ -229,4 +253,6 @@ static inline bool dso__is_kcore(struct dso *dso)
229 253
230void dso__free_a2l(struct dso *dso); 254void dso__free_a2l(struct dso *dso);
231 255
256enum dso_type dso__type(struct dso *dso, struct machine *machine);
257
232#endif /* __PERF_DSO */ 258#endif /* __PERF_DSO */
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index d0281bdfa582..1398c83d896d 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -603,7 +603,14 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
603 603
604size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp) 604size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp)
605{ 605{
606 return fprintf(fp, ": %s:%d\n", event->comm.comm, event->comm.tid); 606 const char *s;
607
608 if (event->header.misc & PERF_RECORD_MISC_COMM_EXEC)
609 s = " exec";
610 else
611 s = "";
612
613 return fprintf(fp, "%s: %s:%d\n", s, event->comm.comm, event->comm.tid);
607} 614}
608 615
609int perf_event__process_comm(struct perf_tool *tool __maybe_unused, 616int perf_event__process_comm(struct perf_tool *tool __maybe_unused,
@@ -781,6 +788,7 @@ try_again:
781 cpumode == PERF_RECORD_MISC_USER && 788 cpumode == PERF_RECORD_MISC_USER &&
782 machine && mg != &machine->kmaps) { 789 machine && mg != &machine->kmaps) {
783 mg = &machine->kmaps; 790 mg = &machine->kmaps;
791 load_map = true;
784 goto try_again; 792 goto try_again;
785 } 793 }
786 } else { 794 } else {
@@ -866,3 +874,45 @@ int perf_event__preprocess_sample(const union perf_event *event,
866 874
867 return 0; 875 return 0;
868} 876}
877
878bool is_bts_event(struct perf_event_attr *attr)
879{
880 return attr->type == PERF_TYPE_HARDWARE &&
881 (attr->config & PERF_COUNT_HW_BRANCH_INSTRUCTIONS) &&
882 attr->sample_period == 1;
883}
884
885bool sample_addr_correlates_sym(struct perf_event_attr *attr)
886{
887 if (attr->type == PERF_TYPE_SOFTWARE &&
888 (attr->config == PERF_COUNT_SW_PAGE_FAULTS ||
889 attr->config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
890 attr->config == PERF_COUNT_SW_PAGE_FAULTS_MAJ))
891 return true;
892
893 if (is_bts_event(attr))
894 return true;
895
896 return false;
897}
898
899void perf_event__preprocess_sample_addr(union perf_event *event,
900 struct perf_sample *sample,
901 struct machine *machine,
902 struct thread *thread,
903 struct addr_location *al)
904{
905 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
906
907 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
908 sample->addr, al);
909 if (!al->map)
910 thread__find_addr_map(thread, machine, cpumode, MAP__VARIABLE,
911 sample->addr, al);
912
913 al->cpu = sample->cpu;
914 al->sym = NULL;
915
916 if (al->map)
917 al->sym = map__find_symbol(al->map, al->addr, NULL);
918}
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index e5dd40addb30..94d6976180da 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -288,6 +288,16 @@ int perf_event__preprocess_sample(const union perf_event *event,
288 struct addr_location *al, 288 struct addr_location *al,
289 struct perf_sample *sample); 289 struct perf_sample *sample);
290 290
291struct thread;
292
293bool is_bts_event(struct perf_event_attr *attr);
294bool sample_addr_correlates_sym(struct perf_event_attr *attr);
295void perf_event__preprocess_sample_addr(union perf_event *event,
296 struct perf_sample *sample,
297 struct machine *machine,
298 struct thread *thread,
299 struct addr_location *al);
300
291const char *perf_event__name(unsigned int id); 301const char *perf_event__name(unsigned int id);
292 302
293size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, 303size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 59ef2802fcf6..814e954c1318 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -606,12 +606,17 @@ static int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
606 return evlist->mmap != NULL ? 0 : -ENOMEM; 606 return evlist->mmap != NULL ? 0 : -ENOMEM;
607} 607}
608 608
609static int __perf_evlist__mmap(struct perf_evlist *evlist, 609struct mmap_params {
610 int idx, int prot, int mask, int fd) 610 int prot;
611 int mask;
612};
613
614static int __perf_evlist__mmap(struct perf_evlist *evlist, int idx,
615 struct mmap_params *mp, int fd)
611{ 616{
612 evlist->mmap[idx].prev = 0; 617 evlist->mmap[idx].prev = 0;
613 evlist->mmap[idx].mask = mask; 618 evlist->mmap[idx].mask = mp->mask;
614 evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, prot, 619 evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, mp->prot,
615 MAP_SHARED, fd, 0); 620 MAP_SHARED, fd, 0);
616 if (evlist->mmap[idx].base == MAP_FAILED) { 621 if (evlist->mmap[idx].base == MAP_FAILED) {
617 pr_debug2("failed to mmap perf event ring buffer, error %d\n", 622 pr_debug2("failed to mmap perf event ring buffer, error %d\n",
@@ -625,8 +630,8 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist,
625} 630}
626 631
627static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, 632static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
628 int prot, int mask, int cpu, int thread, 633 struct mmap_params *mp, int cpu,
629 int *output) 634 int thread, int *output)
630{ 635{
631 struct perf_evsel *evsel; 636 struct perf_evsel *evsel;
632 637
@@ -635,8 +640,7 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
635 640
636 if (*output == -1) { 641 if (*output == -1) {
637 *output = fd; 642 *output = fd;
638 if (__perf_evlist__mmap(evlist, idx, prot, mask, 643 if (__perf_evlist__mmap(evlist, idx, mp, *output) < 0)
639 *output) < 0)
640 return -1; 644 return -1;
641 } else { 645 } else {
642 if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, *output) != 0) 646 if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, *output) != 0)
@@ -651,8 +655,8 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
651 return 0; 655 return 0;
652} 656}
653 657
654static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, 658static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist,
655 int mask) 659 struct mmap_params *mp)
656{ 660{
657 int cpu, thread; 661 int cpu, thread;
658 int nr_cpus = cpu_map__nr(evlist->cpus); 662 int nr_cpus = cpu_map__nr(evlist->cpus);
@@ -663,8 +667,8 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot,
663 int output = -1; 667 int output = -1;
664 668
665 for (thread = 0; thread < nr_threads; thread++) { 669 for (thread = 0; thread < nr_threads; thread++) {
666 if (perf_evlist__mmap_per_evsel(evlist, cpu, prot, mask, 670 if (perf_evlist__mmap_per_evsel(evlist, cpu, mp, cpu,
667 cpu, thread, &output)) 671 thread, &output))
668 goto out_unmap; 672 goto out_unmap;
669 } 673 }
670 } 674 }
@@ -677,8 +681,8 @@ out_unmap:
677 return -1; 681 return -1;
678} 682}
679 683
680static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, 684static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist,
681 int mask) 685 struct mmap_params *mp)
682{ 686{
683 int thread; 687 int thread;
684 int nr_threads = thread_map__nr(evlist->threads); 688 int nr_threads = thread_map__nr(evlist->threads);
@@ -687,8 +691,8 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot,
687 for (thread = 0; thread < nr_threads; thread++) { 691 for (thread = 0; thread < nr_threads; thread++) {
688 int output = -1; 692 int output = -1;
689 693
690 if (perf_evlist__mmap_per_evsel(evlist, thread, prot, mask, 0, 694 if (perf_evlist__mmap_per_evsel(evlist, thread, mp, 0, thread,
691 thread, &output)) 695 &output))
692 goto out_unmap; 696 goto out_unmap;
693 } 697 }
694 698
@@ -793,7 +797,9 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
793 struct perf_evsel *evsel; 797 struct perf_evsel *evsel;
794 const struct cpu_map *cpus = evlist->cpus; 798 const struct cpu_map *cpus = evlist->cpus;
795 const struct thread_map *threads = evlist->threads; 799 const struct thread_map *threads = evlist->threads;
796 int prot = PROT_READ | (overwrite ? 0 : PROT_WRITE), mask; 800 struct mmap_params mp = {
801 .prot = PROT_READ | (overwrite ? 0 : PROT_WRITE),
802 };
797 803
798 if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0) 804 if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0)
799 return -ENOMEM; 805 return -ENOMEM;
@@ -804,7 +810,7 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
804 evlist->overwrite = overwrite; 810 evlist->overwrite = overwrite;
805 evlist->mmap_len = perf_evlist__mmap_size(pages); 811 evlist->mmap_len = perf_evlist__mmap_size(pages);
806 pr_debug("mmap size %zuB\n", evlist->mmap_len); 812 pr_debug("mmap size %zuB\n", evlist->mmap_len);
807 mask = evlist->mmap_len - page_size - 1; 813 mp.mask = evlist->mmap_len - page_size - 1;
808 814
809 evlist__for_each(evlist, evsel) { 815 evlist__for_each(evlist, evsel) {
810 if ((evsel->attr.read_format & PERF_FORMAT_ID) && 816 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
@@ -814,9 +820,9 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
814 } 820 }
815 821
816 if (cpu_map__empty(cpus)) 822 if (cpu_map__empty(cpus))
817 return perf_evlist__mmap_per_thread(evlist, prot, mask); 823 return perf_evlist__mmap_per_thread(evlist, &mp);
818 824
819 return perf_evlist__mmap_per_cpu(evlist, prot, mask); 825 return perf_evlist__mmap_per_cpu(evlist, &mp);
820} 826}
821 827
822int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target) 828int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target)
@@ -1214,10 +1220,11 @@ int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused,
1214 "For your workloads it needs to be <= 1\nHint:\t"); 1220 "For your workloads it needs to be <= 1\nHint:\t");
1215 } 1221 }
1216 printed += scnprintf(buf + printed, size - printed, 1222 printed += scnprintf(buf + printed, size - printed,
1217 "For system wide tracing it needs to be set to -1"); 1223 "For system wide tracing it needs to be set to -1.\n");
1218 1224
1219 printed += scnprintf(buf + printed, size - printed, 1225 printed += scnprintf(buf + printed, size - printed,
1220 ".\nHint:\tThe current value is %d.", value); 1226 "Hint:\tTry: 'sudo sh -c \"echo -1 > /proc/sys/kernel/perf_event_paranoid\"'\n"
1227 "Hint:\tThe current value is %d.", value);
1221 break; 1228 break;
1222 default: 1229 default:
1223 scnprintf(buf, size, "%s", emsg); 1230 scnprintf(buf, size, "%s", emsg);
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 8606175fe1e8..21a373ebea22 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -29,6 +29,7 @@ static struct {
29 bool sample_id_all; 29 bool sample_id_all;
30 bool exclude_guest; 30 bool exclude_guest;
31 bool mmap2; 31 bool mmap2;
32 bool cloexec;
32} perf_missing_features; 33} perf_missing_features;
33 34
34#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) 35#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
@@ -623,7 +624,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
623 attr->mmap_data = track; 624 attr->mmap_data = track;
624 } 625 }
625 626
626 if (opts->call_graph_enabled) 627 if (opts->call_graph_enabled && !evsel->no_aux_samples)
627 perf_evsel__config_callgraph(evsel, opts); 628 perf_evsel__config_callgraph(evsel, opts);
628 629
629 if (target__has_cpu(&opts->target)) 630 if (target__has_cpu(&opts->target))
@@ -637,7 +638,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
637 target__has_cpu(&opts->target) || per_cpu)) 638 target__has_cpu(&opts->target) || per_cpu))
638 perf_evsel__set_sample_bit(evsel, TIME); 639 perf_evsel__set_sample_bit(evsel, TIME);
639 640
640 if (opts->raw_samples) { 641 if (opts->raw_samples && !evsel->no_aux_samples) {
641 perf_evsel__set_sample_bit(evsel, TIME); 642 perf_evsel__set_sample_bit(evsel, TIME);
642 perf_evsel__set_sample_bit(evsel, RAW); 643 perf_evsel__set_sample_bit(evsel, RAW);
643 perf_evsel__set_sample_bit(evsel, CPU); 644 perf_evsel__set_sample_bit(evsel, CPU);
@@ -650,7 +651,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
650 attr->watermark = 0; 651 attr->watermark = 0;
651 attr->wakeup_events = 1; 652 attr->wakeup_events = 1;
652 } 653 }
653 if (opts->branch_stack) { 654 if (opts->branch_stack && !evsel->no_aux_samples) {
654 perf_evsel__set_sample_bit(evsel, BRANCH_STACK); 655 perf_evsel__set_sample_bit(evsel, BRANCH_STACK);
655 attr->branch_sample_type = opts->branch_stack; 656 attr->branch_sample_type = opts->branch_stack;
656 } 657 }
@@ -681,6 +682,11 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
681 if (target__none(&opts->target) && perf_evsel__is_group_leader(evsel) && 682 if (target__none(&opts->target) && perf_evsel__is_group_leader(evsel) &&
682 !opts->initial_delay) 683 !opts->initial_delay)
683 attr->enable_on_exec = 1; 684 attr->enable_on_exec = 1;
685
686 if (evsel->immediate) {
687 attr->disabled = 0;
688 attr->enable_on_exec = 0;
689 }
684} 690}
685 691
686int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) 692int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
@@ -960,6 +966,7 @@ static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp)
960 ret += PRINT_ATTR2(exclude_user, exclude_kernel); 966 ret += PRINT_ATTR2(exclude_user, exclude_kernel);
961 ret += PRINT_ATTR2(exclude_hv, exclude_idle); 967 ret += PRINT_ATTR2(exclude_hv, exclude_idle);
962 ret += PRINT_ATTR2(mmap, comm); 968 ret += PRINT_ATTR2(mmap, comm);
969 ret += PRINT_ATTR2(mmap2, comm_exec);
963 ret += PRINT_ATTR2(freq, inherit_stat); 970 ret += PRINT_ATTR2(freq, inherit_stat);
964 ret += PRINT_ATTR2(enable_on_exec, task); 971 ret += PRINT_ATTR2(enable_on_exec, task);
965 ret += PRINT_ATTR2(watermark, precise_ip); 972 ret += PRINT_ATTR2(watermark, precise_ip);
@@ -967,7 +974,6 @@ static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp)
967 ret += PRINT_ATTR2(exclude_host, exclude_guest); 974 ret += PRINT_ATTR2(exclude_host, exclude_guest);
968 ret += PRINT_ATTR2N("excl.callchain_kern", exclude_callchain_kernel, 975 ret += PRINT_ATTR2N("excl.callchain_kern", exclude_callchain_kernel,
969 "excl.callchain_user", exclude_callchain_user); 976 "excl.callchain_user", exclude_callchain_user);
970 ret += PRINT_ATTR_U32(mmap2);
971 977
972 ret += PRINT_ATTR_U32(wakeup_events); 978 ret += PRINT_ATTR_U32(wakeup_events);
973 ret += PRINT_ATTR_U32(wakeup_watermark); 979 ret += PRINT_ATTR_U32(wakeup_watermark);
@@ -989,7 +995,7 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
989 struct thread_map *threads) 995 struct thread_map *threads)
990{ 996{
991 int cpu, thread; 997 int cpu, thread;
992 unsigned long flags = 0; 998 unsigned long flags = PERF_FLAG_FD_CLOEXEC;
993 int pid = -1, err; 999 int pid = -1, err;
994 enum { NO_CHANGE, SET_TO_MAX, INCREASED_MAX } set_rlimit = NO_CHANGE; 1000 enum { NO_CHANGE, SET_TO_MAX, INCREASED_MAX } set_rlimit = NO_CHANGE;
995 1001
@@ -998,11 +1004,13 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
998 return -ENOMEM; 1004 return -ENOMEM;
999 1005
1000 if (evsel->cgrp) { 1006 if (evsel->cgrp) {
1001 flags = PERF_FLAG_PID_CGROUP; 1007 flags |= PERF_FLAG_PID_CGROUP;
1002 pid = evsel->cgrp->fd; 1008 pid = evsel->cgrp->fd;
1003 } 1009 }
1004 1010
1005fallback_missing_features: 1011fallback_missing_features:
1012 if (perf_missing_features.cloexec)
1013 flags &= ~(unsigned long)PERF_FLAG_FD_CLOEXEC;
1006 if (perf_missing_features.mmap2) 1014 if (perf_missing_features.mmap2)
1007 evsel->attr.mmap2 = 0; 1015 evsel->attr.mmap2 = 0;
1008 if (perf_missing_features.exclude_guest) 1016 if (perf_missing_features.exclude_guest)
@@ -1071,7 +1079,10 @@ try_fallback:
1071 if (err != -EINVAL || cpu > 0 || thread > 0) 1079 if (err != -EINVAL || cpu > 0 || thread > 0)
1072 goto out_close; 1080 goto out_close;
1073 1081
1074 if (!perf_missing_features.mmap2 && evsel->attr.mmap2) { 1082 if (!perf_missing_features.cloexec && (flags & PERF_FLAG_FD_CLOEXEC)) {
1083 perf_missing_features.cloexec = true;
1084 goto fallback_missing_features;
1085 } else if (!perf_missing_features.mmap2 && evsel->attr.mmap2) {
1075 perf_missing_features.mmap2 = true; 1086 perf_missing_features.mmap2 = true;
1076 goto fallback_missing_features; 1087 goto fallback_missing_features;
1077 } else if (!perf_missing_features.exclude_guest && 1088 } else if (!perf_missing_features.exclude_guest &&
@@ -1940,6 +1951,7 @@ int perf_evsel__fprintf(struct perf_evsel *evsel,
1940 if_print(mmap); 1951 if_print(mmap);
1941 if_print(mmap2); 1952 if_print(mmap2);
1942 if_print(comm); 1953 if_print(comm);
1954 if_print(comm_exec);
1943 if_print(freq); 1955 if_print(freq);
1944 if_print(inherit_stat); 1956 if_print(inherit_stat);
1945 if_print(enable_on_exec); 1957 if_print(enable_on_exec);
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index a52e9a5bb2d0..d7f93ce0ebc1 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -83,6 +83,8 @@ struct perf_evsel {
83 int is_pos; 83 int is_pos;
84 bool supported; 84 bool supported;
85 bool needs_swap; 85 bool needs_swap;
86 bool no_aux_samples;
87 bool immediate;
86 /* parse modifier helper */ 88 /* parse modifier helper */
87 int exclude_GH; 89 int exclude_GH;
88 int nr_members; 90 int nr_members;
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 893f8e2df928..158c787ce0c4 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -200,6 +200,47 @@ static int write_buildid(const char *name, size_t name_len, u8 *build_id,
200 return write_padded(fd, name, name_len + 1, len); 200 return write_padded(fd, name, name_len + 1, len);
201} 201}
202 202
203static int __dsos__hit_all(struct list_head *head)
204{
205 struct dso *pos;
206
207 list_for_each_entry(pos, head, node)
208 pos->hit = true;
209
210 return 0;
211}
212
213static int machine__hit_all_dsos(struct machine *machine)
214{
215 int err;
216
217 err = __dsos__hit_all(&machine->kernel_dsos);
218 if (err)
219 return err;
220
221 return __dsos__hit_all(&machine->user_dsos);
222}
223
224int dsos__hit_all(struct perf_session *session)
225{
226 struct rb_node *nd;
227 int err;
228
229 err = machine__hit_all_dsos(&session->machines.host);
230 if (err)
231 return err;
232
233 for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
234 struct machine *pos = rb_entry(nd, struct machine, rb_node);
235
236 err = machine__hit_all_dsos(pos);
237 if (err)
238 return err;
239 }
240
241 return 0;
242}
243
203static int __dsos__write_buildid_table(struct list_head *head, 244static int __dsos__write_buildid_table(struct list_head *head,
204 struct machine *machine, 245 struct machine *machine,
205 pid_t pid, u16 misc, int fd) 246 pid_t pid, u16 misc, int fd)
@@ -215,9 +256,9 @@ static int __dsos__write_buildid_table(struct list_head *head,
215 if (!pos->hit) 256 if (!pos->hit)
216 continue; 257 continue;
217 258
218 if (is_vdso_map(pos->short_name)) { 259 if (dso__is_vdso(pos)) {
219 name = (char *) VDSO__MAP_NAME; 260 name = pos->short_name;
220 name_len = sizeof(VDSO__MAP_NAME) + 1; 261 name_len = pos->short_name_len + 1;
221 } else if (dso__is_kcore(pos)) { 262 } else if (dso__is_kcore(pos)) {
222 machine__mmap_name(machine, nm, sizeof(nm)); 263 machine__mmap_name(machine, nm, sizeof(nm));
223 name = nm; 264 name = nm;
@@ -298,7 +339,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
298 339
299 len = scnprintf(filename, size, "%s%s%s", 340 len = scnprintf(filename, size, "%s%s%s",
300 debugdir, slash ? "/" : "", 341 debugdir, slash ? "/" : "",
301 is_vdso ? VDSO__MAP_NAME : realname); 342 is_vdso ? DSO__NAME_VDSO : realname);
302 if (mkdir_p(filename, 0755)) 343 if (mkdir_p(filename, 0755))
303 goto out_free; 344 goto out_free;
304 345
@@ -386,7 +427,7 @@ static int dso__cache_build_id(struct dso *dso, struct machine *machine,
386 const char *debugdir) 427 const char *debugdir)
387{ 428{
388 bool is_kallsyms = dso->kernel && dso->long_name[0] != '/'; 429 bool is_kallsyms = dso->kernel && dso->long_name[0] != '/';
389 bool is_vdso = is_vdso_map(dso->short_name); 430 bool is_vdso = dso__is_vdso(dso);
390 const char *name = dso->long_name; 431 const char *name = dso->long_name;
391 char nm[PATH_MAX]; 432 char nm[PATH_MAX];
392 433
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index d08cfe499404..8f5cbaea64a5 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -151,6 +151,8 @@ int perf_event__process_build_id(struct perf_tool *tool,
151 struct perf_session *session); 151 struct perf_session *session);
152bool is_perf_magic(u64 magic); 152bool is_perf_magic(u64 magic);
153 153
154int dsos__hit_all(struct perf_session *session);
155
154/* 156/*
155 * arch specific callback 157 * arch specific callback
156 */ 158 */
diff --git a/tools/perf/util/include/linux/kernel.h b/tools/perf/util/include/linux/kernel.h
index 9844c31b7c2b..09e8e7aea7c6 100644
--- a/tools/perf/util/include/linux/kernel.h
+++ b/tools/perf/util/include/linux/kernel.h
@@ -94,27 +94,6 @@ static inline int scnprintf(char * buf, size_t size, const char * fmt, ...)
94 return (i >= ssize) ? (ssize - 1) : i; 94 return (i >= ssize) ? (ssize - 1) : i;
95} 95}
96 96
97int eprintf(int level,
98 const char *fmt, ...) __attribute__((format(printf, 2, 3)));
99
100#ifndef pr_fmt
101#define pr_fmt(fmt) fmt
102#endif
103
104#define pr_err(fmt, ...) \
105 eprintf(0, pr_fmt(fmt), ##__VA_ARGS__)
106#define pr_warning(fmt, ...) \
107 eprintf(0, pr_fmt(fmt), ##__VA_ARGS__)
108#define pr_info(fmt, ...) \
109 eprintf(0, pr_fmt(fmt), ##__VA_ARGS__)
110#define pr_debug(fmt, ...) \
111 eprintf(1, pr_fmt(fmt), ##__VA_ARGS__)
112#define pr_debugN(n, fmt, ...) \
113 eprintf(n, pr_fmt(fmt), ##__VA_ARGS__)
114#define pr_debug2(fmt, ...) pr_debugN(2, pr_fmt(fmt), ##__VA_ARGS__)
115#define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__)
116#define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__)
117
118/* 97/*
119 * This looks more complex than it should be. But we need to 98 * This looks more complex than it should be. But we need to
120 * get the type for the ~ right in round_down (it needs to be 99 * get the type for the ~ right in round_down (it needs to be
diff --git a/tools/perf/util/kvm-stat.h b/tools/perf/util/kvm-stat.h
new file mode 100644
index 000000000000..0b5a8cd2ee79
--- /dev/null
+++ b/tools/perf/util/kvm-stat.h
@@ -0,0 +1,140 @@
1#ifndef __PERF_KVM_STAT_H
2#define __PERF_KVM_STAT_H
3
4#include "../perf.h"
5#include "evsel.h"
6#include "evlist.h"
7#include "session.h"
8#include "tool.h"
9#include "stat.h"
10
11struct event_key {
12 #define INVALID_KEY (~0ULL)
13 u64 key;
14 int info;
15 struct exit_reasons_table *exit_reasons;
16};
17
18struct kvm_event_stats {
19 u64 time;
20 struct stats stats;
21};
22
23struct kvm_event {
24 struct list_head hash_entry;
25 struct rb_node rb;
26
27 struct event_key key;
28
29 struct kvm_event_stats total;
30
31 #define DEFAULT_VCPU_NUM 8
32 int max_vcpu;
33 struct kvm_event_stats *vcpu;
34};
35
36typedef int (*key_cmp_fun)(struct kvm_event*, struct kvm_event*, int);
37
38struct kvm_event_key {
39 const char *name;
40 key_cmp_fun key;
41};
42
43struct perf_kvm_stat;
44
45struct child_event_ops {
46 void (*get_key)(struct perf_evsel *evsel,
47 struct perf_sample *sample,
48 struct event_key *key);
49 const char *name;
50};
51
52struct kvm_events_ops {
53 bool (*is_begin_event)(struct perf_evsel *evsel,
54 struct perf_sample *sample,
55 struct event_key *key);
56 bool (*is_end_event)(struct perf_evsel *evsel,
57 struct perf_sample *sample, struct event_key *key);
58 struct child_event_ops *child_ops;
59 void (*decode_key)(struct perf_kvm_stat *kvm, struct event_key *key,
60 char *decode);
61 const char *name;
62};
63
64struct exit_reasons_table {
65 unsigned long exit_code;
66 const char *reason;
67};
68
69#define EVENTS_BITS 12
70#define EVENTS_CACHE_SIZE (1UL << EVENTS_BITS)
71
72struct perf_kvm_stat {
73 struct perf_tool tool;
74 struct record_opts opts;
75 struct perf_evlist *evlist;
76 struct perf_session *session;
77
78 const char *file_name;
79 const char *report_event;
80 const char *sort_key;
81 int trace_vcpu;
82
83 struct exit_reasons_table *exit_reasons;
84 const char *exit_reasons_isa;
85
86 struct kvm_events_ops *events_ops;
87 key_cmp_fun compare;
88 struct list_head kvm_events_cache[EVENTS_CACHE_SIZE];
89
90 u64 total_time;
91 u64 total_count;
92 u64 lost_events;
93 u64 duration;
94
95 const char *pid_str;
96 struct intlist *pid_list;
97
98 struct rb_root result;
99
100 int timerfd;
101 unsigned int display_time;
102 bool live;
103};
104
105struct kvm_reg_events_ops {
106 const char *name;
107 struct kvm_events_ops *ops;
108};
109
110void exit_event_get_key(struct perf_evsel *evsel,
111 struct perf_sample *sample,
112 struct event_key *key);
113bool exit_event_begin(struct perf_evsel *evsel,
114 struct perf_sample *sample,
115 struct event_key *key);
116bool exit_event_end(struct perf_evsel *evsel,
117 struct perf_sample *sample,
118 struct event_key *key);
119void exit_event_decode_key(struct perf_kvm_stat *kvm,
120 struct event_key *key,
121 char *decode);
122
123bool kvm_exit_event(struct perf_evsel *evsel);
124bool kvm_entry_event(struct perf_evsel *evsel);
125
126#define define_exit_reasons_table(name, symbols) \
127 static struct exit_reasons_table name[] = { \
128 symbols, { -1, NULL } \
129 }
130
131/*
132 * arch specific callbacks and data structures
133 */
134int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid);
135
136extern const char * const kvm_events_tp[];
137extern struct kvm_reg_events_ops kvm_reg_events_ops[];
138extern const char * const kvm_skip_events[];
139
140#endif /* __PERF_KVM_STAT_H */
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index c73e1fc12e53..16bba9fff2c8 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -8,6 +8,7 @@
8#include "sort.h" 8#include "sort.h"
9#include "strlist.h" 9#include "strlist.h"
10#include "thread.h" 10#include "thread.h"
11#include "vdso.h"
11#include <stdbool.h> 12#include <stdbool.h>
12#include <symbol/kallsyms.h> 13#include <symbol/kallsyms.h>
13#include "unwind.h" 14#include "unwind.h"
@@ -23,6 +24,8 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
23 INIT_LIST_HEAD(&machine->dead_threads); 24 INIT_LIST_HEAD(&machine->dead_threads);
24 machine->last_match = NULL; 25 machine->last_match = NULL;
25 26
27 machine->vdso_info = NULL;
28
26 machine->kmaps.machine = machine; 29 machine->kmaps.machine = machine;
27 machine->pid = pid; 30 machine->pid = pid;
28 31
@@ -34,7 +37,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
34 return -ENOMEM; 37 return -ENOMEM;
35 38
36 if (pid != HOST_KERNEL_ID) { 39 if (pid != HOST_KERNEL_ID) {
37 struct thread *thread = machine__findnew_thread(machine, 0, 40 struct thread *thread = machine__findnew_thread(machine, -1,
38 pid); 41 pid);
39 char comm[64]; 42 char comm[64];
40 43
@@ -45,6 +48,8 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
45 thread__set_comm(thread, comm, 0); 48 thread__set_comm(thread, comm, 0);
46 } 49 }
47 50
51 machine->current_tid = NULL;
52
48 return 0; 53 return 0;
49} 54}
50 55
@@ -103,7 +108,9 @@ void machine__exit(struct machine *machine)
103 map_groups__exit(&machine->kmaps); 108 map_groups__exit(&machine->kmaps);
104 dsos__delete(&machine->user_dsos); 109 dsos__delete(&machine->user_dsos);
105 dsos__delete(&machine->kernel_dsos); 110 dsos__delete(&machine->kernel_dsos);
111 vdso__exit(machine);
106 zfree(&machine->root_dir); 112 zfree(&machine->root_dir);
113 zfree(&machine->current_tid);
107} 114}
108 115
109void machine__delete(struct machine *machine) 116void machine__delete(struct machine *machine)
@@ -272,6 +279,52 @@ void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size)
272 return; 279 return;
273} 280}
274 281
282static void machine__update_thread_pid(struct machine *machine,
283 struct thread *th, pid_t pid)
284{
285 struct thread *leader;
286
287 if (pid == th->pid_ || pid == -1 || th->pid_ != -1)
288 return;
289
290 th->pid_ = pid;
291
292 if (th->pid_ == th->tid)
293 return;
294
295 leader = machine__findnew_thread(machine, th->pid_, th->pid_);
296 if (!leader)
297 goto out_err;
298
299 if (!leader->mg)
300 leader->mg = map_groups__new();
301
302 if (!leader->mg)
303 goto out_err;
304
305 if (th->mg == leader->mg)
306 return;
307
308 if (th->mg) {
309 /*
310 * Maps are created from MMAP events which provide the pid and
311 * tid. Consequently there never should be any maps on a thread
312 * with an unknown pid. Just print an error if there are.
313 */
314 if (!map_groups__empty(th->mg))
315 pr_err("Discarding thread maps for %d:%d\n",
316 th->pid_, th->tid);
317 map_groups__delete(th->mg);
318 }
319
320 th->mg = map_groups__get(leader->mg);
321
322 return;
323
324out_err:
325 pr_err("Failed to join map groups for %d:%d\n", th->pid_, th->tid);
326}
327
275static struct thread *__machine__findnew_thread(struct machine *machine, 328static struct thread *__machine__findnew_thread(struct machine *machine,
276 pid_t pid, pid_t tid, 329 pid_t pid, pid_t tid,
277 bool create) 330 bool create)
@@ -285,10 +338,10 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
285 * so most of the time we dont have to look up 338 * so most of the time we dont have to look up
286 * the full rbtree: 339 * the full rbtree:
287 */ 340 */
288 if (machine->last_match && machine->last_match->tid == tid) { 341 th = machine->last_match;
289 if (pid && pid != machine->last_match->pid_) 342 if (th && th->tid == tid) {
290 machine->last_match->pid_ = pid; 343 machine__update_thread_pid(machine, th, pid);
291 return machine->last_match; 344 return th;
292 } 345 }
293 346
294 while (*p != NULL) { 347 while (*p != NULL) {
@@ -297,8 +350,7 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
297 350
298 if (th->tid == tid) { 351 if (th->tid == tid) {
299 machine->last_match = th; 352 machine->last_match = th;
300 if (pid && pid != th->pid_) 353 machine__update_thread_pid(machine, th, pid);
301 th->pid_ = pid;
302 return th; 354 return th;
303 } 355 }
304 356
@@ -325,8 +377,10 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
325 * within thread__init_map_groups to find the thread 377 * within thread__init_map_groups to find the thread
326 * leader and that would screwed the rb tree. 378 * leader and that would screwed the rb tree.
327 */ 379 */
328 if (thread__init_map_groups(th, machine)) 380 if (thread__init_map_groups(th, machine)) {
381 thread__delete(th);
329 return NULL; 382 return NULL;
383 }
330 } 384 }
331 385
332 return th; 386 return th;
@@ -1045,14 +1099,14 @@ int machine__process_mmap2_event(struct machine *machine,
1045 else 1099 else
1046 type = MAP__FUNCTION; 1100 type = MAP__FUNCTION;
1047 1101
1048 map = map__new(&machine->user_dsos, event->mmap2.start, 1102 map = map__new(machine, event->mmap2.start,
1049 event->mmap2.len, event->mmap2.pgoff, 1103 event->mmap2.len, event->mmap2.pgoff,
1050 event->mmap2.pid, event->mmap2.maj, 1104 event->mmap2.pid, event->mmap2.maj,
1051 event->mmap2.min, event->mmap2.ino, 1105 event->mmap2.min, event->mmap2.ino,
1052 event->mmap2.ino_generation, 1106 event->mmap2.ino_generation,
1053 event->mmap2.prot, 1107 event->mmap2.prot,
1054 event->mmap2.flags, 1108 event->mmap2.flags,
1055 event->mmap2.filename, type); 1109 event->mmap2.filename, type, thread);
1056 1110
1057 if (map == NULL) 1111 if (map == NULL)
1058 goto out_problem; 1112 goto out_problem;
@@ -1095,11 +1149,11 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
1095 else 1149 else
1096 type = MAP__FUNCTION; 1150 type = MAP__FUNCTION;
1097 1151
1098 map = map__new(&machine->user_dsos, event->mmap.start, 1152 map = map__new(machine, event->mmap.start,
1099 event->mmap.len, event->mmap.pgoff, 1153 event->mmap.len, event->mmap.pgoff,
1100 event->mmap.pid, 0, 0, 0, 0, 0, 0, 1154 event->mmap.pid, 0, 0, 0, 0, 0, 0,
1101 event->mmap.filename, 1155 event->mmap.filename,
1102 type); 1156 type, thread);
1103 1157
1104 if (map == NULL) 1158 if (map == NULL)
1105 goto out_problem; 1159 goto out_problem;
@@ -1281,7 +1335,9 @@ static int machine__resolve_callchain_sample(struct machine *machine,
1281 u8 cpumode = PERF_RECORD_MISC_USER; 1335 u8 cpumode = PERF_RECORD_MISC_USER;
1282 int chain_nr = min(max_stack, (int)chain->nr); 1336 int chain_nr = min(max_stack, (int)chain->nr);
1283 int i; 1337 int i;
1338 int j;
1284 int err; 1339 int err;
1340 int skip_idx __maybe_unused;
1285 1341
1286 callchain_cursor_reset(&callchain_cursor); 1342 callchain_cursor_reset(&callchain_cursor);
1287 1343
@@ -1290,14 +1346,26 @@ static int machine__resolve_callchain_sample(struct machine *machine,
1290 return 0; 1346 return 0;
1291 } 1347 }
1292 1348
1349 /*
1350 * Based on DWARF debug information, some architectures skip
1351 * a callchain entry saved by the kernel.
1352 */
1353 skip_idx = arch_skip_callchain_idx(machine, thread, chain);
1354
1293 for (i = 0; i < chain_nr; i++) { 1355 for (i = 0; i < chain_nr; i++) {
1294 u64 ip; 1356 u64 ip;
1295 struct addr_location al; 1357 struct addr_location al;
1296 1358
1297 if (callchain_param.order == ORDER_CALLEE) 1359 if (callchain_param.order == ORDER_CALLEE)
1298 ip = chain->ips[i]; 1360 j = i;
1299 else 1361 else
1300 ip = chain->ips[chain->nr - i - 1]; 1362 j = chain->nr - i - 1;
1363
1364#ifdef HAVE_SKIP_CALLCHAIN_IDX
1365 if (j == skip_idx)
1366 continue;
1367#endif
1368 ip = chain->ips[j];
1301 1369
1302 if (ip >= PERF_CONTEXT_MAX) { 1370 if (ip >= PERF_CONTEXT_MAX) {
1303 switch (ip) { 1371 switch (ip) {
@@ -1420,3 +1488,46 @@ int __machine__synthesize_threads(struct machine *machine, struct perf_tool *too
1420 /* command specified */ 1488 /* command specified */
1421 return 0; 1489 return 0;
1422} 1490}
1491
1492pid_t machine__get_current_tid(struct machine *machine, int cpu)
1493{
1494 if (cpu < 0 || cpu >= MAX_NR_CPUS || !machine->current_tid)
1495 return -1;
1496
1497 return machine->current_tid[cpu];
1498}
1499
1500int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid,
1501 pid_t tid)
1502{
1503 struct thread *thread;
1504
1505 if (cpu < 0)
1506 return -EINVAL;
1507
1508 if (!machine->current_tid) {
1509 int i;
1510
1511 machine->current_tid = calloc(MAX_NR_CPUS, sizeof(pid_t));
1512 if (!machine->current_tid)
1513 return -ENOMEM;
1514 for (i = 0; i < MAX_NR_CPUS; i++)
1515 machine->current_tid[i] = -1;
1516 }
1517
1518 if (cpu >= MAX_NR_CPUS) {
1519 pr_err("Requested CPU %d too large. ", cpu);
1520 pr_err("Consider raising MAX_NR_CPUS\n");
1521 return -EINVAL;
1522 }
1523
1524 machine->current_tid[cpu] = tid;
1525
1526 thread = machine__findnew_thread(machine, pid, tid);
1527 if (!thread)
1528 return -ENOMEM;
1529
1530 thread->cpu = cpu;
1531
1532 return 0;
1533}
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index c8c74a119398..b972824e6294 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -20,6 +20,8 @@ union perf_event;
20 20
21extern const char *ref_reloc_sym_names[]; 21extern const char *ref_reloc_sym_names[];
22 22
23struct vdso_info;
24
23struct machine { 25struct machine {
24 struct rb_node rb_node; 26 struct rb_node rb_node;
25 pid_t pid; 27 pid_t pid;
@@ -28,11 +30,13 @@ struct machine {
28 struct rb_root threads; 30 struct rb_root threads;
29 struct list_head dead_threads; 31 struct list_head dead_threads;
30 struct thread *last_match; 32 struct thread *last_match;
33 struct vdso_info *vdso_info;
31 struct list_head user_dsos; 34 struct list_head user_dsos;
32 struct list_head kernel_dsos; 35 struct list_head kernel_dsos;
33 struct map_groups kmaps; 36 struct map_groups kmaps;
34 struct map *vmlinux_maps[MAP__NR_TYPES]; 37 struct map *vmlinux_maps[MAP__NR_TYPES];
35 symbol_filter_t symbol_filter; 38 symbol_filter_t symbol_filter;
39 pid_t *current_tid;
36}; 40};
37 41
38static inline 42static inline
@@ -191,4 +195,8 @@ int machine__synthesize_threads(struct machine *machine, struct target *target,
191 perf_event__process, data_mmap); 195 perf_event__process, data_mmap);
192} 196}
193 197
198pid_t machine__get_current_tid(struct machine *machine, int cpu);
199int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid,
200 pid_t tid);
201
194#endif /* __PERF_MACHINE_H */ 202#endif /* __PERF_MACHINE_H */
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 25c571f4cba6..31b8905dd863 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -12,6 +12,8 @@
12#include "vdso.h" 12#include "vdso.h"
13#include "build-id.h" 13#include "build-id.h"
14#include "util.h" 14#include "util.h"
15#include "debug.h"
16#include "machine.h"
15#include <linux/string.h> 17#include <linux/string.h>
16 18
17const char *map_type__name[MAP__NR_TYPES] = { 19const char *map_type__name[MAP__NR_TYPES] = {
@@ -136,10 +138,10 @@ void map__init(struct map *map, enum map_type type,
136 map->erange_warned = false; 138 map->erange_warned = false;
137} 139}
138 140
139struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, 141struct map *map__new(struct machine *machine, u64 start, u64 len,
140 u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino, 142 u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
141 u64 ino_gen, u32 prot, u32 flags, char *filename, 143 u64 ino_gen, u32 prot, u32 flags, char *filename,
142 enum map_type type) 144 enum map_type type, struct thread *thread)
143{ 145{
144 struct map *map = malloc(sizeof(*map)); 146 struct map *map = malloc(sizeof(*map));
145 147
@@ -172,9 +174,9 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
172 174
173 if (vdso) { 175 if (vdso) {
174 pgoff = 0; 176 pgoff = 0;
175 dso = vdso__dso_findnew(dsos__list); 177 dso = vdso__dso_findnew(machine, thread);
176 } else 178 } else
177 dso = __dsos__findnew(dsos__list, filename); 179 dso = __dsos__findnew(&machine->user_dsos, filename);
178 180
179 if (dso == NULL) 181 if (dso == NULL)
180 goto out_delete; 182 goto out_delete;
@@ -454,6 +456,20 @@ void map_groups__exit(struct map_groups *mg)
454 } 456 }
455} 457}
456 458
459bool map_groups__empty(struct map_groups *mg)
460{
461 int i;
462
463 for (i = 0; i < MAP__NR_TYPES; ++i) {
464 if (maps__first(&mg->maps[i]))
465 return false;
466 if (!list_empty(&mg->removed_maps[i]))
467 return false;
468 }
469
470 return true;
471}
472
457struct map_groups *map_groups__new(void) 473struct map_groups *map_groups__new(void)
458{ 474{
459 struct map_groups *mg = malloc(sizeof(*mg)); 475 struct map_groups *mg = malloc(sizeof(*mg));
@@ -554,8 +570,8 @@ int map_groups__find_ams(struct addr_map_symbol *ams, symbol_filter_t filter)
554 return ams->sym ? 0 : -1; 570 return ams->sym ? 0 : -1;
555} 571}
556 572
557size_t __map_groups__fprintf_maps(struct map_groups *mg, 573size_t __map_groups__fprintf_maps(struct map_groups *mg, enum map_type type,
558 enum map_type type, int verbose, FILE *fp) 574 FILE *fp)
559{ 575{
560 size_t printed = fprintf(fp, "%s:\n", map_type__name[type]); 576 size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);
561 struct rb_node *nd; 577 struct rb_node *nd;
@@ -573,17 +589,16 @@ size_t __map_groups__fprintf_maps(struct map_groups *mg,
573 return printed; 589 return printed;
574} 590}
575 591
576size_t map_groups__fprintf_maps(struct map_groups *mg, int verbose, FILE *fp) 592static size_t map_groups__fprintf_maps(struct map_groups *mg, FILE *fp)
577{ 593{
578 size_t printed = 0, i; 594 size_t printed = 0, i;
579 for (i = 0; i < MAP__NR_TYPES; ++i) 595 for (i = 0; i < MAP__NR_TYPES; ++i)
580 printed += __map_groups__fprintf_maps(mg, i, verbose, fp); 596 printed += __map_groups__fprintf_maps(mg, i, fp);
581 return printed; 597 return printed;
582} 598}
583 599
584static size_t __map_groups__fprintf_removed_maps(struct map_groups *mg, 600static size_t __map_groups__fprintf_removed_maps(struct map_groups *mg,
585 enum map_type type, 601 enum map_type type, FILE *fp)
586 int verbose, FILE *fp)
587{ 602{
588 struct map *pos; 603 struct map *pos;
589 size_t printed = 0; 604 size_t printed = 0;
@@ -600,23 +615,23 @@ static size_t __map_groups__fprintf_removed_maps(struct map_groups *mg,
600} 615}
601 616
602static size_t map_groups__fprintf_removed_maps(struct map_groups *mg, 617static size_t map_groups__fprintf_removed_maps(struct map_groups *mg,
603 int verbose, FILE *fp) 618 FILE *fp)
604{ 619{
605 size_t printed = 0, i; 620 size_t printed = 0, i;
606 for (i = 0; i < MAP__NR_TYPES; ++i) 621 for (i = 0; i < MAP__NR_TYPES; ++i)
607 printed += __map_groups__fprintf_removed_maps(mg, i, verbose, fp); 622 printed += __map_groups__fprintf_removed_maps(mg, i, fp);
608 return printed; 623 return printed;
609} 624}
610 625
611size_t map_groups__fprintf(struct map_groups *mg, int verbose, FILE *fp) 626size_t map_groups__fprintf(struct map_groups *mg, FILE *fp)
612{ 627{
613 size_t printed = map_groups__fprintf_maps(mg, verbose, fp); 628 size_t printed = map_groups__fprintf_maps(mg, fp);
614 printed += fprintf(fp, "Removed maps:\n"); 629 printed += fprintf(fp, "Removed maps:\n");
615 return printed + map_groups__fprintf_removed_maps(mg, verbose, fp); 630 return printed + map_groups__fprintf_removed_maps(mg, fp);
616} 631}
617 632
618int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, 633int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map,
619 int verbose, FILE *fp) 634 FILE *fp)
620{ 635{
621 struct rb_root *root = &mg->maps[map->type]; 636 struct rb_root *root = &mg->maps[map->type];
622 struct rb_node *next = rb_first(root); 637 struct rb_node *next = rb_first(root);
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index 7758c72522ef..2f83954af050 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -66,6 +66,7 @@ struct map_groups {
66 66
67struct map_groups *map_groups__new(void); 67struct map_groups *map_groups__new(void);
68void map_groups__delete(struct map_groups *mg); 68void map_groups__delete(struct map_groups *mg);
69bool map_groups__empty(struct map_groups *mg);
69 70
70static inline struct map_groups *map_groups__get(struct map_groups *mg) 71static inline struct map_groups *map_groups__get(struct map_groups *mg)
71{ 72{
@@ -103,6 +104,7 @@ u64 map__rip_2objdump(struct map *map, u64 rip);
103u64 map__objdump_2mem(struct map *map, u64 ip); 104u64 map__objdump_2mem(struct map *map, u64 ip);
104 105
105struct symbol; 106struct symbol;
107struct thread;
106 108
107/* map__for_each_symbol - iterate over the symbols in the given map 109/* map__for_each_symbol - iterate over the symbols in the given map
108 * 110 *
@@ -118,10 +120,10 @@ typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
118 120
119void map__init(struct map *map, enum map_type type, 121void map__init(struct map *map, enum map_type type,
120 u64 start, u64 end, u64 pgoff, struct dso *dso); 122 u64 start, u64 end, u64 pgoff, struct dso *dso);
121struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, 123struct map *map__new(struct machine *machine, u64 start, u64 len,
122 u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino, 124 u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
123 u64 ino_gen, u32 prot, u32 flags, 125 u64 ino_gen, u32 prot, u32 flags,
124 char *filename, enum map_type type); 126 char *filename, enum map_type type, struct thread *thread);
125struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 127struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
126void map__delete(struct map *map); 128void map__delete(struct map *map);
127struct map *map__clone(struct map *map); 129struct map *map__clone(struct map *map);
@@ -141,8 +143,8 @@ void map__fixup_end(struct map *map);
141 143
142void map__reloc_vmlinux(struct map *map); 144void map__reloc_vmlinux(struct map *map);
143 145
144size_t __map_groups__fprintf_maps(struct map_groups *mg, 146size_t __map_groups__fprintf_maps(struct map_groups *mg, enum map_type type,
145 enum map_type type, int verbose, FILE *fp); 147 FILE *fp);
146void maps__insert(struct rb_root *maps, struct map *map); 148void maps__insert(struct rb_root *maps, struct map *map);
147void maps__remove(struct rb_root *maps, struct map *map); 149void maps__remove(struct rb_root *maps, struct map *map);
148struct map *maps__find(struct rb_root *maps, u64 addr); 150struct map *maps__find(struct rb_root *maps, u64 addr);
@@ -152,8 +154,7 @@ void map_groups__init(struct map_groups *mg);
152void map_groups__exit(struct map_groups *mg); 154void map_groups__exit(struct map_groups *mg);
153int map_groups__clone(struct map_groups *mg, 155int map_groups__clone(struct map_groups *mg,
154 struct map_groups *parent, enum map_type type); 156 struct map_groups *parent, enum map_type type);
155size_t map_groups__fprintf(struct map_groups *mg, int verbose, FILE *fp); 157size_t map_groups__fprintf(struct map_groups *mg, FILE *fp);
156size_t map_groups__fprintf_maps(struct map_groups *mg, int verbose, FILE *fp);
157 158
158int maps__set_kallsyms_ref_reloc_sym(struct map **maps, const char *symbol_name, 159int maps__set_kallsyms_ref_reloc_sym(struct map **maps, const char *symbol_name,
159 u64 addr); 160 u64 addr);
@@ -210,7 +211,7 @@ struct symbol *map_groups__find_function_by_name(struct map_groups *mg,
210} 211}
211 212
212int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, 213int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map,
213 int verbose, FILE *fp); 214 FILE *fp);
214 215
215struct map *map_groups__find_by_name(struct map_groups *mg, 216struct map *map_groups__find_by_name(struct map_groups *mg,
216 enum map_type type, const char *name); 217 enum map_type type, const char *name);
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h
index d8dac8ac5f37..b59ba858e73d 100644
--- a/tools/perf/util/parse-options.h
+++ b/tools/perf/util/parse-options.h
@@ -98,6 +98,7 @@ struct option {
98 parse_opt_cb *callback; 98 parse_opt_cb *callback;
99 intptr_t defval; 99 intptr_t defval;
100 bool *set; 100 bool *set;
101 void *data;
101}; 102};
102 103
103#define check_vtype(v, type) ( BUILD_BUG_ON_ZERO(!__builtin_types_compatible_p(typeof(v), type)) + v ) 104#define check_vtype(v, type) ( BUILD_BUG_ON_ZERO(!__builtin_types_compatible_p(typeof(v), type)) + v )
@@ -131,6 +132,10 @@ struct option {
131 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l),\ 132 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l),\
132 .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d,\ 133 .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d,\
133 .flags = PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NOARG} 134 .flags = PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NOARG}
135#define OPT_CALLBACK_OPTARG(s, l, v, d, a, h, f) \
136 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), \
137 .value = (v), (a), .help = (h), .callback = (f), \
138 .flags = PARSE_OPT_OPTARG, .data = (d) }
134 139
135/* parse_options() will filter out the processed options and leave the 140/* parse_options() will filter out the processed options and leave the
136 * non-option argments in argv[]. 141 * non-option argments in argv[].
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 98e304766416..dca9145d704c 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -26,7 +26,6 @@
26#include <errno.h> 26#include <errno.h>
27#include <stdio.h> 27#include <stdio.h>
28#include <unistd.h> 28#include <unistd.h>
29#include <getopt.h>
30#include <stdlib.h> 29#include <stdlib.h>
31#include <string.h> 30#include <string.h>
32#include <stdarg.h> 31#include <stdarg.h>
diff --git a/tools/perf/util/pstack.c b/tools/perf/util/pstack.c
index daa17aeb6c63..a126e6cc6e73 100644
--- a/tools/perf/util/pstack.c
+++ b/tools/perf/util/pstack.c
@@ -6,6 +6,7 @@
6 6
7#include "util.h" 7#include "util.h"
8#include "pstack.h" 8#include "pstack.h"
9#include "debug.h"
9#include <linux/kernel.h> 10#include <linux/kernel.h>
10#include <stdlib.h> 11#include <stdlib.h>
11 12
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index 122669c18ff4..12aa9b0d0ba1 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -14,12 +14,12 @@
14 */ 14 */
15int verbose; 15int verbose;
16 16
17int eprintf(int level, const char *fmt, ...) 17int eprintf(int level, int var, const char *fmt, ...)
18{ 18{
19 va_list args; 19 va_list args;
20 int ret = 0; 20 int ret = 0;
21 21
22 if (verbose >= level) { 22 if (var >= level) {
23 va_start(args, fmt); 23 va_start(args, fmt);
24 ret = vfprintf(stderr, fmt, args); 24 ret = vfprintf(stderr, fmt, args);
25 va_end(args); 25 va_end(args);
diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c
index 049e0a09ccd3..fe8079edbdc1 100644
--- a/tools/perf/util/record.c
+++ b/tools/perf/util/record.c
@@ -4,6 +4,7 @@
4#include "parse-events.h" 4#include "parse-events.h"
5#include <api/fs/fs.h> 5#include <api/fs/fs.h>
6#include "util.h" 6#include "util.h"
7#include "cloexec.h"
7 8
8typedef void (*setup_probe_fn_t)(struct perf_evsel *evsel); 9typedef void (*setup_probe_fn_t)(struct perf_evsel *evsel);
9 10
@@ -11,6 +12,7 @@ static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str)
11{ 12{
12 struct perf_evlist *evlist; 13 struct perf_evlist *evlist;
13 struct perf_evsel *evsel; 14 struct perf_evsel *evsel;
15 unsigned long flags = perf_event_open_cloexec_flag();
14 int err = -EAGAIN, fd; 16 int err = -EAGAIN, fd;
15 17
16 evlist = perf_evlist__new(); 18 evlist = perf_evlist__new();
@@ -22,14 +24,14 @@ static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str)
22 24
23 evsel = perf_evlist__first(evlist); 25 evsel = perf_evlist__first(evlist);
24 26
25 fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0); 27 fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, flags);
26 if (fd < 0) 28 if (fd < 0)
27 goto out_delete; 29 goto out_delete;
28 close(fd); 30 close(fd);
29 31
30 fn(evsel); 32 fn(evsel);
31 33
32 fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0); 34 fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, flags);
33 if (fd < 0) { 35 if (fd < 0) {
34 if (errno == EINVAL) 36 if (errno == EINVAL)
35 err = -EINVAL; 37 err = -EINVAL;
@@ -69,15 +71,26 @@ static void perf_probe_sample_identifier(struct perf_evsel *evsel)
69 evsel->attr.sample_type |= PERF_SAMPLE_IDENTIFIER; 71 evsel->attr.sample_type |= PERF_SAMPLE_IDENTIFIER;
70} 72}
71 73
74static void perf_probe_comm_exec(struct perf_evsel *evsel)
75{
76 evsel->attr.comm_exec = 1;
77}
78
72bool perf_can_sample_identifier(void) 79bool perf_can_sample_identifier(void)
73{ 80{
74 return perf_probe_api(perf_probe_sample_identifier); 81 return perf_probe_api(perf_probe_sample_identifier);
75} 82}
76 83
84static bool perf_can_comm_exec(void)
85{
86 return perf_probe_api(perf_probe_comm_exec);
87}
88
77void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts) 89void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts)
78{ 90{
79 struct perf_evsel *evsel; 91 struct perf_evsel *evsel;
80 bool use_sample_identifier = false; 92 bool use_sample_identifier = false;
93 bool use_comm_exec;
81 94
82 /* 95 /*
83 * Set the evsel leader links before we configure attributes, 96 * Set the evsel leader links before we configure attributes,
@@ -89,8 +102,13 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts)
89 if (evlist->cpus->map[0] < 0) 102 if (evlist->cpus->map[0] < 0)
90 opts->no_inherit = true; 103 opts->no_inherit = true;
91 104
92 evlist__for_each(evlist, evsel) 105 use_comm_exec = perf_can_comm_exec();
106
107 evlist__for_each(evlist, evsel) {
93 perf_evsel__config(evsel, opts); 108 perf_evsel__config(evsel, opts);
109 if (!evsel->idx && use_comm_exec)
110 evsel->attr.comm_exec = 1;
111 }
94 112
95 if (evlist->nr_entries > 1) { 113 if (evlist->nr_entries > 1) {
96 struct perf_evsel *first = perf_evlist__first(evlist); 114 struct perf_evsel *first = perf_evlist__first(evlist);
@@ -203,7 +221,8 @@ bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str)
203 cpu = evlist->cpus->map[0]; 221 cpu = evlist->cpus->map[0];
204 } 222 }
205 223
206 fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0); 224 fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1,
225 perf_event_open_cloexec_flag());
207 if (fd >= 0) { 226 if (fd >= 0) {
208 close(fd); 227 close(fd);
209 ret = true; 228 ret = true;
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index af7da565a750..b2dba9c0a3a1 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -34,6 +34,7 @@
34#include "../event.h" 34#include "../event.h"
35#include "../trace-event.h" 35#include "../trace-event.h"
36#include "../evsel.h" 36#include "../evsel.h"
37#include "../debug.h"
37 38
38void boot_Perf__Trace__Context(pTHX_ CV *cv); 39void boot_Perf__Trace__Context(pTHX_ CV *cv);
39void boot_DynaLoader(pTHX_ CV *cv); 40void boot_DynaLoader(pTHX_ CV *cv);
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index 1c419321f707..cbce2545da45 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -27,11 +27,13 @@
27#include <errno.h> 27#include <errno.h>
28 28
29#include "../../perf.h" 29#include "../../perf.h"
30#include "../debug.h"
30#include "../evsel.h" 31#include "../evsel.h"
31#include "../util.h" 32#include "../util.h"
32#include "../event.h" 33#include "../event.h"
33#include "../thread.h" 34#include "../thread.h"
34#include "../trace-event.h" 35#include "../trace-event.h"
36#include "../machine.h"
35 37
36PyMODINIT_FUNC initperf_trace_context(void); 38PyMODINIT_FUNC initperf_trace_context(void);
37 39
@@ -50,10 +52,14 @@ static int zero_flag_atom;
50 52
51static PyObject *main_module, *main_dict; 53static PyObject *main_module, *main_dict;
52 54
55static void handler_call_die(const char *handler_name) NORETURN;
53static void handler_call_die(const char *handler_name) 56static void handler_call_die(const char *handler_name)
54{ 57{
55 PyErr_Print(); 58 PyErr_Print();
56 Py_FatalError("problem in Python trace event handler"); 59 Py_FatalError("problem in Python trace event handler");
60 // Py_FatalError does not return
61 // but we have to make the compiler happy
62 abort();
57} 63}
58 64
59/* 65/*
@@ -97,6 +103,7 @@ static void define_value(enum print_arg_type field_type,
97 retval = PyObject_CallObject(handler, t); 103 retval = PyObject_CallObject(handler, t);
98 if (retval == NULL) 104 if (retval == NULL)
99 handler_call_die(handler_name); 105 handler_call_die(handler_name);
106 Py_DECREF(retval);
100 } 107 }
101 108
102 Py_DECREF(t); 109 Py_DECREF(t);
@@ -143,6 +150,7 @@ static void define_field(enum print_arg_type field_type,
143 retval = PyObject_CallObject(handler, t); 150 retval = PyObject_CallObject(handler, t);
144 if (retval == NULL) 151 if (retval == NULL)
145 handler_call_die(handler_name); 152 handler_call_die(handler_name);
153 Py_DECREF(retval);
146 } 154 }
147 155
148 Py_DECREF(t); 156 Py_DECREF(t);
@@ -231,15 +239,133 @@ static inline struct event_format *find_cache_event(struct perf_evsel *evsel)
231 return event; 239 return event;
232} 240}
233 241
242static PyObject *get_field_numeric_entry(struct event_format *event,
243 struct format_field *field, void *data)
244{
245 bool is_array = field->flags & FIELD_IS_ARRAY;
246 PyObject *obj, *list = NULL;
247 unsigned long long val;
248 unsigned int item_size, n_items, i;
249
250 if (is_array) {
251 list = PyList_New(field->arraylen);
252 item_size = field->size / field->arraylen;
253 n_items = field->arraylen;
254 } else {
255 item_size = field->size;
256 n_items = 1;
257 }
258
259 for (i = 0; i < n_items; i++) {
260
261 val = read_size(event, data + field->offset + i * item_size,
262 item_size);
263 if (field->flags & FIELD_IS_SIGNED) {
264 if ((long long)val >= LONG_MIN &&
265 (long long)val <= LONG_MAX)
266 obj = PyInt_FromLong(val);
267 else
268 obj = PyLong_FromLongLong(val);
269 } else {
270 if (val <= LONG_MAX)
271 obj = PyInt_FromLong(val);
272 else
273 obj = PyLong_FromUnsignedLongLong(val);
274 }
275 if (is_array)
276 PyList_SET_ITEM(list, i, obj);
277 }
278 if (is_array)
279 obj = list;
280 return obj;
281}
282
283
284static PyObject *python_process_callchain(struct perf_sample *sample,
285 struct perf_evsel *evsel,
286 struct addr_location *al)
287{
288 PyObject *pylist;
289
290 pylist = PyList_New(0);
291 if (!pylist)
292 Py_FatalError("couldn't create Python list");
293
294 if (!symbol_conf.use_callchain || !sample->callchain)
295 goto exit;
296
297 if (machine__resolve_callchain(al->machine, evsel, al->thread,
298 sample, NULL, NULL,
299 PERF_MAX_STACK_DEPTH) != 0) {
300 pr_err("Failed to resolve callchain. Skipping\n");
301 goto exit;
302 }
303 callchain_cursor_commit(&callchain_cursor);
304
305
306 while (1) {
307 PyObject *pyelem;
308 struct callchain_cursor_node *node;
309 node = callchain_cursor_current(&callchain_cursor);
310 if (!node)
311 break;
312
313 pyelem = PyDict_New();
314 if (!pyelem)
315 Py_FatalError("couldn't create Python dictionary");
316
317
318 pydict_set_item_string_decref(pyelem, "ip",
319 PyLong_FromUnsignedLongLong(node->ip));
320
321 if (node->sym) {
322 PyObject *pysym = PyDict_New();
323 if (!pysym)
324 Py_FatalError("couldn't create Python dictionary");
325 pydict_set_item_string_decref(pysym, "start",
326 PyLong_FromUnsignedLongLong(node->sym->start));
327 pydict_set_item_string_decref(pysym, "end",
328 PyLong_FromUnsignedLongLong(node->sym->end));
329 pydict_set_item_string_decref(pysym, "binding",
330 PyInt_FromLong(node->sym->binding));
331 pydict_set_item_string_decref(pysym, "name",
332 PyString_FromStringAndSize(node->sym->name,
333 node->sym->namelen));
334 pydict_set_item_string_decref(pyelem, "sym", pysym);
335 }
336
337 if (node->map) {
338 struct map *map = node->map;
339 const char *dsoname = "[unknown]";
340 if (map && map->dso && (map->dso->name || map->dso->long_name)) {
341 if (symbol_conf.show_kernel_path && map->dso->long_name)
342 dsoname = map->dso->long_name;
343 else if (map->dso->name)
344 dsoname = map->dso->name;
345 }
346 pydict_set_item_string_decref(pyelem, "dso",
347 PyString_FromString(dsoname));
348 }
349
350 callchain_cursor_advance(&callchain_cursor);
351 PyList_Append(pylist, pyelem);
352 Py_DECREF(pyelem);
353 }
354
355exit:
356 return pylist;
357}
358
359
234static void python_process_tracepoint(struct perf_sample *sample, 360static void python_process_tracepoint(struct perf_sample *sample,
235 struct perf_evsel *evsel, 361 struct perf_evsel *evsel,
236 struct thread *thread, 362 struct thread *thread,
237 struct addr_location *al) 363 struct addr_location *al)
238{ 364{
239 PyObject *handler, *retval, *context, *t, *obj, *dict = NULL; 365 PyObject *handler, *retval, *context, *t, *obj, *callchain;
366 PyObject *dict = NULL;
240 static char handler_name[256]; 367 static char handler_name[256];
241 struct format_field *field; 368 struct format_field *field;
242 unsigned long long val;
243 unsigned long s, ns; 369 unsigned long s, ns;
244 struct event_format *event; 370 struct event_format *event;
245 unsigned n = 0; 371 unsigned n = 0;
@@ -280,18 +406,23 @@ static void python_process_tracepoint(struct perf_sample *sample,
280 PyTuple_SetItem(t, n++, PyString_FromString(handler_name)); 406 PyTuple_SetItem(t, n++, PyString_FromString(handler_name));
281 PyTuple_SetItem(t, n++, context); 407 PyTuple_SetItem(t, n++, context);
282 408
409 /* ip unwinding */
410 callchain = python_process_callchain(sample, evsel, al);
411
283 if (handler) { 412 if (handler) {
284 PyTuple_SetItem(t, n++, PyInt_FromLong(cpu)); 413 PyTuple_SetItem(t, n++, PyInt_FromLong(cpu));
285 PyTuple_SetItem(t, n++, PyInt_FromLong(s)); 414 PyTuple_SetItem(t, n++, PyInt_FromLong(s));
286 PyTuple_SetItem(t, n++, PyInt_FromLong(ns)); 415 PyTuple_SetItem(t, n++, PyInt_FromLong(ns));
287 PyTuple_SetItem(t, n++, PyInt_FromLong(pid)); 416 PyTuple_SetItem(t, n++, PyInt_FromLong(pid));
288 PyTuple_SetItem(t, n++, PyString_FromString(comm)); 417 PyTuple_SetItem(t, n++, PyString_FromString(comm));
418 PyTuple_SetItem(t, n++, callchain);
289 } else { 419 } else {
290 pydict_set_item_string_decref(dict, "common_cpu", PyInt_FromLong(cpu)); 420 pydict_set_item_string_decref(dict, "common_cpu", PyInt_FromLong(cpu));
291 pydict_set_item_string_decref(dict, "common_s", PyInt_FromLong(s)); 421 pydict_set_item_string_decref(dict, "common_s", PyInt_FromLong(s));
292 pydict_set_item_string_decref(dict, "common_ns", PyInt_FromLong(ns)); 422 pydict_set_item_string_decref(dict, "common_ns", PyInt_FromLong(ns));
293 pydict_set_item_string_decref(dict, "common_pid", PyInt_FromLong(pid)); 423 pydict_set_item_string_decref(dict, "common_pid", PyInt_FromLong(pid));
294 pydict_set_item_string_decref(dict, "common_comm", PyString_FromString(comm)); 424 pydict_set_item_string_decref(dict, "common_comm", PyString_FromString(comm));
425 pydict_set_item_string_decref(dict, "common_callchain", callchain);
295 } 426 }
296 for (field = event->format.fields; field; field = field->next) { 427 for (field = event->format.fields; field; field = field->next) {
297 if (field->flags & FIELD_IS_STRING) { 428 if (field->flags & FIELD_IS_STRING) {
@@ -303,20 +434,7 @@ static void python_process_tracepoint(struct perf_sample *sample,
303 offset = field->offset; 434 offset = field->offset;
304 obj = PyString_FromString((char *)data + offset); 435 obj = PyString_FromString((char *)data + offset);
305 } else { /* FIELD_IS_NUMERIC */ 436 } else { /* FIELD_IS_NUMERIC */
306 val = read_size(event, data + field->offset, 437 obj = get_field_numeric_entry(event, field, data);
307 field->size);
308 if (field->flags & FIELD_IS_SIGNED) {
309 if ((long long)val >= LONG_MIN &&
310 (long long)val <= LONG_MAX)
311 obj = PyInt_FromLong(val);
312 else
313 obj = PyLong_FromLongLong(val);
314 } else {
315 if (val <= LONG_MAX)
316 obj = PyInt_FromLong(val);
317 else
318 obj = PyLong_FromUnsignedLongLong(val);
319 }
320 } 438 }
321 if (handler) 439 if (handler)
322 PyTuple_SetItem(t, n++, obj); 440 PyTuple_SetItem(t, n++, obj);
@@ -324,6 +442,7 @@ static void python_process_tracepoint(struct perf_sample *sample,
324 pydict_set_item_string_decref(dict, field->name, obj); 442 pydict_set_item_string_decref(dict, field->name, obj);
325 443
326 } 444 }
445
327 if (!handler) 446 if (!handler)
328 PyTuple_SetItem(t, n++, dict); 447 PyTuple_SetItem(t, n++, dict);
329 448
@@ -334,6 +453,7 @@ static void python_process_tracepoint(struct perf_sample *sample,
334 retval = PyObject_CallObject(handler, t); 453 retval = PyObject_CallObject(handler, t);
335 if (retval == NULL) 454 if (retval == NULL)
336 handler_call_die(handler_name); 455 handler_call_die(handler_name);
456 Py_DECREF(retval);
337 } else { 457 } else {
338 handler = PyDict_GetItemString(main_dict, "trace_unhandled"); 458 handler = PyDict_GetItemString(main_dict, "trace_unhandled");
339 if (handler && PyCallable_Check(handler)) { 459 if (handler && PyCallable_Check(handler)) {
@@ -341,6 +461,7 @@ static void python_process_tracepoint(struct perf_sample *sample,
341 retval = PyObject_CallObject(handler, t); 461 retval = PyObject_CallObject(handler, t);
342 if (retval == NULL) 462 if (retval == NULL)
343 handler_call_die("trace_unhandled"); 463 handler_call_die("trace_unhandled");
464 Py_DECREF(retval);
344 } 465 }
345 Py_DECREF(dict); 466 Py_DECREF(dict);
346 } 467 }
@@ -353,7 +474,7 @@ static void python_process_general_event(struct perf_sample *sample,
353 struct thread *thread, 474 struct thread *thread,
354 struct addr_location *al) 475 struct addr_location *al)
355{ 476{
356 PyObject *handler, *retval, *t, *dict; 477 PyObject *handler, *retval, *t, *dict, *callchain, *dict_sample;
357 static char handler_name[64]; 478 static char handler_name[64];
358 unsigned n = 0; 479 unsigned n = 0;
359 480
@@ -369,6 +490,10 @@ static void python_process_general_event(struct perf_sample *sample,
369 if (!dict) 490 if (!dict)
370 Py_FatalError("couldn't create Python dictionary"); 491 Py_FatalError("couldn't create Python dictionary");
371 492
493 dict_sample = PyDict_New();
494 if (!dict_sample)
495 Py_FatalError("couldn't create Python dictionary");
496
372 snprintf(handler_name, sizeof(handler_name), "%s", "process_event"); 497 snprintf(handler_name, sizeof(handler_name), "%s", "process_event");
373 498
374 handler = PyDict_GetItemString(main_dict, handler_name); 499 handler = PyDict_GetItemString(main_dict, handler_name);
@@ -378,8 +503,21 @@ static void python_process_general_event(struct perf_sample *sample,
378 pydict_set_item_string_decref(dict, "ev_name", PyString_FromString(perf_evsel__name(evsel))); 503 pydict_set_item_string_decref(dict, "ev_name", PyString_FromString(perf_evsel__name(evsel)));
379 pydict_set_item_string_decref(dict, "attr", PyString_FromStringAndSize( 504 pydict_set_item_string_decref(dict, "attr", PyString_FromStringAndSize(
380 (const char *)&evsel->attr, sizeof(evsel->attr))); 505 (const char *)&evsel->attr, sizeof(evsel->attr)));
381 pydict_set_item_string_decref(dict, "sample", PyString_FromStringAndSize( 506
382 (const char *)sample, sizeof(*sample))); 507 pydict_set_item_string_decref(dict_sample, "pid",
508 PyInt_FromLong(sample->pid));
509 pydict_set_item_string_decref(dict_sample, "tid",
510 PyInt_FromLong(sample->tid));
511 pydict_set_item_string_decref(dict_sample, "cpu",
512 PyInt_FromLong(sample->cpu));
513 pydict_set_item_string_decref(dict_sample, "ip",
514 PyLong_FromUnsignedLongLong(sample->ip));
515 pydict_set_item_string_decref(dict_sample, "time",
516 PyLong_FromUnsignedLongLong(sample->time));
517 pydict_set_item_string_decref(dict_sample, "period",
518 PyLong_FromUnsignedLongLong(sample->period));
519 pydict_set_item_string_decref(dict, "sample", dict_sample);
520
383 pydict_set_item_string_decref(dict, "raw_buf", PyString_FromStringAndSize( 521 pydict_set_item_string_decref(dict, "raw_buf", PyString_FromStringAndSize(
384 (const char *)sample->raw_data, sample->raw_size)); 522 (const char *)sample->raw_data, sample->raw_size));
385 pydict_set_item_string_decref(dict, "comm", 523 pydict_set_item_string_decref(dict, "comm",
@@ -393,6 +531,10 @@ static void python_process_general_event(struct perf_sample *sample,
393 PyString_FromString(al->sym->name)); 531 PyString_FromString(al->sym->name));
394 } 532 }
395 533
534 /* ip unwinding */
535 callchain = python_process_callchain(sample, evsel, al);
536 pydict_set_item_string_decref(dict, "callchain", callchain);
537
396 PyTuple_SetItem(t, n++, dict); 538 PyTuple_SetItem(t, n++, dict);
397 if (_PyTuple_Resize(&t, n) == -1) 539 if (_PyTuple_Resize(&t, n) == -1)
398 Py_FatalError("error resizing Python tuple"); 540 Py_FatalError("error resizing Python tuple");
@@ -400,6 +542,7 @@ static void python_process_general_event(struct perf_sample *sample,
400 retval = PyObject_CallObject(handler, t); 542 retval = PyObject_CallObject(handler, t);
401 if (retval == NULL) 543 if (retval == NULL)
402 handler_call_die(handler_name); 544 handler_call_die(handler_name);
545 Py_DECREF(retval);
403exit: 546exit:
404 Py_DECREF(dict); 547 Py_DECREF(dict);
405 Py_DECREF(t); 548 Py_DECREF(t);
@@ -521,8 +664,7 @@ static int python_stop_script(void)
521 retval = PyObject_CallObject(handler, NULL); 664 retval = PyObject_CallObject(handler, NULL);
522 if (retval == NULL) 665 if (retval == NULL)
523 handler_call_die("trace_end"); 666 handler_call_die("trace_end");
524 else 667 Py_DECREF(retval);
525 Py_DECREF(retval);
526out: 668out:
527 Py_XDECREF(main_dict); 669 Py_XDECREF(main_dict);
528 Py_XDECREF(main_module); 670 Py_XDECREF(main_module);
@@ -589,6 +731,7 @@ static int python_generate_script(struct pevent *pevent, const char *outfile)
589 fprintf(ofp, "common_nsecs, "); 731 fprintf(ofp, "common_nsecs, ");
590 fprintf(ofp, "common_pid, "); 732 fprintf(ofp, "common_pid, ");
591 fprintf(ofp, "common_comm,\n\t"); 733 fprintf(ofp, "common_comm,\n\t");
734 fprintf(ofp, "common_callchain, ");
592 735
593 not_first = 0; 736 not_first = 0;
594 count = 0; 737 count = 0;
@@ -632,7 +775,7 @@ static int python_generate_script(struct pevent *pevent, const char *outfile)
632 fprintf(ofp, "%%u"); 775 fprintf(ofp, "%%u");
633 } 776 }
634 777
635 fprintf(ofp, "\\n\" %% \\\n\t\t("); 778 fprintf(ofp, "\" %% \\\n\t\t(");
636 779
637 not_first = 0; 780 not_first = 0;
638 count = 0; 781 count = 0;
@@ -668,7 +811,15 @@ static int python_generate_script(struct pevent *pevent, const char *outfile)
668 fprintf(ofp, "%s", f->name); 811 fprintf(ofp, "%s", f->name);
669 } 812 }
670 813
671 fprintf(ofp, "),\n\n"); 814 fprintf(ofp, ")\n\n");
815
816 fprintf(ofp, "\t\tfor node in common_callchain:");
817 fprintf(ofp, "\n\t\t\tif 'sym' in node:");
818 fprintf(ofp, "\n\t\t\t\tprint \"\\t[%%x] %%s\" %% (node['ip'], node['sym']['name'])");
819 fprintf(ofp, "\n\t\t\telse:");
820 fprintf(ofp, "\n\t\t\t\tprint \"\t[%%x]\" %% (node['ip'])\n\n");
821 fprintf(ofp, "\t\tprint \"\\n\"\n\n");
822
672 } 823 }
673 824
674 fprintf(ofp, "def trace_unhandled(event_name, context, " 825 fprintf(ofp, "def trace_unhandled(event_name, context, "
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 64a186edc7be..88dfef70c13d 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -14,7 +14,6 @@
14#include "util.h" 14#include "util.h"
15#include "cpumap.h" 15#include "cpumap.h"
16#include "perf_regs.h" 16#include "perf_regs.h"
17#include "vdso.h"
18 17
19static int perf_session__open(struct perf_session *session) 18static int perf_session__open(struct perf_session *session)
20{ 19{
@@ -156,7 +155,6 @@ void perf_session__delete(struct perf_session *session)
156 if (session->file) 155 if (session->file)
157 perf_data_file__close(session->file); 156 perf_data_file__close(session->file);
158 free(session); 157 free(session);
159 vdso__exit();
160} 158}
161 159
162static int process_event_synth_tracing_data_stub(struct perf_tool *tool 160static int process_event_synth_tracing_data_stub(struct perf_tool *tool
@@ -511,6 +509,7 @@ static int flush_sample_queue(struct perf_session *s,
511 os->last_flush = iter->timestamp; 509 os->last_flush = iter->timestamp;
512 list_del(&iter->list); 510 list_del(&iter->list);
513 list_add(&iter->list, &os->sample_cache); 511 list_add(&iter->list, &os->sample_cache);
512 os->nr_samples--;
514 513
515 if (show_progress) 514 if (show_progress)
516 ui_progress__update(&prog, 1); 515 ui_progress__update(&prog, 1);
@@ -523,8 +522,6 @@ static int flush_sample_queue(struct perf_session *s,
523 list_entry(head->prev, struct sample_queue, list); 522 list_entry(head->prev, struct sample_queue, list);
524 } 523 }
525 524
526 os->nr_samples = 0;
527
528 return 0; 525 return 0;
529} 526}
530 527
@@ -994,8 +991,10 @@ static int perf_session_deliver_event(struct perf_session *session,
994 } 991 }
995} 992}
996 993
997static int perf_session__process_user_event(struct perf_session *session, union perf_event *event, 994static s64 perf_session__process_user_event(struct perf_session *session,
998 struct perf_tool *tool, u64 file_offset) 995 union perf_event *event,
996 struct perf_tool *tool,
997 u64 file_offset)
999{ 998{
1000 int fd = perf_data_file__fd(session->file); 999 int fd = perf_data_file__fd(session->file);
1001 int err; 1000 int err;
@@ -1037,7 +1036,7 @@ static void event_swap(union perf_event *event, bool sample_id_all)
1037 swap(event, sample_id_all); 1036 swap(event, sample_id_all);
1038} 1037}
1039 1038
1040static int perf_session__process_event(struct perf_session *session, 1039static s64 perf_session__process_event(struct perf_session *session,
1041 union perf_event *event, 1040 union perf_event *event,
1042 struct perf_tool *tool, 1041 struct perf_tool *tool,
1043 u64 file_offset) 1042 u64 file_offset)
@@ -1083,13 +1082,14 @@ void perf_event_header__bswap(struct perf_event_header *hdr)
1083 1082
1084struct thread *perf_session__findnew(struct perf_session *session, pid_t pid) 1083struct thread *perf_session__findnew(struct perf_session *session, pid_t pid)
1085{ 1084{
1086 return machine__findnew_thread(&session->machines.host, 0, pid); 1085 return machine__findnew_thread(&session->machines.host, -1, pid);
1087} 1086}
1088 1087
1089static struct thread *perf_session__register_idle_thread(struct perf_session *session) 1088static struct thread *perf_session__register_idle_thread(struct perf_session *session)
1090{ 1089{
1091 struct thread *thread = perf_session__findnew(session, 0); 1090 struct thread *thread;
1092 1091
1092 thread = machine__findnew_thread(&session->machines.host, 0, 0);
1093 if (thread == NULL || thread__set_comm(thread, "swapper", 0)) { 1093 if (thread == NULL || thread__set_comm(thread, "swapper", 0)) {
1094 pr_err("problem inserting idle task.\n"); 1094 pr_err("problem inserting idle task.\n");
1095 thread = NULL; 1095 thread = NULL;
@@ -1147,7 +1147,7 @@ static int __perf_session__process_pipe_events(struct perf_session *session,
1147 union perf_event *event; 1147 union perf_event *event;
1148 uint32_t size, cur_size = 0; 1148 uint32_t size, cur_size = 0;
1149 void *buf = NULL; 1149 void *buf = NULL;
1150 int skip = 0; 1150 s64 skip = 0;
1151 u64 head; 1151 u64 head;
1152 ssize_t err; 1152 ssize_t err;
1153 void *p; 1153 void *p;
@@ -1276,13 +1276,13 @@ int __perf_session__process_events(struct perf_session *session,
1276 u64 file_size, struct perf_tool *tool) 1276 u64 file_size, struct perf_tool *tool)
1277{ 1277{
1278 int fd = perf_data_file__fd(session->file); 1278 int fd = perf_data_file__fd(session->file);
1279 u64 head, page_offset, file_offset, file_pos; 1279 u64 head, page_offset, file_offset, file_pos, size;
1280 int err, mmap_prot, mmap_flags, map_idx = 0; 1280 int err, mmap_prot, mmap_flags, map_idx = 0;
1281 size_t mmap_size; 1281 size_t mmap_size;
1282 char *buf, *mmaps[NUM_MMAPS]; 1282 char *buf, *mmaps[NUM_MMAPS];
1283 union perf_event *event; 1283 union perf_event *event;
1284 uint32_t size;
1285 struct ui_progress prog; 1284 struct ui_progress prog;
1285 s64 skip;
1286 1286
1287 perf_tool__fill_defaults(tool); 1287 perf_tool__fill_defaults(tool);
1288 1288
@@ -1296,8 +1296,10 @@ int __perf_session__process_events(struct perf_session *session,
1296 ui_progress__init(&prog, file_size, "Processing events..."); 1296 ui_progress__init(&prog, file_size, "Processing events...");
1297 1297
1298 mmap_size = MMAP_SIZE; 1298 mmap_size = MMAP_SIZE;
1299 if (mmap_size > file_size) 1299 if (mmap_size > file_size) {
1300 mmap_size = file_size; 1300 mmap_size = file_size;
1301 session->one_mmap = true;
1302 }
1301 1303
1302 memset(mmaps, 0, sizeof(mmaps)); 1304 memset(mmaps, 0, sizeof(mmaps));
1303 1305
@@ -1319,6 +1321,10 @@ remap:
1319 mmaps[map_idx] = buf; 1321 mmaps[map_idx] = buf;
1320 map_idx = (map_idx + 1) & (ARRAY_SIZE(mmaps) - 1); 1322 map_idx = (map_idx + 1) & (ARRAY_SIZE(mmaps) - 1);
1321 file_pos = file_offset + head; 1323 file_pos = file_offset + head;
1324 if (session->one_mmap) {
1325 session->one_mmap_addr = buf;
1326 session->one_mmap_offset = file_offset;
1327 }
1322 1328
1323more: 1329more:
1324 event = fetch_mmaped_event(session, head, mmap_size, buf); 1330 event = fetch_mmaped_event(session, head, mmap_size, buf);
@@ -1337,7 +1343,8 @@ more:
1337 size = event->header.size; 1343 size = event->header.size;
1338 1344
1339 if (size < sizeof(struct perf_event_header) || 1345 if (size < sizeof(struct perf_event_header) ||
1340 perf_session__process_event(session, event, tool, file_pos) < 0) { 1346 (skip = perf_session__process_event(session, event, tool, file_pos))
1347 < 0) {
1341 pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n", 1348 pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n",
1342 file_offset + head, event->header.size, 1349 file_offset + head, event->header.size,
1343 event->header.type); 1350 event->header.type);
@@ -1345,6 +1352,9 @@ more:
1345 goto out_err; 1352 goto out_err;
1346 } 1353 }
1347 1354
1355 if (skip)
1356 size += skip;
1357
1348 head += size; 1358 head += size;
1349 file_pos += size; 1359 file_pos += size;
1350 1360
@@ -1364,6 +1374,7 @@ out_err:
1364 ui_progress__finish(); 1374 ui_progress__finish();
1365 perf_session__warn_about_errors(session, tool); 1375 perf_session__warn_about_errors(session, tool);
1366 perf_session_free_sample_buffers(session); 1376 perf_session_free_sample_buffers(session);
1377 session->one_mmap = false;
1367 return err; 1378 return err;
1368} 1379}
1369 1380
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 3140f8ae6148..0321013bd9fd 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -36,6 +36,9 @@ struct perf_session {
36 struct trace_event tevent; 36 struct trace_event tevent;
37 struct events_stats stats; 37 struct events_stats stats;
38 bool repipe; 38 bool repipe;
39 bool one_mmap;
40 void *one_mmap_addr;
41 u64 one_mmap_offset;
39 struct ordered_samples ordered_samples; 42 struct ordered_samples ordered_samples;
40 struct perf_data_file *file; 43 struct perf_data_file *file;
41}; 44};
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 1ec57dd82284..14e5a039bc45 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -1215,7 +1215,7 @@ static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1215 hse = container_of(fmt, struct hpp_sort_entry, hpp); 1215 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1216 len = hists__col_len(&evsel->hists, hse->se->se_width_idx); 1216 len = hists__col_len(&evsel->hists, hse->se->se_width_idx);
1217 1217
1218 return scnprintf(hpp->buf, hpp->size, "%*s", len, hse->se->se_header); 1218 return scnprintf(hpp->buf, hpp->size, "%-*s", len, hse->se->se_header);
1219} 1219}
1220 1220
1221static int __sort__hpp_width(struct perf_hpp_fmt *fmt, 1221static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
diff --git a/tools/perf/util/svghelper.c b/tools/perf/util/svghelper.c
index 6a0a13d07a28..283d3e73e2f2 100644
--- a/tools/perf/util/svghelper.c
+++ b/tools/perf/util/svghelper.c
@@ -30,6 +30,7 @@ static u64 turbo_frequency, max_freq;
30 30
31#define SLOT_MULT 30.0 31#define SLOT_MULT 30.0
32#define SLOT_HEIGHT 25.0 32#define SLOT_HEIGHT 25.0
33#define SLOT_HALF (SLOT_HEIGHT / 2)
33 34
34int svg_page_width = 1000; 35int svg_page_width = 1000;
35u64 svg_highlight; 36u64 svg_highlight;
@@ -114,8 +115,14 @@ void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end)
114 fprintf(svgfile, " rect { stroke-width: 1; }\n"); 115 fprintf(svgfile, " rect { stroke-width: 1; }\n");
115 fprintf(svgfile, " rect.process { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:1; stroke:rgb( 0, 0, 0); } \n"); 116 fprintf(svgfile, " rect.process { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:1; stroke:rgb( 0, 0, 0); } \n");
116 fprintf(svgfile, " rect.process2 { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 117 fprintf(svgfile, " rect.process2 { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
118 fprintf(svgfile, " rect.process3 { fill:rgb(180,180,180); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
117 fprintf(svgfile, " rect.sample { fill:rgb( 0, 0,255); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 119 fprintf(svgfile, " rect.sample { fill:rgb( 0, 0,255); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
118 fprintf(svgfile, " rect.sample_hi{ fill:rgb(255,128, 0); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 120 fprintf(svgfile, " rect.sample_hi{ fill:rgb(255,128, 0); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
121 fprintf(svgfile, " rect.error { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
122 fprintf(svgfile, " rect.net { fill:rgb( 0,128, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
123 fprintf(svgfile, " rect.disk { fill:rgb( 0, 0,255); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
124 fprintf(svgfile, " rect.sync { fill:rgb(128,128, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
125 fprintf(svgfile, " rect.poll { fill:rgb( 0,128,128); fill-opacity:0.2; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
119 fprintf(svgfile, " rect.blocked { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 126 fprintf(svgfile, " rect.blocked { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
120 fprintf(svgfile, " rect.waiting { fill:rgb(224,214, 0); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 127 fprintf(svgfile, " rect.waiting { fill:rgb(224,214, 0); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
121 fprintf(svgfile, " rect.WAITING { fill:rgb(255,214, 48); fill-opacity:0.6; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 128 fprintf(svgfile, " rect.WAITING { fill:rgb(255,214, 48); fill-opacity:0.6; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
@@ -132,12 +139,81 @@ void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end)
132 fprintf(svgfile, " ]]>\n </style>\n</defs>\n"); 139 fprintf(svgfile, " ]]>\n </style>\n</defs>\n");
133} 140}
134 141
142static double normalize_height(double height)
143{
144 if (height < 0.25)
145 return 0.25;
146 else if (height < 0.50)
147 return 0.50;
148 else if (height < 0.75)
149 return 0.75;
150 else
151 return 0.100;
152}
153
154void svg_ubox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges)
155{
156 double w = time2pixels(end) - time2pixels(start);
157 height = normalize_height(height);
158
159 if (!svgfile)
160 return;
161
162 fprintf(svgfile, "<g>\n");
163 fprintf(svgfile, "<title>fd=%d error=%d merges=%d</title>\n", fd, err, merges);
164 fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"%s\"/>\n",
165 time2pixels(start),
166 w,
167 Yslot * SLOT_MULT,
168 SLOT_HALF * height,
169 type);
170 fprintf(svgfile, "</g>\n");
171}
172
173void svg_lbox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges)
174{
175 double w = time2pixels(end) - time2pixels(start);
176 height = normalize_height(height);
177
178 if (!svgfile)
179 return;
180
181 fprintf(svgfile, "<g>\n");
182 fprintf(svgfile, "<title>fd=%d error=%d merges=%d</title>\n", fd, err, merges);
183 fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"%s\"/>\n",
184 time2pixels(start),
185 w,
186 Yslot * SLOT_MULT + SLOT_HEIGHT - SLOT_HALF * height,
187 SLOT_HALF * height,
188 type);
189 fprintf(svgfile, "</g>\n");
190}
191
192void svg_fbox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges)
193{
194 double w = time2pixels(end) - time2pixels(start);
195 height = normalize_height(height);
196
197 if (!svgfile)
198 return;
199
200 fprintf(svgfile, "<g>\n");
201 fprintf(svgfile, "<title>fd=%d error=%d merges=%d</title>\n", fd, err, merges);
202 fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"%s\"/>\n",
203 time2pixels(start),
204 w,
205 Yslot * SLOT_MULT + SLOT_HEIGHT - SLOT_HEIGHT * height,
206 SLOT_HEIGHT * height,
207 type);
208 fprintf(svgfile, "</g>\n");
209}
210
135void svg_box(int Yslot, u64 start, u64 end, const char *type) 211void svg_box(int Yslot, u64 start, u64 end, const char *type)
136{ 212{
137 if (!svgfile) 213 if (!svgfile)
138 return; 214 return;
139 215
140 fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"%s\"/>\n", 216 fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"%s\"/>\n",
141 time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT, type); 217 time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT, type);
142} 218}
143 219
@@ -174,7 +250,7 @@ void svg_running(int Yslot, int cpu, u64 start, u64 end, const char *backtrace)
174 cpu, time_to_string(end - start)); 250 cpu, time_to_string(end - start));
175 if (backtrace) 251 if (backtrace)
176 fprintf(svgfile, "<desc>Switched because:\n%s</desc>\n", backtrace); 252 fprintf(svgfile, "<desc>Switched because:\n%s</desc>\n", backtrace);
177 fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"%s\"/>\n", 253 fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"%s\"/>\n",
178 time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT, 254 time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT,
179 type); 255 type);
180 256
@@ -186,7 +262,7 @@ void svg_running(int Yslot, int cpu, u64 start, u64 end, const char *backtrace)
186 text_size = round_text_size(text_size); 262 text_size = round_text_size(text_size);
187 263
188 if (text_size > MIN_TEXT_SIZE) 264 if (text_size > MIN_TEXT_SIZE)
189 fprintf(svgfile, "<text x=\"%1.8f\" y=\"%1.8f\" font-size=\"%1.8fpt\">%i</text>\n", 265 fprintf(svgfile, "<text x=\"%.8f\" y=\"%.8f\" font-size=\"%.8fpt\">%i</text>\n",
190 time2pixels(start), Yslot * SLOT_MULT + SLOT_HEIGHT - 1, text_size, cpu + 1); 266 time2pixels(start), Yslot * SLOT_MULT + SLOT_HEIGHT - 1, text_size, cpu + 1);
191 267
192 fprintf(svgfile, "</g>\n"); 268 fprintf(svgfile, "</g>\n");
@@ -202,10 +278,10 @@ static char *time_to_string(u64 duration)
202 return text; 278 return text;
203 279
204 if (duration < 1000 * 1000) { /* less than 1 msec */ 280 if (duration < 1000 * 1000) { /* less than 1 msec */
205 sprintf(text, "%4.1f us", duration / 1000.0); 281 sprintf(text, "%.1f us", duration / 1000.0);
206 return text; 282 return text;
207 } 283 }
208 sprintf(text, "%4.1f ms", duration / 1000.0 / 1000); 284 sprintf(text, "%.1f ms", duration / 1000.0 / 1000);
209 285
210 return text; 286 return text;
211} 287}
@@ -233,14 +309,14 @@ void svg_waiting(int Yslot, int cpu, u64 start, u64 end, const char *backtrace)
233 309
234 font_size = round_text_size(font_size); 310 font_size = round_text_size(font_size);
235 311
236 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\">\n", time2pixels(start), Yslot * SLOT_MULT); 312 fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\">\n", time2pixels(start), Yslot * SLOT_MULT);
237 fprintf(svgfile, "<title>#%d waiting %s</title>\n", cpu, time_to_string(end - start)); 313 fprintf(svgfile, "<title>#%d waiting %s</title>\n", cpu, time_to_string(end - start));
238 if (backtrace) 314 if (backtrace)
239 fprintf(svgfile, "<desc>Waiting on:\n%s</desc>\n", backtrace); 315 fprintf(svgfile, "<desc>Waiting on:\n%s</desc>\n", backtrace);
240 fprintf(svgfile, "<rect x=\"0\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n", 316 fprintf(svgfile, "<rect x=\"0\" width=\"%.8f\" y=\"0\" height=\"%.1f\" class=\"%s\"/>\n",
241 time2pixels(end)-time2pixels(start), SLOT_HEIGHT, style); 317 time2pixels(end)-time2pixels(start), SLOT_HEIGHT, style);
242 if (font_size > MIN_TEXT_SIZE) 318 if (font_size > MIN_TEXT_SIZE)
243 fprintf(svgfile, "<text transform=\"rotate(90)\" font-size=\"%1.8fpt\"> %s</text>\n", 319 fprintf(svgfile, "<text transform=\"rotate(90)\" font-size=\"%.8fpt\"> %s</text>\n",
244 font_size, text); 320 font_size, text);
245 fprintf(svgfile, "</g>\n"); 321 fprintf(svgfile, "</g>\n");
246} 322}
@@ -289,16 +365,16 @@ void svg_cpu_box(int cpu, u64 __max_freq, u64 __turbo_freq)
289 365
290 fprintf(svgfile, "<g>\n"); 366 fprintf(svgfile, "<g>\n");
291 367
292 fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"cpu\"/>\n", 368 fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"cpu\"/>\n",
293 time2pixels(first_time), 369 time2pixels(first_time),
294 time2pixels(last_time)-time2pixels(first_time), 370 time2pixels(last_time)-time2pixels(first_time),
295 cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT); 371 cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT);
296 372
297 sprintf(cpu_string, "CPU %i", (int)cpu); 373 sprintf(cpu_string, "CPU %i", (int)cpu);
298 fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\">%s</text>\n", 374 fprintf(svgfile, "<text x=\"%.8f\" y=\"%.8f\">%s</text>\n",
299 10+time2pixels(first_time), cpu2y(cpu) + SLOT_HEIGHT/2, cpu_string); 375 10+time2pixels(first_time), cpu2y(cpu) + SLOT_HEIGHT/2, cpu_string);
300 376
301 fprintf(svgfile, "<text transform=\"translate(%4.8f,%4.8f)\" font-size=\"1.25pt\">%s</text>\n", 377 fprintf(svgfile, "<text transform=\"translate(%.8f,%.8f)\" font-size=\"1.25pt\">%s</text>\n",
302 10+time2pixels(first_time), cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - 4, cpu_model()); 378 10+time2pixels(first_time), cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - 4, cpu_model());
303 379
304 fprintf(svgfile, "</g>\n"); 380 fprintf(svgfile, "</g>\n");
@@ -319,11 +395,11 @@ void svg_process(int cpu, u64 start, u64 end, int pid, const char *name, const c
319 else 395 else
320 type = "sample"; 396 type = "sample";
321 397
322 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\">\n", time2pixels(start), cpu2y(cpu)); 398 fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\">\n", time2pixels(start), cpu2y(cpu));
323 fprintf(svgfile, "<title>%d %s running %s</title>\n", pid, name, time_to_string(end - start)); 399 fprintf(svgfile, "<title>%d %s running %s</title>\n", pid, name, time_to_string(end - start));
324 if (backtrace) 400 if (backtrace)
325 fprintf(svgfile, "<desc>Switched because:\n%s</desc>\n", backtrace); 401 fprintf(svgfile, "<desc>Switched because:\n%s</desc>\n", backtrace);
326 fprintf(svgfile, "<rect x=\"0\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n", 402 fprintf(svgfile, "<rect x=\"0\" width=\"%.8f\" y=\"0\" height=\"%.1f\" class=\"%s\"/>\n",
327 time2pixels(end)-time2pixels(start), SLOT_MULT+SLOT_HEIGHT, type); 403 time2pixels(end)-time2pixels(start), SLOT_MULT+SLOT_HEIGHT, type);
328 width = time2pixels(end)-time2pixels(start); 404 width = time2pixels(end)-time2pixels(start);
329 if (width > 6) 405 if (width > 6)
@@ -332,7 +408,7 @@ void svg_process(int cpu, u64 start, u64 end, int pid, const char *name, const c
332 width = round_text_size(width); 408 width = round_text_size(width);
333 409
334 if (width > MIN_TEXT_SIZE) 410 if (width > MIN_TEXT_SIZE)
335 fprintf(svgfile, "<text transform=\"rotate(90)\" font-size=\"%3.8fpt\">%s</text>\n", 411 fprintf(svgfile, "<text transform=\"rotate(90)\" font-size=\"%.8fpt\">%s</text>\n",
336 width, name); 412 width, name);
337 413
338 fprintf(svgfile, "</g>\n"); 414 fprintf(svgfile, "</g>\n");
@@ -353,7 +429,7 @@ void svg_cstate(int cpu, u64 start, u64 end, int type)
353 type = 6; 429 type = 6;
354 sprintf(style, "c%i", type); 430 sprintf(style, "c%i", type);
355 431
356 fprintf(svgfile, "<rect class=\"%s\" x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\"/>\n", 432 fprintf(svgfile, "<rect class=\"%s\" x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\"/>\n",
357 style, 433 style,
358 time2pixels(start), time2pixels(end)-time2pixels(start), 434 time2pixels(start), time2pixels(end)-time2pixels(start),
359 cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT); 435 cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT);
@@ -365,7 +441,7 @@ void svg_cstate(int cpu, u64 start, u64 end, int type)
365 width = round_text_size(width); 441 width = round_text_size(width);
366 442
367 if (width > MIN_TEXT_SIZE) 443 if (width > MIN_TEXT_SIZE)
368 fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\" font-size=\"%3.8fpt\">C%i</text>\n", 444 fprintf(svgfile, "<text x=\"%.8f\" y=\"%.8f\" font-size=\"%.8fpt\">C%i</text>\n",
369 time2pixels(start), cpu2y(cpu)+width, width, type); 445 time2pixels(start), cpu2y(cpu)+width, width, type);
370 446
371 fprintf(svgfile, "</g>\n"); 447 fprintf(svgfile, "</g>\n");
@@ -407,9 +483,9 @@ void svg_pstate(int cpu, u64 start, u64 end, u64 freq)
407 if (max_freq) 483 if (max_freq)
408 height = freq * 1.0 / max_freq * (SLOT_HEIGHT + SLOT_MULT); 484 height = freq * 1.0 / max_freq * (SLOT_HEIGHT + SLOT_MULT);
409 height = 1 + cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - height; 485 height = 1 + cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - height;
410 fprintf(svgfile, "<line x1=\"%4.8f\" x2=\"%4.8f\" y1=\"%4.1f\" y2=\"%4.1f\" class=\"pstate\"/>\n", 486 fprintf(svgfile, "<line x1=\"%.8f\" x2=\"%.8f\" y1=\"%.1f\" y2=\"%.1f\" class=\"pstate\"/>\n",
411 time2pixels(start), time2pixels(end), height, height); 487 time2pixels(start), time2pixels(end), height, height);
412 fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\" font-size=\"0.25pt\">%s</text>\n", 488 fprintf(svgfile, "<text x=\"%.8f\" y=\"%.8f\" font-size=\"0.25pt\">%s</text>\n",
413 time2pixels(start), height+0.9, HzToHuman(freq)); 489 time2pixels(start), height+0.9, HzToHuman(freq));
414 490
415 fprintf(svgfile, "</g>\n"); 491 fprintf(svgfile, "</g>\n");
@@ -435,32 +511,32 @@ void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc
435 511
436 if (row1 < row2) { 512 if (row1 < row2) {
437 if (row1) { 513 if (row1) {
438 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 514 fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
439 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/32); 515 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/32);
440 if (desc2) 516 if (desc2)
441 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &gt;</text></g>\n", 517 fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &gt;</text></g>\n",
442 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT + SLOT_HEIGHT/48, desc2); 518 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT + SLOT_HEIGHT/48, desc2);
443 } 519 }
444 if (row2) { 520 if (row2) {
445 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 521 fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
446 time2pixels(start), row2 * SLOT_MULT - SLOT_MULT/32, time2pixels(start), row2 * SLOT_MULT); 522 time2pixels(start), row2 * SLOT_MULT - SLOT_MULT/32, time2pixels(start), row2 * SLOT_MULT);
447 if (desc1) 523 if (desc1)
448 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &gt;</text></g>\n", 524 fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &gt;</text></g>\n",
449 time2pixels(start), row2 * SLOT_MULT - SLOT_MULT/32, desc1); 525 time2pixels(start), row2 * SLOT_MULT - SLOT_MULT/32, desc1);
450 } 526 }
451 } else { 527 } else {
452 if (row2) { 528 if (row2) {
453 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 529 fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
454 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/32); 530 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/32);
455 if (desc1) 531 if (desc1)
456 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &lt;</text></g>\n", 532 fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &lt;</text></g>\n",
457 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/48, desc1); 533 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/48, desc1);
458 } 534 }
459 if (row1) { 535 if (row1) {
460 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 536 fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
461 time2pixels(start), row1 * SLOT_MULT - SLOT_MULT/32, time2pixels(start), row1 * SLOT_MULT); 537 time2pixels(start), row1 * SLOT_MULT - SLOT_MULT/32, time2pixels(start), row1 * SLOT_MULT);
462 if (desc2) 538 if (desc2)
463 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &lt;</text></g>\n", 539 fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &lt;</text></g>\n",
464 time2pixels(start), row1 * SLOT_MULT - SLOT_HEIGHT/32, desc2); 540 time2pixels(start), row1 * SLOT_MULT - SLOT_HEIGHT/32, desc2);
465 } 541 }
466 } 542 }
@@ -468,7 +544,7 @@ void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc
468 if (row2 > row1) 544 if (row2 > row1)
469 height += SLOT_HEIGHT; 545 height += SLOT_HEIGHT;
470 if (row1) 546 if (row1)
471 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n", 547 fprintf(svgfile, "<circle cx=\"%.8f\" cy=\"%.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n",
472 time2pixels(start), height); 548 time2pixels(start), height);
473 549
474 fprintf(svgfile, "</g>\n"); 550 fprintf(svgfile, "</g>\n");
@@ -488,16 +564,16 @@ void svg_wakeline(u64 start, int row1, int row2, const char *backtrace)
488 fprintf(svgfile, "<desc>%s</desc>\n", backtrace); 564 fprintf(svgfile, "<desc>%s</desc>\n", backtrace);
489 565
490 if (row1 < row2) 566 if (row1 < row2)
491 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 567 fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
492 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT); 568 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT);
493 else 569 else
494 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 570 fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
495 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row1 * SLOT_MULT); 571 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row1 * SLOT_MULT);
496 572
497 height = row1 * SLOT_MULT; 573 height = row1 * SLOT_MULT;
498 if (row2 > row1) 574 if (row2 > row1)
499 height += SLOT_HEIGHT; 575 height += SLOT_HEIGHT;
500 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n", 576 fprintf(svgfile, "<circle cx=\"%.8f\" cy=\"%.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n",
501 time2pixels(start), height); 577 time2pixels(start), height);
502 578
503 fprintf(svgfile, "</g>\n"); 579 fprintf(svgfile, "</g>\n");
@@ -515,9 +591,9 @@ void svg_interrupt(u64 start, int row, const char *backtrace)
515 if (backtrace) 591 if (backtrace)
516 fprintf(svgfile, "<desc>%s</desc>\n", backtrace); 592 fprintf(svgfile, "<desc>%s</desc>\n", backtrace);
517 593
518 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n", 594 fprintf(svgfile, "<circle cx=\"%.8f\" cy=\"%.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n",
519 time2pixels(start), row * SLOT_MULT); 595 time2pixels(start), row * SLOT_MULT);
520 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n", 596 fprintf(svgfile, "<circle cx=\"%.8f\" cy=\"%.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n",
521 time2pixels(start), row * SLOT_MULT + SLOT_HEIGHT); 597 time2pixels(start), row * SLOT_MULT + SLOT_HEIGHT);
522 598
523 fprintf(svgfile, "</g>\n"); 599 fprintf(svgfile, "</g>\n");
@@ -528,7 +604,7 @@ void svg_text(int Yslot, u64 start, const char *text)
528 if (!svgfile) 604 if (!svgfile)
529 return; 605 return;
530 606
531 fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\">%s</text>\n", 607 fprintf(svgfile, "<text x=\"%.8f\" y=\"%.8f\">%s</text>\n",
532 time2pixels(start), Yslot * SLOT_MULT+SLOT_HEIGHT/2, text); 608 time2pixels(start), Yslot * SLOT_MULT+SLOT_HEIGHT/2, text);
533} 609}
534 610
@@ -537,12 +613,26 @@ static void svg_legenda_box(int X, const char *text, const char *style)
537 double boxsize; 613 double boxsize;
538 boxsize = SLOT_HEIGHT / 2; 614 boxsize = SLOT_HEIGHT / 2;
539 615
540 fprintf(svgfile, "<rect x=\"%i\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n", 616 fprintf(svgfile, "<rect x=\"%i\" width=\"%.8f\" y=\"0\" height=\"%.1f\" class=\"%s\"/>\n",
541 X, boxsize, boxsize, style); 617 X, boxsize, boxsize, style);
542 fprintf(svgfile, "<text transform=\"translate(%4.8f, %4.8f)\" font-size=\"%4.8fpt\">%s</text>\n", 618 fprintf(svgfile, "<text transform=\"translate(%.8f, %.8f)\" font-size=\"%.8fpt\">%s</text>\n",
543 X + boxsize + 5, boxsize, 0.8 * boxsize, text); 619 X + boxsize + 5, boxsize, 0.8 * boxsize, text);
544} 620}
545 621
622void svg_io_legenda(void)
623{
624 if (!svgfile)
625 return;
626
627 fprintf(svgfile, "<g>\n");
628 svg_legenda_box(0, "Disk", "disk");
629 svg_legenda_box(100, "Network", "net");
630 svg_legenda_box(200, "Sync", "sync");
631 svg_legenda_box(300, "Poll", "poll");
632 svg_legenda_box(400, "Error", "error");
633 fprintf(svgfile, "</g>\n");
634}
635
546void svg_legenda(void) 636void svg_legenda(void)
547{ 637{
548 if (!svgfile) 638 if (!svgfile)
@@ -559,7 +649,7 @@ void svg_legenda(void)
559 fprintf(svgfile, "</g>\n"); 649 fprintf(svgfile, "</g>\n");
560} 650}
561 651
562void svg_time_grid(void) 652void svg_time_grid(double min_thickness)
563{ 653{
564 u64 i; 654 u64 i;
565 655
@@ -579,8 +669,10 @@ void svg_time_grid(void)
579 color = 128; 669 color = 128;
580 } 670 }
581 671
582 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%" PRIu64 "\" style=\"stroke:rgb(%i,%i,%i);stroke-width:%1.3f\"/>\n", 672 if (thickness >= min_thickness)
583 time2pixels(i), SLOT_MULT/2, time2pixels(i), total_height, color, color, color, thickness); 673 fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%" PRIu64 "\" style=\"stroke:rgb(%i,%i,%i);stroke-width:%.3f\"/>\n",
674 time2pixels(i), SLOT_MULT/2, time2pixels(i),
675 total_height, color, color, color, thickness);
584 676
585 i += 10000000; 677 i += 10000000;
586 } 678 }
diff --git a/tools/perf/util/svghelper.h b/tools/perf/util/svghelper.h
index e3aff5332e30..9292a5291445 100644
--- a/tools/perf/util/svghelper.h
+++ b/tools/perf/util/svghelper.h
@@ -4,6 +4,9 @@
4#include <linux/types.h> 4#include <linux/types.h>
5 5
6extern void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end); 6extern void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end);
7extern void svg_ubox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges);
8extern void svg_lbox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges);
9extern void svg_fbox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges);
7extern void svg_box(int Yslot, u64 start, u64 end, const char *type); 10extern void svg_box(int Yslot, u64 start, u64 end, const char *type);
8extern void svg_blocked(int Yslot, int cpu, u64 start, u64 end, const char *backtrace); 11extern void svg_blocked(int Yslot, int cpu, u64 start, u64 end, const char *backtrace);
9extern void svg_running(int Yslot, int cpu, u64 start, u64 end, const char *backtrace); 12extern void svg_running(int Yslot, int cpu, u64 start, u64 end, const char *backtrace);
@@ -16,7 +19,8 @@ extern void svg_cstate(int cpu, u64 start, u64 end, int type);
16extern void svg_pstate(int cpu, u64 start, u64 end, u64 freq); 19extern void svg_pstate(int cpu, u64 start, u64 end, u64 freq);
17 20
18 21
19extern void svg_time_grid(void); 22extern void svg_time_grid(double min_thickness);
23extern void svg_io_legenda(void);
20extern void svg_legenda(void); 24extern void svg_legenda(void);
21extern void svg_wakeline(u64 start, int row1, int row2, const char *backtrace); 25extern void svg_wakeline(u64 start, int row1, int row2, const char *backtrace);
22extern void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2, const char *backtrace); 26extern void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2, const char *backtrace);
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 6864661a79dd..d75349979e65 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -49,7 +49,8 @@ static inline uint8_t elf_sym__type(const GElf_Sym *sym)
49 49
50static inline int elf_sym__is_function(const GElf_Sym *sym) 50static inline int elf_sym__is_function(const GElf_Sym *sym)
51{ 51{
52 return elf_sym__type(sym) == STT_FUNC && 52 return (elf_sym__type(sym) == STT_FUNC ||
53 elf_sym__type(sym) == STT_GNU_IFUNC) &&
53 sym->st_name != 0 && 54 sym->st_name != 0 &&
54 sym->st_shndx != SHN_UNDEF; 55 sym->st_shndx != SHN_UNDEF;
55} 56}
@@ -598,6 +599,8 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
598 goto out_elf_end; 599 goto out_elf_end;
599 } 600 }
600 601
602 ss->is_64_bit = (gelf_getclass(elf) == ELFCLASS64);
603
601 ss->symtab = elf_section_by_name(elf, &ehdr, &ss->symshdr, ".symtab", 604 ss->symtab = elf_section_by_name(elf, &ehdr, &ss->symshdr, ".symtab",
602 NULL); 605 NULL);
603 if (ss->symshdr.sh_type != SHT_SYMTAB) 606 if (ss->symshdr.sh_type != SHT_SYMTAB)
@@ -619,7 +622,7 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
619 GElf_Shdr shdr; 622 GElf_Shdr shdr;
620 ss->adjust_symbols = (ehdr.e_type == ET_EXEC || 623 ss->adjust_symbols = (ehdr.e_type == ET_EXEC ||
621 ehdr.e_type == ET_REL || 624 ehdr.e_type == ET_REL ||
622 is_vdso_map(dso->short_name) || 625 dso__is_vdso(dso) ||
623 elf_section_by_name(elf, &ehdr, &shdr, 626 elf_section_by_name(elf, &ehdr, &shdr,
624 ".gnu.prelink_undo", 627 ".gnu.prelink_undo",
625 NULL) != NULL); 628 NULL) != NULL);
@@ -698,6 +701,7 @@ int dso__load_sym(struct dso *dso, struct map *map,
698 bool remap_kernel = false, adjust_kernel_syms = false; 701 bool remap_kernel = false, adjust_kernel_syms = false;
699 702
700 dso->symtab_type = syms_ss->type; 703 dso->symtab_type = syms_ss->type;
704 dso->is_64_bit = syms_ss->is_64_bit;
701 dso->rel = syms_ss->ehdr.e_type == ET_REL; 705 dso->rel = syms_ss->ehdr.e_type == ET_REL;
702 706
703 /* 707 /*
@@ -1024,6 +1028,39 @@ int file__read_maps(int fd, bool exe, mapfn_t mapfn, void *data,
1024 return err; 1028 return err;
1025} 1029}
1026 1030
1031enum dso_type dso__type_fd(int fd)
1032{
1033 enum dso_type dso_type = DSO__TYPE_UNKNOWN;
1034 GElf_Ehdr ehdr;
1035 Elf_Kind ek;
1036 Elf *elf;
1037
1038 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
1039 if (elf == NULL)
1040 goto out;
1041
1042 ek = elf_kind(elf);
1043 if (ek != ELF_K_ELF)
1044 goto out_end;
1045
1046 if (gelf_getclass(elf) == ELFCLASS64) {
1047 dso_type = DSO__TYPE_64BIT;
1048 goto out_end;
1049 }
1050
1051 if (gelf_getehdr(elf, &ehdr) == NULL)
1052 goto out_end;
1053
1054 if (ehdr.e_machine == EM_X86_64)
1055 dso_type = DSO__TYPE_X32BIT;
1056 else
1057 dso_type = DSO__TYPE_32BIT;
1058out_end:
1059 elf_end(elf);
1060out:
1061 return dso_type;
1062}
1063
1027static int copy_bytes(int from, off_t from_offs, int to, off_t to_offs, u64 len) 1064static int copy_bytes(int from, off_t from_offs, int to, off_t to_offs, u64 len)
1028{ 1065{
1029 ssize_t r; 1066 ssize_t r;
diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c
index bd15f490d04f..c9541fea9514 100644
--- a/tools/perf/util/symbol-minimal.c
+++ b/tools/perf/util/symbol-minimal.c
@@ -288,6 +288,44 @@ int dso__synthesize_plt_symbols(struct dso *dso __maybe_unused,
288 return 0; 288 return 0;
289} 289}
290 290
291static int fd__is_64_bit(int fd)
292{
293 u8 e_ident[EI_NIDENT];
294
295 if (lseek(fd, 0, SEEK_SET))
296 return -1;
297
298 if (readn(fd, e_ident, sizeof(e_ident)) != sizeof(e_ident))
299 return -1;
300
301 if (memcmp(e_ident, ELFMAG, SELFMAG) ||
302 e_ident[EI_VERSION] != EV_CURRENT)
303 return -1;
304
305 return e_ident[EI_CLASS] == ELFCLASS64;
306}
307
308enum dso_type dso__type_fd(int fd)
309{
310 Elf64_Ehdr ehdr;
311 int ret;
312
313 ret = fd__is_64_bit(fd);
314 if (ret < 0)
315 return DSO__TYPE_UNKNOWN;
316
317 if (ret)
318 return DSO__TYPE_64BIT;
319
320 if (readn(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr))
321 return DSO__TYPE_UNKNOWN;
322
323 if (ehdr.e_machine == EM_X86_64)
324 return DSO__TYPE_X32BIT;
325
326 return DSO__TYPE_32BIT;
327}
328
291int dso__load_sym(struct dso *dso, struct map *map __maybe_unused, 329int dso__load_sym(struct dso *dso, struct map *map __maybe_unused,
292 struct symsrc *ss, 330 struct symsrc *ss,
293 struct symsrc *runtime_ss __maybe_unused, 331 struct symsrc *runtime_ss __maybe_unused,
@@ -295,6 +333,11 @@ int dso__load_sym(struct dso *dso, struct map *map __maybe_unused,
295 int kmodule __maybe_unused) 333 int kmodule __maybe_unused)
296{ 334{
297 unsigned char *build_id[BUILD_ID_SIZE]; 335 unsigned char *build_id[BUILD_ID_SIZE];
336 int ret;
337
338 ret = fd__is_64_bit(ss->fd);
339 if (ret >= 0)
340 dso->is_64_bit = ret;
298 341
299 if (filename__read_build_id(ss->name, build_id, BUILD_ID_SIZE) > 0) { 342 if (filename__read_build_id(ss->name, build_id, BUILD_ID_SIZE) > 0) {
300 dso__set_build_id(dso, build_id); 343 dso__set_build_id(dso, build_id);
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 7b9096f29cdb..eb06746b06b2 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -34,6 +34,7 @@ struct symbol_conf symbol_conf = {
34 .annotate_src = true, 34 .annotate_src = true,
35 .demangle = true, 35 .demangle = true,
36 .cumulate_callchain = true, 36 .cumulate_callchain = true,
37 .show_hist_headers = true,
37 .symfs = "", 38 .symfs = "",
38}; 39};
39 40
@@ -341,6 +342,16 @@ static struct symbol *symbols__first(struct rb_root *symbols)
341 return NULL; 342 return NULL;
342} 343}
343 344
345static struct symbol *symbols__next(struct symbol *sym)
346{
347 struct rb_node *n = rb_next(&sym->rb_node);
348
349 if (n)
350 return rb_entry(n, struct symbol, rb_node);
351
352 return NULL;
353}
354
344struct symbol_name_rb_node { 355struct symbol_name_rb_node {
345 struct rb_node rb_node; 356 struct rb_node rb_node;
346 struct symbol sym; 357 struct symbol sym;
@@ -411,11 +422,16 @@ struct symbol *dso__find_symbol(struct dso *dso,
411 return symbols__find(&dso->symbols[type], addr); 422 return symbols__find(&dso->symbols[type], addr);
412} 423}
413 424
414static struct symbol *dso__first_symbol(struct dso *dso, enum map_type type) 425struct symbol *dso__first_symbol(struct dso *dso, enum map_type type)
415{ 426{
416 return symbols__first(&dso->symbols[type]); 427 return symbols__first(&dso->symbols[type]);
417} 428}
418 429
430struct symbol *dso__next_symbol(struct symbol *sym)
431{
432 return symbols__next(sym);
433}
434
419struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, 435struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
420 const char *name) 436 const char *name)
421{ 437{
@@ -1064,6 +1080,7 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
1064 &is_64_bit); 1080 &is_64_bit);
1065 if (err) 1081 if (err)
1066 goto out_err; 1082 goto out_err;
1083 dso->is_64_bit = is_64_bit;
1067 1084
1068 if (list_empty(&md.maps)) { 1085 if (list_empty(&md.maps)) {
1069 err = -EINVAL; 1086 err = -EINVAL;
@@ -1662,6 +1679,7 @@ do_kallsyms:
1662 free(kallsyms_allocated_filename); 1679 free(kallsyms_allocated_filename);
1663 1680
1664 if (err > 0 && !dso__is_kcore(dso)) { 1681 if (err > 0 && !dso__is_kcore(dso)) {
1682 dso->binary_type = DSO_BINARY_TYPE__KALLSYMS;
1665 dso__set_long_name(dso, "[kernel.kallsyms]", false); 1683 dso__set_long_name(dso, "[kernel.kallsyms]", false);
1666 map__fixup_start(map); 1684 map__fixup_start(map);
1667 map__fixup_end(map); 1685 map__fixup_end(map);
@@ -1709,6 +1727,7 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
1709 if (err > 0) 1727 if (err > 0)
1710 pr_debug("Using %s for symbols\n", kallsyms_filename); 1728 pr_debug("Using %s for symbols\n", kallsyms_filename);
1711 if (err > 0 && !dso__is_kcore(dso)) { 1729 if (err > 0 && !dso__is_kcore(dso)) {
1730 dso->binary_type = DSO_BINARY_TYPE__GUEST_KALLSYMS;
1712 machine__mmap_name(machine, path, sizeof(path)); 1731 machine__mmap_name(machine, path, sizeof(path));
1713 dso__set_long_name(dso, strdup(path), true); 1732 dso__set_long_name(dso, strdup(path), true);
1714 map__fixup_start(map); 1733 map__fixup_start(map);
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 615c752dd767..e7295e93cff9 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -118,7 +118,8 @@ struct symbol_conf {
118 annotate_src, 118 annotate_src,
119 event_group, 119 event_group,
120 demangle, 120 demangle,
121 filter_relative; 121 filter_relative,
122 show_hist_headers;
122 const char *vmlinux_name, 123 const char *vmlinux_name,
123 *kallsyms_name, 124 *kallsyms_name,
124 *source_prefix, 125 *source_prefix,
@@ -215,6 +216,7 @@ struct symsrc {
215 GElf_Shdr dynshdr; 216 GElf_Shdr dynshdr;
216 217
217 bool adjust_symbols; 218 bool adjust_symbols;
219 bool is_64_bit;
218#endif 220#endif
219}; 221};
220 222
@@ -238,6 +240,11 @@ struct symbol *dso__find_symbol(struct dso *dso, enum map_type type,
238struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, 240struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
239 const char *name); 241 const char *name);
240 242
243struct symbol *dso__first_symbol(struct dso *dso, enum map_type type);
244struct symbol *dso__next_symbol(struct symbol *sym);
245
246enum dso_type dso__type_fd(int fd);
247
241int filename__read_build_id(const char *filename, void *bf, size_t size); 248int filename__read_build_id(const char *filename, void *bf, size_t size);
242int sysfs__read_build_id(const char *filename, void *bf, size_t size); 249int sysfs__read_build_id(const char *filename, void *bf, size_t size);
243int modules__parse(const char *filename, void *arg, 250int modules__parse(const char *filename, void *arg,
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 2fde0d5e40b5..12c7a253a63c 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -13,7 +13,7 @@ int thread__init_map_groups(struct thread *thread, struct machine *machine)
13 struct thread *leader; 13 struct thread *leader;
14 pid_t pid = thread->pid_; 14 pid_t pid = thread->pid_;
15 15
16 if (pid == thread->tid) { 16 if (pid == thread->tid || pid == -1) {
17 thread->mg = map_groups__new(); 17 thread->mg = map_groups__new();
18 } else { 18 } else {
19 leader = machine__findnew_thread(machine, pid, pid); 19 leader = machine__findnew_thread(machine, pid, pid);
@@ -34,6 +34,7 @@ struct thread *thread__new(pid_t pid, pid_t tid)
34 thread->pid_ = pid; 34 thread->pid_ = pid;
35 thread->tid = tid; 35 thread->tid = tid;
36 thread->ppid = -1; 36 thread->ppid = -1;
37 thread->cpu = -1;
37 INIT_LIST_HEAD(&thread->comm_list); 38 INIT_LIST_HEAD(&thread->comm_list);
38 39
39 comm_str = malloc(32); 40 comm_str = malloc(32);
@@ -60,8 +61,10 @@ void thread__delete(struct thread *thread)
60{ 61{
61 struct comm *comm, *tmp; 62 struct comm *comm, *tmp;
62 63
63 map_groups__put(thread->mg); 64 if (thread->mg) {
64 thread->mg = NULL; 65 map_groups__put(thread->mg);
66 thread->mg = NULL;
67 }
65 list_for_each_entry_safe(comm, tmp, &thread->comm_list, list) { 68 list_for_each_entry_safe(comm, tmp, &thread->comm_list, list) {
66 list_del(&comm->list); 69 list_del(&comm->list);
67 comm__free(comm); 70 comm__free(comm);
@@ -127,12 +130,12 @@ int thread__comm_len(struct thread *thread)
127size_t thread__fprintf(struct thread *thread, FILE *fp) 130size_t thread__fprintf(struct thread *thread, FILE *fp)
128{ 131{
129 return fprintf(fp, "Thread %d %s\n", thread->tid, thread__comm_str(thread)) + 132 return fprintf(fp, "Thread %d %s\n", thread->tid, thread__comm_str(thread)) +
130 map_groups__fprintf(thread->mg, verbose, fp); 133 map_groups__fprintf(thread->mg, fp);
131} 134}
132 135
133void thread__insert_map(struct thread *thread, struct map *map) 136void thread__insert_map(struct thread *thread, struct map *map)
134{ 137{
135 map_groups__fixup_overlappings(thread->mg, map, verbose, stderr); 138 map_groups__fixup_overlappings(thread->mg, map, stderr);
136 map_groups__insert(thread->mg, map); 139 map_groups__insert(thread->mg, map);
137} 140}
138 141
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 3c0c2724f82c..716b7723cce2 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -17,6 +17,7 @@ struct thread {
17 pid_t pid_; /* Not all tools update this */ 17 pid_t pid_; /* Not all tools update this */
18 pid_t tid; 18 pid_t tid;
19 pid_t ppid; 19 pid_t ppid;
20 int cpu;
20 char shortname[3]; 21 char shortname[3];
21 bool comm_set; 22 bool comm_set;
22 bool dead; /* if set thread has exited */ 23 bool dead; /* if set thread has exited */
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index 7e6fcfe8b438..eb72716017ac 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -40,6 +40,7 @@
40#include "trace-event.h" 40#include "trace-event.h"
41#include <api/fs/debugfs.h> 41#include <api/fs/debugfs.h>
42#include "evsel.h" 42#include "evsel.h"
43#include "debug.h"
43 44
44#define VERSION "0.5" 45#define VERSION "0.5"
45 46
@@ -191,12 +192,10 @@ static int copy_event_system(const char *sys, struct tracepoint_path *tps)
191 strcmp(dent->d_name, "..") == 0 || 192 strcmp(dent->d_name, "..") == 0 ||
192 !name_in_tp_list(dent->d_name, tps)) 193 !name_in_tp_list(dent->d_name, tps))
193 continue; 194 continue;
194 format = malloc(strlen(sys) + strlen(dent->d_name) + 10); 195 if (asprintf(&format, "%s/%s/format", sys, dent->d_name) < 0) {
195 if (!format) {
196 err = -ENOMEM; 196 err = -ENOMEM;
197 goto out; 197 goto out;
198 } 198 }
199 sprintf(format, "%s/%s/format", sys, dent->d_name);
200 ret = stat(format, &st); 199 ret = stat(format, &st);
201 free(format); 200 free(format);
202 if (ret < 0) 201 if (ret < 0)
@@ -217,12 +216,10 @@ static int copy_event_system(const char *sys, struct tracepoint_path *tps)
217 strcmp(dent->d_name, "..") == 0 || 216 strcmp(dent->d_name, "..") == 0 ||
218 !name_in_tp_list(dent->d_name, tps)) 217 !name_in_tp_list(dent->d_name, tps))
219 continue; 218 continue;
220 format = malloc(strlen(sys) + strlen(dent->d_name) + 10); 219 if (asprintf(&format, "%s/%s/format", sys, dent->d_name) < 0) {
221 if (!format) {
222 err = -ENOMEM; 220 err = -ENOMEM;
223 goto out; 221 goto out;
224 } 222 }
225 sprintf(format, "%s/%s/format", sys, dent->d_name);
226 ret = stat(format, &st); 223 ret = stat(format, &st);
227 224
228 if (ret >= 0) { 225 if (ret >= 0) {
@@ -317,12 +314,10 @@ static int record_event_files(struct tracepoint_path *tps)
317 strcmp(dent->d_name, "ftrace") == 0 || 314 strcmp(dent->d_name, "ftrace") == 0 ||
318 !system_in_tp_list(dent->d_name, tps)) 315 !system_in_tp_list(dent->d_name, tps))
319 continue; 316 continue;
320 sys = malloc(strlen(path) + strlen(dent->d_name) + 2); 317 if (asprintf(&sys, "%s/%s", path, dent->d_name) < 0) {
321 if (!sys) {
322 err = -ENOMEM; 318 err = -ENOMEM;
323 goto out; 319 goto out;
324 } 320 }
325 sprintf(sys, "%s/%s", path, dent->d_name);
326 ret = stat(sys, &st); 321 ret = stat(sys, &st);
327 if (ret >= 0) { 322 if (ret >= 0) {
328 ssize_t size = strlen(dent->d_name) + 1; 323 ssize_t size = strlen(dent->d_name) + 1;
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index e113e180c48f..54d9e9b548a8 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -22,7 +22,6 @@
22#include <stdio.h> 22#include <stdio.h>
23#include <stdlib.h> 23#include <stdlib.h>
24#include <string.h> 24#include <string.h>
25#include <getopt.h>
26#include <stdarg.h> 25#include <stdarg.h>
27#include <sys/types.h> 26#include <sys/types.h>
28#include <sys/stat.h> 27#include <sys/stat.h>
@@ -36,6 +35,7 @@
36#include "../perf.h" 35#include "../perf.h"
37#include "util.h" 36#include "util.h"
38#include "trace-event.h" 37#include "trace-event.h"
38#include "debug.h"
39 39
40static int input_fd; 40static int input_fd;
41 41
diff --git a/tools/perf/util/tsc.c b/tools/perf/util/tsc.c
new file mode 100644
index 000000000000..4d4210d4e13d
--- /dev/null
+++ b/tools/perf/util/tsc.c
@@ -0,0 +1,30 @@
1#include <linux/compiler.h>
2#include <linux/types.h>
3
4#include "tsc.h"
5
6u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc)
7{
8 u64 t, quot, rem;
9
10 t = ns - tc->time_zero;
11 quot = t / tc->time_mult;
12 rem = t % tc->time_mult;
13 return (quot << tc->time_shift) +
14 (rem << tc->time_shift) / tc->time_mult;
15}
16
17u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc)
18{
19 u64 quot, rem;
20
21 quot = cyc >> tc->time_shift;
22 rem = cyc & ((1 << tc->time_shift) - 1);
23 return tc->time_zero + quot * tc->time_mult +
24 ((rem * tc->time_mult) >> tc->time_shift);
25}
26
27u64 __weak rdtsc(void)
28{
29 return 0;
30}
diff --git a/tools/perf/util/tsc.h b/tools/perf/util/tsc.h
new file mode 100644
index 000000000000..a8b78f1b3243
--- /dev/null
+++ b/tools/perf/util/tsc.h
@@ -0,0 +1,12 @@
1#ifndef __PERF_TSC_H
2#define __PERF_TSC_H
3
4#include <linux/types.h>
5
6#include "../arch/x86/util/tsc.h"
7
8u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc);
9u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc);
10u64 rdtsc(void);
11
12#endif
diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
index 5ec80a575b50..7419768c38b1 100644
--- a/tools/perf/util/unwind-libdw.c
+++ b/tools/perf/util/unwind-libdw.c
@@ -3,6 +3,7 @@
3#include <elfutils/libdwfl.h> 3#include <elfutils/libdwfl.h>
4#include <inttypes.h> 4#include <inttypes.h>
5#include <errno.h> 5#include <errno.h>
6#include "debug.h"
6#include "unwind.h" 7#include "unwind.h"
7#include "unwind-libdw.h" 8#include "unwind-libdw.h"
8#include "machine.h" 9#include "machine.h"
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
index 25578b98f5c5..92b56db52471 100644
--- a/tools/perf/util/unwind-libunwind.c
+++ b/tools/perf/util/unwind-libunwind.c
@@ -30,6 +30,7 @@
30#include "unwind.h" 30#include "unwind.h"
31#include "symbol.h" 31#include "symbol.h"
32#include "util.h" 32#include "util.h"
33#include "debug.h"
33 34
34extern int 35extern int
35UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, 36UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 95aefa78bb07..e52e7461911b 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -1,5 +1,6 @@
1#include "../perf.h" 1#include "../perf.h"
2#include "util.h" 2#include "util.h"
3#include "debug.h"
3#include <api/fs/fs.h> 4#include <api/fs/fs.h>
4#include <sys/mman.h> 5#include <sys/mman.h>
5#ifdef HAVE_BACKTRACE_SUPPORT 6#ifdef HAVE_BACKTRACE_SUPPORT
@@ -333,12 +334,9 @@ const char *find_tracing_dir(void)
333 if (!debugfs) 334 if (!debugfs)
334 return NULL; 335 return NULL;
335 336
336 tracing = malloc(strlen(debugfs) + 9); 337 if (asprintf(&tracing, "%s/tracing", debugfs) < 0)
337 if (!tracing)
338 return NULL; 338 return NULL;
339 339
340 sprintf(tracing, "%s/tracing", debugfs);
341
342 tracing_found = 1; 340 tracing_found = 1;
343 return tracing; 341 return tracing;
344} 342}
@@ -352,11 +350,9 @@ char *get_tracing_file(const char *name)
352 if (!tracing) 350 if (!tracing)
353 return NULL; 351 return NULL;
354 352
355 file = malloc(strlen(tracing) + strlen(name) + 2); 353 if (asprintf(&file, "%s/%s", tracing, name) < 0)
356 if (!file)
357 return NULL; 354 return NULL;
358 355
359 sprintf(file, "%s/%s", tracing, name);
360 return file; 356 return file;
361} 357}
362 358
diff --git a/tools/perf/util/vdso.c b/tools/perf/util/vdso.c
index 0ddb3b8a89ec..adca69384fcc 100644
--- a/tools/perf/util/vdso.c
+++ b/tools/perf/util/vdso.c
@@ -11,10 +11,34 @@
11#include "vdso.h" 11#include "vdso.h"
12#include "util.h" 12#include "util.h"
13#include "symbol.h" 13#include "symbol.h"
14#include "machine.h"
14#include "linux/string.h" 15#include "linux/string.h"
16#include "debug.h"
15 17
16static bool vdso_found; 18#define VDSO__TEMP_FILE_NAME "/tmp/perf-vdso.so-XXXXXX"
17static char vdso_file[] = "/tmp/perf-vdso.so-XXXXXX"; 19
20struct vdso_file {
21 bool found;
22 bool error;
23 char temp_file_name[sizeof(VDSO__TEMP_FILE_NAME)];
24 const char *dso_name;
25};
26
27struct vdso_info {
28 struct vdso_file vdso;
29};
30
31static struct vdso_info *vdso_info__new(void)
32{
33 static const struct vdso_info vdso_info_init = {
34 .vdso = {
35 .temp_file_name = VDSO__TEMP_FILE_NAME,
36 .dso_name = DSO__NAME_VDSO,
37 },
38 };
39
40 return memdup(&vdso_info_init, sizeof(vdso_info_init));
41}
18 42
19static int find_vdso_map(void **start, void **end) 43static int find_vdso_map(void **start, void **end)
20{ 44{
@@ -47,7 +71,7 @@ static int find_vdso_map(void **start, void **end)
47 return !found; 71 return !found;
48} 72}
49 73
50static char *get_file(void) 74static char *get_file(struct vdso_file *vdso_file)
51{ 75{
52 char *vdso = NULL; 76 char *vdso = NULL;
53 char *buf = NULL; 77 char *buf = NULL;
@@ -55,10 +79,10 @@ static char *get_file(void)
55 size_t size; 79 size_t size;
56 int fd; 80 int fd;
57 81
58 if (vdso_found) 82 if (vdso_file->found)
59 return vdso_file; 83 return vdso_file->temp_file_name;
60 84
61 if (find_vdso_map(&start, &end)) 85 if (vdso_file->error || find_vdso_map(&start, &end))
62 return NULL; 86 return NULL;
63 87
64 size = end - start; 88 size = end - start;
@@ -67,45 +91,78 @@ static char *get_file(void)
67 if (!buf) 91 if (!buf)
68 return NULL; 92 return NULL;
69 93
70 fd = mkstemp(vdso_file); 94 fd = mkstemp(vdso_file->temp_file_name);
71 if (fd < 0) 95 if (fd < 0)
72 goto out; 96 goto out;
73 97
74 if (size == (size_t) write(fd, buf, size)) 98 if (size == (size_t) write(fd, buf, size))
75 vdso = vdso_file; 99 vdso = vdso_file->temp_file_name;
76 100
77 close(fd); 101 close(fd);
78 102
79 out: 103 out:
80 free(buf); 104 free(buf);
81 105
82 vdso_found = (vdso != NULL); 106 vdso_file->found = (vdso != NULL);
107 vdso_file->error = !vdso_file->found;
83 return vdso; 108 return vdso;
84} 109}
85 110
86void vdso__exit(void) 111void vdso__exit(struct machine *machine)
87{ 112{
88 if (vdso_found) 113 struct vdso_info *vdso_info = machine->vdso_info;
89 unlink(vdso_file); 114
115 if (!vdso_info)
116 return;
117
118 if (vdso_info->vdso.found)
119 unlink(vdso_info->vdso.temp_file_name);
120
121 zfree(&machine->vdso_info);
90} 122}
91 123
92struct dso *vdso__dso_findnew(struct list_head *head) 124static struct dso *vdso__new(struct machine *machine, const char *short_name,
125 const char *long_name)
93{ 126{
94 struct dso *dso = dsos__find(head, VDSO__MAP_NAME, true); 127 struct dso *dso;
95 128
129 dso = dso__new(short_name);
130 if (dso != NULL) {
131 dsos__add(&machine->user_dsos, dso);
132 dso__set_long_name(dso, long_name, false);
133 }
134
135 return dso;
136}
137
138struct dso *vdso__dso_findnew(struct machine *machine,
139 struct thread *thread __maybe_unused)
140{
141 struct vdso_info *vdso_info;
142 struct dso *dso;
143
144 if (!machine->vdso_info)
145 machine->vdso_info = vdso_info__new();
146
147 vdso_info = machine->vdso_info;
148 if (!vdso_info)
149 return NULL;
150
151 dso = dsos__find(&machine->user_dsos, DSO__NAME_VDSO, true);
96 if (!dso) { 152 if (!dso) {
97 char *file; 153 char *file;
98 154
99 file = get_file(); 155 file = get_file(&vdso_info->vdso);
100 if (!file) 156 if (!file)
101 return NULL; 157 return NULL;
102 158
103 dso = dso__new(VDSO__MAP_NAME); 159 dso = vdso__new(machine, DSO__NAME_VDSO, file);
104 if (dso != NULL) {
105 dsos__add(head, dso);
106 dso__set_long_name(dso, file, false);
107 }
108 } 160 }
109 161
110 return dso; 162 return dso;
111} 163}
164
165bool dso__is_vdso(struct dso *dso)
166{
167 return !strcmp(dso->short_name, DSO__NAME_VDSO);
168}
diff --git a/tools/perf/util/vdso.h b/tools/perf/util/vdso.h
index 0f76e7caf6f8..af9d6929a215 100644
--- a/tools/perf/util/vdso.h
+++ b/tools/perf/util/vdso.h
@@ -7,12 +7,21 @@
7 7
8#define VDSO__MAP_NAME "[vdso]" 8#define VDSO__MAP_NAME "[vdso]"
9 9
10#define DSO__NAME_VDSO "[vdso]"
11
10static inline bool is_vdso_map(const char *filename) 12static inline bool is_vdso_map(const char *filename)
11{ 13{
12 return !strcmp(filename, VDSO__MAP_NAME); 14 return !strcmp(filename, VDSO__MAP_NAME);
13} 15}
14 16
15struct dso *vdso__dso_findnew(struct list_head *head); 17struct dso;
16void vdso__exit(void); 18
19bool dso__is_vdso(struct dso *dso);
20
21struct machine;
22struct thread;
23
24struct dso *vdso__dso_findnew(struct machine *machine, struct thread *thread);
25void vdso__exit(struct machine *machine);
17 26
18#endif /* __PERF_VDSO__ */ 27#endif /* __PERF_VDSO__ */