aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/Documentation/build-xed.txt19
-rw-r--r--tools/perf/Documentation/intel-pt.txt2
-rw-r--r--tools/perf/Documentation/itrace.txt7
-rw-r--r--tools/perf/Documentation/perf-script.txt18
-rw-r--r--tools/perf/Documentation/perf-top.txt10
-rw-r--r--tools/perf/Documentation/perf-trace.txt67
-rw-r--r--tools/perf/Makefile.config2
-rw-r--r--tools/perf/Makefile.perf25
-rw-r--r--tools/perf/arch/arm64/annotate/instructions.c59
-rwxr-xr-xtools/perf/arch/arm64/entry/syscalls/mksyscalltbl2
-rw-r--r--tools/perf/arch/powerpc/util/book3s_hv_exits.h1
-rw-r--r--tools/perf/arch/s390/annotate/instructions.c2
-rw-r--r--tools/perf/arch/sparc/Makefile2
-rw-r--r--tools/perf/arch/sparc/annotate/instructions.c169
-rw-r--r--tools/perf/builtin-annotate.c7
-rw-r--r--tools/perf/builtin-inject.c40
-rw-r--r--tools/perf/builtin-record.c77
-rw-r--r--tools/perf/builtin-report.c12
-rw-r--r--tools/perf/builtin-script.c274
-rw-r--r--tools/perf/builtin-stat.c1487
-rw-r--r--tools/perf/builtin-top.c21
-rw-r--r--tools/perf/builtin-trace.c271
-rwxr-xr-xtools/perf/check-headers.sh2
-rw-r--r--tools/perf/command-list.txt1
-rw-r--r--tools/perf/examples/bpf/augmented_syscalls.c154
-rw-r--r--tools/perf/examples/bpf/etcsnoop.c80
-rw-r--r--tools/perf/include/bpf/bpf.h3
-rw-r--r--tools/perf/include/bpf/linux/socket.h24
-rw-r--r--tools/perf/perf.h1
-rw-r--r--tools/perf/pmu-events/arch/arm64/ampere/emag/branch.json23
-rw-r--r--tools/perf/pmu-events/arch/arm64/ampere/emag/bus.json26
-rw-r--r--tools/perf/pmu-events/arch/arm64/ampere/emag/cache.json191
-rw-r--r--tools/perf/pmu-events/arch/arm64/ampere/emag/clock.json20
-rw-r--r--tools/perf/pmu-events/arch/arm64/ampere/emag/core-imp-def.json32
-rw-r--r--tools/perf/pmu-events/arch/arm64/ampere/emag/exception.json50
-rw-r--r--tools/perf/pmu-events/arch/arm64/ampere/emag/instruction.json89
-rw-r--r--tools/perf/pmu-events/arch/arm64/ampere/emag/intrinsic.json14
-rw-r--r--tools/perf/pmu-events/arch/arm64/ampere/emag/memory.json29
-rw-r--r--tools/perf/pmu-events/arch/arm64/ampere/emag/pipeline.json50
-rw-r--r--tools/perf/pmu-events/arch/x86/ivytown/uncore-power.json16
-rw-r--r--tools/perf/pmu-events/arch/x86/jaketown/uncore-power.json16
-rw-r--r--tools/perf/scripts/python/call-graph-from-sql.py339
-rw-r--r--tools/perf/scripts/python/export-to-postgresql.py11
-rw-r--r--tools/perf/scripts/python/export-to-sqlite.py8
-rwxr-xr-xtools/perf/scripts/python/exported-sql-viewer.py2128
-rw-r--r--tools/perf/tests/Build1
-rw-r--r--tools/perf/tests/builtin-test.c10
-rw-r--r--tools/perf/tests/evsel-tp-sched.c4
-rwxr-xr-xtools/perf/tests/shell/record+probe_libc_inet_pton.sh2
-rw-r--r--tools/perf/tests/tests.h4
-rw-r--r--tools/perf/tests/wp.c241
-rw-r--r--tools/perf/trace/beauty/Build2
-rw-r--r--tools/perf/trace/beauty/beauty.h41
-rw-r--r--tools/perf/trace/beauty/clone.c3
-rwxr-xr-xtools/perf/trace/beauty/drm_ioctl.sh1
-rw-r--r--tools/perf/trace/beauty/eventfd.c2
-rw-r--r--tools/perf/trace/beauty/fcntl.c3
-rw-r--r--tools/perf/trace/beauty/flock.c2
-rw-r--r--tools/perf/trace/beauty/futex_op.c2
-rw-r--r--tools/perf/trace/beauty/futex_val3.c2
-rw-r--r--tools/perf/trace/beauty/ioctl.c3
-rw-r--r--tools/perf/trace/beauty/kcmp.c3
-rwxr-xr-xtools/perf/trace/beauty/kcmp_type.sh1
-rwxr-xr-xtools/perf/trace/beauty/kvm_ioctl.sh1
-rwxr-xr-xtools/perf/trace/beauty/madvise_behavior.sh1
-rw-r--r--tools/perf/trace/beauty/mmap.c50
-rwxr-xr-xtools/perf/trace/beauty/mmap_flags.sh32
-rw-r--r--tools/perf/trace/beauty/mode_t.c2
-rw-r--r--tools/perf/trace/beauty/mount_flags.c43
-rwxr-xr-xtools/perf/trace/beauty/mount_flags.sh15
-rw-r--r--tools/perf/trace/beauty/msg_flags.c2
-rw-r--r--tools/perf/trace/beauty/open_flags.c2
-rw-r--r--tools/perf/trace/beauty/perf_event_open.c2
-rwxr-xr-xtools/perf/trace/beauty/perf_ioctl.sh1
-rw-r--r--tools/perf/trace/beauty/pid.c3
-rw-r--r--tools/perf/trace/beauty/pkey_alloc.c30
-rwxr-xr-xtools/perf/trace/beauty/pkey_alloc_access_rights.sh1
-rw-r--r--tools/perf/trace/beauty/prctl.c3
-rwxr-xr-xtools/perf/trace/beauty/prctl_option.sh1
-rw-r--r--tools/perf/trace/beauty/sched_policy.c2
-rw-r--r--tools/perf/trace/beauty/seccomp.c2
-rw-r--r--tools/perf/trace/beauty/signum.c2
-rwxr-xr-xtools/perf/trace/beauty/sndrv_ctl_ioctl.sh1
-rwxr-xr-xtools/perf/trace/beauty/sndrv_pcm_ioctl.sh1
-rw-r--r--tools/perf/trace/beauty/sockaddr.c76
-rw-r--r--tools/perf/trace/beauty/socket.c2
-rwxr-xr-xtools/perf/trace/beauty/socket_ipproto.sh1
-rw-r--r--tools/perf/trace/beauty/socket_type.c2
-rw-r--r--tools/perf/trace/beauty/statx.c3
-rwxr-xr-xtools/perf/trace/beauty/vhost_virtio_ioctl.sh1
-rw-r--r--tools/perf/trace/beauty/waitid_options.c2
-rw-r--r--tools/perf/util/Build1
-rw-r--r--tools/perf/util/annotate.c8
-rw-r--r--tools/perf/util/auxtrace.c47
-rw-r--r--tools/perf/util/auxtrace.h46
-rw-r--r--tools/perf/util/bpf-loader.c2
-rw-r--r--tools/perf/util/cs-etm.c42
-rw-r--r--tools/perf/util/data-convert-bt.c58
-rw-r--r--tools/perf/util/db-export.c22
-rw-r--r--tools/perf/util/env.h1
-rw-r--r--tools/perf/util/event.c23
-rw-r--r--tools/perf/util/evlist.c2
-rw-r--r--tools/perf/util/evsel.c69
-rw-r--r--tools/perf/util/evsel.h16
-rw-r--r--tools/perf/util/evsel_fprintf.c2
-rw-r--r--tools/perf/util/genelf.h6
-rw-r--r--tools/perf/util/header.c47
-rw-r--r--tools/perf/util/header.h18
-rw-r--r--tools/perf/util/intel-bts.c20
-rw-r--r--tools/perf/util/intel-pt-decoder/intel-pt-decoder.c34
-rw-r--r--tools/perf/util/intel-pt-decoder/intel-pt-decoder.h2
-rw-r--r--tools/perf/util/intel-pt.c36
-rw-r--r--tools/perf/util/llvm-utils.c2
-rw-r--r--tools/perf/util/machine.c62
-rw-r--r--tools/perf/util/map.c15
-rw-r--r--tools/perf/util/mmap.c6
-rw-r--r--tools/perf/util/mmap.h17
-rw-r--r--tools/perf/util/ordered-events.c87
-rw-r--r--tools/perf/util/ordered-events.h37
-rw-r--r--tools/perf/util/parse-events.c8
-rw-r--r--tools/perf/util/parse-events.h1
-rw-r--r--tools/perf/util/parse-events.l1
-rw-r--r--tools/perf/util/pmu.c13
-rw-r--r--tools/perf/util/probe-event.c39
-rw-r--r--tools/perf/util/probe-event.h1
-rw-r--r--tools/perf/util/probe-file.c34
-rw-r--r--tools/perf/util/probe-file.h1
-rw-r--r--tools/perf/util/python.c20
-rw-r--r--tools/perf/util/s390-cpumsf.c94
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c66
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c100
-rw-r--r--tools/perf/util/session.c75
-rw-r--r--tools/perf/util/session.h5
-rw-r--r--tools/perf/util/setup.py18
-rw-r--r--tools/perf/util/sort.c22
-rw-r--r--tools/perf/util/srcline.c3
-rw-r--r--tools/perf/util/stat-display.c1166
-rw-r--r--tools/perf/util/stat-shadow.c147
-rw-r--r--tools/perf/util/stat.c100
-rw-r--r--tools/perf/util/stat.h77
-rw-r--r--tools/perf/util/strbuf.c10
-rw-r--r--tools/perf/util/symbol-elf.c58
-rw-r--r--tools/perf/util/symbol.h10
-rw-r--r--tools/perf/util/thread-stack.c95
-rw-r--r--tools/perf/util/thread-stack.h2
-rw-r--r--tools/perf/util/thread.c13
-rw-r--r--tools/perf/util/thread.h4
-rw-r--r--tools/perf/util/tool.h7
-rw-r--r--tools/perf/util/trace-event-info.c2
-rw-r--r--tools/perf/util/trace-event-parse.c44
-rw-r--r--tools/perf/util/trace-event-read.c15
-rw-r--r--tools/perf/util/trace-event.c8
-rw-r--r--tools/perf/util/trace-event.h21
-rw-r--r--tools/perf/util/unwind-libdw.c4
-rw-r--r--tools/perf/util/util.c2
-rw-r--r--tools/perf/util/util.h2
156 files changed, 6903 insertions, 2605 deletions
diff --git a/tools/perf/Documentation/build-xed.txt b/tools/perf/Documentation/build-xed.txt
new file mode 100644
index 000000000000..6222c1e7231f
--- /dev/null
+++ b/tools/perf/Documentation/build-xed.txt
@@ -0,0 +1,19 @@
1
2For --xed the xed tool is needed. Here is how to install it:
3
4 $ git clone https://github.com/intelxed/mbuild.git mbuild
5 $ git clone https://github.com/intelxed/xed
6 $ cd xed
7 $ ./mfile.py --share
8 $ ./mfile.py examples
9 $ sudo ./mfile.py --prefix=/usr/local install
10 $ sudo ldconfig
11 $ sudo cp obj/examples/xed /usr/local/bin
12
13Basic xed testing:
14
15 $ xed | head -3
16 ERROR: required argument(s) were missing
17 Copyright (C) 2017, Intel Corporation. All rights reserved.
18 XED version: [v10.0-328-g7d62c8c49b7b]
19 $
diff --git a/tools/perf/Documentation/intel-pt.txt b/tools/perf/Documentation/intel-pt.txt
index 76971d2e4164..115eaacc455f 100644
--- a/tools/perf/Documentation/intel-pt.txt
+++ b/tools/perf/Documentation/intel-pt.txt
@@ -106,7 +106,7 @@ in transaction, respectively.
106While it is possible to create scripts to analyze the data, an alternative 106While it is possible to create scripts to analyze the data, an alternative
107approach is available to export the data to a sqlite or postgresql database. 107approach is available to export the data to a sqlite or postgresql database.
108Refer to script export-to-sqlite.py or export-to-postgresql.py for more details, 108Refer to script export-to-sqlite.py or export-to-postgresql.py for more details,
109and to script call-graph-from-sql.py for an example of using the database. 109and to script exported-sql-viewer.py for an example of using the database.
110 110
111There is also script intel-pt-events.py which provides an example of how to 111There is also script intel-pt-events.py which provides an example of how to
112unpack the raw data for power events and PTWRITE. 112unpack the raw data for power events and PTWRITE.
diff --git a/tools/perf/Documentation/itrace.txt b/tools/perf/Documentation/itrace.txt
index a3abe04c779d..c2182cbabde3 100644
--- a/tools/perf/Documentation/itrace.txt
+++ b/tools/perf/Documentation/itrace.txt
@@ -11,10 +11,11 @@
11 l synthesize last branch entries (use with i or x) 11 l synthesize last branch entries (use with i or x)
12 s skip initial number of events 12 s skip initial number of events
13 13
14 The default is all events i.e. the same as --itrace=ibxwpe 14 The default is all events i.e. the same as --itrace=ibxwpe,
15 except for perf script where it is --itrace=ce
15 16
16 In addition, the period (default 100000) for instructions events 17 In addition, the period (default 100000, except for perf script where it is 1)
17 can be specified in units of: 18 for instructions events can be specified in units of:
18 19
19 i instructions 20 i instructions
20 t ticks 21 t ticks
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt
index afdafe2110a1..a2b37ce48094 100644
--- a/tools/perf/Documentation/perf-script.txt
+++ b/tools/perf/Documentation/perf-script.txt
@@ -383,6 +383,24 @@ include::itrace.txt[]
383 will be printed. Each entry has function name and file/line. Enabled by 383 will be printed. Each entry has function name and file/line. Enabled by
384 default, disable with --no-inline. 384 default, disable with --no-inline.
385 385
386--insn-trace::
387 Show instruction stream for intel_pt traces. Combine with --xed to
388 show disassembly.
389
390--xed::
391 Run xed disassembler on output. Requires installing the xed disassembler.
392
393--call-trace::
394 Show call stream for intel_pt traces. The CPUs are interleaved, but
395 can be filtered with -C.
396
397--call-ret-trace::
398 Show call and return stream for intel_pt traces.
399
400--graph-function::
401 For itrace only show specified functions and their callees for
402 itrace. Multiple functions can be separated by comma.
403
386SEE ALSO 404SEE ALSO
387-------- 405--------
388linkperf:perf-record[1], linkperf:perf-script-perl[1], 406linkperf:perf-record[1], linkperf:perf-script-perl[1],
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index 114fda12aa49..808b664343c9 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -242,6 +242,16 @@ Default is to monitor all CPUS.
242--hierarchy:: 242--hierarchy::
243 Enable hierarchy output. 243 Enable hierarchy output.
244 244
245--overwrite::
246 Enable this to use just the most recent records, which helps in high core count
247 machines such as Knights Landing/Mill, but right now is disabled by default as
248 the pausing used in this technique is leading to loss of metadata events such
249 as PERF_RECORD_MMAP which makes 'perf top' unable to resolve samples, leading
250 to lots of unknown samples appearing on the UI. Enable this if you are in such
251 machines and profiling a workload that doesn't creates short lived threads and/or
252 doesn't uses many executable mmap operations. Work is being planed to solve
253 this situation, till then, this will remain disabled by default.
254
245--force:: 255--force::
246 Don't do ownership validation. 256 Don't do ownership validation.
247 257
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt
index 115db9e06ecd..e113450503d2 100644
--- a/tools/perf/Documentation/perf-trace.txt
+++ b/tools/perf/Documentation/perf-trace.txt
@@ -171,6 +171,11 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs.
171--kernel-syscall-graph:: 171--kernel-syscall-graph::
172 Show the kernel callchains on the syscall exit path. 172 Show the kernel callchains on the syscall exit path.
173 173
174--max-events=N::
175 Stop after processing N events. Note that strace-like events are considered
176 only at exit time or when a syscall is interrupted, i.e. in those cases this
177 option is equivalent to the number of lines printed.
178
174--max-stack:: 179--max-stack::
175 Set the stack depth limit when parsing the callchain, anything 180 Set the stack depth limit when parsing the callchain, anything
176 beyond the specified depth will be ignored. Note that at this point 181 beyond the specified depth will be ignored. Note that at this point
@@ -238,6 +243,68 @@ Trace syscalls, major and minor pagefaults:
238 As you can see, there was major pagefault in python process, from 243 As you can see, there was major pagefault in python process, from
239 CRYPTO_push_info_ routine which faulted somewhere in libcrypto.so. 244 CRYPTO_push_info_ routine which faulted somewhere in libcrypto.so.
240 245
246Trace the first 4 open, openat or open_by_handle_at syscalls (in the future more syscalls may match here):
247
248 $ perf trace -e open* --max-events 4
249 [root@jouet perf]# trace -e open* --max-events 4
250 2272.992 ( 0.037 ms): gnome-shell/1370 openat(dfd: CWD, filename: /proc/self/stat) = 31
251 2277.481 ( 0.139 ms): gnome-shell/3039 openat(dfd: CWD, filename: /proc/self/stat) = 65
252 3026.398 ( 0.076 ms): gnome-shell/3039 openat(dfd: CWD, filename: /proc/self/stat) = 65
253 4294.665 ( 0.015 ms): sed/15879 openat(dfd: CWD, filename: /etc/ld.so.cache, flags: CLOEXEC) = 3
254 $
255
256Trace the first minor page fault when running a workload:
257
258 # perf trace -F min --max-stack=7 --max-events 1 sleep 1
259 0.000 ( 0.000 ms): sleep/18006 minfault [__clear_user+0x1a] => 0x5626efa56080 (?k)
260 __clear_user ([kernel.kallsyms])
261 load_elf_binary ([kernel.kallsyms])
262 search_binary_handler ([kernel.kallsyms])
263 __do_execve_file.isra.33 ([kernel.kallsyms])
264 __x64_sys_execve ([kernel.kallsyms])
265 do_syscall_64 ([kernel.kallsyms])
266 entry_SYSCALL_64 ([kernel.kallsyms])
267 #
268
269Trace the next min page page fault to take place on the first CPU:
270
271 # perf trace -F min --call-graph=dwarf --max-events 1 --cpu 0
272 0.000 ( 0.000 ms): Web Content/17136 minfault [js::gc::Chunk::fetchNextDecommittedArena+0x4b] => 0x7fbe6181b000 (?.)
273 js::gc::FreeSpan::initAsEmpty (inlined)
274 js::gc::Arena::setAsNotAllocated (inlined)
275 js::gc::Chunk::fetchNextDecommittedArena (/usr/lib64/firefox/libxul.so)
276 js::gc::Chunk::allocateArena (/usr/lib64/firefox/libxul.so)
277 js::gc::GCRuntime::allocateArena (/usr/lib64/firefox/libxul.so)
278 js::gc::ArenaLists::allocateFromArena (/usr/lib64/firefox/libxul.so)
279 js::gc::GCRuntime::tryNewTenuredThing<JSString, (js::AllowGC)1> (inlined)
280 js::AllocateString<JSString, (js::AllowGC)1> (/usr/lib64/firefox/libxul.so)
281 js::Allocate<JSThinInlineString, (js::AllowGC)1> (inlined)
282 JSThinInlineString::new_<(js::AllowGC)1> (inlined)
283 AllocateInlineString<(js::AllowGC)1, unsigned char> (inlined)
284 js::ConcatStrings<(js::AllowGC)1> (/usr/lib64/firefox/libxul.so)
285 [0x18b26e6bc2bd] (/tmp/perf-17136.map)
286 #
287
288Trace the next two sched:sched_switch events, four block:*_plug events, the
289next block:*_unplug and the next three net:*dev_queue events, this last one
290with a backtrace of at most 16 entries, system wide:
291
292 # perf trace -e sched:*switch/nr=2/,block:*_plug/nr=4/,block:*_unplug/nr=1/,net:*dev_queue/nr=3,max-stack=16/
293 0.000 :0/0 sched:sched_switch:swapper/2:0 [120] S ==> rcu_sched:10 [120]
294 0.015 rcu_sched/10 sched:sched_switch:rcu_sched:10 [120] R ==> swapper/2:0 [120]
295 254.198 irq/50-iwlwifi/680 net:net_dev_queue:dev=wlp3s0 skbaddr=0xffff93498051f600 len=66
296 __dev_queue_xmit ([kernel.kallsyms])
297 273.977 :0/0 net:net_dev_queue:dev=wlp3s0 skbaddr=0xffff93498051f600 len=78
298 __dev_queue_xmit ([kernel.kallsyms])
299 274.007 :0/0 net:net_dev_queue:dev=wlp3s0 skbaddr=0xffff93498051ff00 len=78
300 __dev_queue_xmit ([kernel.kallsyms])
301 2930.140 kworker/u16:58/2722 block:block_plug:[kworker/u16:58]
302 2930.162 kworker/u16:58/2722 block:block_unplug:[kworker/u16:58] 1
303 4466.094 jbd2/dm-2-8/748 block:block_plug:[jbd2/dm-2-8]
304 8050.123 kworker/u16:30/2694 block:block_plug:[kworker/u16:30]
305 8050.271 kworker/u16:30/2694 block:block_plug:[kworker/u16:30]
306 #
307
241SEE ALSO 308SEE ALSO
242-------- 309--------
243linkperf:perf-record[1], linkperf:perf-script[1] 310linkperf:perf-record[1], linkperf:perf-script[1]
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
index f6d1a03c7523..e30d20fb482d 100644
--- a/tools/perf/Makefile.config
+++ b/tools/perf/Makefile.config
@@ -833,7 +833,7 @@ ifndef NO_JVMTI
833 JDIR=$(shell /usr/sbin/update-java-alternatives -l | head -1 | awk '{print $$3}') 833 JDIR=$(shell /usr/sbin/update-java-alternatives -l | head -1 | awk '{print $$3}')
834 else 834 else
835 ifneq (,$(wildcard /usr/sbin/alternatives)) 835 ifneq (,$(wildcard /usr/sbin/alternatives))
836 JDIR=$(shell alternatives --display java | tail -1 | cut -d' ' -f 5 | sed 's%/jre/bin/java.%%g') 836 JDIR=$(shell /usr/sbin/alternatives --display java | tail -1 | cut -d' ' -f 5 | sed 's%/jre/bin/java.%%g')
837 endif 837 endif
838 endif 838 endif
839 ifndef JDIR 839 ifndef JDIR
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 5224ade3d5af..3ccb4f0bf088 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -1,4 +1,5 @@
1include ../scripts/Makefile.include 1include ../scripts/Makefile.include
2include ../scripts/Makefile.arch
2 3
3# The default target of this Makefile is... 4# The default target of this Makefile is...
4all: 5all:
@@ -385,6 +386,8 @@ export INSTALL SHELL_PATH
385SHELL = $(SHELL_PATH) 386SHELL = $(SHELL_PATH)
386 387
387linux_uapi_dir := $(srctree)/tools/include/uapi/linux 388linux_uapi_dir := $(srctree)/tools/include/uapi/linux
389asm_generic_uapi_dir := $(srctree)/tools/include/uapi/asm-generic
390arch_asm_uapi_dir := $(srctree)/tools/arch/$(ARCH)/include/uapi/asm/
388 391
389beauty_outdir := $(OUTPUT)trace/beauty/generated 392beauty_outdir := $(OUTPUT)trace/beauty/generated
390beauty_ioctl_outdir := $(beauty_outdir)/ioctl 393beauty_ioctl_outdir := $(beauty_outdir)/ioctl
@@ -460,6 +463,18 @@ madvise_behavior_tbl := $(srctree)/tools/perf/trace/beauty/madvise_behavior.sh
460$(madvise_behavior_array): $(madvise_hdr_dir)/mman-common.h $(madvise_behavior_tbl) 463$(madvise_behavior_array): $(madvise_hdr_dir)/mman-common.h $(madvise_behavior_tbl)
461 $(Q)$(SHELL) '$(madvise_behavior_tbl)' $(madvise_hdr_dir) > $@ 464 $(Q)$(SHELL) '$(madvise_behavior_tbl)' $(madvise_hdr_dir) > $@
462 465
466mmap_flags_array := $(beauty_outdir)/mmap_flags_array.c
467mmap_flags_tbl := $(srctree)/tools/perf/trace/beauty/mmap_flags.sh
468
469$(mmap_flags_array): $(asm_generic_uapi_dir)/mman.h $(asm_generic_uapi_dir)/mman-common.h $(arch_asm_uapi_dir)/mman.h $(mmap_flags_tbl)
470 $(Q)$(SHELL) '$(mmap_flags_tbl)' $(asm_generic_uapi_dir) $(arch_asm_uapi_dir) > $@
471
472mount_flags_array := $(beauty_outdir)/mount_flags_array.c
473mount_flags_tbl := $(srctree)/tools/perf/trace/beauty/mount_flags.sh
474
475$(mount_flags_array): $(linux_uapi_dir)/fs.h $(mount_flags_tbl)
476 $(Q)$(SHELL) '$(mount_flags_tbl)' $(linux_uapi_dir) > $@
477
463prctl_option_array := $(beauty_outdir)/prctl_option_array.c 478prctl_option_array := $(beauty_outdir)/prctl_option_array.c
464prctl_hdr_dir := $(srctree)/tools/include/uapi/linux/ 479prctl_hdr_dir := $(srctree)/tools/include/uapi/linux/
465prctl_option_tbl := $(srctree)/tools/perf/trace/beauty/prctl_option.sh 480prctl_option_tbl := $(srctree)/tools/perf/trace/beauty/prctl_option.sh
@@ -577,6 +592,8 @@ prepare: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h archheaders $(drm_ioc
577 $(socket_ipproto_array) \ 592 $(socket_ipproto_array) \
578 $(vhost_virtio_ioctl_array) \ 593 $(vhost_virtio_ioctl_array) \
579 $(madvise_behavior_array) \ 594 $(madvise_behavior_array) \
595 $(mmap_flags_array) \
596 $(mount_flags_array) \
580 $(perf_ioctl_array) \ 597 $(perf_ioctl_array) \
581 $(prctl_option_array) \ 598 $(prctl_option_array) \
582 $(arch_errno_name_array) 599 $(arch_errno_name_array)
@@ -635,7 +652,7 @@ $(LIBPERF_IN): prepare FORCE
635$(LIB_FILE): $(LIBPERF_IN) 652$(LIB_FILE): $(LIBPERF_IN)
636 $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIBPERF_IN) $(LIB_OBJS) 653 $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIBPERF_IN) $(LIB_OBJS)
637 654
638LIBTRACEEVENT_FLAGS += plugin_dir=$(plugindir_SQ) 655LIBTRACEEVENT_FLAGS += plugin_dir=$(plugindir_SQ) 'EXTRA_CFLAGS=$(EXTRA_CFLAGS)' 'LDFLAGS=$(LDFLAGS)'
639 656
640$(LIBTRACEEVENT): FORCE 657$(LIBTRACEEVENT): FORCE
641 $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) $(OUTPUT)libtraceevent.a 658 $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) $(OUTPUT)libtraceevent.a
@@ -779,7 +796,9 @@ endif
779ifndef NO_LIBBPF 796ifndef NO_LIBBPF
780 $(call QUIET_INSTALL, bpf-headers) \ 797 $(call QUIET_INSTALL, bpf-headers) \
781 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perf_include_instdir_SQ)/bpf'; \ 798 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perf_include_instdir_SQ)/bpf'; \
782 $(INSTALL) include/bpf/*.h -t '$(DESTDIR_SQ)$(perf_include_instdir_SQ)/bpf' 799 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perf_include_instdir_SQ)/bpf/linux'; \
800 $(INSTALL) include/bpf/*.h -t '$(DESTDIR_SQ)$(perf_include_instdir_SQ)/bpf'; \
801 $(INSTALL) include/bpf/linux/*.h -t '$(DESTDIR_SQ)$(perf_include_instdir_SQ)/bpf/linux'
783 $(call QUIET_INSTALL, bpf-examples) \ 802 $(call QUIET_INSTALL, bpf-examples) \
784 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perf_examples_instdir_SQ)/bpf'; \ 803 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perf_examples_instdir_SQ)/bpf'; \
785 $(INSTALL) examples/bpf/*.c -t '$(DESTDIR_SQ)$(perf_examples_instdir_SQ)/bpf' 804 $(INSTALL) examples/bpf/*.c -t '$(DESTDIR_SQ)$(perf_examples_instdir_SQ)/bpf'
@@ -861,6 +880,8 @@ clean:: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clea
861 $(OUTPUT)tests/llvm-src-{base,kbuild,prologue,relocation}.c \ 880 $(OUTPUT)tests/llvm-src-{base,kbuild,prologue,relocation}.c \
862 $(OUTPUT)pmu-events/pmu-events.c \ 881 $(OUTPUT)pmu-events/pmu-events.c \
863 $(OUTPUT)$(madvise_behavior_array) \ 882 $(OUTPUT)$(madvise_behavior_array) \
883 $(OUTPUT)$(mmap_flags_array) \
884 $(OUTPUT)$(mount_flags_array) \
864 $(OUTPUT)$(drm_ioctl_array) \ 885 $(OUTPUT)$(drm_ioctl_array) \
865 $(OUTPUT)$(pkey_alloc_access_rights_array) \ 886 $(OUTPUT)$(pkey_alloc_access_rights_array) \
866 $(OUTPUT)$(sndrv_ctl_ioctl_array) \ 887 $(OUTPUT)$(sndrv_ctl_ioctl_array) \
diff --git a/tools/perf/arch/arm64/annotate/instructions.c b/tools/perf/arch/arm64/annotate/instructions.c
index 6688977e4ac7..76c6345a57d5 100644
--- a/tools/perf/arch/arm64/annotate/instructions.c
+++ b/tools/perf/arch/arm64/annotate/instructions.c
@@ -8,6 +8,63 @@ struct arm64_annotate {
8 jump_insn; 8 jump_insn;
9}; 9};
10 10
11static int arm64_mov__parse(struct arch *arch __maybe_unused,
12 struct ins_operands *ops,
13 struct map_symbol *ms __maybe_unused)
14{
15 char *s = strchr(ops->raw, ','), *target, *endptr;
16
17 if (s == NULL)
18 return -1;
19
20 *s = '\0';
21 ops->source.raw = strdup(ops->raw);
22 *s = ',';
23
24 if (ops->source.raw == NULL)
25 return -1;
26
27 target = ++s;
28 ops->target.raw = strdup(target);
29 if (ops->target.raw == NULL)
30 goto out_free_source;
31
32 ops->target.addr = strtoull(target, &endptr, 16);
33 if (endptr == target)
34 goto out_free_target;
35
36 s = strchr(endptr, '<');
37 if (s == NULL)
38 goto out_free_target;
39 endptr = strchr(s + 1, '>');
40 if (endptr == NULL)
41 goto out_free_target;
42
43 *endptr = '\0';
44 *s = ' ';
45 ops->target.name = strdup(s);
46 *s = '<';
47 *endptr = '>';
48 if (ops->target.name == NULL)
49 goto out_free_target;
50
51 return 0;
52
53out_free_target:
54 zfree(&ops->target.raw);
55out_free_source:
56 zfree(&ops->source.raw);
57 return -1;
58}
59
60static int mov__scnprintf(struct ins *ins, char *bf, size_t size,
61 struct ins_operands *ops);
62
63static struct ins_ops arm64_mov_ops = {
64 .parse = arm64_mov__parse,
65 .scnprintf = mov__scnprintf,
66};
67
11static struct ins_ops *arm64__associate_instruction_ops(struct arch *arch, const char *name) 68static struct ins_ops *arm64__associate_instruction_ops(struct arch *arch, const char *name)
12{ 69{
13 struct arm64_annotate *arm = arch->priv; 70 struct arm64_annotate *arm = arch->priv;
@@ -21,7 +78,7 @@ static struct ins_ops *arm64__associate_instruction_ops(struct arch *arch, const
21 else if (!strcmp(name, "ret")) 78 else if (!strcmp(name, "ret"))
22 ops = &ret_ops; 79 ops = &ret_ops;
23 else 80 else
24 return NULL; 81 ops = &arm64_mov_ops;
25 82
26 arch__associate_ins_ops(arch, name, ops); 83 arch__associate_ins_ops(arch, name, ops);
27 return ops; 84 return ops;
diff --git a/tools/perf/arch/arm64/entry/syscalls/mksyscalltbl b/tools/perf/arch/arm64/entry/syscalls/mksyscalltbl
index 2dbb8cade048..c88fd32563eb 100755
--- a/tools/perf/arch/arm64/entry/syscalls/mksyscalltbl
+++ b/tools/perf/arch/arm64/entry/syscalls/mksyscalltbl
@@ -23,7 +23,7 @@ create_table_from_c()
23{ 23{
24 local sc nr last_sc 24 local sc nr last_sc
25 25
26 create_table_exe=`mktemp /tmp/create-table-XXXXXX` 26 create_table_exe=`mktemp ${TMPDIR:-/tmp}/create-table-XXXXXX`
27 27
28 { 28 {
29 29
diff --git a/tools/perf/arch/powerpc/util/book3s_hv_exits.h b/tools/perf/arch/powerpc/util/book3s_hv_exits.h
index 853b95d1e139..2011376c7ab5 100644
--- a/tools/perf/arch/powerpc/util/book3s_hv_exits.h
+++ b/tools/perf/arch/powerpc/util/book3s_hv_exits.h
@@ -15,7 +15,6 @@
15 {0x400, "INST_STORAGE"}, \ 15 {0x400, "INST_STORAGE"}, \
16 {0x480, "INST_SEGMENT"}, \ 16 {0x480, "INST_SEGMENT"}, \
17 {0x500, "EXTERNAL"}, \ 17 {0x500, "EXTERNAL"}, \
18 {0x501, "EXTERNAL_LEVEL"}, \
19 {0x502, "EXTERNAL_HV"}, \ 18 {0x502, "EXTERNAL_HV"}, \
20 {0x600, "ALIGNMENT"}, \ 19 {0x600, "ALIGNMENT"}, \
21 {0x700, "PROGRAM"}, \ 20 {0x700, "PROGRAM"}, \
diff --git a/tools/perf/arch/s390/annotate/instructions.c b/tools/perf/arch/s390/annotate/instructions.c
index cee4e2f7c057..de0dd66dbb48 100644
--- a/tools/perf/arch/s390/annotate/instructions.c
+++ b/tools/perf/arch/s390/annotate/instructions.c
@@ -100,8 +100,6 @@ out_free_source:
100 return -1; 100 return -1;
101} 101}
102 102
103static int mov__scnprintf(struct ins *ins, char *bf, size_t size,
104 struct ins_operands *ops);
105 103
106static struct ins_ops s390_mov_ops = { 104static struct ins_ops s390_mov_ops = {
107 .parse = s390_mov__parse, 105 .parse = s390_mov__parse,
diff --git a/tools/perf/arch/sparc/Makefile b/tools/perf/arch/sparc/Makefile
index 7fbca175099e..275dea7ff59a 100644
--- a/tools/perf/arch/sparc/Makefile
+++ b/tools/perf/arch/sparc/Makefile
@@ -1,3 +1,5 @@
1ifndef NO_DWARF 1ifndef NO_DWARF
2PERF_HAVE_DWARF_REGS := 1 2PERF_HAVE_DWARF_REGS := 1
3endif 3endif
4
5PERF_HAVE_JITDUMP := 1
diff --git a/tools/perf/arch/sparc/annotate/instructions.c b/tools/perf/arch/sparc/annotate/instructions.c
new file mode 100644
index 000000000000..2614c010c235
--- /dev/null
+++ b/tools/perf/arch/sparc/annotate/instructions.c
@@ -0,0 +1,169 @@
1// SPDX-License-Identifier: GPL-2.0
2
3static int is_branch_cond(const char *cond)
4{
5 if (cond[0] == '\0')
6 return 1;
7
8 if (cond[0] == 'a' && cond[1] == '\0')
9 return 1;
10
11 if (cond[0] == 'c' &&
12 (cond[1] == 'c' || cond[1] == 's') &&
13 cond[2] == '\0')
14 return 1;
15
16 if (cond[0] == 'e' &&
17 (cond[1] == '\0' ||
18 (cond[1] == 'q' && cond[2] == '\0')))
19 return 1;
20
21 if (cond[0] == 'g' &&
22 (cond[1] == '\0' ||
23 (cond[1] == 't' && cond[2] == '\0') ||
24 (cond[1] == 'e' && cond[2] == '\0') ||
25 (cond[1] == 'e' && cond[2] == 'u' && cond[3] == '\0')))
26 return 1;
27
28 if (cond[0] == 'l' &&
29 (cond[1] == '\0' ||
30 (cond[1] == 't' && cond[2] == '\0') ||
31 (cond[1] == 'u' && cond[2] == '\0') ||
32 (cond[1] == 'e' && cond[2] == '\0') ||
33 (cond[1] == 'e' && cond[2] == 'u' && cond[3] == '\0')))
34 return 1;
35
36 if (cond[0] == 'n' &&
37 (cond[1] == '\0' ||
38 (cond[1] == 'e' && cond[2] == '\0') ||
39 (cond[1] == 'z' && cond[2] == '\0') ||
40 (cond[1] == 'e' && cond[2] == 'g' && cond[3] == '\0')))
41 return 1;
42
43 if (cond[0] == 'b' &&
44 cond[1] == 'p' &&
45 cond[2] == 'o' &&
46 cond[3] == 's' &&
47 cond[4] == '\0')
48 return 1;
49
50 if (cond[0] == 'v' &&
51 (cond[1] == 'c' || cond[1] == 's') &&
52 cond[2] == '\0')
53 return 1;
54
55 if (cond[0] == 'b' &&
56 cond[1] == 'z' &&
57 cond[2] == '\0')
58 return 1;
59
60 return 0;
61}
62
63static int is_branch_reg_cond(const char *cond)
64{
65 if ((cond[0] == 'n' || cond[0] == 'l') &&
66 cond[1] == 'z' &&
67 cond[2] == '\0')
68 return 1;
69
70 if (cond[0] == 'z' &&
71 cond[1] == '\0')
72 return 1;
73
74 if ((cond[0] == 'g' || cond[0] == 'l') &&
75 cond[1] == 'e' &&
76 cond[2] == 'z' &&
77 cond[3] == '\0')
78 return 1;
79
80 if (cond[0] == 'g' &&
81 cond[1] == 'z' &&
82 cond[2] == '\0')
83 return 1;
84
85 return 0;
86}
87
88static int is_branch_float_cond(const char *cond)
89{
90 if (cond[0] == '\0')
91 return 1;
92
93 if ((cond[0] == 'a' || cond[0] == 'e' ||
94 cond[0] == 'z' || cond[0] == 'g' ||
95 cond[0] == 'l' || cond[0] == 'n' ||
96 cond[0] == 'o' || cond[0] == 'u') &&
97 cond[1] == '\0')
98 return 1;
99
100 if (((cond[0] == 'g' && cond[1] == 'e') ||
101 (cond[0] == 'l' && (cond[1] == 'e' ||
102 cond[1] == 'g')) ||
103 (cond[0] == 'n' && (cond[1] == 'e' ||
104 cond[1] == 'z')) ||
105 (cond[0] == 'u' && (cond[1] == 'e' ||
106 cond[1] == 'g' ||
107 cond[1] == 'l'))) &&
108 cond[2] == '\0')
109 return 1;
110
111 if (cond[0] == 'u' &&
112 (cond[1] == 'g' || cond[1] == 'l') &&
113 cond[2] == 'e' &&
114 cond[3] == '\0')
115 return 1;
116
117 return 0;
118}
119
120static struct ins_ops *sparc__associate_instruction_ops(struct arch *arch, const char *name)
121{
122 struct ins_ops *ops = NULL;
123
124 if (!strcmp(name, "call") ||
125 !strcmp(name, "jmp") ||
126 !strcmp(name, "jmpl")) {
127 ops = &call_ops;
128 } else if (!strcmp(name, "ret") ||
129 !strcmp(name, "retl") ||
130 !strcmp(name, "return")) {
131 ops = &ret_ops;
132 } else if (!strcmp(name, "mov")) {
133 ops = &mov_ops;
134 } else {
135 if (name[0] == 'c' &&
136 (name[1] == 'w' || name[1] == 'x'))
137 name += 2;
138
139 if (name[0] == 'b') {
140 const char *cond = name + 1;
141
142 if (cond[0] == 'r') {
143 if (is_branch_reg_cond(cond + 1))
144 ops = &jump_ops;
145 } else if (is_branch_cond(cond)) {
146 ops = &jump_ops;
147 }
148 } else if (name[0] == 'f' && name[1] == 'b') {
149 if (is_branch_float_cond(name + 2))
150 ops = &jump_ops;
151 }
152 }
153
154 if (ops)
155 arch__associate_ins_ops(arch, name, ops);
156
157 return ops;
158}
159
160static int sparc__annotate_init(struct arch *arch, char *cpuid __maybe_unused)
161{
162 if (!arch->initialized) {
163 arch->initialized = true;
164 arch->associate_instruction_ops = sparc__associate_instruction_ops;
165 arch->objdump.comment_char = '#';
166 }
167
168 return 0;
169}
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 830481b8db26..93d679eaf1f4 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -283,12 +283,11 @@ out_put:
283 return ret; 283 return ret;
284} 284}
285 285
286static int process_feature_event(struct perf_tool *tool, 286static int process_feature_event(struct perf_session *session,
287 union perf_event *event, 287 union perf_event *event)
288 struct perf_session *session)
289{ 288{
290 if (event->feat.feat_id < HEADER_LAST_FEATURE) 289 if (event->feat.feat_id < HEADER_LAST_FEATURE)
291 return perf_event__process_feature(tool, event, session); 290 return perf_event__process_feature(session, event);
292 return 0; 291 return 0;
293} 292}
294 293
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index a3b346359ba0..eda41673c4f3 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -86,12 +86,10 @@ static int perf_event__drop_oe(struct perf_tool *tool __maybe_unused,
86} 86}
87#endif 87#endif
88 88
89static int perf_event__repipe_op2_synth(struct perf_tool *tool, 89static int perf_event__repipe_op2_synth(struct perf_session *session,
90 union perf_event *event, 90 union perf_event *event)
91 struct perf_session *session
92 __maybe_unused)
93{ 91{
94 return perf_event__repipe_synth(tool, event); 92 return perf_event__repipe_synth(session->tool, event);
95} 93}
96 94
97static int perf_event__repipe_attr(struct perf_tool *tool, 95static int perf_event__repipe_attr(struct perf_tool *tool,
@@ -133,10 +131,10 @@ static int copy_bytes(struct perf_inject *inject, int fd, off_t size)
133 return 0; 131 return 0;
134} 132}
135 133
136static s64 perf_event__repipe_auxtrace(struct perf_tool *tool, 134static s64 perf_event__repipe_auxtrace(struct perf_session *session,
137 union perf_event *event, 135 union perf_event *event)
138 struct perf_session *session)
139{ 136{
137 struct perf_tool *tool = session->tool;
140 struct perf_inject *inject = container_of(tool, struct perf_inject, 138 struct perf_inject *inject = container_of(tool, struct perf_inject,
141 tool); 139 tool);
142 int ret; 140 int ret;
@@ -174,9 +172,8 @@ static s64 perf_event__repipe_auxtrace(struct perf_tool *tool,
174#else 172#else
175 173
176static s64 174static s64
177perf_event__repipe_auxtrace(struct perf_tool *tool __maybe_unused, 175perf_event__repipe_auxtrace(struct perf_session *session __maybe_unused,
178 union perf_event *event __maybe_unused, 176 union perf_event *event __maybe_unused)
179 struct perf_session *session __maybe_unused)
180{ 177{
181 pr_err("AUX area tracing not supported\n"); 178 pr_err("AUX area tracing not supported\n");
182 return -EINVAL; 179 return -EINVAL;
@@ -362,26 +359,24 @@ static int perf_event__repipe_exit(struct perf_tool *tool,
362 return err; 359 return err;
363} 360}
364 361
365static int perf_event__repipe_tracing_data(struct perf_tool *tool, 362static int perf_event__repipe_tracing_data(struct perf_session *session,
366 union perf_event *event, 363 union perf_event *event)
367 struct perf_session *session)
368{ 364{
369 int err; 365 int err;
370 366
371 perf_event__repipe_synth(tool, event); 367 perf_event__repipe_synth(session->tool, event);
372 err = perf_event__process_tracing_data(tool, event, session); 368 err = perf_event__process_tracing_data(session, event);
373 369
374 return err; 370 return err;
375} 371}
376 372
377static int perf_event__repipe_id_index(struct perf_tool *tool, 373static int perf_event__repipe_id_index(struct perf_session *session,
378 union perf_event *event, 374 union perf_event *event)
379 struct perf_session *session)
380{ 375{
381 int err; 376 int err;
382 377
383 perf_event__repipe_synth(tool, event); 378 perf_event__repipe_synth(session->tool, event);
384 err = perf_event__process_id_index(tool, event, session); 379 err = perf_event__process_id_index(session, event);
385 380
386 return err; 381 return err;
387} 382}
@@ -803,7 +798,8 @@ int cmd_inject(int argc, const char **argv)
803 "kallsyms pathname"), 798 "kallsyms pathname"),
804 OPT_BOOLEAN('f', "force", &data.force, "don't complain, do it"), 799 OPT_BOOLEAN('f', "force", &data.force, "don't complain, do it"),
805 OPT_CALLBACK_OPTARG(0, "itrace", &inject.itrace_synth_opts, 800 OPT_CALLBACK_OPTARG(0, "itrace", &inject.itrace_synth_opts,
806 NULL, "opts", "Instruction Tracing options", 801 NULL, "opts", "Instruction Tracing options\n"
802 ITRACE_HELP,
807 itrace_parse_synth_opts), 803 itrace_parse_synth_opts),
808 OPT_BOOLEAN(0, "strip", &inject.strip, 804 OPT_BOOLEAN(0, "strip", &inject.strip,
809 "strip non-synthesized events (use with --itrace)"), 805 "strip non-synthesized events (use with --itrace)"),
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 22ebeb92ac51..10cf889c6d75 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -106,9 +106,12 @@ static bool switch_output_time(struct record *rec)
106 trigger_is_ready(&switch_output_trigger); 106 trigger_is_ready(&switch_output_trigger);
107} 107}
108 108
109static int record__write(struct record *rec, void *bf, size_t size) 109static int record__write(struct record *rec, struct perf_mmap *map __maybe_unused,
110 void *bf, size_t size)
110{ 111{
111 if (perf_data__write(rec->session->data, bf, size) < 0) { 112 struct perf_data_file *file = &rec->session->data->file;
113
114 if (perf_data_file__write(file, bf, size) < 0) {
112 pr_err("failed to write perf data, error: %m\n"); 115 pr_err("failed to write perf data, error: %m\n");
113 return -1; 116 return -1;
114 } 117 }
@@ -127,15 +130,15 @@ static int process_synthesized_event(struct perf_tool *tool,
127 struct machine *machine __maybe_unused) 130 struct machine *machine __maybe_unused)
128{ 131{
129 struct record *rec = container_of(tool, struct record, tool); 132 struct record *rec = container_of(tool, struct record, tool);
130 return record__write(rec, event, event->header.size); 133 return record__write(rec, NULL, event, event->header.size);
131} 134}
132 135
133static int record__pushfn(void *to, void *bf, size_t size) 136static int record__pushfn(struct perf_mmap *map, void *to, void *bf, size_t size)
134{ 137{
135 struct record *rec = to; 138 struct record *rec = to;
136 139
137 rec->samples++; 140 rec->samples++;
138 return record__write(rec, bf, size); 141 return record__write(rec, map, bf, size);
139} 142}
140 143
141static volatile int done; 144static volatile int done;
@@ -170,6 +173,7 @@ static void record__sig_exit(void)
170#ifdef HAVE_AUXTRACE_SUPPORT 173#ifdef HAVE_AUXTRACE_SUPPORT
171 174
172static int record__process_auxtrace(struct perf_tool *tool, 175static int record__process_auxtrace(struct perf_tool *tool,
176 struct perf_mmap *map,
173 union perf_event *event, void *data1, 177 union perf_event *event, void *data1,
174 size_t len1, void *data2, size_t len2) 178 size_t len1, void *data2, size_t len2)
175{ 179{
@@ -197,21 +201,21 @@ static int record__process_auxtrace(struct perf_tool *tool,
197 if (padding) 201 if (padding)
198 padding = 8 - padding; 202 padding = 8 - padding;
199 203
200 record__write(rec, event, event->header.size); 204 record__write(rec, map, event, event->header.size);
201 record__write(rec, data1, len1); 205 record__write(rec, map, data1, len1);
202 if (len2) 206 if (len2)
203 record__write(rec, data2, len2); 207 record__write(rec, map, data2, len2);
204 record__write(rec, &pad, padding); 208 record__write(rec, map, &pad, padding);
205 209
206 return 0; 210 return 0;
207} 211}
208 212
209static int record__auxtrace_mmap_read(struct record *rec, 213static int record__auxtrace_mmap_read(struct record *rec,
210 struct auxtrace_mmap *mm) 214 struct perf_mmap *map)
211{ 215{
212 int ret; 216 int ret;
213 217
214 ret = auxtrace_mmap__read(mm, rec->itr, &rec->tool, 218 ret = auxtrace_mmap__read(map, rec->itr, &rec->tool,
215 record__process_auxtrace); 219 record__process_auxtrace);
216 if (ret < 0) 220 if (ret < 0)
217 return ret; 221 return ret;
@@ -223,11 +227,11 @@ static int record__auxtrace_mmap_read(struct record *rec,
223} 227}
224 228
225static int record__auxtrace_mmap_read_snapshot(struct record *rec, 229static int record__auxtrace_mmap_read_snapshot(struct record *rec,
226 struct auxtrace_mmap *mm) 230 struct perf_mmap *map)
227{ 231{
228 int ret; 232 int ret;
229 233
230 ret = auxtrace_mmap__read_snapshot(mm, rec->itr, &rec->tool, 234 ret = auxtrace_mmap__read_snapshot(map, rec->itr, &rec->tool,
231 record__process_auxtrace, 235 record__process_auxtrace,
232 rec->opts.auxtrace_snapshot_size); 236 rec->opts.auxtrace_snapshot_size);
233 if (ret < 0) 237 if (ret < 0)
@@ -245,13 +249,12 @@ static int record__auxtrace_read_snapshot_all(struct record *rec)
245 int rc = 0; 249 int rc = 0;
246 250
247 for (i = 0; i < rec->evlist->nr_mmaps; i++) { 251 for (i = 0; i < rec->evlist->nr_mmaps; i++) {
248 struct auxtrace_mmap *mm = 252 struct perf_mmap *map = &rec->evlist->mmap[i];
249 &rec->evlist->mmap[i].auxtrace_mmap;
250 253
251 if (!mm->base) 254 if (!map->auxtrace_mmap.base)
252 continue; 255 continue;
253 256
254 if (record__auxtrace_mmap_read_snapshot(rec, mm) != 0) { 257 if (record__auxtrace_mmap_read_snapshot(rec, map) != 0) {
255 rc = -1; 258 rc = -1;
256 goto out; 259 goto out;
257 } 260 }
@@ -295,7 +298,7 @@ static int record__auxtrace_init(struct record *rec)
295 298
296static inline 299static inline
297int record__auxtrace_mmap_read(struct record *rec __maybe_unused, 300int record__auxtrace_mmap_read(struct record *rec __maybe_unused,
298 struct auxtrace_mmap *mm __maybe_unused) 301 struct perf_mmap *map __maybe_unused)
299{ 302{
300 return 0; 303 return 0;
301} 304}
@@ -529,17 +532,17 @@ static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evli
529 return 0; 532 return 0;
530 533
531 for (i = 0; i < evlist->nr_mmaps; i++) { 534 for (i = 0; i < evlist->nr_mmaps; i++) {
532 struct auxtrace_mmap *mm = &maps[i].auxtrace_mmap; 535 struct perf_mmap *map = &maps[i];
533 536
534 if (maps[i].base) { 537 if (map->base) {
535 if (perf_mmap__push(&maps[i], rec, record__pushfn) != 0) { 538 if (perf_mmap__push(map, rec, record__pushfn) != 0) {
536 rc = -1; 539 rc = -1;
537 goto out; 540 goto out;
538 } 541 }
539 } 542 }
540 543
541 if (mm->base && !rec->opts.auxtrace_snapshot_mode && 544 if (map->auxtrace_mmap.base && !rec->opts.auxtrace_snapshot_mode &&
542 record__auxtrace_mmap_read(rec, mm) != 0) { 545 record__auxtrace_mmap_read(rec, map) != 0) {
543 rc = -1; 546 rc = -1;
544 goto out; 547 goto out;
545 } 548 }
@@ -550,7 +553,7 @@ static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evli
550 * at least one event. 553 * at least one event.
551 */ 554 */
552 if (bytes_written != rec->bytes_written) 555 if (bytes_written != rec->bytes_written)
553 rc = record__write(rec, &finished_round_event, sizeof(finished_round_event)); 556 rc = record__write(rec, NULL, &finished_round_event, sizeof(finished_round_event));
554 557
555 if (overwrite) 558 if (overwrite)
556 perf_evlist__toggle_bkw_mmap(evlist, BKW_MMAP_EMPTY); 559 perf_evlist__toggle_bkw_mmap(evlist, BKW_MMAP_EMPTY);
@@ -589,6 +592,9 @@ static void record__init_features(struct record *rec)
589 if (!rec->opts.full_auxtrace) 592 if (!rec->opts.full_auxtrace)
590 perf_header__clear_feat(&session->header, HEADER_AUXTRACE); 593 perf_header__clear_feat(&session->header, HEADER_AUXTRACE);
591 594
595 if (!(rec->opts.use_clockid && rec->opts.clockid_res_ns))
596 perf_header__clear_feat(&session->header, HEADER_CLOCKID);
597
592 perf_header__clear_feat(&session->header, HEADER_STAT); 598 perf_header__clear_feat(&session->header, HEADER_STAT);
593} 599}
594 600
@@ -758,7 +764,7 @@ static int record__synthesize(struct record *rec, bool tail)
758 * We need to synthesize events first, because some 764 * We need to synthesize events first, because some
759 * features works on top of them (on report side). 765 * features works on top of them (on report side).
760 */ 766 */
761 err = perf_event__synthesize_attrs(tool, session, 767 err = perf_event__synthesize_attrs(tool, rec->evlist,
762 process_synthesized_event); 768 process_synthesized_event);
763 if (err < 0) { 769 if (err < 0) {
764 pr_err("Couldn't synthesize attrs.\n"); 770 pr_err("Couldn't synthesize attrs.\n");
@@ -894,6 +900,9 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
894 900
895 record__init_features(rec); 901 record__init_features(rec);
896 902
903 if (rec->opts.use_clockid && rec->opts.clockid_res_ns)
904 session->header.env.clockid_res_ns = rec->opts.clockid_res_ns;
905
897 if (forks) { 906 if (forks) {
898 err = perf_evlist__prepare_workload(rec->evlist, &opts->target, 907 err = perf_evlist__prepare_workload(rec->evlist, &opts->target,
899 argv, data->is_pipe, 908 argv, data->is_pipe,
@@ -1334,6 +1343,19 @@ static const struct clockid_map clockids[] = {
1334 CLOCKID_END, 1343 CLOCKID_END,
1335}; 1344};
1336 1345
1346static int get_clockid_res(clockid_t clk_id, u64 *res_ns)
1347{
1348 struct timespec res;
1349
1350 *res_ns = 0;
1351 if (!clock_getres(clk_id, &res))
1352 *res_ns = res.tv_nsec + res.tv_sec * NSEC_PER_SEC;
1353 else
1354 pr_warning("WARNING: Failed to determine specified clock resolution.\n");
1355
1356 return 0;
1357}
1358
1337static int parse_clockid(const struct option *opt, const char *str, int unset) 1359static int parse_clockid(const struct option *opt, const char *str, int unset)
1338{ 1360{
1339 struct record_opts *opts = (struct record_opts *)opt->value; 1361 struct record_opts *opts = (struct record_opts *)opt->value;
@@ -1357,7 +1379,7 @@ static int parse_clockid(const struct option *opt, const char *str, int unset)
1357 1379
1358 /* if its a number, we're done */ 1380 /* if its a number, we're done */
1359 if (sscanf(str, "%d", &opts->clockid) == 1) 1381 if (sscanf(str, "%d", &opts->clockid) == 1)
1360 return 0; 1382 return get_clockid_res(opts->clockid, &opts->clockid_res_ns);
1361 1383
1362 /* allow a "CLOCK_" prefix to the name */ 1384 /* allow a "CLOCK_" prefix to the name */
1363 if (!strncasecmp(str, "CLOCK_", 6)) 1385 if (!strncasecmp(str, "CLOCK_", 6))
@@ -1366,7 +1388,8 @@ static int parse_clockid(const struct option *opt, const char *str, int unset)
1366 for (cm = clockids; cm->name; cm++) { 1388 for (cm = clockids; cm->name; cm++) {
1367 if (!strcasecmp(str, cm->name)) { 1389 if (!strcasecmp(str, cm->name)) {
1368 opts->clockid = cm->clockid; 1390 opts->clockid = cm->clockid;
1369 return 0; 1391 return get_clockid_res(opts->clockid,
1392 &opts->clockid_res_ns);
1370 } 1393 }
1371 } 1394 }
1372 1395
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 76e12bcd1765..257c9c18cb7e 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -201,14 +201,13 @@ static void setup_forced_leader(struct report *report,
201 perf_evlist__force_leader(evlist); 201 perf_evlist__force_leader(evlist);
202} 202}
203 203
204static int process_feature_event(struct perf_tool *tool, 204static int process_feature_event(struct perf_session *session,
205 union perf_event *event, 205 union perf_event *event)
206 struct perf_session *session __maybe_unused)
207{ 206{
208 struct report *rep = container_of(tool, struct report, tool); 207 struct report *rep = container_of(session->tool, struct report, tool);
209 208
210 if (event->feat.feat_id < HEADER_LAST_FEATURE) 209 if (event->feat.feat_id < HEADER_LAST_FEATURE)
211 return perf_event__process_feature(tool, event, session); 210 return perf_event__process_feature(session, event);
212 211
213 if (event->feat.feat_id != HEADER_LAST_FEATURE) { 212 if (event->feat.feat_id != HEADER_LAST_FEATURE) {
214 pr_err("failed: wrong feature ID: %" PRIu64 "\n", 213 pr_err("failed: wrong feature ID: %" PRIu64 "\n",
@@ -981,6 +980,7 @@ int cmd_report(int argc, const char **argv)
981 .id_index = perf_event__process_id_index, 980 .id_index = perf_event__process_id_index,
982 .auxtrace_info = perf_event__process_auxtrace_info, 981 .auxtrace_info = perf_event__process_auxtrace_info,
983 .auxtrace = perf_event__process_auxtrace, 982 .auxtrace = perf_event__process_auxtrace,
983 .event_update = perf_event__process_event_update,
984 .feature = process_feature_event, 984 .feature = process_feature_event,
985 .ordered_events = true, 985 .ordered_events = true,
986 .ordering_requires_timestamps = true, 986 .ordering_requires_timestamps = true,
@@ -1105,7 +1105,7 @@ int cmd_report(int argc, const char **argv)
1105 OPT_CALLBACK(0, "percentage", NULL, "relative|absolute", 1105 OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
1106 "how to display percentage of filtered entries", parse_filter_percentage), 1106 "how to display percentage of filtered entries", parse_filter_percentage),
1107 OPT_CALLBACK_OPTARG(0, "itrace", &itrace_synth_opts, NULL, "opts", 1107 OPT_CALLBACK_OPTARG(0, "itrace", &itrace_synth_opts, NULL, "opts",
1108 "Instruction Tracing options", 1108 "Instruction Tracing options\n" ITRACE_HELP,
1109 itrace_parse_synth_opts), 1109 itrace_parse_synth_opts),
1110 OPT_BOOLEAN(0, "full-source-path", &srcline_full_filename, 1110 OPT_BOOLEAN(0, "full-source-path", &srcline_full_filename,
1111 "Show full source file name path for source lines"), 1111 "Show full source file name path for source lines"),
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index ba481d73f910..b5bc85bd0bbe 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -44,6 +44,7 @@
44#include <sys/stat.h> 44#include <sys/stat.h>
45#include <fcntl.h> 45#include <fcntl.h>
46#include <unistd.h> 46#include <unistd.h>
47#include <subcmd/pager.h>
47 48
48#include "sane_ctype.h" 49#include "sane_ctype.h"
49 50
@@ -406,9 +407,10 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
406 PERF_OUTPUT_WEIGHT)) 407 PERF_OUTPUT_WEIGHT))
407 return -EINVAL; 408 return -EINVAL;
408 409
409 if (PRINT_FIELD(SYM) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) { 410 if (PRINT_FIELD(SYM) &&
411 !(evsel->attr.sample_type & (PERF_SAMPLE_IP|PERF_SAMPLE_ADDR))) {
410 pr_err("Display of symbols requested but neither sample IP nor " 412 pr_err("Display of symbols requested but neither sample IP nor "
411 "sample address\nis selected. Hence, no addresses to convert " 413 "sample address\navailable. Hence, no addresses to convert "
412 "to symbols.\n"); 414 "to symbols.\n");
413 return -EINVAL; 415 return -EINVAL;
414 } 416 }
@@ -417,10 +419,9 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
417 "selected.\n"); 419 "selected.\n");
418 return -EINVAL; 420 return -EINVAL;
419 } 421 }
420 if (PRINT_FIELD(DSO) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR) && 422 if (PRINT_FIELD(DSO) &&
421 !PRINT_FIELD(BRSTACK) && !PRINT_FIELD(BRSTACKSYM) && !PRINT_FIELD(BRSTACKOFF)) { 423 !(evsel->attr.sample_type & (PERF_SAMPLE_IP|PERF_SAMPLE_ADDR))) {
422 pr_err("Display of DSO requested but no address to convert. Select\n" 424 pr_err("Display of DSO requested but no address to convert.\n");
423 "sample IP, sample address, brstack, brstacksym, or brstackoff.\n");
424 return -EINVAL; 425 return -EINVAL;
425 } 426 }
426 if (PRINT_FIELD(SRCLINE) && !PRINT_FIELD(IP)) { 427 if (PRINT_FIELD(SRCLINE) && !PRINT_FIELD(IP)) {
@@ -912,7 +913,7 @@ static int grab_bb(u8 *buffer, u64 start, u64 end,
912 913
913static int ip__fprintf_jump(uint64_t ip, struct branch_entry *en, 914static int ip__fprintf_jump(uint64_t ip, struct branch_entry *en,
914 struct perf_insn *x, u8 *inbuf, int len, 915 struct perf_insn *x, u8 *inbuf, int len,
915 int insn, FILE *fp) 916 int insn, FILE *fp, int *total_cycles)
916{ 917{
917 int printed = fprintf(fp, "\t%016" PRIx64 "\t%-30s\t#%s%s%s%s", ip, 918 int printed = fprintf(fp, "\t%016" PRIx64 "\t%-30s\t#%s%s%s%s", ip,
918 dump_insn(x, ip, inbuf, len, NULL), 919 dump_insn(x, ip, inbuf, len, NULL),
@@ -921,7 +922,8 @@ static int ip__fprintf_jump(uint64_t ip, struct branch_entry *en,
921 en->flags.in_tx ? " INTX" : "", 922 en->flags.in_tx ? " INTX" : "",
922 en->flags.abort ? " ABORT" : ""); 923 en->flags.abort ? " ABORT" : "");
923 if (en->flags.cycles) { 924 if (en->flags.cycles) {
924 printed += fprintf(fp, " %d cycles", en->flags.cycles); 925 *total_cycles += en->flags.cycles;
926 printed += fprintf(fp, " %d cycles [%d]", en->flags.cycles, *total_cycles);
925 if (insn) 927 if (insn)
926 printed += fprintf(fp, " %.2f IPC", (float)insn / en->flags.cycles); 928 printed += fprintf(fp, " %.2f IPC", (float)insn / en->flags.cycles);
927 } 929 }
@@ -978,6 +980,7 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample,
978 u8 buffer[MAXBB]; 980 u8 buffer[MAXBB];
979 unsigned off; 981 unsigned off;
980 struct symbol *lastsym = NULL; 982 struct symbol *lastsym = NULL;
983 int total_cycles = 0;
981 984
982 if (!(br && br->nr)) 985 if (!(br && br->nr))
983 return 0; 986 return 0;
@@ -998,7 +1001,7 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample,
998 printed += ip__fprintf_sym(br->entries[nr - 1].from, thread, 1001 printed += ip__fprintf_sym(br->entries[nr - 1].from, thread,
999 x.cpumode, x.cpu, &lastsym, attr, fp); 1002 x.cpumode, x.cpu, &lastsym, attr, fp);
1000 printed += ip__fprintf_jump(br->entries[nr - 1].from, &br->entries[nr - 1], 1003 printed += ip__fprintf_jump(br->entries[nr - 1].from, &br->entries[nr - 1],
1001 &x, buffer, len, 0, fp); 1004 &x, buffer, len, 0, fp, &total_cycles);
1002 } 1005 }
1003 1006
1004 /* Print all blocks */ 1007 /* Print all blocks */
@@ -1026,7 +1029,8 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample,
1026 1029
1027 printed += ip__fprintf_sym(ip, thread, x.cpumode, x.cpu, &lastsym, attr, fp); 1030 printed += ip__fprintf_sym(ip, thread, x.cpumode, x.cpu, &lastsym, attr, fp);
1028 if (ip == end) { 1031 if (ip == end) {
1029 printed += ip__fprintf_jump(ip, &br->entries[i], &x, buffer + off, len - off, insn, fp); 1032 printed += ip__fprintf_jump(ip, &br->entries[i], &x, buffer + off, len - off, insn, fp,
1033 &total_cycles);
1030 break; 1034 break;
1031 } else { 1035 } else {
1032 printed += fprintf(fp, "\t%016" PRIx64 "\t%s\n", ip, 1036 printed += fprintf(fp, "\t%016" PRIx64 "\t%s\n", ip,
@@ -1104,6 +1108,35 @@ out:
1104 return printed; 1108 return printed;
1105} 1109}
1106 1110
1111static const char *resolve_branch_sym(struct perf_sample *sample,
1112 struct perf_evsel *evsel,
1113 struct thread *thread,
1114 struct addr_location *al,
1115 u64 *ip)
1116{
1117 struct addr_location addr_al;
1118 struct perf_event_attr *attr = &evsel->attr;
1119 const char *name = NULL;
1120
1121 if (sample->flags & (PERF_IP_FLAG_CALL | PERF_IP_FLAG_TRACE_BEGIN)) {
1122 if (sample_addr_correlates_sym(attr)) {
1123 thread__resolve(thread, &addr_al, sample);
1124 if (addr_al.sym)
1125 name = addr_al.sym->name;
1126 else
1127 *ip = sample->addr;
1128 } else {
1129 *ip = sample->addr;
1130 }
1131 } else if (sample->flags & (PERF_IP_FLAG_RETURN | PERF_IP_FLAG_TRACE_END)) {
1132 if (al->sym)
1133 name = al->sym->name;
1134 else
1135 *ip = sample->ip;
1136 }
1137 return name;
1138}
1139
1107static int perf_sample__fprintf_callindent(struct perf_sample *sample, 1140static int perf_sample__fprintf_callindent(struct perf_sample *sample,
1108 struct perf_evsel *evsel, 1141 struct perf_evsel *evsel,
1109 struct thread *thread, 1142 struct thread *thread,
@@ -1111,10 +1144,10 @@ static int perf_sample__fprintf_callindent(struct perf_sample *sample,
1111{ 1144{
1112 struct perf_event_attr *attr = &evsel->attr; 1145 struct perf_event_attr *attr = &evsel->attr;
1113 size_t depth = thread_stack__depth(thread); 1146 size_t depth = thread_stack__depth(thread);
1114 struct addr_location addr_al;
1115 const char *name = NULL; 1147 const char *name = NULL;
1116 static int spacing; 1148 static int spacing;
1117 int len = 0; 1149 int len = 0;
1150 int dlen = 0;
1118 u64 ip = 0; 1151 u64 ip = 0;
1119 1152
1120 /* 1153 /*
@@ -1124,21 +1157,12 @@ static int perf_sample__fprintf_callindent(struct perf_sample *sample,
1124 if (thread->ts && sample->flags & PERF_IP_FLAG_RETURN) 1157 if (thread->ts && sample->flags & PERF_IP_FLAG_RETURN)
1125 depth += 1; 1158 depth += 1;
1126 1159
1127 if (sample->flags & (PERF_IP_FLAG_CALL | PERF_IP_FLAG_TRACE_BEGIN)) { 1160 name = resolve_branch_sym(sample, evsel, thread, al, &ip);
1128 if (sample_addr_correlates_sym(attr)) { 1161
1129 thread__resolve(thread, &addr_al, sample); 1162 if (PRINT_FIELD(DSO) && !(PRINT_FIELD(IP) || PRINT_FIELD(ADDR))) {
1130 if (addr_al.sym) 1163 dlen += fprintf(fp, "(");
1131 name = addr_al.sym->name; 1164 dlen += map__fprintf_dsoname(al->map, fp);
1132 else 1165 dlen += fprintf(fp, ")\t");
1133 ip = sample->addr;
1134 } else {
1135 ip = sample->addr;
1136 }
1137 } else if (sample->flags & (PERF_IP_FLAG_RETURN | PERF_IP_FLAG_TRACE_END)) {
1138 if (al->sym)
1139 name = al->sym->name;
1140 else
1141 ip = sample->ip;
1142 } 1166 }
1143 1167
1144 if (name) 1168 if (name)
@@ -1159,7 +1183,7 @@ static int perf_sample__fprintf_callindent(struct perf_sample *sample,
1159 if (len < spacing) 1183 if (len < spacing)
1160 len += fprintf(fp, "%*s", spacing - len, ""); 1184 len += fprintf(fp, "%*s", spacing - len, "");
1161 1185
1162 return len; 1186 return len + dlen;
1163} 1187}
1164 1188
1165static int perf_sample__fprintf_insn(struct perf_sample *sample, 1189static int perf_sample__fprintf_insn(struct perf_sample *sample,
@@ -1255,6 +1279,18 @@ static struct {
1255 {0, NULL} 1279 {0, NULL}
1256}; 1280};
1257 1281
1282static const char *sample_flags_to_name(u32 flags)
1283{
1284 int i;
1285
1286 for (i = 0; sample_flags[i].name ; i++) {
1287 if (sample_flags[i].flags == flags)
1288 return sample_flags[i].name;
1289 }
1290
1291 return NULL;
1292}
1293
1258static int perf_sample__fprintf_flags(u32 flags, FILE *fp) 1294static int perf_sample__fprintf_flags(u32 flags, FILE *fp)
1259{ 1295{
1260 const char *chars = PERF_IP_FLAG_CHARS; 1296 const char *chars = PERF_IP_FLAG_CHARS;
@@ -1264,11 +1300,20 @@ static int perf_sample__fprintf_flags(u32 flags, FILE *fp)
1264 char str[33]; 1300 char str[33];
1265 int i, pos = 0; 1301 int i, pos = 0;
1266 1302
1267 for (i = 0; sample_flags[i].name ; i++) { 1303 name = sample_flags_to_name(flags & ~PERF_IP_FLAG_IN_TX);
1268 if (sample_flags[i].flags == (flags & ~PERF_IP_FLAG_IN_TX)) { 1304 if (name)
1269 name = sample_flags[i].name; 1305 return fprintf(fp, " %-15s%4s ", name, in_tx ? "(x)" : "");
1270 break; 1306
1271 } 1307 if (flags & PERF_IP_FLAG_TRACE_BEGIN) {
1308 name = sample_flags_to_name(flags & ~(PERF_IP_FLAG_IN_TX | PERF_IP_FLAG_TRACE_BEGIN));
1309 if (name)
1310 return fprintf(fp, " tr strt %-7s%4s ", name, in_tx ? "(x)" : "");
1311 }
1312
1313 if (flags & PERF_IP_FLAG_TRACE_END) {
1314 name = sample_flags_to_name(flags & ~(PERF_IP_FLAG_IN_TX | PERF_IP_FLAG_TRACE_END));
1315 if (name)
1316 return fprintf(fp, " tr end %-7s%4s ", name, in_tx ? "(x)" : "");
1272 } 1317 }
1273 1318
1274 for (i = 0; i < n; i++, flags >>= 1) { 1319 for (i = 0; i < n; i++, flags >>= 1) {
@@ -1281,10 +1326,7 @@ static int perf_sample__fprintf_flags(u32 flags, FILE *fp)
1281 } 1326 }
1282 str[pos] = 0; 1327 str[pos] = 0;
1283 1328
1284 if (name) 1329 return fprintf(fp, " %-19s ", str);
1285 return fprintf(fp, " %-7s%4s ", name, in_tx ? "(x)" : "");
1286
1287 return fprintf(fp, " %-11s ", str);
1288} 1330}
1289 1331
1290struct printer_data { 1332struct printer_data {
@@ -1544,7 +1586,8 @@ struct metric_ctx {
1544 FILE *fp; 1586 FILE *fp;
1545}; 1587};
1546 1588
1547static void script_print_metric(void *ctx, const char *color, 1589static void script_print_metric(struct perf_stat_config *config __maybe_unused,
1590 void *ctx, const char *color,
1548 const char *fmt, 1591 const char *fmt,
1549 const char *unit, double val) 1592 const char *unit, double val)
1550{ 1593{
@@ -1562,7 +1605,8 @@ static void script_print_metric(void *ctx, const char *color,
1562 fprintf(mctx->fp, " %s\n", unit); 1605 fprintf(mctx->fp, " %s\n", unit);
1563} 1606}
1564 1607
1565static void script_new_line(void *ctx) 1608static void script_new_line(struct perf_stat_config *config __maybe_unused,
1609 void *ctx)
1566{ 1610{
1567 struct metric_ctx *mctx = ctx; 1611 struct metric_ctx *mctx = ctx;
1568 1612
@@ -1608,7 +1652,7 @@ static void perf_sample__fprint_metric(struct perf_script *script,
1608 evsel_script(evsel)->val = val; 1652 evsel_script(evsel)->val = val;
1609 if (evsel_script(evsel->leader)->gnum == evsel->leader->nr_members) { 1653 if (evsel_script(evsel->leader)->gnum == evsel->leader->nr_members) {
1610 for_each_group_member (ev2, evsel->leader) { 1654 for_each_group_member (ev2, evsel->leader) {
1611 perf_stat__print_shadow_stats(ev2, 1655 perf_stat__print_shadow_stats(&stat_config, ev2,
1612 evsel_script(ev2)->val, 1656 evsel_script(ev2)->val,
1613 sample->cpu, 1657 sample->cpu,
1614 &ctx, 1658 &ctx,
@@ -1619,6 +1663,47 @@ static void perf_sample__fprint_metric(struct perf_script *script,
1619 } 1663 }
1620} 1664}
1621 1665
1666static bool show_event(struct perf_sample *sample,
1667 struct perf_evsel *evsel,
1668 struct thread *thread,
1669 struct addr_location *al)
1670{
1671 int depth = thread_stack__depth(thread);
1672
1673 if (!symbol_conf.graph_function)
1674 return true;
1675
1676 if (thread->filter) {
1677 if (depth <= thread->filter_entry_depth) {
1678 thread->filter = false;
1679 return false;
1680 }
1681 return true;
1682 } else {
1683 const char *s = symbol_conf.graph_function;
1684 u64 ip;
1685 const char *name = resolve_branch_sym(sample, evsel, thread, al,
1686 &ip);
1687 unsigned nlen;
1688
1689 if (!name)
1690 return false;
1691 nlen = strlen(name);
1692 while (*s) {
1693 unsigned len = strcspn(s, ",");
1694 if (nlen == len && !strncmp(name, s, len)) {
1695 thread->filter = true;
1696 thread->filter_entry_depth = depth;
1697 return true;
1698 }
1699 s += len;
1700 if (*s == ',')
1701 s++;
1702 }
1703 return false;
1704 }
1705}
1706
1622static void process_event(struct perf_script *script, 1707static void process_event(struct perf_script *script,
1623 struct perf_sample *sample, struct perf_evsel *evsel, 1708 struct perf_sample *sample, struct perf_evsel *evsel,
1624 struct addr_location *al, 1709 struct addr_location *al,
@@ -1633,6 +1718,9 @@ static void process_event(struct perf_script *script,
1633 if (output[type].fields == 0) 1718 if (output[type].fields == 0)
1634 return; 1719 return;
1635 1720
1721 if (!show_event(sample, evsel, thread, al))
1722 return;
1723
1636 ++es->samples; 1724 ++es->samples;
1637 1725
1638 perf_sample__fprintf_start(sample, thread, evsel, 1726 perf_sample__fprintf_start(sample, thread, evsel,
@@ -1710,6 +1798,9 @@ static void process_event(struct perf_script *script,
1710 1798
1711 if (PRINT_FIELD(METRIC)) 1799 if (PRINT_FIELD(METRIC))
1712 perf_sample__fprint_metric(script, thread, evsel, sample, fp); 1800 perf_sample__fprint_metric(script, thread, evsel, sample, fp);
1801
1802 if (verbose)
1803 fflush(fp);
1713} 1804}
1714 1805
1715static struct scripting_ops *scripting_ops; 1806static struct scripting_ops *scripting_ops;
@@ -2489,6 +2580,8 @@ parse:
2489 output[j].fields &= ~all_output_options[i].field; 2580 output[j].fields &= ~all_output_options[i].field;
2490 else 2581 else
2491 output[j].fields |= all_output_options[i].field; 2582 output[j].fields |= all_output_options[i].field;
2583 output[j].user_set = true;
2584 output[j].wildcard_set = true;
2492 } 2585 }
2493 } 2586 }
2494 } else { 2587 } else {
@@ -2499,7 +2592,8 @@ parse:
2499 rc = -EINVAL; 2592 rc = -EINVAL;
2500 goto out; 2593 goto out;
2501 } 2594 }
2502 output[type].fields |= all_output_options[i].field; 2595 output[type].user_set = true;
2596 output[type].wildcard_set = true;
2503 } 2597 }
2504 } 2598 }
2505 2599
@@ -2963,9 +3057,8 @@ static void script__setup_sample_type(struct perf_script *script)
2963 } 3057 }
2964} 3058}
2965 3059
2966static int process_stat_round_event(struct perf_tool *tool __maybe_unused, 3060static int process_stat_round_event(struct perf_session *session,
2967 union perf_event *event, 3061 union perf_event *event)
2968 struct perf_session *session)
2969{ 3062{
2970 struct stat_round_event *round = &event->stat_round; 3063 struct stat_round_event *round = &event->stat_round;
2971 struct perf_evsel *counter; 3064 struct perf_evsel *counter;
@@ -2979,9 +3072,8 @@ static int process_stat_round_event(struct perf_tool *tool __maybe_unused,
2979 return 0; 3072 return 0;
2980} 3073}
2981 3074
2982static int process_stat_config_event(struct perf_tool *tool __maybe_unused, 3075static int process_stat_config_event(struct perf_session *session __maybe_unused,
2983 union perf_event *event, 3076 union perf_event *event)
2984 struct perf_session *session __maybe_unused)
2985{ 3077{
2986 perf_event__read_stat_config(&stat_config, &event->stat_config); 3078 perf_event__read_stat_config(&stat_config, &event->stat_config);
2987 return 0; 3079 return 0;
@@ -3007,10 +3099,10 @@ static int set_maps(struct perf_script *script)
3007} 3099}
3008 3100
3009static 3101static
3010int process_thread_map_event(struct perf_tool *tool, 3102int process_thread_map_event(struct perf_session *session,
3011 union perf_event *event, 3103 union perf_event *event)
3012 struct perf_session *session __maybe_unused)
3013{ 3104{
3105 struct perf_tool *tool = session->tool;
3014 struct perf_script *script = container_of(tool, struct perf_script, tool); 3106 struct perf_script *script = container_of(tool, struct perf_script, tool);
3015 3107
3016 if (script->threads) { 3108 if (script->threads) {
@@ -3026,10 +3118,10 @@ int process_thread_map_event(struct perf_tool *tool,
3026} 3118}
3027 3119
3028static 3120static
3029int process_cpu_map_event(struct perf_tool *tool __maybe_unused, 3121int process_cpu_map_event(struct perf_session *session,
3030 union perf_event *event, 3122 union perf_event *event)
3031 struct perf_session *session __maybe_unused)
3032{ 3123{
3124 struct perf_tool *tool = session->tool;
3033 struct perf_script *script = container_of(tool, struct perf_script, tool); 3125 struct perf_script *script = container_of(tool, struct perf_script, tool);
3034 3126
3035 if (script->cpus) { 3127 if (script->cpus) {
@@ -3044,21 +3136,21 @@ int process_cpu_map_event(struct perf_tool *tool __maybe_unused,
3044 return set_maps(script); 3136 return set_maps(script);
3045} 3137}
3046 3138
3047static int process_feature_event(struct perf_tool *tool, 3139static int process_feature_event(struct perf_session *session,
3048 union perf_event *event, 3140 union perf_event *event)
3049 struct perf_session *session)
3050{ 3141{
3051 if (event->feat.feat_id < HEADER_LAST_FEATURE) 3142 if (event->feat.feat_id < HEADER_LAST_FEATURE)
3052 return perf_event__process_feature(tool, event, session); 3143 return perf_event__process_feature(session, event);
3053 return 0; 3144 return 0;
3054} 3145}
3055 3146
3056#ifdef HAVE_AUXTRACE_SUPPORT 3147#ifdef HAVE_AUXTRACE_SUPPORT
3057static int perf_script__process_auxtrace_info(struct perf_tool *tool, 3148static int perf_script__process_auxtrace_info(struct perf_session *session,
3058 union perf_event *event, 3149 union perf_event *event)
3059 struct perf_session *session)
3060{ 3150{
3061 int ret = perf_event__process_auxtrace_info(tool, event, session); 3151 struct perf_tool *tool = session->tool;
3152
3153 int ret = perf_event__process_auxtrace_info(session, event);
3062 3154
3063 if (ret == 0) { 3155 if (ret == 0) {
3064 struct perf_script *script = container_of(tool, struct perf_script, tool); 3156 struct perf_script *script = container_of(tool, struct perf_script, tool);
@@ -3072,6 +3164,44 @@ static int perf_script__process_auxtrace_info(struct perf_tool *tool,
3072#define perf_script__process_auxtrace_info 0 3164#define perf_script__process_auxtrace_info 0
3073#endif 3165#endif
3074 3166
3167static int parse_insn_trace(const struct option *opt __maybe_unused,
3168 const char *str __maybe_unused,
3169 int unset __maybe_unused)
3170{
3171 parse_output_fields(NULL, "+insn,-event,-period", 0);
3172 itrace_parse_synth_opts(opt, "i0ns", 0);
3173 nanosecs = true;
3174 return 0;
3175}
3176
3177static int parse_xed(const struct option *opt __maybe_unused,
3178 const char *str __maybe_unused,
3179 int unset __maybe_unused)
3180{
3181 force_pager("xed -F insn: -A -64 | less");
3182 return 0;
3183}
3184
3185static int parse_call_trace(const struct option *opt __maybe_unused,
3186 const char *str __maybe_unused,
3187 int unset __maybe_unused)
3188{
3189 parse_output_fields(NULL, "-ip,-addr,-event,-period,+callindent", 0);
3190 itrace_parse_synth_opts(opt, "cewp", 0);
3191 nanosecs = true;
3192 return 0;
3193}
3194
3195static int parse_callret_trace(const struct option *opt __maybe_unused,
3196 const char *str __maybe_unused,
3197 int unset __maybe_unused)
3198{
3199 parse_output_fields(NULL, "-ip,-addr,-event,-period,+callindent,+flags", 0);
3200 itrace_parse_synth_opts(opt, "crewp", 0);
3201 nanosecs = true;
3202 return 0;
3203}
3204
3075int cmd_script(int argc, const char **argv) 3205int cmd_script(int argc, const char **argv)
3076{ 3206{
3077 bool show_full_info = false; 3207 bool show_full_info = false;
@@ -3081,7 +3211,10 @@ int cmd_script(int argc, const char **argv)
3081 char *rec_script_path = NULL; 3211 char *rec_script_path = NULL;
3082 char *rep_script_path = NULL; 3212 char *rep_script_path = NULL;
3083 struct perf_session *session; 3213 struct perf_session *session;
3084 struct itrace_synth_opts itrace_synth_opts = { .set = false, }; 3214 struct itrace_synth_opts itrace_synth_opts = {
3215 .set = false,
3216 .default_no_sample = true,
3217 };
3085 char *script_path = NULL; 3218 char *script_path = NULL;
3086 const char **__argv; 3219 const char **__argv;
3087 int i, j, err = 0; 3220 int i, j, err = 0;
@@ -3156,6 +3289,16 @@ int cmd_script(int argc, const char **argv)
3156 "system-wide collection from all CPUs"), 3289 "system-wide collection from all CPUs"),
3157 OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", 3290 OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
3158 "only consider these symbols"), 3291 "only consider these symbols"),
3292 OPT_CALLBACK_OPTARG(0, "insn-trace", &itrace_synth_opts, NULL, NULL,
3293 "Decode instructions from itrace", parse_insn_trace),
3294 OPT_CALLBACK_OPTARG(0, "xed", NULL, NULL, NULL,
3295 "Run xed disassembler on output", parse_xed),
3296 OPT_CALLBACK_OPTARG(0, "call-trace", &itrace_synth_opts, NULL, NULL,
3297 "Decode calls from from itrace", parse_call_trace),
3298 OPT_CALLBACK_OPTARG(0, "call-ret-trace", &itrace_synth_opts, NULL, NULL,
3299 "Decode calls and returns from itrace", parse_callret_trace),
3300 OPT_STRING(0, "graph-function", &symbol_conf.graph_function, "symbol[,symbol...]",
3301 "Only print symbols and callees with --call-trace/--call-ret-trace"),
3159 OPT_STRING(0, "stop-bt", &symbol_conf.bt_stop_list_str, "symbol[,symbol...]", 3302 OPT_STRING(0, "stop-bt", &symbol_conf.bt_stop_list_str, "symbol[,symbol...]",
3160 "Stop display of callgraph at these symbols"), 3303 "Stop display of callgraph at these symbols"),
3161 OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"), 3304 OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"),
@@ -3193,7 +3336,7 @@ int cmd_script(int argc, const char **argv)
3193 OPT_BOOLEAN(0, "ns", &nanosecs, 3336 OPT_BOOLEAN(0, "ns", &nanosecs,
3194 "Use 9 decimal places when displaying time"), 3337 "Use 9 decimal places when displaying time"),
3195 OPT_CALLBACK_OPTARG(0, "itrace", &itrace_synth_opts, NULL, "opts", 3338 OPT_CALLBACK_OPTARG(0, "itrace", &itrace_synth_opts, NULL, "opts",
3196 "Instruction Tracing options", 3339 "Instruction Tracing options\n" ITRACE_HELP,
3197 itrace_parse_synth_opts), 3340 itrace_parse_synth_opts),
3198 OPT_BOOLEAN(0, "full-source-path", &srcline_full_filename, 3341 OPT_BOOLEAN(0, "full-source-path", &srcline_full_filename,
3199 "Show full source file name path for source lines"), 3342 "Show full source file name path for source lines"),
@@ -3389,8 +3532,10 @@ int cmd_script(int argc, const char **argv)
3389 exit(-1); 3532 exit(-1);
3390 } 3533 }
3391 3534
3392 if (!script_name) 3535 if (!script_name) {
3393 setup_pager(); 3536 setup_pager();
3537 use_browser = 0;
3538 }
3394 3539
3395 session = perf_session__new(&data, false, &script.tool); 3540 session = perf_session__new(&data, false, &script.tool);
3396 if (session == NULL) 3541 if (session == NULL)
@@ -3411,7 +3556,8 @@ int cmd_script(int argc, const char **argv)
3411 script.session = session; 3556 script.session = session;
3412 script__setup_sample_type(&script); 3557 script__setup_sample_type(&script);
3413 3558
3414 if (output[PERF_TYPE_HARDWARE].fields & PERF_OUTPUT_CALLINDENT) 3559 if ((output[PERF_TYPE_HARDWARE].fields & PERF_OUTPUT_CALLINDENT) ||
3560 symbol_conf.graph_function)
3415 itrace_synth_opts.thread_stack = true; 3561 itrace_synth_opts.thread_stack = true;
3416 3562
3417 session->itrace_synth_opts = &itrace_synth_opts; 3563 session->itrace_synth_opts = &itrace_synth_opts;
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index d097b5b47eb8..d1028d7755bb 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -88,8 +88,6 @@
88#include "sane_ctype.h" 88#include "sane_ctype.h"
89 89
90#define DEFAULT_SEPARATOR " " 90#define DEFAULT_SEPARATOR " "
91#define CNTR_NOT_SUPPORTED "<not supported>"
92#define CNTR_NOT_COUNTED "<not counted>"
93#define FREEZE_ON_SMI_PATH "devices/cpu/freeze_on_smi" 91#define FREEZE_ON_SMI_PATH "devices/cpu/freeze_on_smi"
94 92
95static void print_counters(struct timespec *ts, int argc, const char **argv); 93static void print_counters(struct timespec *ts, int argc, const char **argv);
@@ -137,54 +135,30 @@ static const char *smi_cost_attrs = {
137 135
138static struct perf_evlist *evsel_list; 136static struct perf_evlist *evsel_list;
139 137
140static struct rblist metric_events;
141
142static struct target target = { 138static struct target target = {
143 .uid = UINT_MAX, 139 .uid = UINT_MAX,
144}; 140};
145 141
146typedef int (*aggr_get_id_t)(struct cpu_map *m, int cpu);
147
148#define METRIC_ONLY_LEN 20 142#define METRIC_ONLY_LEN 20
149 143
150static int run_count = 1;
151static bool no_inherit = false;
152static volatile pid_t child_pid = -1; 144static volatile pid_t child_pid = -1;
153static bool null_run = false;
154static int detailed_run = 0; 145static int detailed_run = 0;
155static bool transaction_run; 146static bool transaction_run;
156static bool topdown_run = false; 147static bool topdown_run = false;
157static bool smi_cost = false; 148static bool smi_cost = false;
158static bool smi_reset = false; 149static bool smi_reset = false;
159static bool big_num = true;
160static int big_num_opt = -1; 150static int big_num_opt = -1;
161static const char *csv_sep = NULL;
162static bool csv_output = false;
163static bool group = false; 151static bool group = false;
164static const char *pre_cmd = NULL; 152static const char *pre_cmd = NULL;
165static const char *post_cmd = NULL; 153static const char *post_cmd = NULL;
166static bool sync_run = false; 154static bool sync_run = false;
167static unsigned int initial_delay = 0;
168static unsigned int unit_width = 4; /* strlen("unit") */
169static bool forever = false; 155static bool forever = false;
170static bool metric_only = false;
171static bool force_metric_only = false; 156static bool force_metric_only = false;
172static bool no_merge = false;
173static bool walltime_run_table = false;
174static struct timespec ref_time; 157static struct timespec ref_time;
175static struct cpu_map *aggr_map;
176static aggr_get_id_t aggr_get_id;
177static bool append_file; 158static bool append_file;
178static bool interval_count; 159static bool interval_count;
179static bool interval_clear;
180static const char *output_name; 160static const char *output_name;
181static int output_fd; 161static int output_fd;
182static int print_free_counters_hint;
183static int print_mixed_hw_group_error;
184static u64 *walltime_run;
185static bool ru_display = false;
186static struct rusage ru_data;
187static unsigned int metric_only_len = METRIC_ONLY_LEN;
188 162
189struct perf_stat { 163struct perf_stat {
190 bool record; 164 bool record;
@@ -204,15 +178,15 @@ static struct perf_stat perf_stat;
204static volatile int done = 0; 178static volatile int done = 0;
205 179
206static struct perf_stat_config stat_config = { 180static struct perf_stat_config stat_config = {
207 .aggr_mode = AGGR_GLOBAL, 181 .aggr_mode = AGGR_GLOBAL,
208 .scale = true, 182 .scale = true,
183 .unit_width = 4, /* strlen("unit") */
184 .run_count = 1,
185 .metric_only_len = METRIC_ONLY_LEN,
186 .walltime_nsecs_stats = &walltime_nsecs_stats,
187 .big_num = true,
209}; 188};
210 189
211static bool is_duration_time(struct perf_evsel *evsel)
212{
213 return !strcmp(evsel->name, "duration_time");
214}
215
216static inline void diff_timespec(struct timespec *r, struct timespec *a, 190static inline void diff_timespec(struct timespec *r, struct timespec *a,
217 struct timespec *b) 191 struct timespec *b)
218{ 192{
@@ -236,66 +210,6 @@ static void perf_stat__reset_stats(void)
236 perf_stat__reset_shadow_per_stat(&stat_config.stats[i]); 210 perf_stat__reset_shadow_per_stat(&stat_config.stats[i]);
237} 211}
238 212
239static int create_perf_stat_counter(struct perf_evsel *evsel)
240{
241 struct perf_event_attr *attr = &evsel->attr;
242 struct perf_evsel *leader = evsel->leader;
243
244 if (stat_config.scale) {
245 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
246 PERF_FORMAT_TOTAL_TIME_RUNNING;
247 }
248
249 /*
250 * The event is part of non trivial group, let's enable
251 * the group read (for leader) and ID retrieval for all
252 * members.
253 */
254 if (leader->nr_members > 1)
255 attr->read_format |= PERF_FORMAT_ID|PERF_FORMAT_GROUP;
256
257 attr->inherit = !no_inherit;
258
259 /*
260 * Some events get initialized with sample_(period/type) set,
261 * like tracepoints. Clear it up for counting.
262 */
263 attr->sample_period = 0;
264
265 /*
266 * But set sample_type to PERF_SAMPLE_IDENTIFIER, which should be harmless
267 * while avoiding that older tools show confusing messages.
268 *
269 * However for pipe sessions we need to keep it zero,
270 * because script's perf_evsel__check_attr is triggered
271 * by attr->sample_type != 0, and we can't run it on
272 * stat sessions.
273 */
274 if (!(STAT_RECORD && perf_stat.data.is_pipe))
275 attr->sample_type = PERF_SAMPLE_IDENTIFIER;
276
277 /*
278 * Disabling all counters initially, they will be enabled
279 * either manually by us or by kernel via enable_on_exec
280 * set later.
281 */
282 if (perf_evsel__is_group_leader(evsel)) {
283 attr->disabled = 1;
284
285 /*
286 * In case of initial_delay we enable tracee
287 * events manually.
288 */
289 if (target__none(&target) && !initial_delay)
290 attr->enable_on_exec = 1;
291 }
292
293 if (target__has_cpu(&target) && !target__has_per_thread(&target))
294 return perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel));
295
296 return perf_evsel__open_per_thread(evsel, evsel_list->threads);
297}
298
299static int process_synthesized_event(struct perf_tool *tool __maybe_unused, 213static int process_synthesized_event(struct perf_tool *tool __maybe_unused,
300 union perf_event *event, 214 union perf_event *event,
301 struct perf_sample *sample __maybe_unused, 215 struct perf_sample *sample __maybe_unused,
@@ -428,15 +342,15 @@ static void process_interval(void)
428 342
429static void enable_counters(void) 343static void enable_counters(void)
430{ 344{
431 if (initial_delay) 345 if (stat_config.initial_delay)
432 usleep(initial_delay * USEC_PER_MSEC); 346 usleep(stat_config.initial_delay * USEC_PER_MSEC);
433 347
434 /* 348 /*
435 * We need to enable counters only if: 349 * We need to enable counters only if:
436 * - we don't have tracee (attaching to task or cpu) 350 * - we don't have tracee (attaching to task or cpu)
437 * - we have initial delay configured 351 * - we have initial delay configured
438 */ 352 */
439 if (!target__none(&target) || initial_delay) 353 if (!target__none(&target) || stat_config.initial_delay)
440 perf_evlist__enable(evsel_list); 354 perf_evlist__enable(evsel_list);
441} 355}
442 356
@@ -464,80 +378,6 @@ static void workload_exec_failed_signal(int signo __maybe_unused, siginfo_t *inf
464 workload_exec_errno = info->si_value.sival_int; 378 workload_exec_errno = info->si_value.sival_int;
465} 379}
466 380
467static int perf_stat_synthesize_config(bool is_pipe)
468{
469 int err;
470
471 if (is_pipe) {
472 err = perf_event__synthesize_attrs(NULL, perf_stat.session,
473 process_synthesized_event);
474 if (err < 0) {
475 pr_err("Couldn't synthesize attrs.\n");
476 return err;
477 }
478 }
479
480 err = perf_event__synthesize_extra_attr(NULL,
481 evsel_list,
482 process_synthesized_event,
483 is_pipe);
484
485 err = perf_event__synthesize_thread_map2(NULL, evsel_list->threads,
486 process_synthesized_event,
487 NULL);
488 if (err < 0) {
489 pr_err("Couldn't synthesize thread map.\n");
490 return err;
491 }
492
493 err = perf_event__synthesize_cpu_map(NULL, evsel_list->cpus,
494 process_synthesized_event, NULL);
495 if (err < 0) {
496 pr_err("Couldn't synthesize thread map.\n");
497 return err;
498 }
499
500 err = perf_event__synthesize_stat_config(NULL, &stat_config,
501 process_synthesized_event, NULL);
502 if (err < 0) {
503 pr_err("Couldn't synthesize config.\n");
504 return err;
505 }
506
507 return 0;
508}
509
510#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
511
512static int __store_counter_ids(struct perf_evsel *counter)
513{
514 int cpu, thread;
515
516 for (cpu = 0; cpu < xyarray__max_x(counter->fd); cpu++) {
517 for (thread = 0; thread < xyarray__max_y(counter->fd);
518 thread++) {
519 int fd = FD(counter, cpu, thread);
520
521 if (perf_evlist__id_add_fd(evsel_list, counter,
522 cpu, thread, fd) < 0)
523 return -1;
524 }
525 }
526
527 return 0;
528}
529
530static int store_counter_ids(struct perf_evsel *counter)
531{
532 struct cpu_map *cpus = counter->cpus;
533 struct thread_map *threads = counter->threads;
534
535 if (perf_evsel__alloc_id(counter, cpus->nr, threads->nr))
536 return -ENOMEM;
537
538 return __store_counter_ids(counter);
539}
540
541static bool perf_evsel__should_store_id(struct perf_evsel *counter) 381static bool perf_evsel__should_store_id(struct perf_evsel *counter)
542{ 382{
543 return STAT_RECORD || counter->attr.read_format & PERF_FORMAT_ID; 383 return STAT_RECORD || counter->attr.read_format & PERF_FORMAT_ID;
@@ -569,6 +409,28 @@ static struct perf_evsel *perf_evsel__reset_weak_group(struct perf_evsel *evsel)
569 return leader; 409 return leader;
570} 410}
571 411
412static bool is_target_alive(struct target *_target,
413 struct thread_map *threads)
414{
415 struct stat st;
416 int i;
417
418 if (!target__has_task(_target))
419 return true;
420
421 for (i = 0; i < threads->nr; i++) {
422 char path[PATH_MAX];
423
424 scnprintf(path, PATH_MAX, "%s/%d", procfs__mountpoint(),
425 threads->map[i].pid);
426
427 if (!stat(path, &st))
428 return true;
429 }
430
431 return false;
432}
433
572static int __run_perf_stat(int argc, const char **argv, int run_idx) 434static int __run_perf_stat(int argc, const char **argv, int run_idx)
573{ 435{
574 int interval = stat_config.interval; 436 int interval = stat_config.interval;
@@ -609,7 +471,7 @@ static int __run_perf_stat(int argc, const char **argv, int run_idx)
609 471
610 evlist__for_each_entry(evsel_list, counter) { 472 evlist__for_each_entry(evsel_list, counter) {
611try_again: 473try_again:
612 if (create_perf_stat_counter(counter) < 0) { 474 if (create_perf_stat_counter(counter, &stat_config, &target) < 0) {
613 475
614 /* Weak group failed. Reset the group. */ 476 /* Weak group failed. Reset the group. */
615 if ((errno == EINVAL || errno == EBADF) && 477 if ((errno == EINVAL || errno == EBADF) &&
@@ -664,11 +526,11 @@ try_again:
664 counter->supported = true; 526 counter->supported = true;
665 527
666 l = strlen(counter->unit); 528 l = strlen(counter->unit);
667 if (l > unit_width) 529 if (l > stat_config.unit_width)
668 unit_width = l; 530 stat_config.unit_width = l;
669 531
670 if (perf_evsel__should_store_id(counter) && 532 if (perf_evsel__should_store_id(counter) &&
671 store_counter_ids(counter)) 533 perf_evsel__store_ids(counter, evsel_list))
672 return -1; 534 return -1;
673 } 535 }
674 536
@@ -699,7 +561,8 @@ try_again:
699 if (err < 0) 561 if (err < 0)
700 return err; 562 return err;
701 563
702 err = perf_stat_synthesize_config(is_pipe); 564 err = perf_stat_synthesize_config(&stat_config, NULL, evsel_list,
565 process_synthesized_event, is_pipe);
703 if (err < 0) 566 if (err < 0)
704 return err; 567 return err;
705 } 568 }
@@ -724,7 +587,7 @@ try_again:
724 break; 587 break;
725 } 588 }
726 } 589 }
727 wait4(child_pid, &status, 0, &ru_data); 590 wait4(child_pid, &status, 0, &stat_config.ru_data);
728 591
729 if (workload_exec_errno) { 592 if (workload_exec_errno) {
730 const char *emsg = str_error_r(workload_exec_errno, msg, sizeof(msg)); 593 const char *emsg = str_error_r(workload_exec_errno, msg, sizeof(msg));
@@ -738,6 +601,8 @@ try_again:
738 enable_counters(); 601 enable_counters();
739 while (!done) { 602 while (!done) {
740 nanosleep(&ts, NULL); 603 nanosleep(&ts, NULL);
604 if (!is_target_alive(&target, evsel_list->threads))
605 break;
741 if (timeout) 606 if (timeout)
742 break; 607 break;
743 if (interval) { 608 if (interval) {
@@ -752,8 +617,8 @@ try_again:
752 617
753 t1 = rdclock(); 618 t1 = rdclock();
754 619
755 if (walltime_run_table) 620 if (stat_config.walltime_run_table)
756 walltime_run[run_idx] = t1 - t0; 621 stat_config.walltime_run[run_idx] = t1 - t0;
757 622
758 update_stats(&walltime_nsecs_stats, t1 - t0); 623 update_stats(&walltime_nsecs_stats, t1 - t0);
759 624
@@ -795,1105 +660,14 @@ static int run_perf_stat(int argc, const char **argv, int run_idx)
795 return ret; 660 return ret;
796} 661}
797 662
798static void print_running(u64 run, u64 ena)
799{
800 if (csv_output) {
801 fprintf(stat_config.output, "%s%" PRIu64 "%s%.2f",
802 csv_sep,
803 run,
804 csv_sep,
805 ena ? 100.0 * run / ena : 100.0);
806 } else if (run != ena) {
807 fprintf(stat_config.output, " (%.2f%%)", 100.0 * run / ena);
808 }
809}
810
811static void print_noise_pct(double total, double avg)
812{
813 double pct = rel_stddev_stats(total, avg);
814
815 if (csv_output)
816 fprintf(stat_config.output, "%s%.2f%%", csv_sep, pct);
817 else if (pct)
818 fprintf(stat_config.output, " ( +-%6.2f%% )", pct);
819}
820
821static void print_noise(struct perf_evsel *evsel, double avg)
822{
823 struct perf_stat_evsel *ps;
824
825 if (run_count == 1)
826 return;
827
828 ps = evsel->stats;
829 print_noise_pct(stddev_stats(&ps->res_stats[0]), avg);
830}
831
832static void aggr_printout(struct perf_evsel *evsel, int id, int nr)
833{
834 switch (stat_config.aggr_mode) {
835 case AGGR_CORE:
836 fprintf(stat_config.output, "S%d-C%*d%s%*d%s",
837 cpu_map__id_to_socket(id),
838 csv_output ? 0 : -8,
839 cpu_map__id_to_cpu(id),
840 csv_sep,
841 csv_output ? 0 : 4,
842 nr,
843 csv_sep);
844 break;
845 case AGGR_SOCKET:
846 fprintf(stat_config.output, "S%*d%s%*d%s",
847 csv_output ? 0 : -5,
848 id,
849 csv_sep,
850 csv_output ? 0 : 4,
851 nr,
852 csv_sep);
853 break;
854 case AGGR_NONE:
855 fprintf(stat_config.output, "CPU%*d%s",
856 csv_output ? 0 : -4,
857 perf_evsel__cpus(evsel)->map[id], csv_sep);
858 break;
859 case AGGR_THREAD:
860 fprintf(stat_config.output, "%*s-%*d%s",
861 csv_output ? 0 : 16,
862 thread_map__comm(evsel->threads, id),
863 csv_output ? 0 : -8,
864 thread_map__pid(evsel->threads, id),
865 csv_sep);
866 break;
867 case AGGR_GLOBAL:
868 case AGGR_UNSET:
869 default:
870 break;
871 }
872}
873
874struct outstate {
875 FILE *fh;
876 bool newline;
877 const char *prefix;
878 int nfields;
879 int id, nr;
880 struct perf_evsel *evsel;
881};
882
883#define METRIC_LEN 35
884
885static void new_line_std(void *ctx)
886{
887 struct outstate *os = ctx;
888
889 os->newline = true;
890}
891
892static void do_new_line_std(struct outstate *os)
893{
894 fputc('\n', os->fh);
895 fputs(os->prefix, os->fh);
896 aggr_printout(os->evsel, os->id, os->nr);
897 if (stat_config.aggr_mode == AGGR_NONE)
898 fprintf(os->fh, " ");
899 fprintf(os->fh, " ");
900}
901
902static void print_metric_std(void *ctx, const char *color, const char *fmt,
903 const char *unit, double val)
904{
905 struct outstate *os = ctx;
906 FILE *out = os->fh;
907 int n;
908 bool newline = os->newline;
909
910 os->newline = false;
911
912 if (unit == NULL || fmt == NULL) {
913 fprintf(out, "%-*s", METRIC_LEN, "");
914 return;
915 }
916
917 if (newline)
918 do_new_line_std(os);
919
920 n = fprintf(out, " # ");
921 if (color)
922 n += color_fprintf(out, color, fmt, val);
923 else
924 n += fprintf(out, fmt, val);
925 fprintf(out, " %-*s", METRIC_LEN - n - 1, unit);
926}
927
928static void new_line_csv(void *ctx)
929{
930 struct outstate *os = ctx;
931 int i;
932
933 fputc('\n', os->fh);
934 if (os->prefix)
935 fprintf(os->fh, "%s%s", os->prefix, csv_sep);
936 aggr_printout(os->evsel, os->id, os->nr);
937 for (i = 0; i < os->nfields; i++)
938 fputs(csv_sep, os->fh);
939}
940
941static void print_metric_csv(void *ctx,
942 const char *color __maybe_unused,
943 const char *fmt, const char *unit, double val)
944{
945 struct outstate *os = ctx;
946 FILE *out = os->fh;
947 char buf[64], *vals, *ends;
948
949 if (unit == NULL || fmt == NULL) {
950 fprintf(out, "%s%s", csv_sep, csv_sep);
951 return;
952 }
953 snprintf(buf, sizeof(buf), fmt, val);
954 ends = vals = ltrim(buf);
955 while (isdigit(*ends) || *ends == '.')
956 ends++;
957 *ends = 0;
958 while (isspace(*unit))
959 unit++;
960 fprintf(out, "%s%s%s%s", csv_sep, vals, csv_sep, unit);
961}
962
963/* Filter out some columns that don't work well in metrics only mode */
964
965static bool valid_only_metric(const char *unit)
966{
967 if (!unit)
968 return false;
969 if (strstr(unit, "/sec") ||
970 strstr(unit, "hz") ||
971 strstr(unit, "Hz") ||
972 strstr(unit, "CPUs utilized"))
973 return false;
974 return true;
975}
976
977static const char *fixunit(char *buf, struct perf_evsel *evsel,
978 const char *unit)
979{
980 if (!strncmp(unit, "of all", 6)) {
981 snprintf(buf, 1024, "%s %s", perf_evsel__name(evsel),
982 unit);
983 return buf;
984 }
985 return unit;
986}
987
988static void print_metric_only(void *ctx, const char *color, const char *fmt,
989 const char *unit, double val)
990{
991 struct outstate *os = ctx;
992 FILE *out = os->fh;
993 char buf[1024], str[1024];
994 unsigned mlen = metric_only_len;
995
996 if (!valid_only_metric(unit))
997 return;
998 unit = fixunit(buf, os->evsel, unit);
999 if (mlen < strlen(unit))
1000 mlen = strlen(unit) + 1;
1001
1002 if (color)
1003 mlen += strlen(color) + sizeof(PERF_COLOR_RESET) - 1;
1004
1005 color_snprintf(str, sizeof(str), color ?: "", fmt, val);
1006 fprintf(out, "%*s ", mlen, str);
1007}
1008
1009static void print_metric_only_csv(void *ctx, const char *color __maybe_unused,
1010 const char *fmt,
1011 const char *unit, double val)
1012{
1013 struct outstate *os = ctx;
1014 FILE *out = os->fh;
1015 char buf[64], *vals, *ends;
1016 char tbuf[1024];
1017
1018 if (!valid_only_metric(unit))
1019 return;
1020 unit = fixunit(tbuf, os->evsel, unit);
1021 snprintf(buf, sizeof buf, fmt, val);
1022 ends = vals = ltrim(buf);
1023 while (isdigit(*ends) || *ends == '.')
1024 ends++;
1025 *ends = 0;
1026 fprintf(out, "%s%s", vals, csv_sep);
1027}
1028
1029static void new_line_metric(void *ctx __maybe_unused)
1030{
1031}
1032
1033static void print_metric_header(void *ctx, const char *color __maybe_unused,
1034 const char *fmt __maybe_unused,
1035 const char *unit, double val __maybe_unused)
1036{
1037 struct outstate *os = ctx;
1038 char tbuf[1024];
1039
1040 if (!valid_only_metric(unit))
1041 return;
1042 unit = fixunit(tbuf, os->evsel, unit);
1043 if (csv_output)
1044 fprintf(os->fh, "%s%s", unit, csv_sep);
1045 else
1046 fprintf(os->fh, "%*s ", metric_only_len, unit);
1047}
1048
1049static int first_shadow_cpu(struct perf_evsel *evsel, int id)
1050{
1051 int i;
1052
1053 if (!aggr_get_id)
1054 return 0;
1055
1056 if (stat_config.aggr_mode == AGGR_NONE)
1057 return id;
1058
1059 if (stat_config.aggr_mode == AGGR_GLOBAL)
1060 return 0;
1061
1062 for (i = 0; i < perf_evsel__nr_cpus(evsel); i++) {
1063 int cpu2 = perf_evsel__cpus(evsel)->map[i];
1064
1065 if (aggr_get_id(evsel_list->cpus, cpu2) == id)
1066 return cpu2;
1067 }
1068 return 0;
1069}
1070
1071static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)
1072{
1073 FILE *output = stat_config.output;
1074 double sc = evsel->scale;
1075 const char *fmt;
1076
1077 if (csv_output) {
1078 fmt = floor(sc) != sc ? "%.2f%s" : "%.0f%s";
1079 } else {
1080 if (big_num)
1081 fmt = floor(sc) != sc ? "%'18.2f%s" : "%'18.0f%s";
1082 else
1083 fmt = floor(sc) != sc ? "%18.2f%s" : "%18.0f%s";
1084 }
1085
1086 aggr_printout(evsel, id, nr);
1087
1088 fprintf(output, fmt, avg, csv_sep);
1089
1090 if (evsel->unit)
1091 fprintf(output, "%-*s%s",
1092 csv_output ? 0 : unit_width,
1093 evsel->unit, csv_sep);
1094
1095 fprintf(output, "%-*s", csv_output ? 0 : 25, perf_evsel__name(evsel));
1096
1097 if (evsel->cgrp)
1098 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
1099}
1100
1101static bool is_mixed_hw_group(struct perf_evsel *counter)
1102{
1103 struct perf_evlist *evlist = counter->evlist;
1104 u32 pmu_type = counter->attr.type;
1105 struct perf_evsel *pos;
1106
1107 if (counter->nr_members < 2)
1108 return false;
1109
1110 evlist__for_each_entry(evlist, pos) {
1111 /* software events can be part of any hardware group */
1112 if (pos->attr.type == PERF_TYPE_SOFTWARE)
1113 continue;
1114 if (pmu_type == PERF_TYPE_SOFTWARE) {
1115 pmu_type = pos->attr.type;
1116 continue;
1117 }
1118 if (pmu_type != pos->attr.type)
1119 return true;
1120 }
1121
1122 return false;
1123}
1124
1125static void printout(int id, int nr, struct perf_evsel *counter, double uval,
1126 char *prefix, u64 run, u64 ena, double noise,
1127 struct runtime_stat *st)
1128{
1129 struct perf_stat_output_ctx out;
1130 struct outstate os = {
1131 .fh = stat_config.output,
1132 .prefix = prefix ? prefix : "",
1133 .id = id,
1134 .nr = nr,
1135 .evsel = counter,
1136 };
1137 print_metric_t pm = print_metric_std;
1138 void (*nl)(void *);
1139
1140 if (metric_only) {
1141 nl = new_line_metric;
1142 if (csv_output)
1143 pm = print_metric_only_csv;
1144 else
1145 pm = print_metric_only;
1146 } else
1147 nl = new_line_std;
1148
1149 if (csv_output && !metric_only) {
1150 static int aggr_fields[] = {
1151 [AGGR_GLOBAL] = 0,
1152 [AGGR_THREAD] = 1,
1153 [AGGR_NONE] = 1,
1154 [AGGR_SOCKET] = 2,
1155 [AGGR_CORE] = 2,
1156 };
1157
1158 pm = print_metric_csv;
1159 nl = new_line_csv;
1160 os.nfields = 3;
1161 os.nfields += aggr_fields[stat_config.aggr_mode];
1162 if (counter->cgrp)
1163 os.nfields++;
1164 }
1165 if (run == 0 || ena == 0 || counter->counts->scaled == -1) {
1166 if (metric_only) {
1167 pm(&os, NULL, "", "", 0);
1168 return;
1169 }
1170 aggr_printout(counter, id, nr);
1171
1172 fprintf(stat_config.output, "%*s%s",
1173 csv_output ? 0 : 18,
1174 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
1175 csv_sep);
1176
1177 if (counter->supported) {
1178 print_free_counters_hint = 1;
1179 if (is_mixed_hw_group(counter))
1180 print_mixed_hw_group_error = 1;
1181 }
1182
1183 fprintf(stat_config.output, "%-*s%s",
1184 csv_output ? 0 : unit_width,
1185 counter->unit, csv_sep);
1186
1187 fprintf(stat_config.output, "%*s",
1188 csv_output ? 0 : -25,
1189 perf_evsel__name(counter));
1190
1191 if (counter->cgrp)
1192 fprintf(stat_config.output, "%s%s",
1193 csv_sep, counter->cgrp->name);
1194
1195 if (!csv_output)
1196 pm(&os, NULL, NULL, "", 0);
1197 print_noise(counter, noise);
1198 print_running(run, ena);
1199 if (csv_output)
1200 pm(&os, NULL, NULL, "", 0);
1201 return;
1202 }
1203
1204 if (!metric_only)
1205 abs_printout(id, nr, counter, uval);
1206
1207 out.print_metric = pm;
1208 out.new_line = nl;
1209 out.ctx = &os;
1210 out.force_header = false;
1211
1212 if (csv_output && !metric_only) {
1213 print_noise(counter, noise);
1214 print_running(run, ena);
1215 }
1216
1217 perf_stat__print_shadow_stats(counter, uval,
1218 first_shadow_cpu(counter, id),
1219 &out, &metric_events, st);
1220 if (!csv_output && !metric_only) {
1221 print_noise(counter, noise);
1222 print_running(run, ena);
1223 }
1224}
1225
1226static void aggr_update_shadow(void)
1227{
1228 int cpu, s2, id, s;
1229 u64 val;
1230 struct perf_evsel *counter;
1231
1232 for (s = 0; s < aggr_map->nr; s++) {
1233 id = aggr_map->map[s];
1234 evlist__for_each_entry(evsel_list, counter) {
1235 val = 0;
1236 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
1237 s2 = aggr_get_id(evsel_list->cpus, cpu);
1238 if (s2 != id)
1239 continue;
1240 val += perf_counts(counter->counts, cpu, 0)->val;
1241 }
1242 perf_stat__update_shadow_stats(counter, val,
1243 first_shadow_cpu(counter, id),
1244 &rt_stat);
1245 }
1246 }
1247}
1248
1249static void uniquify_event_name(struct perf_evsel *counter)
1250{
1251 char *new_name;
1252 char *config;
1253
1254 if (counter->uniquified_name ||
1255 !counter->pmu_name || !strncmp(counter->name, counter->pmu_name,
1256 strlen(counter->pmu_name)))
1257 return;
1258
1259 config = strchr(counter->name, '/');
1260 if (config) {
1261 if (asprintf(&new_name,
1262 "%s%s", counter->pmu_name, config) > 0) {
1263 free(counter->name);
1264 counter->name = new_name;
1265 }
1266 } else {
1267 if (asprintf(&new_name,
1268 "%s [%s]", counter->name, counter->pmu_name) > 0) {
1269 free(counter->name);
1270 counter->name = new_name;
1271 }
1272 }
1273
1274 counter->uniquified_name = true;
1275}
1276
1277static void collect_all_aliases(struct perf_evsel *counter,
1278 void (*cb)(struct perf_evsel *counter, void *data,
1279 bool first),
1280 void *data)
1281{
1282 struct perf_evsel *alias;
1283
1284 alias = list_prepare_entry(counter, &(evsel_list->entries), node);
1285 list_for_each_entry_continue (alias, &evsel_list->entries, node) {
1286 if (strcmp(perf_evsel__name(alias), perf_evsel__name(counter)) ||
1287 alias->scale != counter->scale ||
1288 alias->cgrp != counter->cgrp ||
1289 strcmp(alias->unit, counter->unit) ||
1290 perf_evsel__is_clock(alias) != perf_evsel__is_clock(counter))
1291 break;
1292 alias->merged_stat = true;
1293 cb(alias, data, false);
1294 }
1295}
1296
1297static bool collect_data(struct perf_evsel *counter,
1298 void (*cb)(struct perf_evsel *counter, void *data,
1299 bool first),
1300 void *data)
1301{
1302 if (counter->merged_stat)
1303 return false;
1304 cb(counter, data, true);
1305 if (no_merge)
1306 uniquify_event_name(counter);
1307 else if (counter->auto_merge_stats)
1308 collect_all_aliases(counter, cb, data);
1309 return true;
1310}
1311
1312struct aggr_data {
1313 u64 ena, run, val;
1314 int id;
1315 int nr;
1316 int cpu;
1317};
1318
1319static void aggr_cb(struct perf_evsel *counter, void *data, bool first)
1320{
1321 struct aggr_data *ad = data;
1322 int cpu, s2;
1323
1324 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
1325 struct perf_counts_values *counts;
1326
1327 s2 = aggr_get_id(perf_evsel__cpus(counter), cpu);
1328 if (s2 != ad->id)
1329 continue;
1330 if (first)
1331 ad->nr++;
1332 counts = perf_counts(counter->counts, cpu, 0);
1333 /*
1334 * When any result is bad, make them all to give
1335 * consistent output in interval mode.
1336 */
1337 if (counts->ena == 0 || counts->run == 0 ||
1338 counter->counts->scaled == -1) {
1339 ad->ena = 0;
1340 ad->run = 0;
1341 break;
1342 }
1343 ad->val += counts->val;
1344 ad->ena += counts->ena;
1345 ad->run += counts->run;
1346 }
1347}
1348
1349static void print_aggr(char *prefix)
1350{
1351 FILE *output = stat_config.output;
1352 struct perf_evsel *counter;
1353 int s, id, nr;
1354 double uval;
1355 u64 ena, run, val;
1356 bool first;
1357
1358 if (!(aggr_map || aggr_get_id))
1359 return;
1360
1361 aggr_update_shadow();
1362
1363 /*
1364 * With metric_only everything is on a single line.
1365 * Without each counter has its own line.
1366 */
1367 for (s = 0; s < aggr_map->nr; s++) {
1368 struct aggr_data ad;
1369 if (prefix && metric_only)
1370 fprintf(output, "%s", prefix);
1371
1372 ad.id = id = aggr_map->map[s];
1373 first = true;
1374 evlist__for_each_entry(evsel_list, counter) {
1375 if (is_duration_time(counter))
1376 continue;
1377
1378 ad.val = ad.ena = ad.run = 0;
1379 ad.nr = 0;
1380 if (!collect_data(counter, aggr_cb, &ad))
1381 continue;
1382 nr = ad.nr;
1383 ena = ad.ena;
1384 run = ad.run;
1385 val = ad.val;
1386 if (first && metric_only) {
1387 first = false;
1388 aggr_printout(counter, id, nr);
1389 }
1390 if (prefix && !metric_only)
1391 fprintf(output, "%s", prefix);
1392
1393 uval = val * counter->scale;
1394 printout(id, nr, counter, uval, prefix, run, ena, 1.0,
1395 &rt_stat);
1396 if (!metric_only)
1397 fputc('\n', output);
1398 }
1399 if (metric_only)
1400 fputc('\n', output);
1401 }
1402}
1403
1404static int cmp_val(const void *a, const void *b)
1405{
1406 return ((struct perf_aggr_thread_value *)b)->val -
1407 ((struct perf_aggr_thread_value *)a)->val;
1408}
1409
1410static struct perf_aggr_thread_value *sort_aggr_thread(
1411 struct perf_evsel *counter,
1412 int nthreads, int ncpus,
1413 int *ret)
1414{
1415 int cpu, thread, i = 0;
1416 double uval;
1417 struct perf_aggr_thread_value *buf;
1418
1419 buf = calloc(nthreads, sizeof(struct perf_aggr_thread_value));
1420 if (!buf)
1421 return NULL;
1422
1423 for (thread = 0; thread < nthreads; thread++) {
1424 u64 ena = 0, run = 0, val = 0;
1425
1426 for (cpu = 0; cpu < ncpus; cpu++) {
1427 val += perf_counts(counter->counts, cpu, thread)->val;
1428 ena += perf_counts(counter->counts, cpu, thread)->ena;
1429 run += perf_counts(counter->counts, cpu, thread)->run;
1430 }
1431
1432 uval = val * counter->scale;
1433
1434 /*
1435 * Skip value 0 when enabling --per-thread globally,
1436 * otherwise too many 0 output.
1437 */
1438 if (uval == 0.0 && target__has_per_thread(&target))
1439 continue;
1440
1441 buf[i].counter = counter;
1442 buf[i].id = thread;
1443 buf[i].uval = uval;
1444 buf[i].val = val;
1445 buf[i].run = run;
1446 buf[i].ena = ena;
1447 i++;
1448 }
1449
1450 qsort(buf, i, sizeof(struct perf_aggr_thread_value), cmp_val);
1451
1452 if (ret)
1453 *ret = i;
1454
1455 return buf;
1456}
1457
1458static void print_aggr_thread(struct perf_evsel *counter, char *prefix)
1459{
1460 FILE *output = stat_config.output;
1461 int nthreads = thread_map__nr(counter->threads);
1462 int ncpus = cpu_map__nr(counter->cpus);
1463 int thread, sorted_threads, id;
1464 struct perf_aggr_thread_value *buf;
1465
1466 buf = sort_aggr_thread(counter, nthreads, ncpus, &sorted_threads);
1467 if (!buf) {
1468 perror("cannot sort aggr thread");
1469 return;
1470 }
1471
1472 for (thread = 0; thread < sorted_threads; thread++) {
1473 if (prefix)
1474 fprintf(output, "%s", prefix);
1475
1476 id = buf[thread].id;
1477 if (stat_config.stats)
1478 printout(id, 0, buf[thread].counter, buf[thread].uval,
1479 prefix, buf[thread].run, buf[thread].ena, 1.0,
1480 &stat_config.stats[id]);
1481 else
1482 printout(id, 0, buf[thread].counter, buf[thread].uval,
1483 prefix, buf[thread].run, buf[thread].ena, 1.0,
1484 &rt_stat);
1485 fputc('\n', output);
1486 }
1487
1488 free(buf);
1489}
1490
1491struct caggr_data {
1492 double avg, avg_enabled, avg_running;
1493};
1494
1495static void counter_aggr_cb(struct perf_evsel *counter, void *data,
1496 bool first __maybe_unused)
1497{
1498 struct caggr_data *cd = data;
1499 struct perf_stat_evsel *ps = counter->stats;
1500
1501 cd->avg += avg_stats(&ps->res_stats[0]);
1502 cd->avg_enabled += avg_stats(&ps->res_stats[1]);
1503 cd->avg_running += avg_stats(&ps->res_stats[2]);
1504}
1505
1506/*
1507 * Print out the results of a single counter:
1508 * aggregated counts in system-wide mode
1509 */
1510static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
1511{
1512 FILE *output = stat_config.output;
1513 double uval;
1514 struct caggr_data cd = { .avg = 0.0 };
1515
1516 if (!collect_data(counter, counter_aggr_cb, &cd))
1517 return;
1518
1519 if (prefix && !metric_only)
1520 fprintf(output, "%s", prefix);
1521
1522 uval = cd.avg * counter->scale;
1523 printout(-1, 0, counter, uval, prefix, cd.avg_running, cd.avg_enabled,
1524 cd.avg, &rt_stat);
1525 if (!metric_only)
1526 fprintf(output, "\n");
1527}
1528
1529static void counter_cb(struct perf_evsel *counter, void *data,
1530 bool first __maybe_unused)
1531{
1532 struct aggr_data *ad = data;
1533
1534 ad->val += perf_counts(counter->counts, ad->cpu, 0)->val;
1535 ad->ena += perf_counts(counter->counts, ad->cpu, 0)->ena;
1536 ad->run += perf_counts(counter->counts, ad->cpu, 0)->run;
1537}
1538
1539/*
1540 * Print out the results of a single counter:
1541 * does not use aggregated count in system-wide
1542 */
1543static void print_counter(struct perf_evsel *counter, char *prefix)
1544{
1545 FILE *output = stat_config.output;
1546 u64 ena, run, val;
1547 double uval;
1548 int cpu;
1549
1550 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
1551 struct aggr_data ad = { .cpu = cpu };
1552
1553 if (!collect_data(counter, counter_cb, &ad))
1554 return;
1555 val = ad.val;
1556 ena = ad.ena;
1557 run = ad.run;
1558
1559 if (prefix)
1560 fprintf(output, "%s", prefix);
1561
1562 uval = val * counter->scale;
1563 printout(cpu, 0, counter, uval, prefix, run, ena, 1.0,
1564 &rt_stat);
1565
1566 fputc('\n', output);
1567 }
1568}
1569
1570static void print_no_aggr_metric(char *prefix)
1571{
1572 int cpu;
1573 int nrcpus = 0;
1574 struct perf_evsel *counter;
1575 u64 ena, run, val;
1576 double uval;
1577
1578 nrcpus = evsel_list->cpus->nr;
1579 for (cpu = 0; cpu < nrcpus; cpu++) {
1580 bool first = true;
1581
1582 if (prefix)
1583 fputs(prefix, stat_config.output);
1584 evlist__for_each_entry(evsel_list, counter) {
1585 if (is_duration_time(counter))
1586 continue;
1587 if (first) {
1588 aggr_printout(counter, cpu, 0);
1589 first = false;
1590 }
1591 val = perf_counts(counter->counts, cpu, 0)->val;
1592 ena = perf_counts(counter->counts, cpu, 0)->ena;
1593 run = perf_counts(counter->counts, cpu, 0)->run;
1594
1595 uval = val * counter->scale;
1596 printout(cpu, 0, counter, uval, prefix, run, ena, 1.0,
1597 &rt_stat);
1598 }
1599 fputc('\n', stat_config.output);
1600 }
1601}
1602
1603static int aggr_header_lens[] = {
1604 [AGGR_CORE] = 18,
1605 [AGGR_SOCKET] = 12,
1606 [AGGR_NONE] = 6,
1607 [AGGR_THREAD] = 24,
1608 [AGGR_GLOBAL] = 0,
1609};
1610
1611static const char *aggr_header_csv[] = {
1612 [AGGR_CORE] = "core,cpus,",
1613 [AGGR_SOCKET] = "socket,cpus",
1614 [AGGR_NONE] = "cpu,",
1615 [AGGR_THREAD] = "comm-pid,",
1616 [AGGR_GLOBAL] = ""
1617};
1618
1619static void print_metric_headers(const char *prefix, bool no_indent)
1620{
1621 struct perf_stat_output_ctx out;
1622 struct perf_evsel *counter;
1623 struct outstate os = {
1624 .fh = stat_config.output
1625 };
1626
1627 if (prefix)
1628 fprintf(stat_config.output, "%s", prefix);
1629
1630 if (!csv_output && !no_indent)
1631 fprintf(stat_config.output, "%*s",
1632 aggr_header_lens[stat_config.aggr_mode], "");
1633 if (csv_output) {
1634 if (stat_config.interval)
1635 fputs("time,", stat_config.output);
1636 fputs(aggr_header_csv[stat_config.aggr_mode],
1637 stat_config.output);
1638 }
1639
1640 /* Print metrics headers only */
1641 evlist__for_each_entry(evsel_list, counter) {
1642 if (is_duration_time(counter))
1643 continue;
1644 os.evsel = counter;
1645 out.ctx = &os;
1646 out.print_metric = print_metric_header;
1647 out.new_line = new_line_metric;
1648 out.force_header = true;
1649 os.evsel = counter;
1650 perf_stat__print_shadow_stats(counter, 0,
1651 0,
1652 &out,
1653 &metric_events,
1654 &rt_stat);
1655 }
1656 fputc('\n', stat_config.output);
1657}
1658
1659static void print_interval(char *prefix, struct timespec *ts)
1660{
1661 FILE *output = stat_config.output;
1662 static int num_print_interval;
1663
1664 if (interval_clear)
1665 puts(CONSOLE_CLEAR);
1666
1667 sprintf(prefix, "%6lu.%09lu%s", ts->tv_sec, ts->tv_nsec, csv_sep);
1668
1669 if ((num_print_interval == 0 && !csv_output) || interval_clear) {
1670 switch (stat_config.aggr_mode) {
1671 case AGGR_SOCKET:
1672 fprintf(output, "# time socket cpus");
1673 if (!metric_only)
1674 fprintf(output, " counts %*s events\n", unit_width, "unit");
1675 break;
1676 case AGGR_CORE:
1677 fprintf(output, "# time core cpus");
1678 if (!metric_only)
1679 fprintf(output, " counts %*s events\n", unit_width, "unit");
1680 break;
1681 case AGGR_NONE:
1682 fprintf(output, "# time CPU ");
1683 if (!metric_only)
1684 fprintf(output, " counts %*s events\n", unit_width, "unit");
1685 break;
1686 case AGGR_THREAD:
1687 fprintf(output, "# time comm-pid");
1688 if (!metric_only)
1689 fprintf(output, " counts %*s events\n", unit_width, "unit");
1690 break;
1691 case AGGR_GLOBAL:
1692 default:
1693 fprintf(output, "# time");
1694 if (!metric_only)
1695 fprintf(output, " counts %*s events\n", unit_width, "unit");
1696 case AGGR_UNSET:
1697 break;
1698 }
1699 }
1700
1701 if ((num_print_interval == 0 || interval_clear) && metric_only)
1702 print_metric_headers(" ", true);
1703 if (++num_print_interval == 25)
1704 num_print_interval = 0;
1705}
1706
1707static void print_header(int argc, const char **argv)
1708{
1709 FILE *output = stat_config.output;
1710 int i;
1711
1712 fflush(stdout);
1713
1714 if (!csv_output) {
1715 fprintf(output, "\n");
1716 fprintf(output, " Performance counter stats for ");
1717 if (target.system_wide)
1718 fprintf(output, "\'system wide");
1719 else if (target.cpu_list)
1720 fprintf(output, "\'CPU(s) %s", target.cpu_list);
1721 else if (!target__has_task(&target)) {
1722 fprintf(output, "\'%s", argv ? argv[0] : "pipe");
1723 for (i = 1; argv && (i < argc); i++)
1724 fprintf(output, " %s", argv[i]);
1725 } else if (target.pid)
1726 fprintf(output, "process id \'%s", target.pid);
1727 else
1728 fprintf(output, "thread id \'%s", target.tid);
1729
1730 fprintf(output, "\'");
1731 if (run_count > 1)
1732 fprintf(output, " (%d runs)", run_count);
1733 fprintf(output, ":\n\n");
1734 }
1735}
1736
1737static int get_precision(double num)
1738{
1739 if (num > 1)
1740 return 0;
1741
1742 return lround(ceil(-log10(num)));
1743}
1744
1745static void print_table(FILE *output, int precision, double avg)
1746{
1747 char tmp[64];
1748 int idx, indent = 0;
1749
1750 scnprintf(tmp, 64, " %17.*f", precision, avg);
1751 while (tmp[indent] == ' ')
1752 indent++;
1753
1754 fprintf(output, "%*s# Table of individual measurements:\n", indent, "");
1755
1756 for (idx = 0; idx < run_count; idx++) {
1757 double run = (double) walltime_run[idx] / NSEC_PER_SEC;
1758 int h, n = 1 + abs((int) (100.0 * (run - avg)/run) / 5);
1759
1760 fprintf(output, " %17.*f (%+.*f) ",
1761 precision, run, precision, run - avg);
1762
1763 for (h = 0; h < n; h++)
1764 fprintf(output, "#");
1765
1766 fprintf(output, "\n");
1767 }
1768
1769 fprintf(output, "\n%*s# Final result:\n", indent, "");
1770}
1771
1772static double timeval2double(struct timeval *t)
1773{
1774 return t->tv_sec + (double) t->tv_usec/USEC_PER_SEC;
1775}
1776
1777static void print_footer(void)
1778{
1779 double avg = avg_stats(&walltime_nsecs_stats) / NSEC_PER_SEC;
1780 FILE *output = stat_config.output;
1781 int n;
1782
1783 if (!null_run)
1784 fprintf(output, "\n");
1785
1786 if (run_count == 1) {
1787 fprintf(output, " %17.9f seconds time elapsed", avg);
1788
1789 if (ru_display) {
1790 double ru_utime = timeval2double(&ru_data.ru_utime);
1791 double ru_stime = timeval2double(&ru_data.ru_stime);
1792
1793 fprintf(output, "\n\n");
1794 fprintf(output, " %17.9f seconds user\n", ru_utime);
1795 fprintf(output, " %17.9f seconds sys\n", ru_stime);
1796 }
1797 } else {
1798 double sd = stddev_stats(&walltime_nsecs_stats) / NSEC_PER_SEC;
1799 /*
1800 * Display at most 2 more significant
1801 * digits than the stddev inaccuracy.
1802 */
1803 int precision = get_precision(sd) + 2;
1804
1805 if (walltime_run_table)
1806 print_table(output, precision, avg);
1807
1808 fprintf(output, " %17.*f +- %.*f seconds time elapsed",
1809 precision, avg, precision, sd);
1810
1811 print_noise_pct(sd, avg);
1812 }
1813 fprintf(output, "\n\n");
1814
1815 if (print_free_counters_hint &&
1816 sysctl__read_int("kernel/nmi_watchdog", &n) >= 0 &&
1817 n > 0)
1818 fprintf(output,
1819"Some events weren't counted. Try disabling the NMI watchdog:\n"
1820" echo 0 > /proc/sys/kernel/nmi_watchdog\n"
1821" perf stat ...\n"
1822" echo 1 > /proc/sys/kernel/nmi_watchdog\n");
1823
1824 if (print_mixed_hw_group_error)
1825 fprintf(output,
1826 "The events in group usually have to be from "
1827 "the same PMU. Try reorganizing the group.\n");
1828}
1829
1830static void print_counters(struct timespec *ts, int argc, const char **argv) 663static void print_counters(struct timespec *ts, int argc, const char **argv)
1831{ 664{
1832 int interval = stat_config.interval;
1833 struct perf_evsel *counter;
1834 char buf[64], *prefix = NULL;
1835
1836 /* Do not print anything if we record to the pipe. */ 665 /* Do not print anything if we record to the pipe. */
1837 if (STAT_RECORD && perf_stat.data.is_pipe) 666 if (STAT_RECORD && perf_stat.data.is_pipe)
1838 return; 667 return;
1839 668
1840 if (interval) 669 perf_evlist__print_counters(evsel_list, &stat_config, &target,
1841 print_interval(prefix = buf, ts); 670 ts, argc, argv);
1842 else
1843 print_header(argc, argv);
1844
1845 if (metric_only) {
1846 static int num_print_iv;
1847
1848 if (num_print_iv == 0 && !interval)
1849 print_metric_headers(prefix, false);
1850 if (num_print_iv++ == 25)
1851 num_print_iv = 0;
1852 if (stat_config.aggr_mode == AGGR_GLOBAL && prefix)
1853 fprintf(stat_config.output, "%s", prefix);
1854 }
1855
1856 switch (stat_config.aggr_mode) {
1857 case AGGR_CORE:
1858 case AGGR_SOCKET:
1859 print_aggr(prefix);
1860 break;
1861 case AGGR_THREAD:
1862 evlist__for_each_entry(evsel_list, counter) {
1863 if (is_duration_time(counter))
1864 continue;
1865 print_aggr_thread(counter, prefix);
1866 }
1867 break;
1868 case AGGR_GLOBAL:
1869 evlist__for_each_entry(evsel_list, counter) {
1870 if (is_duration_time(counter))
1871 continue;
1872 print_counter_aggr(counter, prefix);
1873 }
1874 if (metric_only)
1875 fputc('\n', stat_config.output);
1876 break;
1877 case AGGR_NONE:
1878 if (metric_only)
1879 print_no_aggr_metric(prefix);
1880 else {
1881 evlist__for_each_entry(evsel_list, counter) {
1882 if (is_duration_time(counter))
1883 continue;
1884 print_counter(counter, prefix);
1885 }
1886 }
1887 break;
1888 case AGGR_UNSET:
1889 default:
1890 break;
1891 }
1892
1893 if (!interval && !csv_output)
1894 print_footer();
1895
1896 fflush(stat_config.output);
1897} 671}
1898 672
1899static volatile int signr = -1; 673static volatile int signr = -1;
@@ -1950,7 +724,7 @@ static int enable_metric_only(const struct option *opt __maybe_unused,
1950 const char *s __maybe_unused, int unset) 724 const char *s __maybe_unused, int unset)
1951{ 725{
1952 force_metric_only = true; 726 force_metric_only = true;
1953 metric_only = !unset; 727 stat_config.metric_only = !unset;
1954 return 0; 728 return 0;
1955} 729}
1956 730
@@ -1958,7 +732,7 @@ static int parse_metric_groups(const struct option *opt,
1958 const char *str, 732 const char *str,
1959 int unset __maybe_unused) 733 int unset __maybe_unused)
1960{ 734{
1961 return metricgroup__parse_groups(opt, str, &metric_events); 735 return metricgroup__parse_groups(opt, str, &stat_config.metric_events);
1962} 736}
1963 737
1964static const struct option stat_options[] = { 738static const struct option stat_options[] = {
@@ -1969,7 +743,7 @@ static const struct option stat_options[] = {
1969 parse_events_option), 743 parse_events_option),
1970 OPT_CALLBACK(0, "filter", &evsel_list, "filter", 744 OPT_CALLBACK(0, "filter", &evsel_list, "filter",
1971 "event filter", parse_filter), 745 "event filter", parse_filter),
1972 OPT_BOOLEAN('i', "no-inherit", &no_inherit, 746 OPT_BOOLEAN('i', "no-inherit", &stat_config.no_inherit,
1973 "child tasks do not inherit counters"), 747 "child tasks do not inherit counters"),
1974 OPT_STRING('p', "pid", &target.pid, "pid", 748 OPT_STRING('p', "pid", &target.pid, "pid",
1975 "stat events on existing process id"), 749 "stat events on existing process id"),
@@ -1982,11 +756,11 @@ static const struct option stat_options[] = {
1982 OPT_BOOLEAN('c', "scale", &stat_config.scale, "scale/normalize counters"), 756 OPT_BOOLEAN('c', "scale", &stat_config.scale, "scale/normalize counters"),
1983 OPT_INCR('v', "verbose", &verbose, 757 OPT_INCR('v', "verbose", &verbose,
1984 "be more verbose (show counter open errors, etc)"), 758 "be more verbose (show counter open errors, etc)"),
1985 OPT_INTEGER('r', "repeat", &run_count, 759 OPT_INTEGER('r', "repeat", &stat_config.run_count,
1986 "repeat command and print average + stddev (max: 100, forever: 0)"), 760 "repeat command and print average + stddev (max: 100, forever: 0)"),
1987 OPT_BOOLEAN(0, "table", &walltime_run_table, 761 OPT_BOOLEAN(0, "table", &stat_config.walltime_run_table,
1988 "display details about each run (only with -r option)"), 762 "display details about each run (only with -r option)"),
1989 OPT_BOOLEAN('n', "null", &null_run, 763 OPT_BOOLEAN('n', "null", &stat_config.null_run,
1990 "null run - dont start any counters"), 764 "null run - dont start any counters"),
1991 OPT_INCR('d', "detailed", &detailed_run, 765 OPT_INCR('d', "detailed", &detailed_run,
1992 "detailed run - start a lot of events"), 766 "detailed run - start a lot of events"),
@@ -1999,8 +773,8 @@ static const struct option stat_options[] = {
1999 "list of cpus to monitor in system-wide"), 773 "list of cpus to monitor in system-wide"),
2000 OPT_SET_UINT('A', "no-aggr", &stat_config.aggr_mode, 774 OPT_SET_UINT('A', "no-aggr", &stat_config.aggr_mode,
2001 "disable CPU count aggregation", AGGR_NONE), 775 "disable CPU count aggregation", AGGR_NONE),
2002 OPT_BOOLEAN(0, "no-merge", &no_merge, "Do not merge identical named events"), 776 OPT_BOOLEAN(0, "no-merge", &stat_config.no_merge, "Do not merge identical named events"),
2003 OPT_STRING('x', "field-separator", &csv_sep, "separator", 777 OPT_STRING('x', "field-separator", &stat_config.csv_sep, "separator",
2004 "print counts with custom separator"), 778 "print counts with custom separator"),
2005 OPT_CALLBACK('G', "cgroup", &evsel_list, "name", 779 OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
2006 "monitor event in cgroup name only", parse_cgroups), 780 "monitor event in cgroup name only", parse_cgroups),
@@ -2017,7 +791,7 @@ static const struct option stat_options[] = {
2017 "(overhead is possible for values <= 100ms)"), 791 "(overhead is possible for values <= 100ms)"),
2018 OPT_INTEGER(0, "interval-count", &stat_config.times, 792 OPT_INTEGER(0, "interval-count", &stat_config.times,
2019 "print counts for fixed number of times"), 793 "print counts for fixed number of times"),
2020 OPT_BOOLEAN(0, "interval-clear", &interval_clear, 794 OPT_BOOLEAN(0, "interval-clear", &stat_config.interval_clear,
2021 "clear screen in between new interval"), 795 "clear screen in between new interval"),
2022 OPT_UINTEGER(0, "timeout", &stat_config.timeout, 796 OPT_UINTEGER(0, "timeout", &stat_config.timeout,
2023 "stop workload and print counts after a timeout period in ms (>= 10ms)"), 797 "stop workload and print counts after a timeout period in ms (>= 10ms)"),
@@ -2027,9 +801,9 @@ static const struct option stat_options[] = {
2027 "aggregate counts per physical processor core", AGGR_CORE), 801 "aggregate counts per physical processor core", AGGR_CORE),
2028 OPT_SET_UINT(0, "per-thread", &stat_config.aggr_mode, 802 OPT_SET_UINT(0, "per-thread", &stat_config.aggr_mode,
2029 "aggregate counts per thread", AGGR_THREAD), 803 "aggregate counts per thread", AGGR_THREAD),
2030 OPT_UINTEGER('D', "delay", &initial_delay, 804 OPT_UINTEGER('D', "delay", &stat_config.initial_delay,
2031 "ms to wait before starting measurement after program start"), 805 "ms to wait before starting measurement after program start"),
2032 OPT_CALLBACK_NOOPT(0, "metric-only", &metric_only, NULL, 806 OPT_CALLBACK_NOOPT(0, "metric-only", &stat_config.metric_only, NULL,
2033 "Only print computed metrics. No raw values", enable_metric_only), 807 "Only print computed metrics. No raw values", enable_metric_only),
2034 OPT_BOOLEAN(0, "topdown", &topdown_run, 808 OPT_BOOLEAN(0, "topdown", &topdown_run,
2035 "measure topdown level 1 statistics"), 809 "measure topdown level 1 statistics"),
@@ -2041,12 +815,14 @@ static const struct option stat_options[] = {
2041 OPT_END() 815 OPT_END()
2042}; 816};
2043 817
2044static int perf_stat__get_socket(struct cpu_map *map, int cpu) 818static int perf_stat__get_socket(struct perf_stat_config *config __maybe_unused,
819 struct cpu_map *map, int cpu)
2045{ 820{
2046 return cpu_map__get_socket(map, cpu, NULL); 821 return cpu_map__get_socket(map, cpu, NULL);
2047} 822}
2048 823
2049static int perf_stat__get_core(struct cpu_map *map, int cpu) 824static int perf_stat__get_core(struct perf_stat_config *config __maybe_unused,
825 struct cpu_map *map, int cpu)
2050{ 826{
2051 return cpu_map__get_core(map, cpu, NULL); 827 return cpu_map__get_core(map, cpu, NULL);
2052} 828}
@@ -2063,9 +839,8 @@ static int cpu_map__get_max(struct cpu_map *map)
2063 return max; 839 return max;
2064} 840}
2065 841
2066static struct cpu_map *cpus_aggr_map; 842static int perf_stat__get_aggr(struct perf_stat_config *config,
2067 843 aggr_get_id_t get_id, struct cpu_map *map, int idx)
2068static int perf_stat__get_aggr(aggr_get_id_t get_id, struct cpu_map *map, int idx)
2069{ 844{
2070 int cpu; 845 int cpu;
2071 846
@@ -2074,20 +849,22 @@ static int perf_stat__get_aggr(aggr_get_id_t get_id, struct cpu_map *map, int id
2074 849
2075 cpu = map->map[idx]; 850 cpu = map->map[idx];
2076 851
2077 if (cpus_aggr_map->map[cpu] == -1) 852 if (config->cpus_aggr_map->map[cpu] == -1)
2078 cpus_aggr_map->map[cpu] = get_id(map, idx); 853 config->cpus_aggr_map->map[cpu] = get_id(config, map, idx);
2079 854
2080 return cpus_aggr_map->map[cpu]; 855 return config->cpus_aggr_map->map[cpu];
2081} 856}
2082 857
2083static int perf_stat__get_socket_cached(struct cpu_map *map, int idx) 858static int perf_stat__get_socket_cached(struct perf_stat_config *config,
859 struct cpu_map *map, int idx)
2084{ 860{
2085 return perf_stat__get_aggr(perf_stat__get_socket, map, idx); 861 return perf_stat__get_aggr(config, perf_stat__get_socket, map, idx);
2086} 862}
2087 863
2088static int perf_stat__get_core_cached(struct cpu_map *map, int idx) 864static int perf_stat__get_core_cached(struct perf_stat_config *config,
865 struct cpu_map *map, int idx)
2089{ 866{
2090 return perf_stat__get_aggr(perf_stat__get_core, map, idx); 867 return perf_stat__get_aggr(config, perf_stat__get_core, map, idx);
2091} 868}
2092 869
2093static int perf_stat_init_aggr_mode(void) 870static int perf_stat_init_aggr_mode(void)
@@ -2096,18 +873,18 @@ static int perf_stat_init_aggr_mode(void)
2096 873
2097 switch (stat_config.aggr_mode) { 874 switch (stat_config.aggr_mode) {
2098 case AGGR_SOCKET: 875 case AGGR_SOCKET:
2099 if (cpu_map__build_socket_map(evsel_list->cpus, &aggr_map)) { 876 if (cpu_map__build_socket_map(evsel_list->cpus, &stat_config.aggr_map)) {
2100 perror("cannot build socket map"); 877 perror("cannot build socket map");
2101 return -1; 878 return -1;
2102 } 879 }
2103 aggr_get_id = perf_stat__get_socket_cached; 880 stat_config.aggr_get_id = perf_stat__get_socket_cached;
2104 break; 881 break;
2105 case AGGR_CORE: 882 case AGGR_CORE:
2106 if (cpu_map__build_core_map(evsel_list->cpus, &aggr_map)) { 883 if (cpu_map__build_core_map(evsel_list->cpus, &stat_config.aggr_map)) {
2107 perror("cannot build core map"); 884 perror("cannot build core map");
2108 return -1; 885 return -1;
2109 } 886 }
2110 aggr_get_id = perf_stat__get_core_cached; 887 stat_config.aggr_get_id = perf_stat__get_core_cached;
2111 break; 888 break;
2112 case AGGR_NONE: 889 case AGGR_NONE:
2113 case AGGR_GLOBAL: 890 case AGGR_GLOBAL:
@@ -2123,16 +900,16 @@ static int perf_stat_init_aggr_mode(void)
2123 * the aggregation translate cpumap. 900 * the aggregation translate cpumap.
2124 */ 901 */
2125 nr = cpu_map__get_max(evsel_list->cpus); 902 nr = cpu_map__get_max(evsel_list->cpus);
2126 cpus_aggr_map = cpu_map__empty_new(nr + 1); 903 stat_config.cpus_aggr_map = cpu_map__empty_new(nr + 1);
2127 return cpus_aggr_map ? 0 : -ENOMEM; 904 return stat_config.cpus_aggr_map ? 0 : -ENOMEM;
2128} 905}
2129 906
2130static void perf_stat__exit_aggr_mode(void) 907static void perf_stat__exit_aggr_mode(void)
2131{ 908{
2132 cpu_map__put(aggr_map); 909 cpu_map__put(stat_config.aggr_map);
2133 cpu_map__put(cpus_aggr_map); 910 cpu_map__put(stat_config.cpus_aggr_map);
2134 aggr_map = NULL; 911 stat_config.aggr_map = NULL;
2135 cpus_aggr_map = NULL; 912 stat_config.cpus_aggr_map = NULL;
2136} 913}
2137 914
2138static inline int perf_env__get_cpu(struct perf_env *env, struct cpu_map *map, int idx) 915static inline int perf_env__get_cpu(struct perf_env *env, struct cpu_map *map, int idx)
@@ -2190,12 +967,14 @@ static int perf_env__build_core_map(struct perf_env *env, struct cpu_map *cpus,
2190 return cpu_map__build_map(cpus, corep, perf_env__get_core, env); 967 return cpu_map__build_map(cpus, corep, perf_env__get_core, env);
2191} 968}
2192 969
2193static int perf_stat__get_socket_file(struct cpu_map *map, int idx) 970static int perf_stat__get_socket_file(struct perf_stat_config *config __maybe_unused,
971 struct cpu_map *map, int idx)
2194{ 972{
2195 return perf_env__get_socket(map, idx, &perf_stat.session->header.env); 973 return perf_env__get_socket(map, idx, &perf_stat.session->header.env);
2196} 974}
2197 975
2198static int perf_stat__get_core_file(struct cpu_map *map, int idx) 976static int perf_stat__get_core_file(struct perf_stat_config *config __maybe_unused,
977 struct cpu_map *map, int idx)
2199{ 978{
2200 return perf_env__get_core(map, idx, &perf_stat.session->header.env); 979 return perf_env__get_core(map, idx, &perf_stat.session->header.env);
2201} 980}
@@ -2206,18 +985,18 @@ static int perf_stat_init_aggr_mode_file(struct perf_stat *st)
2206 985
2207 switch (stat_config.aggr_mode) { 986 switch (stat_config.aggr_mode) {
2208 case AGGR_SOCKET: 987 case AGGR_SOCKET:
2209 if (perf_env__build_socket_map(env, evsel_list->cpus, &aggr_map)) { 988 if (perf_env__build_socket_map(env, evsel_list->cpus, &stat_config.aggr_map)) {
2210 perror("cannot build socket map"); 989 perror("cannot build socket map");
2211 return -1; 990 return -1;
2212 } 991 }
2213 aggr_get_id = perf_stat__get_socket_file; 992 stat_config.aggr_get_id = perf_stat__get_socket_file;
2214 break; 993 break;
2215 case AGGR_CORE: 994 case AGGR_CORE:
2216 if (perf_env__build_core_map(env, evsel_list->cpus, &aggr_map)) { 995 if (perf_env__build_core_map(env, evsel_list->cpus, &stat_config.aggr_map)) {
2217 perror("cannot build core map"); 996 perror("cannot build core map");
2218 return -1; 997 return -1;
2219 } 998 }
2220 aggr_get_id = perf_stat__get_core_file; 999 stat_config.aggr_get_id = perf_stat__get_core_file;
2221 break; 1000 break;
2222 case AGGR_NONE: 1001 case AGGR_NONE:
2223 case AGGR_GLOBAL: 1002 case AGGR_GLOBAL:
@@ -2401,7 +1180,7 @@ static int add_default_attributes(void)
2401 struct parse_events_error errinfo; 1180 struct parse_events_error errinfo;
2402 1181
2403 /* Set attrs if no event is selected and !null_run: */ 1182 /* Set attrs if no event is selected and !null_run: */
2404 if (null_run) 1183 if (stat_config.null_run)
2405 return 0; 1184 return 0;
2406 1185
2407 if (transaction_run) { 1186 if (transaction_run) {
@@ -2414,7 +1193,7 @@ static int add_default_attributes(void)
2414 struct option opt = { .value = &evsel_list }; 1193 struct option opt = { .value = &evsel_list };
2415 1194
2416 return metricgroup__parse_groups(&opt, "transaction", 1195 return metricgroup__parse_groups(&opt, "transaction",
2417 &metric_events); 1196 &stat_config.metric_events);
2418 } 1197 }
2419 1198
2420 if (pmu_have_event("cpu", "cycles-ct") && 1199 if (pmu_have_event("cpu", "cycles-ct") &&
@@ -2452,7 +1231,7 @@ static int add_default_attributes(void)
2452 if (pmu_have_event("msr", "aperf") && 1231 if (pmu_have_event("msr", "aperf") &&
2453 pmu_have_event("msr", "smi")) { 1232 pmu_have_event("msr", "smi")) {
2454 if (!force_metric_only) 1233 if (!force_metric_only)
2455 metric_only = true; 1234 stat_config.metric_only = true;
2456 err = parse_events(evsel_list, smi_cost_attrs, &errinfo); 1235 err = parse_events(evsel_list, smi_cost_attrs, &errinfo);
2457 } else { 1236 } else {
2458 fprintf(stderr, "To measure SMI cost, it needs " 1237 fprintf(stderr, "To measure SMI cost, it needs "
@@ -2483,7 +1262,7 @@ static int add_default_attributes(void)
2483 } 1262 }
2484 1263
2485 if (!force_metric_only) 1264 if (!force_metric_only)
2486 metric_only = true; 1265 stat_config.metric_only = true;
2487 if (topdown_filter_events(topdown_attrs, &str, 1266 if (topdown_filter_events(topdown_attrs, &str,
2488 arch_topdown_check_group(&warn)) < 0) { 1267 arch_topdown_check_group(&warn)) < 0) {
2489 pr_err("Out of memory\n"); 1268 pr_err("Out of memory\n");
@@ -2580,7 +1359,7 @@ static int __cmd_record(int argc, const char **argv)
2580 if (output_name) 1359 if (output_name)
2581 data->file.path = output_name; 1360 data->file.path = output_name;
2582 1361
2583 if (run_count != 1 || forever) { 1362 if (stat_config.run_count != 1 || forever) {
2584 pr_err("Cannot use -r option with perf stat record.\n"); 1363 pr_err("Cannot use -r option with perf stat record.\n");
2585 return -1; 1364 return -1;
2586 } 1365 }
@@ -2599,9 +1378,8 @@ static int __cmd_record(int argc, const char **argv)
2599 return argc; 1378 return argc;
2600} 1379}
2601 1380
2602static int process_stat_round_event(struct perf_tool *tool __maybe_unused, 1381static int process_stat_round_event(struct perf_session *session,
2603 union perf_event *event, 1382 union perf_event *event)
2604 struct perf_session *session)
2605{ 1383{
2606 struct stat_round_event *stat_round = &event->stat_round; 1384 struct stat_round_event *stat_round = &event->stat_round;
2607 struct perf_evsel *counter; 1385 struct perf_evsel *counter;
@@ -2626,10 +1404,10 @@ static int process_stat_round_event(struct perf_tool *tool __maybe_unused,
2626} 1404}
2627 1405
2628static 1406static
2629int process_stat_config_event(struct perf_tool *tool, 1407int process_stat_config_event(struct perf_session *session,
2630 union perf_event *event, 1408 union perf_event *event)
2631 struct perf_session *session __maybe_unused)
2632{ 1409{
1410 struct perf_tool *tool = session->tool;
2633 struct perf_stat *st = container_of(tool, struct perf_stat, tool); 1411 struct perf_stat *st = container_of(tool, struct perf_stat, tool);
2634 1412
2635 perf_event__read_stat_config(&stat_config, &event->stat_config); 1413 perf_event__read_stat_config(&stat_config, &event->stat_config);
@@ -2669,10 +1447,10 @@ static int set_maps(struct perf_stat *st)
2669} 1447}
2670 1448
2671static 1449static
2672int process_thread_map_event(struct perf_tool *tool, 1450int process_thread_map_event(struct perf_session *session,
2673 union perf_event *event, 1451 union perf_event *event)
2674 struct perf_session *session __maybe_unused)
2675{ 1452{
1453 struct perf_tool *tool = session->tool;
2676 struct perf_stat *st = container_of(tool, struct perf_stat, tool); 1454 struct perf_stat *st = container_of(tool, struct perf_stat, tool);
2677 1455
2678 if (st->threads) { 1456 if (st->threads) {
@@ -2688,10 +1466,10 @@ int process_thread_map_event(struct perf_tool *tool,
2688} 1466}
2689 1467
2690static 1468static
2691int process_cpu_map_event(struct perf_tool *tool, 1469int process_cpu_map_event(struct perf_session *session,
2692 union perf_event *event, 1470 union perf_event *event)
2693 struct perf_session *session __maybe_unused)
2694{ 1471{
1472 struct perf_tool *tool = session->tool;
2695 struct perf_stat *st = container_of(tool, struct perf_stat, tool); 1473 struct perf_stat *st = container_of(tool, struct perf_stat, tool);
2696 struct cpu_map *cpus; 1474 struct cpu_map *cpus;
2697 1475
@@ -2853,12 +1631,12 @@ int cmd_stat(int argc, const char **argv)
2853 perf_stat__collect_metric_expr(evsel_list); 1631 perf_stat__collect_metric_expr(evsel_list);
2854 perf_stat__init_shadow_stats(); 1632 perf_stat__init_shadow_stats();
2855 1633
2856 if (csv_sep) { 1634 if (stat_config.csv_sep) {
2857 csv_output = true; 1635 stat_config.csv_output = true;
2858 if (!strcmp(csv_sep, "\\t")) 1636 if (!strcmp(stat_config.csv_sep, "\\t"))
2859 csv_sep = "\t"; 1637 stat_config.csv_sep = "\t";
2860 } else 1638 } else
2861 csv_sep = DEFAULT_SEPARATOR; 1639 stat_config.csv_sep = DEFAULT_SEPARATOR;
2862 1640
2863 if (argc && !strncmp(argv[0], "rec", 3)) { 1641 if (argc && !strncmp(argv[0], "rec", 3)) {
2864 argc = __cmd_record(argc, argv); 1642 argc = __cmd_record(argc, argv);
@@ -2883,17 +1661,17 @@ int cmd_stat(int argc, const char **argv)
2883 goto out; 1661 goto out;
2884 } 1662 }
2885 1663
2886 if (metric_only && stat_config.aggr_mode == AGGR_THREAD) { 1664 if (stat_config.metric_only && stat_config.aggr_mode == AGGR_THREAD) {
2887 fprintf(stderr, "--metric-only is not supported with --per-thread\n"); 1665 fprintf(stderr, "--metric-only is not supported with --per-thread\n");
2888 goto out; 1666 goto out;
2889 } 1667 }
2890 1668
2891 if (metric_only && run_count > 1) { 1669 if (stat_config.metric_only && stat_config.run_count > 1) {
2892 fprintf(stderr, "--metric-only is not supported with -r\n"); 1670 fprintf(stderr, "--metric-only is not supported with -r\n");
2893 goto out; 1671 goto out;
2894 } 1672 }
2895 1673
2896 if (walltime_run_table && run_count <= 1) { 1674 if (stat_config.walltime_run_table && stat_config.run_count <= 1) {
2897 fprintf(stderr, "--table is only supported with -r\n"); 1675 fprintf(stderr, "--table is only supported with -r\n");
2898 parse_options_usage(stat_usage, stat_options, "r", 1); 1676 parse_options_usage(stat_usage, stat_options, "r", 1);
2899 parse_options_usage(NULL, stat_options, "table", 0); 1677 parse_options_usage(NULL, stat_options, "table", 0);
@@ -2931,7 +1709,7 @@ int cmd_stat(int argc, const char **argv)
2931 /* 1709 /*
2932 * let the spreadsheet do the pretty-printing 1710 * let the spreadsheet do the pretty-printing
2933 */ 1711 */
2934 if (csv_output) { 1712 if (stat_config.csv_output) {
2935 /* User explicitly passed -B? */ 1713 /* User explicitly passed -B? */
2936 if (big_num_opt == 1) { 1714 if (big_num_opt == 1) {
2937 fprintf(stderr, "-B option not supported with -x\n"); 1715 fprintf(stderr, "-B option not supported with -x\n");
@@ -2939,9 +1717,9 @@ int cmd_stat(int argc, const char **argv)
2939 parse_options_usage(NULL, stat_options, "x", 1); 1717 parse_options_usage(NULL, stat_options, "x", 1);
2940 goto out; 1718 goto out;
2941 } else /* Nope, so disable big number formatting */ 1719 } else /* Nope, so disable big number formatting */
2942 big_num = false; 1720 stat_config.big_num = false;
2943 } else if (big_num_opt == 0) /* User passed --no-big-num */ 1721 } else if (big_num_opt == 0) /* User passed --no-big-num */
2944 big_num = false; 1722 stat_config.big_num = false;
2945 1723
2946 setup_system_wide(argc); 1724 setup_system_wide(argc);
2947 1725
@@ -2949,21 +1727,21 @@ int cmd_stat(int argc, const char **argv)
2949 * Display user/system times only for single 1727 * Display user/system times only for single
2950 * run and when there's specified tracee. 1728 * run and when there's specified tracee.
2951 */ 1729 */
2952 if ((run_count == 1) && target__none(&target)) 1730 if ((stat_config.run_count == 1) && target__none(&target))
2953 ru_display = true; 1731 stat_config.ru_display = true;
2954 1732
2955 if (run_count < 0) { 1733 if (stat_config.run_count < 0) {
2956 pr_err("Run count must be a positive number\n"); 1734 pr_err("Run count must be a positive number\n");
2957 parse_options_usage(stat_usage, stat_options, "r", 1); 1735 parse_options_usage(stat_usage, stat_options, "r", 1);
2958 goto out; 1736 goto out;
2959 } else if (run_count == 0) { 1737 } else if (stat_config.run_count == 0) {
2960 forever = true; 1738 forever = true;
2961 run_count = 1; 1739 stat_config.run_count = 1;
2962 } 1740 }
2963 1741
2964 if (walltime_run_table) { 1742 if (stat_config.walltime_run_table) {
2965 walltime_run = zalloc(run_count * sizeof(walltime_run[0])); 1743 stat_config.walltime_run = zalloc(stat_config.run_count * sizeof(stat_config.walltime_run[0]));
2966 if (!walltime_run) { 1744 if (!stat_config.walltime_run) {
2967 pr_err("failed to setup -r option"); 1745 pr_err("failed to setup -r option");
2968 goto out; 1746 goto out;
2969 } 1747 }
@@ -3066,6 +1844,17 @@ int cmd_stat(int argc, const char **argv)
3066 goto out; 1844 goto out;
3067 1845
3068 /* 1846 /*
1847 * Set sample_type to PERF_SAMPLE_IDENTIFIER, which should be harmless
1848 * while avoiding that older tools show confusing messages.
1849 *
1850 * However for pipe sessions we need to keep it zero,
1851 * because script's perf_evsel__check_attr is triggered
1852 * by attr->sample_type != 0, and we can't run it on
1853 * stat sessions.
1854 */
1855 stat_config.identifier = !(STAT_RECORD && perf_stat.data.is_pipe);
1856
1857 /*
3069 * We dont want to block the signals - that would cause 1858 * We dont want to block the signals - that would cause
3070 * child tasks to inherit that and Ctrl-C would not work. 1859 * child tasks to inherit that and Ctrl-C would not work.
3071 * What we want is for Ctrl-C to work in the exec()-ed 1860 * What we want is for Ctrl-C to work in the exec()-ed
@@ -3079,8 +1868,8 @@ int cmd_stat(int argc, const char **argv)
3079 signal(SIGABRT, skip_signal); 1868 signal(SIGABRT, skip_signal);
3080 1869
3081 status = 0; 1870 status = 0;
3082 for (run_idx = 0; forever || run_idx < run_count; run_idx++) { 1871 for (run_idx = 0; forever || run_idx < stat_config.run_count; run_idx++) {
3083 if (run_count != 1 && verbose > 0) 1872 if (stat_config.run_count != 1 && verbose > 0)
3084 fprintf(output, "[ perf stat: executing run #%d ... ]\n", 1873 fprintf(output, "[ perf stat: executing run #%d ... ]\n",
3085 run_idx + 1); 1874 run_idx + 1);
3086 1875
@@ -3132,7 +1921,7 @@ int cmd_stat(int argc, const char **argv)
3132 perf_stat__exit_aggr_mode(); 1921 perf_stat__exit_aggr_mode();
3133 perf_evlist__free_stats(evsel_list); 1922 perf_evlist__free_stats(evsel_list);
3134out: 1923out:
3135 free(walltime_run); 1924 free(stat_config.walltime_run);
3136 1925
3137 if (smi_cost && smi_reset) 1926 if (smi_cost && smi_reset)
3138 sysfs__write_int(FREEZE_ON_SMI_PATH, 0); 1927 sysfs__write_int(FREEZE_ON_SMI_PATH, 0);
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index d21d8751e749..b2838de13de0 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -1134,11 +1134,6 @@ static int __cmd_top(struct perf_top *top)
1134 if (!target__none(&opts->target)) 1134 if (!target__none(&opts->target))
1135 perf_evlist__enable(top->evlist); 1135 perf_evlist__enable(top->evlist);
1136 1136
1137 /* Wait for a minimal set of events before starting the snapshot */
1138 perf_evlist__poll(top->evlist, 100);
1139
1140 perf_top__mmap_read(top);
1141
1142 ret = -1; 1137 ret = -1;
1143 if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui : 1138 if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui :
1144 display_thread), top)) { 1139 display_thread), top)) {
@@ -1156,6 +1151,11 @@ static int __cmd_top(struct perf_top *top)
1156 } 1151 }
1157 } 1152 }
1158 1153
1154 /* Wait for a minimal set of events before starting the snapshot */
1155 perf_evlist__poll(top->evlist, 100);
1156
1157 perf_top__mmap_read(top);
1158
1159 while (!done) { 1159 while (!done) {
1160 u64 hits = top->samples; 1160 u64 hits = top->samples;
1161 1161
@@ -1257,7 +1257,14 @@ int cmd_top(int argc, const char **argv)
1257 .uses_mmap = true, 1257 .uses_mmap = true,
1258 }, 1258 },
1259 .proc_map_timeout = 500, 1259 .proc_map_timeout = 500,
1260 .overwrite = 1, 1260 /*
1261 * FIXME: This will lose PERF_RECORD_MMAP and other metadata
1262 * when we pause, fix that and reenable. Probably using a
1263 * separate evlist with a dummy event, i.e. a non-overwrite
1264 * ring buffer just for metadata events, while PERF_RECORD_SAMPLE
1265 * stays in overwrite mode. -acme
1266 * */
1267 .overwrite = 0,
1261 }, 1268 },
1262 .max_stack = sysctl__max_stack(), 1269 .max_stack = sysctl__max_stack(),
1263 .annotation_opts = annotation__default_options, 1270 .annotation_opts = annotation__default_options,
@@ -1372,6 +1379,8 @@ int cmd_top(int argc, const char **argv)
1372 "Show raw trace event output (do not use print fmt or plugins)"), 1379 "Show raw trace event output (do not use print fmt or plugins)"),
1373 OPT_BOOLEAN(0, "hierarchy", &symbol_conf.report_hierarchy, 1380 OPT_BOOLEAN(0, "hierarchy", &symbol_conf.report_hierarchy,
1374 "Show entries in a hierarchy"), 1381 "Show entries in a hierarchy"),
1382 OPT_BOOLEAN(0, "overwrite", &top.record_opts.overwrite,
1383 "Use a backward ring buffer, default: no"),
1375 OPT_BOOLEAN(0, "force", &symbol_conf.force, "don't complain, do it"), 1384 OPT_BOOLEAN(0, "force", &symbol_conf.force, "don't complain, do it"),
1376 OPT_UINTEGER(0, "num-thread-synthesize", &top.nr_threads_synthesize, 1385 OPT_UINTEGER(0, "num-thread-synthesize", &top.nr_threads_synthesize,
1377 "number of thread to run event synthesize"), 1386 "number of thread to run event synthesize"),
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 22ab8e67c760..dc8a6c4986ce 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -89,6 +89,8 @@ struct trace {
89 u64 base_time; 89 u64 base_time;
90 FILE *output; 90 FILE *output;
91 unsigned long nr_events; 91 unsigned long nr_events;
92 unsigned long nr_events_printed;
93 unsigned long max_events;
92 struct strlist *ev_qualifier; 94 struct strlist *ev_qualifier;
93 struct { 95 struct {
94 size_t nr; 96 size_t nr;
@@ -181,7 +183,7 @@ static int __tp_field__init_uint(struct tp_field *field, int size, int offset, b
181 return 0; 183 return 0;
182} 184}
183 185
184static int tp_field__init_uint(struct tp_field *field, struct format_field *format_field, bool needs_swap) 186static int tp_field__init_uint(struct tp_field *field, struct tep_format_field *format_field, bool needs_swap)
185{ 187{
186 return __tp_field__init_uint(field, format_field->size, format_field->offset, needs_swap); 188 return __tp_field__init_uint(field, format_field->size, format_field->offset, needs_swap);
187} 189}
@@ -198,7 +200,7 @@ static int __tp_field__init_ptr(struct tp_field *field, int offset)
198 return 0; 200 return 0;
199} 201}
200 202
201static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field) 203static int tp_field__init_ptr(struct tp_field *field, struct tep_format_field *format_field)
202{ 204{
203 return __tp_field__init_ptr(field, format_field->offset); 205 return __tp_field__init_ptr(field, format_field->offset);
204} 206}
@@ -214,7 +216,7 @@ static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
214 struct tp_field *field, 216 struct tp_field *field,
215 const char *name) 217 const char *name)
216{ 218{
217 struct format_field *format_field = perf_evsel__field(evsel, name); 219 struct tep_format_field *format_field = perf_evsel__field(evsel, name);
218 220
219 if (format_field == NULL) 221 if (format_field == NULL)
220 return -1; 222 return -1;
@@ -230,7 +232,7 @@ static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
230 struct tp_field *field, 232 struct tp_field *field,
231 const char *name) 233 const char *name)
232{ 234{
233 struct format_field *format_field = perf_evsel__field(evsel, name); 235 struct tep_format_field *format_field = perf_evsel__field(evsel, name);
234 236
235 if (format_field == NULL) 237 if (format_field == NULL)
236 return -1; 238 return -1;
@@ -288,6 +290,13 @@ static int perf_evsel__init_augmented_syscall_tp_args(struct perf_evsel *evsel)
288 return __tp_field__init_ptr(&sc->args, sc->id.offset + sizeof(u64)); 290 return __tp_field__init_ptr(&sc->args, sc->id.offset + sizeof(u64));
289} 291}
290 292
293static int perf_evsel__init_augmented_syscall_tp_ret(struct perf_evsel *evsel)
294{
295 struct syscall_tp *sc = evsel->priv;
296
297 return __tp_field__init_uint(&sc->ret, sizeof(u64), sc->id.offset + sizeof(u64), evsel->needs_swap);
298}
299
291static int perf_evsel__init_raw_syscall_tp(struct perf_evsel *evsel, void *handler) 300static int perf_evsel__init_raw_syscall_tp(struct perf_evsel *evsel, void *handler)
292{ 301{
293 evsel->priv = malloc(sizeof(struct syscall_tp)); 302 evsel->priv = malloc(sizeof(struct syscall_tp));
@@ -498,16 +507,6 @@ static const char *clockid[] = {
498}; 507};
499static DEFINE_STRARRAY(clockid); 508static DEFINE_STRARRAY(clockid);
500 509
501static const char *socket_families[] = {
502 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
503 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
504 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
505 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
506 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
507 "ALG", "NFC", "VSOCK",
508};
509static DEFINE_STRARRAY(socket_families);
510
511static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size, 510static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
512 struct syscall_arg *arg) 511 struct syscall_arg *arg)
513{ 512{
@@ -615,6 +614,7 @@ static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
615 614
616struct syscall_arg_fmt { 615struct syscall_arg_fmt {
617 size_t (*scnprintf)(char *bf, size_t size, struct syscall_arg *arg); 616 size_t (*scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
617 unsigned long (*mask_val)(struct syscall_arg *arg, unsigned long val);
618 void *parm; 618 void *parm;
619 const char *name; 619 const char *name;
620 bool show_zero; 620 bool show_zero;
@@ -631,6 +631,8 @@ static struct syscall_fmt {
631} syscall_fmts[] = { 631} syscall_fmts[] = {
632 { .name = "access", 632 { .name = "access",
633 .arg = { [1] = { .scnprintf = SCA_ACCMODE, /* mode */ }, }, }, 633 .arg = { [1] = { .scnprintf = SCA_ACCMODE, /* mode */ }, }, },
634 { .name = "bind",
635 .arg = { [1] = { .scnprintf = SCA_SOCKADDR, /* umyaddr */ }, }, },
634 { .name = "bpf", 636 { .name = "bpf",
635 .arg = { [0] = STRARRAY(cmd, bpf_cmd), }, }, 637 .arg = { [0] = STRARRAY(cmd, bpf_cmd), }, },
636 { .name = "brk", .hexret = true, 638 { .name = "brk", .hexret = true,
@@ -645,6 +647,8 @@ static struct syscall_fmt {
645 [4] = { .name = "tls", .scnprintf = SCA_HEX, }, }, }, 647 [4] = { .name = "tls", .scnprintf = SCA_HEX, }, }, },
646 { .name = "close", 648 { .name = "close",
647 .arg = { [0] = { .scnprintf = SCA_CLOSE_FD, /* fd */ }, }, }, 649 .arg = { [0] = { .scnprintf = SCA_CLOSE_FD, /* fd */ }, }, },
650 { .name = "connect",
651 .arg = { [1] = { .scnprintf = SCA_SOCKADDR, /* servaddr */ }, }, },
648 { .name = "epoll_ctl", 652 { .name = "epoll_ctl",
649 .arg = { [1] = STRARRAY(op, epoll_ctl_ops), }, }, 653 .arg = { [1] = STRARRAY(op, epoll_ctl_ops), }, },
650 { .name = "eventfd2", 654 { .name = "eventfd2",
@@ -722,6 +726,10 @@ static struct syscall_fmt {
722 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, 726 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ },
723 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ }, 727 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ },
724 [3] = { .scnprintf = SCA_MMAP_FLAGS, /* flags */ }, }, }, 728 [3] = { .scnprintf = SCA_MMAP_FLAGS, /* flags */ }, }, },
729 { .name = "mount",
730 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* dev_name */ },
731 [3] = { .scnprintf = SCA_MOUNT_FLAGS, /* flags */
732 .mask_val = SCAMV_MOUNT_FLAGS, /* flags */ }, }, },
725 { .name = "mprotect", 733 { .name = "mprotect",
726 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ }, 734 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
727 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ }, }, }, 735 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ }, }, },
@@ -801,7 +809,8 @@ static struct syscall_fmt {
801 { .name = "sendmsg", 809 { .name = "sendmsg",
802 .arg = { [2] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, }, 810 .arg = { [2] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
803 { .name = "sendto", 811 { .name = "sendto",
804 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, }, 812 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ },
813 [4] = { .scnprintf = SCA_SOCKADDR, /* addr */ }, }, },
805 { .name = "set_tid_address", .errpid = true, }, 814 { .name = "set_tid_address", .errpid = true, },
806 { .name = "setitimer", 815 { .name = "setitimer",
807 .arg = { [0] = STRARRAY(which, itimers), }, }, 816 .arg = { [0] = STRARRAY(which, itimers), }, },
@@ -830,6 +839,8 @@ static struct syscall_fmt {
830 .arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, }, 839 .arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
831 { .name = "tkill", 840 { .name = "tkill",
832 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, }, 841 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
842 { .name = "umount2", .alias = "umount",
843 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* name */ }, }, },
833 { .name = "uname", .alias = "newuname", }, 844 { .name = "uname", .alias = "newuname", },
834 { .name = "unlinkat", 845 { .name = "unlinkat",
835 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, }, 846 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
@@ -853,16 +864,30 @@ static struct syscall_fmt *syscall_fmt__find(const char *name)
853 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp); 864 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
854} 865}
855 866
867static struct syscall_fmt *syscall_fmt__find_by_alias(const char *alias)
868{
869 int i, nmemb = ARRAY_SIZE(syscall_fmts);
870
871 for (i = 0; i < nmemb; ++i) {
872 if (syscall_fmts[i].alias && strcmp(syscall_fmts[i].alias, alias) == 0)
873 return &syscall_fmts[i];
874 }
875
876 return NULL;
877}
878
856/* 879/*
857 * is_exit: is this "exit" or "exit_group"? 880 * is_exit: is this "exit" or "exit_group"?
858 * is_open: is this "open" or "openat"? To associate the fd returned in sys_exit with the pathname in sys_enter. 881 * is_open: is this "open" or "openat"? To associate the fd returned in sys_exit with the pathname in sys_enter.
882 * args_size: sum of the sizes of the syscall arguments, anything after that is augmented stuff: pathname for openat, etc.
859 */ 883 */
860struct syscall { 884struct syscall {
861 struct event_format *tp_format; 885 struct tep_event_format *tp_format;
862 int nr_args; 886 int nr_args;
887 int args_size;
863 bool is_exit; 888 bool is_exit;
864 bool is_open; 889 bool is_open;
865 struct format_field *args; 890 struct tep_format_field *args;
866 const char *name; 891 const char *name;
867 struct syscall_fmt *fmt; 892 struct syscall_fmt *fmt;
868 struct syscall_arg_fmt *arg_fmt; 893 struct syscall_arg_fmt *arg_fmt;
@@ -1095,11 +1120,21 @@ static void thread__set_filename_pos(struct thread *thread, const char *bf,
1095 ttrace->filename.entry_str_pos = bf - ttrace->entry_str; 1120 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1096} 1121}
1097 1122
1123static size_t syscall_arg__scnprintf_augmented_string(struct syscall_arg *arg, char *bf, size_t size)
1124{
1125 struct augmented_arg *augmented_arg = arg->augmented.args;
1126
1127 return scnprintf(bf, size, "%.*s", augmented_arg->size, augmented_arg->value);
1128}
1129
1098static size_t syscall_arg__scnprintf_filename(char *bf, size_t size, 1130static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1099 struct syscall_arg *arg) 1131 struct syscall_arg *arg)
1100{ 1132{
1101 unsigned long ptr = arg->val; 1133 unsigned long ptr = arg->val;
1102 1134
1135 if (arg->augmented.args)
1136 return syscall_arg__scnprintf_augmented_string(arg, bf, size);
1137
1103 if (!arg->trace->vfs_getname) 1138 if (!arg->trace->vfs_getname)
1104 return scnprintf(bf, size, "%#x", ptr); 1139 return scnprintf(bf, size, "%#x", ptr);
1105 1140
@@ -1142,11 +1177,9 @@ static void sig_handler(int sig)
1142 interrupted = sig == SIGINT; 1177 interrupted = sig == SIGINT;
1143} 1178}
1144 1179
1145static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread, 1180static size_t trace__fprintf_comm_tid(struct trace *trace, struct thread *thread, FILE *fp)
1146 u64 duration, bool duration_calculated, u64 tstamp, FILE *fp)
1147{ 1181{
1148 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp); 1182 size_t printed = 0;
1149 printed += fprintf_duration(duration, duration_calculated, fp);
1150 1183
1151 if (trace->multiple_threads) { 1184 if (trace->multiple_threads) {
1152 if (trace->show_comm) 1185 if (trace->show_comm)
@@ -1157,6 +1190,14 @@ static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thre
1157 return printed; 1190 return printed;
1158} 1191}
1159 1192
1193static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
1194 u64 duration, bool duration_calculated, u64 tstamp, FILE *fp)
1195{
1196 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
1197 printed += fprintf_duration(duration, duration_calculated, fp);
1198 return printed + trace__fprintf_comm_tid(trace, thread, fp);
1199}
1200
1160static int trace__process_event(struct trace *trace, struct machine *machine, 1201static int trace__process_event(struct trace *trace, struct machine *machine,
1161 union perf_event *event, struct perf_sample *sample) 1202 union perf_event *event, struct perf_sample *sample)
1162{ 1203{
@@ -1258,10 +1299,12 @@ static int syscall__alloc_arg_fmts(struct syscall *sc, int nr_args)
1258 1299
1259static int syscall__set_arg_fmts(struct syscall *sc) 1300static int syscall__set_arg_fmts(struct syscall *sc)
1260{ 1301{
1261 struct format_field *field; 1302 struct tep_format_field *field, *last_field = NULL;
1262 int idx = 0, len; 1303 int idx = 0, len;
1263 1304
1264 for (field = sc->args; field; field = field->next, ++idx) { 1305 for (field = sc->args; field; field = field->next, ++idx) {
1306 last_field = field;
1307
1265 if (sc->fmt && sc->fmt->arg[idx].scnprintf) 1308 if (sc->fmt && sc->fmt->arg[idx].scnprintf)
1266 continue; 1309 continue;
1267 1310
@@ -1270,7 +1313,7 @@ static int syscall__set_arg_fmts(struct syscall *sc)
1270 strcmp(field->name, "path") == 0 || 1313 strcmp(field->name, "path") == 0 ||
1271 strcmp(field->name, "pathname") == 0)) 1314 strcmp(field->name, "pathname") == 0))
1272 sc->arg_fmt[idx].scnprintf = SCA_FILENAME; 1315 sc->arg_fmt[idx].scnprintf = SCA_FILENAME;
1273 else if (field->flags & FIELD_IS_POINTER) 1316 else if (field->flags & TEP_FIELD_IS_POINTER)
1274 sc->arg_fmt[idx].scnprintf = syscall_arg__scnprintf_hex; 1317 sc->arg_fmt[idx].scnprintf = syscall_arg__scnprintf_hex;
1275 else if (strcmp(field->type, "pid_t") == 0) 1318 else if (strcmp(field->type, "pid_t") == 0)
1276 sc->arg_fmt[idx].scnprintf = SCA_PID; 1319 sc->arg_fmt[idx].scnprintf = SCA_PID;
@@ -1292,6 +1335,9 @@ static int syscall__set_arg_fmts(struct syscall *sc)
1292 } 1335 }
1293 } 1336 }
1294 1337
1338 if (last_field)
1339 sc->args_size = last_field->offset + last_field->size;
1340
1295 return 0; 1341 return 0;
1296} 1342}
1297 1343
@@ -1459,6 +1505,19 @@ static size_t syscall__scnprintf_name(struct syscall *sc, char *bf, size_t size,
1459 return scnprintf(bf, size, "arg%d: ", arg->idx); 1505 return scnprintf(bf, size, "arg%d: ", arg->idx);
1460} 1506}
1461 1507
1508/*
1509 * Check if the value is in fact zero, i.e. mask whatever needs masking, such
1510 * as mount 'flags' argument that needs ignoring some magic flag, see comment
1511 * in tools/perf/trace/beauty/mount_flags.c
1512 */
1513static unsigned long syscall__mask_val(struct syscall *sc, struct syscall_arg *arg, unsigned long val)
1514{
1515 if (sc->arg_fmt && sc->arg_fmt[arg->idx].mask_val)
1516 return sc->arg_fmt[arg->idx].mask_val(arg, val);
1517
1518 return val;
1519}
1520
1462static size_t syscall__scnprintf_val(struct syscall *sc, char *bf, size_t size, 1521static size_t syscall__scnprintf_val(struct syscall *sc, char *bf, size_t size,
1463 struct syscall_arg *arg, unsigned long val) 1522 struct syscall_arg *arg, unsigned long val)
1464{ 1523{
@@ -1472,14 +1531,18 @@ static size_t syscall__scnprintf_val(struct syscall *sc, char *bf, size_t size,
1472} 1531}
1473 1532
1474static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size, 1533static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
1475 unsigned char *args, struct trace *trace, 1534 unsigned char *args, void *augmented_args, int augmented_args_size,
1476 struct thread *thread) 1535 struct trace *trace, struct thread *thread)
1477{ 1536{
1478 size_t printed = 0; 1537 size_t printed = 0;
1479 unsigned long val; 1538 unsigned long val;
1480 u8 bit = 1; 1539 u8 bit = 1;
1481 struct syscall_arg arg = { 1540 struct syscall_arg arg = {
1482 .args = args, 1541 .args = args,
1542 .augmented = {
1543 .size = augmented_args_size,
1544 .args = augmented_args,
1545 },
1483 .idx = 0, 1546 .idx = 0,
1484 .mask = 0, 1547 .mask = 0,
1485 .trace = trace, 1548 .trace = trace,
@@ -1495,7 +1558,7 @@ static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
1495 ttrace->ret_scnprintf = NULL; 1558 ttrace->ret_scnprintf = NULL;
1496 1559
1497 if (sc->args != NULL) { 1560 if (sc->args != NULL) {
1498 struct format_field *field; 1561 struct tep_format_field *field;
1499 1562
1500 for (field = sc->args; field; 1563 for (field = sc->args; field;
1501 field = field->next, ++arg.idx, bit <<= 1) { 1564 field = field->next, ++arg.idx, bit <<= 1) {
@@ -1503,6 +1566,11 @@ static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
1503 continue; 1566 continue;
1504 1567
1505 val = syscall_arg__val(&arg, arg.idx); 1568 val = syscall_arg__val(&arg, arg.idx);
1569 /*
1570 * Some syscall args need some mask, most don't and
1571 * return val untouched.
1572 */
1573 val = syscall__mask_val(sc, &arg, val);
1506 1574
1507 /* 1575 /*
1508 * Suppress this argument if its value is zero and 1576 * Suppress this argument if its value is zero and
@@ -1634,6 +1702,8 @@ static int trace__printf_interrupted_entry(struct trace *trace)
1634 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str); 1702 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1635 ttrace->entry_pending = false; 1703 ttrace->entry_pending = false;
1636 1704
1705 ++trace->nr_events_printed;
1706
1637 return printed; 1707 return printed;
1638} 1708}
1639 1709
@@ -1654,6 +1724,17 @@ static int trace__fprintf_sample(struct trace *trace, struct perf_evsel *evsel,
1654 return printed; 1724 return printed;
1655} 1725}
1656 1726
1727static void *syscall__augmented_args(struct syscall *sc, struct perf_sample *sample, int *augmented_args_size)
1728{
1729 void *augmented_args = NULL;
1730
1731 *augmented_args_size = sample->raw_size - sc->args_size;
1732 if (*augmented_args_size > 0)
1733 augmented_args = sample->raw_data + sc->args_size;
1734
1735 return augmented_args;
1736}
1737
1657static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel, 1738static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1658 union perf_event *event __maybe_unused, 1739 union perf_event *event __maybe_unused,
1659 struct perf_sample *sample) 1740 struct perf_sample *sample)
@@ -1663,6 +1744,8 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1663 size_t printed = 0; 1744 size_t printed = 0;
1664 struct thread *thread; 1745 struct thread *thread;
1665 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1; 1746 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
1747 int augmented_args_size = 0;
1748 void *augmented_args = NULL;
1666 struct syscall *sc = trace__syscall_info(trace, evsel, id); 1749 struct syscall *sc = trace__syscall_info(trace, evsel, id);
1667 struct thread_trace *ttrace; 1750 struct thread_trace *ttrace;
1668 1751
@@ -1686,13 +1769,24 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1686 1769
1687 if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) 1770 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
1688 trace__printf_interrupted_entry(trace); 1771 trace__printf_interrupted_entry(trace);
1689 1772 /*
1773 * If this is raw_syscalls.sys_enter, then it always comes with the 6 possible
1774 * arguments, even if the syscall being handled, say "openat", uses only 4 arguments
1775 * this breaks syscall__augmented_args() check for augmented args, as we calculate
1776 * syscall->args_size using each syscalls:sys_enter_NAME tracefs format file,
1777 * so when handling, say the openat syscall, we end up getting 6 args for the
1778 * raw_syscalls:sys_enter event, when we expected just 4, we end up mistakenly
1779 * thinking that the extra 2 u64 args are the augmented filename, so just check
1780 * here and avoid using augmented syscalls when the evsel is the raw_syscalls one.
1781 */
1782 if (evsel != trace->syscalls.events.sys_enter)
1783 augmented_args = syscall__augmented_args(sc, sample, &augmented_args_size);
1690 ttrace->entry_time = sample->time; 1784 ttrace->entry_time = sample->time;
1691 msg = ttrace->entry_str; 1785 msg = ttrace->entry_str;
1692 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name); 1786 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
1693 1787
1694 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed, 1788 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
1695 args, trace, thread); 1789 args, augmented_args, augmented_args_size, trace, thread);
1696 1790
1697 if (sc->is_exit) { 1791 if (sc->is_exit) {
1698 if (!(trace->duration_filter || trace->summary_only || trace->failure_only || trace->min_stack)) { 1792 if (!(trace->duration_filter || trace->summary_only || trace->failure_only || trace->min_stack)) {
@@ -1723,7 +1817,8 @@ static int trace__fprintf_sys_enter(struct trace *trace, struct perf_evsel *evse
1723 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1; 1817 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
1724 struct syscall *sc = trace__syscall_info(trace, evsel, id); 1818 struct syscall *sc = trace__syscall_info(trace, evsel, id);
1725 char msg[1024]; 1819 char msg[1024];
1726 void *args; 1820 void *args, *augmented_args = NULL;
1821 int augmented_args_size;
1727 1822
1728 if (sc == NULL) 1823 if (sc == NULL)
1729 return -1; 1824 return -1;
@@ -1738,7 +1833,8 @@ static int trace__fprintf_sys_enter(struct trace *trace, struct perf_evsel *evse
1738 goto out_put; 1833 goto out_put;
1739 1834
1740 args = perf_evsel__sc_tp_ptr(evsel, args, sample); 1835 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
1741 syscall__scnprintf_args(sc, msg, sizeof(msg), args, trace, thread); 1836 augmented_args = syscall__augmented_args(sc, sample, &augmented_args_size);
1837 syscall__scnprintf_args(sc, msg, sizeof(msg), args, augmented_args, augmented_args_size, trace, thread);
1742 fprintf(trace->output, "%s", msg); 1838 fprintf(trace->output, "%s", msg);
1743 err = 0; 1839 err = 0;
1744out_put: 1840out_put:
@@ -1754,12 +1850,14 @@ static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evse
1754 int max_stack = evsel->attr.sample_max_stack ? 1850 int max_stack = evsel->attr.sample_max_stack ?
1755 evsel->attr.sample_max_stack : 1851 evsel->attr.sample_max_stack :
1756 trace->max_stack; 1852 trace->max_stack;
1853 int err;
1757 1854
1758 if (machine__resolve(trace->host, &al, sample) < 0 || 1855 if (machine__resolve(trace->host, &al, sample) < 0)
1759 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, max_stack))
1760 return -1; 1856 return -1;
1761 1857
1762 return 0; 1858 err = thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, max_stack);
1859 addr_location__put(&al);
1860 return err;
1763} 1861}
1764 1862
1765static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample) 1863static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
@@ -1884,6 +1982,13 @@ errno_print: {
1884 1982
1885 fputc('\n', trace->output); 1983 fputc('\n', trace->output);
1886 1984
1985 /*
1986 * We only consider an 'event' for the sake of --max-events a non-filtered
1987 * sys_enter + sys_exit and other tracepoint events.
1988 */
1989 if (++trace->nr_events_printed == trace->max_events && trace->max_events != ULONG_MAX)
1990 interrupted = true;
1991
1887 if (callchain_ret > 0) 1992 if (callchain_ret > 0)
1888 trace__fprintf_callchain(trace, sample); 1993 trace__fprintf_callchain(trace, sample);
1889 else if (callchain_ret < 0) 1994 else if (callchain_ret < 0)
@@ -2016,13 +2121,25 @@ static void bpf_output__fprintf(struct trace *trace,
2016{ 2121{
2017 binary__fprintf(sample->raw_data, sample->raw_size, 8, 2122 binary__fprintf(sample->raw_data, sample->raw_size, 8,
2018 bpf_output__printer, NULL, trace->output); 2123 bpf_output__printer, NULL, trace->output);
2124 ++trace->nr_events_printed;
2019} 2125}
2020 2126
2021static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel, 2127static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
2022 union perf_event *event __maybe_unused, 2128 union perf_event *event __maybe_unused,
2023 struct perf_sample *sample) 2129 struct perf_sample *sample)
2024{ 2130{
2131 struct thread *thread;
2025 int callchain_ret = 0; 2132 int callchain_ret = 0;
2133 /*
2134 * Check if we called perf_evsel__disable(evsel) due to, for instance,
2135 * this event's max_events having been hit and this is an entry coming
2136 * from the ring buffer that we should discard, since the max events
2137 * have already been considered/printed.
2138 */
2139 if (evsel->disabled)
2140 return 0;
2141
2142 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2026 2143
2027 if (sample->callchain) { 2144 if (sample->callchain) {
2028 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor); 2145 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
@@ -2039,22 +2156,47 @@ static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
2039 if (trace->trace_syscalls) 2156 if (trace->trace_syscalls)
2040 fprintf(trace->output, "( ): "); 2157 fprintf(trace->output, "( ): ");
2041 2158
2159 if (thread)
2160 trace__fprintf_comm_tid(trace, thread, trace->output);
2161
2162 if (evsel == trace->syscalls.events.augmented) {
2163 int id = perf_evsel__sc_tp_uint(evsel, id, sample);
2164 struct syscall *sc = trace__syscall_info(trace, evsel, id);
2165
2166 if (sc) {
2167 fprintf(trace->output, "%s(", sc->name);
2168 trace__fprintf_sys_enter(trace, evsel, sample);
2169 fputc(')', trace->output);
2170 goto newline;
2171 }
2172
2173 /*
2174 * XXX: Not having the associated syscall info or not finding/adding
2175 * the thread should never happen, but if it does...
2176 * fall thru and print it as a bpf_output event.
2177 */
2178 }
2179
2042 fprintf(trace->output, "%s:", evsel->name); 2180 fprintf(trace->output, "%s:", evsel->name);
2043 2181
2044 if (perf_evsel__is_bpf_output(evsel)) { 2182 if (perf_evsel__is_bpf_output(evsel)) {
2045 if (evsel == trace->syscalls.events.augmented) 2183 bpf_output__fprintf(trace, sample);
2046 trace__fprintf_sys_enter(trace, evsel, sample);
2047 else
2048 bpf_output__fprintf(trace, sample);
2049 } else if (evsel->tp_format) { 2184 } else if (evsel->tp_format) {
2050 if (strncmp(evsel->tp_format->name, "sys_enter_", 10) || 2185 if (strncmp(evsel->tp_format->name, "sys_enter_", 10) ||
2051 trace__fprintf_sys_enter(trace, evsel, sample)) { 2186 trace__fprintf_sys_enter(trace, evsel, sample)) {
2052 event_format__fprintf(evsel->tp_format, sample->cpu, 2187 event_format__fprintf(evsel->tp_format, sample->cpu,
2053 sample->raw_data, sample->raw_size, 2188 sample->raw_data, sample->raw_size,
2054 trace->output); 2189 trace->output);
2190 ++trace->nr_events_printed;
2191
2192 if (evsel->max_events != ULONG_MAX && ++evsel->nr_events_printed == evsel->max_events) {
2193 perf_evsel__disable(evsel);
2194 perf_evsel__close(evsel);
2195 }
2055 } 2196 }
2056 } 2197 }
2057 2198
2199newline:
2058 fprintf(trace->output, "\n"); 2200 fprintf(trace->output, "\n");
2059 2201
2060 if (callchain_ret > 0) 2202 if (callchain_ret > 0)
@@ -2062,6 +2204,7 @@ static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
2062 else if (callchain_ret < 0) 2204 else if (callchain_ret < 0)
2063 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel)); 2205 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
2064out: 2206out:
2207 thread__put(thread);
2065 return 0; 2208 return 0;
2066} 2209}
2067 2210
@@ -2148,6 +2291,8 @@ static int trace__pgfault(struct trace *trace,
2148 trace__fprintf_callchain(trace, sample); 2291 trace__fprintf_callchain(trace, sample);
2149 else if (callchain_ret < 0) 2292 else if (callchain_ret < 0)
2150 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel)); 2293 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
2294
2295 ++trace->nr_events_printed;
2151out: 2296out:
2152 err = 0; 2297 err = 0;
2153out_put: 2298out_put:
@@ -2325,6 +2470,9 @@ static void trace__handle_event(struct trace *trace, union perf_event *event, st
2325 tracepoint_handler handler = evsel->handler; 2470 tracepoint_handler handler = evsel->handler;
2326 handler(trace, evsel, event, sample); 2471 handler(trace, evsel, event, sample);
2327 } 2472 }
2473
2474 if (trace->nr_events_printed >= trace->max_events && trace->max_events != ULONG_MAX)
2475 interrupted = true;
2328} 2476}
2329 2477
2330static int trace__add_syscall_newtp(struct trace *trace) 2478static int trace__add_syscall_newtp(struct trace *trace)
@@ -2629,7 +2777,7 @@ next_event:
2629 int timeout = done ? 100 : -1; 2777 int timeout = done ? 100 : -1;
2630 2778
2631 if (!draining && perf_evlist__poll(evlist, timeout) > 0) { 2779 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2632 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0) 2780 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP | POLLNVAL) == 0)
2633 draining = true; 2781 draining = true;
2634 2782
2635 goto again; 2783 goto again;
@@ -3061,6 +3209,7 @@ static int trace__parse_events_option(const struct option *opt, const char *str,
3061 int len = strlen(str) + 1, err = -1, list, idx; 3209 int len = strlen(str) + 1, err = -1, list, idx;
3062 char *strace_groups_dir = system_path(STRACE_GROUPS_DIR); 3210 char *strace_groups_dir = system_path(STRACE_GROUPS_DIR);
3063 char group_name[PATH_MAX]; 3211 char group_name[PATH_MAX];
3212 struct syscall_fmt *fmt;
3064 3213
3065 if (strace_groups_dir == NULL) 3214 if (strace_groups_dir == NULL)
3066 return -1; 3215 return -1;
@@ -3078,12 +3227,19 @@ static int trace__parse_events_option(const struct option *opt, const char *str,
3078 if (syscalltbl__id(trace->sctbl, s) >= 0 || 3227 if (syscalltbl__id(trace->sctbl, s) >= 0 ||
3079 syscalltbl__strglobmatch_first(trace->sctbl, s, &idx) >= 0) { 3228 syscalltbl__strglobmatch_first(trace->sctbl, s, &idx) >= 0) {
3080 list = 1; 3229 list = 1;
3230 goto do_concat;
3231 }
3232
3233 fmt = syscall_fmt__find_by_alias(s);
3234 if (fmt != NULL) {
3235 list = 1;
3236 s = fmt->name;
3081 } else { 3237 } else {
3082 path__join(group_name, sizeof(group_name), strace_groups_dir, s); 3238 path__join(group_name, sizeof(group_name), strace_groups_dir, s);
3083 if (access(group_name, R_OK) == 0) 3239 if (access(group_name, R_OK) == 0)
3084 list = 1; 3240 list = 1;
3085 } 3241 }
3086 3242do_concat:
3087 if (lists[list]) { 3243 if (lists[list]) {
3088 sprintf(lists[list] + strlen(lists[list]), ",%s", s); 3244 sprintf(lists[list] + strlen(lists[list]), ",%s", s);
3089 } else { 3245 } else {
@@ -3172,6 +3328,7 @@ int cmd_trace(int argc, const char **argv)
3172 .trace_syscalls = false, 3328 .trace_syscalls = false,
3173 .kernel_syscallchains = false, 3329 .kernel_syscallchains = false,
3174 .max_stack = UINT_MAX, 3330 .max_stack = UINT_MAX,
3331 .max_events = ULONG_MAX,
3175 }; 3332 };
3176 const char *output_name = NULL; 3333 const char *output_name = NULL;
3177 const struct option trace_options[] = { 3334 const struct option trace_options[] = {
@@ -3224,6 +3381,8 @@ int cmd_trace(int argc, const char **argv)
3224 &record_parse_callchain_opt), 3381 &record_parse_callchain_opt),
3225 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains, 3382 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
3226 "Show the kernel callchains on the syscall exit path"), 3383 "Show the kernel callchains on the syscall exit path"),
3384 OPT_ULONG(0, "max-events", &trace.max_events,
3385 "Set the maximum number of events to print, exit after that is reached. "),
3227 OPT_UINTEGER(0, "min-stack", &trace.min_stack, 3386 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
3228 "Set the minimum stack depth when parsing the callchain, " 3387 "Set the minimum stack depth when parsing the callchain, "
3229 "anything below the specified depth will be ignored."), 3388 "anything below the specified depth will be ignored."),
@@ -3276,12 +3435,8 @@ int cmd_trace(int argc, const char **argv)
3276 goto out; 3435 goto out;
3277 } 3436 }
3278 3437
3279 if (evsel) { 3438 if (evsel)
3280 if (perf_evsel__init_augmented_syscall_tp(evsel) ||
3281 perf_evsel__init_augmented_syscall_tp_args(evsel))
3282 goto out;
3283 trace.syscalls.events.augmented = evsel; 3439 trace.syscalls.events.augmented = evsel;
3284 }
3285 3440
3286 err = bpf__setup_stdout(trace.evlist); 3441 err = bpf__setup_stdout(trace.evlist);
3287 if (err) { 3442 if (err) {
@@ -3326,6 +3481,34 @@ int cmd_trace(int argc, const char **argv)
3326 } 3481 }
3327 } 3482 }
3328 3483
3484 /*
3485 * If we are augmenting syscalls, then combine what we put in the
3486 * __augmented_syscalls__ BPF map with what is in the
3487 * syscalls:sys_exit_FOO tracepoints, i.e. just like we do without BPF,
3488 * combining raw_syscalls:sys_enter with raw_syscalls:sys_exit.
3489 *
3490 * We'll switch to look at two BPF maps, one for sys_enter and the
3491 * other for sys_exit when we start augmenting the sys_exit paths with
3492 * buffers that are being copied from kernel to userspace, think 'read'
3493 * syscall.
3494 */
3495 if (trace.syscalls.events.augmented) {
3496 evsel = trace.syscalls.events.augmented;
3497
3498 if (perf_evsel__init_augmented_syscall_tp(evsel) ||
3499 perf_evsel__init_augmented_syscall_tp_args(evsel))
3500 goto out;
3501 evsel->handler = trace__sys_enter;
3502
3503 evlist__for_each_entry(trace.evlist, evsel) {
3504 if (strstarts(perf_evsel__name(evsel), "syscalls:sys_exit_")) {
3505 perf_evsel__init_augmented_syscall_tp(evsel);
3506 perf_evsel__init_augmented_syscall_tp_ret(evsel);
3507 evsel->handler = trace__sys_exit;
3508 }
3509 }
3510 }
3511
3329 if ((argc >= 1) && (strcmp(argv[0], "record") == 0)) 3512 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3330 return trace__record(&trace, argc-1, &argv[1]); 3513 return trace__record(&trace, argc-1, &argv[1]);
3331 3514
diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh
index 466540ee8ea7..9531f7bd7d9b 100755
--- a/tools/perf/check-headers.sh
+++ b/tools/perf/check-headers.sh
@@ -5,6 +5,7 @@ HEADERS='
5include/uapi/drm/drm.h 5include/uapi/drm/drm.h
6include/uapi/drm/i915_drm.h 6include/uapi/drm/i915_drm.h
7include/uapi/linux/fcntl.h 7include/uapi/linux/fcntl.h
8include/uapi/linux/fs.h
8include/uapi/linux/kcmp.h 9include/uapi/linux/kcmp.h
9include/uapi/linux/kvm.h 10include/uapi/linux/kvm.h
10include/uapi/linux/in.h 11include/uapi/linux/in.h
@@ -14,6 +15,7 @@ include/uapi/linux/sched.h
14include/uapi/linux/stat.h 15include/uapi/linux/stat.h
15include/uapi/linux/vhost.h 16include/uapi/linux/vhost.h
16include/uapi/sound/asound.h 17include/uapi/sound/asound.h
18include/linux/bits.h
17include/linux/hash.h 19include/linux/hash.h
18include/uapi/linux/hw_breakpoint.h 20include/uapi/linux/hw_breakpoint.h
19arch/x86/include/asm/disabled-features.h 21arch/x86/include/asm/disabled-features.h
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt
index 2d0caf20ff3a..bc6c585f74fc 100644
--- a/tools/perf/command-list.txt
+++ b/tools/perf/command-list.txt
@@ -30,3 +30,4 @@ perf-test mainporcelain common
30perf-timechart mainporcelain common 30perf-timechart mainporcelain common
31perf-top mainporcelain common 31perf-top mainporcelain common
32perf-trace mainporcelain audit 32perf-trace mainporcelain audit
33perf-version mainporcelain common
diff --git a/tools/perf/examples/bpf/augmented_syscalls.c b/tools/perf/examples/bpf/augmented_syscalls.c
index 69a31386d8cd..2ae44813ef2d 100644
--- a/tools/perf/examples/bpf/augmented_syscalls.c
+++ b/tools/perf/examples/bpf/augmented_syscalls.c
@@ -1,6 +1,6 @@
1// SPDX-License-Identifier: GPL-2.0 1// SPDX-License-Identifier: GPL-2.0
2/* 2/*
3 * Augment the openat syscall with the contents of the filename pointer argument. 3 * Augment syscalls with the contents of the pointer arguments.
4 * 4 *
5 * Test it with: 5 * Test it with:
6 * 6 *
@@ -10,15 +10,14 @@
10 * the last one should be the one for '/etc/passwd'. 10 * the last one should be the one for '/etc/passwd'.
11 * 11 *
12 * This matches what is marshalled into the raw_syscall:sys_enter payload 12 * This matches what is marshalled into the raw_syscall:sys_enter payload
13 * expected by the 'perf trace' beautifiers, and can be used by them unmodified, 13 * expected by the 'perf trace' beautifiers, and can be used by them, that will
14 * which will be done as that feature is implemented in the next csets, for now 14 * check if perf_sample->raw_data is more than what is expected for each
15 * it will appear in a dump done by the default tracepoint handler in 'perf trace', 15 * syscalls:sys_{enter,exit}_SYSCALL tracepoint, uing the extra data as the
16 * that uses bpf_output__fprintf() to just dump those contents, as done with 16 * contents of pointer arguments.
17 * the bpf-output event associated with the __bpf_output__ map declared in
18 * tools/perf/include/bpf/stdio.h.
19 */ 17 */
20 18
21#include <stdio.h> 19#include <stdio.h>
20#include <linux/socket.h>
22 21
23struct bpf_map SEC("maps") __augmented_syscalls__ = { 22struct bpf_map SEC("maps") __augmented_syscalls__ = {
24 .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY, 23 .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
@@ -27,6 +26,44 @@ struct bpf_map SEC("maps") __augmented_syscalls__ = {
27 .max_entries = __NR_CPUS__, 26 .max_entries = __NR_CPUS__,
28}; 27};
29 28
29struct syscall_exit_args {
30 unsigned long long common_tp_fields;
31 long syscall_nr;
32 long ret;
33};
34
35struct augmented_filename {
36 unsigned int size;
37 int reserved;
38 char value[256];
39};
40
41#define augmented_filename_syscall(syscall) \
42struct augmented_enter_##syscall##_args { \
43 struct syscall_enter_##syscall##_args args; \
44 struct augmented_filename filename; \
45}; \
46int syscall_enter(syscall)(struct syscall_enter_##syscall##_args *args) \
47{ \
48 struct augmented_enter_##syscall##_args augmented_args = { .filename.reserved = 0, }; \
49 unsigned int len = sizeof(augmented_args); \
50 probe_read(&augmented_args.args, sizeof(augmented_args.args), args); \
51 augmented_args.filename.size = probe_read_str(&augmented_args.filename.value, \
52 sizeof(augmented_args.filename.value), \
53 args->filename_ptr); \
54 if (augmented_args.filename.size < sizeof(augmented_args.filename.value)) { \
55 len -= sizeof(augmented_args.filename.value) - augmented_args.filename.size; \
56 len &= sizeof(augmented_args.filename.value) - 1; \
57 } \
58 perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU, \
59 &augmented_args, len); \
60 return 0; \
61} \
62int syscall_exit(syscall)(struct syscall_exit_args *args) \
63{ \
64 return 1; /* 0 as soon as we start copying data returned by the kernel, e.g. 'read' */ \
65}
66
30struct syscall_enter_openat_args { 67struct syscall_enter_openat_args {
31 unsigned long long common_tp_fields; 68 unsigned long long common_tp_fields;
32 long syscall_nr; 69 long syscall_nr;
@@ -36,20 +73,101 @@ struct syscall_enter_openat_args {
36 long mode; 73 long mode;
37}; 74};
38 75
39struct augmented_enter_openat_args { 76augmented_filename_syscall(openat);
40 struct syscall_enter_openat_args args; 77
41 char filename[64]; 78struct syscall_enter_open_args {
79 unsigned long long common_tp_fields;
80 long syscall_nr;
81 char *filename_ptr;
82 long flags;
83 long mode;
84};
85
86augmented_filename_syscall(open);
87
88struct syscall_enter_inotify_add_watch_args {
89 unsigned long long common_tp_fields;
90 long syscall_nr;
91 long fd;
92 char *filename_ptr;
93 long mask;
94};
95
96augmented_filename_syscall(inotify_add_watch);
97
98struct statbuf;
99
100struct syscall_enter_newstat_args {
101 unsigned long long common_tp_fields;
102 long syscall_nr;
103 char *filename_ptr;
104 struct stat *statbuf;
42}; 105};
43 106
44int syscall_enter(openat)(struct syscall_enter_openat_args *args) 107augmented_filename_syscall(newstat);
45{ 108
46 struct augmented_enter_openat_args augmented_args; 109#ifndef _K_SS_MAXSIZE
110#define _K_SS_MAXSIZE 128
111#endif
47 112
48 probe_read(&augmented_args.args, sizeof(augmented_args.args), args); 113#define augmented_sockaddr_syscall(syscall) \
49 probe_read_str(&augmented_args.filename, sizeof(augmented_args.filename), args->filename_ptr); 114struct augmented_enter_##syscall##_args { \
50 perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU, 115 struct syscall_enter_##syscall##_args args; \
51 &augmented_args, sizeof(augmented_args)); 116 struct sockaddr_storage addr; \
52 return 1; 117}; \
118int syscall_enter(syscall)(struct syscall_enter_##syscall##_args *args) \
119{ \
120 struct augmented_enter_##syscall##_args augmented_args; \
121 unsigned long addrlen = sizeof(augmented_args.addr); \
122 probe_read(&augmented_args.args, sizeof(augmented_args.args), args); \
123/* FIXME_CLANG_OPTIMIZATION_THAT_ACCESSES_USER_CONTROLLED_ADDRLEN_DESPITE_THIS_CHECK */ \
124/* if (addrlen > augmented_args.args.addrlen) */ \
125/* addrlen = augmented_args.args.addrlen; */ \
126/* */ \
127 probe_read(&augmented_args.addr, addrlen, args->addr_ptr); \
128 perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU, \
129 &augmented_args, \
130 sizeof(augmented_args) - sizeof(augmented_args.addr) + addrlen); \
131 return 0; \
132} \
133int syscall_exit(syscall)(struct syscall_exit_args *args) \
134{ \
135 return 1; /* 0 as soon as we start copying data returned by the kernel, e.g. 'read' */ \
53} 136}
54 137
138struct sockaddr;
139
140struct syscall_enter_bind_args {
141 unsigned long long common_tp_fields;
142 long syscall_nr;
143 long fd;
144 struct sockaddr *addr_ptr;
145 unsigned long addrlen;
146};
147
148augmented_sockaddr_syscall(bind);
149
150struct syscall_enter_connect_args {
151 unsigned long long common_tp_fields;
152 long syscall_nr;
153 long fd;
154 struct sockaddr *addr_ptr;
155 unsigned long addrlen;
156};
157
158augmented_sockaddr_syscall(connect);
159
160struct syscall_enter_sendto_args {
161 unsigned long long common_tp_fields;
162 long syscall_nr;
163 long fd;
164 void *buff;
165 long len;
166 unsigned long flags;
167 struct sockaddr *addr_ptr;
168 long addr_len;
169};
170
171augmented_sockaddr_syscall(sendto);
172
55license(GPL); 173license(GPL);
diff --git a/tools/perf/examples/bpf/etcsnoop.c b/tools/perf/examples/bpf/etcsnoop.c
new file mode 100644
index 000000000000..b59e8812ee8c
--- /dev/null
+++ b/tools/perf/examples/bpf/etcsnoop.c
@@ -0,0 +1,80 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Augment the filename syscalls with the contents of the filename pointer argument
4 * filtering only those that do not start with /etc/.
5 *
6 * Test it with:
7 *
8 * perf trace -e tools/perf/examples/bpf/augmented_syscalls.c cat /etc/passwd > /dev/null
9 *
10 * It'll catch some openat syscalls related to the dynamic linked and
11 * the last one should be the one for '/etc/passwd'.
12 *
13 * This matches what is marshalled into the raw_syscall:sys_enter payload
14 * expected by the 'perf trace' beautifiers, and can be used by them unmodified,
15 * which will be done as that feature is implemented in the next csets, for now
16 * it will appear in a dump done by the default tracepoint handler in 'perf trace',
17 * that uses bpf_output__fprintf() to just dump those contents, as done with
18 * the bpf-output event associated with the __bpf_output__ map declared in
19 * tools/perf/include/bpf/stdio.h.
20 */
21
22#include <stdio.h>
23
24struct bpf_map SEC("maps") __augmented_syscalls__ = {
25 .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
26 .key_size = sizeof(int),
27 .value_size = sizeof(u32),
28 .max_entries = __NR_CPUS__,
29};
30
31struct augmented_filename {
32 int size;
33 int reserved;
34 char value[64];
35};
36
37#define augmented_filename_syscall_enter(syscall) \
38struct augmented_enter_##syscall##_args { \
39 struct syscall_enter_##syscall##_args args; \
40 struct augmented_filename filename; \
41}; \
42int syscall_enter(syscall)(struct syscall_enter_##syscall##_args *args) \
43{ \
44 char etc[6] = "/etc/"; \
45 struct augmented_enter_##syscall##_args augmented_args = { .filename.reserved = 0, }; \
46 probe_read(&augmented_args.args, sizeof(augmented_args.args), args); \
47 augmented_args.filename.size = probe_read_str(&augmented_args.filename.value, \
48 sizeof(augmented_args.filename.value), \
49 args->filename_ptr); \
50 if (__builtin_memcmp(augmented_args.filename.value, etc, 4) != 0) \
51 return 0; \
52 perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU, \
53 &augmented_args, \
54 (sizeof(augmented_args) - sizeof(augmented_args.filename.value) + \
55 augmented_args.filename.size)); \
56 return 0; \
57}
58
59struct syscall_enter_openat_args {
60 unsigned long long common_tp_fields;
61 long syscall_nr;
62 long dfd;
63 char *filename_ptr;
64 long flags;
65 long mode;
66};
67
68augmented_filename_syscall_enter(openat);
69
70struct syscall_enter_open_args {
71 unsigned long long common_tp_fields;
72 long syscall_nr;
73 char *filename_ptr;
74 long flags;
75 long mode;
76};
77
78augmented_filename_syscall_enter(open);
79
80license(GPL);
diff --git a/tools/perf/include/bpf/bpf.h b/tools/perf/include/bpf/bpf.h
index 47897d65e799..52b6d87fe822 100644
--- a/tools/perf/include/bpf/bpf.h
+++ b/tools/perf/include/bpf/bpf.h
@@ -26,6 +26,9 @@ struct bpf_map {
26#define syscall_enter(name) \ 26#define syscall_enter(name) \
27 SEC("syscalls:sys_enter_" #name) syscall_enter_ ## name 27 SEC("syscalls:sys_enter_" #name) syscall_enter_ ## name
28 28
29#define syscall_exit(name) \
30 SEC("syscalls:sys_exit_" #name) syscall_exit_ ## name
31
29#define license(name) \ 32#define license(name) \
30char _license[] SEC("license") = #name; \ 33char _license[] SEC("license") = #name; \
31int _version SEC("version") = LINUX_VERSION_CODE; 34int _version SEC("version") = LINUX_VERSION_CODE;
diff --git a/tools/perf/include/bpf/linux/socket.h b/tools/perf/include/bpf/linux/socket.h
new file mode 100644
index 000000000000..7f844568dab8
--- /dev/null
+++ b/tools/perf/include/bpf/linux/socket.h
@@ -0,0 +1,24 @@
1/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
2#ifndef _UAPI_LINUX_SOCKET_H
3#define _UAPI_LINUX_SOCKET_H
4
5/*
6 * Desired design of maximum size and alignment (see RFC2553)
7 */
8#define _K_SS_MAXSIZE 128 /* Implementation specific max size */
9#define _K_SS_ALIGNSIZE (__alignof__ (struct sockaddr *))
10 /* Implementation specific desired alignment */
11
12typedef unsigned short __kernel_sa_family_t;
13
14struct __kernel_sockaddr_storage {
15 __kernel_sa_family_t ss_family; /* address family */
16 /* Following field(s) are implementation specific */
17 char __data[_K_SS_MAXSIZE - sizeof(unsigned short)];
18 /* space to achieve desired size, */
19 /* _SS_MAXSIZE value minus size of ss_family */
20} __attribute__ ((aligned(_K_SS_ALIGNSIZE))); /* force desired alignment */
21
22#define sockaddr_storage __kernel_sockaddr_storage
23
24#endif /* _UAPI_LINUX_SOCKET_H */
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 21bf7f5a3cf5..0ed4a34c74c4 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -81,6 +81,7 @@ struct record_opts {
81 unsigned initial_delay; 81 unsigned initial_delay;
82 bool use_clockid; 82 bool use_clockid;
83 clockid_t clockid; 83 clockid_t clockid;
84 u64 clockid_res_ns;
84 unsigned int proc_map_timeout; 85 unsigned int proc_map_timeout;
85}; 86};
86 87
diff --git a/tools/perf/pmu-events/arch/arm64/ampere/emag/branch.json b/tools/perf/pmu-events/arch/arm64/ampere/emag/branch.json
new file mode 100644
index 000000000000..abc98b018446
--- /dev/null
+++ b/tools/perf/pmu-events/arch/arm64/ampere/emag/branch.json
@@ -0,0 +1,23 @@
1[
2 {
3 "ArchStdEvent": "BR_IMMED_SPEC",
4 },
5 {
6 "ArchStdEvent": "BR_RETURN_SPEC",
7 },
8 {
9 "ArchStdEvent": "BR_INDIRECT_SPEC",
10 },
11 {
12 "PublicDescription": "Mispredicted or not predicted branch speculatively executed",
13 "EventCode": "0x10",
14 "EventName": "BR_MIS_PRED",
15 "BriefDescription": "Branch mispredicted"
16 },
17 {
18 "PublicDescription": "Predictable branch speculatively executed",
19 "EventCode": "0x12",
20 "EventName": "BR_PRED",
21 "BriefDescription": "Predictable branch"
22 },
23]
diff --git a/tools/perf/pmu-events/arch/arm64/ampere/emag/bus.json b/tools/perf/pmu-events/arch/arm64/ampere/emag/bus.json
new file mode 100644
index 000000000000..687b2629e1d1
--- /dev/null
+++ b/tools/perf/pmu-events/arch/arm64/ampere/emag/bus.json
@@ -0,0 +1,26 @@
1[
2 {
3 "ArchStdEvent": "BUS_ACCESS_RD",
4 },
5 {
6 "ArchStdEvent": "BUS_ACCESS_WR",
7 },
8 {
9 "ArchStdEvent": "BUS_ACCESS_SHARED",
10 },
11 {
12 "ArchStdEvent": "BUS_ACCESS_NOT_SHARED",
13 },
14 {
15 "ArchStdEvent": "BUS_ACCESS_NORMAL",
16 },
17 {
18 "ArchStdEvent": "BUS_ACCESS_PERIPH",
19 },
20 {
21 "PublicDescription": "Bus access",
22 "EventCode": "0x19",
23 "EventName": "BUS_ACCESS",
24 "BriefDescription": "Bus access"
25 },
26]
diff --git a/tools/perf/pmu-events/arch/arm64/ampere/emag/cache.json b/tools/perf/pmu-events/arch/arm64/ampere/emag/cache.json
new file mode 100644
index 000000000000..df9201434cb6
--- /dev/null
+++ b/tools/perf/pmu-events/arch/arm64/ampere/emag/cache.json
@@ -0,0 +1,191 @@
1[
2 {
3 "ArchStdEvent": "L1D_CACHE_RD",
4 },
5 {
6 "ArchStdEvent": "L1D_CACHE_WR",
7 },
8 {
9 "ArchStdEvent": "L1D_CACHE_REFILL_RD",
10 },
11 {
12 "ArchStdEvent": "L1D_CACHE_INVAL",
13 },
14 {
15 "ArchStdEvent": "L1D_TLB_REFILL_RD",
16 },
17 {
18 "ArchStdEvent": "L1D_TLB_REFILL_WR",
19 },
20 {
21 "ArchStdEvent": "L2D_CACHE_RD",
22 },
23 {
24 "ArchStdEvent": "L2D_CACHE_WR",
25 },
26 {
27 "ArchStdEvent": "L2D_CACHE_REFILL_RD",
28 },
29 {
30 "ArchStdEvent": "L2D_CACHE_REFILL_WR",
31 },
32 {
33 "ArchStdEvent": "L2D_CACHE_WB_VICTIM",
34 },
35 {
36 "ArchStdEvent": "L2D_CACHE_WB_CLEAN",
37 },
38 {
39 "ArchStdEvent": "L2D_CACHE_INVAL",
40 },
41 {
42 "PublicDescription": "Level 1 instruction cache refill",
43 "EventCode": "0x01",
44 "EventName": "L1I_CACHE_REFILL",
45 "BriefDescription": "L1I cache refill"
46 },
47 {
48 "PublicDescription": "Level 1 instruction TLB refill",
49 "EventCode": "0x02",
50 "EventName": "L1I_TLB_REFILL",
51 "BriefDescription": "L1I TLB refill"
52 },
53 {
54 "PublicDescription": "Level 1 data cache refill",
55 "EventCode": "0x03",
56 "EventName": "L1D_CACHE_REFILL",
57 "BriefDescription": "L1D cache refill"
58 },
59 {
60 "PublicDescription": "Level 1 data cache access",
61 "EventCode": "0x04",
62 "EventName": "L1D_CACHE_ACCESS",
63 "BriefDescription": "L1D cache access"
64 },
65 {
66 "PublicDescription": "Level 1 data TLB refill",
67 "EventCode": "0x05",
68 "EventName": "L1D_TLB_REFILL",
69 "BriefDescription": "L1D TLB refill"
70 },
71 {
72 "PublicDescription": "Level 1 instruction cache access",
73 "EventCode": "0x14",
74 "EventName": "L1I_CACHE_ACCESS",
75 "BriefDescription": "L1I cache access"
76 },
77 {
78 "PublicDescription": "Level 2 data cache access",
79 "EventCode": "0x16",
80 "EventName": "L2D_CACHE_ACCESS",
81 "BriefDescription": "L2D cache access"
82 },
83 {
84 "PublicDescription": "Level 2 data refill",
85 "EventCode": "0x17",
86 "EventName": "L2D_CACHE_REFILL",
87 "BriefDescription": "L2D cache refill"
88 },
89 {
90 "PublicDescription": "Level 2 data cache, Write-Back",
91 "EventCode": "0x18",
92 "EventName": "L2D_CACHE_WB",
93 "BriefDescription": "L2D cache Write-Back"
94 },
95 {
96 "PublicDescription": "Level 1 data TLB access. This event counts any load or store operation which accesses the data L1 TLB",
97 "EventCode": "0x25",
98 "EventName": "L1D_TLB_ACCESS",
99 "BriefDescription": "L1D TLB access"
100 },
101 {
102 "PublicDescription": "Level 1 instruction TLB access. This event counts any instruction fetch which accesses the instruction L1 TLB",
103 "EventCode": "0x26",
104 "EventName": "L1I_TLB_ACCESS",
105 "BriefDescription": "L1I TLB access"
106 },
107 {
108 "PublicDescription": "Level 2 access to data TLB that caused a page table walk. This event counts on any data access which causes L2D_TLB_REFILL to count",
109 "EventCode": "0x34",
110 "EventName": "L2D_TLB_ACCESS",
111 "BriefDescription": "L2D TLB access"
112 },
113 {
114 "PublicDescription": "Level 2 access to instruciton TLB that caused a page table walk. This event counts on any instruciton access which causes L2I_TLB_REFILL to count",
115 "EventCode": "0x35",
116 "EventName": "L2I_TLB_ACCESS",
117 "BriefDescription": "L2D TLB access"
118 },
119 {
120 "PublicDescription": "Branch target buffer misprediction",
121 "EventCode": "0x102",
122 "EventName": "BTB_MIS_PRED",
123 "BriefDescription": "BTB misprediction"
124 },
125 {
126 "PublicDescription": "ITB miss",
127 "EventCode": "0x103",
128 "EventName": "ITB_MISS",
129 "BriefDescription": "ITB miss"
130 },
131 {
132 "PublicDescription": "DTB miss",
133 "EventCode": "0x104",
134 "EventName": "DTB_MISS",
135 "BriefDescription": "DTB miss"
136 },
137 {
138 "PublicDescription": "Level 1 data cache late miss",
139 "EventCode": "0x105",
140 "EventName": "L1D_CACHE_LATE_MISS",
141 "BriefDescription": "L1D cache late miss"
142 },
143 {
144 "PublicDescription": "Level 1 data cache prefetch request",
145 "EventCode": "0x106",
146 "EventName": "L1D_CACHE_PREFETCH",
147 "BriefDescription": "L1D cache prefetch"
148 },
149 {
150 "PublicDescription": "Level 2 data cache prefetch request",
151 "EventCode": "0x107",
152 "EventName": "L2D_CACHE_PREFETCH",
153 "BriefDescription": "L2D cache prefetch"
154 },
155 {
156 "PublicDescription": "Level 1 stage 2 TLB refill",
157 "EventCode": "0x111",
158 "EventName": "L1_STAGE2_TLB_REFILL",
159 "BriefDescription": "L1 stage 2 TLB refill"
160 },
161 {
162 "PublicDescription": "Page walk cache level-0 stage-1 hit",
163 "EventCode": "0x112",
164 "EventName": "PAGE_WALK_L0_STAGE1_HIT",
165 "BriefDescription": "Page walk, L0 stage-1 hit"
166 },
167 {
168 "PublicDescription": "Page walk cache level-1 stage-1 hit",
169 "EventCode": "0x113",
170 "EventName": "PAGE_WALK_L1_STAGE1_HIT",
171 "BriefDescription": "Page walk, L1 stage-1 hit"
172 },
173 {
174 "PublicDescription": "Page walk cache level-2 stage-1 hit",
175 "EventCode": "0x114",
176 "EventName": "PAGE_WALK_L2_STAGE1_HIT",
177 "BriefDescription": "Page walk, L2 stage-1 hit"
178 },
179 {
180 "PublicDescription": "Page walk cache level-1 stage-2 hit",
181 "EventCode": "0x115",
182 "EventName": "PAGE_WALK_L1_STAGE2_HIT",
183 "BriefDescription": "Page walk, L1 stage-2 hit"
184 },
185 {
186 "PublicDescription": "Page walk cache level-2 stage-2 hit",
187 "EventCode": "0x116",
188 "EventName": "PAGE_WALK_L2_STAGE2_HIT",
189 "BriefDescription": "Page walk, L2 stage-2 hit"
190 },
191]
diff --git a/tools/perf/pmu-events/arch/arm64/ampere/emag/clock.json b/tools/perf/pmu-events/arch/arm64/ampere/emag/clock.json
new file mode 100644
index 000000000000..38cd1f1a70dc
--- /dev/null
+++ b/tools/perf/pmu-events/arch/arm64/ampere/emag/clock.json
@@ -0,0 +1,20 @@
1[
2 {
3 "PublicDescription": "The number of core clock cycles",
4 "EventCode": "0x11",
5 "EventName": "CPU_CYCLES",
6 "BriefDescription": "Clock cycles"
7 },
8 {
9 "PublicDescription": "FSU clocking gated off cycle",
10 "EventCode": "0x101",
11 "EventName": "FSU_CLOCK_OFF_CYCLES",
12 "BriefDescription": "FSU clocking gated off cycle"
13 },
14 {
15 "PublicDescription": "Wait state cycle",
16 "EventCode": "0x110",
17 "EventName": "Wait_CYCLES",
18 "BriefDescription": "Wait state cycle"
19 },
20]
diff --git a/tools/perf/pmu-events/arch/arm64/ampere/emag/core-imp-def.json b/tools/perf/pmu-events/arch/arm64/ampere/emag/core-imp-def.json
deleted file mode 100644
index bc03c06c3918..000000000000
--- a/tools/perf/pmu-events/arch/arm64/ampere/emag/core-imp-def.json
+++ /dev/null
@@ -1,32 +0,0 @@
1[
2 {
3 "ArchStdEvent": "L1D_CACHE_RD",
4 },
5 {
6 "ArchStdEvent": "L1D_CACHE_WR",
7 },
8 {
9 "ArchStdEvent": "L1D_CACHE_REFILL_RD",
10 },
11 {
12 "ArchStdEvent": "L1D_CACHE_REFILL_WR",
13 },
14 {
15 "ArchStdEvent": "L1D_TLB_REFILL_RD",
16 },
17 {
18 "ArchStdEvent": "L1D_TLB_REFILL_WR",
19 },
20 {
21 "ArchStdEvent": "L1D_TLB_RD",
22 },
23 {
24 "ArchStdEvent": "L1D_TLB_WR",
25 },
26 {
27 "ArchStdEvent": "BUS_ACCESS_RD",
28 },
29 {
30 "ArchStdEvent": "BUS_ACCESS_WR",
31 }
32]
diff --git a/tools/perf/pmu-events/arch/arm64/ampere/emag/exception.json b/tools/perf/pmu-events/arch/arm64/ampere/emag/exception.json
new file mode 100644
index 000000000000..3720dc28a15f
--- /dev/null
+++ b/tools/perf/pmu-events/arch/arm64/ampere/emag/exception.json
@@ -0,0 +1,50 @@
1[
2 {
3 "ArchStdEvent": "EXC_UNDEF",
4 },
5 {
6 "ArchStdEvent": "EXC_SVC",
7 },
8 {
9 "ArchStdEvent": "EXC_PABORT",
10 },
11 {
12 "ArchStdEvent": "EXC_DABORT",
13 },
14 {
15 "ArchStdEvent": "EXC_IRQ",
16 },
17 {
18 "ArchStdEvent": "EXC_FIQ",
19 },
20 {
21 "ArchStdEvent": "EXC_HVC",
22 },
23 {
24 "ArchStdEvent": "EXC_TRAP_PABORT",
25 },
26 {
27 "ArchStdEvent": "EXC_TRAP_DABORT",
28 },
29 {
30 "ArchStdEvent": "EXC_TRAP_OTHER",
31 },
32 {
33 "ArchStdEvent": "EXC_TRAP_IRQ",
34 },
35 {
36 "ArchStdEvent": "EXC_TRAP_FIQ",
37 },
38 {
39 "PublicDescription": "Exception taken",
40 "EventCode": "0x09",
41 "EventName": "EXC_TAKEN",
42 "BriefDescription": "Exception taken"
43 },
44 {
45 "PublicDescription": "Instruction architecturally executed, condition check pass, exception return",
46 "EventCode": "0x0a",
47 "EventName": "EXC_RETURN",
48 "BriefDescription": "Exception return"
49 },
50]
diff --git a/tools/perf/pmu-events/arch/arm64/ampere/emag/instruction.json b/tools/perf/pmu-events/arch/arm64/ampere/emag/instruction.json
new file mode 100644
index 000000000000..82cf753e6472
--- /dev/null
+++ b/tools/perf/pmu-events/arch/arm64/ampere/emag/instruction.json
@@ -0,0 +1,89 @@
1[
2 {
3 "ArchStdEvent": "LD_SPEC",
4 },
5 {
6 "ArchStdEvent": "ST_SPEC",
7 },
8 {
9 "ArchStdEvent": "LDST_SPEC",
10 },
11 {
12 "ArchStdEvent": "DP_SPEC",
13 },
14 {
15 "ArchStdEvent": "ASE_SPEC",
16 },
17 {
18 "ArchStdEvent": "VFP_SPEC",
19 },
20 {
21 "ArchStdEvent": "PC_WRITE_SPEC",
22 },
23 {
24 "ArchStdEvent": "CRYPTO_SPEC",
25 },
26 {
27 "ArchStdEvent": "ISB_SPEC",
28 },
29 {
30 "ArchStdEvent": "DSB_SPEC",
31 },
32 {
33 "ArchStdEvent": "DMB_SPEC",
34 },
35 {
36 "ArchStdEvent": "RC_LD_SPEC",
37 },
38 {
39 "ArchStdEvent": "RC_ST_SPEC",
40 },
41 {
42 "PublicDescription": "Instruction architecturally executed, software increment",
43 "EventCode": "0x00",
44 "EventName": "SW_INCR",
45 "BriefDescription": "Software increment"
46 },
47 {
48 "PublicDescription": "Instruction architecturally executed",
49 "EventCode": "0x08",
50 "EventName": "INST_RETIRED",
51 "BriefDescription": "Instruction retired"
52 },
53 {
54 "PublicDescription": "Instruction architecturally executed, condition code check pass, write to CONTEXTIDR",
55 "EventCode": "0x0b",
56 "EventName": "CID_WRITE_RETIRED",
57 "BriefDescription": "Write to CONTEXTIDR"
58 },
59 {
60 "PublicDescription": "Operation speculatively executed",
61 "EventCode": "0x1b",
62 "EventName": "INST_SPEC",
63 "BriefDescription": "Speculatively executed"
64 },
65 {
66 "PublicDescription": "Instruction architecturally executed (condition check pass), write to TTBR",
67 "EventCode": "0x1c",
68 "EventName": "TTBR_WRITE_RETIRED",
69 "BriefDescription": "Instruction executed, TTBR write"
70 },
71 {
72 "PublicDescription": "Instruction architecturally executed, branch. This event counts all branches, taken or not. This excludes exception entries, debug entries and CCFAIL branches",
73 "EventCode": "0x21",
74 "EventName": "BR_RETIRED",
75 "BriefDescription": "Branch retired"
76 },
77 {
78 "PublicDescription": "Instruction architecturally executed, mispredicted branch. This event counts any branch counted by BR_RETIRED which is not correctly predicted and causes a pipeline flush",
79 "EventCode": "0x22",
80 "EventName": "BR_MISPRED_RETIRED",
81 "BriefDescription": "Mispredicted branch retired"
82 },
83 {
84 "PublicDescription": "Operation speculatively executed, NOP",
85 "EventCode": "0x100",
86 "EventName": "NOP_SPEC",
87 "BriefDescription": "Speculatively executed, NOP"
88 },
89]
diff --git a/tools/perf/pmu-events/arch/arm64/ampere/emag/intrinsic.json b/tools/perf/pmu-events/arch/arm64/ampere/emag/intrinsic.json
new file mode 100644
index 000000000000..2aecc5c2347d
--- /dev/null
+++ b/tools/perf/pmu-events/arch/arm64/ampere/emag/intrinsic.json
@@ -0,0 +1,14 @@
1[
2 {
3 "ArchStdEvent": "LDREX_SPEC",
4 },
5 {
6 "ArchStdEvent": "STREX_PASS_SPEC",
7 },
8 {
9 "ArchStdEvent": "STREX_FAIL_SPEC",
10 },
11 {
12 "ArchStdEvent": "STREX_SPEC",
13 },
14]
diff --git a/tools/perf/pmu-events/arch/arm64/ampere/emag/memory.json b/tools/perf/pmu-events/arch/arm64/ampere/emag/memory.json
new file mode 100644
index 000000000000..08508697b318
--- /dev/null
+++ b/tools/perf/pmu-events/arch/arm64/ampere/emag/memory.json
@@ -0,0 +1,29 @@
1[
2 {
3 "ArchStdEvent": "MEM_ACCESS_RD",
4 },
5 {
6 "ArchStdEvent": "MEM_ACCESS_WR",
7 },
8 {
9 "ArchStdEvent": "UNALIGNED_LD_SPEC",
10 },
11 {
12 "ArchStdEvent": "UNALIGNED_ST_SPEC",
13 },
14 {
15 "ArchStdEvent": "UNALIGNED_LDST_SPEC",
16 },
17 {
18 "PublicDescription": "Data memory access",
19 "EventCode": "0x13",
20 "EventName": "MEM_ACCESS",
21 "BriefDescription": "Memory access"
22 },
23 {
24 "PublicDescription": "Local memory error. This event counts any correctable or uncorrectable memory error (ECC or parity) in the protected core RAMs",
25 "EventCode": "0x1a",
26 "EventName": "MEM_ERROR",
27 "BriefDescription": "Memory error"
28 },
29]
diff --git a/tools/perf/pmu-events/arch/arm64/ampere/emag/pipeline.json b/tools/perf/pmu-events/arch/arm64/ampere/emag/pipeline.json
new file mode 100644
index 000000000000..e2087de586bf
--- /dev/null
+++ b/tools/perf/pmu-events/arch/arm64/ampere/emag/pipeline.json
@@ -0,0 +1,50 @@
1[
2 {
3 "PublicDescription": "Decode starved for instruction cycle",
4 "EventCode": "0x108",
5 "EventName": "DECODE_STALL",
6 "BriefDescription": "Decode starved"
7 },
8 {
9 "PublicDescription": "Op dispatch stalled cycle",
10 "EventCode": "0x109",
11 "EventName": "DISPATCH_STALL",
12 "BriefDescription": "Dispatch stalled"
13 },
14 {
15 "PublicDescription": "IXA Op non-issue",
16 "EventCode": "0x10a",
17 "EventName": "IXA_STALL",
18 "BriefDescription": "IXA stalled"
19 },
20 {
21 "PublicDescription": "IXB Op non-issue",
22 "EventCode": "0x10b",
23 "EventName": "IXB_STALL",
24 "BriefDescription": "IXB stalled"
25 },
26 {
27 "PublicDescription": "BX Op non-issue",
28 "EventCode": "0x10c",
29 "EventName": "BX_STALL",
30 "BriefDescription": "BX stalled"
31 },
32 {
33 "PublicDescription": "LX Op non-issue",
34 "EventCode": "0x10d",
35 "EventName": "LX_STALL",
36 "BriefDescription": "LX stalled"
37 },
38 {
39 "PublicDescription": "SX Op non-issue",
40 "EventCode": "0x10e",
41 "EventName": "SX_STALL",
42 "BriefDescription": "SX stalled"
43 },
44 {
45 "PublicDescription": "FX Op non-issue",
46 "EventCode": "0x10f",
47 "EventName": "FX_STALL",
48 "BriefDescription": "FX stalled"
49 },
50]
diff --git a/tools/perf/pmu-events/arch/x86/ivytown/uncore-power.json b/tools/perf/pmu-events/arch/x86/ivytown/uncore-power.json
index d40498f2cb1e..635c09fda1d9 100644
--- a/tools/perf/pmu-events/arch/x86/ivytown/uncore-power.json
+++ b/tools/perf/pmu-events/arch/x86/ivytown/uncore-power.json
@@ -188,7 +188,7 @@
188 "Counter": "0,1,2,3", 188 "Counter": "0,1,2,3",
189 "EventCode": "0xb", 189 "EventCode": "0xb",
190 "EventName": "UNC_P_FREQ_GE_1200MHZ_CYCLES", 190 "EventName": "UNC_P_FREQ_GE_1200MHZ_CYCLES",
191 "Filter": "filter_band0=1200", 191 "Filter": "filter_band0=12",
192 "MetricExpr": "(UNC_P_FREQ_GE_1200MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.", 192 "MetricExpr": "(UNC_P_FREQ_GE_1200MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.",
193 "MetricName": "freq_ge_1200mhz_cycles %", 193 "MetricName": "freq_ge_1200mhz_cycles %",
194 "PerPkg": "1", 194 "PerPkg": "1",
@@ -199,7 +199,7 @@
199 "Counter": "0,1,2,3", 199 "Counter": "0,1,2,3",
200 "EventCode": "0xc", 200 "EventCode": "0xc",
201 "EventName": "UNC_P_FREQ_GE_2000MHZ_CYCLES", 201 "EventName": "UNC_P_FREQ_GE_2000MHZ_CYCLES",
202 "Filter": "filter_band1=2000", 202 "Filter": "filter_band1=20",
203 "MetricExpr": "(UNC_P_FREQ_GE_2000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.", 203 "MetricExpr": "(UNC_P_FREQ_GE_2000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.",
204 "MetricName": "freq_ge_2000mhz_cycles %", 204 "MetricName": "freq_ge_2000mhz_cycles %",
205 "PerPkg": "1", 205 "PerPkg": "1",
@@ -210,7 +210,7 @@
210 "Counter": "0,1,2,3", 210 "Counter": "0,1,2,3",
211 "EventCode": "0xd", 211 "EventCode": "0xd",
212 "EventName": "UNC_P_FREQ_GE_3000MHZ_CYCLES", 212 "EventName": "UNC_P_FREQ_GE_3000MHZ_CYCLES",
213 "Filter": "filter_band2=3000", 213 "Filter": "filter_band2=30",
214 "MetricExpr": "(UNC_P_FREQ_GE_3000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.", 214 "MetricExpr": "(UNC_P_FREQ_GE_3000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.",
215 "MetricName": "freq_ge_3000mhz_cycles %", 215 "MetricName": "freq_ge_3000mhz_cycles %",
216 "PerPkg": "1", 216 "PerPkg": "1",
@@ -221,7 +221,7 @@
221 "Counter": "0,1,2,3", 221 "Counter": "0,1,2,3",
222 "EventCode": "0xe", 222 "EventCode": "0xe",
223 "EventName": "UNC_P_FREQ_GE_4000MHZ_CYCLES", 223 "EventName": "UNC_P_FREQ_GE_4000MHZ_CYCLES",
224 "Filter": "filter_band3=4000", 224 "Filter": "filter_band3=40",
225 "MetricExpr": "(UNC_P_FREQ_GE_4000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.", 225 "MetricExpr": "(UNC_P_FREQ_GE_4000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.",
226 "MetricName": "freq_ge_4000mhz_cycles %", 226 "MetricName": "freq_ge_4000mhz_cycles %",
227 "PerPkg": "1", 227 "PerPkg": "1",
@@ -232,7 +232,7 @@
232 "Counter": "0,1,2,3", 232 "Counter": "0,1,2,3",
233 "EventCode": "0xb", 233 "EventCode": "0xb",
234 "EventName": "UNC_P_FREQ_GE_1200MHZ_TRANSITIONS", 234 "EventName": "UNC_P_FREQ_GE_1200MHZ_TRANSITIONS",
235 "Filter": "edge=1,filter_band0=1200", 235 "Filter": "edge=1,filter_band0=12",
236 "MetricExpr": "(UNC_P_FREQ_GE_1200MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.", 236 "MetricExpr": "(UNC_P_FREQ_GE_1200MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.",
237 "MetricName": "freq_ge_1200mhz_cycles %", 237 "MetricName": "freq_ge_1200mhz_cycles %",
238 "PerPkg": "1", 238 "PerPkg": "1",
@@ -243,7 +243,7 @@
243 "Counter": "0,1,2,3", 243 "Counter": "0,1,2,3",
244 "EventCode": "0xc", 244 "EventCode": "0xc",
245 "EventName": "UNC_P_FREQ_GE_2000MHZ_TRANSITIONS", 245 "EventName": "UNC_P_FREQ_GE_2000MHZ_TRANSITIONS",
246 "Filter": "edge=1,filter_band1=2000", 246 "Filter": "edge=1,filter_band1=20",
247 "MetricExpr": "(UNC_P_FREQ_GE_2000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.", 247 "MetricExpr": "(UNC_P_FREQ_GE_2000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.",
248 "MetricName": "freq_ge_2000mhz_cycles %", 248 "MetricName": "freq_ge_2000mhz_cycles %",
249 "PerPkg": "1", 249 "PerPkg": "1",
@@ -254,7 +254,7 @@
254 "Counter": "0,1,2,3", 254 "Counter": "0,1,2,3",
255 "EventCode": "0xd", 255 "EventCode": "0xd",
256 "EventName": "UNC_P_FREQ_GE_3000MHZ_TRANSITIONS", 256 "EventName": "UNC_P_FREQ_GE_3000MHZ_TRANSITIONS",
257 "Filter": "edge=1,filter_band2=4000", 257 "Filter": "edge=1,filter_band2=30",
258 "MetricExpr": "(UNC_P_FREQ_GE_3000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.", 258 "MetricExpr": "(UNC_P_FREQ_GE_3000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.",
259 "MetricName": "freq_ge_3000mhz_cycles %", 259 "MetricName": "freq_ge_3000mhz_cycles %",
260 "PerPkg": "1", 260 "PerPkg": "1",
@@ -265,7 +265,7 @@
265 "Counter": "0,1,2,3", 265 "Counter": "0,1,2,3",
266 "EventCode": "0xe", 266 "EventCode": "0xe",
267 "EventName": "UNC_P_FREQ_GE_4000MHZ_TRANSITIONS", 267 "EventName": "UNC_P_FREQ_GE_4000MHZ_TRANSITIONS",
268 "Filter": "edge=1,filter_band3=4000", 268 "Filter": "edge=1,filter_band3=40",
269 "MetricExpr": "(UNC_P_FREQ_GE_4000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.", 269 "MetricExpr": "(UNC_P_FREQ_GE_4000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.",
270 "MetricName": "freq_ge_4000mhz_cycles %", 270 "MetricName": "freq_ge_4000mhz_cycles %",
271 "PerPkg": "1", 271 "PerPkg": "1",
diff --git a/tools/perf/pmu-events/arch/x86/jaketown/uncore-power.json b/tools/perf/pmu-events/arch/x86/jaketown/uncore-power.json
index 16034bfd06dd..8755693d86c6 100644
--- a/tools/perf/pmu-events/arch/x86/jaketown/uncore-power.json
+++ b/tools/perf/pmu-events/arch/x86/jaketown/uncore-power.json
@@ -187,7 +187,7 @@
187 "Counter": "0,1,2,3", 187 "Counter": "0,1,2,3",
188 "EventCode": "0xb", 188 "EventCode": "0xb",
189 "EventName": "UNC_P_FREQ_GE_1200MHZ_CYCLES", 189 "EventName": "UNC_P_FREQ_GE_1200MHZ_CYCLES",
190 "Filter": "filter_band0=1200", 190 "Filter": "filter_band0=12",
191 "MetricExpr": "(UNC_P_FREQ_GE_1200MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.", 191 "MetricExpr": "(UNC_P_FREQ_GE_1200MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.",
192 "MetricName": "freq_ge_1200mhz_cycles %", 192 "MetricName": "freq_ge_1200mhz_cycles %",
193 "PerPkg": "1", 193 "PerPkg": "1",
@@ -198,7 +198,7 @@
198 "Counter": "0,1,2,3", 198 "Counter": "0,1,2,3",
199 "EventCode": "0xc", 199 "EventCode": "0xc",
200 "EventName": "UNC_P_FREQ_GE_2000MHZ_CYCLES", 200 "EventName": "UNC_P_FREQ_GE_2000MHZ_CYCLES",
201 "Filter": "filter_band1=2000", 201 "Filter": "filter_band1=20",
202 "MetricExpr": "(UNC_P_FREQ_GE_2000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.", 202 "MetricExpr": "(UNC_P_FREQ_GE_2000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.",
203 "MetricName": "freq_ge_2000mhz_cycles %", 203 "MetricName": "freq_ge_2000mhz_cycles %",
204 "PerPkg": "1", 204 "PerPkg": "1",
@@ -209,7 +209,7 @@
209 "Counter": "0,1,2,3", 209 "Counter": "0,1,2,3",
210 "EventCode": "0xd", 210 "EventCode": "0xd",
211 "EventName": "UNC_P_FREQ_GE_3000MHZ_CYCLES", 211 "EventName": "UNC_P_FREQ_GE_3000MHZ_CYCLES",
212 "Filter": "filter_band2=3000", 212 "Filter": "filter_band2=30",
213 "MetricExpr": "(UNC_P_FREQ_GE_3000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.", 213 "MetricExpr": "(UNC_P_FREQ_GE_3000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.",
214 "MetricName": "freq_ge_3000mhz_cycles %", 214 "MetricName": "freq_ge_3000mhz_cycles %",
215 "PerPkg": "1", 215 "PerPkg": "1",
@@ -220,7 +220,7 @@
220 "Counter": "0,1,2,3", 220 "Counter": "0,1,2,3",
221 "EventCode": "0xe", 221 "EventCode": "0xe",
222 "EventName": "UNC_P_FREQ_GE_4000MHZ_CYCLES", 222 "EventName": "UNC_P_FREQ_GE_4000MHZ_CYCLES",
223 "Filter": "filter_band3=4000", 223 "Filter": "filter_band3=40",
224 "MetricExpr": "(UNC_P_FREQ_GE_4000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.", 224 "MetricExpr": "(UNC_P_FREQ_GE_4000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.",
225 "MetricName": "freq_ge_4000mhz_cycles %", 225 "MetricName": "freq_ge_4000mhz_cycles %",
226 "PerPkg": "1", 226 "PerPkg": "1",
@@ -231,7 +231,7 @@
231 "Counter": "0,1,2,3", 231 "Counter": "0,1,2,3",
232 "EventCode": "0xb", 232 "EventCode": "0xb",
233 "EventName": "UNC_P_FREQ_GE_1200MHZ_TRANSITIONS", 233 "EventName": "UNC_P_FREQ_GE_1200MHZ_TRANSITIONS",
234 "Filter": "edge=1,filter_band0=1200", 234 "Filter": "edge=1,filter_band0=12",
235 "MetricExpr": "(UNC_P_FREQ_GE_1200MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.", 235 "MetricExpr": "(UNC_P_FREQ_GE_1200MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.",
236 "MetricName": "freq_ge_1200mhz_cycles %", 236 "MetricName": "freq_ge_1200mhz_cycles %",
237 "PerPkg": "1", 237 "PerPkg": "1",
@@ -242,7 +242,7 @@
242 "Counter": "0,1,2,3", 242 "Counter": "0,1,2,3",
243 "EventCode": "0xc", 243 "EventCode": "0xc",
244 "EventName": "UNC_P_FREQ_GE_2000MHZ_TRANSITIONS", 244 "EventName": "UNC_P_FREQ_GE_2000MHZ_TRANSITIONS",
245 "Filter": "edge=1,filter_band1=2000", 245 "Filter": "edge=1,filter_band1=20",
246 "MetricExpr": "(UNC_P_FREQ_GE_2000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.", 246 "MetricExpr": "(UNC_P_FREQ_GE_2000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.",
247 "MetricName": "freq_ge_2000mhz_cycles %", 247 "MetricName": "freq_ge_2000mhz_cycles %",
248 "PerPkg": "1", 248 "PerPkg": "1",
@@ -253,7 +253,7 @@
253 "Counter": "0,1,2,3", 253 "Counter": "0,1,2,3",
254 "EventCode": "0xd", 254 "EventCode": "0xd",
255 "EventName": "UNC_P_FREQ_GE_3000MHZ_TRANSITIONS", 255 "EventName": "UNC_P_FREQ_GE_3000MHZ_TRANSITIONS",
256 "Filter": "edge=1,filter_band2=4000", 256 "Filter": "edge=1,filter_band2=30",
257 "MetricExpr": "(UNC_P_FREQ_GE_3000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.", 257 "MetricExpr": "(UNC_P_FREQ_GE_3000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.",
258 "MetricName": "freq_ge_3000mhz_cycles %", 258 "MetricName": "freq_ge_3000mhz_cycles %",
259 "PerPkg": "1", 259 "PerPkg": "1",
@@ -264,7 +264,7 @@
264 "Counter": "0,1,2,3", 264 "Counter": "0,1,2,3",
265 "EventCode": "0xe", 265 "EventCode": "0xe",
266 "EventName": "UNC_P_FREQ_GE_4000MHZ_TRANSITIONS", 266 "EventName": "UNC_P_FREQ_GE_4000MHZ_TRANSITIONS",
267 "Filter": "edge=1,filter_band3=4000", 267 "Filter": "edge=1,filter_band3=40",
268 "MetricExpr": "(UNC_P_FREQ_GE_4000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.", 268 "MetricExpr": "(UNC_P_FREQ_GE_4000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.",
269 "MetricName": "freq_ge_4000mhz_cycles %", 269 "MetricName": "freq_ge_4000mhz_cycles %",
270 "PerPkg": "1", 270 "PerPkg": "1",
diff --git a/tools/perf/scripts/python/call-graph-from-sql.py b/tools/perf/scripts/python/call-graph-from-sql.py
deleted file mode 100644
index b494a67a1c67..000000000000
--- a/tools/perf/scripts/python/call-graph-from-sql.py
+++ /dev/null
@@ -1,339 +0,0 @@
1#!/usr/bin/python2
2# call-graph-from-sql.py: create call-graph from sql database
3# Copyright (c) 2014-2017, Intel Corporation.
4#
5# This program is free software; you can redistribute it and/or modify it
6# under the terms and conditions of the GNU General Public License,
7# version 2, as published by the Free Software Foundation.
8#
9# This program is distributed in the hope it will be useful, but WITHOUT
10# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12# more details.
13
14# To use this script you will need to have exported data using either the
15# export-to-sqlite.py or the export-to-postgresql.py script. Refer to those
16# scripts for details.
17#
18# Following on from the example in the export scripts, a
19# call-graph can be displayed for the pt_example database like this:
20#
21# python tools/perf/scripts/python/call-graph-from-sql.py pt_example
22#
23# Note that for PostgreSQL, this script supports connecting to remote databases
24# by setting hostname, port, username, password, and dbname e.g.
25#
26# python tools/perf/scripts/python/call-graph-from-sql.py "hostname=myhost username=myuser password=mypassword dbname=pt_example"
27#
28# The result is a GUI window with a tree representing a context-sensitive
29# call-graph. Expanding a couple of levels of the tree and adjusting column
30# widths to suit will display something like:
31#
32# Call Graph: pt_example
33# Call Path Object Count Time(ns) Time(%) Branch Count Branch Count(%)
34# v- ls
35# v- 2638:2638
36# v- _start ld-2.19.so 1 10074071 100.0 211135 100.0
37# |- unknown unknown 1 13198 0.1 1 0.0
38# >- _dl_start ld-2.19.so 1 1400980 13.9 19637 9.3
39# >- _d_linit_internal ld-2.19.so 1 448152 4.4 11094 5.3
40# v-__libc_start_main@plt ls 1 8211741 81.5 180397 85.4
41# >- _dl_fixup ld-2.19.so 1 7607 0.1 108 0.1
42# >- __cxa_atexit libc-2.19.so 1 11737 0.1 10 0.0
43# >- __libc_csu_init ls 1 10354 0.1 10 0.0
44# |- _setjmp libc-2.19.so 1 0 0.0 4 0.0
45# v- main ls 1 8182043 99.6 180254 99.9
46#
47# Points to note:
48# The top level is a command name (comm)
49# The next level is a thread (pid:tid)
50# Subsequent levels are functions
51# 'Count' is the number of calls
52# 'Time' is the elapsed time until the function returns
53# Percentages are relative to the level above
54# 'Branch Count' is the total number of branches for that function and all
55# functions that it calls
56
57import sys
58from PySide.QtCore import *
59from PySide.QtGui import *
60from PySide.QtSql import *
61from decimal import *
62
63class TreeItem():
64
65 def __init__(self, db, row, parent_item):
66 self.db = db
67 self.row = row
68 self.parent_item = parent_item
69 self.query_done = False;
70 self.child_count = 0
71 self.child_items = []
72 self.data = ["", "", "", "", "", "", ""]
73 self.comm_id = 0
74 self.thread_id = 0
75 self.call_path_id = 1
76 self.branch_count = 0
77 self.time = 0
78 if not parent_item:
79 self.setUpRoot()
80
81 def setUpRoot(self):
82 self.query_done = True
83 query = QSqlQuery(self.db)
84 ret = query.exec_('SELECT id, comm FROM comms')
85 if not ret:
86 raise Exception("Query failed: " + query.lastError().text())
87 while query.next():
88 if not query.value(0):
89 continue
90 child_item = TreeItem(self.db, self.child_count, self)
91 self.child_items.append(child_item)
92 self.child_count += 1
93 child_item.setUpLevel1(query.value(0), query.value(1))
94
95 def setUpLevel1(self, comm_id, comm):
96 self.query_done = True;
97 self.comm_id = comm_id
98 self.data[0] = comm
99 self.child_items = []
100 self.child_count = 0
101 query = QSqlQuery(self.db)
102 ret = query.exec_('SELECT thread_id, ( SELECT pid FROM threads WHERE id = thread_id ), ( SELECT tid FROM threads WHERE id = thread_id ) FROM comm_threads WHERE comm_id = ' + str(comm_id))
103 if not ret:
104 raise Exception("Query failed: " + query.lastError().text())
105 while query.next():
106 child_item = TreeItem(self.db, self.child_count, self)
107 self.child_items.append(child_item)
108 self.child_count += 1
109 child_item.setUpLevel2(comm_id, query.value(0), query.value(1), query.value(2))
110
111 def setUpLevel2(self, comm_id, thread_id, pid, tid):
112 self.comm_id = comm_id
113 self.thread_id = thread_id
114 self.data[0] = str(pid) + ":" + str(tid)
115
116 def getChildItem(self, row):
117 return self.child_items[row]
118
119 def getParentItem(self):
120 return self.parent_item
121
122 def getRow(self):
123 return self.row
124
125 def timePercent(self, b):
126 if not self.time:
127 return "0.0"
128 x = (b * Decimal(100)) / self.time
129 return str(x.quantize(Decimal('.1'), rounding=ROUND_HALF_UP))
130
131 def branchPercent(self, b):
132 if not self.branch_count:
133 return "0.0"
134 x = (b * Decimal(100)) / self.branch_count
135 return str(x.quantize(Decimal('.1'), rounding=ROUND_HALF_UP))
136
137 def addChild(self, call_path_id, name, dso, count, time, branch_count):
138 child_item = TreeItem(self.db, self.child_count, self)
139 child_item.comm_id = self.comm_id
140 child_item.thread_id = self.thread_id
141 child_item.call_path_id = call_path_id
142 child_item.branch_count = branch_count
143 child_item.time = time
144 child_item.data[0] = name
145 if dso == "[kernel.kallsyms]":
146 dso = "[kernel]"
147 child_item.data[1] = dso
148 child_item.data[2] = str(count)
149 child_item.data[3] = str(time)
150 child_item.data[4] = self.timePercent(time)
151 child_item.data[5] = str(branch_count)
152 child_item.data[6] = self.branchPercent(branch_count)
153 self.child_items.append(child_item)
154 self.child_count += 1
155
156 def selectCalls(self):
157 self.query_done = True;
158 query = QSqlQuery(self.db)
159 ret = query.exec_('SELECT id, call_path_id, branch_count, call_time, return_time, '
160 '( SELECT name FROM symbols WHERE id = ( SELECT symbol_id FROM call_paths WHERE id = call_path_id ) ), '
161 '( SELECT short_name FROM dsos WHERE id = ( SELECT dso_id FROM symbols WHERE id = ( SELECT symbol_id FROM call_paths WHERE id = call_path_id ) ) ), '
162 '( SELECT ip FROM call_paths where id = call_path_id ) '
163 'FROM calls WHERE parent_call_path_id = ' + str(self.call_path_id) + ' AND comm_id = ' + str(self.comm_id) + ' AND thread_id = ' + str(self.thread_id) +
164 ' ORDER BY call_path_id')
165 if not ret:
166 raise Exception("Query failed: " + query.lastError().text())
167 last_call_path_id = 0
168 name = ""
169 dso = ""
170 count = 0
171 branch_count = 0
172 total_branch_count = 0
173 time = 0
174 total_time = 0
175 while query.next():
176 if query.value(1) == last_call_path_id:
177 count += 1
178 branch_count += query.value(2)
179 time += query.value(4) - query.value(3)
180 else:
181 if count:
182 self.addChild(last_call_path_id, name, dso, count, time, branch_count)
183 last_call_path_id = query.value(1)
184 name = query.value(5)
185 dso = query.value(6)
186 count = 1
187 total_branch_count += branch_count
188 total_time += time
189 branch_count = query.value(2)
190 time = query.value(4) - query.value(3)
191 if count:
192 self.addChild(last_call_path_id, name, dso, count, time, branch_count)
193 total_branch_count += branch_count
194 total_time += time
195 # Top level does not have time or branch count, so fix that here
196 if total_branch_count > self.branch_count:
197 self.branch_count = total_branch_count
198 if self.branch_count:
199 for child_item in self.child_items:
200 child_item.data[6] = self.branchPercent(child_item.branch_count)
201 if total_time > self.time:
202 self.time = total_time
203 if self.time:
204 for child_item in self.child_items:
205 child_item.data[4] = self.timePercent(child_item.time)
206
207 def childCount(self):
208 if not self.query_done:
209 self.selectCalls()
210 return self.child_count
211
212 def columnCount(self):
213 return 7
214
215 def columnHeader(self, column):
216 headers = ["Call Path", "Object", "Count ", "Time (ns) ", "Time (%) ", "Branch Count ", "Branch Count (%) "]
217 return headers[column]
218
219 def getData(self, column):
220 return self.data[column]
221
222class TreeModel(QAbstractItemModel):
223
224 def __init__(self, db, parent=None):
225 super(TreeModel, self).__init__(parent)
226 self.db = db
227 self.root = TreeItem(db, 0, None)
228
229 def columnCount(self, parent):
230 return self.root.columnCount()
231
232 def rowCount(self, parent):
233 if parent.isValid():
234 parent_item = parent.internalPointer()
235 else:
236 parent_item = self.root
237 return parent_item.childCount()
238
239 def headerData(self, section, orientation, role):
240 if role == Qt.TextAlignmentRole:
241 if section > 1:
242 return Qt.AlignRight
243 if role != Qt.DisplayRole:
244 return None
245 if orientation != Qt.Horizontal:
246 return None
247 return self.root.columnHeader(section)
248
249 def parent(self, child):
250 child_item = child.internalPointer()
251 if child_item is self.root:
252 return QModelIndex()
253 parent_item = child_item.getParentItem()
254 return self.createIndex(parent_item.getRow(), 0, parent_item)
255
256 def index(self, row, column, parent):
257 if parent.isValid():
258 parent_item = parent.internalPointer()
259 else:
260 parent_item = self.root
261 child_item = parent_item.getChildItem(row)
262 return self.createIndex(row, column, child_item)
263
264 def data(self, index, role):
265 if role == Qt.TextAlignmentRole:
266 if index.column() > 1:
267 return Qt.AlignRight
268 if role != Qt.DisplayRole:
269 return None
270 index_item = index.internalPointer()
271 return index_item.getData(index.column())
272
273class MainWindow(QMainWindow):
274
275 def __init__(self, db, dbname, parent=None):
276 super(MainWindow, self).__init__(parent)
277
278 self.setObjectName("MainWindow")
279 self.setWindowTitle("Call Graph: " + dbname)
280 self.move(100, 100)
281 self.resize(800, 600)
282 style = self.style()
283 icon = style.standardIcon(QStyle.SP_MessageBoxInformation)
284 self.setWindowIcon(icon);
285
286 self.model = TreeModel(db)
287
288 self.view = QTreeView()
289 self.view.setModel(self.model)
290
291 self.setCentralWidget(self.view)
292
293if __name__ == '__main__':
294 if (len(sys.argv) < 2):
295 print >> sys.stderr, "Usage is: call-graph-from-sql.py <database name>"
296 raise Exception("Too few arguments")
297
298 dbname = sys.argv[1]
299
300 is_sqlite3 = False
301 try:
302 f = open(dbname)
303 if f.read(15) == "SQLite format 3":
304 is_sqlite3 = True
305 f.close()
306 except:
307 pass
308
309 if is_sqlite3:
310 db = QSqlDatabase.addDatabase('QSQLITE')
311 else:
312 db = QSqlDatabase.addDatabase('QPSQL')
313 opts = dbname.split()
314 for opt in opts:
315 if '=' in opt:
316 opt = opt.split('=')
317 if opt[0] == 'hostname':
318 db.setHostName(opt[1])
319 elif opt[0] == 'port':
320 db.setPort(int(opt[1]))
321 elif opt[0] == 'username':
322 db.setUserName(opt[1])
323 elif opt[0] == 'password':
324 db.setPassword(opt[1])
325 elif opt[0] == 'dbname':
326 dbname = opt[1]
327 else:
328 dbname = opt
329
330 db.setDatabaseName(dbname)
331 if not db.open():
332 raise Exception("Failed to open database " + dbname + " error: " + db.lastError().text())
333
334 app = QApplication(sys.argv)
335 window = MainWindow(db, dbname)
336 window.show()
337 err = app.exec_()
338 db.close()
339 sys.exit(err)
diff --git a/tools/perf/scripts/python/export-to-postgresql.py b/tools/perf/scripts/python/export-to-postgresql.py
index efcaf6cac2eb..0564dd7377f2 100644
--- a/tools/perf/scripts/python/export-to-postgresql.py
+++ b/tools/perf/scripts/python/export-to-postgresql.py
@@ -59,7 +59,7 @@ import datetime
59# pt_example=# \q 59# pt_example=# \q
60# 60#
61# An example of using the database is provided by the script 61# An example of using the database is provided by the script
62# call-graph-from-sql.py. Refer to that script for details. 62# exported-sql-viewer.py. Refer to that script for details.
63# 63#
64# Tables: 64# Tables:
65# 65#
@@ -204,14 +204,23 @@ from ctypes import *
204libpq = CDLL("libpq.so.5") 204libpq = CDLL("libpq.so.5")
205PQconnectdb = libpq.PQconnectdb 205PQconnectdb = libpq.PQconnectdb
206PQconnectdb.restype = c_void_p 206PQconnectdb.restype = c_void_p
207PQconnectdb.argtypes = [ c_char_p ]
207PQfinish = libpq.PQfinish 208PQfinish = libpq.PQfinish
209PQfinish.argtypes = [ c_void_p ]
208PQstatus = libpq.PQstatus 210PQstatus = libpq.PQstatus
211PQstatus.restype = c_int
212PQstatus.argtypes = [ c_void_p ]
209PQexec = libpq.PQexec 213PQexec = libpq.PQexec
210PQexec.restype = c_void_p 214PQexec.restype = c_void_p
215PQexec.argtypes = [ c_void_p, c_char_p ]
211PQresultStatus = libpq.PQresultStatus 216PQresultStatus = libpq.PQresultStatus
217PQresultStatus.restype = c_int
218PQresultStatus.argtypes = [ c_void_p ]
212PQputCopyData = libpq.PQputCopyData 219PQputCopyData = libpq.PQputCopyData
220PQputCopyData.restype = c_int
213PQputCopyData.argtypes = [ c_void_p, c_void_p, c_int ] 221PQputCopyData.argtypes = [ c_void_p, c_void_p, c_int ]
214PQputCopyEnd = libpq.PQputCopyEnd 222PQputCopyEnd = libpq.PQputCopyEnd
223PQputCopyEnd.restype = c_int
215PQputCopyEnd.argtypes = [ c_void_p, c_void_p ] 224PQputCopyEnd.argtypes = [ c_void_p, c_void_p ]
216 225
217sys.path.append(os.environ['PERF_EXEC_PATH'] + \ 226sys.path.append(os.environ['PERF_EXEC_PATH'] + \
diff --git a/tools/perf/scripts/python/export-to-sqlite.py b/tools/perf/scripts/python/export-to-sqlite.py
index f827bf77e9d2..245caf2643ed 100644
--- a/tools/perf/scripts/python/export-to-sqlite.py
+++ b/tools/perf/scripts/python/export-to-sqlite.py
@@ -40,7 +40,7 @@ import datetime
40# sqlite> .quit 40# sqlite> .quit
41# 41#
42# An example of using the database is provided by the script 42# An example of using the database is provided by the script
43# call-graph-from-sql.py. Refer to that script for details. 43# exported-sql-viewer.py. Refer to that script for details.
44# 44#
45# The database structure is practically the same as created by the script 45# The database structure is practically the same as created by the script
46# export-to-postgresql.py. Refer to that script for details. A notable 46# export-to-postgresql.py. Refer to that script for details. A notable
@@ -440,7 +440,11 @@ def branch_type_table(*x):
440 440
441def sample_table(*x): 441def sample_table(*x):
442 if branches: 442 if branches:
443 bind_exec(sample_query, 18, x) 443 for xx in x[0:15]:
444 sample_query.addBindValue(str(xx))
445 for xx in x[19:22]:
446 sample_query.addBindValue(str(xx))
447 do_query_(sample_query)
444 else: 448 else:
445 bind_exec(sample_query, 22, x) 449 bind_exec(sample_query, 22, x)
446 450
diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py
new file mode 100755
index 000000000000..24cb0bd56afa
--- /dev/null
+++ b/tools/perf/scripts/python/exported-sql-viewer.py
@@ -0,0 +1,2128 @@
1#!/usr/bin/python2
2# SPDX-License-Identifier: GPL-2.0
3# exported-sql-viewer.py: view data from sql database
4# Copyright (c) 2014-2018, Intel Corporation.
5
6# To use this script you will need to have exported data using either the
7# export-to-sqlite.py or the export-to-postgresql.py script. Refer to those
8# scripts for details.
9#
10# Following on from the example in the export scripts, a
11# call-graph can be displayed for the pt_example database like this:
12#
13# python tools/perf/scripts/python/exported-sql-viewer.py pt_example
14#
15# Note that for PostgreSQL, this script supports connecting to remote databases
16# by setting hostname, port, username, password, and dbname e.g.
17#
18# python tools/perf/scripts/python/exported-sql-viewer.py "hostname=myhost username=myuser password=mypassword dbname=pt_example"
19#
20# The result is a GUI window with a tree representing a context-sensitive
21# call-graph. Expanding a couple of levels of the tree and adjusting column
22# widths to suit will display something like:
23#
24# Call Graph: pt_example
25# Call Path Object Count Time(ns) Time(%) Branch Count Branch Count(%)
26# v- ls
27# v- 2638:2638
28# v- _start ld-2.19.so 1 10074071 100.0 211135 100.0
29# |- unknown unknown 1 13198 0.1 1 0.0
30# >- _dl_start ld-2.19.so 1 1400980 13.9 19637 9.3
31# >- _d_linit_internal ld-2.19.so 1 448152 4.4 11094 5.3
32# v-__libc_start_main@plt ls 1 8211741 81.5 180397 85.4
33# >- _dl_fixup ld-2.19.so 1 7607 0.1 108 0.1
34# >- __cxa_atexit libc-2.19.so 1 11737 0.1 10 0.0
35# >- __libc_csu_init ls 1 10354 0.1 10 0.0
36# |- _setjmp libc-2.19.so 1 0 0.0 4 0.0
37# v- main ls 1 8182043 99.6 180254 99.9
38#
39# Points to note:
40# The top level is a command name (comm)
41# The next level is a thread (pid:tid)
42# Subsequent levels are functions
43# 'Count' is the number of calls
44# 'Time' is the elapsed time until the function returns
45# Percentages are relative to the level above
46# 'Branch Count' is the total number of branches for that function and all
47# functions that it calls
48
49# There is also a "All branches" report, which displays branches and
50# possibly disassembly. However, presently, the only supported disassembler is
51# Intel XED, and additionally the object code must be present in perf build ID
52# cache. To use Intel XED, libxed.so must be present. To build and install
53# libxed.so:
54# git clone https://github.com/intelxed/mbuild.git mbuild
55# git clone https://github.com/intelxed/xed
56# cd xed
57# ./mfile.py --share
58# sudo ./mfile.py --prefix=/usr/local install
59# sudo ldconfig
60#
61# Example report:
62#
63# Time CPU Command PID TID Branch Type In Tx Branch
64# 8107675239590 2 ls 22011 22011 return from interrupt No ffffffff86a00a67 native_irq_return_iret ([kernel]) -> 7fab593ea260 _start (ld-2.19.so)
65# 7fab593ea260 48 89 e7 mov %rsp, %rdi
66# 8107675239899 2 ls 22011 22011 hardware interrupt No 7fab593ea260 _start (ld-2.19.so) -> ffffffff86a012e0 page_fault ([kernel])
67# 8107675241900 2 ls 22011 22011 return from interrupt No ffffffff86a00a67 native_irq_return_iret ([kernel]) -> 7fab593ea260 _start (ld-2.19.so)
68# 7fab593ea260 48 89 e7 mov %rsp, %rdi
69# 7fab593ea263 e8 c8 06 00 00 callq 0x7fab593ea930
70# 8107675241900 2 ls 22011 22011 call No 7fab593ea263 _start+0x3 (ld-2.19.so) -> 7fab593ea930 _dl_start (ld-2.19.so)
71# 7fab593ea930 55 pushq %rbp
72# 7fab593ea931 48 89 e5 mov %rsp, %rbp
73# 7fab593ea934 41 57 pushq %r15
74# 7fab593ea936 41 56 pushq %r14
75# 7fab593ea938 41 55 pushq %r13
76# 7fab593ea93a 41 54 pushq %r12
77# 7fab593ea93c 53 pushq %rbx
78# 7fab593ea93d 48 89 fb mov %rdi, %rbx
79# 7fab593ea940 48 83 ec 68 sub $0x68, %rsp
80# 7fab593ea944 0f 31 rdtsc
81# 7fab593ea946 48 c1 e2 20 shl $0x20, %rdx
82# 7fab593ea94a 89 c0 mov %eax, %eax
83# 7fab593ea94c 48 09 c2 or %rax, %rdx
84# 7fab593ea94f 48 8b 05 1a 15 22 00 movq 0x22151a(%rip), %rax
85# 8107675242232 2 ls 22011 22011 hardware interrupt No 7fab593ea94f _dl_start+0x1f (ld-2.19.so) -> ffffffff86a012e0 page_fault ([kernel])
86# 8107675242900 2 ls 22011 22011 return from interrupt No ffffffff86a00a67 native_irq_return_iret ([kernel]) -> 7fab593ea94f _dl_start+0x1f (ld-2.19.so)
87# 7fab593ea94f 48 8b 05 1a 15 22 00 movq 0x22151a(%rip), %rax
88# 7fab593ea956 48 89 15 3b 13 22 00 movq %rdx, 0x22133b(%rip)
89# 8107675243232 2 ls 22011 22011 hardware interrupt No 7fab593ea956 _dl_start+0x26 (ld-2.19.so) -> ffffffff86a012e0 page_fault ([kernel])
90
91import sys
92import weakref
93import threading
94import string
95import cPickle
96import re
97import os
98from PySide.QtCore import *
99from PySide.QtGui import *
100from PySide.QtSql import *
101from decimal import *
102from ctypes import *
103from multiprocessing import Process, Array, Value, Event
104
105# Data formatting helpers
106
107def tohex(ip):
108 if ip < 0:
109 ip += 1 << 64
110 return "%x" % ip
111
112def offstr(offset):
113 if offset:
114 return "+0x%x" % offset
115 return ""
116
117def dsoname(name):
118 if name == "[kernel.kallsyms]":
119 return "[kernel]"
120 return name
121
122# Percent to one decimal place
123
124def PercentToOneDP(n, d):
125 if not d:
126 return "0.0"
127 x = (n * Decimal(100)) / d
128 return str(x.quantize(Decimal(".1"), rounding=ROUND_HALF_UP))
129
130# Helper for queries that must not fail
131
132def QueryExec(query, stmt):
133 ret = query.exec_(stmt)
134 if not ret:
135 raise Exception("Query failed: " + query.lastError().text())
136
137# Background thread
138
139class Thread(QThread):
140
141 done = Signal(object)
142
143 def __init__(self, task, param=None, parent=None):
144 super(Thread, self).__init__(parent)
145 self.task = task
146 self.param = param
147
148 def run(self):
149 while True:
150 if self.param is None:
151 done, result = self.task()
152 else:
153 done, result = self.task(self.param)
154 self.done.emit(result)
155 if done:
156 break
157
158# Tree data model
159
160class TreeModel(QAbstractItemModel):
161
162 def __init__(self, root, parent=None):
163 super(TreeModel, self).__init__(parent)
164 self.root = root
165 self.last_row_read = 0
166
167 def Item(self, parent):
168 if parent.isValid():
169 return parent.internalPointer()
170 else:
171 return self.root
172
173 def rowCount(self, parent):
174 result = self.Item(parent).childCount()
175 if result < 0:
176 result = 0
177 self.dataChanged.emit(parent, parent)
178 return result
179
180 def hasChildren(self, parent):
181 return self.Item(parent).hasChildren()
182
183 def headerData(self, section, orientation, role):
184 if role == Qt.TextAlignmentRole:
185 return self.columnAlignment(section)
186 if role != Qt.DisplayRole:
187 return None
188 if orientation != Qt.Horizontal:
189 return None
190 return self.columnHeader(section)
191
192 def parent(self, child):
193 child_item = child.internalPointer()
194 if child_item is self.root:
195 return QModelIndex()
196 parent_item = child_item.getParentItem()
197 return self.createIndex(parent_item.getRow(), 0, parent_item)
198
199 def index(self, row, column, parent):
200 child_item = self.Item(parent).getChildItem(row)
201 return self.createIndex(row, column, child_item)
202
203 def DisplayData(self, item, index):
204 return item.getData(index.column())
205
206 def FetchIfNeeded(self, row):
207 if row > self.last_row_read:
208 self.last_row_read = row
209 if row + 10 >= self.root.child_count:
210 self.fetcher.Fetch(glb_chunk_sz)
211
212 def columnAlignment(self, column):
213 return Qt.AlignLeft
214
215 def columnFont(self, column):
216 return None
217
218 def data(self, index, role):
219 if role == Qt.TextAlignmentRole:
220 return self.columnAlignment(index.column())
221 if role == Qt.FontRole:
222 return self.columnFont(index.column())
223 if role != Qt.DisplayRole:
224 return None
225 item = index.internalPointer()
226 return self.DisplayData(item, index)
227
228# Table data model
229
230class TableModel(QAbstractTableModel):
231
232 def __init__(self, parent=None):
233 super(TableModel, self).__init__(parent)
234 self.child_count = 0
235 self.child_items = []
236 self.last_row_read = 0
237
238 def Item(self, parent):
239 if parent.isValid():
240 return parent.internalPointer()
241 else:
242 return self
243
244 def rowCount(self, parent):
245 return self.child_count
246
247 def headerData(self, section, orientation, role):
248 if role == Qt.TextAlignmentRole:
249 return self.columnAlignment(section)
250 if role != Qt.DisplayRole:
251 return None
252 if orientation != Qt.Horizontal:
253 return None
254 return self.columnHeader(section)
255
256 def index(self, row, column, parent):
257 return self.createIndex(row, column, self.child_items[row])
258
259 def DisplayData(self, item, index):
260 return item.getData(index.column())
261
262 def FetchIfNeeded(self, row):
263 if row > self.last_row_read:
264 self.last_row_read = row
265 if row + 10 >= self.child_count:
266 self.fetcher.Fetch(glb_chunk_sz)
267
268 def columnAlignment(self, column):
269 return Qt.AlignLeft
270
271 def columnFont(self, column):
272 return None
273
274 def data(self, index, role):
275 if role == Qt.TextAlignmentRole:
276 return self.columnAlignment(index.column())
277 if role == Qt.FontRole:
278 return self.columnFont(index.column())
279 if role != Qt.DisplayRole:
280 return None
281 item = index.internalPointer()
282 return self.DisplayData(item, index)
283
284# Model cache
285
286model_cache = weakref.WeakValueDictionary()
287model_cache_lock = threading.Lock()
288
289def LookupCreateModel(model_name, create_fn):
290 model_cache_lock.acquire()
291 try:
292 model = model_cache[model_name]
293 except:
294 model = None
295 if model is None:
296 model = create_fn()
297 model_cache[model_name] = model
298 model_cache_lock.release()
299 return model
300
301# Find bar
302
303class FindBar():
304
305 def __init__(self, parent, finder, is_reg_expr=False):
306 self.finder = finder
307 self.context = []
308 self.last_value = None
309 self.last_pattern = None
310
311 label = QLabel("Find:")
312 label.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
313
314 self.textbox = QComboBox()
315 self.textbox.setEditable(True)
316 self.textbox.currentIndexChanged.connect(self.ValueChanged)
317
318 self.progress = QProgressBar()
319 self.progress.setRange(0, 0)
320 self.progress.hide()
321
322 if is_reg_expr:
323 self.pattern = QCheckBox("Regular Expression")
324 else:
325 self.pattern = QCheckBox("Pattern")
326 self.pattern.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
327
328 self.next_button = QToolButton()
329 self.next_button.setIcon(parent.style().standardIcon(QStyle.SP_ArrowDown))
330 self.next_button.released.connect(lambda: self.NextPrev(1))
331
332 self.prev_button = QToolButton()
333 self.prev_button.setIcon(parent.style().standardIcon(QStyle.SP_ArrowUp))
334 self.prev_button.released.connect(lambda: self.NextPrev(-1))
335
336 self.close_button = QToolButton()
337 self.close_button.setIcon(parent.style().standardIcon(QStyle.SP_DockWidgetCloseButton))
338 self.close_button.released.connect(self.Deactivate)
339
340 self.hbox = QHBoxLayout()
341 self.hbox.setContentsMargins(0, 0, 0, 0)
342
343 self.hbox.addWidget(label)
344 self.hbox.addWidget(self.textbox)
345 self.hbox.addWidget(self.progress)
346 self.hbox.addWidget(self.pattern)
347 self.hbox.addWidget(self.next_button)
348 self.hbox.addWidget(self.prev_button)
349 self.hbox.addWidget(self.close_button)
350
351 self.bar = QWidget()
352 self.bar.setLayout(self.hbox);
353 self.bar.hide()
354
355 def Widget(self):
356 return self.bar
357
358 def Activate(self):
359 self.bar.show()
360 self.textbox.setFocus()
361
362 def Deactivate(self):
363 self.bar.hide()
364
365 def Busy(self):
366 self.textbox.setEnabled(False)
367 self.pattern.hide()
368 self.next_button.hide()
369 self.prev_button.hide()
370 self.progress.show()
371
372 def Idle(self):
373 self.textbox.setEnabled(True)
374 self.progress.hide()
375 self.pattern.show()
376 self.next_button.show()
377 self.prev_button.show()
378
379 def Find(self, direction):
380 value = self.textbox.currentText()
381 pattern = self.pattern.isChecked()
382 self.last_value = value
383 self.last_pattern = pattern
384 self.finder.Find(value, direction, pattern, self.context)
385
386 def ValueChanged(self):
387 value = self.textbox.currentText()
388 pattern = self.pattern.isChecked()
389 index = self.textbox.currentIndex()
390 data = self.textbox.itemData(index)
391 # Store the pattern in the combo box to keep it with the text value
392 if data == None:
393 self.textbox.setItemData(index, pattern)
394 else:
395 self.pattern.setChecked(data)
396 self.Find(0)
397
398 def NextPrev(self, direction):
399 value = self.textbox.currentText()
400 pattern = self.pattern.isChecked()
401 if value != self.last_value:
402 index = self.textbox.findText(value)
403 # Allow for a button press before the value has been added to the combo box
404 if index < 0:
405 index = self.textbox.count()
406 self.textbox.addItem(value, pattern)
407 self.textbox.setCurrentIndex(index)
408 return
409 else:
410 self.textbox.setItemData(index, pattern)
411 elif pattern != self.last_pattern:
412 # Keep the pattern recorded in the combo box up to date
413 index = self.textbox.currentIndex()
414 self.textbox.setItemData(index, pattern)
415 self.Find(direction)
416
417 def NotFound(self):
418 QMessageBox.information(self.bar, "Find", "'" + self.textbox.currentText() + "' not found")
419
420# Context-sensitive call graph data model item base
421
422class CallGraphLevelItemBase(object):
423
424 def __init__(self, glb, row, parent_item):
425 self.glb = glb
426 self.row = row
427 self.parent_item = parent_item
428 self.query_done = False;
429 self.child_count = 0
430 self.child_items = []
431
432 def getChildItem(self, row):
433 return self.child_items[row]
434
435 def getParentItem(self):
436 return self.parent_item
437
438 def getRow(self):
439 return self.row
440
441 def childCount(self):
442 if not self.query_done:
443 self.Select()
444 if not self.child_count:
445 return -1
446 return self.child_count
447
448 def hasChildren(self):
449 if not self.query_done:
450 return True
451 return self.child_count > 0
452
453 def getData(self, column):
454 return self.data[column]
455
456# Context-sensitive call graph data model level 2+ item base
457
458class CallGraphLevelTwoPlusItemBase(CallGraphLevelItemBase):
459
460 def __init__(self, glb, row, comm_id, thread_id, call_path_id, time, branch_count, parent_item):
461 super(CallGraphLevelTwoPlusItemBase, self).__init__(glb, row, parent_item)
462 self.comm_id = comm_id
463 self.thread_id = thread_id
464 self.call_path_id = call_path_id
465 self.branch_count = branch_count
466 self.time = time
467
468 def Select(self):
469 self.query_done = True;
470 query = QSqlQuery(self.glb.db)
471 QueryExec(query, "SELECT call_path_id, name, short_name, COUNT(calls.id), SUM(return_time - call_time), SUM(branch_count)"
472 " FROM calls"
473 " INNER JOIN call_paths ON calls.call_path_id = call_paths.id"
474 " INNER JOIN symbols ON call_paths.symbol_id = symbols.id"
475 " INNER JOIN dsos ON symbols.dso_id = dsos.id"
476 " WHERE parent_call_path_id = " + str(self.call_path_id) +
477 " AND comm_id = " + str(self.comm_id) +
478 " AND thread_id = " + str(self.thread_id) +
479 " GROUP BY call_path_id, name, short_name"
480 " ORDER BY call_path_id")
481 while query.next():
482 child_item = CallGraphLevelThreeItem(self.glb, self.child_count, self.comm_id, self.thread_id, query.value(0), query.value(1), query.value(2), query.value(3), int(query.value(4)), int(query.value(5)), self)
483 self.child_items.append(child_item)
484 self.child_count += 1
485
486# Context-sensitive call graph data model level three item
487
488class CallGraphLevelThreeItem(CallGraphLevelTwoPlusItemBase):
489
490 def __init__(self, glb, row, comm_id, thread_id, call_path_id, name, dso, count, time, branch_count, parent_item):
491 super(CallGraphLevelThreeItem, self).__init__(glb, row, comm_id, thread_id, call_path_id, time, branch_count, parent_item)
492 dso = dsoname(dso)
493 self.data = [ name, dso, str(count), str(time), PercentToOneDP(time, parent_item.time), str(branch_count), PercentToOneDP(branch_count, parent_item.branch_count) ]
494 self.dbid = call_path_id
495
496# Context-sensitive call graph data model level two item
497
498class CallGraphLevelTwoItem(CallGraphLevelTwoPlusItemBase):
499
500 def __init__(self, glb, row, comm_id, thread_id, pid, tid, parent_item):
501 super(CallGraphLevelTwoItem, self).__init__(glb, row, comm_id, thread_id, 1, 0, 0, parent_item)
502 self.data = [str(pid) + ":" + str(tid), "", "", "", "", "", ""]
503 self.dbid = thread_id
504
505 def Select(self):
506 super(CallGraphLevelTwoItem, self).Select()
507 for child_item in self.child_items:
508 self.time += child_item.time
509 self.branch_count += child_item.branch_count
510 for child_item in self.child_items:
511 child_item.data[4] = PercentToOneDP(child_item.time, self.time)
512 child_item.data[6] = PercentToOneDP(child_item.branch_count, self.branch_count)
513
514# Context-sensitive call graph data model level one item
515
516class CallGraphLevelOneItem(CallGraphLevelItemBase):
517
518 def __init__(self, glb, row, comm_id, comm, parent_item):
519 super(CallGraphLevelOneItem, self).__init__(glb, row, parent_item)
520 self.data = [comm, "", "", "", "", "", ""]
521 self.dbid = comm_id
522
523 def Select(self):
524 self.query_done = True;
525 query = QSqlQuery(self.glb.db)
526 QueryExec(query, "SELECT thread_id, pid, tid"
527 " FROM comm_threads"
528 " INNER JOIN threads ON thread_id = threads.id"
529 " WHERE comm_id = " + str(self.dbid))
530 while query.next():
531 child_item = CallGraphLevelTwoItem(self.glb, self.child_count, self.dbid, query.value(0), query.value(1), query.value(2), self)
532 self.child_items.append(child_item)
533 self.child_count += 1
534
535# Context-sensitive call graph data model root item
536
537class CallGraphRootItem(CallGraphLevelItemBase):
538
539 def __init__(self, glb):
540 super(CallGraphRootItem, self).__init__(glb, 0, None)
541 self.dbid = 0
542 self.query_done = True;
543 query = QSqlQuery(glb.db)
544 QueryExec(query, "SELECT id, comm FROM comms")
545 while query.next():
546 if not query.value(0):
547 continue
548 child_item = CallGraphLevelOneItem(glb, self.child_count, query.value(0), query.value(1), self)
549 self.child_items.append(child_item)
550 self.child_count += 1
551
552# Context-sensitive call graph data model
553
554class CallGraphModel(TreeModel):
555
556 def __init__(self, glb, parent=None):
557 super(CallGraphModel, self).__init__(CallGraphRootItem(glb), parent)
558 self.glb = glb
559
560 def columnCount(self, parent=None):
561 return 7
562
563 def columnHeader(self, column):
564 headers = ["Call Path", "Object", "Count ", "Time (ns) ", "Time (%) ", "Branch Count ", "Branch Count (%) "]
565 return headers[column]
566
567 def columnAlignment(self, column):
568 alignment = [ Qt.AlignLeft, Qt.AlignLeft, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight ]
569 return alignment[column]
570
571 def FindSelect(self, value, pattern, query):
572 if pattern:
573 # postgresql and sqlite pattern patching differences:
574 # postgresql LIKE is case sensitive but sqlite LIKE is not
575 # postgresql LIKE allows % and _ to be escaped with \ but sqlite LIKE does not
576 # postgresql supports ILIKE which is case insensitive
577 # sqlite supports GLOB (text only) which uses * and ? and is case sensitive
578 if not self.glb.dbref.is_sqlite3:
579 # Escape % and _
580 s = value.replace("%", "\%")
581 s = s.replace("_", "\_")
582 # Translate * and ? into SQL LIKE pattern characters % and _
583 trans = string.maketrans("*?", "%_")
584 match = " LIKE '" + str(s).translate(trans) + "'"
585 else:
586 match = " GLOB '" + str(value) + "'"
587 else:
588 match = " = '" + str(value) + "'"
589 QueryExec(query, "SELECT call_path_id, comm_id, thread_id"
590 " FROM calls"
591 " INNER JOIN call_paths ON calls.call_path_id = call_paths.id"
592 " INNER JOIN symbols ON call_paths.symbol_id = symbols.id"
593 " WHERE symbols.name" + match +
594 " GROUP BY comm_id, thread_id, call_path_id"
595 " ORDER BY comm_id, thread_id, call_path_id")
596
597 def FindPath(self, query):
598 # Turn the query result into a list of ids that the tree view can walk
599 # to open the tree at the right place.
600 ids = []
601 parent_id = query.value(0)
602 while parent_id:
603 ids.insert(0, parent_id)
604 q2 = QSqlQuery(self.glb.db)
605 QueryExec(q2, "SELECT parent_id"
606 " FROM call_paths"
607 " WHERE id = " + str(parent_id))
608 if not q2.next():
609 break
610 parent_id = q2.value(0)
611 # The call path root is not used
612 if ids[0] == 1:
613 del ids[0]
614 ids.insert(0, query.value(2))
615 ids.insert(0, query.value(1))
616 return ids
617
618 def Found(self, query, found):
619 if found:
620 return self.FindPath(query)
621 return []
622
623 def FindValue(self, value, pattern, query, last_value, last_pattern):
624 if last_value == value and pattern == last_pattern:
625 found = query.first()
626 else:
627 self.FindSelect(value, pattern, query)
628 found = query.next()
629 return self.Found(query, found)
630
631 def FindNext(self, query):
632 found = query.next()
633 if not found:
634 found = query.first()
635 return self.Found(query, found)
636
637 def FindPrev(self, query):
638 found = query.previous()
639 if not found:
640 found = query.last()
641 return self.Found(query, found)
642
643 def FindThread(self, c):
644 if c.direction == 0 or c.value != c.last_value or c.pattern != c.last_pattern:
645 ids = self.FindValue(c.value, c.pattern, c.query, c.last_value, c.last_pattern)
646 elif c.direction > 0:
647 ids = self.FindNext(c.query)
648 else:
649 ids = self.FindPrev(c.query)
650 return (True, ids)
651
652 def Find(self, value, direction, pattern, context, callback):
653 class Context():
654 def __init__(self, *x):
655 self.value, self.direction, self.pattern, self.query, self.last_value, self.last_pattern = x
656 def Update(self, *x):
657 self.value, self.direction, self.pattern, self.last_value, self.last_pattern = x + (self.value, self.pattern)
658 if len(context):
659 context[0].Update(value, direction, pattern)
660 else:
661 context.append(Context(value, direction, pattern, QSqlQuery(self.glb.db), None, None))
662 # Use a thread so the UI is not blocked during the SELECT
663 thread = Thread(self.FindThread, context[0])
664 thread.done.connect(lambda ids, t=thread, c=callback: self.FindDone(t, c, ids), Qt.QueuedConnection)
665 thread.start()
666
667 def FindDone(self, thread, callback, ids):
668 callback(ids)
669
670# Vertical widget layout
671
672class VBox():
673
674 def __init__(self, w1, w2, w3=None):
675 self.vbox = QWidget()
676 self.vbox.setLayout(QVBoxLayout());
677
678 self.vbox.layout().setContentsMargins(0, 0, 0, 0)
679
680 self.vbox.layout().addWidget(w1)
681 self.vbox.layout().addWidget(w2)
682 if w3:
683 self.vbox.layout().addWidget(w3)
684
685 def Widget(self):
686 return self.vbox
687
688# Context-sensitive call graph window
689
690class CallGraphWindow(QMdiSubWindow):
691
692 def __init__(self, glb, parent=None):
693 super(CallGraphWindow, self).__init__(parent)
694
695 self.model = LookupCreateModel("Context-Sensitive Call Graph", lambda x=glb: CallGraphModel(x))
696
697 self.view = QTreeView()
698 self.view.setModel(self.model)
699
700 for c, w in ((0, 250), (1, 100), (2, 60), (3, 70), (4, 70), (5, 100)):
701 self.view.setColumnWidth(c, w)
702
703 self.find_bar = FindBar(self, self)
704
705 self.vbox = VBox(self.view, self.find_bar.Widget())
706
707 self.setWidget(self.vbox.Widget())
708
709 AddSubWindow(glb.mainwindow.mdi_area, self, "Context-Sensitive Call Graph")
710
711 def DisplayFound(self, ids):
712 if not len(ids):
713 return False
714 parent = QModelIndex()
715 for dbid in ids:
716 found = False
717 n = self.model.rowCount(parent)
718 for row in xrange(n):
719 child = self.model.index(row, 0, parent)
720 if child.internalPointer().dbid == dbid:
721 found = True
722 self.view.setCurrentIndex(child)
723 parent = child
724 break
725 if not found:
726 break
727 return found
728
729 def Find(self, value, direction, pattern, context):
730 self.view.setFocus()
731 self.find_bar.Busy()
732 self.model.Find(value, direction, pattern, context, self.FindDone)
733
734 def FindDone(self, ids):
735 found = True
736 if not self.DisplayFound(ids):
737 found = False
738 self.find_bar.Idle()
739 if not found:
740 self.find_bar.NotFound()
741
742# Child data item finder
743
744class ChildDataItemFinder():
745
746 def __init__(self, root):
747 self.root = root
748 self.value, self.direction, self.pattern, self.last_value, self.last_pattern = (None,) * 5
749 self.rows = []
750 self.pos = 0
751
752 def FindSelect(self):
753 self.rows = []
754 if self.pattern:
755 pattern = re.compile(self.value)
756 for child in self.root.child_items:
757 for column_data in child.data:
758 if re.search(pattern, str(column_data)) is not None:
759 self.rows.append(child.row)
760 break
761 else:
762 for child in self.root.child_items:
763 for column_data in child.data:
764 if self.value in str(column_data):
765 self.rows.append(child.row)
766 break
767
768 def FindValue(self):
769 self.pos = 0
770 if self.last_value != self.value or self.pattern != self.last_pattern:
771 self.FindSelect()
772 if not len(self.rows):
773 return -1
774 return self.rows[self.pos]
775
776 def FindThread(self):
777 if self.direction == 0 or self.value != self.last_value or self.pattern != self.last_pattern:
778 row = self.FindValue()
779 elif len(self.rows):
780 if self.direction > 0:
781 self.pos += 1
782 if self.pos >= len(self.rows):
783 self.pos = 0
784 else:
785 self.pos -= 1
786 if self.pos < 0:
787 self.pos = len(self.rows) - 1
788 row = self.rows[self.pos]
789 else:
790 row = -1
791 return (True, row)
792
793 def Find(self, value, direction, pattern, context, callback):
794 self.value, self.direction, self.pattern, self.last_value, self.last_pattern = (value, direction,pattern, self.value, self.pattern)
795 # Use a thread so the UI is not blocked
796 thread = Thread(self.FindThread)
797 thread.done.connect(lambda row, t=thread, c=callback: self.FindDone(t, c, row), Qt.QueuedConnection)
798 thread.start()
799
800 def FindDone(self, thread, callback, row):
801 callback(row)
802
803# Number of database records to fetch in one go
804
805glb_chunk_sz = 10000
806
807# size of pickled integer big enough for record size
808
809glb_nsz = 8
810
811# Background process for SQL data fetcher
812
813class SQLFetcherProcess():
814
815 def __init__(self, dbref, sql, buffer, head, tail, fetch_count, fetching_done, process_target, wait_event, fetched_event, prep):
816 # Need a unique connection name
817 conn_name = "SQLFetcher" + str(os.getpid())
818 self.db, dbname = dbref.Open(conn_name)
819 self.sql = sql
820 self.buffer = buffer
821 self.head = head
822 self.tail = tail
823 self.fetch_count = fetch_count
824 self.fetching_done = fetching_done
825 self.process_target = process_target
826 self.wait_event = wait_event
827 self.fetched_event = fetched_event
828 self.prep = prep
829 self.query = QSqlQuery(self.db)
830 self.query_limit = 0 if "$$last_id$$" in sql else 2
831 self.last_id = -1
832 self.fetched = 0
833 self.more = True
834 self.local_head = self.head.value
835 self.local_tail = self.tail.value
836
837 def Select(self):
838 if self.query_limit:
839 if self.query_limit == 1:
840 return
841 self.query_limit -= 1
842 stmt = self.sql.replace("$$last_id$$", str(self.last_id))
843 QueryExec(self.query, stmt)
844
845 def Next(self):
846 if not self.query.next():
847 self.Select()
848 if not self.query.next():
849 return None
850 self.last_id = self.query.value(0)
851 return self.prep(self.query)
852
853 def WaitForTarget(self):
854 while True:
855 self.wait_event.clear()
856 target = self.process_target.value
857 if target > self.fetched or target < 0:
858 break
859 self.wait_event.wait()
860 return target
861
862 def HasSpace(self, sz):
863 if self.local_tail <= self.local_head:
864 space = len(self.buffer) - self.local_head
865 if space > sz:
866 return True
867 if space >= glb_nsz:
868 # Use 0 (or space < glb_nsz) to mean there is no more at the top of the buffer
869 nd = cPickle.dumps(0, cPickle.HIGHEST_PROTOCOL)
870 self.buffer[self.local_head : self.local_head + len(nd)] = nd
871 self.local_head = 0
872 if self.local_tail - self.local_head > sz:
873 return True
874 return False
875
876 def WaitForSpace(self, sz):
877 if self.HasSpace(sz):
878 return
879 while True:
880 self.wait_event.clear()
881 self.local_tail = self.tail.value
882 if self.HasSpace(sz):
883 return
884 self.wait_event.wait()
885
886 def AddToBuffer(self, obj):
887 d = cPickle.dumps(obj, cPickle.HIGHEST_PROTOCOL)
888 n = len(d)
889 nd = cPickle.dumps(n, cPickle.HIGHEST_PROTOCOL)
890 sz = n + glb_nsz
891 self.WaitForSpace(sz)
892 pos = self.local_head
893 self.buffer[pos : pos + len(nd)] = nd
894 self.buffer[pos + glb_nsz : pos + sz] = d
895 self.local_head += sz
896
897 def FetchBatch(self, batch_size):
898 fetched = 0
899 while batch_size > fetched:
900 obj = self.Next()
901 if obj is None:
902 self.more = False
903 break
904 self.AddToBuffer(obj)
905 fetched += 1
906 if fetched:
907 self.fetched += fetched
908 with self.fetch_count.get_lock():
909 self.fetch_count.value += fetched
910 self.head.value = self.local_head
911 self.fetched_event.set()
912
913 def Run(self):
914 while self.more:
915 target = self.WaitForTarget()
916 if target < 0:
917 break
918 batch_size = min(glb_chunk_sz, target - self.fetched)
919 self.FetchBatch(batch_size)
920 self.fetching_done.value = True
921 self.fetched_event.set()
922
923def SQLFetcherFn(*x):
924 process = SQLFetcherProcess(*x)
925 process.Run()
926
927# SQL data fetcher
928
929class SQLFetcher(QObject):
930
931 done = Signal(object)
932
933 def __init__(self, glb, sql, prep, process_data, parent=None):
934 super(SQLFetcher, self).__init__(parent)
935 self.process_data = process_data
936 self.more = True
937 self.target = 0
938 self.last_target = 0
939 self.fetched = 0
940 self.buffer_size = 16 * 1024 * 1024
941 self.buffer = Array(c_char, self.buffer_size, lock=False)
942 self.head = Value(c_longlong)
943 self.tail = Value(c_longlong)
944 self.local_tail = 0
945 self.fetch_count = Value(c_longlong)
946 self.fetching_done = Value(c_bool)
947 self.last_count = 0
948 self.process_target = Value(c_longlong)
949 self.wait_event = Event()
950 self.fetched_event = Event()
951 glb.AddInstanceToShutdownOnExit(self)
952 self.process = Process(target=SQLFetcherFn, args=(glb.dbref, sql, self.buffer, self.head, self.tail, self.fetch_count, self.fetching_done, self.process_target, self.wait_event, self.fetched_event, prep))
953 self.process.start()
954 self.thread = Thread(self.Thread)
955 self.thread.done.connect(self.ProcessData, Qt.QueuedConnection)
956 self.thread.start()
957
958 def Shutdown(self):
959 # Tell the thread and process to exit
960 self.process_target.value = -1
961 self.wait_event.set()
962 self.more = False
963 self.fetching_done.value = True
964 self.fetched_event.set()
965
966 def Thread(self):
967 if not self.more:
968 return True, 0
969 while True:
970 self.fetched_event.clear()
971 fetch_count = self.fetch_count.value
972 if fetch_count != self.last_count:
973 break
974 if self.fetching_done.value:
975 self.more = False
976 return True, 0
977 self.fetched_event.wait()
978 count = fetch_count - self.last_count
979 self.last_count = fetch_count
980 self.fetched += count
981 return False, count
982
983 def Fetch(self, nr):
984 if not self.more:
985 # -1 inidcates there are no more
986 return -1
987 result = self.fetched
988 extra = result + nr - self.target
989 if extra > 0:
990 self.target += extra
991 # process_target < 0 indicates shutting down
992 if self.process_target.value >= 0:
993 self.process_target.value = self.target
994 self.wait_event.set()
995 return result
996
997 def RemoveFromBuffer(self):
998 pos = self.local_tail
999 if len(self.buffer) - pos < glb_nsz:
1000 pos = 0
1001 n = cPickle.loads(self.buffer[pos : pos + glb_nsz])
1002 if n == 0:
1003 pos = 0
1004 n = cPickle.loads(self.buffer[0 : glb_nsz])
1005 pos += glb_nsz
1006 obj = cPickle.loads(self.buffer[pos : pos + n])
1007 self.local_tail = pos + n
1008 return obj
1009
1010 def ProcessData(self, count):
1011 for i in xrange(count):
1012 obj = self.RemoveFromBuffer()
1013 self.process_data(obj)
1014 self.tail.value = self.local_tail
1015 self.wait_event.set()
1016 self.done.emit(count)
1017
1018# Fetch more records bar
1019
1020class FetchMoreRecordsBar():
1021
1022 def __init__(self, model, parent):
1023 self.model = model
1024
1025 self.label = QLabel("Number of records (x " + "{:,}".format(glb_chunk_sz) + ") to fetch:")
1026 self.label.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
1027
1028 self.fetch_count = QSpinBox()
1029 self.fetch_count.setRange(1, 1000000)
1030 self.fetch_count.setValue(10)
1031 self.fetch_count.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
1032
1033 self.fetch = QPushButton("Go!")
1034 self.fetch.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
1035 self.fetch.released.connect(self.FetchMoreRecords)
1036
1037 self.progress = QProgressBar()
1038 self.progress.setRange(0, 100)
1039 self.progress.hide()
1040
1041 self.done_label = QLabel("All records fetched")
1042 self.done_label.hide()
1043
1044 self.spacer = QLabel("")
1045
1046 self.close_button = QToolButton()
1047 self.close_button.setIcon(parent.style().standardIcon(QStyle.SP_DockWidgetCloseButton))
1048 self.close_button.released.connect(self.Deactivate)
1049
1050 self.hbox = QHBoxLayout()
1051 self.hbox.setContentsMargins(0, 0, 0, 0)
1052
1053 self.hbox.addWidget(self.label)
1054 self.hbox.addWidget(self.fetch_count)
1055 self.hbox.addWidget(self.fetch)
1056 self.hbox.addWidget(self.spacer)
1057 self.hbox.addWidget(self.progress)
1058 self.hbox.addWidget(self.done_label)
1059 self.hbox.addWidget(self.close_button)
1060
1061 self.bar = QWidget()
1062 self.bar.setLayout(self.hbox);
1063 self.bar.show()
1064
1065 self.in_progress = False
1066 self.model.progress.connect(self.Progress)
1067
1068 self.done = False
1069
1070 if not model.HasMoreRecords():
1071 self.Done()
1072
1073 def Widget(self):
1074 return self.bar
1075
1076 def Activate(self):
1077 self.bar.show()
1078 self.fetch.setFocus()
1079
1080 def Deactivate(self):
1081 self.bar.hide()
1082
1083 def Enable(self, enable):
1084 self.fetch.setEnabled(enable)
1085 self.fetch_count.setEnabled(enable)
1086
1087 def Busy(self):
1088 self.Enable(False)
1089 self.fetch.hide()
1090 self.spacer.hide()
1091 self.progress.show()
1092
1093 def Idle(self):
1094 self.in_progress = False
1095 self.Enable(True)
1096 self.progress.hide()
1097 self.fetch.show()
1098 self.spacer.show()
1099
1100 def Target(self):
1101 return self.fetch_count.value() * glb_chunk_sz
1102
1103 def Done(self):
1104 self.done = True
1105 self.Idle()
1106 self.label.hide()
1107 self.fetch_count.hide()
1108 self.fetch.hide()
1109 self.spacer.hide()
1110 self.done_label.show()
1111
1112 def Progress(self, count):
1113 if self.in_progress:
1114 if count:
1115 percent = ((count - self.start) * 100) / self.Target()
1116 if percent >= 100:
1117 self.Idle()
1118 else:
1119 self.progress.setValue(percent)
1120 if not count:
1121 # Count value of zero means no more records
1122 self.Done()
1123
1124 def FetchMoreRecords(self):
1125 if self.done:
1126 return
1127 self.progress.setValue(0)
1128 self.Busy()
1129 self.in_progress = True
1130 self.start = self.model.FetchMoreRecords(self.Target())
1131
1132# Brance data model level two item
1133
1134class BranchLevelTwoItem():
1135
1136 def __init__(self, row, text, parent_item):
1137 self.row = row
1138 self.parent_item = parent_item
1139 self.data = [""] * 8
1140 self.data[7] = text
1141 self.level = 2
1142
1143 def getParentItem(self):
1144 return self.parent_item
1145
1146 def getRow(self):
1147 return self.row
1148
1149 def childCount(self):
1150 return 0
1151
1152 def hasChildren(self):
1153 return False
1154
1155 def getData(self, column):
1156 return self.data[column]
1157
1158# Brance data model level one item
1159
1160class BranchLevelOneItem():
1161
1162 def __init__(self, glb, row, data, parent_item):
1163 self.glb = glb
1164 self.row = row
1165 self.parent_item = parent_item
1166 self.child_count = 0
1167 self.child_items = []
1168 self.data = data[1:]
1169 self.dbid = data[0]
1170 self.level = 1
1171 self.query_done = False
1172
1173 def getChildItem(self, row):
1174 return self.child_items[row]
1175
1176 def getParentItem(self):
1177 return self.parent_item
1178
1179 def getRow(self):
1180 return self.row
1181
1182 def Select(self):
1183 self.query_done = True
1184
1185 if not self.glb.have_disassembler:
1186 return
1187
1188 query = QSqlQuery(self.glb.db)
1189
1190 QueryExec(query, "SELECT cpu, to_dso_id, to_symbol_id, to_sym_offset, short_name, long_name, build_id, sym_start, to_ip"
1191 " FROM samples"
1192 " INNER JOIN dsos ON samples.to_dso_id = dsos.id"
1193 " INNER JOIN symbols ON samples.to_symbol_id = symbols.id"
1194 " WHERE samples.id = " + str(self.dbid))
1195 if not query.next():
1196 return
1197 cpu = query.value(0)
1198 dso = query.value(1)
1199 sym = query.value(2)
1200 if dso == 0 or sym == 0:
1201 return
1202 off = query.value(3)
1203 short_name = query.value(4)
1204 long_name = query.value(5)
1205 build_id = query.value(6)
1206 sym_start = query.value(7)
1207 ip = query.value(8)
1208
1209 QueryExec(query, "SELECT samples.dso_id, symbol_id, sym_offset, sym_start"
1210 " FROM samples"
1211 " INNER JOIN symbols ON samples.symbol_id = symbols.id"
1212 " WHERE samples.id > " + str(self.dbid) + " AND cpu = " + str(cpu) +
1213 " ORDER BY samples.id"
1214 " LIMIT 1")
1215 if not query.next():
1216 return
1217 if query.value(0) != dso:
1218 # Cannot disassemble from one dso to another
1219 return
1220 bsym = query.value(1)
1221 boff = query.value(2)
1222 bsym_start = query.value(3)
1223 if bsym == 0:
1224 return
1225 tot = bsym_start + boff + 1 - sym_start - off
1226 if tot <= 0 or tot > 16384:
1227 return
1228
1229 inst = self.glb.disassembler.Instruction()
1230 f = self.glb.FileFromNamesAndBuildId(short_name, long_name, build_id)
1231 if not f:
1232 return
1233 mode = 0 if Is64Bit(f) else 1
1234 self.glb.disassembler.SetMode(inst, mode)
1235
1236 buf_sz = tot + 16
1237 buf = create_string_buffer(tot + 16)
1238 f.seek(sym_start + off)
1239 buf.value = f.read(buf_sz)
1240 buf_ptr = addressof(buf)
1241 i = 0
1242 while tot > 0:
1243 cnt, text = self.glb.disassembler.DisassembleOne(inst, buf_ptr, buf_sz, ip)
1244 if cnt:
1245 byte_str = tohex(ip).rjust(16)
1246 for k in xrange(cnt):
1247 byte_str += " %02x" % ord(buf[i])
1248 i += 1
1249 while k < 15:
1250 byte_str += " "
1251 k += 1
1252 self.child_items.append(BranchLevelTwoItem(0, byte_str + " " + text, self))
1253 self.child_count += 1
1254 else:
1255 return
1256 buf_ptr += cnt
1257 tot -= cnt
1258 buf_sz -= cnt
1259 ip += cnt
1260
1261 def childCount(self):
1262 if not self.query_done:
1263 self.Select()
1264 if not self.child_count:
1265 return -1
1266 return self.child_count
1267
1268 def hasChildren(self):
1269 if not self.query_done:
1270 return True
1271 return self.child_count > 0
1272
1273 def getData(self, column):
1274 return self.data[column]
1275
1276# Brance data model root item
1277
1278class BranchRootItem():
1279
1280 def __init__(self):
1281 self.child_count = 0
1282 self.child_items = []
1283 self.level = 0
1284
1285 def getChildItem(self, row):
1286 return self.child_items[row]
1287
1288 def getParentItem(self):
1289 return None
1290
1291 def getRow(self):
1292 return 0
1293
1294 def childCount(self):
1295 return self.child_count
1296
1297 def hasChildren(self):
1298 return self.child_count > 0
1299
1300 def getData(self, column):
1301 return ""
1302
1303# Branch data preparation
1304
1305def BranchDataPrep(query):
1306 data = []
1307 for i in xrange(0, 8):
1308 data.append(query.value(i))
1309 data.append(tohex(query.value(8)).rjust(16) + " " + query.value(9) + offstr(query.value(10)) +
1310 " (" + dsoname(query.value(11)) + ")" + " -> " +
1311 tohex(query.value(12)) + " " + query.value(13) + offstr(query.value(14)) +
1312 " (" + dsoname(query.value(15)) + ")")
1313 return data
1314
1315# Branch data model
1316
1317class BranchModel(TreeModel):
1318
1319 progress = Signal(object)
1320
1321 def __init__(self, glb, event_id, where_clause, parent=None):
1322 super(BranchModel, self).__init__(BranchRootItem(), parent)
1323 self.glb = glb
1324 self.event_id = event_id
1325 self.more = True
1326 self.populated = 0
1327 sql = ("SELECT samples.id, time, cpu, comm, pid, tid, branch_types.name,"
1328 " CASE WHEN in_tx = '0' THEN 'No' ELSE 'Yes' END,"
1329 " ip, symbols.name, sym_offset, dsos.short_name,"
1330 " to_ip, to_symbols.name, to_sym_offset, to_dsos.short_name"
1331 " FROM samples"
1332 " INNER JOIN comms ON comm_id = comms.id"
1333 " INNER JOIN threads ON thread_id = threads.id"
1334 " INNER JOIN branch_types ON branch_type = branch_types.id"
1335 " INNER JOIN symbols ON symbol_id = symbols.id"
1336 " INNER JOIN symbols to_symbols ON to_symbol_id = to_symbols.id"
1337 " INNER JOIN dsos ON samples.dso_id = dsos.id"
1338 " INNER JOIN dsos AS to_dsos ON samples.to_dso_id = to_dsos.id"
1339 " WHERE samples.id > $$last_id$$" + where_clause +
1340 " AND evsel_id = " + str(self.event_id) +
1341 " ORDER BY samples.id"
1342 " LIMIT " + str(glb_chunk_sz))
1343 self.fetcher = SQLFetcher(glb, sql, BranchDataPrep, self.AddSample)
1344 self.fetcher.done.connect(self.Update)
1345 self.fetcher.Fetch(glb_chunk_sz)
1346
1347 def columnCount(self, parent=None):
1348 return 8
1349
1350 def columnHeader(self, column):
1351 return ("Time", "CPU", "Command", "PID", "TID", "Branch Type", "In Tx", "Branch")[column]
1352
1353 def columnFont(self, column):
1354 if column != 7:
1355 return None
1356 return QFont("Monospace")
1357
1358 def DisplayData(self, item, index):
1359 if item.level == 1:
1360 self.FetchIfNeeded(item.row)
1361 return item.getData(index.column())
1362
1363 def AddSample(self, data):
1364 child = BranchLevelOneItem(self.glb, self.populated, data, self.root)
1365 self.root.child_items.append(child)
1366 self.populated += 1
1367
1368 def Update(self, fetched):
1369 if not fetched:
1370 self.more = False
1371 self.progress.emit(0)
1372 child_count = self.root.child_count
1373 count = self.populated - child_count
1374 if count > 0:
1375 parent = QModelIndex()
1376 self.beginInsertRows(parent, child_count, child_count + count - 1)
1377 self.insertRows(child_count, count, parent)
1378 self.root.child_count += count
1379 self.endInsertRows()
1380 self.progress.emit(self.root.child_count)
1381
1382 def FetchMoreRecords(self, count):
1383 current = self.root.child_count
1384 if self.more:
1385 self.fetcher.Fetch(count)
1386 else:
1387 self.progress.emit(0)
1388 return current
1389
1390 def HasMoreRecords(self):
1391 return self.more
1392
1393# Branch window
1394
1395class BranchWindow(QMdiSubWindow):
1396
1397 def __init__(self, glb, event_id, name, where_clause, parent=None):
1398 super(BranchWindow, self).__init__(parent)
1399
1400 model_name = "Branch Events " + str(event_id)
1401 if len(where_clause):
1402 model_name = where_clause + " " + model_name
1403
1404 self.model = LookupCreateModel(model_name, lambda: BranchModel(glb, event_id, where_clause))
1405
1406 self.view = QTreeView()
1407 self.view.setUniformRowHeights(True)
1408 self.view.setModel(self.model)
1409
1410 self.ResizeColumnsToContents()
1411
1412 self.find_bar = FindBar(self, self, True)
1413
1414 self.finder = ChildDataItemFinder(self.model.root)
1415
1416 self.fetch_bar = FetchMoreRecordsBar(self.model, self)
1417
1418 self.vbox = VBox(self.view, self.find_bar.Widget(), self.fetch_bar.Widget())
1419
1420 self.setWidget(self.vbox.Widget())
1421
1422 AddSubWindow(glb.mainwindow.mdi_area, self, name + " Branch Events")
1423
1424 def ResizeColumnToContents(self, column, n):
1425 # Using the view's resizeColumnToContents() here is extrememly slow
1426 # so implement a crude alternative
1427 mm = "MM" if column else "MMMM"
1428 font = self.view.font()
1429 metrics = QFontMetrics(font)
1430 max = 0
1431 for row in xrange(n):
1432 val = self.model.root.child_items[row].data[column]
1433 len = metrics.width(str(val) + mm)
1434 max = len if len > max else max
1435 val = self.model.columnHeader(column)
1436 len = metrics.width(str(val) + mm)
1437 max = len if len > max else max
1438 self.view.setColumnWidth(column, max)
1439
1440 def ResizeColumnsToContents(self):
1441 n = min(self.model.root.child_count, 100)
1442 if n < 1:
1443 # No data yet, so connect a signal to notify when there is
1444 self.model.rowsInserted.connect(self.UpdateColumnWidths)
1445 return
1446 columns = self.model.columnCount()
1447 for i in xrange(columns):
1448 self.ResizeColumnToContents(i, n)
1449
1450 def UpdateColumnWidths(self, *x):
1451 # This only needs to be done once, so disconnect the signal now
1452 self.model.rowsInserted.disconnect(self.UpdateColumnWidths)
1453 self.ResizeColumnsToContents()
1454
1455 def Find(self, value, direction, pattern, context):
1456 self.view.setFocus()
1457 self.find_bar.Busy()
1458 self.finder.Find(value, direction, pattern, context, self.FindDone)
1459
1460 def FindDone(self, row):
1461 self.find_bar.Idle()
1462 if row >= 0:
1463 self.view.setCurrentIndex(self.model.index(row, 0, QModelIndex()))
1464 else:
1465 self.find_bar.NotFound()
1466
1467# Event list
1468
1469def GetEventList(db):
1470 events = []
1471 query = QSqlQuery(db)
1472 QueryExec(query, "SELECT name FROM selected_events WHERE id > 0 ORDER BY id")
1473 while query.next():
1474 events.append(query.value(0))
1475 return events
1476
1477# SQL data preparation
1478
1479def SQLTableDataPrep(query, count):
1480 data = []
1481 for i in xrange(count):
1482 data.append(query.value(i))
1483 return data
1484
1485# SQL table data model item
1486
1487class SQLTableItem():
1488
1489 def __init__(self, row, data):
1490 self.row = row
1491 self.data = data
1492
1493 def getData(self, column):
1494 return self.data[column]
1495
1496# SQL table data model
1497
1498class SQLTableModel(TableModel):
1499
1500 progress = Signal(object)
1501
1502 def __init__(self, glb, sql, column_count, parent=None):
1503 super(SQLTableModel, self).__init__(parent)
1504 self.glb = glb
1505 self.more = True
1506 self.populated = 0
1507 self.fetcher = SQLFetcher(glb, sql, lambda x, y=column_count: SQLTableDataPrep(x, y), self.AddSample)
1508 self.fetcher.done.connect(self.Update)
1509 self.fetcher.Fetch(glb_chunk_sz)
1510
1511 def DisplayData(self, item, index):
1512 self.FetchIfNeeded(item.row)
1513 return item.getData(index.column())
1514
1515 def AddSample(self, data):
1516 child = SQLTableItem(self.populated, data)
1517 self.child_items.append(child)
1518 self.populated += 1
1519
1520 def Update(self, fetched):
1521 if not fetched:
1522 self.more = False
1523 self.progress.emit(0)
1524 child_count = self.child_count
1525 count = self.populated - child_count
1526 if count > 0:
1527 parent = QModelIndex()
1528 self.beginInsertRows(parent, child_count, child_count + count - 1)
1529 self.insertRows(child_count, count, parent)
1530 self.child_count += count
1531 self.endInsertRows()
1532 self.progress.emit(self.child_count)
1533
1534 def FetchMoreRecords(self, count):
1535 current = self.child_count
1536 if self.more:
1537 self.fetcher.Fetch(count)
1538 else:
1539 self.progress.emit(0)
1540 return current
1541
1542 def HasMoreRecords(self):
1543 return self.more
1544
1545# SQL automatic table data model
1546
1547class SQLAutoTableModel(SQLTableModel):
1548
1549 def __init__(self, glb, table_name, parent=None):
1550 sql = "SELECT * FROM " + table_name + " WHERE id > $$last_id$$ ORDER BY id LIMIT " + str(glb_chunk_sz)
1551 if table_name == "comm_threads_view":
1552 # For now, comm_threads_view has no id column
1553 sql = "SELECT * FROM " + table_name + " WHERE comm_id > $$last_id$$ ORDER BY comm_id LIMIT " + str(glb_chunk_sz)
1554 self.column_headers = []
1555 query = QSqlQuery(glb.db)
1556 if glb.dbref.is_sqlite3:
1557 QueryExec(query, "PRAGMA table_info(" + table_name + ")")
1558 while query.next():
1559 self.column_headers.append(query.value(1))
1560 if table_name == "sqlite_master":
1561 sql = "SELECT * FROM " + table_name
1562 else:
1563 if table_name[:19] == "information_schema.":
1564 sql = "SELECT * FROM " + table_name
1565 select_table_name = table_name[19:]
1566 schema = "information_schema"
1567 else:
1568 select_table_name = table_name
1569 schema = "public"
1570 QueryExec(query, "SELECT column_name FROM information_schema.columns WHERE table_schema = '" + schema + "' and table_name = '" + select_table_name + "'")
1571 while query.next():
1572 self.column_headers.append(query.value(0))
1573 super(SQLAutoTableModel, self).__init__(glb, sql, len(self.column_headers), parent)
1574
1575 def columnCount(self, parent=None):
1576 return len(self.column_headers)
1577
1578 def columnHeader(self, column):
1579 return self.column_headers[column]
1580
1581# Base class for custom ResizeColumnsToContents
1582
1583class ResizeColumnsToContentsBase(QObject):
1584
1585 def __init__(self, parent=None):
1586 super(ResizeColumnsToContentsBase, self).__init__(parent)
1587
1588 def ResizeColumnToContents(self, column, n):
1589 # Using the view's resizeColumnToContents() here is extrememly slow
1590 # so implement a crude alternative
1591 font = self.view.font()
1592 metrics = QFontMetrics(font)
1593 max = 0
1594 for row in xrange(n):
1595 val = self.data_model.child_items[row].data[column]
1596 len = metrics.width(str(val) + "MM")
1597 max = len if len > max else max
1598 val = self.data_model.columnHeader(column)
1599 len = metrics.width(str(val) + "MM")
1600 max = len if len > max else max
1601 self.view.setColumnWidth(column, max)
1602
1603 def ResizeColumnsToContents(self):
1604 n = min(self.data_model.child_count, 100)
1605 if n < 1:
1606 # No data yet, so connect a signal to notify when there is
1607 self.data_model.rowsInserted.connect(self.UpdateColumnWidths)
1608 return
1609 columns = self.data_model.columnCount()
1610 for i in xrange(columns):
1611 self.ResizeColumnToContents(i, n)
1612
1613 def UpdateColumnWidths(self, *x):
1614 # This only needs to be done once, so disconnect the signal now
1615 self.data_model.rowsInserted.disconnect(self.UpdateColumnWidths)
1616 self.ResizeColumnsToContents()
1617
1618# Table window
1619
1620class TableWindow(QMdiSubWindow, ResizeColumnsToContentsBase):
1621
1622 def __init__(self, glb, table_name, parent=None):
1623 super(TableWindow, self).__init__(parent)
1624
1625 self.data_model = LookupCreateModel(table_name + " Table", lambda: SQLAutoTableModel(glb, table_name))
1626
1627 self.model = QSortFilterProxyModel()
1628 self.model.setSourceModel(self.data_model)
1629
1630 self.view = QTableView()
1631 self.view.setModel(self.model)
1632 self.view.setEditTriggers(QAbstractItemView.NoEditTriggers)
1633 self.view.verticalHeader().setVisible(False)
1634 self.view.sortByColumn(-1, Qt.AscendingOrder)
1635 self.view.setSortingEnabled(True)
1636
1637 self.ResizeColumnsToContents()
1638
1639 self.find_bar = FindBar(self, self, True)
1640
1641 self.finder = ChildDataItemFinder(self.data_model)
1642
1643 self.fetch_bar = FetchMoreRecordsBar(self.data_model, self)
1644
1645 self.vbox = VBox(self.view, self.find_bar.Widget(), self.fetch_bar.Widget())
1646
1647 self.setWidget(self.vbox.Widget())
1648
1649 AddSubWindow(glb.mainwindow.mdi_area, self, table_name + " Table")
1650
1651 def Find(self, value, direction, pattern, context):
1652 self.view.setFocus()
1653 self.find_bar.Busy()
1654 self.finder.Find(value, direction, pattern, context, self.FindDone)
1655
1656 def FindDone(self, row):
1657 self.find_bar.Idle()
1658 if row >= 0:
1659 self.view.setCurrentIndex(self.model.index(row, 0, QModelIndex()))
1660 else:
1661 self.find_bar.NotFound()
1662
1663# Table list
1664
1665def GetTableList(glb):
1666 tables = []
1667 query = QSqlQuery(glb.db)
1668 if glb.dbref.is_sqlite3:
1669 QueryExec(query, "SELECT name FROM sqlite_master WHERE type IN ( 'table' , 'view' ) ORDER BY name")
1670 else:
1671 QueryExec(query, "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_type IN ( 'BASE TABLE' , 'VIEW' ) ORDER BY table_name")
1672 while query.next():
1673 tables.append(query.value(0))
1674 if glb.dbref.is_sqlite3:
1675 tables.append("sqlite_master")
1676 else:
1677 tables.append("information_schema.tables")
1678 tables.append("information_schema.views")
1679 tables.append("information_schema.columns")
1680 return tables
1681
1682# Action Definition
1683
1684def CreateAction(label, tip, callback, parent=None, shortcut=None):
1685 action = QAction(label, parent)
1686 if shortcut != None:
1687 action.setShortcuts(shortcut)
1688 action.setStatusTip(tip)
1689 action.triggered.connect(callback)
1690 return action
1691
1692# Typical application actions
1693
1694def CreateExitAction(app, parent=None):
1695 return CreateAction("&Quit", "Exit the application", app.closeAllWindows, parent, QKeySequence.Quit)
1696
1697# Typical MDI actions
1698
1699def CreateCloseActiveWindowAction(mdi_area):
1700 return CreateAction("Cl&ose", "Close the active window", mdi_area.closeActiveSubWindow, mdi_area)
1701
1702def CreateCloseAllWindowsAction(mdi_area):
1703 return CreateAction("Close &All", "Close all the windows", mdi_area.closeAllSubWindows, mdi_area)
1704
1705def CreateTileWindowsAction(mdi_area):
1706 return CreateAction("&Tile", "Tile the windows", mdi_area.tileSubWindows, mdi_area)
1707
1708def CreateCascadeWindowsAction(mdi_area):
1709 return CreateAction("&Cascade", "Cascade the windows", mdi_area.cascadeSubWindows, mdi_area)
1710
1711def CreateNextWindowAction(mdi_area):
1712 return CreateAction("Ne&xt", "Move the focus to the next window", mdi_area.activateNextSubWindow, mdi_area, QKeySequence.NextChild)
1713
1714def CreatePreviousWindowAction(mdi_area):
1715 return CreateAction("Pre&vious", "Move the focus to the previous window", mdi_area.activatePreviousSubWindow, mdi_area, QKeySequence.PreviousChild)
1716
1717# Typical MDI window menu
1718
1719class WindowMenu():
1720
1721 def __init__(self, mdi_area, menu):
1722 self.mdi_area = mdi_area
1723 self.window_menu = menu.addMenu("&Windows")
1724 self.close_active_window = CreateCloseActiveWindowAction(mdi_area)
1725 self.close_all_windows = CreateCloseAllWindowsAction(mdi_area)
1726 self.tile_windows = CreateTileWindowsAction(mdi_area)
1727 self.cascade_windows = CreateCascadeWindowsAction(mdi_area)
1728 self.next_window = CreateNextWindowAction(mdi_area)
1729 self.previous_window = CreatePreviousWindowAction(mdi_area)
1730 self.window_menu.aboutToShow.connect(self.Update)
1731
1732 def Update(self):
1733 self.window_menu.clear()
1734 sub_window_count = len(self.mdi_area.subWindowList())
1735 have_sub_windows = sub_window_count != 0
1736 self.close_active_window.setEnabled(have_sub_windows)
1737 self.close_all_windows.setEnabled(have_sub_windows)
1738 self.tile_windows.setEnabled(have_sub_windows)
1739 self.cascade_windows.setEnabled(have_sub_windows)
1740 self.next_window.setEnabled(have_sub_windows)
1741 self.previous_window.setEnabled(have_sub_windows)
1742 self.window_menu.addAction(self.close_active_window)
1743 self.window_menu.addAction(self.close_all_windows)
1744 self.window_menu.addSeparator()
1745 self.window_menu.addAction(self.tile_windows)
1746 self.window_menu.addAction(self.cascade_windows)
1747 self.window_menu.addSeparator()
1748 self.window_menu.addAction(self.next_window)
1749 self.window_menu.addAction(self.previous_window)
1750 if sub_window_count == 0:
1751 return
1752 self.window_menu.addSeparator()
1753 nr = 1
1754 for sub_window in self.mdi_area.subWindowList():
1755 label = str(nr) + " " + sub_window.name
1756 if nr < 10:
1757 label = "&" + label
1758 action = self.window_menu.addAction(label)
1759 action.setCheckable(True)
1760 action.setChecked(sub_window == self.mdi_area.activeSubWindow())
1761 action.triggered.connect(lambda x=nr: self.setActiveSubWindow(x))
1762 self.window_menu.addAction(action)
1763 nr += 1
1764
1765 def setActiveSubWindow(self, nr):
1766 self.mdi_area.setActiveSubWindow(self.mdi_area.subWindowList()[nr - 1])
1767
1768# Font resize
1769
1770def ResizeFont(widget, diff):
1771 font = widget.font()
1772 sz = font.pointSize()
1773 font.setPointSize(sz + diff)
1774 widget.setFont(font)
1775
1776def ShrinkFont(widget):
1777 ResizeFont(widget, -1)
1778
1779def EnlargeFont(widget):
1780 ResizeFont(widget, 1)
1781
1782# Unique name for sub-windows
1783
1784def NumberedWindowName(name, nr):
1785 if nr > 1:
1786 name += " <" + str(nr) + ">"
1787 return name
1788
1789def UniqueSubWindowName(mdi_area, name):
1790 nr = 1
1791 while True:
1792 unique_name = NumberedWindowName(name, nr)
1793 ok = True
1794 for sub_window in mdi_area.subWindowList():
1795 if sub_window.name == unique_name:
1796 ok = False
1797 break
1798 if ok:
1799 return unique_name
1800 nr += 1
1801
1802# Add a sub-window
1803
1804def AddSubWindow(mdi_area, sub_window, name):
1805 unique_name = UniqueSubWindowName(mdi_area, name)
1806 sub_window.setMinimumSize(200, 100)
1807 sub_window.resize(800, 600)
1808 sub_window.setWindowTitle(unique_name)
1809 sub_window.setAttribute(Qt.WA_DeleteOnClose)
1810 sub_window.setWindowIcon(sub_window.style().standardIcon(QStyle.SP_FileIcon))
1811 sub_window.name = unique_name
1812 mdi_area.addSubWindow(sub_window)
1813 sub_window.show()
1814
1815# Main window
1816
1817class MainWindow(QMainWindow):
1818
1819 def __init__(self, glb, parent=None):
1820 super(MainWindow, self).__init__(parent)
1821
1822 self.glb = glb
1823
1824 self.setWindowTitle("Exported SQL Viewer: " + glb.dbname)
1825 self.setWindowIcon(self.style().standardIcon(QStyle.SP_ComputerIcon))
1826 self.setMinimumSize(200, 100)
1827
1828 self.mdi_area = QMdiArea()
1829 self.mdi_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
1830 self.mdi_area.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
1831
1832 self.setCentralWidget(self.mdi_area)
1833
1834 menu = self.menuBar()
1835
1836 file_menu = menu.addMenu("&File")
1837 file_menu.addAction(CreateExitAction(glb.app, self))
1838
1839 edit_menu = menu.addMenu("&Edit")
1840 edit_menu.addAction(CreateAction("&Find...", "Find items", self.Find, self, QKeySequence.Find))
1841 edit_menu.addAction(CreateAction("Fetch &more records...", "Fetch more records", self.FetchMoreRecords, self, [QKeySequence(Qt.Key_F8)]))
1842 edit_menu.addAction(CreateAction("&Shrink Font", "Make text smaller", self.ShrinkFont, self, [QKeySequence("Ctrl+-")]))
1843 edit_menu.addAction(CreateAction("&Enlarge Font", "Make text bigger", self.EnlargeFont, self, [QKeySequence("Ctrl++")]))
1844
1845 reports_menu = menu.addMenu("&Reports")
1846 reports_menu.addAction(CreateAction("Context-Sensitive Call &Graph", "Create a new window containing a context-sensitive call graph", self.NewCallGraph, self))
1847
1848 self.EventMenu(GetEventList(glb.db), reports_menu)
1849
1850 self.TableMenu(GetTableList(glb), menu)
1851
1852 self.window_menu = WindowMenu(self.mdi_area, menu)
1853
1854 def Find(self):
1855 win = self.mdi_area.activeSubWindow()
1856 if win:
1857 try:
1858 win.find_bar.Activate()
1859 except:
1860 pass
1861
1862 def FetchMoreRecords(self):
1863 win = self.mdi_area.activeSubWindow()
1864 if win:
1865 try:
1866 win.fetch_bar.Activate()
1867 except:
1868 pass
1869
1870 def ShrinkFont(self):
1871 win = self.mdi_area.activeSubWindow()
1872 ShrinkFont(win.view)
1873
1874 def EnlargeFont(self):
1875 win = self.mdi_area.activeSubWindow()
1876 EnlargeFont(win.view)
1877
1878 def EventMenu(self, events, reports_menu):
1879 branches_events = 0
1880 for event in events:
1881 event = event.split(":")[0]
1882 if event == "branches":
1883 branches_events += 1
1884 dbid = 0
1885 for event in events:
1886 dbid += 1
1887 event = event.split(":")[0]
1888 if event == "branches":
1889 label = "All branches" if branches_events == 1 else "All branches " + "(id=" + dbid + ")"
1890 reports_menu.addAction(CreateAction(label, "Create a new window displaying branch events", lambda x=dbid: self.NewBranchView(x), self))
1891
1892 def TableMenu(self, tables, menu):
1893 table_menu = menu.addMenu("&Tables")
1894 for table in tables:
1895 table_menu.addAction(CreateAction(table, "Create a new window containing a table view", lambda t=table: self.NewTableView(t), self))
1896
1897 def NewCallGraph(self):
1898 CallGraphWindow(self.glb, self)
1899
1900 def NewBranchView(self, event_id):
1901 BranchWindow(self.glb, event_id, "", "", self)
1902
1903 def NewTableView(self, table_name):
1904 TableWindow(self.glb, table_name, self)
1905
1906# XED Disassembler
1907
1908class xed_state_t(Structure):
1909
1910 _fields_ = [
1911 ("mode", c_int),
1912 ("width", c_int)
1913 ]
1914
1915class XEDInstruction():
1916
1917 def __init__(self, libxed):
1918 # Current xed_decoded_inst_t structure is 192 bytes. Use 512 to allow for future expansion
1919 xedd_t = c_byte * 512
1920 self.xedd = xedd_t()
1921 self.xedp = addressof(self.xedd)
1922 libxed.xed_decoded_inst_zero(self.xedp)
1923 self.state = xed_state_t()
1924 self.statep = addressof(self.state)
1925 # Buffer for disassembled instruction text
1926 self.buffer = create_string_buffer(256)
1927 self.bufferp = addressof(self.buffer)
1928
1929class LibXED():
1930
1931 def __init__(self):
1932 self.libxed = CDLL("libxed.so")
1933
1934 self.xed_tables_init = self.libxed.xed_tables_init
1935 self.xed_tables_init.restype = None
1936 self.xed_tables_init.argtypes = []
1937
1938 self.xed_decoded_inst_zero = self.libxed.xed_decoded_inst_zero
1939 self.xed_decoded_inst_zero.restype = None
1940 self.xed_decoded_inst_zero.argtypes = [ c_void_p ]
1941
1942 self.xed_operand_values_set_mode = self.libxed.xed_operand_values_set_mode
1943 self.xed_operand_values_set_mode.restype = None
1944 self.xed_operand_values_set_mode.argtypes = [ c_void_p, c_void_p ]
1945
1946 self.xed_decoded_inst_zero_keep_mode = self.libxed.xed_decoded_inst_zero_keep_mode
1947 self.xed_decoded_inst_zero_keep_mode.restype = None
1948 self.xed_decoded_inst_zero_keep_mode.argtypes = [ c_void_p ]
1949
1950 self.xed_decode = self.libxed.xed_decode
1951 self.xed_decode.restype = c_int
1952 self.xed_decode.argtypes = [ c_void_p, c_void_p, c_uint ]
1953
1954 self.xed_format_context = self.libxed.xed_format_context
1955 self.xed_format_context.restype = c_uint
1956 self.xed_format_context.argtypes = [ c_int, c_void_p, c_void_p, c_int, c_ulonglong, c_void_p, c_void_p ]
1957
1958 self.xed_tables_init()
1959
1960 def Instruction(self):
1961 return XEDInstruction(self)
1962
1963 def SetMode(self, inst, mode):
1964 if mode:
1965 inst.state.mode = 4 # 32-bit
1966 inst.state.width = 4 # 4 bytes
1967 else:
1968 inst.state.mode = 1 # 64-bit
1969 inst.state.width = 8 # 8 bytes
1970 self.xed_operand_values_set_mode(inst.xedp, inst.statep)
1971
1972 def DisassembleOne(self, inst, bytes_ptr, bytes_cnt, ip):
1973 self.xed_decoded_inst_zero_keep_mode(inst.xedp)
1974 err = self.xed_decode(inst.xedp, bytes_ptr, bytes_cnt)
1975 if err:
1976 return 0, ""
1977 # Use AT&T mode (2), alternative is Intel (3)
1978 ok = self.xed_format_context(2, inst.xedp, inst.bufferp, sizeof(inst.buffer), ip, 0, 0)
1979 if not ok:
1980 return 0, ""
1981 # Return instruction length and the disassembled instruction text
1982 # For now, assume the length is in byte 166
1983 return inst.xedd[166], inst.buffer.value
1984
1985def TryOpen(file_name):
1986 try:
1987 return open(file_name, "rb")
1988 except:
1989 return None
1990
1991def Is64Bit(f):
1992 result = sizeof(c_void_p)
1993 # ELF support only
1994 pos = f.tell()
1995 f.seek(0)
1996 header = f.read(7)
1997 f.seek(pos)
1998 magic = header[0:4]
1999 eclass = ord(header[4])
2000 encoding = ord(header[5])
2001 version = ord(header[6])
2002 if magic == chr(127) + "ELF" and eclass > 0 and eclass < 3 and encoding > 0 and encoding < 3 and version == 1:
2003 result = True if eclass == 2 else False
2004 return result
2005
2006# Global data
2007
2008class Glb():
2009
2010 def __init__(self, dbref, db, dbname):
2011 self.dbref = dbref
2012 self.db = db
2013 self.dbname = dbname
2014 self.home_dir = os.path.expanduser("~")
2015 self.buildid_dir = os.getenv("PERF_BUILDID_DIR")
2016 if self.buildid_dir:
2017 self.buildid_dir += "/.build-id/"
2018 else:
2019 self.buildid_dir = self.home_dir + "/.debug/.build-id/"
2020 self.app = None
2021 self.mainwindow = None
2022 self.instances_to_shutdown_on_exit = weakref.WeakSet()
2023 try:
2024 self.disassembler = LibXED()
2025 self.have_disassembler = True
2026 except:
2027 self.have_disassembler = False
2028
2029 def FileFromBuildId(self, build_id):
2030 file_name = self.buildid_dir + build_id[0:2] + "/" + build_id[2:] + "/elf"
2031 return TryOpen(file_name)
2032
2033 def FileFromNamesAndBuildId(self, short_name, long_name, build_id):
2034 # Assume current machine i.e. no support for virtualization
2035 if short_name[0:7] == "[kernel" and os.path.basename(long_name) == "kcore":
2036 file_name = os.getenv("PERF_KCORE")
2037 f = TryOpen(file_name) if file_name else None
2038 if f:
2039 return f
2040 # For now, no special handling if long_name is /proc/kcore
2041 f = TryOpen(long_name)
2042 if f:
2043 return f
2044 f = self.FileFromBuildId(build_id)
2045 if f:
2046 return f
2047 return None
2048
2049 def AddInstanceToShutdownOnExit(self, instance):
2050 self.instances_to_shutdown_on_exit.add(instance)
2051
2052 # Shutdown any background processes or threads
2053 def ShutdownInstances(self):
2054 for x in self.instances_to_shutdown_on_exit:
2055 try:
2056 x.Shutdown()
2057 except:
2058 pass
2059
2060# Database reference
2061
2062class DBRef():
2063
2064 def __init__(self, is_sqlite3, dbname):
2065 self.is_sqlite3 = is_sqlite3
2066 self.dbname = dbname
2067
2068 def Open(self, connection_name):
2069 dbname = self.dbname
2070 if self.is_sqlite3:
2071 db = QSqlDatabase.addDatabase("QSQLITE", connection_name)
2072 else:
2073 db = QSqlDatabase.addDatabase("QPSQL", connection_name)
2074 opts = dbname.split()
2075 for opt in opts:
2076 if "=" in opt:
2077 opt = opt.split("=")
2078 if opt[0] == "hostname":
2079 db.setHostName(opt[1])
2080 elif opt[0] == "port":
2081 db.setPort(int(opt[1]))
2082 elif opt[0] == "username":
2083 db.setUserName(opt[1])
2084 elif opt[0] == "password":
2085 db.setPassword(opt[1])
2086 elif opt[0] == "dbname":
2087 dbname = opt[1]
2088 else:
2089 dbname = opt
2090
2091 db.setDatabaseName(dbname)
2092 if not db.open():
2093 raise Exception("Failed to open database " + dbname + " error: " + db.lastError().text())
2094 return db, dbname
2095
2096# Main
2097
2098def Main():
2099 if (len(sys.argv) < 2):
2100 print >> sys.stderr, "Usage is: exported-sql-viewer.py <database name>"
2101 raise Exception("Too few arguments")
2102
2103 dbname = sys.argv[1]
2104
2105 is_sqlite3 = False
2106 try:
2107 f = open(dbname)
2108 if f.read(15) == "SQLite format 3":
2109 is_sqlite3 = True
2110 f.close()
2111 except:
2112 pass
2113
2114 dbref = DBRef(is_sqlite3, dbname)
2115 db, dbname = dbref.Open("main")
2116 glb = Glb(dbref, db, dbname)
2117 app = QApplication(sys.argv)
2118 glb.app = app
2119 mainwindow = MainWindow(glb)
2120 glb.mainwindow = mainwindow
2121 mainwindow.show()
2122 err = app.exec_()
2123 glb.ShutdownInstances()
2124 db.close()
2125 sys.exit(err)
2126
2127if __name__ == "__main__":
2128 Main()
diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build
index 6c108fa79ae3..0b2b8305c965 100644
--- a/tools/perf/tests/Build
+++ b/tools/perf/tests/Build
@@ -21,6 +21,7 @@ perf-y += python-use.o
21perf-y += bp_signal.o 21perf-y += bp_signal.o
22perf-y += bp_signal_overflow.o 22perf-y += bp_signal_overflow.o
23perf-y += bp_account.o 23perf-y += bp_account.o
24perf-y += wp.o
24perf-y += task-exit.o 25perf-y += task-exit.o
25perf-y += sw-clock.o 26perf-y += sw-clock.o
26perf-y += mmap-thread-lookup.o 27perf-y += mmap-thread-lookup.o
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index d7a5e1b9aa6f..12c09e0ece71 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -121,6 +121,16 @@ static struct test generic_tests[] = {
121 .is_supported = test__bp_signal_is_supported, 121 .is_supported = test__bp_signal_is_supported,
122 }, 122 },
123 { 123 {
124 .desc = "Watchpoint",
125 .func = test__wp,
126 .is_supported = test__wp_is_supported,
127 .subtest = {
128 .skip_if_fail = false,
129 .get_nr = test__wp_subtest_get_nr,
130 .get_desc = test__wp_subtest_get_desc,
131 },
132 },
133 {
124 .desc = "Number of exit events of a simple workload", 134 .desc = "Number of exit events of a simple workload",
125 .func = test__task_exit, 135 .func = test__task_exit,
126 }, 136 },
diff --git a/tools/perf/tests/evsel-tp-sched.c b/tools/perf/tests/evsel-tp-sched.c
index 699561fa512c..5f8501c68da4 100644
--- a/tools/perf/tests/evsel-tp-sched.c
+++ b/tools/perf/tests/evsel-tp-sched.c
@@ -8,7 +8,7 @@
8static int perf_evsel__test_field(struct perf_evsel *evsel, const char *name, 8static int perf_evsel__test_field(struct perf_evsel *evsel, const char *name,
9 int size, bool should_be_signed) 9 int size, bool should_be_signed)
10{ 10{
11 struct format_field *field = perf_evsel__field(evsel, name); 11 struct tep_format_field *field = perf_evsel__field(evsel, name);
12 int is_signed; 12 int is_signed;
13 int ret = 0; 13 int ret = 0;
14 14
@@ -17,7 +17,7 @@ static int perf_evsel__test_field(struct perf_evsel *evsel, const char *name,
17 return -1; 17 return -1;
18 } 18 }
19 19
20 is_signed = !!(field->flags | FIELD_IS_SIGNED); 20 is_signed = !!(field->flags | TEP_FIELD_IS_SIGNED);
21 if (should_be_signed && !is_signed) { 21 if (should_be_signed && !is_signed) {
22 pr_debug("%s: \"%s\" signedness(%d) is wrong, should be %d\n", 22 pr_debug("%s: \"%s\" signedness(%d) is wrong, should be %d\n",
23 evsel->name, name, is_signed, should_be_signed); 23 evsel->name, name, is_signed, should_be_signed);
diff --git a/tools/perf/tests/shell/record+probe_libc_inet_pton.sh b/tools/perf/tests/shell/record+probe_libc_inet_pton.sh
index 3013ac8f83d0..cab7b0aea6ea 100755
--- a/tools/perf/tests/shell/record+probe_libc_inet_pton.sh
+++ b/tools/perf/tests/shell/record+probe_libc_inet_pton.sh
@@ -48,7 +48,7 @@ trace_libc_inet_pton_backtrace() {
48 *) 48 *)
49 eventattr='max-stack=3' 49 eventattr='max-stack=3'
50 echo "getaddrinfo\+0x[[:xdigit:]]+[[:space:]]\($libc\)$" >> $expected 50 echo "getaddrinfo\+0x[[:xdigit:]]+[[:space:]]\($libc\)$" >> $expected
51 echo ".*\+0x[[:xdigit:]]+[[:space:]]\(.*/bin/ping.*\)$" >> $expected 51 echo ".*(\+0x[[:xdigit:]]+|\[unknown\])[[:space:]]\(.*/bin/ping.*\)$" >> $expected
52 ;; 52 ;;
53 esac 53 esac
54 54
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index a9760e790563..b82f55fcc294 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -59,6 +59,9 @@ int test__python_use(struct test *test, int subtest);
59int test__bp_signal(struct test *test, int subtest); 59int test__bp_signal(struct test *test, int subtest);
60int test__bp_signal_overflow(struct test *test, int subtest); 60int test__bp_signal_overflow(struct test *test, int subtest);
61int test__bp_accounting(struct test *test, int subtest); 61int test__bp_accounting(struct test *test, int subtest);
62int test__wp(struct test *test, int subtest);
63const char *test__wp_subtest_get_desc(int subtest);
64int test__wp_subtest_get_nr(void);
62int test__task_exit(struct test *test, int subtest); 65int test__task_exit(struct test *test, int subtest);
63int test__mem(struct test *test, int subtest); 66int test__mem(struct test *test, int subtest);
64int test__sw_clock_freq(struct test *test, int subtest); 67int test__sw_clock_freq(struct test *test, int subtest);
@@ -106,6 +109,7 @@ int test__unit_number__scnprint(struct test *test, int subtest);
106int test__mem2node(struct test *t, int subtest); 109int test__mem2node(struct test *t, int subtest);
107 110
108bool test__bp_signal_is_supported(void); 111bool test__bp_signal_is_supported(void);
112bool test__wp_is_supported(void);
109 113
110#if defined(__arm__) || defined(__aarch64__) 114#if defined(__arm__) || defined(__aarch64__)
111#ifdef HAVE_DWARF_UNWIND_SUPPORT 115#ifdef HAVE_DWARF_UNWIND_SUPPORT
diff --git a/tools/perf/tests/wp.c b/tools/perf/tests/wp.c
new file mode 100644
index 000000000000..f89e6806557b
--- /dev/null
+++ b/tools/perf/tests/wp.c
@@ -0,0 +1,241 @@
1// SPDX-License-Identifier: GPL-2.0
2#include <stdlib.h>
3#include <sys/ioctl.h>
4#include <linux/hw_breakpoint.h>
5#include "tests.h"
6#include "debug.h"
7#include "cloexec.h"
8
9#define WP_TEST_ASSERT_VAL(fd, text, val) \
10do { \
11 long long count; \
12 wp_read(fd, &count, sizeof(long long)); \
13 TEST_ASSERT_VAL(text, count == val); \
14} while (0)
15
16volatile u64 data1;
17volatile u8 data2[3];
18
19static int wp_read(int fd, long long *count, int size)
20{
21 int ret = read(fd, count, size);
22
23 if (ret != size) {
24 pr_debug("failed to read: %d\n", ret);
25 return -1;
26 }
27 return 0;
28}
29
30static void get__perf_event_attr(struct perf_event_attr *attr, int wp_type,
31 void *wp_addr, unsigned long wp_len)
32{
33 memset(attr, 0, sizeof(struct perf_event_attr));
34 attr->type = PERF_TYPE_BREAKPOINT;
35 attr->size = sizeof(struct perf_event_attr);
36 attr->config = 0;
37 attr->bp_type = wp_type;
38 attr->bp_addr = (unsigned long)wp_addr;
39 attr->bp_len = wp_len;
40 attr->sample_period = 1;
41 attr->sample_type = PERF_SAMPLE_IP;
42 attr->exclude_kernel = 1;
43 attr->exclude_hv = 1;
44}
45
46static int __event(int wp_type, void *wp_addr, unsigned long wp_len)
47{
48 int fd;
49 struct perf_event_attr attr;
50
51 get__perf_event_attr(&attr, wp_type, wp_addr, wp_len);
52 fd = sys_perf_event_open(&attr, 0, -1, -1,
53 perf_event_open_cloexec_flag());
54 if (fd < 0)
55 pr_debug("failed opening event %x\n", attr.bp_type);
56
57 return fd;
58}
59
60static int wp_ro_test(void)
61{
62 int fd;
63 unsigned long tmp, tmp1 = rand();
64
65 fd = __event(HW_BREAKPOINT_R, (void *)&data1, sizeof(data1));
66 if (fd < 0)
67 return -1;
68
69 tmp = data1;
70 WP_TEST_ASSERT_VAL(fd, "RO watchpoint", 1);
71
72 data1 = tmp1 + tmp;
73 WP_TEST_ASSERT_VAL(fd, "RO watchpoint", 1);
74
75 close(fd);
76 return 0;
77}
78
79static int wp_wo_test(void)
80{
81 int fd;
82 unsigned long tmp, tmp1 = rand();
83
84 fd = __event(HW_BREAKPOINT_W, (void *)&data1, sizeof(data1));
85 if (fd < 0)
86 return -1;
87
88 tmp = data1;
89 WP_TEST_ASSERT_VAL(fd, "WO watchpoint", 0);
90
91 data1 = tmp1 + tmp;
92 WP_TEST_ASSERT_VAL(fd, "WO watchpoint", 1);
93
94 close(fd);
95 return 0;
96}
97
98static int wp_rw_test(void)
99{
100 int fd;
101 unsigned long tmp, tmp1 = rand();
102
103 fd = __event(HW_BREAKPOINT_R | HW_BREAKPOINT_W, (void *)&data1,
104 sizeof(data1));
105 if (fd < 0)
106 return -1;
107
108 tmp = data1;
109 WP_TEST_ASSERT_VAL(fd, "RW watchpoint", 1);
110
111 data1 = tmp1 + tmp;
112 WP_TEST_ASSERT_VAL(fd, "RW watchpoint", 2);
113
114 close(fd);
115 return 0;
116}
117
118static int wp_modify_test(void)
119{
120 int fd, ret;
121 unsigned long tmp = rand();
122 struct perf_event_attr new_attr;
123
124 fd = __event(HW_BREAKPOINT_W, (void *)&data1, sizeof(data1));
125 if (fd < 0)
126 return -1;
127
128 data1 = tmp;
129 WP_TEST_ASSERT_VAL(fd, "Modify watchpoint", 1);
130
131 /* Modify watchpoint with disabled = 1 */
132 get__perf_event_attr(&new_attr, HW_BREAKPOINT_W, (void *)&data2[0],
133 sizeof(u8) * 2);
134 new_attr.disabled = 1;
135 ret = ioctl(fd, PERF_EVENT_IOC_MODIFY_ATTRIBUTES, &new_attr);
136 if (ret < 0) {
137 pr_debug("ioctl(PERF_EVENT_IOC_MODIFY_ATTRIBUTES) failed\n");
138 close(fd);
139 return ret;
140 }
141
142 data2[1] = tmp; /* Not Counted */
143 WP_TEST_ASSERT_VAL(fd, "Modify watchpoint", 1);
144
145 /* Enable the event */
146 ioctl(fd, PERF_EVENT_IOC_ENABLE, 0);
147 if (ret < 0) {
148 pr_debug("Failed to enable event\n");
149 close(fd);
150 return ret;
151 }
152
153 data2[1] = tmp; /* Counted */
154 WP_TEST_ASSERT_VAL(fd, "Modify watchpoint", 2);
155
156 data2[2] = tmp; /* Not Counted */
157 WP_TEST_ASSERT_VAL(fd, "Modify watchpoint", 2);
158
159 close(fd);
160 return 0;
161}
162
163static bool wp_ro_supported(void)
164{
165#if defined (__x86_64__) || defined (__i386__)
166 return false;
167#else
168 return true;
169#endif
170}
171
172static void wp_ro_skip_msg(void)
173{
174#if defined (__x86_64__) || defined (__i386__)
175 pr_debug("Hardware does not support read only watchpoints.\n");
176#endif
177}
178
179static struct {
180 const char *desc;
181 int (*target_func)(void);
182 bool (*is_supported)(void);
183 void (*skip_msg)(void);
184} wp_testcase_table[] = {
185 {
186 .desc = "Read Only Watchpoint",
187 .target_func = &wp_ro_test,
188 .is_supported = &wp_ro_supported,
189 .skip_msg = &wp_ro_skip_msg,
190 },
191 {
192 .desc = "Write Only Watchpoint",
193 .target_func = &wp_wo_test,
194 },
195 {
196 .desc = "Read / Write Watchpoint",
197 .target_func = &wp_rw_test,
198 },
199 {
200 .desc = "Modify Watchpoint",
201 .target_func = &wp_modify_test,
202 },
203};
204
205int test__wp_subtest_get_nr(void)
206{
207 return (int)ARRAY_SIZE(wp_testcase_table);
208}
209
210const char *test__wp_subtest_get_desc(int i)
211{
212 if (i < 0 || i >= (int)ARRAY_SIZE(wp_testcase_table))
213 return NULL;
214 return wp_testcase_table[i].desc;
215}
216
217int test__wp(struct test *test __maybe_unused, int i)
218{
219 if (i < 0 || i >= (int)ARRAY_SIZE(wp_testcase_table))
220 return TEST_FAIL;
221
222 if (wp_testcase_table[i].is_supported &&
223 !wp_testcase_table[i].is_supported()) {
224 wp_testcase_table[i].skip_msg();
225 return TEST_SKIP;
226 }
227
228 return !wp_testcase_table[i].target_func() ? TEST_OK : TEST_FAIL;
229}
230
231/* The s390 so far does not have support for
232 * instruction breakpoint using the perf_event_open() system call.
233 */
234bool test__wp_is_supported(void)
235{
236#if defined(__s390x__)
237 return false;
238#else
239 return true;
240#endif
241}
diff --git a/tools/perf/trace/beauty/Build b/tools/perf/trace/beauty/Build
index f528ba35e140..304313073242 100644
--- a/tools/perf/trace/beauty/Build
+++ b/tools/perf/trace/beauty/Build
@@ -5,7 +5,9 @@ ifeq ($(SRCARCH),$(filter $(SRCARCH),x86))
5libperf-y += ioctl.o 5libperf-y += ioctl.o
6endif 6endif
7libperf-y += kcmp.o 7libperf-y += kcmp.o
8libperf-y += mount_flags.o
8libperf-y += pkey_alloc.o 9libperf-y += pkey_alloc.o
9libperf-y += prctl.o 10libperf-y += prctl.o
11libperf-y += sockaddr.o
10libperf-y += socket.o 12libperf-y += socket.o
11libperf-y += statx.o 13libperf-y += statx.o
diff --git a/tools/perf/trace/beauty/beauty.h b/tools/perf/trace/beauty/beauty.h
index 9615af5d412b..039c29039b2c 100644
--- a/tools/perf/trace/beauty/beauty.h
+++ b/tools/perf/trace/beauty/beauty.h
@@ -24,15 +24,43 @@ struct strarray {
24} 24}
25 25
26size_t strarray__scnprintf(struct strarray *sa, char *bf, size_t size, const char *intfmt, int val); 26size_t strarray__scnprintf(struct strarray *sa, char *bf, size_t size, const char *intfmt, int val);
27size_t strarray__scnprintf_flags(struct strarray *sa, char *bf, size_t size, unsigned long flags);
27 28
28struct trace; 29struct trace;
29struct thread; 30struct thread;
30 31
31size_t pid__scnprintf_fd(struct trace *trace, pid_t pid, int fd, char *bf, size_t size); 32size_t pid__scnprintf_fd(struct trace *trace, pid_t pid, int fd, char *bf, size_t size);
32 33
34extern struct strarray strarray__socket_families;
35
36/**
37 * augmented_arg: extra payload for syscall pointer arguments
38
39 * If perf_sample->raw_size is more than what a syscall sys_enter_FOO puts,
40 * then its the arguments contents, so that we can show more than just a
41 * pointer. This will be done initially with eBPF, the start of that is at the
42 * tools/perf/examples/bpf/augmented_syscalls.c example for the openat, but
43 * will eventually be done automagically caching the running kernel tracefs
44 * events data into an eBPF C script, that then gets compiled and its .o file
45 * cached for subsequent use. For char pointers like the ones for 'open' like
46 * syscalls its easy, for the rest we should use DWARF or better, BTF, much
47 * more compact.
48 *
49 * @size: 8 if all we need is an integer, otherwise all of the augmented arg.
50 * @int_arg: will be used for integer like pointer contents, like 'accept's 'upeer_addrlen'
51 * @value: u64 aligned, for structs, pathnames
52 */
53struct augmented_arg {
54 int size;
55 int int_arg;
56 u64 value[];
57};
58
33/** 59/**
34 * @val: value of syscall argument being formatted 60 * @val: value of syscall argument being formatted
35 * @args: All the args, use syscall_args__val(arg, nth) to access one 61 * @args: All the args, use syscall_args__val(arg, nth) to access one
62 * @augmented_args: Extra data that can be collected, for instance, with eBPF for expanding the pathname for open, etc
63 * @augmented_args_size: augmented_args total payload size
36 * @thread: tid state (maps, pid, tid, etc) 64 * @thread: tid state (maps, pid, tid, etc)
37 * @trace: 'perf trace' internals: all threads, etc 65 * @trace: 'perf trace' internals: all threads, etc
38 * @parm: private area, may be an strarray, for instance 66 * @parm: private area, may be an strarray, for instance
@@ -43,6 +71,10 @@ size_t pid__scnprintf_fd(struct trace *trace, pid_t pid, int fd, char *bf, size_
43struct syscall_arg { 71struct syscall_arg {
44 unsigned long val; 72 unsigned long val;
45 unsigned char *args; 73 unsigned char *args;
74 struct {
75 struct augmented_arg *args;
76 int size;
77 } augmented;
46 struct thread *thread; 78 struct thread *thread;
47 struct trace *trace; 79 struct trace *trace;
48 void *parm; 80 void *parm;
@@ -91,6 +123,12 @@ size_t syscall_arg__scnprintf_kcmp_type(char *bf, size_t size, struct syscall_ar
91size_t syscall_arg__scnprintf_kcmp_idx(char *bf, size_t size, struct syscall_arg *arg); 123size_t syscall_arg__scnprintf_kcmp_idx(char *bf, size_t size, struct syscall_arg *arg);
92#define SCA_KCMP_IDX syscall_arg__scnprintf_kcmp_idx 124#define SCA_KCMP_IDX syscall_arg__scnprintf_kcmp_idx
93 125
126unsigned long syscall_arg__mask_val_mount_flags(struct syscall_arg *arg, unsigned long flags);
127#define SCAMV_MOUNT_FLAGS syscall_arg__mask_val_mount_flags
128
129size_t syscall_arg__scnprintf_mount_flags(char *bf, size_t size, struct syscall_arg *arg);
130#define SCA_MOUNT_FLAGS syscall_arg__scnprintf_mount_flags
131
94size_t syscall_arg__scnprintf_pkey_alloc_access_rights(char *bf, size_t size, struct syscall_arg *arg); 132size_t syscall_arg__scnprintf_pkey_alloc_access_rights(char *bf, size_t size, struct syscall_arg *arg);
95#define SCA_PKEY_ALLOC_ACCESS_RIGHTS syscall_arg__scnprintf_pkey_alloc_access_rights 133#define SCA_PKEY_ALLOC_ACCESS_RIGHTS syscall_arg__scnprintf_pkey_alloc_access_rights
96 134
@@ -106,6 +144,9 @@ size_t syscall_arg__scnprintf_prctl_arg2(char *bf, size_t size, struct syscall_a
106size_t syscall_arg__scnprintf_prctl_arg3(char *bf, size_t size, struct syscall_arg *arg); 144size_t syscall_arg__scnprintf_prctl_arg3(char *bf, size_t size, struct syscall_arg *arg);
107#define SCA_PRCTL_ARG3 syscall_arg__scnprintf_prctl_arg3 145#define SCA_PRCTL_ARG3 syscall_arg__scnprintf_prctl_arg3
108 146
147size_t syscall_arg__scnprintf_sockaddr(char *bf, size_t size, struct syscall_arg *arg);
148#define SCA_SOCKADDR syscall_arg__scnprintf_sockaddr
149
109size_t syscall_arg__scnprintf_socket_protocol(char *bf, size_t size, struct syscall_arg *arg); 150size_t syscall_arg__scnprintf_socket_protocol(char *bf, size_t size, struct syscall_arg *arg);
110#define SCA_SK_PROTO syscall_arg__scnprintf_socket_protocol 151#define SCA_SK_PROTO syscall_arg__scnprintf_socket_protocol
111 152
diff --git a/tools/perf/trace/beauty/clone.c b/tools/perf/trace/beauty/clone.c
index d64d049ab991..010406500c30 100644
--- a/tools/perf/trace/beauty/clone.c
+++ b/tools/perf/trace/beauty/clone.c
@@ -1,9 +1,8 @@
1// SPDX-License-Identifier: LGPL-2.1
1/* 2/*
2 * trace/beauty/cone.c 3 * trace/beauty/cone.c
3 * 4 *
4 * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> 5 * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
5 *
6 * Released under the GPL v2. (and only v2, not any later version)
7 */ 6 */
8 7
9#include "trace/beauty/beauty.h" 8#include "trace/beauty/beauty.h"
diff --git a/tools/perf/trace/beauty/drm_ioctl.sh b/tools/perf/trace/beauty/drm_ioctl.sh
index 9d3816815e60..9aa94fd523a9 100755
--- a/tools/perf/trace/beauty/drm_ioctl.sh
+++ b/tools/perf/trace/beauty/drm_ioctl.sh
@@ -1,4 +1,5 @@
1#!/bin/sh 1#!/bin/sh
2# SPDX-License-Identifier: LGPL-2.1
2 3
3[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/drm/ 4[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/drm/
4 5
diff --git a/tools/perf/trace/beauty/eventfd.c b/tools/perf/trace/beauty/eventfd.c
index 5d6a477a6400..db5b9b492113 100644
--- a/tools/perf/trace/beauty/eventfd.c
+++ b/tools/perf/trace/beauty/eventfd.c
@@ -1,4 +1,4 @@
1// SPDX-License-Identifier: GPL-2.0 1// SPDX-License-Identifier: LGPL-2.1
2#ifndef EFD_SEMAPHORE 2#ifndef EFD_SEMAPHORE
3#define EFD_SEMAPHORE 1 3#define EFD_SEMAPHORE 1
4#endif 4#endif
diff --git a/tools/perf/trace/beauty/fcntl.c b/tools/perf/trace/beauty/fcntl.c
index 9e8900c13cb1..e6de31674e24 100644
--- a/tools/perf/trace/beauty/fcntl.c
+++ b/tools/perf/trace/beauty/fcntl.c
@@ -1,9 +1,8 @@
1// SPDX-License-Identifier: LGPL-2.1
1/* 2/*
2 * trace/beauty/fcntl.c 3 * trace/beauty/fcntl.c
3 * 4 *
4 * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> 5 * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
5 *
6 * Released under the GPL v2. (and only v2, not any later version)
7 */ 6 */
8 7
9#include "trace/beauty/beauty.h" 8#include "trace/beauty/beauty.h"
diff --git a/tools/perf/trace/beauty/flock.c b/tools/perf/trace/beauty/flock.c
index c4ff6ad30b06..cf02ae5f0ba6 100644
--- a/tools/perf/trace/beauty/flock.c
+++ b/tools/perf/trace/beauty/flock.c
@@ -1,4 +1,4 @@
1// SPDX-License-Identifier: GPL-2.0 1// SPDX-License-Identifier: LGPL-2.1
2 2
3#include "trace/beauty/beauty.h" 3#include "trace/beauty/beauty.h"
4#include <linux/kernel.h> 4#include <linux/kernel.h>
diff --git a/tools/perf/trace/beauty/futex_op.c b/tools/perf/trace/beauty/futex_op.c
index 61850fbc85ff..1136bde56406 100644
--- a/tools/perf/trace/beauty/futex_op.c
+++ b/tools/perf/trace/beauty/futex_op.c
@@ -1,4 +1,4 @@
1// SPDX-License-Identifier: GPL-2.0 1// SPDX-License-Identifier: LGPL-2.1
2#include <linux/futex.h> 2#include <linux/futex.h>
3 3
4#ifndef FUTEX_WAIT_BITSET 4#ifndef FUTEX_WAIT_BITSET
diff --git a/tools/perf/trace/beauty/futex_val3.c b/tools/perf/trace/beauty/futex_val3.c
index 26f6b3253511..138b7d588a70 100644
--- a/tools/perf/trace/beauty/futex_val3.c
+++ b/tools/perf/trace/beauty/futex_val3.c
@@ -1,4 +1,4 @@
1// SPDX-License-Identifier: GPL-2.0 1// SPDX-License-Identifier: LGPL-2.1
2#include <linux/futex.h> 2#include <linux/futex.h>
3 3
4#ifndef FUTEX_BITSET_MATCH_ANY 4#ifndef FUTEX_BITSET_MATCH_ANY
diff --git a/tools/perf/trace/beauty/ioctl.c b/tools/perf/trace/beauty/ioctl.c
index 1be3b4cf0827..5d2a7fd8d407 100644
--- a/tools/perf/trace/beauty/ioctl.c
+++ b/tools/perf/trace/beauty/ioctl.c
@@ -1,9 +1,8 @@
1// SPDX-License-Identifier: LGPL-2.1
1/* 2/*
2 * trace/beauty/ioctl.c 3 * trace/beauty/ioctl.c
3 * 4 *
4 * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> 5 * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
5 *
6 * Released under the GPL v2. (and only v2, not any later version)
7 */ 6 */
8 7
9#include "trace/beauty/beauty.h" 8#include "trace/beauty/beauty.h"
diff --git a/tools/perf/trace/beauty/kcmp.c b/tools/perf/trace/beauty/kcmp.c
index f62040eb9d5c..b276a274f203 100644
--- a/tools/perf/trace/beauty/kcmp.c
+++ b/tools/perf/trace/beauty/kcmp.c
@@ -1,9 +1,8 @@
1// SPDX-License-Identifier: LGPL-2.1
1/* 2/*
2 * trace/beauty/kcmp.c 3 * trace/beauty/kcmp.c
3 * 4 *
4 * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> 5 * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
5 *
6 * Released under the GPL v2. (and only v2, not any later version)
7 */ 6 */
8 7
9#include "trace/beauty/beauty.h" 8#include "trace/beauty/beauty.h"
diff --git a/tools/perf/trace/beauty/kcmp_type.sh b/tools/perf/trace/beauty/kcmp_type.sh
index a3c304caa336..df8b17486d57 100755
--- a/tools/perf/trace/beauty/kcmp_type.sh
+++ b/tools/perf/trace/beauty/kcmp_type.sh
@@ -1,4 +1,5 @@
1#!/bin/sh 1#!/bin/sh
2# SPDX-License-Identifier: LGPL-2.1
2 3
3[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ 4[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/
4 5
diff --git a/tools/perf/trace/beauty/kvm_ioctl.sh b/tools/perf/trace/beauty/kvm_ioctl.sh
index c4699fd46bb6..4ce54f5bf756 100755
--- a/tools/perf/trace/beauty/kvm_ioctl.sh
+++ b/tools/perf/trace/beauty/kvm_ioctl.sh
@@ -1,4 +1,5 @@
1#!/bin/sh 1#!/bin/sh
2# SPDX-License-Identifier: LGPL-2.1
2 3
3[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ 4[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/
4 5
diff --git a/tools/perf/trace/beauty/madvise_behavior.sh b/tools/perf/trace/beauty/madvise_behavior.sh
index 431639eb4d29..4527d290cdfc 100755
--- a/tools/perf/trace/beauty/madvise_behavior.sh
+++ b/tools/perf/trace/beauty/madvise_behavior.sh
@@ -1,4 +1,5 @@
1#!/bin/sh 1#!/bin/sh
2# SPDX-License-Identifier: LGPL-2.1
2 3
3[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/asm-generic/ 4[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/asm-generic/
4 5
diff --git a/tools/perf/trace/beauty/mmap.c b/tools/perf/trace/beauty/mmap.c
index 9f68077b241b..c534bd96ef5c 100644
--- a/tools/perf/trace/beauty/mmap.c
+++ b/tools/perf/trace/beauty/mmap.c
@@ -1,5 +1,6 @@
1// SPDX-License-Identifier: GPL-2.0 1// SPDX-License-Identifier: LGPL-2.1
2#include <uapi/linux/mman.h> 2#include <uapi/linux/mman.h>
3#include <linux/log2.h>
3 4
4static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size, 5static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
5 struct syscall_arg *arg) 6 struct syscall_arg *arg)
@@ -30,50 +31,23 @@ static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
30 31
31#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot 32#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
32 33
34static size_t mmap__scnprintf_flags(unsigned long flags, char *bf, size_t size)
35{
36#include "trace/beauty/generated/mmap_flags_array.c"
37 static DEFINE_STRARRAY(mmap_flags);
38
39 return strarray__scnprintf_flags(&strarray__mmap_flags, bf, size, flags);
40}
41
33static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size, 42static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
34 struct syscall_arg *arg) 43 struct syscall_arg *arg)
35{ 44{
36 int printed = 0, flags = arg->val; 45 unsigned long flags = arg->val;
37 46
38 if (flags & MAP_ANONYMOUS) 47 if (flags & MAP_ANONYMOUS)
39 arg->mask |= (1 << 4) | (1 << 5); /* Mask 4th ('fd') and 5th ('offset') args, ignored */ 48 arg->mask |= (1 << 4) | (1 << 5); /* Mask 4th ('fd') and 5th ('offset') args, ignored */
40 49
41#define P_MMAP_FLAG(n) \ 50 return mmap__scnprintf_flags(flags, bf, size);
42 if (flags & MAP_##n) { \
43 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
44 flags &= ~MAP_##n; \
45 }
46
47 P_MMAP_FLAG(SHARED);
48 P_MMAP_FLAG(PRIVATE);
49#ifdef MAP_32BIT
50 P_MMAP_FLAG(32BIT);
51#endif
52 P_MMAP_FLAG(ANONYMOUS);
53 P_MMAP_FLAG(DENYWRITE);
54 P_MMAP_FLAG(EXECUTABLE);
55 P_MMAP_FLAG(FILE);
56 P_MMAP_FLAG(FIXED);
57#ifdef MAP_FIXED_NOREPLACE
58 P_MMAP_FLAG(FIXED_NOREPLACE);
59#endif
60 P_MMAP_FLAG(GROWSDOWN);
61 P_MMAP_FLAG(HUGETLB);
62 P_MMAP_FLAG(LOCKED);
63 P_MMAP_FLAG(NONBLOCK);
64 P_MMAP_FLAG(NORESERVE);
65 P_MMAP_FLAG(POPULATE);
66 P_MMAP_FLAG(STACK);
67 P_MMAP_FLAG(UNINITIALIZED);
68#ifdef MAP_SYNC
69 P_MMAP_FLAG(SYNC);
70#endif
71#undef P_MMAP_FLAG
72
73 if (flags)
74 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
75
76 return printed;
77} 51}
78 52
79#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags 53#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
diff --git a/tools/perf/trace/beauty/mmap_flags.sh b/tools/perf/trace/beauty/mmap_flags.sh
new file mode 100755
index 000000000000..22c3fdca8975
--- /dev/null
+++ b/tools/perf/trace/beauty/mmap_flags.sh
@@ -0,0 +1,32 @@
1#!/bin/sh
2# SPDX-License-Identifier: LGPL-2.1
3
4if [ $# -ne 2 ] ; then
5 [ $# -eq 1 ] && hostarch=$1 || hostarch=`uname -m | sed -e s/i.86/x86/ -e s/x86_64/x86/`
6 header_dir=tools/include/uapi/asm-generic
7 arch_header_dir=tools/arch/${hostarch}/include/uapi/asm
8else
9 header_dir=$1
10 arch_header_dir=$2
11fi
12
13arch_mman=${arch_header_dir}/mman.h
14
15# those in egrep -vw are flags, we want just the bits
16
17printf "static const char *mmap_flags[] = {\n"
18regex='^[[:space:]]*#[[:space:]]*define[[:space:]]+MAP_([[:alnum:]_]+)[[:space:]]+(0x[[:xdigit:]]+)[[:space:]]*.*'
19egrep -q $regex ${arch_mman} && \
20(egrep $regex ${arch_mman} | \
21 sed -r "s/$regex/\2 \1/g" | \
22 xargs printf "\t[ilog2(%s) + 1] = \"%s\",\n")
23egrep -q '#[[:space:]]*include[[:space:]]+<uapi/asm-generic/mman.*' ${arch_mman} &&
24(egrep $regex ${header_dir}/mman-common.h | \
25 egrep -vw 'MAP_(UNINITIALIZED|TYPE|SHARED_VALIDATE)' | \
26 sed -r "s/$regex/\2 \1/g" | \
27 xargs printf "\t[ilog2(%s) + 1] = \"%s\",\n")
28egrep -q '#[[:space:]]*include[[:space:]]+<uapi/asm-generic/mman.h>.*' ${arch_mman} &&
29(egrep $regex ${header_dir}/mman.h | \
30 sed -r "s/$regex/\2 \1/g" | \
31 xargs printf "\t[ilog2(%s) + 1] = \"%s\",\n")
32printf "};\n"
diff --git a/tools/perf/trace/beauty/mode_t.c b/tools/perf/trace/beauty/mode_t.c
index d929ad7dd97b..6879d36d3004 100644
--- a/tools/perf/trace/beauty/mode_t.c
+++ b/tools/perf/trace/beauty/mode_t.c
@@ -1,4 +1,4 @@
1// SPDX-License-Identifier: GPL-2.0 1// SPDX-License-Identifier: LGPL-2.1
2#include <sys/types.h> 2#include <sys/types.h>
3#include <sys/stat.h> 3#include <sys/stat.h>
4#include <unistd.h> 4#include <unistd.h>
diff --git a/tools/perf/trace/beauty/mount_flags.c b/tools/perf/trace/beauty/mount_flags.c
new file mode 100644
index 000000000000..712935c6620a
--- /dev/null
+++ b/tools/perf/trace/beauty/mount_flags.c
@@ -0,0 +1,43 @@
1// SPDX-License-Identifier: LGPL-2.1
2/*
3 * trace/beauty/mount_flags.c
4 *
5 * Copyright (C) 2018, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
6 */
7
8#include "trace/beauty/beauty.h"
9#include <linux/compiler.h>
10#include <linux/kernel.h>
11#include <linux/log2.h>
12#include <sys/mount.h>
13
14static size_t mount__scnprintf_flags(unsigned long flags, char *bf, size_t size)
15{
16#include "trace/beauty/generated/mount_flags_array.c"
17 static DEFINE_STRARRAY(mount_flags);
18
19 return strarray__scnprintf_flags(&strarray__mount_flags, bf, size, flags);
20}
21
22unsigned long syscall_arg__mask_val_mount_flags(struct syscall_arg *arg __maybe_unused, unsigned long flags)
23{
24 // do_mount in fs/namespace.c:
25 /*
26 * Pre-0.97 versions of mount() didn't have a flags word. When the
27 * flags word was introduced its top half was required to have the
28 * magic value 0xC0ED, and this remained so until 2.4.0-test9.
29 * Therefore, if this magic number is present, it carries no
30 * information and must be discarded.
31 */
32 if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
33 flags &= ~MS_MGC_MSK;
34
35 return flags;
36}
37
38size_t syscall_arg__scnprintf_mount_flags(char *bf, size_t size, struct syscall_arg *arg)
39{
40 unsigned long flags = arg->val;
41
42 return mount__scnprintf_flags(flags, bf, size);
43}
diff --git a/tools/perf/trace/beauty/mount_flags.sh b/tools/perf/trace/beauty/mount_flags.sh
new file mode 100755
index 000000000000..45547573a1db
--- /dev/null
+++ b/tools/perf/trace/beauty/mount_flags.sh
@@ -0,0 +1,15 @@
1#!/bin/sh
2# SPDX-License-Identifier: LGPL-2.1
3
4[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/
5
6printf "static const char *mount_flags[] = {\n"
7regex='^[[:space:]]*#[[:space:]]*define[[:space:]]+MS_([[:alnum:]_]+)[[:space:]]+([[:digit:]]+)[[:space:]]*.*'
8egrep $regex ${header_dir}/fs.h | egrep -v '(MSK|VERBOSE|MGC_VAL)\>' | \
9 sed -r "s/$regex/\2 \2 \1/g" | sort -n | \
10 xargs printf "\t[%s ? (ilog2(%s) + 1) : 0] = \"%s\",\n"
11regex='^[[:space:]]*#[[:space:]]*define[[:space:]]+MS_([[:alnum:]_]+)[[:space:]]+\(1<<([[:digit:]]+)\)[[:space:]]*.*'
12egrep $regex ${header_dir}/fs.h | \
13 sed -r "s/$regex/\2 \1/g" | \
14 xargs printf "\t[%s + 1] = \"%s\",\n"
15printf "};\n"
diff --git a/tools/perf/trace/beauty/msg_flags.c b/tools/perf/trace/beauty/msg_flags.c
index c064d6aae659..1b9d6306d274 100644
--- a/tools/perf/trace/beauty/msg_flags.c
+++ b/tools/perf/trace/beauty/msg_flags.c
@@ -1,4 +1,4 @@
1// SPDX-License-Identifier: GPL-2.0 1// SPDX-License-Identifier: LGPL-2.1
2#include <sys/types.h> 2#include <sys/types.h>
3#include <sys/socket.h> 3#include <sys/socket.h>
4 4
diff --git a/tools/perf/trace/beauty/open_flags.c b/tools/perf/trace/beauty/open_flags.c
index 6aec6178a99d..cc673fec9184 100644
--- a/tools/perf/trace/beauty/open_flags.c
+++ b/tools/perf/trace/beauty/open_flags.c
@@ -1,4 +1,4 @@
1// SPDX-License-Identifier: GPL-2.0 1// SPDX-License-Identifier: LGPL-2.1
2#include <sys/types.h> 2#include <sys/types.h>
3#include <sys/stat.h> 3#include <sys/stat.h>
4#include <fcntl.h> 4#include <fcntl.h>
diff --git a/tools/perf/trace/beauty/perf_event_open.c b/tools/perf/trace/beauty/perf_event_open.c
index 2bafd7c995ff..981185c1974b 100644
--- a/tools/perf/trace/beauty/perf_event_open.c
+++ b/tools/perf/trace/beauty/perf_event_open.c
@@ -1,4 +1,4 @@
1// SPDX-License-Identifier: GPL-2.0 1// SPDX-License-Identifier: LGPL-2.1
2#ifndef PERF_FLAG_FD_NO_GROUP 2#ifndef PERF_FLAG_FD_NO_GROUP
3# define PERF_FLAG_FD_NO_GROUP (1UL << 0) 3# define PERF_FLAG_FD_NO_GROUP (1UL << 0)
4#endif 4#endif
diff --git a/tools/perf/trace/beauty/perf_ioctl.sh b/tools/perf/trace/beauty/perf_ioctl.sh
index 6492c74df928..9aabd9743ef6 100755
--- a/tools/perf/trace/beauty/perf_ioctl.sh
+++ b/tools/perf/trace/beauty/perf_ioctl.sh
@@ -1,4 +1,5 @@
1#!/bin/sh 1#!/bin/sh
2# SPDX-License-Identifier: LGPL-2.1
2 3
3[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ 4[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/
4 5
diff --git a/tools/perf/trace/beauty/pid.c b/tools/perf/trace/beauty/pid.c
index 0313df342830..1a6acc46807b 100644
--- a/tools/perf/trace/beauty/pid.c
+++ b/tools/perf/trace/beauty/pid.c
@@ -1,4 +1,5 @@
1// SPDX-License-Identifier: GPL-2.0 1// SPDX-License-Identifier: LGPL-2.1
2
2size_t syscall_arg__scnprintf_pid(char *bf, size_t size, struct syscall_arg *arg) 3size_t syscall_arg__scnprintf_pid(char *bf, size_t size, struct syscall_arg *arg)
3{ 4{
4 int pid = arg->val; 5 int pid = arg->val;
diff --git a/tools/perf/trace/beauty/pkey_alloc.c b/tools/perf/trace/beauty/pkey_alloc.c
index 2ba784a3734a..1b8ed4cac815 100644
--- a/tools/perf/trace/beauty/pkey_alloc.c
+++ b/tools/perf/trace/beauty/pkey_alloc.c
@@ -1,40 +1,36 @@
1// SPDX-License-Identifier: LGPL-2.1
1/* 2/*
2 * trace/beauty/pkey_alloc.c 3 * trace/beauty/pkey_alloc.c
3 * 4 *
4 * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> 5 * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
5 *
6 * Released under the GPL v2. (and only v2, not any later version)
7 */ 6 */
8 7
9#include "trace/beauty/beauty.h" 8#include "trace/beauty/beauty.h"
10#include <linux/kernel.h> 9#include <linux/kernel.h>
11#include <linux/log2.h> 10#include <linux/log2.h>
12 11
13static size_t pkey_alloc__scnprintf_access_rights(int access_rights, char *bf, size_t size) 12size_t strarray__scnprintf_flags(struct strarray *sa, char *bf, size_t size, unsigned long flags)
14{ 13{
15 int i, printed = 0; 14 int i, printed = 0;
16 15
17#include "trace/beauty/generated/pkey_alloc_access_rights_array.c" 16 if (flags == 0) {
18 static DEFINE_STRARRAY(pkey_alloc_access_rights); 17 const char *s = sa->entries[0];
19
20 if (access_rights == 0) {
21 const char *s = strarray__pkey_alloc_access_rights.entries[0];
22 if (s) 18 if (s)
23 return scnprintf(bf, size, "%s", s); 19 return scnprintf(bf, size, "%s", s);
24 return scnprintf(bf, size, "%d", 0); 20 return scnprintf(bf, size, "%d", 0);
25 } 21 }
26 22
27 for (i = 1; i < strarray__pkey_alloc_access_rights.nr_entries; ++i) { 23 for (i = 1; i < sa->nr_entries; ++i) {
28 int bit = 1 << (i - 1); 24 unsigned long bit = 1UL << (i - 1);
29 25
30 if (!(access_rights & bit)) 26 if (!(flags & bit))
31 continue; 27 continue;
32 28
33 if (printed != 0) 29 if (printed != 0)
34 printed += scnprintf(bf + printed, size - printed, "|"); 30 printed += scnprintf(bf + printed, size - printed, "|");
35 31
36 if (strarray__pkey_alloc_access_rights.entries[i] != NULL) 32 if (sa->entries[i] != NULL)
37 printed += scnprintf(bf + printed, size - printed, "%s", strarray__pkey_alloc_access_rights.entries[i]); 33 printed += scnprintf(bf + printed, size - printed, "%s", sa->entries[i]);
38 else 34 else
39 printed += scnprintf(bf + printed, size - printed, "0x%#", bit); 35 printed += scnprintf(bf + printed, size - printed, "0x%#", bit);
40 } 36 }
@@ -42,6 +38,14 @@ static size_t pkey_alloc__scnprintf_access_rights(int access_rights, char *bf, s
42 return printed; 38 return printed;
43} 39}
44 40
41static size_t pkey_alloc__scnprintf_access_rights(int access_rights, char *bf, size_t size)
42{
43#include "trace/beauty/generated/pkey_alloc_access_rights_array.c"
44 static DEFINE_STRARRAY(pkey_alloc_access_rights);
45
46 return strarray__scnprintf_flags(&strarray__pkey_alloc_access_rights, bf, size, access_rights);
47}
48
45size_t syscall_arg__scnprintf_pkey_alloc_access_rights(char *bf, size_t size, struct syscall_arg *arg) 49size_t syscall_arg__scnprintf_pkey_alloc_access_rights(char *bf, size_t size, struct syscall_arg *arg)
46{ 50{
47 unsigned long cmd = arg->val; 51 unsigned long cmd = arg->val;
diff --git a/tools/perf/trace/beauty/pkey_alloc_access_rights.sh b/tools/perf/trace/beauty/pkey_alloc_access_rights.sh
index e0a51aeb20b2..f8f1b560cf8a 100755
--- a/tools/perf/trace/beauty/pkey_alloc_access_rights.sh
+++ b/tools/perf/trace/beauty/pkey_alloc_access_rights.sh
@@ -1,4 +1,5 @@
1#!/bin/sh 1#!/bin/sh
2# SPDX-License-Identifier: LGPL-2.1
2 3
3[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/asm-generic/ 4[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/asm-generic/
4 5
diff --git a/tools/perf/trace/beauty/prctl.c b/tools/perf/trace/beauty/prctl.c
index 246130dad6c4..be7a5d395975 100644
--- a/tools/perf/trace/beauty/prctl.c
+++ b/tools/perf/trace/beauty/prctl.c
@@ -1,9 +1,8 @@
1// SPDX-License-Identifier: LGPL-2.1
1/* 2/*
2 * trace/beauty/prctl.c 3 * trace/beauty/prctl.c
3 * 4 *
4 * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> 5 * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
5 *
6 * Released under the GPL v2. (and only v2, not any later version)
7 */ 6 */
8 7
9#include "trace/beauty/beauty.h" 8#include "trace/beauty/beauty.h"
diff --git a/tools/perf/trace/beauty/prctl_option.sh b/tools/perf/trace/beauty/prctl_option.sh
index f24722146ebe..d32f8f1124af 100755
--- a/tools/perf/trace/beauty/prctl_option.sh
+++ b/tools/perf/trace/beauty/prctl_option.sh
@@ -1,4 +1,5 @@
1#!/bin/sh 1#!/bin/sh
2# SPDX-License-Identifier: LGPL-2.1
2 3
3[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ 4[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/
4 5
diff --git a/tools/perf/trace/beauty/sched_policy.c b/tools/perf/trace/beauty/sched_policy.c
index ba5096ae76b6..48f2b5c9aa3e 100644
--- a/tools/perf/trace/beauty/sched_policy.c
+++ b/tools/perf/trace/beauty/sched_policy.c
@@ -1,4 +1,4 @@
1// SPDX-License-Identifier: GPL-2.0 1// SPDX-License-Identifier: LGPL-2.1
2#include <sched.h> 2#include <sched.h>
3 3
4/* 4/*
diff --git a/tools/perf/trace/beauty/seccomp.c b/tools/perf/trace/beauty/seccomp.c
index b7097fd5fed9..e36156b19c70 100644
--- a/tools/perf/trace/beauty/seccomp.c
+++ b/tools/perf/trace/beauty/seccomp.c
@@ -1,4 +1,4 @@
1// SPDX-License-Identifier: GPL-2.0 1// SPDX-License-Identifier: LGPL-2.1
2#ifndef SECCOMP_SET_MODE_STRICT 2#ifndef SECCOMP_SET_MODE_STRICT
3#define SECCOMP_SET_MODE_STRICT 0 3#define SECCOMP_SET_MODE_STRICT 0
4#endif 4#endif
diff --git a/tools/perf/trace/beauty/signum.c b/tools/perf/trace/beauty/signum.c
index bde18a53f090..587fec545b8a 100644
--- a/tools/perf/trace/beauty/signum.c
+++ b/tools/perf/trace/beauty/signum.c
@@ -1,4 +1,4 @@
1// SPDX-License-Identifier: GPL-2.0 1// SPDX-License-Identifier: LGPL-2.1
2#include <signal.h> 2#include <signal.h>
3 3
4static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg) 4static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
diff --git a/tools/perf/trace/beauty/sndrv_ctl_ioctl.sh b/tools/perf/trace/beauty/sndrv_ctl_ioctl.sh
index eb511bb5fbd3..e0803b957593 100755
--- a/tools/perf/trace/beauty/sndrv_ctl_ioctl.sh
+++ b/tools/perf/trace/beauty/sndrv_ctl_ioctl.sh
@@ -1,4 +1,5 @@
1#!/bin/sh 1#!/bin/sh
2# SPDX-License-Identifier: LGPL-2.1
2 3
3[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/sound/ 4[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/sound/
4 5
diff --git a/tools/perf/trace/beauty/sndrv_pcm_ioctl.sh b/tools/perf/trace/beauty/sndrv_pcm_ioctl.sh
index 6818392968b2..7a464a7bf913 100755
--- a/tools/perf/trace/beauty/sndrv_pcm_ioctl.sh
+++ b/tools/perf/trace/beauty/sndrv_pcm_ioctl.sh
@@ -1,4 +1,5 @@
1#!/bin/sh 1#!/bin/sh
2# SPDX-License-Identifier: LGPL-2.1
2 3
3[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/sound/ 4[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/sound/
4 5
diff --git a/tools/perf/trace/beauty/sockaddr.c b/tools/perf/trace/beauty/sockaddr.c
new file mode 100644
index 000000000000..9410ad230f10
--- /dev/null
+++ b/tools/perf/trace/beauty/sockaddr.c
@@ -0,0 +1,76 @@
1// SPDX-License-Identifier: LGPL-2.1
2// Copyright (C) 2018, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
3
4#include "trace/beauty/beauty.h"
5#include <sys/socket.h>
6#include <sys/types.h>
7#include <sys/un.h>
8#include <arpa/inet.h>
9
10static const char *socket_families[] = {
11 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
12 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
13 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
14 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
15 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
16 "ALG", "NFC", "VSOCK",
17};
18DEFINE_STRARRAY(socket_families);
19
20static size_t af_inet__scnprintf(struct sockaddr *sa, char *bf, size_t size)
21{
22 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
23 char tmp[16];
24 return scnprintf(bf, size, ", port: %d, addr: %s", ntohs(sin->sin_port),
25 inet_ntop(sin->sin_family, &sin->sin_addr, tmp, sizeof(tmp)));
26}
27
28static size_t af_inet6__scnprintf(struct sockaddr *sa, char *bf, size_t size)
29{
30 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
31 u32 flowinfo = ntohl(sin6->sin6_flowinfo);
32 char tmp[512];
33 size_t printed = scnprintf(bf, size, ", port: %d, addr: %s", ntohs(sin6->sin6_port),
34 inet_ntop(sin6->sin6_family, &sin6->sin6_addr, tmp, sizeof(tmp)));
35 if (flowinfo != 0)
36 printed += scnprintf(bf + printed, size - printed, ", flowinfo: %lu", flowinfo);
37 if (sin6->sin6_scope_id != 0)
38 printed += scnprintf(bf + printed, size - printed, ", scope_id: %lu", sin6->sin6_scope_id);
39
40 return printed;
41}
42
43static size_t af_local__scnprintf(struct sockaddr *sa, char *bf, size_t size)
44{
45 struct sockaddr_un *sun = (struct sockaddr_un *)sa;
46 return scnprintf(bf, size, ", path: %s", sun->sun_path);
47}
48
49static size_t (*af_scnprintfs[])(struct sockaddr *sa, char *bf, size_t size) = {
50 [AF_LOCAL] = af_local__scnprintf,
51 [AF_INET] = af_inet__scnprintf,
52 [AF_INET6] = af_inet6__scnprintf,
53};
54
55static size_t syscall_arg__scnprintf_augmented_sockaddr(struct syscall_arg *arg, char *bf, size_t size)
56{
57 struct sockaddr *sa = (struct sockaddr *)arg->augmented.args;
58 char family[32];
59 size_t printed;
60
61 strarray__scnprintf(&strarray__socket_families, family, sizeof(family), "%d", sa->sa_family);
62 printed = scnprintf(bf, size, "{ .family: %s", family);
63
64 if (sa->sa_family < ARRAY_SIZE(af_scnprintfs) && af_scnprintfs[sa->sa_family])
65 printed += af_scnprintfs[sa->sa_family](sa, bf + printed, size - printed);
66
67 return printed + scnprintf(bf + printed, size - printed, " }");
68}
69
70size_t syscall_arg__scnprintf_sockaddr(char *bf, size_t size, struct syscall_arg *arg)
71{
72 if (arg->augmented.args)
73 return syscall_arg__scnprintf_augmented_sockaddr(arg, bf, size);
74
75 return scnprintf(bf, size, "%#x", arg->val);
76}
diff --git a/tools/perf/trace/beauty/socket.c b/tools/perf/trace/beauty/socket.c
index 65227269384b..d971a2596417 100644
--- a/tools/perf/trace/beauty/socket.c
+++ b/tools/perf/trace/beauty/socket.c
@@ -1,4 +1,4 @@
1// SPDX-License-Identifier: GPL-2.0 1// SPDX-License-Identifier: LGPL-2.1
2/* 2/*
3 * trace/beauty/socket.c 3 * trace/beauty/socket.c
4 * 4 *
diff --git a/tools/perf/trace/beauty/socket_ipproto.sh b/tools/perf/trace/beauty/socket_ipproto.sh
index a3cc24633bec..de0f2f29017f 100755
--- a/tools/perf/trace/beauty/socket_ipproto.sh
+++ b/tools/perf/trace/beauty/socket_ipproto.sh
@@ -1,4 +1,5 @@
1#!/bin/sh 1#!/bin/sh
2# SPDX-License-Identifier: LGPL-2.1
2 3
3[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ 4[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/
4 5
diff --git a/tools/perf/trace/beauty/socket_type.c b/tools/perf/trace/beauty/socket_type.c
index bca26aef4a77..a63a9a332aa0 100644
--- a/tools/perf/trace/beauty/socket_type.c
+++ b/tools/perf/trace/beauty/socket_type.c
@@ -1,4 +1,4 @@
1// SPDX-License-Identifier: GPL-2.0 1// SPDX-License-Identifier: LGPL-2.1
2#include <sys/types.h> 2#include <sys/types.h>
3#include <sys/socket.h> 3#include <sys/socket.h>
4 4
diff --git a/tools/perf/trace/beauty/statx.c b/tools/perf/trace/beauty/statx.c
index 5643b692af4c..630f2760dd66 100644
--- a/tools/perf/trace/beauty/statx.c
+++ b/tools/perf/trace/beauty/statx.c
@@ -1,9 +1,8 @@
1// SPDX-License-Identifier: LGPL-2.1
1/* 2/*
2 * trace/beauty/statx.c 3 * trace/beauty/statx.c
3 * 4 *
4 * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> 5 * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
5 *
6 * Released under the GPL v2. (and only v2, not any later version)
7 */ 6 */
8 7
9#include "trace/beauty/beauty.h" 8#include "trace/beauty/beauty.h"
diff --git a/tools/perf/trace/beauty/vhost_virtio_ioctl.sh b/tools/perf/trace/beauty/vhost_virtio_ioctl.sh
index 0f6a5197d0be..439773daaf77 100755
--- a/tools/perf/trace/beauty/vhost_virtio_ioctl.sh
+++ b/tools/perf/trace/beauty/vhost_virtio_ioctl.sh
@@ -1,4 +1,5 @@
1#!/bin/sh 1#!/bin/sh
2# SPDX-License-Identifier: LGPL-2.1
2 3
3[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ 4[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/
4 5
diff --git a/tools/perf/trace/beauty/waitid_options.c b/tools/perf/trace/beauty/waitid_options.c
index 8465281a093d..42ff58ad613b 100644
--- a/tools/perf/trace/beauty/waitid_options.c
+++ b/tools/perf/trace/beauty/waitid_options.c
@@ -1,4 +1,4 @@
1// SPDX-License-Identifier: GPL-2.0 1// SPDX-License-Identifier: LGPL-2.1
2#include <sys/types.h> 2#include <sys/types.h>
3#include <sys/wait.h> 3#include <sys/wait.h>
4 4
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index 7efe15b9618d..ecd9f9ceda77 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -73,6 +73,7 @@ libperf-y += vdso.o
73libperf-y += counts.o 73libperf-y += counts.o
74libperf-y += stat.o 74libperf-y += stat.o
75libperf-y += stat-shadow.o 75libperf-y += stat-shadow.o
76libperf-y += stat-display.o
76libperf-y += record.o 77libperf-y += record.o
77libperf-y += srcline.o 78libperf-y += srcline.o
78libperf-y += data.o 79libperf-y += data.o
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 28cd6a17491b..6936daf89ddd 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -139,6 +139,7 @@ static int arch__associate_ins_ops(struct arch* arch, const char *name, struct i
139#include "arch/x86/annotate/instructions.c" 139#include "arch/x86/annotate/instructions.c"
140#include "arch/powerpc/annotate/instructions.c" 140#include "arch/powerpc/annotate/instructions.c"
141#include "arch/s390/annotate/instructions.c" 141#include "arch/s390/annotate/instructions.c"
142#include "arch/sparc/annotate/instructions.c"
142 143
143static struct arch architectures[] = { 144static struct arch architectures[] = {
144 { 145 {
@@ -170,6 +171,13 @@ static struct arch architectures[] = {
170 .comment_char = '#', 171 .comment_char = '#',
171 }, 172 },
172 }, 173 },
174 {
175 .name = "sparc",
176 .init = sparc__annotate_init,
177 .objdump = {
178 .comment_char = '#',
179 },
180 },
173}; 181};
174 182
175static void ins__delete(struct ins_operands *ops) 183static void ins__delete(struct ins_operands *ops)
diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
index db1511359c5e..72d5ba2479bf 100644
--- a/tools/perf/util/auxtrace.c
+++ b/tools/perf/util/auxtrace.c
@@ -906,9 +906,8 @@ out_free:
906 return err; 906 return err;
907} 907}
908 908
909int perf_event__process_auxtrace_info(struct perf_tool *tool __maybe_unused, 909int perf_event__process_auxtrace_info(struct perf_session *session,
910 union perf_event *event, 910 union perf_event *event)
911 struct perf_session *session)
912{ 911{
913 enum auxtrace_type type = event->auxtrace_info.type; 912 enum auxtrace_type type = event->auxtrace_info.type;
914 913
@@ -932,9 +931,8 @@ int perf_event__process_auxtrace_info(struct perf_tool *tool __maybe_unused,
932 } 931 }
933} 932}
934 933
935s64 perf_event__process_auxtrace(struct perf_tool *tool, 934s64 perf_event__process_auxtrace(struct perf_session *session,
936 union perf_event *event, 935 union perf_event *event)
937 struct perf_session *session)
938{ 936{
939 s64 err; 937 s64 err;
940 938
@@ -950,7 +948,7 @@ s64 perf_event__process_auxtrace(struct perf_tool *tool,
950 if (!session->auxtrace || event->header.type != PERF_RECORD_AUXTRACE) 948 if (!session->auxtrace || event->header.type != PERF_RECORD_AUXTRACE)
951 return -EINVAL; 949 return -EINVAL;
952 950
953 err = session->auxtrace->process_auxtrace_event(session, event, tool); 951 err = session->auxtrace->process_auxtrace_event(session, event, session->tool);
954 if (err < 0) 952 if (err < 0)
955 return err; 953 return err;
956 954
@@ -964,16 +962,23 @@ s64 perf_event__process_auxtrace(struct perf_tool *tool,
964#define PERF_ITRACE_DEFAULT_LAST_BRANCH_SZ 64 962#define PERF_ITRACE_DEFAULT_LAST_BRANCH_SZ 64
965#define PERF_ITRACE_MAX_LAST_BRANCH_SZ 1024 963#define PERF_ITRACE_MAX_LAST_BRANCH_SZ 1024
966 964
967void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts) 965void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts,
966 bool no_sample)
968{ 967{
969 synth_opts->instructions = true;
970 synth_opts->branches = true; 968 synth_opts->branches = true;
971 synth_opts->transactions = true; 969 synth_opts->transactions = true;
972 synth_opts->ptwrites = true; 970 synth_opts->ptwrites = true;
973 synth_opts->pwr_events = true; 971 synth_opts->pwr_events = true;
974 synth_opts->errors = true; 972 synth_opts->errors = true;
975 synth_opts->period_type = PERF_ITRACE_DEFAULT_PERIOD_TYPE; 973 if (no_sample) {
976 synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD; 974 synth_opts->period_type = PERF_ITRACE_PERIOD_INSTRUCTIONS;
975 synth_opts->period = 1;
976 synth_opts->calls = true;
977 } else {
978 synth_opts->instructions = true;
979 synth_opts->period_type = PERF_ITRACE_DEFAULT_PERIOD_TYPE;
980 synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD;
981 }
977 synth_opts->callchain_sz = PERF_ITRACE_DEFAULT_CALLCHAIN_SZ; 982 synth_opts->callchain_sz = PERF_ITRACE_DEFAULT_CALLCHAIN_SZ;
978 synth_opts->last_branch_sz = PERF_ITRACE_DEFAULT_LAST_BRANCH_SZ; 983 synth_opts->last_branch_sz = PERF_ITRACE_DEFAULT_LAST_BRANCH_SZ;
979 synth_opts->initial_skip = 0; 984 synth_opts->initial_skip = 0;
@@ -1001,7 +1006,7 @@ int itrace_parse_synth_opts(const struct option *opt, const char *str,
1001 } 1006 }
1002 1007
1003 if (!str) { 1008 if (!str) {
1004 itrace_synth_opts__set_default(synth_opts); 1009 itrace_synth_opts__set_default(synth_opts, false);
1005 return 0; 1010 return 0;
1006 } 1011 }
1007 1012
@@ -1185,9 +1190,8 @@ void events_stats__auxtrace_error_warn(const struct events_stats *stats)
1185 } 1190 }
1186} 1191}
1187 1192
1188int perf_event__process_auxtrace_error(struct perf_tool *tool __maybe_unused, 1193int perf_event__process_auxtrace_error(struct perf_session *session,
1189 union perf_event *event, 1194 union perf_event *event)
1190 struct perf_session *session)
1191{ 1195{
1192 if (auxtrace__dont_decode(session)) 1196 if (auxtrace__dont_decode(session))
1193 return 0; 1197 return 0;
@@ -1196,11 +1200,12 @@ int perf_event__process_auxtrace_error(struct perf_tool *tool __maybe_unused,
1196 return 0; 1200 return 0;
1197} 1201}
1198 1202
1199static int __auxtrace_mmap__read(struct auxtrace_mmap *mm, 1203static int __auxtrace_mmap__read(struct perf_mmap *map,
1200 struct auxtrace_record *itr, 1204 struct auxtrace_record *itr,
1201 struct perf_tool *tool, process_auxtrace_t fn, 1205 struct perf_tool *tool, process_auxtrace_t fn,
1202 bool snapshot, size_t snapshot_size) 1206 bool snapshot, size_t snapshot_size)
1203{ 1207{
1208 struct auxtrace_mmap *mm = &map->auxtrace_mmap;
1204 u64 head, old = mm->prev, offset, ref; 1209 u64 head, old = mm->prev, offset, ref;
1205 unsigned char *data = mm->base; 1210 unsigned char *data = mm->base;
1206 size_t size, head_off, old_off, len1, len2, padding; 1211 size_t size, head_off, old_off, len1, len2, padding;
@@ -1287,7 +1292,7 @@ static int __auxtrace_mmap__read(struct auxtrace_mmap *mm,
1287 ev.auxtrace.tid = mm->tid; 1292 ev.auxtrace.tid = mm->tid;
1288 ev.auxtrace.cpu = mm->cpu; 1293 ev.auxtrace.cpu = mm->cpu;
1289 1294
1290 if (fn(tool, &ev, data1, len1, data2, len2)) 1295 if (fn(tool, map, &ev, data1, len1, data2, len2))
1291 return -1; 1296 return -1;
1292 1297
1293 mm->prev = head; 1298 mm->prev = head;
@@ -1306,18 +1311,18 @@ static int __auxtrace_mmap__read(struct auxtrace_mmap *mm,
1306 return 1; 1311 return 1;
1307} 1312}
1308 1313
1309int auxtrace_mmap__read(struct auxtrace_mmap *mm, struct auxtrace_record *itr, 1314int auxtrace_mmap__read(struct perf_mmap *map, struct auxtrace_record *itr,
1310 struct perf_tool *tool, process_auxtrace_t fn) 1315 struct perf_tool *tool, process_auxtrace_t fn)
1311{ 1316{
1312 return __auxtrace_mmap__read(mm, itr, tool, fn, false, 0); 1317 return __auxtrace_mmap__read(map, itr, tool, fn, false, 0);
1313} 1318}
1314 1319
1315int auxtrace_mmap__read_snapshot(struct auxtrace_mmap *mm, 1320int auxtrace_mmap__read_snapshot(struct perf_mmap *map,
1316 struct auxtrace_record *itr, 1321 struct auxtrace_record *itr,
1317 struct perf_tool *tool, process_auxtrace_t fn, 1322 struct perf_tool *tool, process_auxtrace_t fn,
1318 size_t snapshot_size) 1323 size_t snapshot_size)
1319{ 1324{
1320 return __auxtrace_mmap__read(mm, itr, tool, fn, true, snapshot_size); 1325 return __auxtrace_mmap__read(map, itr, tool, fn, true, snapshot_size);
1321} 1326}
1322 1327
1323/** 1328/**
diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h
index 71fc3bd74299..8e50f96d4b23 100644
--- a/tools/perf/util/auxtrace.h
+++ b/tools/perf/util/auxtrace.h
@@ -23,6 +23,7 @@
23#include <linux/list.h> 23#include <linux/list.h>
24#include <linux/perf_event.h> 24#include <linux/perf_event.h>
25#include <linux/types.h> 25#include <linux/types.h>
26#include <asm/bitsperlong.h>
26 27
27#include "../perf.h" 28#include "../perf.h"
28#include "event.h" 29#include "event.h"
@@ -33,6 +34,7 @@ union perf_event;
33struct perf_session; 34struct perf_session;
34struct perf_evlist; 35struct perf_evlist;
35struct perf_tool; 36struct perf_tool;
37struct perf_mmap;
36struct option; 38struct option;
37struct record_opts; 39struct record_opts;
38struct auxtrace_info_event; 40struct auxtrace_info_event;
@@ -56,6 +58,7 @@ enum itrace_period_type {
56/** 58/**
57 * struct itrace_synth_opts - AUX area tracing synthesis options. 59 * struct itrace_synth_opts - AUX area tracing synthesis options.
58 * @set: indicates whether or not options have been set 60 * @set: indicates whether or not options have been set
61 * @default_no_sample: Default to no sampling.
59 * @inject: indicates the event (not just the sample) must be fully synthesized 62 * @inject: indicates the event (not just the sample) must be fully synthesized
60 * because 'perf inject' will write it out 63 * because 'perf inject' will write it out
61 * @instructions: whether to synthesize 'instructions' events 64 * @instructions: whether to synthesize 'instructions' events
@@ -80,6 +83,7 @@ enum itrace_period_type {
80 */ 83 */
81struct itrace_synth_opts { 84struct itrace_synth_opts {
82 bool set; 85 bool set;
86 bool default_no_sample;
83 bool inject; 87 bool inject;
84 bool instructions; 88 bool instructions;
85 bool branches; 89 bool branches;
@@ -434,13 +438,14 @@ void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp,
434 bool per_cpu); 438 bool per_cpu);
435 439
436typedef int (*process_auxtrace_t)(struct perf_tool *tool, 440typedef int (*process_auxtrace_t)(struct perf_tool *tool,
441 struct perf_mmap *map,
437 union perf_event *event, void *data1, 442 union perf_event *event, void *data1,
438 size_t len1, void *data2, size_t len2); 443 size_t len1, void *data2, size_t len2);
439 444
440int auxtrace_mmap__read(struct auxtrace_mmap *mm, struct auxtrace_record *itr, 445int auxtrace_mmap__read(struct perf_mmap *map, struct auxtrace_record *itr,
441 struct perf_tool *tool, process_auxtrace_t fn); 446 struct perf_tool *tool, process_auxtrace_t fn);
442 447
443int auxtrace_mmap__read_snapshot(struct auxtrace_mmap *mm, 448int auxtrace_mmap__read_snapshot(struct perf_mmap *map,
444 struct auxtrace_record *itr, 449 struct auxtrace_record *itr,
445 struct perf_tool *tool, process_auxtrace_t fn, 450 struct perf_tool *tool, process_auxtrace_t fn,
446 size_t snapshot_size); 451 size_t snapshot_size);
@@ -517,18 +522,16 @@ int perf_event__synthesize_auxtrace_info(struct auxtrace_record *itr,
517 struct perf_tool *tool, 522 struct perf_tool *tool,
518 struct perf_session *session, 523 struct perf_session *session,
519 perf_event__handler_t process); 524 perf_event__handler_t process);
520int perf_event__process_auxtrace_info(struct perf_tool *tool, 525int perf_event__process_auxtrace_info(struct perf_session *session,
521 union perf_event *event, 526 union perf_event *event);
522 struct perf_session *session); 527s64 perf_event__process_auxtrace(struct perf_session *session,
523s64 perf_event__process_auxtrace(struct perf_tool *tool, 528 union perf_event *event);
524 union perf_event *event, 529int perf_event__process_auxtrace_error(struct perf_session *session,
525 struct perf_session *session); 530 union perf_event *event);
526int perf_event__process_auxtrace_error(struct perf_tool *tool,
527 union perf_event *event,
528 struct perf_session *session);
529int itrace_parse_synth_opts(const struct option *opt, const char *str, 531int itrace_parse_synth_opts(const struct option *opt, const char *str,
530 int unset); 532 int unset);
531void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts); 533void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts,
534 bool no_sample);
532 535
533size_t perf_event__fprintf_auxtrace_error(union perf_event *event, FILE *fp); 536size_t perf_event__fprintf_auxtrace_error(union perf_event *event, FILE *fp);
534void perf_session__auxtrace_error_inc(struct perf_session *session, 537void perf_session__auxtrace_error_inc(struct perf_session *session,
@@ -577,6 +580,23 @@ static inline void auxtrace__free(struct perf_session *session)
577 return session->auxtrace->free(session); 580 return session->auxtrace->free(session);
578} 581}
579 582
583#define ITRACE_HELP \
584" i: synthesize instructions events\n" \
585" b: synthesize branches events\n" \
586" c: synthesize branches events (calls only)\n" \
587" r: synthesize branches events (returns only)\n" \
588" x: synthesize transactions events\n" \
589" w: synthesize ptwrite events\n" \
590" p: synthesize power events\n" \
591" e: synthesize error events\n" \
592" d: create a debug log\n" \
593" g[len]: synthesize a call chain (use with i or x)\n" \
594" l[len]: synthesize last branch entries (use with i or x)\n" \
595" sNUMBER: skip initial number of events\n" \
596" PERIOD[ns|us|ms|i|t]: specify period to sample stream\n" \
597" concatenate multiple options. Default is ibxwpe or cewp\n"
598
599
580#else 600#else
581 601
582static inline struct auxtrace_record * 602static inline struct auxtrace_record *
@@ -717,6 +737,8 @@ void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp,
717 struct perf_evlist *evlist, int idx, 737 struct perf_evlist *evlist, int idx,
718 bool per_cpu); 738 bool per_cpu);
719 739
740#define ITRACE_HELP ""
741
720#endif 742#endif
721 743
722#endif 744#endif
diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index 47aac41349a2..f9ae1a993806 100644
--- a/tools/perf/util/bpf-loader.c
+++ b/tools/perf/util/bpf-loader.c
@@ -1615,7 +1615,7 @@ struct perf_evsel *bpf__setup_output_event(struct perf_evlist *evlist, const cha
1615int bpf__setup_stdout(struct perf_evlist *evlist) 1615int bpf__setup_stdout(struct perf_evlist *evlist)
1616{ 1616{
1617 struct perf_evsel *evsel = bpf__setup_output_event(evlist, "__bpf_stdout__"); 1617 struct perf_evsel *evsel = bpf__setup_output_event(evlist, "__bpf_stdout__");
1618 return IS_ERR(evsel) ? PTR_ERR(evsel) : 0; 1618 return PTR_ERR_OR_ZERO(evsel);
1619} 1619}
1620 1620
1621#define ERRNO_OFFSET(e) ((e) - __BPF_LOADER_ERRNO__START) 1621#define ERRNO_OFFSET(e) ((e) - __BPF_LOADER_ERRNO__START)
diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
index 2ae640257fdb..73430b73570d 100644
--- a/tools/perf/util/cs-etm.c
+++ b/tools/perf/util/cs-etm.c
@@ -244,6 +244,27 @@ static void cs_etm__free(struct perf_session *session)
244 zfree(&aux); 244 zfree(&aux);
245} 245}
246 246
247static u8 cs_etm__cpu_mode(struct cs_etm_queue *etmq, u64 address)
248{
249 struct machine *machine;
250
251 machine = etmq->etm->machine;
252
253 if (address >= etmq->etm->kernel_start) {
254 if (machine__is_host(machine))
255 return PERF_RECORD_MISC_KERNEL;
256 else
257 return PERF_RECORD_MISC_GUEST_KERNEL;
258 } else {
259 if (machine__is_host(machine))
260 return PERF_RECORD_MISC_USER;
261 else if (perf_guest)
262 return PERF_RECORD_MISC_GUEST_USER;
263 else
264 return PERF_RECORD_MISC_HYPERVISOR;
265 }
266}
267
247static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u64 address, 268static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u64 address,
248 size_t size, u8 *buffer) 269 size_t size, u8 *buffer)
249{ 270{
@@ -258,10 +279,7 @@ static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u64 address,
258 return -1; 279 return -1;
259 280
260 machine = etmq->etm->machine; 281 machine = etmq->etm->machine;
261 if (address >= etmq->etm->kernel_start) 282 cpumode = cs_etm__cpu_mode(etmq, address);
262 cpumode = PERF_RECORD_MISC_KERNEL;
263 else
264 cpumode = PERF_RECORD_MISC_USER;
265 283
266 thread = etmq->thread; 284 thread = etmq->thread;
267 if (!thread) { 285 if (!thread) {
@@ -653,7 +671,7 @@ static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq,
653 struct perf_sample sample = {.ip = 0,}; 671 struct perf_sample sample = {.ip = 0,};
654 672
655 event->sample.header.type = PERF_RECORD_SAMPLE; 673 event->sample.header.type = PERF_RECORD_SAMPLE;
656 event->sample.header.misc = PERF_RECORD_MISC_USER; 674 event->sample.header.misc = cs_etm__cpu_mode(etmq, addr);
657 event->sample.header.size = sizeof(struct perf_event_header); 675 event->sample.header.size = sizeof(struct perf_event_header);
658 676
659 sample.ip = addr; 677 sample.ip = addr;
@@ -665,7 +683,7 @@ static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq,
665 sample.cpu = etmq->packet->cpu; 683 sample.cpu = etmq->packet->cpu;
666 sample.flags = 0; 684 sample.flags = 0;
667 sample.insn_len = 1; 685 sample.insn_len = 1;
668 sample.cpumode = event->header.misc; 686 sample.cpumode = event->sample.header.misc;
669 687
670 if (etm->synth_opts.last_branch) { 688 if (etm->synth_opts.last_branch) {
671 cs_etm__copy_last_branch_rb(etmq); 689 cs_etm__copy_last_branch_rb(etmq);
@@ -706,12 +724,15 @@ static int cs_etm__synth_branch_sample(struct cs_etm_queue *etmq)
706 u64 nr; 724 u64 nr;
707 struct branch_entry entries; 725 struct branch_entry entries;
708 } dummy_bs; 726 } dummy_bs;
727 u64 ip;
728
729 ip = cs_etm__last_executed_instr(etmq->prev_packet);
709 730
710 event->sample.header.type = PERF_RECORD_SAMPLE; 731 event->sample.header.type = PERF_RECORD_SAMPLE;
711 event->sample.header.misc = PERF_RECORD_MISC_USER; 732 event->sample.header.misc = cs_etm__cpu_mode(etmq, ip);
712 event->sample.header.size = sizeof(struct perf_event_header); 733 event->sample.header.size = sizeof(struct perf_event_header);
713 734
714 sample.ip = cs_etm__last_executed_instr(etmq->prev_packet); 735 sample.ip = ip;
715 sample.pid = etmq->pid; 736 sample.pid = etmq->pid;
716 sample.tid = etmq->tid; 737 sample.tid = etmq->tid;
717 sample.addr = cs_etm__first_executed_instr(etmq->packet); 738 sample.addr = cs_etm__first_executed_instr(etmq->packet);
@@ -720,7 +741,7 @@ static int cs_etm__synth_branch_sample(struct cs_etm_queue *etmq)
720 sample.period = 1; 741 sample.period = 1;
721 sample.cpu = etmq->packet->cpu; 742 sample.cpu = etmq->packet->cpu;
722 sample.flags = 0; 743 sample.flags = 0;
723 sample.cpumode = PERF_RECORD_MISC_USER; 744 sample.cpumode = event->sample.header.misc;
724 745
725 /* 746 /*
726 * perf report cannot handle events without a branch stack 747 * perf report cannot handle events without a branch stack
@@ -1432,7 +1453,8 @@ int cs_etm__process_auxtrace_info(union perf_event *event,
1432 if (session->itrace_synth_opts && session->itrace_synth_opts->set) { 1453 if (session->itrace_synth_opts && session->itrace_synth_opts->set) {
1433 etm->synth_opts = *session->itrace_synth_opts; 1454 etm->synth_opts = *session->itrace_synth_opts;
1434 } else { 1455 } else {
1435 itrace_synth_opts__set_default(&etm->synth_opts); 1456 itrace_synth_opts__set_default(&etm->synth_opts,
1457 session->itrace_synth_opts->default_no_sample);
1436 etm->synth_opts.callchain = false; 1458 etm->synth_opts.callchain = false;
1437 } 1459 }
1438 1460
diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c
index abd38abf1d91..2a36fab76994 100644
--- a/tools/perf/util/data-convert-bt.c
+++ b/tools/perf/util/data-convert-bt.c
@@ -182,20 +182,20 @@ err_put_field:
182} 182}
183 183
184static struct bt_ctf_field_type* 184static struct bt_ctf_field_type*
185get_tracepoint_field_type(struct ctf_writer *cw, struct format_field *field) 185get_tracepoint_field_type(struct ctf_writer *cw, struct tep_format_field *field)
186{ 186{
187 unsigned long flags = field->flags; 187 unsigned long flags = field->flags;
188 188
189 if (flags & FIELD_IS_STRING) 189 if (flags & TEP_FIELD_IS_STRING)
190 return cw->data.string; 190 return cw->data.string;
191 191
192 if (!(flags & FIELD_IS_SIGNED)) { 192 if (!(flags & TEP_FIELD_IS_SIGNED)) {
193 /* unsigned long are mostly pointers */ 193 /* unsigned long are mostly pointers */
194 if (flags & FIELD_IS_LONG || flags & FIELD_IS_POINTER) 194 if (flags & TEP_FIELD_IS_LONG || flags & TEP_FIELD_IS_POINTER)
195 return cw->data.u64_hex; 195 return cw->data.u64_hex;
196 } 196 }
197 197
198 if (flags & FIELD_IS_SIGNED) { 198 if (flags & TEP_FIELD_IS_SIGNED) {
199 if (field->size == 8) 199 if (field->size == 8)
200 return cw->data.s64; 200 return cw->data.s64;
201 else 201 else
@@ -287,7 +287,7 @@ static int add_tracepoint_field_value(struct ctf_writer *cw,
287 struct bt_ctf_event_class *event_class, 287 struct bt_ctf_event_class *event_class,
288 struct bt_ctf_event *event, 288 struct bt_ctf_event *event,
289 struct perf_sample *sample, 289 struct perf_sample *sample,
290 struct format_field *fmtf) 290 struct tep_format_field *fmtf)
291{ 291{
292 struct bt_ctf_field_type *type; 292 struct bt_ctf_field_type *type;
293 struct bt_ctf_field *array_field; 293 struct bt_ctf_field *array_field;
@@ -304,10 +304,10 @@ static int add_tracepoint_field_value(struct ctf_writer *cw,
304 name = fmtf->alias; 304 name = fmtf->alias;
305 offset = fmtf->offset; 305 offset = fmtf->offset;
306 len = fmtf->size; 306 len = fmtf->size;
307 if (flags & FIELD_IS_STRING) 307 if (flags & TEP_FIELD_IS_STRING)
308 flags &= ~FIELD_IS_ARRAY; 308 flags &= ~TEP_FIELD_IS_ARRAY;
309 309
310 if (flags & FIELD_IS_DYNAMIC) { 310 if (flags & TEP_FIELD_IS_DYNAMIC) {
311 unsigned long long tmp_val; 311 unsigned long long tmp_val;
312 312
313 tmp_val = tep_read_number(fmtf->event->pevent, 313 tmp_val = tep_read_number(fmtf->event->pevent,
@@ -317,7 +317,7 @@ static int add_tracepoint_field_value(struct ctf_writer *cw,
317 offset &= 0xffff; 317 offset &= 0xffff;
318 } 318 }
319 319
320 if (flags & FIELD_IS_ARRAY) { 320 if (flags & TEP_FIELD_IS_ARRAY) {
321 321
322 type = bt_ctf_event_class_get_field_by_name( 322 type = bt_ctf_event_class_get_field_by_name(
323 event_class, name); 323 event_class, name);
@@ -338,7 +338,7 @@ static int add_tracepoint_field_value(struct ctf_writer *cw,
338 type = get_tracepoint_field_type(cw, fmtf); 338 type = get_tracepoint_field_type(cw, fmtf);
339 339
340 for (i = 0; i < n_items; i++) { 340 for (i = 0; i < n_items; i++) {
341 if (flags & FIELD_IS_ARRAY) 341 if (flags & TEP_FIELD_IS_ARRAY)
342 field = bt_ctf_field_array_get_field(array_field, i); 342 field = bt_ctf_field_array_get_field(array_field, i);
343 else 343 else
344 field = bt_ctf_field_create(type); 344 field = bt_ctf_field_create(type);
@@ -348,7 +348,7 @@ static int add_tracepoint_field_value(struct ctf_writer *cw,
348 return -1; 348 return -1;
349 } 349 }
350 350
351 if (flags & FIELD_IS_STRING) 351 if (flags & TEP_FIELD_IS_STRING)
352 ret = string_set_value(field, data + offset + i * len); 352 ret = string_set_value(field, data + offset + i * len);
353 else { 353 else {
354 unsigned long long value_int; 354 unsigned long long value_int;
@@ -357,7 +357,7 @@ static int add_tracepoint_field_value(struct ctf_writer *cw,
357 fmtf->event->pevent, 357 fmtf->event->pevent,
358 data + offset + i * len, len); 358 data + offset + i * len, len);
359 359
360 if (!(flags & FIELD_IS_SIGNED)) 360 if (!(flags & TEP_FIELD_IS_SIGNED))
361 ret = bt_ctf_field_unsigned_integer_set_value( 361 ret = bt_ctf_field_unsigned_integer_set_value(
362 field, value_int); 362 field, value_int);
363 else 363 else
@@ -369,7 +369,7 @@ static int add_tracepoint_field_value(struct ctf_writer *cw,
369 pr_err("failed to set file value %s\n", name); 369 pr_err("failed to set file value %s\n", name);
370 goto err_put_field; 370 goto err_put_field;
371 } 371 }
372 if (!(flags & FIELD_IS_ARRAY)) { 372 if (!(flags & TEP_FIELD_IS_ARRAY)) {
373 ret = bt_ctf_event_set_payload(event, name, field); 373 ret = bt_ctf_event_set_payload(event, name, field);
374 if (ret) { 374 if (ret) {
375 pr_err("failed to set payload %s\n", name); 375 pr_err("failed to set payload %s\n", name);
@@ -378,7 +378,7 @@ static int add_tracepoint_field_value(struct ctf_writer *cw,
378 } 378 }
379 bt_ctf_field_put(field); 379 bt_ctf_field_put(field);
380 } 380 }
381 if (flags & FIELD_IS_ARRAY) { 381 if (flags & TEP_FIELD_IS_ARRAY) {
382 ret = bt_ctf_event_set_payload(event, name, array_field); 382 ret = bt_ctf_event_set_payload(event, name, array_field);
383 if (ret) { 383 if (ret) {
384 pr_err("Failed add payload array %s\n", name); 384 pr_err("Failed add payload array %s\n", name);
@@ -396,10 +396,10 @@ err_put_field:
396static int add_tracepoint_fields_values(struct ctf_writer *cw, 396static int add_tracepoint_fields_values(struct ctf_writer *cw,
397 struct bt_ctf_event_class *event_class, 397 struct bt_ctf_event_class *event_class,
398 struct bt_ctf_event *event, 398 struct bt_ctf_event *event,
399 struct format_field *fields, 399 struct tep_format_field *fields,
400 struct perf_sample *sample) 400 struct perf_sample *sample)
401{ 401{
402 struct format_field *field; 402 struct tep_format_field *field;
403 int ret; 403 int ret;
404 404
405 for (field = fields; field; field = field->next) { 405 for (field = fields; field; field = field->next) {
@@ -417,8 +417,8 @@ static int add_tracepoint_values(struct ctf_writer *cw,
417 struct perf_evsel *evsel, 417 struct perf_evsel *evsel,
418 struct perf_sample *sample) 418 struct perf_sample *sample)
419{ 419{
420 struct format_field *common_fields = evsel->tp_format->format.common_fields; 420 struct tep_format_field *common_fields = evsel->tp_format->format.common_fields;
421 struct format_field *fields = evsel->tp_format->format.fields; 421 struct tep_format_field *fields = evsel->tp_format->format.fields;
422 int ret; 422 int ret;
423 423
424 ret = add_tracepoint_fields_values(cw, event_class, event, 424 ret = add_tracepoint_fields_values(cw, event_class, event,
@@ -970,7 +970,7 @@ out:
970 970
971static int event_class_add_field(struct bt_ctf_event_class *event_class, 971static int event_class_add_field(struct bt_ctf_event_class *event_class,
972 struct bt_ctf_field_type *type, 972 struct bt_ctf_field_type *type,
973 struct format_field *field) 973 struct tep_format_field *field)
974{ 974{
975 struct bt_ctf_field_type *t = NULL; 975 struct bt_ctf_field_type *t = NULL;
976 char *name; 976 char *name;
@@ -1009,10 +1009,10 @@ static int event_class_add_field(struct bt_ctf_event_class *event_class,
1009} 1009}
1010 1010
1011static int add_tracepoint_fields_types(struct ctf_writer *cw, 1011static int add_tracepoint_fields_types(struct ctf_writer *cw,
1012 struct format_field *fields, 1012 struct tep_format_field *fields,
1013 struct bt_ctf_event_class *event_class) 1013 struct bt_ctf_event_class *event_class)
1014{ 1014{
1015 struct format_field *field; 1015 struct tep_format_field *field;
1016 int ret; 1016 int ret;
1017 1017
1018 for (field = fields; field; field = field->next) { 1018 for (field = fields; field; field = field->next) {
@@ -1030,15 +1030,15 @@ static int add_tracepoint_fields_types(struct ctf_writer *cw,
1030 * type and don't care that it is an array. What we don't 1030 * type and don't care that it is an array. What we don't
1031 * support is an array of strings. 1031 * support is an array of strings.
1032 */ 1032 */
1033 if (flags & FIELD_IS_STRING) 1033 if (flags & TEP_FIELD_IS_STRING)
1034 flags &= ~FIELD_IS_ARRAY; 1034 flags &= ~TEP_FIELD_IS_ARRAY;
1035 1035
1036 if (flags & FIELD_IS_ARRAY) 1036 if (flags & TEP_FIELD_IS_ARRAY)
1037 type = bt_ctf_field_type_array_create(type, field->arraylen); 1037 type = bt_ctf_field_type_array_create(type, field->arraylen);
1038 1038
1039 ret = event_class_add_field(event_class, type, field); 1039 ret = event_class_add_field(event_class, type, field);
1040 1040
1041 if (flags & FIELD_IS_ARRAY) 1041 if (flags & TEP_FIELD_IS_ARRAY)
1042 bt_ctf_field_type_put(type); 1042 bt_ctf_field_type_put(type);
1043 1043
1044 if (ret) { 1044 if (ret) {
@@ -1055,8 +1055,8 @@ static int add_tracepoint_types(struct ctf_writer *cw,
1055 struct perf_evsel *evsel, 1055 struct perf_evsel *evsel,
1056 struct bt_ctf_event_class *class) 1056 struct bt_ctf_event_class *class)
1057{ 1057{
1058 struct format_field *common_fields = evsel->tp_format->format.common_fields; 1058 struct tep_format_field *common_fields = evsel->tp_format->format.common_fields;
1059 struct format_field *fields = evsel->tp_format->format.fields; 1059 struct tep_format_field *fields = evsel->tp_format->format.fields;
1060 int ret; 1060 int ret;
1061 1061
1062 ret = add_tracepoint_fields_types(cw, common_fields, class); 1062 ret = add_tracepoint_fields_types(cw, common_fields, class);
@@ -1578,7 +1578,7 @@ int bt_convert__perf2ctf(const char *input, const char *path,
1578{ 1578{
1579 struct perf_session *session; 1579 struct perf_session *session;
1580 struct perf_data data = { 1580 struct perf_data data = {
1581 .file.path = input, 1581 .file = { .path = input, .fd = -1 },
1582 .mode = PERF_DATA_MODE_READ, 1582 .mode = PERF_DATA_MODE_READ,
1583 .force = opts->force, 1583 .force = opts->force,
1584 }; 1584 };
diff --git a/tools/perf/util/db-export.c b/tools/perf/util/db-export.c
index 7123746edcf4..69fbb0a72d0c 100644
--- a/tools/perf/util/db-export.c
+++ b/tools/perf/util/db-export.c
@@ -463,6 +463,28 @@ int db_export__branch_types(struct db_export *dbe)
463 if (err) 463 if (err)
464 break; 464 break;
465 } 465 }
466
467 /* Add trace begin / end variants */
468 for (i = 0; branch_types[i].name ; i++) {
469 const char *name = branch_types[i].name;
470 u32 type = branch_types[i].branch_type;
471 char buf[64];
472
473 if (type == PERF_IP_FLAG_BRANCH ||
474 (type & (PERF_IP_FLAG_TRACE_BEGIN | PERF_IP_FLAG_TRACE_END)))
475 continue;
476
477 snprintf(buf, sizeof(buf), "trace begin / %s", name);
478 err = db_export__branch_type(dbe, type | PERF_IP_FLAG_TRACE_BEGIN, buf);
479 if (err)
480 break;
481
482 snprintf(buf, sizeof(buf), "%s / trace end", name);
483 err = db_export__branch_type(dbe, type | PERF_IP_FLAG_TRACE_END, buf);
484 if (err)
485 break;
486 }
487
466 return err; 488 return err;
467} 489}
468 490
diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h
index 1f3ccc368530..d01b8355f4ca 100644
--- a/tools/perf/util/env.h
+++ b/tools/perf/util/env.h
@@ -63,6 +63,7 @@ struct perf_env {
63 struct numa_node *numa_nodes; 63 struct numa_node *numa_nodes;
64 struct memory_node *memory_nodes; 64 struct memory_node *memory_nodes;
65 unsigned long long memory_bsize; 65 unsigned long long memory_bsize;
66 u64 clockid_res_ns;
66}; 67};
67 68
68extern struct perf_env perf_env; 69extern struct perf_env perf_env;
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 0cd42150f712..e9c108a6b1c3 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -308,6 +308,7 @@ static int perf_event__synthesize_fork(struct perf_tool *tool,
308 event->fork.pid = tgid; 308 event->fork.pid = tgid;
309 event->fork.tid = pid; 309 event->fork.tid = pid;
310 event->fork.header.type = PERF_RECORD_FORK; 310 event->fork.header.type = PERF_RECORD_FORK;
311 event->fork.header.misc = PERF_RECORD_MISC_FORK_EXEC;
311 312
312 event->fork.header.size = (sizeof(event->fork) + machine->id_hdr_size); 313 event->fork.header.size = (sizeof(event->fork) + machine->id_hdr_size);
313 314
@@ -1081,6 +1082,7 @@ void *cpu_map_data__alloc(struct cpu_map *map, size_t *size, u16 *type, int *max
1081 } 1082 }
1082 1083
1083 *size += sizeof(struct cpu_map_data); 1084 *size += sizeof(struct cpu_map_data);
1085 *size = PERF_ALIGN(*size, sizeof(u64));
1084 return zalloc(*size); 1086 return zalloc(*size);
1085} 1087}
1086 1088
@@ -1560,26 +1562,9 @@ struct map *thread__find_map(struct thread *thread, u8 cpumode, u64 addr,
1560 1562
1561 return NULL; 1563 return NULL;
1562 } 1564 }
1563try_again: 1565
1564 al->map = map_groups__find(mg, al->addr); 1566 al->map = map_groups__find(mg, al->addr);
1565 if (al->map == NULL) { 1567 if (al->map != NULL) {
1566 /*
1567 * If this is outside of all known maps, and is a negative
1568 * address, try to look it up in the kernel dso, as it might be
1569 * a vsyscall or vdso (which executes in user-mode).
1570 *
1571 * XXX This is nasty, we should have a symbol list in the
1572 * "[vdso]" dso, but for now lets use the old trick of looking
1573 * in the whole kernel symbol list.
1574 */
1575 if (cpumode == PERF_RECORD_MISC_USER && machine &&
1576 mg != &machine->kmaps &&
1577 machine__kernel_ip(machine, al->addr)) {
1578 mg = &machine->kmaps;
1579 load_map = true;
1580 goto try_again;
1581 }
1582 } else {
1583 /* 1568 /*
1584 * Kernel maps might be changed when loading symbols so loading 1569 * Kernel maps might be changed when loading symbols so loading
1585 * must be done prior to using kernel maps. 1570 * must be done prior to using kernel maps.
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index be440df29615..e88e6f9b1463 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -358,7 +358,7 @@ void perf_evlist__disable(struct perf_evlist *evlist)
358 struct perf_evsel *pos; 358 struct perf_evsel *pos;
359 359
360 evlist__for_each_entry(evlist, pos) { 360 evlist__for_each_entry(evlist, pos) {
361 if (!perf_evsel__is_group_leader(pos) || !pos->fd) 361 if (pos->disabled || !perf_evsel__is_group_leader(pos) || !pos->fd)
362 continue; 362 continue;
363 perf_evsel__disable(pos); 363 perf_evsel__disable(pos);
364 } 364 }
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 1a61628a1c12..6d187059a373 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -232,6 +232,7 @@ void perf_evsel__init(struct perf_evsel *evsel,
232 evsel->leader = evsel; 232 evsel->leader = evsel;
233 evsel->unit = ""; 233 evsel->unit = "";
234 evsel->scale = 1.0; 234 evsel->scale = 1.0;
235 evsel->max_events = ULONG_MAX;
235 evsel->evlist = NULL; 236 evsel->evlist = NULL;
236 evsel->bpf_fd = -1; 237 evsel->bpf_fd = -1;
237 INIT_LIST_HEAD(&evsel->node); 238 INIT_LIST_HEAD(&evsel->node);
@@ -793,6 +794,9 @@ static void apply_config_terms(struct perf_evsel *evsel,
793 case PERF_EVSEL__CONFIG_TERM_MAX_STACK: 794 case PERF_EVSEL__CONFIG_TERM_MAX_STACK:
794 max_stack = term->val.max_stack; 795 max_stack = term->val.max_stack;
795 break; 796 break;
797 case PERF_EVSEL__CONFIG_TERM_MAX_EVENTS:
798 evsel->max_events = term->val.max_events;
799 break;
796 case PERF_EVSEL__CONFIG_TERM_INHERIT: 800 case PERF_EVSEL__CONFIG_TERM_INHERIT:
797 /* 801 /*
798 * attr->inherit should has already been set by 802 * attr->inherit should has already been set by
@@ -1089,6 +1093,9 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts,
1089 attr->exclude_user = 1; 1093 attr->exclude_user = 1;
1090 } 1094 }
1091 1095
1096 if (evsel->own_cpus)
1097 evsel->attr.read_format |= PERF_FORMAT_ID;
1098
1092 /* 1099 /*
1093 * Apply event specific term settings, 1100 * Apply event specific term settings,
1094 * it overloads any global configuration. 1101 * it overloads any global configuration.
@@ -1200,16 +1207,27 @@ int perf_evsel__append_addr_filter(struct perf_evsel *evsel, const char *filter)
1200 1207
1201int perf_evsel__enable(struct perf_evsel *evsel) 1208int perf_evsel__enable(struct perf_evsel *evsel)
1202{ 1209{
1203 return perf_evsel__run_ioctl(evsel, 1210 int err = perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_ENABLE, 0);
1204 PERF_EVENT_IOC_ENABLE, 1211
1205 0); 1212 if (!err)
1213 evsel->disabled = false;
1214
1215 return err;
1206} 1216}
1207 1217
1208int perf_evsel__disable(struct perf_evsel *evsel) 1218int perf_evsel__disable(struct perf_evsel *evsel)
1209{ 1219{
1210 return perf_evsel__run_ioctl(evsel, 1220 int err = perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_DISABLE, 0);
1211 PERF_EVENT_IOC_DISABLE, 1221 /*
1212 0); 1222 * We mark it disabled here so that tools that disable a event can
1223 * ignore events after they disable it. I.e. the ring buffer may have
1224 * already a few more events queued up before the kernel got the stop
1225 * request.
1226 */
1227 if (!err)
1228 evsel->disabled = true;
1229
1230 return err;
1213} 1231}
1214 1232
1215int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads) 1233int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
@@ -2682,7 +2700,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,
2682 return 0; 2700 return 0;
2683} 2701}
2684 2702
2685struct format_field *perf_evsel__field(struct perf_evsel *evsel, const char *name) 2703struct tep_format_field *perf_evsel__field(struct perf_evsel *evsel, const char *name)
2686{ 2704{
2687 return tep_find_field(evsel->tp_format, name); 2705 return tep_find_field(evsel->tp_format, name);
2688} 2706}
@@ -2690,7 +2708,7 @@ struct format_field *perf_evsel__field(struct perf_evsel *evsel, const char *nam
2690void *perf_evsel__rawptr(struct perf_evsel *evsel, struct perf_sample *sample, 2708void *perf_evsel__rawptr(struct perf_evsel *evsel, struct perf_sample *sample,
2691 const char *name) 2709 const char *name)
2692{ 2710{
2693 struct format_field *field = perf_evsel__field(evsel, name); 2711 struct tep_format_field *field = perf_evsel__field(evsel, name);
2694 int offset; 2712 int offset;
2695 2713
2696 if (!field) 2714 if (!field)
@@ -2698,7 +2716,7 @@ void *perf_evsel__rawptr(struct perf_evsel *evsel, struct perf_sample *sample,
2698 2716
2699 offset = field->offset; 2717 offset = field->offset;
2700 2718
2701 if (field->flags & FIELD_IS_DYNAMIC) { 2719 if (field->flags & TEP_FIELD_IS_DYNAMIC) {
2702 offset = *(int *)(sample->raw_data + field->offset); 2720 offset = *(int *)(sample->raw_data + field->offset);
2703 offset &= 0xffff; 2721 offset &= 0xffff;
2704 } 2722 }
@@ -2706,7 +2724,7 @@ void *perf_evsel__rawptr(struct perf_evsel *evsel, struct perf_sample *sample,
2706 return sample->raw_data + offset; 2724 return sample->raw_data + offset;
2707} 2725}
2708 2726
2709u64 format_field__intval(struct format_field *field, struct perf_sample *sample, 2727u64 format_field__intval(struct tep_format_field *field, struct perf_sample *sample,
2710 bool needs_swap) 2728 bool needs_swap)
2711{ 2729{
2712 u64 value; 2730 u64 value;
@@ -2748,7 +2766,7 @@ u64 format_field__intval(struct format_field *field, struct perf_sample *sample,
2748u64 perf_evsel__intval(struct perf_evsel *evsel, struct perf_sample *sample, 2766u64 perf_evsel__intval(struct perf_evsel *evsel, struct perf_sample *sample,
2749 const char *name) 2767 const char *name)
2750{ 2768{
2751 struct format_field *field = perf_evsel__field(evsel, name); 2769 struct tep_format_field *field = perf_evsel__field(evsel, name);
2752 2770
2753 if (!field) 2771 if (!field)
2754 return 0; 2772 return 0;
@@ -2940,3 +2958,32 @@ struct perf_env *perf_evsel__env(struct perf_evsel *evsel)
2940 return evsel->evlist->env; 2958 return evsel->evlist->env;
2941 return NULL; 2959 return NULL;
2942} 2960}
2961
2962static int store_evsel_ids(struct perf_evsel *evsel, struct perf_evlist *evlist)
2963{
2964 int cpu, thread;
2965
2966 for (cpu = 0; cpu < xyarray__max_x(evsel->fd); cpu++) {
2967 for (thread = 0; thread < xyarray__max_y(evsel->fd);
2968 thread++) {
2969 int fd = FD(evsel, cpu, thread);
2970
2971 if (perf_evlist__id_add_fd(evlist, evsel,
2972 cpu, thread, fd) < 0)
2973 return -1;
2974 }
2975 }
2976
2977 return 0;
2978}
2979
2980int perf_evsel__store_ids(struct perf_evsel *evsel, struct perf_evlist *evlist)
2981{
2982 struct cpu_map *cpus = evsel->cpus;
2983 struct thread_map *threads = evsel->threads;
2984
2985 if (perf_evsel__alloc_id(evsel, cpus->nr, threads->nr))
2986 return -ENOMEM;
2987
2988 return store_evsel_ids(evsel, evlist);
2989}
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 163c960614d3..3147ca76c6fc 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -46,6 +46,7 @@ enum term_type {
46 PERF_EVSEL__CONFIG_TERM_STACK_USER, 46 PERF_EVSEL__CONFIG_TERM_STACK_USER,
47 PERF_EVSEL__CONFIG_TERM_INHERIT, 47 PERF_EVSEL__CONFIG_TERM_INHERIT,
48 PERF_EVSEL__CONFIG_TERM_MAX_STACK, 48 PERF_EVSEL__CONFIG_TERM_MAX_STACK,
49 PERF_EVSEL__CONFIG_TERM_MAX_EVENTS,
49 PERF_EVSEL__CONFIG_TERM_OVERWRITE, 50 PERF_EVSEL__CONFIG_TERM_OVERWRITE,
50 PERF_EVSEL__CONFIG_TERM_DRV_CFG, 51 PERF_EVSEL__CONFIG_TERM_DRV_CFG,
51 PERF_EVSEL__CONFIG_TERM_BRANCH, 52 PERF_EVSEL__CONFIG_TERM_BRANCH,
@@ -65,6 +66,7 @@ struct perf_evsel_config_term {
65 bool inherit; 66 bool inherit;
66 bool overwrite; 67 bool overwrite;
67 char *branch; 68 char *branch;
69 unsigned long max_events;
68 } val; 70 } val;
69 bool weak; 71 bool weak;
70}; 72};
@@ -99,10 +101,12 @@ struct perf_evsel {
99 struct perf_counts *prev_raw_counts; 101 struct perf_counts *prev_raw_counts;
100 int idx; 102 int idx;
101 u32 ids; 103 u32 ids;
104 unsigned long max_events;
105 unsigned long nr_events_printed;
102 char *name; 106 char *name;
103 double scale; 107 double scale;
104 const char *unit; 108 const char *unit;
105 struct event_format *tp_format; 109 struct tep_event_format *tp_format;
106 off_t id_offset; 110 off_t id_offset;
107 struct perf_stat_evsel *stats; 111 struct perf_stat_evsel *stats;
108 void *priv; 112 void *priv;
@@ -119,6 +123,7 @@ struct perf_evsel {
119 bool snapshot; 123 bool snapshot;
120 bool supported; 124 bool supported;
121 bool needs_swap; 125 bool needs_swap;
126 bool disabled;
122 bool no_aux_samples; 127 bool no_aux_samples;
123 bool immediate; 128 bool immediate;
124 bool system_wide; 129 bool system_wide;
@@ -211,7 +216,7 @@ static inline struct perf_evsel *perf_evsel__newtp(const char *sys, const char *
211 216
212struct perf_evsel *perf_evsel__new_cycles(bool precise); 217struct perf_evsel *perf_evsel__new_cycles(bool precise);
213 218
214struct event_format *event_format__new(const char *sys, const char *name); 219struct tep_event_format *event_format__new(const char *sys, const char *name);
215 220
216void perf_evsel__init(struct perf_evsel *evsel, 221void perf_evsel__init(struct perf_evsel *evsel,
217 struct perf_event_attr *attr, int idx); 222 struct perf_event_attr *attr, int idx);
@@ -296,11 +301,11 @@ static inline char *perf_evsel__strval(struct perf_evsel *evsel,
296 return perf_evsel__rawptr(evsel, sample, name); 301 return perf_evsel__rawptr(evsel, sample, name);
297} 302}
298 303
299struct format_field; 304struct tep_format_field;
300 305
301u64 format_field__intval(struct format_field *field, struct perf_sample *sample, bool needs_swap); 306u64 format_field__intval(struct tep_format_field *field, struct perf_sample *sample, bool needs_swap);
302 307
303struct format_field *perf_evsel__field(struct perf_evsel *evsel, const char *name); 308struct tep_format_field *perf_evsel__field(struct perf_evsel *evsel, const char *name);
304 309
305#define perf_evsel__match(evsel, t, c) \ 310#define perf_evsel__match(evsel, t, c) \
306 (evsel->attr.type == PERF_TYPE_##t && \ 311 (evsel->attr.type == PERF_TYPE_##t && \
@@ -481,4 +486,5 @@ int perf_event_attr__fprintf(FILE *fp, struct perf_event_attr *attr,
481 486
482struct perf_env *perf_evsel__env(struct perf_evsel *evsel); 487struct perf_env *perf_evsel__env(struct perf_evsel *evsel);
483 488
489int perf_evsel__store_ids(struct perf_evsel *evsel, struct perf_evlist *evlist);
484#endif /* __PERF_EVSEL_H */ 490#endif /* __PERF_EVSEL_H */
diff --git a/tools/perf/util/evsel_fprintf.c b/tools/perf/util/evsel_fprintf.c
index 06dfb027879d..0d0a4c6f368b 100644
--- a/tools/perf/util/evsel_fprintf.c
+++ b/tools/perf/util/evsel_fprintf.c
@@ -73,7 +73,7 @@ int perf_evsel__fprintf(struct perf_evsel *evsel,
73 } 73 }
74 74
75 if (details->trace_fields) { 75 if (details->trace_fields) {
76 struct format_field *field; 76 struct tep_format_field *field;
77 77
78 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) { 78 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) {
79 printed += comma_fprintf(fp, &first, " (not a tracepoint)"); 79 printed += comma_fprintf(fp, &first, " (not a tracepoint)");
diff --git a/tools/perf/util/genelf.h b/tools/perf/util/genelf.h
index de322d51c7fe..b72440bf9a79 100644
--- a/tools/perf/util/genelf.h
+++ b/tools/perf/util/genelf.h
@@ -29,6 +29,12 @@ int jit_add_debug_info(Elf *e, uint64_t code_addr, void *debug, int nr_debug_ent
29#elif defined(__powerpc__) 29#elif defined(__powerpc__)
30#define GEN_ELF_ARCH EM_PPC 30#define GEN_ELF_ARCH EM_PPC
31#define GEN_ELF_CLASS ELFCLASS32 31#define GEN_ELF_CLASS ELFCLASS32
32#elif defined(__sparc__) && defined(__arch64__)
33#define GEN_ELF_ARCH EM_SPARCV9
34#define GEN_ELF_CLASS ELFCLASS64
35#elif defined(__sparc__)
36#define GEN_ELF_ARCH EM_SPARC
37#define GEN_ELF_CLASS ELFCLASS32
32#else 38#else
33#error "unsupported architecture" 39#error "unsupported architecture"
34#endif 40#endif
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 3cadc252dd89..4fd45be95a43 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1034,6 +1034,13 @@ static int write_auxtrace(struct feat_fd *ff,
1034 return err; 1034 return err;
1035} 1035}
1036 1036
1037static int write_clockid(struct feat_fd *ff,
1038 struct perf_evlist *evlist __maybe_unused)
1039{
1040 return do_write(ff, &ff->ph->env.clockid_res_ns,
1041 sizeof(ff->ph->env.clockid_res_ns));
1042}
1043
1037static int cpu_cache_level__sort(const void *a, const void *b) 1044static int cpu_cache_level__sort(const void *a, const void *b)
1038{ 1045{
1039 struct cpu_cache_level *cache_a = (struct cpu_cache_level *)a; 1046 struct cpu_cache_level *cache_a = (struct cpu_cache_level *)a;
@@ -1508,6 +1515,12 @@ static void print_cpu_topology(struct feat_fd *ff, FILE *fp)
1508 fprintf(fp, "# Core ID and Socket ID information is not available\n"); 1515 fprintf(fp, "# Core ID and Socket ID information is not available\n");
1509} 1516}
1510 1517
1518static void print_clockid(struct feat_fd *ff, FILE *fp)
1519{
1520 fprintf(fp, "# clockid frequency: %"PRIu64" MHz\n",
1521 ff->ph->env.clockid_res_ns * 1000);
1522}
1523
1511static void free_event_desc(struct perf_evsel *events) 1524static void free_event_desc(struct perf_evsel *events)
1512{ 1525{
1513 struct perf_evsel *evsel; 1526 struct perf_evsel *evsel;
@@ -2531,6 +2544,15 @@ out:
2531 return ret; 2544 return ret;
2532} 2545}
2533 2546
2547static int process_clockid(struct feat_fd *ff,
2548 void *data __maybe_unused)
2549{
2550 if (do_read_u64(ff, &ff->ph->env.clockid_res_ns))
2551 return -1;
2552
2553 return 0;
2554}
2555
2534struct feature_ops { 2556struct feature_ops {
2535 int (*write)(struct feat_fd *ff, struct perf_evlist *evlist); 2557 int (*write)(struct feat_fd *ff, struct perf_evlist *evlist);
2536 void (*print)(struct feat_fd *ff, FILE *fp); 2558 void (*print)(struct feat_fd *ff, FILE *fp);
@@ -2590,6 +2612,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
2590 FEAT_OPN(CACHE, cache, true), 2612 FEAT_OPN(CACHE, cache, true),
2591 FEAT_OPR(SAMPLE_TIME, sample_time, false), 2613 FEAT_OPR(SAMPLE_TIME, sample_time, false),
2592 FEAT_OPR(MEM_TOPOLOGY, mem_topology, true), 2614 FEAT_OPR(MEM_TOPOLOGY, mem_topology, true),
2615 FEAT_OPR(CLOCKID, clockid, false)
2593}; 2616};
2594 2617
2595struct header_print_data { 2618struct header_print_data {
@@ -3206,7 +3229,7 @@ static int read_attr(int fd, struct perf_header *ph,
3206static int perf_evsel__prepare_tracepoint_event(struct perf_evsel *evsel, 3229static int perf_evsel__prepare_tracepoint_event(struct perf_evsel *evsel,
3207 struct tep_handle *pevent) 3230 struct tep_handle *pevent)
3208{ 3231{
3209 struct event_format *event; 3232 struct tep_event_format *event;
3210 char bf[128]; 3233 char bf[128];
3211 3234
3212 /* already prepared */ 3235 /* already prepared */
@@ -3448,10 +3471,10 @@ int perf_event__synthesize_features(struct perf_tool *tool,
3448 return ret; 3471 return ret;
3449} 3472}
3450 3473
3451int perf_event__process_feature(struct perf_tool *tool, 3474int perf_event__process_feature(struct perf_session *session,
3452 union perf_event *event, 3475 union perf_event *event)
3453 struct perf_session *session __maybe_unused)
3454{ 3476{
3477 struct perf_tool *tool = session->tool;
3455 struct feat_fd ff = { .fd = 0 }; 3478 struct feat_fd ff = { .fd = 0 };
3456 struct feature_event *fe = (struct feature_event *)event; 3479 struct feature_event *fe = (struct feature_event *)event;
3457 int type = fe->header.type; 3480 int type = fe->header.type;
@@ -3637,13 +3660,13 @@ size_t perf_event__fprintf_event_update(union perf_event *event, FILE *fp)
3637} 3660}
3638 3661
3639int perf_event__synthesize_attrs(struct perf_tool *tool, 3662int perf_event__synthesize_attrs(struct perf_tool *tool,
3640 struct perf_session *session, 3663 struct perf_evlist *evlist,
3641 perf_event__handler_t process) 3664 perf_event__handler_t process)
3642{ 3665{
3643 struct perf_evsel *evsel; 3666 struct perf_evsel *evsel;
3644 int err = 0; 3667 int err = 0;
3645 3668
3646 evlist__for_each_entry(session->evlist, evsel) { 3669 evlist__for_each_entry(evlist, evsel) {
3647 err = perf_event__synthesize_attr(tool, &evsel->attr, evsel->ids, 3670 err = perf_event__synthesize_attr(tool, &evsel->attr, evsel->ids,
3648 evsel->id, process); 3671 evsel->id, process);
3649 if (err) { 3672 if (err) {
@@ -3856,9 +3879,8 @@ int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd,
3856 return aligned_size; 3879 return aligned_size;
3857} 3880}
3858 3881
3859int perf_event__process_tracing_data(struct perf_tool *tool __maybe_unused, 3882int perf_event__process_tracing_data(struct perf_session *session,
3860 union perf_event *event, 3883 union perf_event *event)
3861 struct perf_session *session)
3862{ 3884{
3863 ssize_t size_read, padding, size = event->tracing_data.size; 3885 ssize_t size_read, padding, size = event->tracing_data.size;
3864 int fd = perf_data__fd(session->data); 3886 int fd = perf_data__fd(session->data);
@@ -3924,9 +3946,8 @@ int perf_event__synthesize_build_id(struct perf_tool *tool,
3924 return err; 3946 return err;
3925} 3947}
3926 3948
3927int perf_event__process_build_id(struct perf_tool *tool __maybe_unused, 3949int perf_event__process_build_id(struct perf_session *session,
3928 union perf_event *event, 3950 union perf_event *event)
3929 struct perf_session *session)
3930{ 3951{
3931 __event_process_build_id(&event->build_id, 3952 __event_process_build_id(&event->build_id,
3932 event->build_id.filename, 3953 event->build_id.filename,
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 6d7fe44aadc0..0d553ddca0a3 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -38,6 +38,7 @@ enum {
38 HEADER_CACHE, 38 HEADER_CACHE,
39 HEADER_SAMPLE_TIME, 39 HEADER_SAMPLE_TIME,
40 HEADER_MEM_TOPOLOGY, 40 HEADER_MEM_TOPOLOGY,
41 HEADER_CLOCKID,
41 HEADER_LAST_FEATURE, 42 HEADER_LAST_FEATURE,
42 HEADER_FEAT_BITS = 256, 43 HEADER_FEAT_BITS = 256,
43}; 44};
@@ -116,15 +117,14 @@ int perf_event__synthesize_extra_attr(struct perf_tool *tool,
116 perf_event__handler_t process, 117 perf_event__handler_t process,
117 bool is_pipe); 118 bool is_pipe);
118 119
119int perf_event__process_feature(struct perf_tool *tool, 120int perf_event__process_feature(struct perf_session *session,
120 union perf_event *event, 121 union perf_event *event);
121 struct perf_session *session);
122 122
123int perf_event__synthesize_attr(struct perf_tool *tool, 123int perf_event__synthesize_attr(struct perf_tool *tool,
124 struct perf_event_attr *attr, u32 ids, u64 *id, 124 struct perf_event_attr *attr, u32 ids, u64 *id,
125 perf_event__handler_t process); 125 perf_event__handler_t process);
126int perf_event__synthesize_attrs(struct perf_tool *tool, 126int perf_event__synthesize_attrs(struct perf_tool *tool,
127 struct perf_session *session, 127 struct perf_evlist *evlist,
128 perf_event__handler_t process); 128 perf_event__handler_t process);
129int perf_event__synthesize_event_update_unit(struct perf_tool *tool, 129int perf_event__synthesize_event_update_unit(struct perf_tool *tool,
130 struct perf_evsel *evsel, 130 struct perf_evsel *evsel,
@@ -148,17 +148,15 @@ size_t perf_event__fprintf_event_update(union perf_event *event, FILE *fp);
148int perf_event__synthesize_tracing_data(struct perf_tool *tool, 148int perf_event__synthesize_tracing_data(struct perf_tool *tool,
149 int fd, struct perf_evlist *evlist, 149 int fd, struct perf_evlist *evlist,
150 perf_event__handler_t process); 150 perf_event__handler_t process);
151int perf_event__process_tracing_data(struct perf_tool *tool, 151int perf_event__process_tracing_data(struct perf_session *session,
152 union perf_event *event, 152 union perf_event *event);
153 struct perf_session *session);
154 153
155int perf_event__synthesize_build_id(struct perf_tool *tool, 154int perf_event__synthesize_build_id(struct perf_tool *tool,
156 struct dso *pos, u16 misc, 155 struct dso *pos, u16 misc,
157 perf_event__handler_t process, 156 perf_event__handler_t process,
158 struct machine *machine); 157 struct machine *machine);
159int perf_event__process_build_id(struct perf_tool *tool, 158int perf_event__process_build_id(struct perf_session *session,
160 union perf_event *event, 159 union perf_event *event);
161 struct perf_session *session);
162bool is_perf_magic(u64 magic); 160bool is_perf_magic(u64 magic);
163 161
164#define NAME_ALIGN 64 162#define NAME_ALIGN 64
diff --git a/tools/perf/util/intel-bts.c b/tools/perf/util/intel-bts.c
index 7f0c83b6332b..7b27d77306c2 100644
--- a/tools/perf/util/intel-bts.c
+++ b/tools/perf/util/intel-bts.c
@@ -269,6 +269,13 @@ static int intel_bts_do_fix_overlap(struct auxtrace_queue *queue,
269 return 0; 269 return 0;
270} 270}
271 271
272static inline u8 intel_bts_cpumode(struct intel_bts *bts, uint64_t ip)
273{
274 return machine__kernel_ip(bts->machine, ip) ?
275 PERF_RECORD_MISC_KERNEL :
276 PERF_RECORD_MISC_USER;
277}
278
272static int intel_bts_synth_branch_sample(struct intel_bts_queue *btsq, 279static int intel_bts_synth_branch_sample(struct intel_bts_queue *btsq,
273 struct branch *branch) 280 struct branch *branch)
274{ 281{
@@ -281,12 +288,8 @@ static int intel_bts_synth_branch_sample(struct intel_bts_queue *btsq,
281 bts->num_events++ <= bts->synth_opts.initial_skip) 288 bts->num_events++ <= bts->synth_opts.initial_skip)
282 return 0; 289 return 0;
283 290
284 event.sample.header.type = PERF_RECORD_SAMPLE;
285 event.sample.header.misc = PERF_RECORD_MISC_USER;
286 event.sample.header.size = sizeof(struct perf_event_header);
287
288 sample.cpumode = PERF_RECORD_MISC_USER;
289 sample.ip = le64_to_cpu(branch->from); 291 sample.ip = le64_to_cpu(branch->from);
292 sample.cpumode = intel_bts_cpumode(bts, sample.ip);
290 sample.pid = btsq->pid; 293 sample.pid = btsq->pid;
291 sample.tid = btsq->tid; 294 sample.tid = btsq->tid;
292 sample.addr = le64_to_cpu(branch->to); 295 sample.addr = le64_to_cpu(branch->to);
@@ -298,6 +301,10 @@ static int intel_bts_synth_branch_sample(struct intel_bts_queue *btsq,
298 sample.insn_len = btsq->intel_pt_insn.length; 301 sample.insn_len = btsq->intel_pt_insn.length;
299 memcpy(sample.insn, btsq->intel_pt_insn.buf, INTEL_PT_INSN_BUF_SZ); 302 memcpy(sample.insn, btsq->intel_pt_insn.buf, INTEL_PT_INSN_BUF_SZ);
300 303
304 event.sample.header.type = PERF_RECORD_SAMPLE;
305 event.sample.header.misc = sample.cpumode;
306 event.sample.header.size = sizeof(struct perf_event_header);
307
301 if (bts->synth_opts.inject) { 308 if (bts->synth_opts.inject) {
302 event.sample.header.size = bts->branches_event_size; 309 event.sample.header.size = bts->branches_event_size;
303 ret = perf_event__synthesize_sample(&event, 310 ret = perf_event__synthesize_sample(&event,
@@ -910,7 +917,8 @@ int intel_bts_process_auxtrace_info(union perf_event *event,
910 if (session->itrace_synth_opts && session->itrace_synth_opts->set) { 917 if (session->itrace_synth_opts && session->itrace_synth_opts->set) {
911 bts->synth_opts = *session->itrace_synth_opts; 918 bts->synth_opts = *session->itrace_synth_opts;
912 } else { 919 } else {
913 itrace_synth_opts__set_default(&bts->synth_opts); 920 itrace_synth_opts__set_default(&bts->synth_opts,
921 session->itrace_synth_opts->default_no_sample);
914 if (session->itrace_synth_opts) 922 if (session->itrace_synth_opts)
915 bts->synth_opts.thread_stack = 923 bts->synth_opts.thread_stack =
916 session->itrace_synth_opts->thread_stack; 924 session->itrace_synth_opts->thread_stack;
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
index d404bed7003a..58f6a9ceb590 100644
--- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
+++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
@@ -1165,7 +1165,7 @@ static int intel_pt_walk_tip(struct intel_pt_decoder *decoder)
1165 decoder->pge = false; 1165 decoder->pge = false;
1166 decoder->continuous_period = false; 1166 decoder->continuous_period = false;
1167 decoder->pkt_state = INTEL_PT_STATE_IN_SYNC; 1167 decoder->pkt_state = INTEL_PT_STATE_IN_SYNC;
1168 decoder->state.to_ip = 0; 1168 decoder->state.type |= INTEL_PT_TRACE_END;
1169 return 0; 1169 return 0;
1170 } 1170 }
1171 if (err == INTEL_PT_RETURN) 1171 if (err == INTEL_PT_RETURN)
@@ -1179,9 +1179,13 @@ static int intel_pt_walk_tip(struct intel_pt_decoder *decoder)
1179 decoder->continuous_period = false; 1179 decoder->continuous_period = false;
1180 decoder->pkt_state = INTEL_PT_STATE_IN_SYNC; 1180 decoder->pkt_state = INTEL_PT_STATE_IN_SYNC;
1181 decoder->state.from_ip = decoder->ip; 1181 decoder->state.from_ip = decoder->ip;
1182 decoder->state.to_ip = 0; 1182 if (decoder->packet.count == 0) {
1183 if (decoder->packet.count != 0) 1183 decoder->state.to_ip = 0;
1184 } else {
1185 decoder->state.to_ip = decoder->last_ip;
1184 decoder->ip = decoder->last_ip; 1186 decoder->ip = decoder->last_ip;
1187 }
1188 decoder->state.type |= INTEL_PT_TRACE_END;
1185 } else { 1189 } else {
1186 decoder->pkt_state = INTEL_PT_STATE_IN_SYNC; 1190 decoder->pkt_state = INTEL_PT_STATE_IN_SYNC;
1187 decoder->state.from_ip = decoder->ip; 1191 decoder->state.from_ip = decoder->ip;
@@ -1208,7 +1212,8 @@ static int intel_pt_walk_tip(struct intel_pt_decoder *decoder)
1208 decoder->pkt_state = INTEL_PT_STATE_IN_SYNC; 1212 decoder->pkt_state = INTEL_PT_STATE_IN_SYNC;
1209 decoder->ip = to_ip; 1213 decoder->ip = to_ip;
1210 decoder->state.from_ip = decoder->ip; 1214 decoder->state.from_ip = decoder->ip;
1211 decoder->state.to_ip = 0; 1215 decoder->state.to_ip = to_ip;
1216 decoder->state.type |= INTEL_PT_TRACE_END;
1212 return 0; 1217 return 0;
1213 } 1218 }
1214 intel_pt_log_at("ERROR: Conditional branch when expecting indirect branch", 1219 intel_pt_log_at("ERROR: Conditional branch when expecting indirect branch",
@@ -1640,14 +1645,15 @@ static int intel_pt_walk_fup_tip(struct intel_pt_decoder *decoder)
1640 1645
1641 case INTEL_PT_TIP_PGD: 1646 case INTEL_PT_TIP_PGD:
1642 decoder->state.from_ip = decoder->ip; 1647 decoder->state.from_ip = decoder->ip;
1643 decoder->state.to_ip = 0; 1648 if (decoder->packet.count == 0) {
1644 if (decoder->packet.count != 0) { 1649 decoder->state.to_ip = 0;
1650 } else {
1645 intel_pt_set_ip(decoder); 1651 intel_pt_set_ip(decoder);
1646 intel_pt_log("Omitting PGD ip " x64_fmt "\n", 1652 decoder->state.to_ip = decoder->ip;
1647 decoder->ip);
1648 } 1653 }
1649 decoder->pge = false; 1654 decoder->pge = false;
1650 decoder->continuous_period = false; 1655 decoder->continuous_period = false;
1656 decoder->state.type |= INTEL_PT_TRACE_END;
1651 return 0; 1657 return 0;
1652 1658
1653 case INTEL_PT_TIP_PGE: 1659 case INTEL_PT_TIP_PGE:
@@ -1661,6 +1667,7 @@ static int intel_pt_walk_fup_tip(struct intel_pt_decoder *decoder)
1661 intel_pt_set_ip(decoder); 1667 intel_pt_set_ip(decoder);
1662 decoder->state.to_ip = decoder->ip; 1668 decoder->state.to_ip = decoder->ip;
1663 } 1669 }
1670 decoder->state.type |= INTEL_PT_TRACE_BEGIN;
1664 return 0; 1671 return 0;
1665 1672
1666 case INTEL_PT_TIP: 1673 case INTEL_PT_TIP:
@@ -1739,6 +1746,7 @@ next:
1739 intel_pt_set_ip(decoder); 1746 intel_pt_set_ip(decoder);
1740 decoder->state.from_ip = 0; 1747 decoder->state.from_ip = 0;
1741 decoder->state.to_ip = decoder->ip; 1748 decoder->state.to_ip = decoder->ip;
1749 decoder->state.type |= INTEL_PT_TRACE_BEGIN;
1742 return 0; 1750 return 0;
1743 } 1751 }
1744 1752
@@ -2077,9 +2085,13 @@ static int intel_pt_walk_to_ip(struct intel_pt_decoder *decoder)
2077 decoder->pge = decoder->packet.type != INTEL_PT_TIP_PGD; 2085 decoder->pge = decoder->packet.type != INTEL_PT_TIP_PGD;
2078 if (intel_pt_have_ip(decoder)) 2086 if (intel_pt_have_ip(decoder))
2079 intel_pt_set_ip(decoder); 2087 intel_pt_set_ip(decoder);
2080 if (decoder->ip) 2088 if (!decoder->ip)
2081 return 0; 2089 break;
2082 break; 2090 if (decoder->packet.type == INTEL_PT_TIP_PGE)
2091 decoder->state.type |= INTEL_PT_TRACE_BEGIN;
2092 if (decoder->packet.type == INTEL_PT_TIP_PGD)
2093 decoder->state.type |= INTEL_PT_TRACE_END;
2094 return 0;
2083 2095
2084 case INTEL_PT_FUP: 2096 case INTEL_PT_FUP:
2085 if (intel_pt_have_ip(decoder)) 2097 if (intel_pt_have_ip(decoder))
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h
index 51c18d67f4ca..ed088d4726ba 100644
--- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h
+++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h
@@ -37,6 +37,8 @@ enum intel_pt_sample_type {
37 INTEL_PT_EX_STOP = 1 << 6, 37 INTEL_PT_EX_STOP = 1 << 6,
38 INTEL_PT_PWR_EXIT = 1 << 7, 38 INTEL_PT_PWR_EXIT = 1 << 7,
39 INTEL_PT_CBR_CHG = 1 << 8, 39 INTEL_PT_CBR_CHG = 1 << 8,
40 INTEL_PT_TRACE_BEGIN = 1 << 9,
41 INTEL_PT_TRACE_END = 1 << 10,
40}; 42};
41 43
42enum intel_pt_period_type { 44enum intel_pt_period_type {
diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c
index aec68908d604..86cc9a64e982 100644
--- a/tools/perf/util/intel-pt.c
+++ b/tools/perf/util/intel-pt.c
@@ -407,6 +407,13 @@ intel_pt_cache_lookup(struct dso *dso, struct machine *machine, u64 offset)
407 return auxtrace_cache__lookup(dso->auxtrace_cache, offset); 407 return auxtrace_cache__lookup(dso->auxtrace_cache, offset);
408} 408}
409 409
410static inline u8 intel_pt_cpumode(struct intel_pt *pt, uint64_t ip)
411{
412 return ip >= pt->kernel_start ?
413 PERF_RECORD_MISC_KERNEL :
414 PERF_RECORD_MISC_USER;
415}
416
410static int intel_pt_walk_next_insn(struct intel_pt_insn *intel_pt_insn, 417static int intel_pt_walk_next_insn(struct intel_pt_insn *intel_pt_insn,
411 uint64_t *insn_cnt_ptr, uint64_t *ip, 418 uint64_t *insn_cnt_ptr, uint64_t *ip,
412 uint64_t to_ip, uint64_t max_insn_cnt, 419 uint64_t to_ip, uint64_t max_insn_cnt,
@@ -429,10 +436,7 @@ static int intel_pt_walk_next_insn(struct intel_pt_insn *intel_pt_insn,
429 if (to_ip && *ip == to_ip) 436 if (to_ip && *ip == to_ip)
430 goto out_no_cache; 437 goto out_no_cache;
431 438
432 if (*ip >= ptq->pt->kernel_start) 439 cpumode = intel_pt_cpumode(ptq->pt, *ip);
433 cpumode = PERF_RECORD_MISC_KERNEL;
434 else
435 cpumode = PERF_RECORD_MISC_USER;
436 440
437 thread = ptq->thread; 441 thread = ptq->thread;
438 if (!thread) { 442 if (!thread) {
@@ -759,7 +763,8 @@ static struct intel_pt_queue *intel_pt_alloc_queue(struct intel_pt *pt,
759 if (pt->synth_opts.callchain) { 763 if (pt->synth_opts.callchain) {
760 size_t sz = sizeof(struct ip_callchain); 764 size_t sz = sizeof(struct ip_callchain);
761 765
762 sz += pt->synth_opts.callchain_sz * sizeof(u64); 766 /* Add 1 to callchain_sz for callchain context */
767 sz += (pt->synth_opts.callchain_sz + 1) * sizeof(u64);
763 ptq->chain = zalloc(sz); 768 ptq->chain = zalloc(sz);
764 if (!ptq->chain) 769 if (!ptq->chain)
765 goto out_free; 770 goto out_free;
@@ -908,6 +913,11 @@ static void intel_pt_sample_flags(struct intel_pt_queue *ptq)
908 ptq->insn_len = ptq->state->insn_len; 913 ptq->insn_len = ptq->state->insn_len;
909 memcpy(ptq->insn, ptq->state->insn, INTEL_PT_INSN_BUF_SZ); 914 memcpy(ptq->insn, ptq->state->insn, INTEL_PT_INSN_BUF_SZ);
910 } 915 }
916
917 if (ptq->state->type & INTEL_PT_TRACE_BEGIN)
918 ptq->flags |= PERF_IP_FLAG_TRACE_BEGIN;
919 if (ptq->state->type & INTEL_PT_TRACE_END)
920 ptq->flags |= PERF_IP_FLAG_TRACE_END;
911} 921}
912 922
913static int intel_pt_setup_queue(struct intel_pt *pt, 923static int intel_pt_setup_queue(struct intel_pt *pt,
@@ -1053,15 +1063,11 @@ static void intel_pt_prep_b_sample(struct intel_pt *pt,
1053 union perf_event *event, 1063 union perf_event *event,
1054 struct perf_sample *sample) 1064 struct perf_sample *sample)
1055{ 1065{
1056 event->sample.header.type = PERF_RECORD_SAMPLE;
1057 event->sample.header.misc = PERF_RECORD_MISC_USER;
1058 event->sample.header.size = sizeof(struct perf_event_header);
1059
1060 if (!pt->timeless_decoding) 1066 if (!pt->timeless_decoding)
1061 sample->time = tsc_to_perf_time(ptq->timestamp, &pt->tc); 1067 sample->time = tsc_to_perf_time(ptq->timestamp, &pt->tc);
1062 1068
1063 sample->cpumode = PERF_RECORD_MISC_USER;
1064 sample->ip = ptq->state->from_ip; 1069 sample->ip = ptq->state->from_ip;
1070 sample->cpumode = intel_pt_cpumode(pt, sample->ip);
1065 sample->pid = ptq->pid; 1071 sample->pid = ptq->pid;
1066 sample->tid = ptq->tid; 1072 sample->tid = ptq->tid;
1067 sample->addr = ptq->state->to_ip; 1073 sample->addr = ptq->state->to_ip;
@@ -1070,6 +1076,10 @@ static void intel_pt_prep_b_sample(struct intel_pt *pt,
1070 sample->flags = ptq->flags; 1076 sample->flags = ptq->flags;
1071 sample->insn_len = ptq->insn_len; 1077 sample->insn_len = ptq->insn_len;
1072 memcpy(sample->insn, ptq->insn, INTEL_PT_INSN_BUF_SZ); 1078 memcpy(sample->insn, ptq->insn, INTEL_PT_INSN_BUF_SZ);
1079
1080 event->sample.header.type = PERF_RECORD_SAMPLE;
1081 event->sample.header.misc = sample->cpumode;
1082 event->sample.header.size = sizeof(struct perf_event_header);
1073} 1083}
1074 1084
1075static int intel_pt_inject_event(union perf_event *event, 1085static int intel_pt_inject_event(union perf_event *event,
@@ -1155,7 +1165,8 @@ static void intel_pt_prep_sample(struct intel_pt *pt,
1155 1165
1156 if (pt->synth_opts.callchain) { 1166 if (pt->synth_opts.callchain) {
1157 thread_stack__sample(ptq->thread, ptq->chain, 1167 thread_stack__sample(ptq->thread, ptq->chain,
1158 pt->synth_opts.callchain_sz, sample->ip); 1168 pt->synth_opts.callchain_sz + 1,
1169 sample->ip, pt->kernel_start);
1159 sample->callchain = ptq->chain; 1170 sample->callchain = ptq->chain;
1160 } 1171 }
1161 1172
@@ -2554,7 +2565,8 @@ int intel_pt_process_auxtrace_info(union perf_event *event,
2554 if (session->itrace_synth_opts && session->itrace_synth_opts->set) { 2565 if (session->itrace_synth_opts && session->itrace_synth_opts->set) {
2555 pt->synth_opts = *session->itrace_synth_opts; 2566 pt->synth_opts = *session->itrace_synth_opts;
2556 } else { 2567 } else {
2557 itrace_synth_opts__set_default(&pt->synth_opts); 2568 itrace_synth_opts__set_default(&pt->synth_opts,
2569 session->itrace_synth_opts->default_no_sample);
2558 if (use_browser != -1) { 2570 if (use_browser != -1) {
2559 pt->synth_opts.branches = false; 2571 pt->synth_opts.branches = false;
2560 pt->synth_opts.callchain = true; 2572 pt->synth_opts.callchain = true;
diff --git a/tools/perf/util/llvm-utils.c b/tools/perf/util/llvm-utils.c
index 19262f98cd4e..5b0b60f00275 100644
--- a/tools/perf/util/llvm-utils.c
+++ b/tools/perf/util/llvm-utils.c
@@ -19,7 +19,7 @@
19#define CLANG_BPF_CMD_DEFAULT_TEMPLATE \ 19#define CLANG_BPF_CMD_DEFAULT_TEMPLATE \
20 "$CLANG_EXEC -D__KERNEL__ -D__NR_CPUS__=$NR_CPUS "\ 20 "$CLANG_EXEC -D__KERNEL__ -D__NR_CPUS__=$NR_CPUS "\
21 "-DLINUX_VERSION_CODE=$LINUX_VERSION_CODE " \ 21 "-DLINUX_VERSION_CODE=$LINUX_VERSION_CODE " \
22 "$CLANG_OPTIONS $KERNEL_INC_OPTIONS $PERF_BPF_INC_OPTIONS " \ 22 "$CLANG_OPTIONS $PERF_BPF_INC_OPTIONS $KERNEL_INC_OPTIONS " \
23 "-Wno-unused-value -Wno-pointer-sign " \ 23 "-Wno-unused-value -Wno-pointer-sign " \
24 "-working-directory $WORKING_DIR " \ 24 "-working-directory $WORKING_DIR " \
25 "-c \"$CLANG_SOURCE\" -target bpf $CLANG_EMIT_LLVM -O2 -o - $LLVM_OPTIONS_PIPE" 25 "-c \"$CLANG_SOURCE\" -target bpf $CLANG_EMIT_LLVM -O2 -o - $LLVM_OPTIONS_PIPE"
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index c4acd2001db0..8f36ce813bc5 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -1708,6 +1708,7 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event
1708 struct thread *parent = machine__findnew_thread(machine, 1708 struct thread *parent = machine__findnew_thread(machine,
1709 event->fork.ppid, 1709 event->fork.ppid,
1710 event->fork.ptid); 1710 event->fork.ptid);
1711 bool do_maps_clone = true;
1711 int err = 0; 1712 int err = 0;
1712 1713
1713 if (dump_trace) 1714 if (dump_trace)
@@ -1736,9 +1737,25 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event
1736 1737
1737 thread = machine__findnew_thread(machine, event->fork.pid, 1738 thread = machine__findnew_thread(machine, event->fork.pid,
1738 event->fork.tid); 1739 event->fork.tid);
1740 /*
1741 * When synthesizing FORK events, we are trying to create thread
1742 * objects for the already running tasks on the machine.
1743 *
1744 * Normally, for a kernel FORK event, we want to clone the parent's
1745 * maps because that is what the kernel just did.
1746 *
1747 * But when synthesizing, this should not be done. If we do, we end up
1748 * with overlapping maps as we process the sythesized MMAP2 events that
1749 * get delivered shortly thereafter.
1750 *
1751 * Use the FORK event misc flags in an internal way to signal this
1752 * situation, so we can elide the map clone when appropriate.
1753 */
1754 if (event->fork.header.misc & PERF_RECORD_MISC_FORK_EXEC)
1755 do_maps_clone = false;
1739 1756
1740 if (thread == NULL || parent == NULL || 1757 if (thread == NULL || parent == NULL ||
1741 thread__fork(thread, parent, sample->time) < 0) { 1758 thread__fork(thread, parent, sample->time, do_maps_clone) < 0) {
1742 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n"); 1759 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
1743 err = -1; 1760 err = -1;
1744 } 1761 }
@@ -2140,6 +2157,27 @@ static int resolve_lbr_callchain_sample(struct thread *thread,
2140 return 0; 2157 return 0;
2141} 2158}
2142 2159
2160static int find_prev_cpumode(struct ip_callchain *chain, struct thread *thread,
2161 struct callchain_cursor *cursor,
2162 struct symbol **parent,
2163 struct addr_location *root_al,
2164 u8 *cpumode, int ent)
2165{
2166 int err = 0;
2167
2168 while (--ent >= 0) {
2169 u64 ip = chain->ips[ent];
2170
2171 if (ip >= PERF_CONTEXT_MAX) {
2172 err = add_callchain_ip(thread, cursor, parent,
2173 root_al, cpumode, ip,
2174 false, NULL, NULL, 0);
2175 break;
2176 }
2177 }
2178 return err;
2179}
2180
2143static int thread__resolve_callchain_sample(struct thread *thread, 2181static int thread__resolve_callchain_sample(struct thread *thread,
2144 struct callchain_cursor *cursor, 2182 struct callchain_cursor *cursor,
2145 struct perf_evsel *evsel, 2183 struct perf_evsel *evsel,
@@ -2246,6 +2284,12 @@ static int thread__resolve_callchain_sample(struct thread *thread,
2246 } 2284 }
2247 2285
2248check_calls: 2286check_calls:
2287 if (callchain_param.order != ORDER_CALLEE) {
2288 err = find_prev_cpumode(chain, thread, cursor, parent, root_al,
2289 &cpumode, chain->nr - first_call);
2290 if (err)
2291 return (err < 0) ? err : 0;
2292 }
2249 for (i = first_call, nr_entries = 0; 2293 for (i = first_call, nr_entries = 0;
2250 i < chain_nr && nr_entries < max_stack; i++) { 2294 i < chain_nr && nr_entries < max_stack; i++) {
2251 u64 ip; 2295 u64 ip;
@@ -2260,9 +2304,15 @@ check_calls:
2260 continue; 2304 continue;
2261#endif 2305#endif
2262 ip = chain->ips[j]; 2306 ip = chain->ips[j];
2263
2264 if (ip < PERF_CONTEXT_MAX) 2307 if (ip < PERF_CONTEXT_MAX)
2265 ++nr_entries; 2308 ++nr_entries;
2309 else if (callchain_param.order != ORDER_CALLEE) {
2310 err = find_prev_cpumode(chain, thread, cursor, parent,
2311 root_al, &cpumode, j);
2312 if (err)
2313 return (err < 0) ? err : 0;
2314 continue;
2315 }
2266 2316
2267 err = add_callchain_ip(thread, cursor, parent, 2317 err = add_callchain_ip(thread, cursor, parent,
2268 root_al, &cpumode, ip, 2318 root_al, &cpumode, ip,
@@ -2286,7 +2336,8 @@ static int append_inlines(struct callchain_cursor *cursor,
2286 if (!symbol_conf.inline_name || !map || !sym) 2336 if (!symbol_conf.inline_name || !map || !sym)
2287 return ret; 2337 return ret;
2288 2338
2289 addr = map__rip_2objdump(map, ip); 2339 addr = map__map_ip(map, ip);
2340 addr = map__rip_2objdump(map, addr);
2290 2341
2291 inline_node = inlines__tree_find(&map->dso->inlined_nodes, addr); 2342 inline_node = inlines__tree_find(&map->dso->inlined_nodes, addr);
2292 if (!inline_node) { 2343 if (!inline_node) {
@@ -2312,7 +2363,7 @@ static int unwind_entry(struct unwind_entry *entry, void *arg)
2312{ 2363{
2313 struct callchain_cursor *cursor = arg; 2364 struct callchain_cursor *cursor = arg;
2314 const char *srcline = NULL; 2365 const char *srcline = NULL;
2315 u64 addr; 2366 u64 addr = entry->ip;
2316 2367
2317 if (symbol_conf.hide_unresolved && entry->sym == NULL) 2368 if (symbol_conf.hide_unresolved && entry->sym == NULL)
2318 return 0; 2369 return 0;
@@ -2324,7 +2375,8 @@ static int unwind_entry(struct unwind_entry *entry, void *arg)
2324 * Convert entry->ip from a virtual address to an offset in 2375 * Convert entry->ip from a virtual address to an offset in
2325 * its corresponding binary. 2376 * its corresponding binary.
2326 */ 2377 */
2327 addr = map__map_ip(entry->map, entry->ip); 2378 if (entry->map)
2379 addr = map__map_ip(entry->map, entry->ip);
2328 2380
2329 srcline = callchain_srcline(entry->map, entry->sym, addr); 2381 srcline = callchain_srcline(entry->map, entry->sym, addr);
2330 return callchain_cursor_append(cursor, entry->ip, 2382 return callchain_cursor_append(cursor, entry->ip,
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 6a6929f208b4..354e54550d2b 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -320,12 +320,11 @@ int map__load(struct map *map)
320 build_id__sprintf(map->dso->build_id, 320 build_id__sprintf(map->dso->build_id,
321 sizeof(map->dso->build_id), 321 sizeof(map->dso->build_id),
322 sbuild_id); 322 sbuild_id);
323 pr_warning("%s with build id %s not found", 323 pr_debug("%s with build id %s not found", name, sbuild_id);
324 name, sbuild_id);
325 } else 324 } else
326 pr_warning("Failed to open %s", name); 325 pr_debug("Failed to open %s", name);
327 326
328 pr_warning(", continuing without symbols\n"); 327 pr_debug(", continuing without symbols\n");
329 return -1; 328 return -1;
330 } else if (nr == 0) { 329 } else if (nr == 0) {
331#ifdef HAVE_LIBELF_SUPPORT 330#ifdef HAVE_LIBELF_SUPPORT
@@ -334,12 +333,11 @@ int map__load(struct map *map)
334 333
335 if (len > sizeof(DSO__DELETED) && 334 if (len > sizeof(DSO__DELETED) &&
336 strcmp(name + real_len + 1, DSO__DELETED) == 0) { 335 strcmp(name + real_len + 1, DSO__DELETED) == 0) {
337 pr_warning("%.*s was updated (is prelink enabled?). " 336 pr_debug("%.*s was updated (is prelink enabled?). "
338 "Restart the long running apps that use it!\n", 337 "Restart the long running apps that use it!\n",
339 (int)real_len, name); 338 (int)real_len, name);
340 } else { 339 } else {
341 pr_warning("no symbols found in %s, maybe install " 340 pr_debug("no symbols found in %s, maybe install a debug package?\n", name);
342 "a debug package?\n", name);
343 } 341 }
344#endif 342#endif
345 return -1; 343 return -1;
@@ -712,8 +710,7 @@ static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp
712 if (verbose >= 2) { 710 if (verbose >= 2) {
713 711
714 if (use_browser) { 712 if (use_browser) {
715 pr_warning("overlapping maps in %s " 713 pr_debug("overlapping maps in %s (disable tui for more info)\n",
716 "(disable tui for more info)\n",
717 map->dso->name); 714 map->dso->name);
718 } else { 715 } else {
719 fputs("overlapping maps:\n", fp); 716 fputs("overlapping maps:\n", fp);
diff --git a/tools/perf/util/mmap.c b/tools/perf/util/mmap.c
index 215f69f41672..cdb95b3a1213 100644
--- a/tools/perf/util/mmap.c
+++ b/tools/perf/util/mmap.c
@@ -281,7 +281,7 @@ int perf_mmap__read_init(struct perf_mmap *map)
281} 281}
282 282
283int perf_mmap__push(struct perf_mmap *md, void *to, 283int perf_mmap__push(struct perf_mmap *md, void *to,
284 int push(void *to, void *buf, size_t size)) 284 int push(struct perf_mmap *map, void *to, void *buf, size_t size))
285{ 285{
286 u64 head = perf_mmap__read_head(md); 286 u64 head = perf_mmap__read_head(md);
287 unsigned char *data = md->base + page_size; 287 unsigned char *data = md->base + page_size;
@@ -300,7 +300,7 @@ int perf_mmap__push(struct perf_mmap *md, void *to,
300 size = md->mask + 1 - (md->start & md->mask); 300 size = md->mask + 1 - (md->start & md->mask);
301 md->start += size; 301 md->start += size;
302 302
303 if (push(to, buf, size) < 0) { 303 if (push(md, to, buf, size) < 0) {
304 rc = -1; 304 rc = -1;
305 goto out; 305 goto out;
306 } 306 }
@@ -310,7 +310,7 @@ int perf_mmap__push(struct perf_mmap *md, void *to,
310 size = md->end - md->start; 310 size = md->end - md->start;
311 md->start += size; 311 md->start += size;
312 312
313 if (push(to, buf, size) < 0) { 313 if (push(md, to, buf, size) < 0) {
314 rc = -1; 314 rc = -1;
315 goto out; 315 goto out;
316 } 316 }
diff --git a/tools/perf/util/mmap.h b/tools/perf/util/mmap.h
index 05a6d47c7956..cc5e2d6d17a9 100644
--- a/tools/perf/util/mmap.h
+++ b/tools/perf/util/mmap.h
@@ -4,7 +4,7 @@
4#include <linux/compiler.h> 4#include <linux/compiler.h>
5#include <linux/refcount.h> 5#include <linux/refcount.h>
6#include <linux/types.h> 6#include <linux/types.h>
7#include <asm/barrier.h> 7#include <linux/ring_buffer.h>
8#include <stdbool.h> 8#include <stdbool.h>
9#include "auxtrace.h" 9#include "auxtrace.h"
10#include "event.h" 10#include "event.h"
@@ -71,21 +71,12 @@ void perf_mmap__consume(struct perf_mmap *map);
71 71
72static inline u64 perf_mmap__read_head(struct perf_mmap *mm) 72static inline u64 perf_mmap__read_head(struct perf_mmap *mm)
73{ 73{
74 struct perf_event_mmap_page *pc = mm->base; 74 return ring_buffer_read_head(mm->base);
75 u64 head = READ_ONCE(pc->data_head);
76 rmb();
77 return head;
78} 75}
79 76
80static inline void perf_mmap__write_tail(struct perf_mmap *md, u64 tail) 77static inline void perf_mmap__write_tail(struct perf_mmap *md, u64 tail)
81{ 78{
82 struct perf_event_mmap_page *pc = md->base; 79 ring_buffer_write_tail(md->base, tail);
83
84 /*
85 * ensure all reads are done before we write the tail out.
86 */
87 mb();
88 pc->data_tail = tail;
89} 80}
90 81
91union perf_event *perf_mmap__read_forward(struct perf_mmap *map); 82union perf_event *perf_mmap__read_forward(struct perf_mmap *map);
@@ -93,7 +84,7 @@ union perf_event *perf_mmap__read_forward(struct perf_mmap *map);
93union perf_event *perf_mmap__read_event(struct perf_mmap *map); 84union perf_event *perf_mmap__read_event(struct perf_mmap *map);
94 85
95int perf_mmap__push(struct perf_mmap *md, void *to, 86int perf_mmap__push(struct perf_mmap *md, void *to,
96 int push(void *to, void *buf, size_t size)); 87 int push(struct perf_mmap *map, void *to, void *buf, size_t size));
97 88
98size_t perf_mmap__mmap_len(struct perf_mmap *map); 89size_t perf_mmap__mmap_len(struct perf_mmap *map);
99 90
diff --git a/tools/perf/util/ordered-events.c b/tools/perf/util/ordered-events.c
index bad9e0296e9a..1904e7f6ec84 100644
--- a/tools/perf/util/ordered-events.c
+++ b/tools/perf/util/ordered-events.c
@@ -80,14 +80,20 @@ static union perf_event *dup_event(struct ordered_events *oe,
80 return oe->copy_on_queue ? __dup_event(oe, event) : event; 80 return oe->copy_on_queue ? __dup_event(oe, event) : event;
81} 81}
82 82
83static void free_dup_event(struct ordered_events *oe, union perf_event *event) 83static void __free_dup_event(struct ordered_events *oe, union perf_event *event)
84{ 84{
85 if (event && oe->copy_on_queue) { 85 if (event) {
86 oe->cur_alloc_size -= event->header.size; 86 oe->cur_alloc_size -= event->header.size;
87 free(event); 87 free(event);
88 } 88 }
89} 89}
90 90
91static void free_dup_event(struct ordered_events *oe, union perf_event *event)
92{
93 if (oe->copy_on_queue)
94 __free_dup_event(oe, event);
95}
96
91#define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct ordered_event)) 97#define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct ordered_event))
92static struct ordered_event *alloc_event(struct ordered_events *oe, 98static struct ordered_event *alloc_event(struct ordered_events *oe,
93 union perf_event *event) 99 union perf_event *event)
@@ -95,21 +101,49 @@ static struct ordered_event *alloc_event(struct ordered_events *oe,
95 struct list_head *cache = &oe->cache; 101 struct list_head *cache = &oe->cache;
96 struct ordered_event *new = NULL; 102 struct ordered_event *new = NULL;
97 union perf_event *new_event; 103 union perf_event *new_event;
104 size_t size;
98 105
99 new_event = dup_event(oe, event); 106 new_event = dup_event(oe, event);
100 if (!new_event) 107 if (!new_event)
101 return NULL; 108 return NULL;
102 109
110 /*
111 * We maintain the following scheme of buffers for ordered
112 * event allocation:
113 *
114 * to_free list -> buffer1 (64K)
115 * buffer2 (64K)
116 * ...
117 *
118 * Each buffer keeps an array of ordered events objects:
119 * buffer -> event[0]
120 * event[1]
121 * ...
122 *
123 * Each allocated ordered event is linked to one of
124 * following lists:
125 * - time ordered list 'events'
126 * - list of currently removed events 'cache'
127 *
128 * Allocation of the ordered event uses the following order
129 * to get the memory:
130 * - use recently removed object from 'cache' list
131 * - use available object in current allocation buffer
132 * - allocate new buffer if the current buffer is full
133 *
134 * Removal of ordered event object moves it from events to
135 * the cache list.
136 */
137 size = sizeof(*oe->buffer) + MAX_SAMPLE_BUFFER * sizeof(*new);
138
103 if (!list_empty(cache)) { 139 if (!list_empty(cache)) {
104 new = list_entry(cache->next, struct ordered_event, list); 140 new = list_entry(cache->next, struct ordered_event, list);
105 list_del(&new->list); 141 list_del(&new->list);
106 } else if (oe->buffer) { 142 } else if (oe->buffer) {
107 new = oe->buffer + oe->buffer_idx; 143 new = &oe->buffer->event[oe->buffer_idx];
108 if (++oe->buffer_idx == MAX_SAMPLE_BUFFER) 144 if (++oe->buffer_idx == MAX_SAMPLE_BUFFER)
109 oe->buffer = NULL; 145 oe->buffer = NULL;
110 } else if (oe->cur_alloc_size < oe->max_alloc_size) { 146 } else if ((oe->cur_alloc_size + size) < oe->max_alloc_size) {
111 size_t size = MAX_SAMPLE_BUFFER * sizeof(*new);
112
113 oe->buffer = malloc(size); 147 oe->buffer = malloc(size);
114 if (!oe->buffer) { 148 if (!oe->buffer) {
115 free_dup_event(oe, new_event); 149 free_dup_event(oe, new_event);
@@ -122,11 +156,11 @@ static struct ordered_event *alloc_event(struct ordered_events *oe,
122 oe->cur_alloc_size += size; 156 oe->cur_alloc_size += size;
123 list_add(&oe->buffer->list, &oe->to_free); 157 list_add(&oe->buffer->list, &oe->to_free);
124 158
125 /* First entry is abused to maintain the to_free list. */ 159 oe->buffer_idx = 1;
126 oe->buffer_idx = 2; 160 new = &oe->buffer->event[0];
127 new = oe->buffer + 1;
128 } else { 161 } else {
129 pr("allocation limit reached %" PRIu64 "B\n", oe->max_alloc_size); 162 pr("allocation limit reached %" PRIu64 "B\n", oe->max_alloc_size);
163 return NULL;
130 } 164 }
131 165
132 new->event = new_event; 166 new->event = new_event;
@@ -300,15 +334,38 @@ void ordered_events__init(struct ordered_events *oe, ordered_events__deliver_t d
300 oe->deliver = deliver; 334 oe->deliver = deliver;
301} 335}
302 336
337static void
338ordered_events_buffer__free(struct ordered_events_buffer *buffer,
339 unsigned int max, struct ordered_events *oe)
340{
341 if (oe->copy_on_queue) {
342 unsigned int i;
343
344 for (i = 0; i < max; i++)
345 __free_dup_event(oe, buffer->event[i].event);
346 }
347
348 free(buffer);
349}
350
303void ordered_events__free(struct ordered_events *oe) 351void ordered_events__free(struct ordered_events *oe)
304{ 352{
305 while (!list_empty(&oe->to_free)) { 353 struct ordered_events_buffer *buffer, *tmp;
306 struct ordered_event *event;
307 354
308 event = list_entry(oe->to_free.next, struct ordered_event, list); 355 if (list_empty(&oe->to_free))
309 list_del(&event->list); 356 return;
310 free_dup_event(oe, event->event); 357
311 free(event); 358 /*
359 * Current buffer might not have all the events allocated
360 * yet, we need to free only allocated ones ...
361 */
362 list_del(&oe->buffer->list);
363 ordered_events_buffer__free(oe->buffer, oe->buffer_idx, oe);
364
365 /* ... and continue with the rest */
366 list_for_each_entry_safe(buffer, tmp, &oe->to_free, list) {
367 list_del(&buffer->list);
368 ordered_events_buffer__free(buffer, MAX_SAMPLE_BUFFER, oe);
312 } 369 }
313} 370}
314 371
diff --git a/tools/perf/util/ordered-events.h b/tools/perf/util/ordered-events.h
index 8c7a2948593e..1338d5c345dc 100644
--- a/tools/perf/util/ordered-events.h
+++ b/tools/perf/util/ordered-events.h
@@ -25,23 +25,28 @@ struct ordered_events;
25typedef int (*ordered_events__deliver_t)(struct ordered_events *oe, 25typedef int (*ordered_events__deliver_t)(struct ordered_events *oe,
26 struct ordered_event *event); 26 struct ordered_event *event);
27 27
28struct ordered_events_buffer {
29 struct list_head list;
30 struct ordered_event event[0];
31};
32
28struct ordered_events { 33struct ordered_events {
29 u64 last_flush; 34 u64 last_flush;
30 u64 next_flush; 35 u64 next_flush;
31 u64 max_timestamp; 36 u64 max_timestamp;
32 u64 max_alloc_size; 37 u64 max_alloc_size;
33 u64 cur_alloc_size; 38 u64 cur_alloc_size;
34 struct list_head events; 39 struct list_head events;
35 struct list_head cache; 40 struct list_head cache;
36 struct list_head to_free; 41 struct list_head to_free;
37 struct ordered_event *buffer; 42 struct ordered_events_buffer *buffer;
38 struct ordered_event *last; 43 struct ordered_event *last;
39 ordered_events__deliver_t deliver; 44 ordered_events__deliver_t deliver;
40 int buffer_idx; 45 int buffer_idx;
41 unsigned int nr_events; 46 unsigned int nr_events;
42 enum oe_flush last_flush_type; 47 enum oe_flush last_flush_type;
43 u32 nr_unordered_events; 48 u32 nr_unordered_events;
44 bool copy_on_queue; 49 bool copy_on_queue;
45}; 50};
46 51
47int ordered_events__queue(struct ordered_events *oe, union perf_event *event, 52int ordered_events__queue(struct ordered_events *oe, union perf_event *event,
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index f8cd3e7c9186..59be3466d64d 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -926,6 +926,7 @@ static const char *config_term_names[__PARSE_EVENTS__TERM_TYPE_NR] = {
926 [PARSE_EVENTS__TERM_TYPE_NOINHERIT] = "no-inherit", 926 [PARSE_EVENTS__TERM_TYPE_NOINHERIT] = "no-inherit",
927 [PARSE_EVENTS__TERM_TYPE_INHERIT] = "inherit", 927 [PARSE_EVENTS__TERM_TYPE_INHERIT] = "inherit",
928 [PARSE_EVENTS__TERM_TYPE_MAX_STACK] = "max-stack", 928 [PARSE_EVENTS__TERM_TYPE_MAX_STACK] = "max-stack",
929 [PARSE_EVENTS__TERM_TYPE_MAX_EVENTS] = "nr",
929 [PARSE_EVENTS__TERM_TYPE_OVERWRITE] = "overwrite", 930 [PARSE_EVENTS__TERM_TYPE_OVERWRITE] = "overwrite",
930 [PARSE_EVENTS__TERM_TYPE_NOOVERWRITE] = "no-overwrite", 931 [PARSE_EVENTS__TERM_TYPE_NOOVERWRITE] = "no-overwrite",
931 [PARSE_EVENTS__TERM_TYPE_DRV_CFG] = "driver-config", 932 [PARSE_EVENTS__TERM_TYPE_DRV_CFG] = "driver-config",
@@ -1037,6 +1038,9 @@ do { \
1037 case PARSE_EVENTS__TERM_TYPE_MAX_STACK: 1038 case PARSE_EVENTS__TERM_TYPE_MAX_STACK:
1038 CHECK_TYPE_VAL(NUM); 1039 CHECK_TYPE_VAL(NUM);
1039 break; 1040 break;
1041 case PARSE_EVENTS__TERM_TYPE_MAX_EVENTS:
1042 CHECK_TYPE_VAL(NUM);
1043 break;
1040 default: 1044 default:
1041 err->str = strdup("unknown term"); 1045 err->str = strdup("unknown term");
1042 err->idx = term->err_term; 1046 err->idx = term->err_term;
@@ -1084,6 +1088,7 @@ static int config_term_tracepoint(struct perf_event_attr *attr,
1084 case PARSE_EVENTS__TERM_TYPE_INHERIT: 1088 case PARSE_EVENTS__TERM_TYPE_INHERIT:
1085 case PARSE_EVENTS__TERM_TYPE_NOINHERIT: 1089 case PARSE_EVENTS__TERM_TYPE_NOINHERIT:
1086 case PARSE_EVENTS__TERM_TYPE_MAX_STACK: 1090 case PARSE_EVENTS__TERM_TYPE_MAX_STACK:
1091 case PARSE_EVENTS__TERM_TYPE_MAX_EVENTS:
1087 case PARSE_EVENTS__TERM_TYPE_OVERWRITE: 1092 case PARSE_EVENTS__TERM_TYPE_OVERWRITE:
1088 case PARSE_EVENTS__TERM_TYPE_NOOVERWRITE: 1093 case PARSE_EVENTS__TERM_TYPE_NOOVERWRITE:
1089 return config_term_common(attr, term, err); 1094 return config_term_common(attr, term, err);
@@ -1162,6 +1167,9 @@ do { \
1162 case PARSE_EVENTS__TERM_TYPE_MAX_STACK: 1167 case PARSE_EVENTS__TERM_TYPE_MAX_STACK:
1163 ADD_CONFIG_TERM(MAX_STACK, max_stack, term->val.num); 1168 ADD_CONFIG_TERM(MAX_STACK, max_stack, term->val.num);
1164 break; 1169 break;
1170 case PARSE_EVENTS__TERM_TYPE_MAX_EVENTS:
1171 ADD_CONFIG_TERM(MAX_EVENTS, max_events, term->val.num);
1172 break;
1165 case PARSE_EVENTS__TERM_TYPE_OVERWRITE: 1173 case PARSE_EVENTS__TERM_TYPE_OVERWRITE:
1166 ADD_CONFIG_TERM(OVERWRITE, overwrite, term->val.num ? 1 : 0); 1174 ADD_CONFIG_TERM(OVERWRITE, overwrite, term->val.num ? 1 : 0);
1167 break; 1175 break;
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 4473dac27aee..5ed035cbcbb7 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -71,6 +71,7 @@ enum {
71 PARSE_EVENTS__TERM_TYPE_NOINHERIT, 71 PARSE_EVENTS__TERM_TYPE_NOINHERIT,
72 PARSE_EVENTS__TERM_TYPE_INHERIT, 72 PARSE_EVENTS__TERM_TYPE_INHERIT,
73 PARSE_EVENTS__TERM_TYPE_MAX_STACK, 73 PARSE_EVENTS__TERM_TYPE_MAX_STACK,
74 PARSE_EVENTS__TERM_TYPE_MAX_EVENTS,
74 PARSE_EVENTS__TERM_TYPE_NOOVERWRITE, 75 PARSE_EVENTS__TERM_TYPE_NOOVERWRITE,
75 PARSE_EVENTS__TERM_TYPE_OVERWRITE, 76 PARSE_EVENTS__TERM_TYPE_OVERWRITE,
76 PARSE_EVENTS__TERM_TYPE_DRV_CFG, 77 PARSE_EVENTS__TERM_TYPE_DRV_CFG,
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index 5f761f3ed0f3..7805c71aaae2 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -269,6 +269,7 @@ time { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_TIME); }
269call-graph { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CALLGRAPH); } 269call-graph { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CALLGRAPH); }
270stack-size { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_STACKSIZE); } 270stack-size { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_STACKSIZE); }
271max-stack { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_MAX_STACK); } 271max-stack { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_MAX_STACK); }
272nr { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_MAX_EVENTS); }
272inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_INHERIT); } 273inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_INHERIT); }
273no-inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NOINHERIT); } 274no-inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NOINHERIT); }
274overwrite { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_OVERWRITE); } 275overwrite { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_OVERWRITE); }
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index afd68524ffa9..7799788f662f 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -930,13 +930,14 @@ static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v,
930 930
931static __u64 pmu_format_max_value(const unsigned long *format) 931static __u64 pmu_format_max_value(const unsigned long *format)
932{ 932{
933 __u64 w = 0; 933 int w;
934 int fbit;
935
936 for_each_set_bit(fbit, format, PERF_PMU_FORMAT_BITS)
937 w |= (1ULL << fbit);
938 934
939 return w; 935 w = bitmap_weight(format, PERF_PMU_FORMAT_BITS);
936 if (!w)
937 return 0;
938 if (w < 64)
939 return (1ULL << w) - 1;
940 return -1;
940} 941}
941 942
942/* 943/*
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index f119eb628dbb..e86f8be89157 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1819,6 +1819,12 @@ int parse_probe_trace_command(const char *cmd, struct probe_trace_event *tev)
1819 tp->offset = strtoul(fmt2_str, NULL, 10); 1819 tp->offset = strtoul(fmt2_str, NULL, 10);
1820 } 1820 }
1821 1821
1822 if (tev->uprobes) {
1823 fmt2_str = strchr(p, '(');
1824 if (fmt2_str)
1825 tp->ref_ctr_offset = strtoul(fmt2_str + 1, NULL, 0);
1826 }
1827
1822 tev->nargs = argc - 2; 1828 tev->nargs = argc - 2;
1823 tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); 1829 tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
1824 if (tev->args == NULL) { 1830 if (tev->args == NULL) {
@@ -2012,6 +2018,22 @@ static int synthesize_probe_trace_arg(struct probe_trace_arg *arg,
2012 return err; 2018 return err;
2013} 2019}
2014 2020
2021static int
2022synthesize_uprobe_trace_def(struct probe_trace_event *tev, struct strbuf *buf)
2023{
2024 struct probe_trace_point *tp = &tev->point;
2025 int err;
2026
2027 err = strbuf_addf(buf, "%s:0x%lx", tp->module, tp->address);
2028
2029 if (err >= 0 && tp->ref_ctr_offset) {
2030 if (!uprobe_ref_ctr_is_supported())
2031 return -1;
2032 err = strbuf_addf(buf, "(0x%lx)", tp->ref_ctr_offset);
2033 }
2034 return err >= 0 ? 0 : -1;
2035}
2036
2015char *synthesize_probe_trace_command(struct probe_trace_event *tev) 2037char *synthesize_probe_trace_command(struct probe_trace_event *tev)
2016{ 2038{
2017 struct probe_trace_point *tp = &tev->point; 2039 struct probe_trace_point *tp = &tev->point;
@@ -2041,15 +2063,17 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev)
2041 } 2063 }
2042 2064
2043 /* Use the tp->address for uprobes */ 2065 /* Use the tp->address for uprobes */
2044 if (tev->uprobes) 2066 if (tev->uprobes) {
2045 err = strbuf_addf(&buf, "%s:0x%lx", tp->module, tp->address); 2067 err = synthesize_uprobe_trace_def(tev, &buf);
2046 else if (!strncmp(tp->symbol, "0x", 2)) 2068 } else if (!strncmp(tp->symbol, "0x", 2)) {
2047 /* Absolute address. See try_to_find_absolute_address() */ 2069 /* Absolute address. See try_to_find_absolute_address() */
2048 err = strbuf_addf(&buf, "%s%s0x%lx", tp->module ?: "", 2070 err = strbuf_addf(&buf, "%s%s0x%lx", tp->module ?: "",
2049 tp->module ? ":" : "", tp->address); 2071 tp->module ? ":" : "", tp->address);
2050 else 2072 } else {
2051 err = strbuf_addf(&buf, "%s%s%s+%lu", tp->module ?: "", 2073 err = strbuf_addf(&buf, "%s%s%s+%lu", tp->module ?: "",
2052 tp->module ? ":" : "", tp->symbol, tp->offset); 2074 tp->module ? ":" : "", tp->symbol, tp->offset);
2075 }
2076
2053 if (err) 2077 if (err)
2054 goto error; 2078 goto error;
2055 2079
@@ -2633,6 +2657,13 @@ static void warn_uprobe_event_compat(struct probe_trace_event *tev)
2633{ 2657{
2634 int i; 2658 int i;
2635 char *buf = synthesize_probe_trace_command(tev); 2659 char *buf = synthesize_probe_trace_command(tev);
2660 struct probe_trace_point *tp = &tev->point;
2661
2662 if (tp->ref_ctr_offset && !uprobe_ref_ctr_is_supported()) {
2663 pr_warning("A semaphore is associated with %s:%s and "
2664 "seems your kernel doesn't support it.\n",
2665 tev->group, tev->event);
2666 }
2636 2667
2637 /* Old uprobe event doesn't support memory dereference */ 2668 /* Old uprobe event doesn't support memory dereference */
2638 if (!tev->uprobes || tev->nargs == 0 || !buf) 2669 if (!tev->uprobes || tev->nargs == 0 || !buf)
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 45b14f020558..15a98c3a2a2f 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -27,6 +27,7 @@ struct probe_trace_point {
27 char *symbol; /* Base symbol */ 27 char *symbol; /* Base symbol */
28 char *module; /* Module name */ 28 char *module; /* Module name */
29 unsigned long offset; /* Offset from symbol */ 29 unsigned long offset; /* Offset from symbol */
30 unsigned long ref_ctr_offset; /* SDT reference counter offset */
30 unsigned long address; /* Actual address of the trace point */ 31 unsigned long address; /* Actual address of the trace point */
31 bool retprobe; /* Return probe flag */ 32 bool retprobe; /* Return probe flag */
32}; 33};
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
index b76088fadf3d..aac7817d9e14 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -696,8 +696,16 @@ out_err:
696#ifdef HAVE_GELF_GETNOTE_SUPPORT 696#ifdef HAVE_GELF_GETNOTE_SUPPORT
697static unsigned long long sdt_note__get_addr(struct sdt_note *note) 697static unsigned long long sdt_note__get_addr(struct sdt_note *note)
698{ 698{
699 return note->bit32 ? (unsigned long long)note->addr.a32[0] 699 return note->bit32 ?
700 : (unsigned long long)note->addr.a64[0]; 700 (unsigned long long)note->addr.a32[SDT_NOTE_IDX_LOC] :
701 (unsigned long long)note->addr.a64[SDT_NOTE_IDX_LOC];
702}
703
704static unsigned long long sdt_note__get_ref_ctr_offset(struct sdt_note *note)
705{
706 return note->bit32 ?
707 (unsigned long long)note->addr.a32[SDT_NOTE_IDX_REFCTR] :
708 (unsigned long long)note->addr.a64[SDT_NOTE_IDX_REFCTR];
701} 709}
702 710
703static const char * const type_to_suffix[] = { 711static const char * const type_to_suffix[] = {
@@ -775,14 +783,21 @@ static char *synthesize_sdt_probe_command(struct sdt_note *note,
775{ 783{
776 struct strbuf buf; 784 struct strbuf buf;
777 char *ret = NULL, **args; 785 char *ret = NULL, **args;
778 int i, args_count; 786 int i, args_count, err;
787 unsigned long long ref_ctr_offset;
779 788
780 if (strbuf_init(&buf, 32) < 0) 789 if (strbuf_init(&buf, 32) < 0)
781 return NULL; 790 return NULL;
782 791
783 if (strbuf_addf(&buf, "p:%s/%s %s:0x%llx", 792 err = strbuf_addf(&buf, "p:%s/%s %s:0x%llx",
784 sdtgrp, note->name, pathname, 793 sdtgrp, note->name, pathname,
785 sdt_note__get_addr(note)) < 0) 794 sdt_note__get_addr(note));
795
796 ref_ctr_offset = sdt_note__get_ref_ctr_offset(note);
797 if (ref_ctr_offset && err >= 0)
798 err = strbuf_addf(&buf, "(0x%llx)", ref_ctr_offset);
799
800 if (err < 0)
786 goto error; 801 goto error;
787 802
788 if (!note->args) 803 if (!note->args)
@@ -998,6 +1013,7 @@ int probe_cache__show_all_caches(struct strfilter *filter)
998enum ftrace_readme { 1013enum ftrace_readme {
999 FTRACE_README_PROBE_TYPE_X = 0, 1014 FTRACE_README_PROBE_TYPE_X = 0,
1000 FTRACE_README_KRETPROBE_OFFSET, 1015 FTRACE_README_KRETPROBE_OFFSET,
1016 FTRACE_README_UPROBE_REF_CTR,
1001 FTRACE_README_END, 1017 FTRACE_README_END,
1002}; 1018};
1003 1019
@@ -1009,6 +1025,7 @@ static struct {
1009 [idx] = {.pattern = pat, .avail = false} 1025 [idx] = {.pattern = pat, .avail = false}
1010 DEFINE_TYPE(FTRACE_README_PROBE_TYPE_X, "*type: * x8/16/32/64,*"), 1026 DEFINE_TYPE(FTRACE_README_PROBE_TYPE_X, "*type: * x8/16/32/64,*"),
1011 DEFINE_TYPE(FTRACE_README_KRETPROBE_OFFSET, "*place (kretprobe): *"), 1027 DEFINE_TYPE(FTRACE_README_KRETPROBE_OFFSET, "*place (kretprobe): *"),
1028 DEFINE_TYPE(FTRACE_README_UPROBE_REF_CTR, "*ref_ctr_offset*"),
1012}; 1029};
1013 1030
1014static bool scan_ftrace_readme(enum ftrace_readme type) 1031static bool scan_ftrace_readme(enum ftrace_readme type)
@@ -1064,3 +1081,8 @@ bool kretprobe_offset_is_supported(void)
1064{ 1081{
1065 return scan_ftrace_readme(FTRACE_README_KRETPROBE_OFFSET); 1082 return scan_ftrace_readme(FTRACE_README_KRETPROBE_OFFSET);
1066} 1083}
1084
1085bool uprobe_ref_ctr_is_supported(void)
1086{
1087 return scan_ftrace_readme(FTRACE_README_UPROBE_REF_CTR);
1088}
diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h
index 63f29b1d22c1..2a249182f2a6 100644
--- a/tools/perf/util/probe-file.h
+++ b/tools/perf/util/probe-file.h
@@ -69,6 +69,7 @@ struct probe_cache_entry *probe_cache__find_by_name(struct probe_cache *pcache,
69int probe_cache__show_all_caches(struct strfilter *filter); 69int probe_cache__show_all_caches(struct strfilter *filter);
70bool probe_type_is_available(enum probe_type type); 70bool probe_type_is_available(enum probe_type type);
71bool kretprobe_offset_is_supported(void); 71bool kretprobe_offset_is_supported(void);
72bool uprobe_ref_ctr_is_supported(void);
72#else /* ! HAVE_LIBELF_SUPPORT */ 73#else /* ! HAVE_LIBELF_SUPPORT */
73static inline struct probe_cache *probe_cache__new(const char *tgt __maybe_unused, struct nsinfo *nsi __maybe_unused) 74static inline struct probe_cache *probe_cache__new(const char *tgt __maybe_unused, struct nsinfo *nsi __maybe_unused)
74{ 75{
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index ce501ba14b08..50150dfc0cdf 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -340,7 +340,7 @@ static bool is_tracepoint(struct pyrf_event *pevent)
340} 340}
341 341
342static PyObject* 342static PyObject*
343tracepoint_field(struct pyrf_event *pe, struct format_field *field) 343tracepoint_field(struct pyrf_event *pe, struct tep_format_field *field)
344{ 344{
345 struct tep_handle *pevent = field->event->pevent; 345 struct tep_handle *pevent = field->event->pevent;
346 void *data = pe->sample.raw_data; 346 void *data = pe->sample.raw_data;
@@ -348,28 +348,28 @@ tracepoint_field(struct pyrf_event *pe, struct format_field *field)
348 unsigned long long val; 348 unsigned long long val;
349 unsigned int offset, len; 349 unsigned int offset, len;
350 350
351 if (field->flags & FIELD_IS_ARRAY) { 351 if (field->flags & TEP_FIELD_IS_ARRAY) {
352 offset = field->offset; 352 offset = field->offset;
353 len = field->size; 353 len = field->size;
354 if (field->flags & FIELD_IS_DYNAMIC) { 354 if (field->flags & TEP_FIELD_IS_DYNAMIC) {
355 val = tep_read_number(pevent, data + offset, len); 355 val = tep_read_number(pevent, data + offset, len);
356 offset = val; 356 offset = val;
357 len = offset >> 16; 357 len = offset >> 16;
358 offset &= 0xffff; 358 offset &= 0xffff;
359 } 359 }
360 if (field->flags & FIELD_IS_STRING && 360 if (field->flags & TEP_FIELD_IS_STRING &&
361 is_printable_array(data + offset, len)) { 361 is_printable_array(data + offset, len)) {
362 ret = _PyUnicode_FromString((char *)data + offset); 362 ret = _PyUnicode_FromString((char *)data + offset);
363 } else { 363 } else {
364 ret = PyByteArray_FromStringAndSize((const char *) data + offset, len); 364 ret = PyByteArray_FromStringAndSize((const char *) data + offset, len);
365 field->flags &= ~FIELD_IS_STRING; 365 field->flags &= ~TEP_FIELD_IS_STRING;
366 } 366 }
367 } else { 367 } else {
368 val = tep_read_number(pevent, data + field->offset, 368 val = tep_read_number(pevent, data + field->offset,
369 field->size); 369 field->size);
370 if (field->flags & FIELD_IS_POINTER) 370 if (field->flags & TEP_FIELD_IS_POINTER)
371 ret = PyLong_FromUnsignedLong((unsigned long) val); 371 ret = PyLong_FromUnsignedLong((unsigned long) val);
372 else if (field->flags & FIELD_IS_SIGNED) 372 else if (field->flags & TEP_FIELD_IS_SIGNED)
373 ret = PyLong_FromLong((long) val); 373 ret = PyLong_FromLong((long) val);
374 else 374 else
375 ret = PyLong_FromUnsignedLong((unsigned long) val); 375 ret = PyLong_FromUnsignedLong((unsigned long) val);
@@ -383,10 +383,10 @@ get_tracepoint_field(struct pyrf_event *pevent, PyObject *attr_name)
383{ 383{
384 const char *str = _PyUnicode_AsString(PyObject_Str(attr_name)); 384 const char *str = _PyUnicode_AsString(PyObject_Str(attr_name));
385 struct perf_evsel *evsel = pevent->evsel; 385 struct perf_evsel *evsel = pevent->evsel;
386 struct format_field *field; 386 struct tep_format_field *field;
387 387
388 if (!evsel->tp_format) { 388 if (!evsel->tp_format) {
389 struct event_format *tp_format; 389 struct tep_event_format *tp_format;
390 390
391 tp_format = trace_event__tp_format_id(evsel->attr.config); 391 tp_format = trace_event__tp_format_id(evsel->attr.config);
392 if (!tp_format) 392 if (!tp_format)
@@ -1240,7 +1240,7 @@ static struct {
1240static PyObject *pyrf__tracepoint(struct pyrf_evsel *pevsel, 1240static PyObject *pyrf__tracepoint(struct pyrf_evsel *pevsel,
1241 PyObject *args, PyObject *kwargs) 1241 PyObject *args, PyObject *kwargs)
1242{ 1242{
1243 struct event_format *tp_format; 1243 struct tep_event_format *tp_format;
1244 static char *kwlist[] = { "sys", "name", NULL }; 1244 static char *kwlist[] = { "sys", "name", NULL };
1245 char *sys = NULL; 1245 char *sys = NULL;
1246 char *name = NULL; 1246 char *name = NULL;
diff --git a/tools/perf/util/s390-cpumsf.c b/tools/perf/util/s390-cpumsf.c
index d2c78ffd9fee..a2eeebbfb25f 100644
--- a/tools/perf/util/s390-cpumsf.c
+++ b/tools/perf/util/s390-cpumsf.c
@@ -147,6 +147,9 @@
147#include <linux/bitops.h> 147#include <linux/bitops.h>
148#include <linux/log2.h> 148#include <linux/log2.h>
149 149
150#include <sys/stat.h>
151#include <sys/types.h>
152
150#include "cpumap.h" 153#include "cpumap.h"
151#include "color.h" 154#include "color.h"
152#include "evsel.h" 155#include "evsel.h"
@@ -159,6 +162,7 @@
159#include "auxtrace.h" 162#include "auxtrace.h"
160#include "s390-cpumsf.h" 163#include "s390-cpumsf.h"
161#include "s390-cpumsf-kernel.h" 164#include "s390-cpumsf-kernel.h"
165#include "config.h"
162 166
163struct s390_cpumsf { 167struct s390_cpumsf {
164 struct auxtrace auxtrace; 168 struct auxtrace auxtrace;
@@ -170,6 +174,8 @@ struct s390_cpumsf {
170 u32 pmu_type; 174 u32 pmu_type;
171 u16 machine_type; 175 u16 machine_type;
172 bool data_queued; 176 bool data_queued;
177 bool use_logfile;
178 char *logdir;
173}; 179};
174 180
175struct s390_cpumsf_queue { 181struct s390_cpumsf_queue {
@@ -177,6 +183,7 @@ struct s390_cpumsf_queue {
177 unsigned int queue_nr; 183 unsigned int queue_nr;
178 struct auxtrace_buffer *buffer; 184 struct auxtrace_buffer *buffer;
179 int cpu; 185 int cpu;
186 FILE *logfile;
180}; 187};
181 188
182/* Display s390 CPU measurement facility basic-sampling data entry */ 189/* Display s390 CPU measurement facility basic-sampling data entry */
@@ -595,6 +602,12 @@ static int s390_cpumsf_run_decoder(struct s390_cpumsf_queue *sfq,
595 buffer->use_size = buffer->size; 602 buffer->use_size = buffer->size;
596 buffer->use_data = buffer->data; 603 buffer->use_data = buffer->data;
597 } 604 }
605 if (sfq->logfile) { /* Write into log file */
606 size_t rc = fwrite(buffer->data, buffer->size, 1,
607 sfq->logfile);
608 if (rc != 1)
609 pr_err("Failed to write auxiliary data\n");
610 }
598 } else 611 } else
599 buffer = sfq->buffer; 612 buffer = sfq->buffer;
600 613
@@ -606,6 +619,13 @@ static int s390_cpumsf_run_decoder(struct s390_cpumsf_queue *sfq,
606 return -ENOMEM; 619 return -ENOMEM;
607 buffer->use_size = buffer->size; 620 buffer->use_size = buffer->size;
608 buffer->use_data = buffer->data; 621 buffer->use_data = buffer->data;
622
623 if (sfq->logfile) { /* Write into log file */
624 size_t rc = fwrite(buffer->data, buffer->size, 1,
625 sfq->logfile);
626 if (rc != 1)
627 pr_err("Failed to write auxiliary data\n");
628 }
609 } 629 }
610 pr_debug4("%s queue_nr:%d buffer:%" PRId64 " offset:%#" PRIx64 " size:%#zx rest:%#zx\n", 630 pr_debug4("%s queue_nr:%d buffer:%" PRId64 " offset:%#" PRIx64 " size:%#zx rest:%#zx\n",
611 __func__, sfq->queue_nr, buffer->buffer_nr, buffer->offset, 631 __func__, sfq->queue_nr, buffer->buffer_nr, buffer->offset,
@@ -640,6 +660,23 @@ s390_cpumsf_alloc_queue(struct s390_cpumsf *sf, unsigned int queue_nr)
640 sfq->sf = sf; 660 sfq->sf = sf;
641 sfq->queue_nr = queue_nr; 661 sfq->queue_nr = queue_nr;
642 sfq->cpu = -1; 662 sfq->cpu = -1;
663 if (sf->use_logfile) {
664 char *name;
665 int rc;
666
667 rc = (sf->logdir)
668 ? asprintf(&name, "%s/aux.smp.%02x",
669 sf->logdir, queue_nr)
670 : asprintf(&name, "aux.smp.%02x", queue_nr);
671 if (rc > 0)
672 sfq->logfile = fopen(name, "w");
673 if (sfq->logfile == NULL) {
674 pr_err("Failed to open auxiliary log file %s,"
675 "continue...\n", name);
676 sf->use_logfile = false;
677 }
678 free(name);
679 }
643 return sfq; 680 return sfq;
644} 681}
645 682
@@ -850,8 +887,16 @@ static void s390_cpumsf_free_queues(struct perf_session *session)
850 struct auxtrace_queues *queues = &sf->queues; 887 struct auxtrace_queues *queues = &sf->queues;
851 unsigned int i; 888 unsigned int i;
852 889
853 for (i = 0; i < queues->nr_queues; i++) 890 for (i = 0; i < queues->nr_queues; i++) {
891 struct s390_cpumsf_queue *sfq = (struct s390_cpumsf_queue *)
892 queues->queue_array[i].priv;
893
894 if (sfq != NULL && sfq->logfile) {
895 fclose(sfq->logfile);
896 sfq->logfile = NULL;
897 }
854 zfree(&queues->queue_array[i].priv); 898 zfree(&queues->queue_array[i].priv);
899 }
855 auxtrace_queues__free(queues); 900 auxtrace_queues__free(queues);
856} 901}
857 902
@@ -864,6 +909,7 @@ static void s390_cpumsf_free(struct perf_session *session)
864 auxtrace_heap__free(&sf->heap); 909 auxtrace_heap__free(&sf->heap);
865 s390_cpumsf_free_queues(session); 910 s390_cpumsf_free_queues(session);
866 session->auxtrace = NULL; 911 session->auxtrace = NULL;
912 free(sf->logdir);
867 free(sf); 913 free(sf);
868} 914}
869 915
@@ -877,17 +923,55 @@ static int s390_cpumsf_get_type(const char *cpuid)
877 923
878/* Check itrace options set on perf report command. 924/* Check itrace options set on perf report command.
879 * Return true, if none are set or all options specified can be 925 * Return true, if none are set or all options specified can be
880 * handled on s390. 926 * handled on s390 (currently only option 'd' for logging.
881 * Return false otherwise. 927 * Return false otherwise.
882 */ 928 */
883static bool check_auxtrace_itrace(struct itrace_synth_opts *itops) 929static bool check_auxtrace_itrace(struct itrace_synth_opts *itops)
884{ 930{
931 bool ison = false;
932
885 if (!itops || !itops->set) 933 if (!itops || !itops->set)
886 return true; 934 return true;
887 pr_err("No --itrace options supported\n"); 935 ison = itops->inject || itops->instructions || itops->branches ||
936 itops->transactions || itops->ptwrites ||
937 itops->pwr_events || itops->errors ||
938 itops->dont_decode || itops->calls || itops->returns ||
939 itops->callchain || itops->thread_stack ||
940 itops->last_branch;
941 if (!ison)
942 return true;
943 pr_err("Unsupported --itrace options specified\n");
888 return false; 944 return false;
889} 945}
890 946
947/* Check for AUXTRACE dump directory if it is needed.
948 * On failure print an error message but continue.
949 * Return 0 on wrong keyword in config file and 1 otherwise.
950 */
951static int s390_cpumsf__config(const char *var, const char *value, void *cb)
952{
953 struct s390_cpumsf *sf = cb;
954 struct stat stbuf;
955 int rc;
956
957 if (strcmp(var, "auxtrace.dumpdir"))
958 return 0;
959 sf->logdir = strdup(value);
960 if (sf->logdir == NULL) {
961 pr_err("Failed to find auxtrace log directory %s,"
962 " continue with current directory...\n", value);
963 return 1;
964 }
965 rc = stat(sf->logdir, &stbuf);
966 if (rc == -1 || !S_ISDIR(stbuf.st_mode)) {
967 pr_err("Missing auxtrace log directory %s,"
968 " continue with current directory...\n", value);
969 free(sf->logdir);
970 sf->logdir = NULL;
971 }
972 return 1;
973}
974
891int s390_cpumsf_process_auxtrace_info(union perf_event *event, 975int s390_cpumsf_process_auxtrace_info(union perf_event *event,
892 struct perf_session *session) 976 struct perf_session *session)
893{ 977{
@@ -906,6 +990,9 @@ int s390_cpumsf_process_auxtrace_info(union perf_event *event,
906 err = -EINVAL; 990 err = -EINVAL;
907 goto err_free; 991 goto err_free;
908 } 992 }
993 sf->use_logfile = session->itrace_synth_opts->log;
994 if (sf->use_logfile)
995 perf_config(s390_cpumsf__config, sf);
909 996
910 err = auxtrace_queues__init(&sf->queues); 997 err = auxtrace_queues__init(&sf->queues);
911 if (err) 998 if (err)
@@ -940,6 +1027,7 @@ err_free_queues:
940 auxtrace_queues__free(&sf->queues); 1027 auxtrace_queues__free(&sf->queues);
941 session->auxtrace = NULL; 1028 session->auxtrace = NULL;
942err_free: 1029err_free:
1030 free(sf->logdir);
943 free(sf); 1031 free(sf);
944 return err; 1032 return err;
945} 1033}
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index 45484f0f7292..89cb887648f9 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -99,7 +99,7 @@ static void define_symbolic_value(const char *ev_name,
99 LEAVE; 99 LEAVE;
100} 100}
101 101
102static void define_symbolic_values(struct print_flag_sym *field, 102static void define_symbolic_values(struct tep_print_flag_sym *field,
103 const char *ev_name, 103 const char *ev_name,
104 const char *field_name) 104 const char *field_name)
105{ 105{
@@ -157,7 +157,7 @@ static void define_flag_value(const char *ev_name,
157 LEAVE; 157 LEAVE;
158} 158}
159 159
160static void define_flag_values(struct print_flag_sym *field, 160static void define_flag_values(struct tep_print_flag_sym *field,
161 const char *ev_name, 161 const char *ev_name,
162 const char *field_name) 162 const char *field_name)
163{ 163{
@@ -189,62 +189,62 @@ static void define_flag_field(const char *ev_name,
189 LEAVE; 189 LEAVE;
190} 190}
191 191
192static void define_event_symbols(struct event_format *event, 192static void define_event_symbols(struct tep_event_format *event,
193 const char *ev_name, 193 const char *ev_name,
194 struct print_arg *args) 194 struct tep_print_arg *args)
195{ 195{
196 if (args == NULL) 196 if (args == NULL)
197 return; 197 return;
198 198
199 switch (args->type) { 199 switch (args->type) {
200 case PRINT_NULL: 200 case TEP_PRINT_NULL:
201 break; 201 break;
202 case PRINT_ATOM: 202 case TEP_PRINT_ATOM:
203 define_flag_value(ev_name, cur_field_name, "0", 203 define_flag_value(ev_name, cur_field_name, "0",
204 args->atom.atom); 204 args->atom.atom);
205 zero_flag_atom = 0; 205 zero_flag_atom = 0;
206 break; 206 break;
207 case PRINT_FIELD: 207 case TEP_PRINT_FIELD:
208 free(cur_field_name); 208 free(cur_field_name);
209 cur_field_name = strdup(args->field.name); 209 cur_field_name = strdup(args->field.name);
210 break; 210 break;
211 case PRINT_FLAGS: 211 case TEP_PRINT_FLAGS:
212 define_event_symbols(event, ev_name, args->flags.field); 212 define_event_symbols(event, ev_name, args->flags.field);
213 define_flag_field(ev_name, cur_field_name, args->flags.delim); 213 define_flag_field(ev_name, cur_field_name, args->flags.delim);
214 define_flag_values(args->flags.flags, ev_name, cur_field_name); 214 define_flag_values(args->flags.flags, ev_name, cur_field_name);
215 break; 215 break;
216 case PRINT_SYMBOL: 216 case TEP_PRINT_SYMBOL:
217 define_event_symbols(event, ev_name, args->symbol.field); 217 define_event_symbols(event, ev_name, args->symbol.field);
218 define_symbolic_field(ev_name, cur_field_name); 218 define_symbolic_field(ev_name, cur_field_name);
219 define_symbolic_values(args->symbol.symbols, ev_name, 219 define_symbolic_values(args->symbol.symbols, ev_name,
220 cur_field_name); 220 cur_field_name);
221 break; 221 break;
222 case PRINT_HEX: 222 case TEP_PRINT_HEX:
223 case PRINT_HEX_STR: 223 case TEP_PRINT_HEX_STR:
224 define_event_symbols(event, ev_name, args->hex.field); 224 define_event_symbols(event, ev_name, args->hex.field);
225 define_event_symbols(event, ev_name, args->hex.size); 225 define_event_symbols(event, ev_name, args->hex.size);
226 break; 226 break;
227 case PRINT_INT_ARRAY: 227 case TEP_PRINT_INT_ARRAY:
228 define_event_symbols(event, ev_name, args->int_array.field); 228 define_event_symbols(event, ev_name, args->int_array.field);
229 define_event_symbols(event, ev_name, args->int_array.count); 229 define_event_symbols(event, ev_name, args->int_array.count);
230 define_event_symbols(event, ev_name, args->int_array.el_size); 230 define_event_symbols(event, ev_name, args->int_array.el_size);
231 break; 231 break;
232 case PRINT_BSTRING: 232 case TEP_PRINT_BSTRING:
233 case PRINT_DYNAMIC_ARRAY: 233 case TEP_PRINT_DYNAMIC_ARRAY:
234 case PRINT_DYNAMIC_ARRAY_LEN: 234 case TEP_PRINT_DYNAMIC_ARRAY_LEN:
235 case PRINT_STRING: 235 case TEP_PRINT_STRING:
236 case PRINT_BITMASK: 236 case TEP_PRINT_BITMASK:
237 break; 237 break;
238 case PRINT_TYPE: 238 case TEP_PRINT_TYPE:
239 define_event_symbols(event, ev_name, args->typecast.item); 239 define_event_symbols(event, ev_name, args->typecast.item);
240 break; 240 break;
241 case PRINT_OP: 241 case TEP_PRINT_OP:
242 if (strcmp(args->op.op, ":") == 0) 242 if (strcmp(args->op.op, ":") == 0)
243 zero_flag_atom = 1; 243 zero_flag_atom = 1;
244 define_event_symbols(event, ev_name, args->op.left); 244 define_event_symbols(event, ev_name, args->op.left);
245 define_event_symbols(event, ev_name, args->op.right); 245 define_event_symbols(event, ev_name, args->op.right);
246 break; 246 break;
247 case PRINT_FUNC: 247 case TEP_PRINT_FUNC:
248 default: 248 default:
249 pr_err("Unsupported print arg type\n"); 249 pr_err("Unsupported print arg type\n");
250 /* we should warn... */ 250 /* we should warn... */
@@ -338,8 +338,8 @@ static void perl_process_tracepoint(struct perf_sample *sample,
338 struct addr_location *al) 338 struct addr_location *al)
339{ 339{
340 struct thread *thread = al->thread; 340 struct thread *thread = al->thread;
341 struct event_format *event = evsel->tp_format; 341 struct tep_event_format *event = evsel->tp_format;
342 struct format_field *field; 342 struct tep_format_field *field;
343 static char handler[256]; 343 static char handler[256];
344 unsigned long long val; 344 unsigned long long val;
345 unsigned long s, ns; 345 unsigned long s, ns;
@@ -388,9 +388,9 @@ static void perl_process_tracepoint(struct perf_sample *sample,
388 /* common fields other than pid can be accessed via xsub fns */ 388 /* common fields other than pid can be accessed via xsub fns */
389 389
390 for (field = event->format.fields; field; field = field->next) { 390 for (field = event->format.fields; field; field = field->next) {
391 if (field->flags & FIELD_IS_STRING) { 391 if (field->flags & TEP_FIELD_IS_STRING) {
392 int offset; 392 int offset;
393 if (field->flags & FIELD_IS_DYNAMIC) { 393 if (field->flags & TEP_FIELD_IS_DYNAMIC) {
394 offset = *(int *)(data + field->offset); 394 offset = *(int *)(data + field->offset);
395 offset &= 0xffff; 395 offset &= 0xffff;
396 } else 396 } else
@@ -399,7 +399,7 @@ static void perl_process_tracepoint(struct perf_sample *sample,
399 } else { /* FIELD_IS_NUMERIC */ 399 } else { /* FIELD_IS_NUMERIC */
400 val = read_size(event, data + field->offset, 400 val = read_size(event, data + field->offset,
401 field->size); 401 field->size);
402 if (field->flags & FIELD_IS_SIGNED) { 402 if (field->flags & TEP_FIELD_IS_SIGNED) {
403 XPUSHs(sv_2mortal(newSViv(val))); 403 XPUSHs(sv_2mortal(newSViv(val)));
404 } else { 404 } else {
405 XPUSHs(sv_2mortal(newSVuv(val))); 405 XPUSHs(sv_2mortal(newSVuv(val)));
@@ -537,8 +537,8 @@ static int perl_stop_script(void)
537 537
538static int perl_generate_script(struct tep_handle *pevent, const char *outfile) 538static int perl_generate_script(struct tep_handle *pevent, const char *outfile)
539{ 539{
540 struct event_format *event = NULL; 540 struct tep_event_format *event = NULL;
541 struct format_field *f; 541 struct tep_format_field *f;
542 char fname[PATH_MAX]; 542 char fname[PATH_MAX];
543 int not_first, count; 543 int not_first, count;
544 FILE *ofp; 544 FILE *ofp;
@@ -646,11 +646,11 @@ sub print_backtrace\n\
646 count++; 646 count++;
647 647
648 fprintf(ofp, "%s=", f->name); 648 fprintf(ofp, "%s=", f->name);
649 if (f->flags & FIELD_IS_STRING || 649 if (f->flags & TEP_FIELD_IS_STRING ||
650 f->flags & FIELD_IS_FLAG || 650 f->flags & TEP_FIELD_IS_FLAG ||
651 f->flags & FIELD_IS_SYMBOLIC) 651 f->flags & TEP_FIELD_IS_SYMBOLIC)
652 fprintf(ofp, "%%s"); 652 fprintf(ofp, "%%s");
653 else if (f->flags & FIELD_IS_SIGNED) 653 else if (f->flags & TEP_FIELD_IS_SIGNED)
654 fprintf(ofp, "%%d"); 654 fprintf(ofp, "%%d");
655 else 655 else
656 fprintf(ofp, "%%u"); 656 fprintf(ofp, "%%u");
@@ -668,7 +668,7 @@ sub print_backtrace\n\
668 if (++count % 5 == 0) 668 if (++count % 5 == 0)
669 fprintf(ofp, "\n\t "); 669 fprintf(ofp, "\n\t ");
670 670
671 if (f->flags & FIELD_IS_FLAG) { 671 if (f->flags & TEP_FIELD_IS_FLAG) {
672 if ((count - 1) % 5 != 0) { 672 if ((count - 1) % 5 != 0) {
673 fprintf(ofp, "\n\t "); 673 fprintf(ofp, "\n\t ");
674 count = 4; 674 count = 4;
@@ -678,7 +678,7 @@ sub print_backtrace\n\
678 event->name); 678 event->name);
679 fprintf(ofp, "\"%s\", $%s)", f->name, 679 fprintf(ofp, "\"%s\", $%s)", f->name,
680 f->name); 680 f->name);
681 } else if (f->flags & FIELD_IS_SYMBOLIC) { 681 } else if (f->flags & TEP_FIELD_IS_SYMBOLIC) {
682 if ((count - 1) % 5 != 0) { 682 if ((count - 1) % 5 != 0) {
683 fprintf(ofp, "\n\t "); 683 fprintf(ofp, "\n\t ");
684 count = 4; 684 count = 4;
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index dfc6093f118c..69aa93d4ee99 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -193,7 +193,7 @@ static void try_call_object(const char *handler_name, PyObject *args)
193 call_object(handler, args, handler_name); 193 call_object(handler, args, handler_name);
194} 194}
195 195
196static void define_value(enum print_arg_type field_type, 196static void define_value(enum tep_print_arg_type field_type,
197 const char *ev_name, 197 const char *ev_name,
198 const char *field_name, 198 const char *field_name,
199 const char *field_value, 199 const char *field_value,
@@ -204,7 +204,7 @@ static void define_value(enum print_arg_type field_type,
204 unsigned long long value; 204 unsigned long long value;
205 unsigned n = 0; 205 unsigned n = 0;
206 206
207 if (field_type == PRINT_SYMBOL) 207 if (field_type == TEP_PRINT_SYMBOL)
208 handler_name = "define_symbolic_value"; 208 handler_name = "define_symbolic_value";
209 209
210 t = PyTuple_New(4); 210 t = PyTuple_New(4);
@@ -223,8 +223,8 @@ static void define_value(enum print_arg_type field_type,
223 Py_DECREF(t); 223 Py_DECREF(t);
224} 224}
225 225
226static void define_values(enum print_arg_type field_type, 226static void define_values(enum tep_print_arg_type field_type,
227 struct print_flag_sym *field, 227 struct tep_print_flag_sym *field,
228 const char *ev_name, 228 const char *ev_name,
229 const char *field_name) 229 const char *field_name)
230{ 230{
@@ -235,7 +235,7 @@ static void define_values(enum print_arg_type field_type,
235 define_values(field_type, field->next, ev_name, field_name); 235 define_values(field_type, field->next, ev_name, field_name);
236} 236}
237 237
238static void define_field(enum print_arg_type field_type, 238static void define_field(enum tep_print_arg_type field_type,
239 const char *ev_name, 239 const char *ev_name,
240 const char *field_name, 240 const char *field_name,
241 const char *delim) 241 const char *delim)
@@ -244,10 +244,10 @@ static void define_field(enum print_arg_type field_type,
244 PyObject *t; 244 PyObject *t;
245 unsigned n = 0; 245 unsigned n = 0;
246 246
247 if (field_type == PRINT_SYMBOL) 247 if (field_type == TEP_PRINT_SYMBOL)
248 handler_name = "define_symbolic_field"; 248 handler_name = "define_symbolic_field";
249 249
250 if (field_type == PRINT_FLAGS) 250 if (field_type == TEP_PRINT_FLAGS)
251 t = PyTuple_New(3); 251 t = PyTuple_New(3);
252 else 252 else
253 t = PyTuple_New(2); 253 t = PyTuple_New(2);
@@ -256,7 +256,7 @@ static void define_field(enum print_arg_type field_type,
256 256
257 PyTuple_SetItem(t, n++, _PyUnicode_FromString(ev_name)); 257 PyTuple_SetItem(t, n++, _PyUnicode_FromString(ev_name));
258 PyTuple_SetItem(t, n++, _PyUnicode_FromString(field_name)); 258 PyTuple_SetItem(t, n++, _PyUnicode_FromString(field_name));
259 if (field_type == PRINT_FLAGS) 259 if (field_type == TEP_PRINT_FLAGS)
260 PyTuple_SetItem(t, n++, _PyUnicode_FromString(delim)); 260 PyTuple_SetItem(t, n++, _PyUnicode_FromString(delim));
261 261
262 try_call_object(handler_name, t); 262 try_call_object(handler_name, t);
@@ -264,54 +264,54 @@ static void define_field(enum print_arg_type field_type,
264 Py_DECREF(t); 264 Py_DECREF(t);
265} 265}
266 266
267static void define_event_symbols(struct event_format *event, 267static void define_event_symbols(struct tep_event_format *event,
268 const char *ev_name, 268 const char *ev_name,
269 struct print_arg *args) 269 struct tep_print_arg *args)
270{ 270{
271 if (args == NULL) 271 if (args == NULL)
272 return; 272 return;
273 273
274 switch (args->type) { 274 switch (args->type) {
275 case PRINT_NULL: 275 case TEP_PRINT_NULL:
276 break; 276 break;
277 case PRINT_ATOM: 277 case TEP_PRINT_ATOM:
278 define_value(PRINT_FLAGS, ev_name, cur_field_name, "0", 278 define_value(TEP_PRINT_FLAGS, ev_name, cur_field_name, "0",
279 args->atom.atom); 279 args->atom.atom);
280 zero_flag_atom = 0; 280 zero_flag_atom = 0;
281 break; 281 break;
282 case PRINT_FIELD: 282 case TEP_PRINT_FIELD:
283 free(cur_field_name); 283 free(cur_field_name);
284 cur_field_name = strdup(args->field.name); 284 cur_field_name = strdup(args->field.name);
285 break; 285 break;
286 case PRINT_FLAGS: 286 case TEP_PRINT_FLAGS:
287 define_event_symbols(event, ev_name, args->flags.field); 287 define_event_symbols(event, ev_name, args->flags.field);
288 define_field(PRINT_FLAGS, ev_name, cur_field_name, 288 define_field(TEP_PRINT_FLAGS, ev_name, cur_field_name,
289 args->flags.delim); 289 args->flags.delim);
290 define_values(PRINT_FLAGS, args->flags.flags, ev_name, 290 define_values(TEP_PRINT_FLAGS, args->flags.flags, ev_name,
291 cur_field_name); 291 cur_field_name);
292 break; 292 break;
293 case PRINT_SYMBOL: 293 case TEP_PRINT_SYMBOL:
294 define_event_symbols(event, ev_name, args->symbol.field); 294 define_event_symbols(event, ev_name, args->symbol.field);
295 define_field(PRINT_SYMBOL, ev_name, cur_field_name, NULL); 295 define_field(TEP_PRINT_SYMBOL, ev_name, cur_field_name, NULL);
296 define_values(PRINT_SYMBOL, args->symbol.symbols, ev_name, 296 define_values(TEP_PRINT_SYMBOL, args->symbol.symbols, ev_name,
297 cur_field_name); 297 cur_field_name);
298 break; 298 break;
299 case PRINT_HEX: 299 case TEP_PRINT_HEX:
300 case PRINT_HEX_STR: 300 case TEP_PRINT_HEX_STR:
301 define_event_symbols(event, ev_name, args->hex.field); 301 define_event_symbols(event, ev_name, args->hex.field);
302 define_event_symbols(event, ev_name, args->hex.size); 302 define_event_symbols(event, ev_name, args->hex.size);
303 break; 303 break;
304 case PRINT_INT_ARRAY: 304 case TEP_PRINT_INT_ARRAY:
305 define_event_symbols(event, ev_name, args->int_array.field); 305 define_event_symbols(event, ev_name, args->int_array.field);
306 define_event_symbols(event, ev_name, args->int_array.count); 306 define_event_symbols(event, ev_name, args->int_array.count);
307 define_event_symbols(event, ev_name, args->int_array.el_size); 307 define_event_symbols(event, ev_name, args->int_array.el_size);
308 break; 308 break;
309 case PRINT_STRING: 309 case TEP_PRINT_STRING:
310 break; 310 break;
311 case PRINT_TYPE: 311 case TEP_PRINT_TYPE:
312 define_event_symbols(event, ev_name, args->typecast.item); 312 define_event_symbols(event, ev_name, args->typecast.item);
313 break; 313 break;
314 case PRINT_OP: 314 case TEP_PRINT_OP:
315 if (strcmp(args->op.op, ":") == 0) 315 if (strcmp(args->op.op, ":") == 0)
316 zero_flag_atom = 1; 316 zero_flag_atom = 1;
317 define_event_symbols(event, ev_name, args->op.left); 317 define_event_symbols(event, ev_name, args->op.left);
@@ -319,11 +319,11 @@ static void define_event_symbols(struct event_format *event,
319 break; 319 break;
320 default: 320 default:
321 /* gcc warns for these? */ 321 /* gcc warns for these? */
322 case PRINT_BSTRING: 322 case TEP_PRINT_BSTRING:
323 case PRINT_DYNAMIC_ARRAY: 323 case TEP_PRINT_DYNAMIC_ARRAY:
324 case PRINT_DYNAMIC_ARRAY_LEN: 324 case TEP_PRINT_DYNAMIC_ARRAY_LEN:
325 case PRINT_FUNC: 325 case TEP_PRINT_FUNC:
326 case PRINT_BITMASK: 326 case TEP_PRINT_BITMASK:
327 /* we should warn... */ 327 /* we should warn... */
328 return; 328 return;
329 } 329 }
@@ -332,10 +332,10 @@ static void define_event_symbols(struct event_format *event,
332 define_event_symbols(event, ev_name, args->next); 332 define_event_symbols(event, ev_name, args->next);
333} 333}
334 334
335static PyObject *get_field_numeric_entry(struct event_format *event, 335static PyObject *get_field_numeric_entry(struct tep_event_format *event,
336 struct format_field *field, void *data) 336 struct tep_format_field *field, void *data)
337{ 337{
338 bool is_array = field->flags & FIELD_IS_ARRAY; 338 bool is_array = field->flags & TEP_FIELD_IS_ARRAY;
339 PyObject *obj = NULL, *list = NULL; 339 PyObject *obj = NULL, *list = NULL;
340 unsigned long long val; 340 unsigned long long val;
341 unsigned int item_size, n_items, i; 341 unsigned int item_size, n_items, i;
@@ -353,7 +353,7 @@ static PyObject *get_field_numeric_entry(struct event_format *event,
353 353
354 val = read_size(event, data + field->offset + i * item_size, 354 val = read_size(event, data + field->offset + i * item_size,
355 item_size); 355 item_size);
356 if (field->flags & FIELD_IS_SIGNED) { 356 if (field->flags & TEP_FIELD_IS_SIGNED) {
357 if ((long long)val >= LONG_MIN && 357 if ((long long)val >= LONG_MIN &&
358 (long long)val <= LONG_MAX) 358 (long long)val <= LONG_MAX)
359 obj = _PyLong_FromLong(val); 359 obj = _PyLong_FromLong(val);
@@ -790,11 +790,11 @@ static void python_process_tracepoint(struct perf_sample *sample,
790 struct perf_evsel *evsel, 790 struct perf_evsel *evsel,
791 struct addr_location *al) 791 struct addr_location *al)
792{ 792{
793 struct event_format *event = evsel->tp_format; 793 struct tep_event_format *event = evsel->tp_format;
794 PyObject *handler, *context, *t, *obj = NULL, *callchain; 794 PyObject *handler, *context, *t, *obj = NULL, *callchain;
795 PyObject *dict = NULL, *all_entries_dict = NULL; 795 PyObject *dict = NULL, *all_entries_dict = NULL;
796 static char handler_name[256]; 796 static char handler_name[256];
797 struct format_field *field; 797 struct tep_format_field *field;
798 unsigned long s, ns; 798 unsigned long s, ns;
799 unsigned n = 0; 799 unsigned n = 0;
800 int pid; 800 int pid;
@@ -867,22 +867,22 @@ static void python_process_tracepoint(struct perf_sample *sample,
867 unsigned int offset, len; 867 unsigned int offset, len;
868 unsigned long long val; 868 unsigned long long val;
869 869
870 if (field->flags & FIELD_IS_ARRAY) { 870 if (field->flags & TEP_FIELD_IS_ARRAY) {
871 offset = field->offset; 871 offset = field->offset;
872 len = field->size; 872 len = field->size;
873 if (field->flags & FIELD_IS_DYNAMIC) { 873 if (field->flags & TEP_FIELD_IS_DYNAMIC) {
874 val = tep_read_number(scripting_context->pevent, 874 val = tep_read_number(scripting_context->pevent,
875 data + offset, len); 875 data + offset, len);
876 offset = val; 876 offset = val;
877 len = offset >> 16; 877 len = offset >> 16;
878 offset &= 0xffff; 878 offset &= 0xffff;
879 } 879 }
880 if (field->flags & FIELD_IS_STRING && 880 if (field->flags & TEP_FIELD_IS_STRING &&
881 is_printable_array(data + offset, len)) { 881 is_printable_array(data + offset, len)) {
882 obj = _PyUnicode_FromString((char *) data + offset); 882 obj = _PyUnicode_FromString((char *) data + offset);
883 } else { 883 } else {
884 obj = PyByteArray_FromStringAndSize((const char *) data + offset, len); 884 obj = PyByteArray_FromStringAndSize((const char *) data + offset, len);
885 field->flags &= ~FIELD_IS_STRING; 885 field->flags &= ~TEP_FIELD_IS_STRING;
886 } 886 }
887 } else { /* FIELD_IS_NUMERIC */ 887 } else { /* FIELD_IS_NUMERIC */
888 obj = get_field_numeric_entry(event, field, data); 888 obj = get_field_numeric_entry(event, field, data);
@@ -1590,8 +1590,8 @@ static int python_stop_script(void)
1590 1590
1591static int python_generate_script(struct tep_handle *pevent, const char *outfile) 1591static int python_generate_script(struct tep_handle *pevent, const char *outfile)
1592{ 1592{
1593 struct event_format *event = NULL; 1593 struct tep_event_format *event = NULL;
1594 struct format_field *f; 1594 struct tep_format_field *f;
1595 char fname[PATH_MAX]; 1595 char fname[PATH_MAX];
1596 int not_first, count; 1596 int not_first, count;
1597 FILE *ofp; 1597 FILE *ofp;
@@ -1686,12 +1686,12 @@ static int python_generate_script(struct tep_handle *pevent, const char *outfile
1686 count++; 1686 count++;
1687 1687
1688 fprintf(ofp, "%s=", f->name); 1688 fprintf(ofp, "%s=", f->name);
1689 if (f->flags & FIELD_IS_STRING || 1689 if (f->flags & TEP_FIELD_IS_STRING ||
1690 f->flags & FIELD_IS_FLAG || 1690 f->flags & TEP_FIELD_IS_FLAG ||
1691 f->flags & FIELD_IS_ARRAY || 1691 f->flags & TEP_FIELD_IS_ARRAY ||
1692 f->flags & FIELD_IS_SYMBOLIC) 1692 f->flags & TEP_FIELD_IS_SYMBOLIC)
1693 fprintf(ofp, "%%s"); 1693 fprintf(ofp, "%%s");
1694 else if (f->flags & FIELD_IS_SIGNED) 1694 else if (f->flags & TEP_FIELD_IS_SIGNED)
1695 fprintf(ofp, "%%d"); 1695 fprintf(ofp, "%%d");
1696 else 1696 else
1697 fprintf(ofp, "%%u"); 1697 fprintf(ofp, "%%u");
@@ -1709,7 +1709,7 @@ static int python_generate_script(struct tep_handle *pevent, const char *outfile
1709 if (++count % 5 == 0) 1709 if (++count % 5 == 0)
1710 fprintf(ofp, "\n\t\t"); 1710 fprintf(ofp, "\n\t\t");
1711 1711
1712 if (f->flags & FIELD_IS_FLAG) { 1712 if (f->flags & TEP_FIELD_IS_FLAG) {
1713 if ((count - 1) % 5 != 0) { 1713 if ((count - 1) % 5 != 0) {
1714 fprintf(ofp, "\n\t\t"); 1714 fprintf(ofp, "\n\t\t");
1715 count = 4; 1715 count = 4;
@@ -1719,7 +1719,7 @@ static int python_generate_script(struct tep_handle *pevent, const char *outfile
1719 event->name); 1719 event->name);
1720 fprintf(ofp, "\"%s\", %s)", f->name, 1720 fprintf(ofp, "\"%s\", %s)", f->name,
1721 f->name); 1721 f->name);
1722 } else if (f->flags & FIELD_IS_SYMBOLIC) { 1722 } else if (f->flags & TEP_FIELD_IS_SYMBOLIC) {
1723 if ((count - 1) % 5 != 0) { 1723 if ((count - 1) % 5 != 0) {
1724 fprintf(ofp, "\n\t\t"); 1724 fprintf(ofp, "\n\t\t");
1725 count = 4; 1725 count = 4;
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 8b9369303561..7d2c8ce6cfad 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -199,12 +199,10 @@ void perf_session__delete(struct perf_session *session)
199 free(session); 199 free(session);
200} 200}
201 201
202static int process_event_synth_tracing_data_stub(struct perf_tool *tool 202static int process_event_synth_tracing_data_stub(struct perf_session *session
203 __maybe_unused, 203 __maybe_unused,
204 union perf_event *event 204 union perf_event *event
205 __maybe_unused, 205 __maybe_unused)
206 struct perf_session *session
207 __maybe_unused)
208{ 206{
209 dump_printf(": unhandled!\n"); 207 dump_printf(": unhandled!\n");
210 return 0; 208 return 0;
@@ -277,10 +275,8 @@ static int skipn(int fd, off_t n)
277 return 0; 275 return 0;
278} 276}
279 277
280static s64 process_event_auxtrace_stub(struct perf_tool *tool __maybe_unused, 278static s64 process_event_auxtrace_stub(struct perf_session *session __maybe_unused,
281 union perf_event *event, 279 union perf_event *event)
282 struct perf_session *session
283 __maybe_unused)
284{ 280{
285 dump_printf(": unhandled!\n"); 281 dump_printf(": unhandled!\n");
286 if (perf_data__is_pipe(session->data)) 282 if (perf_data__is_pipe(session->data))
@@ -288,9 +284,8 @@ static s64 process_event_auxtrace_stub(struct perf_tool *tool __maybe_unused,
288 return event->auxtrace.size; 284 return event->auxtrace.size;
289} 285}
290 286
291static int process_event_op2_stub(struct perf_tool *tool __maybe_unused, 287static int process_event_op2_stub(struct perf_session *session __maybe_unused,
292 union perf_event *event __maybe_unused, 288 union perf_event *event __maybe_unused)
293 struct perf_session *session __maybe_unused)
294{ 289{
295 dump_printf(": unhandled!\n"); 290 dump_printf(": unhandled!\n");
296 return 0; 291 return 0;
@@ -298,9 +293,8 @@ static int process_event_op2_stub(struct perf_tool *tool __maybe_unused,
298 293
299 294
300static 295static
301int process_event_thread_map_stub(struct perf_tool *tool __maybe_unused, 296int process_event_thread_map_stub(struct perf_session *session __maybe_unused,
302 union perf_event *event __maybe_unused, 297 union perf_event *event __maybe_unused)
303 struct perf_session *session __maybe_unused)
304{ 298{
305 if (dump_trace) 299 if (dump_trace)
306 perf_event__fprintf_thread_map(event, stdout); 300 perf_event__fprintf_thread_map(event, stdout);
@@ -310,9 +304,8 @@ int process_event_thread_map_stub(struct perf_tool *tool __maybe_unused,
310} 304}
311 305
312static 306static
313int process_event_cpu_map_stub(struct perf_tool *tool __maybe_unused, 307int process_event_cpu_map_stub(struct perf_session *session __maybe_unused,
314 union perf_event *event __maybe_unused, 308 union perf_event *event __maybe_unused)
315 struct perf_session *session __maybe_unused)
316{ 309{
317 if (dump_trace) 310 if (dump_trace)
318 perf_event__fprintf_cpu_map(event, stdout); 311 perf_event__fprintf_cpu_map(event, stdout);
@@ -322,9 +315,8 @@ int process_event_cpu_map_stub(struct perf_tool *tool __maybe_unused,
322} 315}
323 316
324static 317static
325int process_event_stat_config_stub(struct perf_tool *tool __maybe_unused, 318int process_event_stat_config_stub(struct perf_session *session __maybe_unused,
326 union perf_event *event __maybe_unused, 319 union perf_event *event __maybe_unused)
327 struct perf_session *session __maybe_unused)
328{ 320{
329 if (dump_trace) 321 if (dump_trace)
330 perf_event__fprintf_stat_config(event, stdout); 322 perf_event__fprintf_stat_config(event, stdout);
@@ -333,10 +325,8 @@ int process_event_stat_config_stub(struct perf_tool *tool __maybe_unused,
333 return 0; 325 return 0;
334} 326}
335 327
336static int process_stat_stub(struct perf_tool *tool __maybe_unused, 328static int process_stat_stub(struct perf_session *perf_session __maybe_unused,
337 union perf_event *event __maybe_unused, 329 union perf_event *event)
338 struct perf_session *perf_session
339 __maybe_unused)
340{ 330{
341 if (dump_trace) 331 if (dump_trace)
342 perf_event__fprintf_stat(event, stdout); 332 perf_event__fprintf_stat(event, stdout);
@@ -345,10 +335,8 @@ static int process_stat_stub(struct perf_tool *tool __maybe_unused,
345 return 0; 335 return 0;
346} 336}
347 337
348static int process_stat_round_stub(struct perf_tool *tool __maybe_unused, 338static int process_stat_round_stub(struct perf_session *perf_session __maybe_unused,
349 union perf_event *event __maybe_unused, 339 union perf_event *event)
350 struct perf_session *perf_session
351 __maybe_unused)
352{ 340{
353 if (dump_trace) 341 if (dump_trace)
354 perf_event__fprintf_stat_round(event, stdout); 342 perf_event__fprintf_stat_round(event, stdout);
@@ -1374,37 +1362,37 @@ static s64 perf_session__process_user_event(struct perf_session *session,
1374 case PERF_RECORD_HEADER_TRACING_DATA: 1362 case PERF_RECORD_HEADER_TRACING_DATA:
1375 /* setup for reading amidst mmap */ 1363 /* setup for reading amidst mmap */
1376 lseek(fd, file_offset, SEEK_SET); 1364 lseek(fd, file_offset, SEEK_SET);
1377 return tool->tracing_data(tool, event, session); 1365 return tool->tracing_data(session, event);
1378 case PERF_RECORD_HEADER_BUILD_ID: 1366 case PERF_RECORD_HEADER_BUILD_ID:
1379 return tool->build_id(tool, event, session); 1367 return tool->build_id(session, event);
1380 case PERF_RECORD_FINISHED_ROUND: 1368 case PERF_RECORD_FINISHED_ROUND:
1381 return tool->finished_round(tool, event, oe); 1369 return tool->finished_round(tool, event, oe);
1382 case PERF_RECORD_ID_INDEX: 1370 case PERF_RECORD_ID_INDEX:
1383 return tool->id_index(tool, event, session); 1371 return tool->id_index(session, event);
1384 case PERF_RECORD_AUXTRACE_INFO: 1372 case PERF_RECORD_AUXTRACE_INFO:
1385 return tool->auxtrace_info(tool, event, session); 1373 return tool->auxtrace_info(session, event);
1386 case PERF_RECORD_AUXTRACE: 1374 case PERF_RECORD_AUXTRACE:
1387 /* setup for reading amidst mmap */ 1375 /* setup for reading amidst mmap */
1388 lseek(fd, file_offset + event->header.size, SEEK_SET); 1376 lseek(fd, file_offset + event->header.size, SEEK_SET);
1389 return tool->auxtrace(tool, event, session); 1377 return tool->auxtrace(session, event);
1390 case PERF_RECORD_AUXTRACE_ERROR: 1378 case PERF_RECORD_AUXTRACE_ERROR:
1391 perf_session__auxtrace_error_inc(session, event); 1379 perf_session__auxtrace_error_inc(session, event);
1392 return tool->auxtrace_error(tool, event, session); 1380 return tool->auxtrace_error(session, event);
1393 case PERF_RECORD_THREAD_MAP: 1381 case PERF_RECORD_THREAD_MAP:
1394 return tool->thread_map(tool, event, session); 1382 return tool->thread_map(session, event);
1395 case PERF_RECORD_CPU_MAP: 1383 case PERF_RECORD_CPU_MAP:
1396 return tool->cpu_map(tool, event, session); 1384 return tool->cpu_map(session, event);
1397 case PERF_RECORD_STAT_CONFIG: 1385 case PERF_RECORD_STAT_CONFIG:
1398 return tool->stat_config(tool, event, session); 1386 return tool->stat_config(session, event);
1399 case PERF_RECORD_STAT: 1387 case PERF_RECORD_STAT:
1400 return tool->stat(tool, event, session); 1388 return tool->stat(session, event);
1401 case PERF_RECORD_STAT_ROUND: 1389 case PERF_RECORD_STAT_ROUND:
1402 return tool->stat_round(tool, event, session); 1390 return tool->stat_round(session, event);
1403 case PERF_RECORD_TIME_CONV: 1391 case PERF_RECORD_TIME_CONV:
1404 session->time_conv = event->time_conv; 1392 session->time_conv = event->time_conv;
1405 return tool->time_conv(tool, event, session); 1393 return tool->time_conv(session, event);
1406 case PERF_RECORD_HEADER_FEATURE: 1394 case PERF_RECORD_HEADER_FEATURE:
1407 return tool->feature(tool, event, session); 1395 return tool->feature(session, event);
1408 default: 1396 default:
1409 return -EINVAL; 1397 return -EINVAL;
1410 } 1398 }
@@ -2133,9 +2121,8 @@ out:
2133 return err; 2121 return err;
2134} 2122}
2135 2123
2136int perf_event__process_id_index(struct perf_tool *tool __maybe_unused, 2124int perf_event__process_id_index(struct perf_session *session,
2137 union perf_event *event, 2125 union perf_event *event)
2138 struct perf_session *session)
2139{ 2126{
2140 struct perf_evlist *evlist = session->evlist; 2127 struct perf_evlist *evlist = session->evlist;
2141 struct id_index_event *ie = &event->id_index; 2128 struct id_index_event *ie = &event->id_index;
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index da40b4b380ca..d96eccd7d27f 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -120,9 +120,8 @@ int perf_session__deliver_synth_event(struct perf_session *session,
120 union perf_event *event, 120 union perf_event *event,
121 struct perf_sample *sample); 121 struct perf_sample *sample);
122 122
123int perf_event__process_id_index(struct perf_tool *tool, 123int perf_event__process_id_index(struct perf_session *session,
124 union perf_event *event, 124 union perf_event *event);
125 struct perf_session *session);
126 125
127int perf_event__synthesize_id_index(struct perf_tool *tool, 126int perf_event__synthesize_id_index(struct perf_tool *tool,
128 perf_event__handler_t process, 127 perf_event__handler_t process,
diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py
index 97efbcad076e..63f758c655d5 100644
--- a/tools/perf/util/setup.py
+++ b/tools/perf/util/setup.py
@@ -5,16 +5,18 @@ from subprocess import Popen, PIPE
5from re import sub 5from re import sub
6 6
7def clang_has_option(option): 7def clang_has_option(option):
8 return [o for o in Popen(['clang', option], stderr=PIPE).stderr.readlines() if "unknown argument" in o] == [ ] 8 return [o for o in Popen(['clang', option], stderr=PIPE).stderr.readlines() if b"unknown argument" in o] == [ ]
9 9
10cc = getenv("CC") 10cc = getenv("CC")
11if cc == "clang": 11if cc == "clang":
12 from _sysconfigdata import build_time_vars 12 from distutils.sysconfig import get_config_vars
13 build_time_vars["CFLAGS"] = sub("-specs=[^ ]+", "", build_time_vars["CFLAGS"]) 13 vars = get_config_vars()
14 if not clang_has_option("-mcet"): 14 for var in ('CFLAGS', 'OPT'):
15 build_time_vars["CFLAGS"] = sub("-mcet", "", build_time_vars["CFLAGS"]) 15 vars[var] = sub("-specs=[^ ]+", "", vars[var])
16 if not clang_has_option("-fcf-protection"): 16 if not clang_has_option("-mcet"):
17 build_time_vars["CFLAGS"] = sub("-fcf-protection", "", build_time_vars["CFLAGS"]) 17 vars[var] = sub("-mcet", "", vars[var])
18 if not clang_has_option("-fcf-protection"):
19 vars[var] = sub("-fcf-protection", "", vars[var])
18 20
19from distutils.core import setup, Extension 21from distutils.core import setup, Extension
20 22
@@ -35,7 +37,7 @@ class install_lib(_install_lib):
35 37
36cflags = getenv('CFLAGS', '').split() 38cflags = getenv('CFLAGS', '').split()
37# switch off several checks (need to be at the end of cflags list) 39# switch off several checks (need to be at the end of cflags list)
38cflags += ['-fno-strict-aliasing', '-Wno-write-strings', '-Wno-unused-parameter' ] 40cflags += ['-fno-strict-aliasing', '-Wno-write-strings', '-Wno-unused-parameter', '-Wno-redundant-decls' ]
39if cc != "clang": 41if cc != "clang":
40 cflags += ['-Wno-cast-function-type' ] 42 cflags += ['-Wno-cast-function-type' ]
41 43
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index b284276ec963..f96c005b3c41 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -1884,7 +1884,7 @@ static int __sort_dimension__add_hpp_output(struct sort_dimension *sd,
1884struct hpp_dynamic_entry { 1884struct hpp_dynamic_entry {
1885 struct perf_hpp_fmt hpp; 1885 struct perf_hpp_fmt hpp;
1886 struct perf_evsel *evsel; 1886 struct perf_evsel *evsel;
1887 struct format_field *field; 1887 struct tep_format_field *field;
1888 unsigned dynamic_len; 1888 unsigned dynamic_len;
1889 bool raw_trace; 1889 bool raw_trace;
1890}; 1890};
@@ -1899,7 +1899,7 @@ static int hde_width(struct hpp_dynamic_entry *hde)
1899 if (namelen > len) 1899 if (namelen > len)
1900 len = namelen; 1900 len = namelen;
1901 1901
1902 if (!(hde->field->flags & FIELD_IS_STRING)) { 1902 if (!(hde->field->flags & TEP_FIELD_IS_STRING)) {
1903 /* length for print hex numbers */ 1903 /* length for print hex numbers */
1904 fieldlen = hde->field->size * 2 + 2; 1904 fieldlen = hde->field->size * 2 + 2;
1905 } 1905 }
@@ -1915,7 +1915,7 @@ static void update_dynamic_len(struct hpp_dynamic_entry *hde,
1915 struct hist_entry *he) 1915 struct hist_entry *he)
1916{ 1916{
1917 char *str, *pos; 1917 char *str, *pos;
1918 struct format_field *field = hde->field; 1918 struct tep_format_field *field = hde->field;
1919 size_t namelen; 1919 size_t namelen;
1920 bool last = false; 1920 bool last = false;
1921 1921
@@ -2000,7 +2000,7 @@ static int __sort__hde_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
2000 struct hpp_dynamic_entry *hde; 2000 struct hpp_dynamic_entry *hde;
2001 size_t len = fmt->user_len; 2001 size_t len = fmt->user_len;
2002 char *str, *pos; 2002 char *str, *pos;
2003 struct format_field *field; 2003 struct tep_format_field *field;
2004 size_t namelen; 2004 size_t namelen;
2005 bool last = false; 2005 bool last = false;
2006 int ret; 2006 int ret;
@@ -2060,7 +2060,7 @@ static int64_t __sort__hde_cmp(struct perf_hpp_fmt *fmt,
2060 struct hist_entry *a, struct hist_entry *b) 2060 struct hist_entry *a, struct hist_entry *b)
2061{ 2061{
2062 struct hpp_dynamic_entry *hde; 2062 struct hpp_dynamic_entry *hde;
2063 struct format_field *field; 2063 struct tep_format_field *field;
2064 unsigned offset, size; 2064 unsigned offset, size;
2065 2065
2066 hde = container_of(fmt, struct hpp_dynamic_entry, hpp); 2066 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
@@ -2071,7 +2071,7 @@ static int64_t __sort__hde_cmp(struct perf_hpp_fmt *fmt,
2071 } 2071 }
2072 2072
2073 field = hde->field; 2073 field = hde->field;
2074 if (field->flags & FIELD_IS_DYNAMIC) { 2074 if (field->flags & TEP_FIELD_IS_DYNAMIC) {
2075 unsigned long long dyn; 2075 unsigned long long dyn;
2076 2076
2077 tep_read_number_field(field, a->raw_data, &dyn); 2077 tep_read_number_field(field, a->raw_data, &dyn);
@@ -2117,7 +2117,7 @@ static void hde_free(struct perf_hpp_fmt *fmt)
2117} 2117}
2118 2118
2119static struct hpp_dynamic_entry * 2119static struct hpp_dynamic_entry *
2120__alloc_dynamic_entry(struct perf_evsel *evsel, struct format_field *field, 2120__alloc_dynamic_entry(struct perf_evsel *evsel, struct tep_format_field *field,
2121 int level) 2121 int level)
2122{ 2122{
2123 struct hpp_dynamic_entry *hde; 2123 struct hpp_dynamic_entry *hde;
@@ -2252,7 +2252,7 @@ static struct perf_evsel *find_evsel(struct perf_evlist *evlist, char *event_nam
2252} 2252}
2253 2253
2254static int __dynamic_dimension__add(struct perf_evsel *evsel, 2254static int __dynamic_dimension__add(struct perf_evsel *evsel,
2255 struct format_field *field, 2255 struct tep_format_field *field,
2256 bool raw_trace, int level) 2256 bool raw_trace, int level)
2257{ 2257{
2258 struct hpp_dynamic_entry *hde; 2258 struct hpp_dynamic_entry *hde;
@@ -2270,7 +2270,7 @@ static int __dynamic_dimension__add(struct perf_evsel *evsel,
2270static int add_evsel_fields(struct perf_evsel *evsel, bool raw_trace, int level) 2270static int add_evsel_fields(struct perf_evsel *evsel, bool raw_trace, int level)
2271{ 2271{
2272 int ret; 2272 int ret;
2273 struct format_field *field; 2273 struct tep_format_field *field;
2274 2274
2275 field = evsel->tp_format->format.fields; 2275 field = evsel->tp_format->format.fields;
2276 while (field) { 2276 while (field) {
@@ -2305,7 +2305,7 @@ static int add_all_matching_fields(struct perf_evlist *evlist,
2305{ 2305{
2306 int ret = -ESRCH; 2306 int ret = -ESRCH;
2307 struct perf_evsel *evsel; 2307 struct perf_evsel *evsel;
2308 struct format_field *field; 2308 struct tep_format_field *field;
2309 2309
2310 evlist__for_each_entry(evlist, evsel) { 2310 evlist__for_each_entry(evlist, evsel) {
2311 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) 2311 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
@@ -2327,7 +2327,7 @@ static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok,
2327{ 2327{
2328 char *str, *event_name, *field_name, *opt_name; 2328 char *str, *event_name, *field_name, *opt_name;
2329 struct perf_evsel *evsel; 2329 struct perf_evsel *evsel;
2330 struct format_field *field; 2330 struct tep_format_field *field;
2331 bool raw_trace = symbol_conf.raw_trace; 2331 bool raw_trace = symbol_conf.raw_trace;
2332 int ret = 0; 2332 int ret = 0;
2333 2333
diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c
index 09d6746e6ec8..e767c4a9d4d2 100644
--- a/tools/perf/util/srcline.c
+++ b/tools/perf/util/srcline.c
@@ -85,6 +85,9 @@ static struct symbol *new_inline_sym(struct dso *dso,
85 struct symbol *inline_sym; 85 struct symbol *inline_sym;
86 char *demangled = NULL; 86 char *demangled = NULL;
87 87
88 if (!funcname)
89 funcname = "??";
90
88 if (dso) { 91 if (dso) {
89 demangled = dso__demangle_sym(dso, 0, funcname); 92 demangled = dso__demangle_sym(dso, 0, funcname);
90 if (demangled) 93 if (demangled)
diff --git a/tools/perf/util/stat-display.c b/tools/perf/util/stat-display.c
new file mode 100644
index 000000000000..e7b4c44ebb62
--- /dev/null
+++ b/tools/perf/util/stat-display.c
@@ -0,0 +1,1166 @@
1#include <stdio.h>
2#include <inttypes.h>
3#include <linux/time64.h>
4#include <math.h>
5#include "evlist.h"
6#include "evsel.h"
7#include "stat.h"
8#include "top.h"
9#include "thread_map.h"
10#include "cpumap.h"
11#include "string2.h"
12#include "sane_ctype.h"
13#include "cgroup.h"
14#include <math.h>
15#include <api/fs/fs.h>
16
17#define CNTR_NOT_SUPPORTED "<not supported>"
18#define CNTR_NOT_COUNTED "<not counted>"
19
20static bool is_duration_time(struct perf_evsel *evsel)
21{
22 return !strcmp(evsel->name, "duration_time");
23}
24
25static void print_running(struct perf_stat_config *config,
26 u64 run, u64 ena)
27{
28 if (config->csv_output) {
29 fprintf(config->output, "%s%" PRIu64 "%s%.2f",
30 config->csv_sep,
31 run,
32 config->csv_sep,
33 ena ? 100.0 * run / ena : 100.0);
34 } else if (run != ena) {
35 fprintf(config->output, " (%.2f%%)", 100.0 * run / ena);
36 }
37}
38
39static void print_noise_pct(struct perf_stat_config *config,
40 double total, double avg)
41{
42 double pct = rel_stddev_stats(total, avg);
43
44 if (config->csv_output)
45 fprintf(config->output, "%s%.2f%%", config->csv_sep, pct);
46 else if (pct)
47 fprintf(config->output, " ( +-%6.2f%% )", pct);
48}
49
50static void print_noise(struct perf_stat_config *config,
51 struct perf_evsel *evsel, double avg)
52{
53 struct perf_stat_evsel *ps;
54
55 if (config->run_count == 1)
56 return;
57
58 ps = evsel->stats;
59 print_noise_pct(config, stddev_stats(&ps->res_stats[0]), avg);
60}
61
62static void aggr_printout(struct perf_stat_config *config,
63 struct perf_evsel *evsel, int id, int nr)
64{
65 switch (config->aggr_mode) {
66 case AGGR_CORE:
67 fprintf(config->output, "S%d-C%*d%s%*d%s",
68 cpu_map__id_to_socket(id),
69 config->csv_output ? 0 : -8,
70 cpu_map__id_to_cpu(id),
71 config->csv_sep,
72 config->csv_output ? 0 : 4,
73 nr,
74 config->csv_sep);
75 break;
76 case AGGR_SOCKET:
77 fprintf(config->output, "S%*d%s%*d%s",
78 config->csv_output ? 0 : -5,
79 id,
80 config->csv_sep,
81 config->csv_output ? 0 : 4,
82 nr,
83 config->csv_sep);
84 break;
85 case AGGR_NONE:
86 fprintf(config->output, "CPU%*d%s",
87 config->csv_output ? 0 : -4,
88 perf_evsel__cpus(evsel)->map[id], config->csv_sep);
89 break;
90 case AGGR_THREAD:
91 fprintf(config->output, "%*s-%*d%s",
92 config->csv_output ? 0 : 16,
93 thread_map__comm(evsel->threads, id),
94 config->csv_output ? 0 : -8,
95 thread_map__pid(evsel->threads, id),
96 config->csv_sep);
97 break;
98 case AGGR_GLOBAL:
99 case AGGR_UNSET:
100 default:
101 break;
102 }
103}
104
105struct outstate {
106 FILE *fh;
107 bool newline;
108 const char *prefix;
109 int nfields;
110 int id, nr;
111 struct perf_evsel *evsel;
112};
113
114#define METRIC_LEN 35
115
116static void new_line_std(struct perf_stat_config *config __maybe_unused,
117 void *ctx)
118{
119 struct outstate *os = ctx;
120
121 os->newline = true;
122}
123
124static void do_new_line_std(struct perf_stat_config *config,
125 struct outstate *os)
126{
127 fputc('\n', os->fh);
128 fputs(os->prefix, os->fh);
129 aggr_printout(config, os->evsel, os->id, os->nr);
130 if (config->aggr_mode == AGGR_NONE)
131 fprintf(os->fh, " ");
132 fprintf(os->fh, " ");
133}
134
135static void print_metric_std(struct perf_stat_config *config,
136 void *ctx, const char *color, const char *fmt,
137 const char *unit, double val)
138{
139 struct outstate *os = ctx;
140 FILE *out = os->fh;
141 int n;
142 bool newline = os->newline;
143
144 os->newline = false;
145
146 if (unit == NULL || fmt == NULL) {
147 fprintf(out, "%-*s", METRIC_LEN, "");
148 return;
149 }
150
151 if (newline)
152 do_new_line_std(config, os);
153
154 n = fprintf(out, " # ");
155 if (color)
156 n += color_fprintf(out, color, fmt, val);
157 else
158 n += fprintf(out, fmt, val);
159 fprintf(out, " %-*s", METRIC_LEN - n - 1, unit);
160}
161
162static void new_line_csv(struct perf_stat_config *config, void *ctx)
163{
164 struct outstate *os = ctx;
165 int i;
166
167 fputc('\n', os->fh);
168 if (os->prefix)
169 fprintf(os->fh, "%s%s", os->prefix, config->csv_sep);
170 aggr_printout(config, os->evsel, os->id, os->nr);
171 for (i = 0; i < os->nfields; i++)
172 fputs(config->csv_sep, os->fh);
173}
174
175static void print_metric_csv(struct perf_stat_config *config __maybe_unused,
176 void *ctx,
177 const char *color __maybe_unused,
178 const char *fmt, const char *unit, double val)
179{
180 struct outstate *os = ctx;
181 FILE *out = os->fh;
182 char buf[64], *vals, *ends;
183
184 if (unit == NULL || fmt == NULL) {
185 fprintf(out, "%s%s", config->csv_sep, config->csv_sep);
186 return;
187 }
188 snprintf(buf, sizeof(buf), fmt, val);
189 ends = vals = ltrim(buf);
190 while (isdigit(*ends) || *ends == '.')
191 ends++;
192 *ends = 0;
193 while (isspace(*unit))
194 unit++;
195 fprintf(out, "%s%s%s%s", config->csv_sep, vals, config->csv_sep, unit);
196}
197
198/* Filter out some columns that don't work well in metrics only mode */
199
200static bool valid_only_metric(const char *unit)
201{
202 if (!unit)
203 return false;
204 if (strstr(unit, "/sec") ||
205 strstr(unit, "hz") ||
206 strstr(unit, "Hz") ||
207 strstr(unit, "CPUs utilized"))
208 return false;
209 return true;
210}
211
212static const char *fixunit(char *buf, struct perf_evsel *evsel,
213 const char *unit)
214{
215 if (!strncmp(unit, "of all", 6)) {
216 snprintf(buf, 1024, "%s %s", perf_evsel__name(evsel),
217 unit);
218 return buf;
219 }
220 return unit;
221}
222
223static void print_metric_only(struct perf_stat_config *config,
224 void *ctx, const char *color, const char *fmt,
225 const char *unit, double val)
226{
227 struct outstate *os = ctx;
228 FILE *out = os->fh;
229 char buf[1024], str[1024];
230 unsigned mlen = config->metric_only_len;
231
232 if (!valid_only_metric(unit))
233 return;
234 unit = fixunit(buf, os->evsel, unit);
235 if (mlen < strlen(unit))
236 mlen = strlen(unit) + 1;
237
238 if (color)
239 mlen += strlen(color) + sizeof(PERF_COLOR_RESET) - 1;
240
241 color_snprintf(str, sizeof(str), color ?: "", fmt, val);
242 fprintf(out, "%*s ", mlen, str);
243}
244
245static void print_metric_only_csv(struct perf_stat_config *config __maybe_unused,
246 void *ctx, const char *color __maybe_unused,
247 const char *fmt,
248 const char *unit, double val)
249{
250 struct outstate *os = ctx;
251 FILE *out = os->fh;
252 char buf[64], *vals, *ends;
253 char tbuf[1024];
254
255 if (!valid_only_metric(unit))
256 return;
257 unit = fixunit(tbuf, os->evsel, unit);
258 snprintf(buf, sizeof buf, fmt, val);
259 ends = vals = ltrim(buf);
260 while (isdigit(*ends) || *ends == '.')
261 ends++;
262 *ends = 0;
263 fprintf(out, "%s%s", vals, config->csv_sep);
264}
265
266static void new_line_metric(struct perf_stat_config *config __maybe_unused,
267 void *ctx __maybe_unused)
268{
269}
270
271static void print_metric_header(struct perf_stat_config *config,
272 void *ctx, const char *color __maybe_unused,
273 const char *fmt __maybe_unused,
274 const char *unit, double val __maybe_unused)
275{
276 struct outstate *os = ctx;
277 char tbuf[1024];
278
279 if (!valid_only_metric(unit))
280 return;
281 unit = fixunit(tbuf, os->evsel, unit);
282 if (config->csv_output)
283 fprintf(os->fh, "%s%s", unit, config->csv_sep);
284 else
285 fprintf(os->fh, "%*s ", config->metric_only_len, unit);
286}
287
288static int first_shadow_cpu(struct perf_stat_config *config,
289 struct perf_evsel *evsel, int id)
290{
291 struct perf_evlist *evlist = evsel->evlist;
292 int i;
293
294 if (!config->aggr_get_id)
295 return 0;
296
297 if (config->aggr_mode == AGGR_NONE)
298 return id;
299
300 if (config->aggr_mode == AGGR_GLOBAL)
301 return 0;
302
303 for (i = 0; i < perf_evsel__nr_cpus(evsel); i++) {
304 int cpu2 = perf_evsel__cpus(evsel)->map[i];
305
306 if (config->aggr_get_id(config, evlist->cpus, cpu2) == id)
307 return cpu2;
308 }
309 return 0;
310}
311
312static void abs_printout(struct perf_stat_config *config,
313 int id, int nr, struct perf_evsel *evsel, double avg)
314{
315 FILE *output = config->output;
316 double sc = evsel->scale;
317 const char *fmt;
318
319 if (config->csv_output) {
320 fmt = floor(sc) != sc ? "%.2f%s" : "%.0f%s";
321 } else {
322 if (config->big_num)
323 fmt = floor(sc) != sc ? "%'18.2f%s" : "%'18.0f%s";
324 else
325 fmt = floor(sc) != sc ? "%18.2f%s" : "%18.0f%s";
326 }
327
328 aggr_printout(config, evsel, id, nr);
329
330 fprintf(output, fmt, avg, config->csv_sep);
331
332 if (evsel->unit)
333 fprintf(output, "%-*s%s",
334 config->csv_output ? 0 : config->unit_width,
335 evsel->unit, config->csv_sep);
336
337 fprintf(output, "%-*s", config->csv_output ? 0 : 25, perf_evsel__name(evsel));
338
339 if (evsel->cgrp)
340 fprintf(output, "%s%s", config->csv_sep, evsel->cgrp->name);
341}
342
343static bool is_mixed_hw_group(struct perf_evsel *counter)
344{
345 struct perf_evlist *evlist = counter->evlist;
346 u32 pmu_type = counter->attr.type;
347 struct perf_evsel *pos;
348
349 if (counter->nr_members < 2)
350 return false;
351
352 evlist__for_each_entry(evlist, pos) {
353 /* software events can be part of any hardware group */
354 if (pos->attr.type == PERF_TYPE_SOFTWARE)
355 continue;
356 if (pmu_type == PERF_TYPE_SOFTWARE) {
357 pmu_type = pos->attr.type;
358 continue;
359 }
360 if (pmu_type != pos->attr.type)
361 return true;
362 }
363
364 return false;
365}
366
367static void printout(struct perf_stat_config *config, int id, int nr,
368 struct perf_evsel *counter, double uval,
369 char *prefix, u64 run, u64 ena, double noise,
370 struct runtime_stat *st)
371{
372 struct perf_stat_output_ctx out;
373 struct outstate os = {
374 .fh = config->output,
375 .prefix = prefix ? prefix : "",
376 .id = id,
377 .nr = nr,
378 .evsel = counter,
379 };
380 print_metric_t pm = print_metric_std;
381 new_line_t nl;
382
383 if (config->metric_only) {
384 nl = new_line_metric;
385 if (config->csv_output)
386 pm = print_metric_only_csv;
387 else
388 pm = print_metric_only;
389 } else
390 nl = new_line_std;
391
392 if (config->csv_output && !config->metric_only) {
393 static int aggr_fields[] = {
394 [AGGR_GLOBAL] = 0,
395 [AGGR_THREAD] = 1,
396 [AGGR_NONE] = 1,
397 [AGGR_SOCKET] = 2,
398 [AGGR_CORE] = 2,
399 };
400
401 pm = print_metric_csv;
402 nl = new_line_csv;
403 os.nfields = 3;
404 os.nfields += aggr_fields[config->aggr_mode];
405 if (counter->cgrp)
406 os.nfields++;
407 }
408 if (run == 0 || ena == 0 || counter->counts->scaled == -1) {
409 if (config->metric_only) {
410 pm(config, &os, NULL, "", "", 0);
411 return;
412 }
413 aggr_printout(config, counter, id, nr);
414
415 fprintf(config->output, "%*s%s",
416 config->csv_output ? 0 : 18,
417 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
418 config->csv_sep);
419
420 if (counter->supported) {
421 config->print_free_counters_hint = 1;
422 if (is_mixed_hw_group(counter))
423 config->print_mixed_hw_group_error = 1;
424 }
425
426 fprintf(config->output, "%-*s%s",
427 config->csv_output ? 0 : config->unit_width,
428 counter->unit, config->csv_sep);
429
430 fprintf(config->output, "%*s",
431 config->csv_output ? 0 : -25,
432 perf_evsel__name(counter));
433
434 if (counter->cgrp)
435 fprintf(config->output, "%s%s",
436 config->csv_sep, counter->cgrp->name);
437
438 if (!config->csv_output)
439 pm(config, &os, NULL, NULL, "", 0);
440 print_noise(config, counter, noise);
441 print_running(config, run, ena);
442 if (config->csv_output)
443 pm(config, &os, NULL, NULL, "", 0);
444 return;
445 }
446
447 if (!config->metric_only)
448 abs_printout(config, id, nr, counter, uval);
449
450 out.print_metric = pm;
451 out.new_line = nl;
452 out.ctx = &os;
453 out.force_header = false;
454
455 if (config->csv_output && !config->metric_only) {
456 print_noise(config, counter, noise);
457 print_running(config, run, ena);
458 }
459
460 perf_stat__print_shadow_stats(config, counter, uval,
461 first_shadow_cpu(config, counter, id),
462 &out, &config->metric_events, st);
463 if (!config->csv_output && !config->metric_only) {
464 print_noise(config, counter, noise);
465 print_running(config, run, ena);
466 }
467}
468
469static void aggr_update_shadow(struct perf_stat_config *config,
470 struct perf_evlist *evlist)
471{
472 int cpu, s2, id, s;
473 u64 val;
474 struct perf_evsel *counter;
475
476 for (s = 0; s < config->aggr_map->nr; s++) {
477 id = config->aggr_map->map[s];
478 evlist__for_each_entry(evlist, counter) {
479 val = 0;
480 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
481 s2 = config->aggr_get_id(config, evlist->cpus, cpu);
482 if (s2 != id)
483 continue;
484 val += perf_counts(counter->counts, cpu, 0)->val;
485 }
486 perf_stat__update_shadow_stats(counter, val,
487 first_shadow_cpu(config, counter, id),
488 &rt_stat);
489 }
490 }
491}
492
493static void uniquify_event_name(struct perf_evsel *counter)
494{
495 char *new_name;
496 char *config;
497
498 if (counter->uniquified_name ||
499 !counter->pmu_name || !strncmp(counter->name, counter->pmu_name,
500 strlen(counter->pmu_name)))
501 return;
502
503 config = strchr(counter->name, '/');
504 if (config) {
505 if (asprintf(&new_name,
506 "%s%s", counter->pmu_name, config) > 0) {
507 free(counter->name);
508 counter->name = new_name;
509 }
510 } else {
511 if (asprintf(&new_name,
512 "%s [%s]", counter->name, counter->pmu_name) > 0) {
513 free(counter->name);
514 counter->name = new_name;
515 }
516 }
517
518 counter->uniquified_name = true;
519}
520
521static void collect_all_aliases(struct perf_stat_config *config, struct perf_evsel *counter,
522 void (*cb)(struct perf_stat_config *config, struct perf_evsel *counter, void *data,
523 bool first),
524 void *data)
525{
526 struct perf_evlist *evlist = counter->evlist;
527 struct perf_evsel *alias;
528
529 alias = list_prepare_entry(counter, &(evlist->entries), node);
530 list_for_each_entry_continue (alias, &evlist->entries, node) {
531 if (strcmp(perf_evsel__name(alias), perf_evsel__name(counter)) ||
532 alias->scale != counter->scale ||
533 alias->cgrp != counter->cgrp ||
534 strcmp(alias->unit, counter->unit) ||
535 perf_evsel__is_clock(alias) != perf_evsel__is_clock(counter))
536 break;
537 alias->merged_stat = true;
538 cb(config, alias, data, false);
539 }
540}
541
542static bool collect_data(struct perf_stat_config *config, struct perf_evsel *counter,
543 void (*cb)(struct perf_stat_config *config, struct perf_evsel *counter, void *data,
544 bool first),
545 void *data)
546{
547 if (counter->merged_stat)
548 return false;
549 cb(config, counter, data, true);
550 if (config->no_merge)
551 uniquify_event_name(counter);
552 else if (counter->auto_merge_stats)
553 collect_all_aliases(config, counter, cb, data);
554 return true;
555}
556
557struct aggr_data {
558 u64 ena, run, val;
559 int id;
560 int nr;
561 int cpu;
562};
563
564static void aggr_cb(struct perf_stat_config *config,
565 struct perf_evsel *counter, void *data, bool first)
566{
567 struct aggr_data *ad = data;
568 int cpu, s2;
569
570 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
571 struct perf_counts_values *counts;
572
573 s2 = config->aggr_get_id(config, perf_evsel__cpus(counter), cpu);
574 if (s2 != ad->id)
575 continue;
576 if (first)
577 ad->nr++;
578 counts = perf_counts(counter->counts, cpu, 0);
579 /*
580 * When any result is bad, make them all to give
581 * consistent output in interval mode.
582 */
583 if (counts->ena == 0 || counts->run == 0 ||
584 counter->counts->scaled == -1) {
585 ad->ena = 0;
586 ad->run = 0;
587 break;
588 }
589 ad->val += counts->val;
590 ad->ena += counts->ena;
591 ad->run += counts->run;
592 }
593}
594
595static void print_aggr(struct perf_stat_config *config,
596 struct perf_evlist *evlist,
597 char *prefix)
598{
599 bool metric_only = config->metric_only;
600 FILE *output = config->output;
601 struct perf_evsel *counter;
602 int s, id, nr;
603 double uval;
604 u64 ena, run, val;
605 bool first;
606
607 if (!(config->aggr_map || config->aggr_get_id))
608 return;
609
610 aggr_update_shadow(config, evlist);
611
612 /*
613 * With metric_only everything is on a single line.
614 * Without each counter has its own line.
615 */
616 for (s = 0; s < config->aggr_map->nr; s++) {
617 struct aggr_data ad;
618 if (prefix && metric_only)
619 fprintf(output, "%s", prefix);
620
621 ad.id = id = config->aggr_map->map[s];
622 first = true;
623 evlist__for_each_entry(evlist, counter) {
624 if (is_duration_time(counter))
625 continue;
626
627 ad.val = ad.ena = ad.run = 0;
628 ad.nr = 0;
629 if (!collect_data(config, counter, aggr_cb, &ad))
630 continue;
631 nr = ad.nr;
632 ena = ad.ena;
633 run = ad.run;
634 val = ad.val;
635 if (first && metric_only) {
636 first = false;
637 aggr_printout(config, counter, id, nr);
638 }
639 if (prefix && !metric_only)
640 fprintf(output, "%s", prefix);
641
642 uval = val * counter->scale;
643 printout(config, id, nr, counter, uval, prefix,
644 run, ena, 1.0, &rt_stat);
645 if (!metric_only)
646 fputc('\n', output);
647 }
648 if (metric_only)
649 fputc('\n', output);
650 }
651}
652
653static int cmp_val(const void *a, const void *b)
654{
655 return ((struct perf_aggr_thread_value *)b)->val -
656 ((struct perf_aggr_thread_value *)a)->val;
657}
658
659static struct perf_aggr_thread_value *sort_aggr_thread(
660 struct perf_evsel *counter,
661 int nthreads, int ncpus,
662 int *ret,
663 struct target *_target)
664{
665 int cpu, thread, i = 0;
666 double uval;
667 struct perf_aggr_thread_value *buf;
668
669 buf = calloc(nthreads, sizeof(struct perf_aggr_thread_value));
670 if (!buf)
671 return NULL;
672
673 for (thread = 0; thread < nthreads; thread++) {
674 u64 ena = 0, run = 0, val = 0;
675
676 for (cpu = 0; cpu < ncpus; cpu++) {
677 val += perf_counts(counter->counts, cpu, thread)->val;
678 ena += perf_counts(counter->counts, cpu, thread)->ena;
679 run += perf_counts(counter->counts, cpu, thread)->run;
680 }
681
682 uval = val * counter->scale;
683
684 /*
685 * Skip value 0 when enabling --per-thread globally,
686 * otherwise too many 0 output.
687 */
688 if (uval == 0.0 && target__has_per_thread(_target))
689 continue;
690
691 buf[i].counter = counter;
692 buf[i].id = thread;
693 buf[i].uval = uval;
694 buf[i].val = val;
695 buf[i].run = run;
696 buf[i].ena = ena;
697 i++;
698 }
699
700 qsort(buf, i, sizeof(struct perf_aggr_thread_value), cmp_val);
701
702 if (ret)
703 *ret = i;
704
705 return buf;
706}
707
708static void print_aggr_thread(struct perf_stat_config *config,
709 struct target *_target,
710 struct perf_evsel *counter, char *prefix)
711{
712 FILE *output = config->output;
713 int nthreads = thread_map__nr(counter->threads);
714 int ncpus = cpu_map__nr(counter->cpus);
715 int thread, sorted_threads, id;
716 struct perf_aggr_thread_value *buf;
717
718 buf = sort_aggr_thread(counter, nthreads, ncpus, &sorted_threads, _target);
719 if (!buf) {
720 perror("cannot sort aggr thread");
721 return;
722 }
723
724 for (thread = 0; thread < sorted_threads; thread++) {
725 if (prefix)
726 fprintf(output, "%s", prefix);
727
728 id = buf[thread].id;
729 if (config->stats)
730 printout(config, id, 0, buf[thread].counter, buf[thread].uval,
731 prefix, buf[thread].run, buf[thread].ena, 1.0,
732 &config->stats[id]);
733 else
734 printout(config, id, 0, buf[thread].counter, buf[thread].uval,
735 prefix, buf[thread].run, buf[thread].ena, 1.0,
736 &rt_stat);
737 fputc('\n', output);
738 }
739
740 free(buf);
741}
742
743struct caggr_data {
744 double avg, avg_enabled, avg_running;
745};
746
747static void counter_aggr_cb(struct perf_stat_config *config __maybe_unused,
748 struct perf_evsel *counter, void *data,
749 bool first __maybe_unused)
750{
751 struct caggr_data *cd = data;
752 struct perf_stat_evsel *ps = counter->stats;
753
754 cd->avg += avg_stats(&ps->res_stats[0]);
755 cd->avg_enabled += avg_stats(&ps->res_stats[1]);
756 cd->avg_running += avg_stats(&ps->res_stats[2]);
757}
758
759/*
760 * Print out the results of a single counter:
761 * aggregated counts in system-wide mode
762 */
763static void print_counter_aggr(struct perf_stat_config *config,
764 struct perf_evsel *counter, char *prefix)
765{
766 bool metric_only = config->metric_only;
767 FILE *output = config->output;
768 double uval;
769 struct caggr_data cd = { .avg = 0.0 };
770
771 if (!collect_data(config, counter, counter_aggr_cb, &cd))
772 return;
773
774 if (prefix && !metric_only)
775 fprintf(output, "%s", prefix);
776
777 uval = cd.avg * counter->scale;
778 printout(config, -1, 0, counter, uval, prefix, cd.avg_running, cd.avg_enabled,
779 cd.avg, &rt_stat);
780 if (!metric_only)
781 fprintf(output, "\n");
782}
783
784static void counter_cb(struct perf_stat_config *config __maybe_unused,
785 struct perf_evsel *counter, void *data,
786 bool first __maybe_unused)
787{
788 struct aggr_data *ad = data;
789
790 ad->val += perf_counts(counter->counts, ad->cpu, 0)->val;
791 ad->ena += perf_counts(counter->counts, ad->cpu, 0)->ena;
792 ad->run += perf_counts(counter->counts, ad->cpu, 0)->run;
793}
794
795/*
796 * Print out the results of a single counter:
797 * does not use aggregated count in system-wide
798 */
799static void print_counter(struct perf_stat_config *config,
800 struct perf_evsel *counter, char *prefix)
801{
802 FILE *output = config->output;
803 u64 ena, run, val;
804 double uval;
805 int cpu;
806
807 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
808 struct aggr_data ad = { .cpu = cpu };
809
810 if (!collect_data(config, counter, counter_cb, &ad))
811 return;
812 val = ad.val;
813 ena = ad.ena;
814 run = ad.run;
815
816 if (prefix)
817 fprintf(output, "%s", prefix);
818
819 uval = val * counter->scale;
820 printout(config, cpu, 0, counter, uval, prefix, run, ena, 1.0,
821 &rt_stat);
822
823 fputc('\n', output);
824 }
825}
826
827static void print_no_aggr_metric(struct perf_stat_config *config,
828 struct perf_evlist *evlist,
829 char *prefix)
830{
831 int cpu;
832 int nrcpus = 0;
833 struct perf_evsel *counter;
834 u64 ena, run, val;
835 double uval;
836
837 nrcpus = evlist->cpus->nr;
838 for (cpu = 0; cpu < nrcpus; cpu++) {
839 bool first = true;
840
841 if (prefix)
842 fputs(prefix, config->output);
843 evlist__for_each_entry(evlist, counter) {
844 if (is_duration_time(counter))
845 continue;
846 if (first) {
847 aggr_printout(config, counter, cpu, 0);
848 first = false;
849 }
850 val = perf_counts(counter->counts, cpu, 0)->val;
851 ena = perf_counts(counter->counts, cpu, 0)->ena;
852 run = perf_counts(counter->counts, cpu, 0)->run;
853
854 uval = val * counter->scale;
855 printout(config, cpu, 0, counter, uval, prefix, run, ena, 1.0,
856 &rt_stat);
857 }
858 fputc('\n', config->output);
859 }
860}
861
862static int aggr_header_lens[] = {
863 [AGGR_CORE] = 18,
864 [AGGR_SOCKET] = 12,
865 [AGGR_NONE] = 6,
866 [AGGR_THREAD] = 24,
867 [AGGR_GLOBAL] = 0,
868};
869
870static const char *aggr_header_csv[] = {
871 [AGGR_CORE] = "core,cpus,",
872 [AGGR_SOCKET] = "socket,cpus",
873 [AGGR_NONE] = "cpu,",
874 [AGGR_THREAD] = "comm-pid,",
875 [AGGR_GLOBAL] = ""
876};
877
878static void print_metric_headers(struct perf_stat_config *config,
879 struct perf_evlist *evlist,
880 const char *prefix, bool no_indent)
881{
882 struct perf_stat_output_ctx out;
883 struct perf_evsel *counter;
884 struct outstate os = {
885 .fh = config->output
886 };
887
888 if (prefix)
889 fprintf(config->output, "%s", prefix);
890
891 if (!config->csv_output && !no_indent)
892 fprintf(config->output, "%*s",
893 aggr_header_lens[config->aggr_mode], "");
894 if (config->csv_output) {
895 if (config->interval)
896 fputs("time,", config->output);
897 fputs(aggr_header_csv[config->aggr_mode], config->output);
898 }
899
900 /* Print metrics headers only */
901 evlist__for_each_entry(evlist, counter) {
902 if (is_duration_time(counter))
903 continue;
904 os.evsel = counter;
905 out.ctx = &os;
906 out.print_metric = print_metric_header;
907 out.new_line = new_line_metric;
908 out.force_header = true;
909 os.evsel = counter;
910 perf_stat__print_shadow_stats(config, counter, 0,
911 0,
912 &out,
913 &config->metric_events,
914 &rt_stat);
915 }
916 fputc('\n', config->output);
917}
918
919static void print_interval(struct perf_stat_config *config,
920 struct perf_evlist *evlist,
921 char *prefix, struct timespec *ts)
922{
923 bool metric_only = config->metric_only;
924 unsigned int unit_width = config->unit_width;
925 FILE *output = config->output;
926 static int num_print_interval;
927
928 if (config->interval_clear)
929 puts(CONSOLE_CLEAR);
930
931 sprintf(prefix, "%6lu.%09lu%s", ts->tv_sec, ts->tv_nsec, config->csv_sep);
932
933 if ((num_print_interval == 0 && !config->csv_output) || config->interval_clear) {
934 switch (config->aggr_mode) {
935 case AGGR_SOCKET:
936 fprintf(output, "# time socket cpus");
937 if (!metric_only)
938 fprintf(output, " counts %*s events\n", unit_width, "unit");
939 break;
940 case AGGR_CORE:
941 fprintf(output, "# time core cpus");
942 if (!metric_only)
943 fprintf(output, " counts %*s events\n", unit_width, "unit");
944 break;
945 case AGGR_NONE:
946 fprintf(output, "# time CPU ");
947 if (!metric_only)
948 fprintf(output, " counts %*s events\n", unit_width, "unit");
949 break;
950 case AGGR_THREAD:
951 fprintf(output, "# time comm-pid");
952 if (!metric_only)
953 fprintf(output, " counts %*s events\n", unit_width, "unit");
954 break;
955 case AGGR_GLOBAL:
956 default:
957 fprintf(output, "# time");
958 if (!metric_only)
959 fprintf(output, " counts %*s events\n", unit_width, "unit");
960 case AGGR_UNSET:
961 break;
962 }
963 }
964
965 if ((num_print_interval == 0 || config->interval_clear) && metric_only)
966 print_metric_headers(config, evlist, " ", true);
967 if (++num_print_interval == 25)
968 num_print_interval = 0;
969}
970
971static void print_header(struct perf_stat_config *config,
972 struct target *_target,
973 int argc, const char **argv)
974{
975 FILE *output = config->output;
976 int i;
977
978 fflush(stdout);
979
980 if (!config->csv_output) {
981 fprintf(output, "\n");
982 fprintf(output, " Performance counter stats for ");
983 if (_target->system_wide)
984 fprintf(output, "\'system wide");
985 else if (_target->cpu_list)
986 fprintf(output, "\'CPU(s) %s", _target->cpu_list);
987 else if (!target__has_task(_target)) {
988 fprintf(output, "\'%s", argv ? argv[0] : "pipe");
989 for (i = 1; argv && (i < argc); i++)
990 fprintf(output, " %s", argv[i]);
991 } else if (_target->pid)
992 fprintf(output, "process id \'%s", _target->pid);
993 else
994 fprintf(output, "thread id \'%s", _target->tid);
995
996 fprintf(output, "\'");
997 if (config->run_count > 1)
998 fprintf(output, " (%d runs)", config->run_count);
999 fprintf(output, ":\n\n");
1000 }
1001}
1002
1003static int get_precision(double num)
1004{
1005 if (num > 1)
1006 return 0;
1007
1008 return lround(ceil(-log10(num)));
1009}
1010
1011static void print_table(struct perf_stat_config *config,
1012 FILE *output, int precision, double avg)
1013{
1014 char tmp[64];
1015 int idx, indent = 0;
1016
1017 scnprintf(tmp, 64, " %17.*f", precision, avg);
1018 while (tmp[indent] == ' ')
1019 indent++;
1020
1021 fprintf(output, "%*s# Table of individual measurements:\n", indent, "");
1022
1023 for (idx = 0; idx < config->run_count; idx++) {
1024 double run = (double) config->walltime_run[idx] / NSEC_PER_SEC;
1025 int h, n = 1 + abs((int) (100.0 * (run - avg)/run) / 5);
1026
1027 fprintf(output, " %17.*f (%+.*f) ",
1028 precision, run, precision, run - avg);
1029
1030 for (h = 0; h < n; h++)
1031 fprintf(output, "#");
1032
1033 fprintf(output, "\n");
1034 }
1035
1036 fprintf(output, "\n%*s# Final result:\n", indent, "");
1037}
1038
1039static double timeval2double(struct timeval *t)
1040{
1041 return t->tv_sec + (double) t->tv_usec/USEC_PER_SEC;
1042}
1043
1044static void print_footer(struct perf_stat_config *config)
1045{
1046 double avg = avg_stats(config->walltime_nsecs_stats) / NSEC_PER_SEC;
1047 FILE *output = config->output;
1048 int n;
1049
1050 if (!config->null_run)
1051 fprintf(output, "\n");
1052
1053 if (config->run_count == 1) {
1054 fprintf(output, " %17.9f seconds time elapsed", avg);
1055
1056 if (config->ru_display) {
1057 double ru_utime = timeval2double(&config->ru_data.ru_utime);
1058 double ru_stime = timeval2double(&config->ru_data.ru_stime);
1059
1060 fprintf(output, "\n\n");
1061 fprintf(output, " %17.9f seconds user\n", ru_utime);
1062 fprintf(output, " %17.9f seconds sys\n", ru_stime);
1063 }
1064 } else {
1065 double sd = stddev_stats(config->walltime_nsecs_stats) / NSEC_PER_SEC;
1066 /*
1067 * Display at most 2 more significant
1068 * digits than the stddev inaccuracy.
1069 */
1070 int precision = get_precision(sd) + 2;
1071
1072 if (config->walltime_run_table)
1073 print_table(config, output, precision, avg);
1074
1075 fprintf(output, " %17.*f +- %.*f seconds time elapsed",
1076 precision, avg, precision, sd);
1077
1078 print_noise_pct(config, sd, avg);
1079 }
1080 fprintf(output, "\n\n");
1081
1082 if (config->print_free_counters_hint &&
1083 sysctl__read_int("kernel/nmi_watchdog", &n) >= 0 &&
1084 n > 0)
1085 fprintf(output,
1086"Some events weren't counted. Try disabling the NMI watchdog:\n"
1087" echo 0 > /proc/sys/kernel/nmi_watchdog\n"
1088" perf stat ...\n"
1089" echo 1 > /proc/sys/kernel/nmi_watchdog\n");
1090
1091 if (config->print_mixed_hw_group_error)
1092 fprintf(output,
1093 "The events in group usually have to be from "
1094 "the same PMU. Try reorganizing the group.\n");
1095}
1096
1097void
1098perf_evlist__print_counters(struct perf_evlist *evlist,
1099 struct perf_stat_config *config,
1100 struct target *_target,
1101 struct timespec *ts,
1102 int argc, const char **argv)
1103{
1104 bool metric_only = config->metric_only;
1105 int interval = config->interval;
1106 struct perf_evsel *counter;
1107 char buf[64], *prefix = NULL;
1108
1109 if (interval)
1110 print_interval(config, evlist, prefix = buf, ts);
1111 else
1112 print_header(config, _target, argc, argv);
1113
1114 if (metric_only) {
1115 static int num_print_iv;
1116
1117 if (num_print_iv == 0 && !interval)
1118 print_metric_headers(config, evlist, prefix, false);
1119 if (num_print_iv++ == 25)
1120 num_print_iv = 0;
1121 if (config->aggr_mode == AGGR_GLOBAL && prefix)
1122 fprintf(config->output, "%s", prefix);
1123 }
1124
1125 switch (config->aggr_mode) {
1126 case AGGR_CORE:
1127 case AGGR_SOCKET:
1128 print_aggr(config, evlist, prefix);
1129 break;
1130 case AGGR_THREAD:
1131 evlist__for_each_entry(evlist, counter) {
1132 if (is_duration_time(counter))
1133 continue;
1134 print_aggr_thread(config, _target, counter, prefix);
1135 }
1136 break;
1137 case AGGR_GLOBAL:
1138 evlist__for_each_entry(evlist, counter) {
1139 if (is_duration_time(counter))
1140 continue;
1141 print_counter_aggr(config, counter, prefix);
1142 }
1143 if (metric_only)
1144 fputc('\n', config->output);
1145 break;
1146 case AGGR_NONE:
1147 if (metric_only)
1148 print_no_aggr_metric(config, evlist, prefix);
1149 else {
1150 evlist__for_each_entry(evlist, counter) {
1151 if (is_duration_time(counter))
1152 continue;
1153 print_counter(config, counter, prefix);
1154 }
1155 }
1156 break;
1157 case AGGR_UNSET:
1158 default:
1159 break;
1160 }
1161
1162 if (!interval && !config->csv_output)
1163 print_footer(config);
1164
1165 fflush(config->output);
1166}
diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c
index 99990f5f2512..8ad32763cfff 100644
--- a/tools/perf/util/stat-shadow.c
+++ b/tools/perf/util/stat-shadow.c
@@ -410,7 +410,8 @@ static double runtime_stat_n(struct runtime_stat *st,
410 return v->stats.n; 410 return v->stats.n;
411} 411}
412 412
413static void print_stalled_cycles_frontend(int cpu, 413static void print_stalled_cycles_frontend(struct perf_stat_config *config,
414 int cpu,
414 struct perf_evsel *evsel, double avg, 415 struct perf_evsel *evsel, double avg,
415 struct perf_stat_output_ctx *out, 416 struct perf_stat_output_ctx *out,
416 struct runtime_stat *st) 417 struct runtime_stat *st)
@@ -427,13 +428,14 @@ static void print_stalled_cycles_frontend(int cpu,
427 color = get_ratio_color(GRC_STALLED_CYCLES_FE, ratio); 428 color = get_ratio_color(GRC_STALLED_CYCLES_FE, ratio);
428 429
429 if (ratio) 430 if (ratio)
430 out->print_metric(out->ctx, color, "%7.2f%%", "frontend cycles idle", 431 out->print_metric(config, out->ctx, color, "%7.2f%%", "frontend cycles idle",
431 ratio); 432 ratio);
432 else 433 else
433 out->print_metric(out->ctx, NULL, NULL, "frontend cycles idle", 0); 434 out->print_metric(config, out->ctx, NULL, NULL, "frontend cycles idle", 0);
434} 435}
435 436
436static void print_stalled_cycles_backend(int cpu, 437static void print_stalled_cycles_backend(struct perf_stat_config *config,
438 int cpu,
437 struct perf_evsel *evsel, double avg, 439 struct perf_evsel *evsel, double avg,
438 struct perf_stat_output_ctx *out, 440 struct perf_stat_output_ctx *out,
439 struct runtime_stat *st) 441 struct runtime_stat *st)
@@ -449,10 +451,11 @@ static void print_stalled_cycles_backend(int cpu,
449 451
450 color = get_ratio_color(GRC_STALLED_CYCLES_BE, ratio); 452 color = get_ratio_color(GRC_STALLED_CYCLES_BE, ratio);
451 453
452 out->print_metric(out->ctx, color, "%7.2f%%", "backend cycles idle", ratio); 454 out->print_metric(config, out->ctx, color, "%7.2f%%", "backend cycles idle", ratio);
453} 455}
454 456
455static void print_branch_misses(int cpu, 457static void print_branch_misses(struct perf_stat_config *config,
458 int cpu,
456 struct perf_evsel *evsel, 459 struct perf_evsel *evsel,
457 double avg, 460 double avg,
458 struct perf_stat_output_ctx *out, 461 struct perf_stat_output_ctx *out,
@@ -469,10 +472,11 @@ static void print_branch_misses(int cpu,
469 472
470 color = get_ratio_color(GRC_CACHE_MISSES, ratio); 473 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
471 474
472 out->print_metric(out->ctx, color, "%7.2f%%", "of all branches", ratio); 475 out->print_metric(config, out->ctx, color, "%7.2f%%", "of all branches", ratio);
473} 476}
474 477
475static void print_l1_dcache_misses(int cpu, 478static void print_l1_dcache_misses(struct perf_stat_config *config,
479 int cpu,
476 struct perf_evsel *evsel, 480 struct perf_evsel *evsel,
477 double avg, 481 double avg,
478 struct perf_stat_output_ctx *out, 482 struct perf_stat_output_ctx *out,
@@ -490,10 +494,11 @@ static void print_l1_dcache_misses(int cpu,
490 494
491 color = get_ratio_color(GRC_CACHE_MISSES, ratio); 495 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
492 496
493 out->print_metric(out->ctx, color, "%7.2f%%", "of all L1-dcache hits", ratio); 497 out->print_metric(config, out->ctx, color, "%7.2f%%", "of all L1-dcache hits", ratio);
494} 498}
495 499
496static void print_l1_icache_misses(int cpu, 500static void print_l1_icache_misses(struct perf_stat_config *config,
501 int cpu,
497 struct perf_evsel *evsel, 502 struct perf_evsel *evsel,
498 double avg, 503 double avg,
499 struct perf_stat_output_ctx *out, 504 struct perf_stat_output_ctx *out,
@@ -510,10 +515,11 @@ static void print_l1_icache_misses(int cpu,
510 ratio = avg / total * 100.0; 515 ratio = avg / total * 100.0;
511 516
512 color = get_ratio_color(GRC_CACHE_MISSES, ratio); 517 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
513 out->print_metric(out->ctx, color, "%7.2f%%", "of all L1-icache hits", ratio); 518 out->print_metric(config, out->ctx, color, "%7.2f%%", "of all L1-icache hits", ratio);
514} 519}
515 520
516static void print_dtlb_cache_misses(int cpu, 521static void print_dtlb_cache_misses(struct perf_stat_config *config,
522 int cpu,
517 struct perf_evsel *evsel, 523 struct perf_evsel *evsel,
518 double avg, 524 double avg,
519 struct perf_stat_output_ctx *out, 525 struct perf_stat_output_ctx *out,
@@ -529,10 +535,11 @@ static void print_dtlb_cache_misses(int cpu,
529 ratio = avg / total * 100.0; 535 ratio = avg / total * 100.0;
530 536
531 color = get_ratio_color(GRC_CACHE_MISSES, ratio); 537 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
532 out->print_metric(out->ctx, color, "%7.2f%%", "of all dTLB cache hits", ratio); 538 out->print_metric(config, out->ctx, color, "%7.2f%%", "of all dTLB cache hits", ratio);
533} 539}
534 540
535static void print_itlb_cache_misses(int cpu, 541static void print_itlb_cache_misses(struct perf_stat_config *config,
542 int cpu,
536 struct perf_evsel *evsel, 543 struct perf_evsel *evsel,
537 double avg, 544 double avg,
538 struct perf_stat_output_ctx *out, 545 struct perf_stat_output_ctx *out,
@@ -548,10 +555,11 @@ static void print_itlb_cache_misses(int cpu,
548 ratio = avg / total * 100.0; 555 ratio = avg / total * 100.0;
549 556
550 color = get_ratio_color(GRC_CACHE_MISSES, ratio); 557 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
551 out->print_metric(out->ctx, color, "%7.2f%%", "of all iTLB cache hits", ratio); 558 out->print_metric(config, out->ctx, color, "%7.2f%%", "of all iTLB cache hits", ratio);
552} 559}
553 560
554static void print_ll_cache_misses(int cpu, 561static void print_ll_cache_misses(struct perf_stat_config *config,
562 int cpu,
555 struct perf_evsel *evsel, 563 struct perf_evsel *evsel,
556 double avg, 564 double avg,
557 struct perf_stat_output_ctx *out, 565 struct perf_stat_output_ctx *out,
@@ -567,7 +575,7 @@ static void print_ll_cache_misses(int cpu,
567 ratio = avg / total * 100.0; 575 ratio = avg / total * 100.0;
568 576
569 color = get_ratio_color(GRC_CACHE_MISSES, ratio); 577 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
570 out->print_metric(out->ctx, color, "%7.2f%%", "of all LL-cache hits", ratio); 578 out->print_metric(config, out->ctx, color, "%7.2f%%", "of all LL-cache hits", ratio);
571} 579}
572 580
573/* 581/*
@@ -674,7 +682,8 @@ static double td_be_bound(int ctx, int cpu, struct runtime_stat *st)
674 return sanitize_val(1.0 - sum); 682 return sanitize_val(1.0 - sum);
675} 683}
676 684
677static void print_smi_cost(int cpu, struct perf_evsel *evsel, 685static void print_smi_cost(struct perf_stat_config *config,
686 int cpu, struct perf_evsel *evsel,
678 struct perf_stat_output_ctx *out, 687 struct perf_stat_output_ctx *out,
679 struct runtime_stat *st) 688 struct runtime_stat *st)
680{ 689{
@@ -694,11 +703,12 @@ static void print_smi_cost(int cpu, struct perf_evsel *evsel,
694 703
695 if (cost > 10) 704 if (cost > 10)
696 color = PERF_COLOR_RED; 705 color = PERF_COLOR_RED;
697 out->print_metric(out->ctx, color, "%8.1f%%", "SMI cycles%", cost); 706 out->print_metric(config, out->ctx, color, "%8.1f%%", "SMI cycles%", cost);
698 out->print_metric(out->ctx, NULL, "%4.0f", "SMI#", smi_num); 707 out->print_metric(config, out->ctx, NULL, "%4.0f", "SMI#", smi_num);
699} 708}
700 709
701static void generic_metric(const char *metric_expr, 710static void generic_metric(struct perf_stat_config *config,
711 const char *metric_expr,
702 struct perf_evsel **metric_events, 712 struct perf_evsel **metric_events,
703 char *name, 713 char *name,
704 const char *metric_name, 714 const char *metric_name,
@@ -737,20 +747,21 @@ static void generic_metric(const char *metric_expr,
737 const char *p = metric_expr; 747 const char *p = metric_expr;
738 748
739 if (expr__parse(&ratio, &pctx, &p) == 0) 749 if (expr__parse(&ratio, &pctx, &p) == 0)
740 print_metric(ctxp, NULL, "%8.1f", 750 print_metric(config, ctxp, NULL, "%8.1f",
741 metric_name ? 751 metric_name ?
742 metric_name : 752 metric_name :
743 out->force_header ? name : "", 753 out->force_header ? name : "",
744 ratio); 754 ratio);
745 else 755 else
746 print_metric(ctxp, NULL, NULL, 756 print_metric(config, ctxp, NULL, NULL,
747 out->force_header ? 757 out->force_header ?
748 (metric_name ? metric_name : name) : "", 0); 758 (metric_name ? metric_name : name) : "", 0);
749 } else 759 } else
750 print_metric(ctxp, NULL, NULL, "", 0); 760 print_metric(config, ctxp, NULL, NULL, "", 0);
751} 761}
752 762
753void perf_stat__print_shadow_stats(struct perf_evsel *evsel, 763void perf_stat__print_shadow_stats(struct perf_stat_config *config,
764 struct perf_evsel *evsel,
754 double avg, int cpu, 765 double avg, int cpu,
755 struct perf_stat_output_ctx *out, 766 struct perf_stat_output_ctx *out,
756 struct rblist *metric_events, 767 struct rblist *metric_events,
@@ -769,10 +780,10 @@ void perf_stat__print_shadow_stats(struct perf_evsel *evsel,
769 780
770 if (total) { 781 if (total) {
771 ratio = avg / total; 782 ratio = avg / total;
772 print_metric(ctxp, NULL, "%7.2f ", 783 print_metric(config, ctxp, NULL, "%7.2f ",
773 "insn per cycle", ratio); 784 "insn per cycle", ratio);
774 } else { 785 } else {
775 print_metric(ctxp, NULL, NULL, "insn per cycle", 0); 786 print_metric(config, ctxp, NULL, NULL, "insn per cycle", 0);
776 } 787 }
777 788
778 total = runtime_stat_avg(st, STAT_STALLED_CYCLES_FRONT, 789 total = runtime_stat_avg(st, STAT_STALLED_CYCLES_FRONT,
@@ -783,20 +794,20 @@ void perf_stat__print_shadow_stats(struct perf_evsel *evsel,
783 ctx, cpu)); 794 ctx, cpu));
784 795
785 if (total && avg) { 796 if (total && avg) {
786 out->new_line(ctxp); 797 out->new_line(config, ctxp);
787 ratio = total / avg; 798 ratio = total / avg;
788 print_metric(ctxp, NULL, "%7.2f ", 799 print_metric(config, ctxp, NULL, "%7.2f ",
789 "stalled cycles per insn", 800 "stalled cycles per insn",
790 ratio); 801 ratio);
791 } else if (have_frontend_stalled) { 802 } else if (have_frontend_stalled) {
792 print_metric(ctxp, NULL, NULL, 803 print_metric(config, ctxp, NULL, NULL,
793 "stalled cycles per insn", 0); 804 "stalled cycles per insn", 0);
794 } 805 }
795 } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES)) { 806 } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES)) {
796 if (runtime_stat_n(st, STAT_BRANCHES, ctx, cpu) != 0) 807 if (runtime_stat_n(st, STAT_BRANCHES, ctx, cpu) != 0)
797 print_branch_misses(cpu, evsel, avg, out, st); 808 print_branch_misses(config, cpu, evsel, avg, out, st);
798 else 809 else
799 print_metric(ctxp, NULL, NULL, "of all branches", 0); 810 print_metric(config, ctxp, NULL, NULL, "of all branches", 0);
800 } else if ( 811 } else if (
801 evsel->attr.type == PERF_TYPE_HW_CACHE && 812 evsel->attr.type == PERF_TYPE_HW_CACHE &&
802 evsel->attr.config == ( PERF_COUNT_HW_CACHE_L1D | 813 evsel->attr.config == ( PERF_COUNT_HW_CACHE_L1D |
@@ -804,9 +815,9 @@ void perf_stat__print_shadow_stats(struct perf_evsel *evsel,
804 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) { 815 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) {
805 816
806 if (runtime_stat_n(st, STAT_L1_DCACHE, ctx, cpu) != 0) 817 if (runtime_stat_n(st, STAT_L1_DCACHE, ctx, cpu) != 0)
807 print_l1_dcache_misses(cpu, evsel, avg, out, st); 818 print_l1_dcache_misses(config, cpu, evsel, avg, out, st);
808 else 819 else
809 print_metric(ctxp, NULL, NULL, "of all L1-dcache hits", 0); 820 print_metric(config, ctxp, NULL, NULL, "of all L1-dcache hits", 0);
810 } else if ( 821 } else if (
811 evsel->attr.type == PERF_TYPE_HW_CACHE && 822 evsel->attr.type == PERF_TYPE_HW_CACHE &&
812 evsel->attr.config == ( PERF_COUNT_HW_CACHE_L1I | 823 evsel->attr.config == ( PERF_COUNT_HW_CACHE_L1I |
@@ -814,9 +825,9 @@ void perf_stat__print_shadow_stats(struct perf_evsel *evsel,
814 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) { 825 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) {
815 826
816 if (runtime_stat_n(st, STAT_L1_ICACHE, ctx, cpu) != 0) 827 if (runtime_stat_n(st, STAT_L1_ICACHE, ctx, cpu) != 0)
817 print_l1_icache_misses(cpu, evsel, avg, out, st); 828 print_l1_icache_misses(config, cpu, evsel, avg, out, st);
818 else 829 else
819 print_metric(ctxp, NULL, NULL, "of all L1-icache hits", 0); 830 print_metric(config, ctxp, NULL, NULL, "of all L1-icache hits", 0);
820 } else if ( 831 } else if (
821 evsel->attr.type == PERF_TYPE_HW_CACHE && 832 evsel->attr.type == PERF_TYPE_HW_CACHE &&
822 evsel->attr.config == ( PERF_COUNT_HW_CACHE_DTLB | 833 evsel->attr.config == ( PERF_COUNT_HW_CACHE_DTLB |
@@ -824,9 +835,9 @@ void perf_stat__print_shadow_stats(struct perf_evsel *evsel,
824 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) { 835 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) {
825 836
826 if (runtime_stat_n(st, STAT_DTLB_CACHE, ctx, cpu) != 0) 837 if (runtime_stat_n(st, STAT_DTLB_CACHE, ctx, cpu) != 0)
827 print_dtlb_cache_misses(cpu, evsel, avg, out, st); 838 print_dtlb_cache_misses(config, cpu, evsel, avg, out, st);
828 else 839 else
829 print_metric(ctxp, NULL, NULL, "of all dTLB cache hits", 0); 840 print_metric(config, ctxp, NULL, NULL, "of all dTLB cache hits", 0);
830 } else if ( 841 } else if (
831 evsel->attr.type == PERF_TYPE_HW_CACHE && 842 evsel->attr.type == PERF_TYPE_HW_CACHE &&
832 evsel->attr.config == ( PERF_COUNT_HW_CACHE_ITLB | 843 evsel->attr.config == ( PERF_COUNT_HW_CACHE_ITLB |
@@ -834,9 +845,9 @@ void perf_stat__print_shadow_stats(struct perf_evsel *evsel,
834 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) { 845 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) {
835 846
836 if (runtime_stat_n(st, STAT_ITLB_CACHE, ctx, cpu) != 0) 847 if (runtime_stat_n(st, STAT_ITLB_CACHE, ctx, cpu) != 0)
837 print_itlb_cache_misses(cpu, evsel, avg, out, st); 848 print_itlb_cache_misses(config, cpu, evsel, avg, out, st);
838 else 849 else
839 print_metric(ctxp, NULL, NULL, "of all iTLB cache hits", 0); 850 print_metric(config, ctxp, NULL, NULL, "of all iTLB cache hits", 0);
840 } else if ( 851 } else if (
841 evsel->attr.type == PERF_TYPE_HW_CACHE && 852 evsel->attr.type == PERF_TYPE_HW_CACHE &&
842 evsel->attr.config == ( PERF_COUNT_HW_CACHE_LL | 853 evsel->attr.config == ( PERF_COUNT_HW_CACHE_LL |
@@ -844,9 +855,9 @@ void perf_stat__print_shadow_stats(struct perf_evsel *evsel,
844 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) { 855 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) {
845 856
846 if (runtime_stat_n(st, STAT_LL_CACHE, ctx, cpu) != 0) 857 if (runtime_stat_n(st, STAT_LL_CACHE, ctx, cpu) != 0)
847 print_ll_cache_misses(cpu, evsel, avg, out, st); 858 print_ll_cache_misses(config, cpu, evsel, avg, out, st);
848 else 859 else
849 print_metric(ctxp, NULL, NULL, "of all LL-cache hits", 0); 860 print_metric(config, ctxp, NULL, NULL, "of all LL-cache hits", 0);
850 } else if (perf_evsel__match(evsel, HARDWARE, HW_CACHE_MISSES)) { 861 } else if (perf_evsel__match(evsel, HARDWARE, HW_CACHE_MISSES)) {
851 total = runtime_stat_avg(st, STAT_CACHEREFS, ctx, cpu); 862 total = runtime_stat_avg(st, STAT_CACHEREFS, ctx, cpu);
852 863
@@ -854,32 +865,32 @@ void perf_stat__print_shadow_stats(struct perf_evsel *evsel,
854 ratio = avg * 100 / total; 865 ratio = avg * 100 / total;
855 866
856 if (runtime_stat_n(st, STAT_CACHEREFS, ctx, cpu) != 0) 867 if (runtime_stat_n(st, STAT_CACHEREFS, ctx, cpu) != 0)
857 print_metric(ctxp, NULL, "%8.3f %%", 868 print_metric(config, ctxp, NULL, "%8.3f %%",
858 "of all cache refs", ratio); 869 "of all cache refs", ratio);
859 else 870 else
860 print_metric(ctxp, NULL, NULL, "of all cache refs", 0); 871 print_metric(config, ctxp, NULL, NULL, "of all cache refs", 0);
861 } else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_FRONTEND)) { 872 } else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_FRONTEND)) {
862 print_stalled_cycles_frontend(cpu, evsel, avg, out, st); 873 print_stalled_cycles_frontend(config, cpu, evsel, avg, out, st);
863 } else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_BACKEND)) { 874 } else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_BACKEND)) {
864 print_stalled_cycles_backend(cpu, evsel, avg, out, st); 875 print_stalled_cycles_backend(config, cpu, evsel, avg, out, st);
865 } else if (perf_evsel__match(evsel, HARDWARE, HW_CPU_CYCLES)) { 876 } else if (perf_evsel__match(evsel, HARDWARE, HW_CPU_CYCLES)) {
866 total = runtime_stat_avg(st, STAT_NSECS, 0, cpu); 877 total = runtime_stat_avg(st, STAT_NSECS, 0, cpu);
867 878
868 if (total) { 879 if (total) {
869 ratio = avg / total; 880 ratio = avg / total;
870 print_metric(ctxp, NULL, "%8.3f", "GHz", ratio); 881 print_metric(config, ctxp, NULL, "%8.3f", "GHz", ratio);
871 } else { 882 } else {
872 print_metric(ctxp, NULL, NULL, "Ghz", 0); 883 print_metric(config, ctxp, NULL, NULL, "Ghz", 0);
873 } 884 }
874 } else if (perf_stat_evsel__is(evsel, CYCLES_IN_TX)) { 885 } else if (perf_stat_evsel__is(evsel, CYCLES_IN_TX)) {
875 total = runtime_stat_avg(st, STAT_CYCLES, ctx, cpu); 886 total = runtime_stat_avg(st, STAT_CYCLES, ctx, cpu);
876 887
877 if (total) 888 if (total)
878 print_metric(ctxp, NULL, 889 print_metric(config, ctxp, NULL,
879 "%7.2f%%", "transactional cycles", 890 "%7.2f%%", "transactional cycles",
880 100.0 * (avg / total)); 891 100.0 * (avg / total));
881 else 892 else
882 print_metric(ctxp, NULL, NULL, "transactional cycles", 893 print_metric(config, ctxp, NULL, NULL, "transactional cycles",
883 0); 894 0);
884 } else if (perf_stat_evsel__is(evsel, CYCLES_IN_TX_CP)) { 895 } else if (perf_stat_evsel__is(evsel, CYCLES_IN_TX_CP)) {
885 total = runtime_stat_avg(st, STAT_CYCLES, ctx, cpu); 896 total = runtime_stat_avg(st, STAT_CYCLES, ctx, cpu);
@@ -888,10 +899,10 @@ void perf_stat__print_shadow_stats(struct perf_evsel *evsel,
888 if (total2 < avg) 899 if (total2 < avg)
889 total2 = avg; 900 total2 = avg;
890 if (total) 901 if (total)
891 print_metric(ctxp, NULL, "%7.2f%%", "aborted cycles", 902 print_metric(config, ctxp, NULL, "%7.2f%%", "aborted cycles",
892 100.0 * ((total2-avg) / total)); 903 100.0 * ((total2-avg) / total));
893 else 904 else
894 print_metric(ctxp, NULL, NULL, "aborted cycles", 0); 905 print_metric(config, ctxp, NULL, NULL, "aborted cycles", 0);
895 } else if (perf_stat_evsel__is(evsel, TRANSACTION_START)) { 906 } else if (perf_stat_evsel__is(evsel, TRANSACTION_START)) {
896 total = runtime_stat_avg(st, STAT_CYCLES_IN_TX, 907 total = runtime_stat_avg(st, STAT_CYCLES_IN_TX,
897 ctx, cpu); 908 ctx, cpu);
@@ -900,10 +911,10 @@ void perf_stat__print_shadow_stats(struct perf_evsel *evsel,
900 ratio = total / avg; 911 ratio = total / avg;
901 912
902 if (runtime_stat_n(st, STAT_CYCLES_IN_TX, ctx, cpu) != 0) 913 if (runtime_stat_n(st, STAT_CYCLES_IN_TX, ctx, cpu) != 0)
903 print_metric(ctxp, NULL, "%8.0f", 914 print_metric(config, ctxp, NULL, "%8.0f",
904 "cycles / transaction", ratio); 915 "cycles / transaction", ratio);
905 else 916 else
906 print_metric(ctxp, NULL, NULL, "cycles / transaction", 917 print_metric(config, ctxp, NULL, NULL, "cycles / transaction",
907 0); 918 0);
908 } else if (perf_stat_evsel__is(evsel, ELISION_START)) { 919 } else if (perf_stat_evsel__is(evsel, ELISION_START)) {
909 total = runtime_stat_avg(st, STAT_CYCLES_IN_TX, 920 total = runtime_stat_avg(st, STAT_CYCLES_IN_TX,
@@ -912,33 +923,33 @@ void perf_stat__print_shadow_stats(struct perf_evsel *evsel,
912 if (avg) 923 if (avg)
913 ratio = total / avg; 924 ratio = total / avg;
914 925
915 print_metric(ctxp, NULL, "%8.0f", "cycles / elision", ratio); 926 print_metric(config, ctxp, NULL, "%8.0f", "cycles / elision", ratio);
916 } else if (perf_evsel__is_clock(evsel)) { 927 } else if (perf_evsel__is_clock(evsel)) {
917 if ((ratio = avg_stats(&walltime_nsecs_stats)) != 0) 928 if ((ratio = avg_stats(&walltime_nsecs_stats)) != 0)
918 print_metric(ctxp, NULL, "%8.3f", "CPUs utilized", 929 print_metric(config, ctxp, NULL, "%8.3f", "CPUs utilized",
919 avg / (ratio * evsel->scale)); 930 avg / (ratio * evsel->scale));
920 else 931 else
921 print_metric(ctxp, NULL, NULL, "CPUs utilized", 0); 932 print_metric(config, ctxp, NULL, NULL, "CPUs utilized", 0);
922 } else if (perf_stat_evsel__is(evsel, TOPDOWN_FETCH_BUBBLES)) { 933 } else if (perf_stat_evsel__is(evsel, TOPDOWN_FETCH_BUBBLES)) {
923 double fe_bound = td_fe_bound(ctx, cpu, st); 934 double fe_bound = td_fe_bound(ctx, cpu, st);
924 935
925 if (fe_bound > 0.2) 936 if (fe_bound > 0.2)
926 color = PERF_COLOR_RED; 937 color = PERF_COLOR_RED;
927 print_metric(ctxp, color, "%8.1f%%", "frontend bound", 938 print_metric(config, ctxp, color, "%8.1f%%", "frontend bound",
928 fe_bound * 100.); 939 fe_bound * 100.);
929 } else if (perf_stat_evsel__is(evsel, TOPDOWN_SLOTS_RETIRED)) { 940 } else if (perf_stat_evsel__is(evsel, TOPDOWN_SLOTS_RETIRED)) {
930 double retiring = td_retiring(ctx, cpu, st); 941 double retiring = td_retiring(ctx, cpu, st);
931 942
932 if (retiring > 0.7) 943 if (retiring > 0.7)
933 color = PERF_COLOR_GREEN; 944 color = PERF_COLOR_GREEN;
934 print_metric(ctxp, color, "%8.1f%%", "retiring", 945 print_metric(config, ctxp, color, "%8.1f%%", "retiring",
935 retiring * 100.); 946 retiring * 100.);
936 } else if (perf_stat_evsel__is(evsel, TOPDOWN_RECOVERY_BUBBLES)) { 947 } else if (perf_stat_evsel__is(evsel, TOPDOWN_RECOVERY_BUBBLES)) {
937 double bad_spec = td_bad_spec(ctx, cpu, st); 948 double bad_spec = td_bad_spec(ctx, cpu, st);
938 949
939 if (bad_spec > 0.1) 950 if (bad_spec > 0.1)
940 color = PERF_COLOR_RED; 951 color = PERF_COLOR_RED;
941 print_metric(ctxp, color, "%8.1f%%", "bad speculation", 952 print_metric(config, ctxp, color, "%8.1f%%", "bad speculation",
942 bad_spec * 100.); 953 bad_spec * 100.);
943 } else if (perf_stat_evsel__is(evsel, TOPDOWN_SLOTS_ISSUED)) { 954 } else if (perf_stat_evsel__is(evsel, TOPDOWN_SLOTS_ISSUED)) {
944 double be_bound = td_be_bound(ctx, cpu, st); 955 double be_bound = td_be_bound(ctx, cpu, st);
@@ -955,12 +966,12 @@ void perf_stat__print_shadow_stats(struct perf_evsel *evsel,
955 if (be_bound > 0.2) 966 if (be_bound > 0.2)
956 color = PERF_COLOR_RED; 967 color = PERF_COLOR_RED;
957 if (td_total_slots(ctx, cpu, st) > 0) 968 if (td_total_slots(ctx, cpu, st) > 0)
958 print_metric(ctxp, color, "%8.1f%%", name, 969 print_metric(config, ctxp, color, "%8.1f%%", name,
959 be_bound * 100.); 970 be_bound * 100.);
960 else 971 else
961 print_metric(ctxp, NULL, NULL, name, 0); 972 print_metric(config, ctxp, NULL, NULL, name, 0);
962 } else if (evsel->metric_expr) { 973 } else if (evsel->metric_expr) {
963 generic_metric(evsel->metric_expr, evsel->metric_events, evsel->name, 974 generic_metric(config, evsel->metric_expr, evsel->metric_events, evsel->name,
964 evsel->metric_name, avg, cpu, out, st); 975 evsel->metric_name, avg, cpu, out, st);
965 } else if (runtime_stat_n(st, STAT_NSECS, 0, cpu) != 0) { 976 } else if (runtime_stat_n(st, STAT_NSECS, 0, cpu) != 0) {
966 char unit = 'M'; 977 char unit = 'M';
@@ -975,9 +986,9 @@ void perf_stat__print_shadow_stats(struct perf_evsel *evsel,
975 unit = 'K'; 986 unit = 'K';
976 } 987 }
977 snprintf(unit_buf, sizeof(unit_buf), "%c/sec", unit); 988 snprintf(unit_buf, sizeof(unit_buf), "%c/sec", unit);
978 print_metric(ctxp, NULL, "%8.3f", unit_buf, ratio); 989 print_metric(config, ctxp, NULL, "%8.3f", unit_buf, ratio);
979 } else if (perf_stat_evsel__is(evsel, SMI_NUM)) { 990 } else if (perf_stat_evsel__is(evsel, SMI_NUM)) {
980 print_smi_cost(cpu, evsel, out, st); 991 print_smi_cost(config, cpu, evsel, out, st);
981 } else { 992 } else {
982 num = 0; 993 num = 0;
983 } 994 }
@@ -987,12 +998,12 @@ void perf_stat__print_shadow_stats(struct perf_evsel *evsel,
987 998
988 list_for_each_entry (mexp, &me->head, nd) { 999 list_for_each_entry (mexp, &me->head, nd) {
989 if (num++ > 0) 1000 if (num++ > 0)
990 out->new_line(ctxp); 1001 out->new_line(config, ctxp);
991 generic_metric(mexp->metric_expr, mexp->metric_events, 1002 generic_metric(config, mexp->metric_expr, mexp->metric_events,
992 evsel->name, mexp->metric_name, 1003 evsel->name, mexp->metric_name,
993 avg, cpu, out, st); 1004 avg, cpu, out, st);
994 } 1005 }
995 } 1006 }
996 if (num == 0) 1007 if (num == 0)
997 print_metric(ctxp, NULL, NULL, NULL, 0); 1008 print_metric(config, ctxp, NULL, NULL, NULL, 0);
998} 1009}
diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c
index a0061e0b0fad..4d40515307b8 100644
--- a/tools/perf/util/stat.c
+++ b/tools/perf/util/stat.c
@@ -374,9 +374,8 @@ int perf_stat_process_counter(struct perf_stat_config *config,
374 return 0; 374 return 0;
375} 375}
376 376
377int perf_event__process_stat_event(struct perf_tool *tool __maybe_unused, 377int perf_event__process_stat_event(struct perf_session *session,
378 union perf_event *event, 378 union perf_event *event)
379 struct perf_session *session)
380{ 379{
381 struct perf_counts_values count; 380 struct perf_counts_values count;
382 struct stat_event *st = &event->stat; 381 struct stat_event *st = &event->stat;
@@ -435,3 +434,98 @@ size_t perf_event__fprintf_stat_config(union perf_event *event, FILE *fp)
435 434
436 return ret; 435 return ret;
437} 436}
437
438int create_perf_stat_counter(struct perf_evsel *evsel,
439 struct perf_stat_config *config,
440 struct target *target)
441{
442 struct perf_event_attr *attr = &evsel->attr;
443 struct perf_evsel *leader = evsel->leader;
444
445 if (config->scale) {
446 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
447 PERF_FORMAT_TOTAL_TIME_RUNNING;
448 }
449
450 /*
451 * The event is part of non trivial group, let's enable
452 * the group read (for leader) and ID retrieval for all
453 * members.
454 */
455 if (leader->nr_members > 1)
456 attr->read_format |= PERF_FORMAT_ID|PERF_FORMAT_GROUP;
457
458 attr->inherit = !config->no_inherit;
459
460 /*
461 * Some events get initialized with sample_(period/type) set,
462 * like tracepoints. Clear it up for counting.
463 */
464 attr->sample_period = 0;
465
466 if (config->identifier)
467 attr->sample_type = PERF_SAMPLE_IDENTIFIER;
468
469 /*
470 * Disabling all counters initially, they will be enabled
471 * either manually by us or by kernel via enable_on_exec
472 * set later.
473 */
474 if (perf_evsel__is_group_leader(evsel)) {
475 attr->disabled = 1;
476
477 /*
478 * In case of initial_delay we enable tracee
479 * events manually.
480 */
481 if (target__none(target) && !config->initial_delay)
482 attr->enable_on_exec = 1;
483 }
484
485 if (target__has_cpu(target) && !target__has_per_thread(target))
486 return perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel));
487
488 return perf_evsel__open_per_thread(evsel, evsel->threads);
489}
490
491int perf_stat_synthesize_config(struct perf_stat_config *config,
492 struct perf_tool *tool,
493 struct perf_evlist *evlist,
494 perf_event__handler_t process,
495 bool attrs)
496{
497 int err;
498
499 if (attrs) {
500 err = perf_event__synthesize_attrs(tool, evlist, process);
501 if (err < 0) {
502 pr_err("Couldn't synthesize attrs.\n");
503 return err;
504 }
505 }
506
507 err = perf_event__synthesize_extra_attr(tool, evlist, process,
508 attrs);
509
510 err = perf_event__synthesize_thread_map2(tool, evlist->threads,
511 process, NULL);
512 if (err < 0) {
513 pr_err("Couldn't synthesize thread map.\n");
514 return err;
515 }
516
517 err = perf_event__synthesize_cpu_map(tool, evlist->cpus,
518 process, NULL);
519 if (err < 0) {
520 pr_err("Couldn't synthesize thread map.\n");
521 return err;
522 }
523
524 err = perf_event__synthesize_stat_config(tool, config, process, NULL);
525 if (err < 0) {
526 pr_err("Couldn't synthesize config.\n");
527 return err;
528 }
529
530 return 0;
531}
diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h
index 36efb986f7fc..2f9c9159a364 100644
--- a/tools/perf/util/stat.h
+++ b/tools/perf/util/stat.h
@@ -4,8 +4,14 @@
4 4
5#include <linux/types.h> 5#include <linux/types.h>
6#include <stdio.h> 6#include <stdio.h>
7#include <sys/types.h>
8#include <sys/time.h>
9#include <sys/resource.h>
10#include <sys/wait.h>
7#include "xyarray.h" 11#include "xyarray.h"
8#include "rblist.h" 12#include "rblist.h"
13#include "perf.h"
14#include "event.h"
9 15
10struct stats { 16struct stats {
11 double n, mean, M2; 17 double n, mean, M2;
@@ -84,15 +90,42 @@ struct runtime_stat {
84 struct rblist value_list; 90 struct rblist value_list;
85}; 91};
86 92
93typedef int (*aggr_get_id_t)(struct perf_stat_config *config,
94 struct cpu_map *m, int cpu);
95
87struct perf_stat_config { 96struct perf_stat_config {
88 enum aggr_mode aggr_mode; 97 enum aggr_mode aggr_mode;
89 bool scale; 98 bool scale;
90 FILE *output; 99 bool no_inherit;
91 unsigned int interval; 100 bool identifier;
92 unsigned int timeout; 101 bool csv_output;
93 int times; 102 bool interval_clear;
94 struct runtime_stat *stats; 103 bool metric_only;
95 int stats_num; 104 bool null_run;
105 bool ru_display;
106 bool big_num;
107 bool no_merge;
108 bool walltime_run_table;
109 FILE *output;
110 unsigned int interval;
111 unsigned int timeout;
112 unsigned int initial_delay;
113 unsigned int unit_width;
114 unsigned int metric_only_len;
115 int times;
116 int run_count;
117 int print_free_counters_hint;
118 int print_mixed_hw_group_error;
119 struct runtime_stat *stats;
120 int stats_num;
121 const char *csv_sep;
122 struct stats *walltime_nsecs_stats;
123 struct rusage ru_data;
124 struct cpu_map *aggr_map;
125 aggr_get_id_t aggr_get_id;
126 struct cpu_map *cpus_aggr_map;
127 u64 *walltime_run;
128 struct rblist metric_events;
96}; 129};
97 130
98void update_stats(struct stats *stats, u64 val); 131void update_stats(struct stats *stats, u64 val);
@@ -130,9 +163,10 @@ bool __perf_evsel_stat__is(struct perf_evsel *evsel,
130extern struct runtime_stat rt_stat; 163extern struct runtime_stat rt_stat;
131extern struct stats walltime_nsecs_stats; 164extern struct stats walltime_nsecs_stats;
132 165
133typedef void (*print_metric_t)(void *ctx, const char *color, const char *unit, 166typedef void (*print_metric_t)(struct perf_stat_config *config,
167 void *ctx, const char *color, const char *unit,
134 const char *fmt, double val); 168 const char *fmt, double val);
135typedef void (*new_line_t )(void *ctx); 169typedef void (*new_line_t)(struct perf_stat_config *config, void *ctx);
136 170
137void runtime_stat__init(struct runtime_stat *st); 171void runtime_stat__init(struct runtime_stat *st);
138void runtime_stat__exit(struct runtime_stat *st); 172void runtime_stat__exit(struct runtime_stat *st);
@@ -148,7 +182,8 @@ struct perf_stat_output_ctx {
148 bool force_header; 182 bool force_header;
149}; 183};
150 184
151void perf_stat__print_shadow_stats(struct perf_evsel *evsel, 185void perf_stat__print_shadow_stats(struct perf_stat_config *config,
186 struct perf_evsel *evsel,
152 double avg, int cpu, 187 double avg, int cpu,
153 struct perf_stat_output_ctx *out, 188 struct perf_stat_output_ctx *out,
154 struct rblist *metric_events, 189 struct rblist *metric_events,
@@ -164,11 +199,25 @@ int perf_stat_process_counter(struct perf_stat_config *config,
164struct perf_tool; 199struct perf_tool;
165union perf_event; 200union perf_event;
166struct perf_session; 201struct perf_session;
167int perf_event__process_stat_event(struct perf_tool *tool, 202int perf_event__process_stat_event(struct perf_session *session,
168 union perf_event *event, 203 union perf_event *event);
169 struct perf_session *session);
170 204
171size_t perf_event__fprintf_stat(union perf_event *event, FILE *fp); 205size_t perf_event__fprintf_stat(union perf_event *event, FILE *fp);
172size_t perf_event__fprintf_stat_round(union perf_event *event, FILE *fp); 206size_t perf_event__fprintf_stat_round(union perf_event *event, FILE *fp);
173size_t perf_event__fprintf_stat_config(union perf_event *event, FILE *fp); 207size_t perf_event__fprintf_stat_config(union perf_event *event, FILE *fp);
208
209int create_perf_stat_counter(struct perf_evsel *evsel,
210 struct perf_stat_config *config,
211 struct target *target);
212int perf_stat_synthesize_config(struct perf_stat_config *config,
213 struct perf_tool *tool,
214 struct perf_evlist *evlist,
215 perf_event__handler_t process,
216 bool attrs);
217void
218perf_evlist__print_counters(struct perf_evlist *evlist,
219 struct perf_stat_config *config,
220 struct target *_target,
221 struct timespec *ts,
222 int argc, const char **argv);
174#endif 223#endif
diff --git a/tools/perf/util/strbuf.c b/tools/perf/util/strbuf.c
index 3d1cf5bf7f18..9005fbe0780e 100644
--- a/tools/perf/util/strbuf.c
+++ b/tools/perf/util/strbuf.c
@@ -98,19 +98,25 @@ static int strbuf_addv(struct strbuf *sb, const char *fmt, va_list ap)
98 98
99 va_copy(ap_saved, ap); 99 va_copy(ap_saved, ap);
100 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); 100 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
101 if (len < 0) 101 if (len < 0) {
102 va_end(ap_saved);
102 return len; 103 return len;
104 }
103 if (len > strbuf_avail(sb)) { 105 if (len > strbuf_avail(sb)) {
104 ret = strbuf_grow(sb, len); 106 ret = strbuf_grow(sb, len);
105 if (ret) 107 if (ret) {
108 va_end(ap_saved);
106 return ret; 109 return ret;
110 }
107 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap_saved); 111 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap_saved);
108 va_end(ap_saved); 112 va_end(ap_saved);
109 if (len > strbuf_avail(sb)) { 113 if (len > strbuf_avail(sb)) {
110 pr_debug("this should not happen, your vsnprintf is broken"); 114 pr_debug("this should not happen, your vsnprintf is broken");
115 va_end(ap_saved);
111 return -EINVAL; 116 return -EINVAL;
112 } 117 }
113 } 118 }
119 va_end(ap_saved);
114 return strbuf_setlen(sb, sb->len + len); 120 return strbuf_setlen(sb, sb->len + len);
115} 121}
116 122
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 29770ea61768..66a84d5846c8 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -324,7 +324,17 @@ int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss)
324 plt_entry_size = 16; 324 plt_entry_size = 16;
325 break; 325 break;
326 326
327 default: /* FIXME: s390/alpha/mips/parisc/poperpc/sh/sparc/xtensa need to be checked */ 327 case EM_SPARC:
328 plt_header_size = 48;
329 plt_entry_size = 12;
330 break;
331
332 case EM_SPARCV9:
333 plt_header_size = 128;
334 plt_entry_size = 32;
335 break;
336
337 default: /* FIXME: s390/alpha/mips/parisc/poperpc/sh/xtensa need to be checked */
328 plt_header_size = shdr_plt.sh_entsize; 338 plt_header_size = shdr_plt.sh_entsize;
329 plt_entry_size = shdr_plt.sh_entsize; 339 plt_entry_size = shdr_plt.sh_entsize;
330 break; 340 break;
@@ -1947,6 +1957,34 @@ void kcore_extract__delete(struct kcore_extract *kce)
1947} 1957}
1948 1958
1949#ifdef HAVE_GELF_GETNOTE_SUPPORT 1959#ifdef HAVE_GELF_GETNOTE_SUPPORT
1960
1961static void sdt_adjust_loc(struct sdt_note *tmp, GElf_Addr base_off)
1962{
1963 if (!base_off)
1964 return;
1965
1966 if (tmp->bit32)
1967 tmp->addr.a32[SDT_NOTE_IDX_LOC] =
1968 tmp->addr.a32[SDT_NOTE_IDX_LOC] + base_off -
1969 tmp->addr.a32[SDT_NOTE_IDX_BASE];
1970 else
1971 tmp->addr.a64[SDT_NOTE_IDX_LOC] =
1972 tmp->addr.a64[SDT_NOTE_IDX_LOC] + base_off -
1973 tmp->addr.a64[SDT_NOTE_IDX_BASE];
1974}
1975
1976static void sdt_adjust_refctr(struct sdt_note *tmp, GElf_Addr base_addr,
1977 GElf_Addr base_off)
1978{
1979 if (!base_off)
1980 return;
1981
1982 if (tmp->bit32 && tmp->addr.a32[SDT_NOTE_IDX_REFCTR])
1983 tmp->addr.a32[SDT_NOTE_IDX_REFCTR] -= (base_addr - base_off);
1984 else if (tmp->addr.a64[SDT_NOTE_IDX_REFCTR])
1985 tmp->addr.a64[SDT_NOTE_IDX_REFCTR] -= (base_addr - base_off);
1986}
1987
1950/** 1988/**
1951 * populate_sdt_note : Parse raw data and identify SDT note 1989 * populate_sdt_note : Parse raw data and identify SDT note
1952 * @elf: elf of the opened file 1990 * @elf: elf of the opened file
@@ -1964,7 +2002,6 @@ static int populate_sdt_note(Elf **elf, const char *data, size_t len,
1964 const char *provider, *name, *args; 2002 const char *provider, *name, *args;
1965 struct sdt_note *tmp = NULL; 2003 struct sdt_note *tmp = NULL;
1966 GElf_Ehdr ehdr; 2004 GElf_Ehdr ehdr;
1967 GElf_Addr base_off = 0;
1968 GElf_Shdr shdr; 2005 GElf_Shdr shdr;
1969 int ret = -EINVAL; 2006 int ret = -EINVAL;
1970 2007
@@ -2060,17 +2097,12 @@ static int populate_sdt_note(Elf **elf, const char *data, size_t len,
2060 * base address in the description of the SDT note. If its different, 2097 * base address in the description of the SDT note. If its different,
2061 * then accordingly, adjust the note location. 2098 * then accordingly, adjust the note location.
2062 */ 2099 */
2063 if (elf_section_by_name(*elf, &ehdr, &shdr, SDT_BASE_SCN, NULL)) { 2100 if (elf_section_by_name(*elf, &ehdr, &shdr, SDT_BASE_SCN, NULL))
2064 base_off = shdr.sh_offset; 2101 sdt_adjust_loc(tmp, shdr.sh_offset);
2065 if (base_off) { 2102
2066 if (tmp->bit32) 2103 /* Adjust reference counter offset */
2067 tmp->addr.a32[0] = tmp->addr.a32[0] + base_off - 2104 if (elf_section_by_name(*elf, &ehdr, &shdr, SDT_PROBES_SCN, NULL))
2068 tmp->addr.a32[1]; 2105 sdt_adjust_refctr(tmp, shdr.sh_addr, shdr.sh_offset);
2069 else
2070 tmp->addr.a64[0] = tmp->addr.a64[0] + base_off -
2071 tmp->addr.a64[1];
2072 }
2073 }
2074 2106
2075 list_add_tail(&tmp->note_list, sdt_notes); 2107 list_add_tail(&tmp->note_list, sdt_notes);
2076 return 0; 2108 return 0;
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index f25fae4b5743..d026d215bdc6 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -123,7 +123,8 @@ struct symbol_conf {
123 const char *vmlinux_name, 123 const char *vmlinux_name,
124 *kallsyms_name, 124 *kallsyms_name,
125 *source_prefix, 125 *source_prefix,
126 *field_sep; 126 *field_sep,
127 *graph_function;
127 const char *default_guest_vmlinux_name, 128 const char *default_guest_vmlinux_name,
128 *default_guest_kallsyms, 129 *default_guest_kallsyms,
129 *default_guest_modules; 130 *default_guest_modules;
@@ -379,12 +380,19 @@ int get_sdt_note_list(struct list_head *head, const char *target);
379int cleanup_sdt_note_list(struct list_head *sdt_notes); 380int cleanup_sdt_note_list(struct list_head *sdt_notes);
380int sdt_notes__get_count(struct list_head *start); 381int sdt_notes__get_count(struct list_head *start);
381 382
383#define SDT_PROBES_SCN ".probes"
382#define SDT_BASE_SCN ".stapsdt.base" 384#define SDT_BASE_SCN ".stapsdt.base"
383#define SDT_NOTE_SCN ".note.stapsdt" 385#define SDT_NOTE_SCN ".note.stapsdt"
384#define SDT_NOTE_TYPE 3 386#define SDT_NOTE_TYPE 3
385#define SDT_NOTE_NAME "stapsdt" 387#define SDT_NOTE_NAME "stapsdt"
386#define NR_ADDR 3 388#define NR_ADDR 3
387 389
390enum {
391 SDT_NOTE_IDX_LOC = 0,
392 SDT_NOTE_IDX_BASE,
393 SDT_NOTE_IDX_REFCTR,
394};
395
388struct mem_info *mem_info__new(void); 396struct mem_info *mem_info__new(void);
389struct mem_info *mem_info__get(struct mem_info *mi); 397struct mem_info *mem_info__get(struct mem_info *mi);
390void mem_info__put(struct mem_info *mi); 398void mem_info__put(struct mem_info *mi);
diff --git a/tools/perf/util/thread-stack.c b/tools/perf/util/thread-stack.c
index dd17d6a38d3a..61a4286a74dc 100644
--- a/tools/perf/util/thread-stack.c
+++ b/tools/perf/util/thread-stack.c
@@ -36,6 +36,7 @@
36 * @branch_count: the branch count when the entry was created 36 * @branch_count: the branch count when the entry was created
37 * @cp: call path 37 * @cp: call path
38 * @no_call: a 'call' was not seen 38 * @no_call: a 'call' was not seen
39 * @trace_end: a 'call' but trace ended
39 */ 40 */
40struct thread_stack_entry { 41struct thread_stack_entry {
41 u64 ret_addr; 42 u64 ret_addr;
@@ -44,6 +45,7 @@ struct thread_stack_entry {
44 u64 branch_count; 45 u64 branch_count;
45 struct call_path *cp; 46 struct call_path *cp;
46 bool no_call; 47 bool no_call;
48 bool trace_end;
47}; 49};
48 50
49/** 51/**
@@ -112,7 +114,8 @@ static struct thread_stack *thread_stack__new(struct thread *thread,
112 return ts; 114 return ts;
113} 115}
114 116
115static int thread_stack__push(struct thread_stack *ts, u64 ret_addr) 117static int thread_stack__push(struct thread_stack *ts, u64 ret_addr,
118 bool trace_end)
116{ 119{
117 int err = 0; 120 int err = 0;
118 121
@@ -124,6 +127,7 @@ static int thread_stack__push(struct thread_stack *ts, u64 ret_addr)
124 } 127 }
125 } 128 }
126 129
130 ts->stack[ts->cnt].trace_end = trace_end;
127 ts->stack[ts->cnt++].ret_addr = ret_addr; 131 ts->stack[ts->cnt++].ret_addr = ret_addr;
128 132
129 return err; 133 return err;
@@ -150,6 +154,18 @@ static void thread_stack__pop(struct thread_stack *ts, u64 ret_addr)
150 } 154 }
151} 155}
152 156
157static void thread_stack__pop_trace_end(struct thread_stack *ts)
158{
159 size_t i;
160
161 for (i = ts->cnt; i; ) {
162 if (ts->stack[--i].trace_end)
163 ts->cnt = i;
164 else
165 return;
166 }
167}
168
153static bool thread_stack__in_kernel(struct thread_stack *ts) 169static bool thread_stack__in_kernel(struct thread_stack *ts)
154{ 170{
155 if (!ts->cnt) 171 if (!ts->cnt)
@@ -254,10 +270,19 @@ int thread_stack__event(struct thread *thread, u32 flags, u64 from_ip,
254 ret_addr = from_ip + insn_len; 270 ret_addr = from_ip + insn_len;
255 if (ret_addr == to_ip) 271 if (ret_addr == to_ip)
256 return 0; /* Zero-length calls are excluded */ 272 return 0; /* Zero-length calls are excluded */
257 return thread_stack__push(thread->ts, ret_addr); 273 return thread_stack__push(thread->ts, ret_addr,
258 } else if (flags & PERF_IP_FLAG_RETURN) { 274 flags & PERF_IP_FLAG_TRACE_END);
259 if (!from_ip) 275 } else if (flags & PERF_IP_FLAG_TRACE_BEGIN) {
260 return 0; 276 /*
277 * If the caller did not change the trace number (which would
278 * have flushed the stack) then try to make sense of the stack.
279 * Possibly, tracing began after returning to the current
280 * address, so try to pop that. Also, do not expect a call made
281 * when the trace ended, to return, so pop that.
282 */
283 thread_stack__pop(thread->ts, to_ip);
284 thread_stack__pop_trace_end(thread->ts);
285 } else if ((flags & PERF_IP_FLAG_RETURN) && from_ip) {
261 thread_stack__pop(thread->ts, to_ip); 286 thread_stack__pop(thread->ts, to_ip);
262 } 287 }
263 288
@@ -285,20 +310,46 @@ void thread_stack__free(struct thread *thread)
285 } 310 }
286} 311}
287 312
313static inline u64 callchain_context(u64 ip, u64 kernel_start)
314{
315 return ip < kernel_start ? PERF_CONTEXT_USER : PERF_CONTEXT_KERNEL;
316}
317
288void thread_stack__sample(struct thread *thread, struct ip_callchain *chain, 318void thread_stack__sample(struct thread *thread, struct ip_callchain *chain,
289 size_t sz, u64 ip) 319 size_t sz, u64 ip, u64 kernel_start)
290{ 320{
291 size_t i; 321 u64 context = callchain_context(ip, kernel_start);
322 u64 last_context;
323 size_t i, j;
292 324
293 if (!thread || !thread->ts) 325 if (sz < 2) {
294 chain->nr = 1; 326 chain->nr = 0;
295 else 327 return;
296 chain->nr = min(sz, thread->ts->cnt + 1); 328 }
329
330 chain->ips[0] = context;
331 chain->ips[1] = ip;
297 332
298 chain->ips[0] = ip; 333 if (!thread || !thread->ts) {
334 chain->nr = 2;
335 return;
336 }
337
338 last_context = context;
339
340 for (i = 2, j = 1; i < sz && j <= thread->ts->cnt; i++, j++) {
341 ip = thread->ts->stack[thread->ts->cnt - j].ret_addr;
342 context = callchain_context(ip, kernel_start);
343 if (context != last_context) {
344 if (i >= sz - 1)
345 break;
346 chain->ips[i++] = context;
347 last_context = context;
348 }
349 chain->ips[i] = ip;
350 }
299 351
300 for (i = 1; i < chain->nr; i++) 352 chain->nr = i;
301 chain->ips[i] = thread->ts->stack[thread->ts->cnt - i].ret_addr;
302} 353}
303 354
304struct call_return_processor * 355struct call_return_processor *
@@ -332,7 +383,7 @@ void call_return_processor__free(struct call_return_processor *crp)
332 383
333static int thread_stack__push_cp(struct thread_stack *ts, u64 ret_addr, 384static int thread_stack__push_cp(struct thread_stack *ts, u64 ret_addr,
334 u64 timestamp, u64 ref, struct call_path *cp, 385 u64 timestamp, u64 ref, struct call_path *cp,
335 bool no_call) 386 bool no_call, bool trace_end)
336{ 387{
337 struct thread_stack_entry *tse; 388 struct thread_stack_entry *tse;
338 int err; 389 int err;
@@ -350,6 +401,7 @@ static int thread_stack__push_cp(struct thread_stack *ts, u64 ret_addr,
350 tse->branch_count = ts->branch_count; 401 tse->branch_count = ts->branch_count;
351 tse->cp = cp; 402 tse->cp = cp;
352 tse->no_call = no_call; 403 tse->no_call = no_call;
404 tse->trace_end = trace_end;
353 405
354 return 0; 406 return 0;
355} 407}
@@ -423,7 +475,7 @@ static int thread_stack__bottom(struct thread *thread, struct thread_stack *ts,
423 return -ENOMEM; 475 return -ENOMEM;
424 476
425 return thread_stack__push_cp(thread->ts, ip, sample->time, ref, cp, 477 return thread_stack__push_cp(thread->ts, ip, sample->time, ref, cp,
426 true); 478 true, false);
427} 479}
428 480
429static int thread_stack__no_call_return(struct thread *thread, 481static int thread_stack__no_call_return(struct thread *thread,
@@ -455,7 +507,7 @@ static int thread_stack__no_call_return(struct thread *thread,
455 if (!cp) 507 if (!cp)
456 return -ENOMEM; 508 return -ENOMEM;
457 return thread_stack__push_cp(ts, 0, sample->time, ref, 509 return thread_stack__push_cp(ts, 0, sample->time, ref,
458 cp, true); 510 cp, true, false);
459 } 511 }
460 } else if (thread_stack__in_kernel(ts) && sample->ip < ks) { 512 } else if (thread_stack__in_kernel(ts) && sample->ip < ks) {
461 /* Return to userspace, so pop all kernel addresses */ 513 /* Return to userspace, so pop all kernel addresses */
@@ -480,7 +532,7 @@ static int thread_stack__no_call_return(struct thread *thread,
480 return -ENOMEM; 532 return -ENOMEM;
481 533
482 err = thread_stack__push_cp(ts, sample->addr, sample->time, ref, cp, 534 err = thread_stack__push_cp(ts, sample->addr, sample->time, ref, cp,
483 true); 535 true, false);
484 if (err) 536 if (err)
485 return err; 537 return err;
486 538
@@ -500,7 +552,7 @@ static int thread_stack__trace_begin(struct thread *thread,
500 552
501 /* Pop trace end */ 553 /* Pop trace end */
502 tse = &ts->stack[ts->cnt - 1]; 554 tse = &ts->stack[ts->cnt - 1];
503 if (tse->cp->sym == NULL && tse->cp->ip == 0) { 555 if (tse->trace_end) {
504 err = thread_stack__call_return(thread, ts, --ts->cnt, 556 err = thread_stack__call_return(thread, ts, --ts->cnt,
505 timestamp, ref, false); 557 timestamp, ref, false);
506 if (err) 558 if (err)
@@ -529,7 +581,7 @@ static int thread_stack__trace_end(struct thread_stack *ts,
529 ret_addr = sample->ip + sample->insn_len; 581 ret_addr = sample->ip + sample->insn_len;
530 582
531 return thread_stack__push_cp(ts, ret_addr, sample->time, ref, cp, 583 return thread_stack__push_cp(ts, ret_addr, sample->time, ref, cp,
532 false); 584 false, true);
533} 585}
534 586
535int thread_stack__process(struct thread *thread, struct comm *comm, 587int thread_stack__process(struct thread *thread, struct comm *comm,
@@ -579,6 +631,7 @@ int thread_stack__process(struct thread *thread, struct comm *comm,
579 ts->last_time = sample->time; 631 ts->last_time = sample->time;
580 632
581 if (sample->flags & PERF_IP_FLAG_CALL) { 633 if (sample->flags & PERF_IP_FLAG_CALL) {
634 bool trace_end = sample->flags & PERF_IP_FLAG_TRACE_END;
582 struct call_path_root *cpr = ts->crp->cpr; 635 struct call_path_root *cpr = ts->crp->cpr;
583 struct call_path *cp; 636 struct call_path *cp;
584 u64 ret_addr; 637 u64 ret_addr;
@@ -596,7 +649,7 @@ int thread_stack__process(struct thread *thread, struct comm *comm,
596 if (!cp) 649 if (!cp)
597 return -ENOMEM; 650 return -ENOMEM;
598 err = thread_stack__push_cp(ts, ret_addr, sample->time, ref, 651 err = thread_stack__push_cp(ts, ret_addr, sample->time, ref,
599 cp, false); 652 cp, false, trace_end);
600 } else if (sample->flags & PERF_IP_FLAG_RETURN) { 653 } else if (sample->flags & PERF_IP_FLAG_RETURN) {
601 if (!sample->ip || !sample->addr) 654 if (!sample->ip || !sample->addr)
602 return 0; 655 return 0;
diff --git a/tools/perf/util/thread-stack.h b/tools/perf/util/thread-stack.h
index b7e41c4ebfdd..f97c00a8c251 100644
--- a/tools/perf/util/thread-stack.h
+++ b/tools/perf/util/thread-stack.h
@@ -84,7 +84,7 @@ int thread_stack__event(struct thread *thread, u32 flags, u64 from_ip,
84 u64 to_ip, u16 insn_len, u64 trace_nr); 84 u64 to_ip, u16 insn_len, u64 trace_nr);
85void thread_stack__set_trace_nr(struct thread *thread, u64 trace_nr); 85void thread_stack__set_trace_nr(struct thread *thread, u64 trace_nr);
86void thread_stack__sample(struct thread *thread, struct ip_callchain *chain, 86void thread_stack__sample(struct thread *thread, struct ip_callchain *chain,
87 size_t sz, u64 ip); 87 size_t sz, u64 ip, u64 kernel_start);
88int thread_stack__flush(struct thread *thread); 88int thread_stack__flush(struct thread *thread);
89void thread_stack__free(struct thread *thread); 89void thread_stack__free(struct thread *thread);
90size_t thread_stack__depth(struct thread *thread); 90size_t thread_stack__depth(struct thread *thread);
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 2048d393ece6..3d9ed7d0e281 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -330,7 +330,8 @@ static int thread__prepare_access(struct thread *thread)
330} 330}
331 331
332static int thread__clone_map_groups(struct thread *thread, 332static int thread__clone_map_groups(struct thread *thread,
333 struct thread *parent) 333 struct thread *parent,
334 bool do_maps_clone)
334{ 335{
335 /* This is new thread, we share map groups for process. */ 336 /* This is new thread, we share map groups for process. */
336 if (thread->pid_ == parent->pid_) 337 if (thread->pid_ == parent->pid_)
@@ -341,15 +342,11 @@ static int thread__clone_map_groups(struct thread *thread,
341 thread->pid_, thread->tid, parent->pid_, parent->tid); 342 thread->pid_, thread->tid, parent->pid_, parent->tid);
342 return 0; 343 return 0;
343 } 344 }
344
345 /* But this one is new process, copy maps. */ 345 /* But this one is new process, copy maps. */
346 if (map_groups__clone(thread, parent->mg) < 0) 346 return do_maps_clone ? map_groups__clone(thread, parent->mg) : 0;
347 return -ENOMEM;
348
349 return 0;
350} 347}
351 348
352int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp) 349int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp, bool do_maps_clone)
353{ 350{
354 if (parent->comm_set) { 351 if (parent->comm_set) {
355 const char *comm = thread__comm_str(parent); 352 const char *comm = thread__comm_str(parent);
@@ -362,7 +359,7 @@ int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp)
362 } 359 }
363 360
364 thread->ppid = parent->tid; 361 thread->ppid = parent->tid;
365 return thread__clone_map_groups(thread, parent); 362 return thread__clone_map_groups(thread, parent, do_maps_clone);
366} 363}
367 364
368void thread__find_cpumode_addr_location(struct thread *thread, u64 addr, 365void thread__find_cpumode_addr_location(struct thread *thread, u64 addr,
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 07606aa6998d..30e2b4c165fe 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -42,6 +42,8 @@ struct thread {
42 void *addr_space; 42 void *addr_space;
43 struct unwind_libunwind_ops *unwind_libunwind_ops; 43 struct unwind_libunwind_ops *unwind_libunwind_ops;
44#endif 44#endif
45 bool filter;
46 int filter_entry_depth;
45}; 47};
46 48
47struct machine; 49struct machine;
@@ -87,7 +89,7 @@ struct comm *thread__comm(const struct thread *thread);
87struct comm *thread__exec_comm(const struct thread *thread); 89struct comm *thread__exec_comm(const struct thread *thread);
88const char *thread__comm_str(const struct thread *thread); 90const char *thread__comm_str(const struct thread *thread);
89int thread__insert_map(struct thread *thread, struct map *map); 91int thread__insert_map(struct thread *thread, struct map *map);
90int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp); 92int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp, bool do_maps_clone);
91size_t thread__fprintf(struct thread *thread, FILE *fp); 93size_t thread__fprintf(struct thread *thread, FILE *fp);
92 94
93struct thread *thread__main_thread(struct machine *machine, struct thread *thread); 95struct thread *thread__main_thread(struct machine *machine, struct thread *thread);
diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h
index 183c91453522..56e4ca54020a 100644
--- a/tools/perf/util/tool.h
+++ b/tools/perf/util/tool.h
@@ -26,15 +26,12 @@ typedef int (*event_attr_op)(struct perf_tool *tool,
26 union perf_event *event, 26 union perf_event *event,
27 struct perf_evlist **pevlist); 27 struct perf_evlist **pevlist);
28 28
29typedef int (*event_op2)(struct perf_tool *tool, union perf_event *event, 29typedef int (*event_op2)(struct perf_session *session, union perf_event *event);
30 struct perf_session *session); 30typedef s64 (*event_op3)(struct perf_session *session, union perf_event *event);
31 31
32typedef int (*event_oe)(struct perf_tool *tool, union perf_event *event, 32typedef int (*event_oe)(struct perf_tool *tool, union perf_event *event,
33 struct ordered_events *oe); 33 struct ordered_events *oe);
34 34
35typedef s64 (*event_op3)(struct perf_tool *tool, union perf_event *event,
36 struct perf_session *session);
37
38enum show_feature_header { 35enum show_feature_header {
39 SHOW_FEAT_NO_HEADER = 0, 36 SHOW_FEAT_NO_HEADER = 0,
40 SHOW_FEAT_HEADER, 37 SHOW_FEAT_HEADER,
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index 7b0ca7cbb7de..8ad8e755127b 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -531,12 +531,14 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs,
531 "/tmp/perf-XXXXXX"); 531 "/tmp/perf-XXXXXX");
532 if (!mkstemp(tdata->temp_file)) { 532 if (!mkstemp(tdata->temp_file)) {
533 pr_debug("Can't make temp file"); 533 pr_debug("Can't make temp file");
534 free(tdata);
534 return NULL; 535 return NULL;
535 } 536 }
536 537
537 temp_fd = open(tdata->temp_file, O_RDWR); 538 temp_fd = open(tdata->temp_file, O_RDWR);
538 if (temp_fd < 0) { 539 if (temp_fd < 0) {
539 pr_debug("Can't read '%s'", tdata->temp_file); 540 pr_debug("Can't read '%s'", tdata->temp_file);
541 free(tdata);
540 return NULL; 542 return NULL;
541 } 543 }
542 544
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index e76214f8d596..32e558a65af3 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -33,14 +33,15 @@ static int get_common_field(struct scripting_context *context,
33 int *offset, int *size, const char *type) 33 int *offset, int *size, const char *type)
34{ 34{
35 struct tep_handle *pevent = context->pevent; 35 struct tep_handle *pevent = context->pevent;
36 struct event_format *event; 36 struct tep_event_format *event;
37 struct format_field *field; 37 struct tep_format_field *field;
38 38
39 if (!*size) { 39 if (!*size) {
40 if (!pevent->events) 40
41 event = tep_get_first_event(pevent);
42 if (!event)
41 return 0; 43 return 0;
42 44
43 event = pevent->events[0];
44 field = tep_find_common_field(event, type); 45 field = tep_find_common_field(event, type);
45 if (!field) 46 if (!field)
46 return 0; 47 return 0;
@@ -94,9 +95,9 @@ int common_pc(struct scripting_context *context)
94} 95}
95 96
96unsigned long long 97unsigned long long
97raw_field_value(struct event_format *event, const char *name, void *data) 98raw_field_value(struct tep_event_format *event, const char *name, void *data)
98{ 99{
99 struct format_field *field; 100 struct tep_format_field *field;
100 unsigned long long val; 101 unsigned long long val;
101 102
102 field = tep_find_any_field(event, name); 103 field = tep_find_any_field(event, name);
@@ -108,12 +109,12 @@ raw_field_value(struct event_format *event, const char *name, void *data)
108 return val; 109 return val;
109} 110}
110 111
111unsigned long long read_size(struct event_format *event, void *ptr, int size) 112unsigned long long read_size(struct tep_event_format *event, void *ptr, int size)
112{ 113{
113 return tep_read_number(event->pevent, ptr, size); 114 return tep_read_number(event->pevent, ptr, size);
114} 115}
115 116
116void event_format__fprintf(struct event_format *event, 117void event_format__fprintf(struct tep_event_format *event,
117 int cpu, void *data, int size, FILE *fp) 118 int cpu, void *data, int size, FILE *fp)
118{ 119{
119 struct tep_record record; 120 struct tep_record record;
@@ -130,7 +131,7 @@ void event_format__fprintf(struct event_format *event,
130 trace_seq_destroy(&s); 131 trace_seq_destroy(&s);
131} 132}
132 133
133void event_format__print(struct event_format *event, 134void event_format__print(struct tep_event_format *event,
134 int cpu, void *data, int size) 135 int cpu, void *data, int size)
135{ 136{
136 return event_format__fprintf(event, cpu, data, size, stdout); 137 return event_format__fprintf(event, cpu, data, size, stdout);
@@ -158,6 +159,7 @@ void parse_ftrace_printk(struct tep_handle *pevent,
158 printk = strdup(fmt+1); 159 printk = strdup(fmt+1);
159 line = strtok_r(NULL, "\n", &next); 160 line = strtok_r(NULL, "\n", &next);
160 tep_register_print_string(pevent, printk, addr); 161 tep_register_print_string(pevent, printk, addr);
162 free(printk);
161 } 163 }
162} 164}
163 165
@@ -188,29 +190,33 @@ int parse_event_file(struct tep_handle *pevent,
188 return tep_parse_event(pevent, buf, size, sys); 190 return tep_parse_event(pevent, buf, size, sys);
189} 191}
190 192
191struct event_format *trace_find_next_event(struct tep_handle *pevent, 193struct tep_event_format *trace_find_next_event(struct tep_handle *pevent,
192 struct event_format *event) 194 struct tep_event_format *event)
193{ 195{
194 static int idx; 196 static int idx;
197 int events_count;
198 struct tep_event_format *all_events;
195 199
196 if (!pevent || !pevent->events) 200 all_events = tep_get_first_event(pevent);
201 events_count = tep_get_events_count(pevent);
202 if (!pevent || !all_events || events_count < 1)
197 return NULL; 203 return NULL;
198 204
199 if (!event) { 205 if (!event) {
200 idx = 0; 206 idx = 0;
201 return pevent->events[0]; 207 return all_events;
202 } 208 }
203 209
204 if (idx < pevent->nr_events && event == pevent->events[idx]) { 210 if (idx < events_count && event == (all_events + idx)) {
205 idx++; 211 idx++;
206 if (idx == pevent->nr_events) 212 if (idx == events_count)
207 return NULL; 213 return NULL;
208 return pevent->events[idx]; 214 return (all_events + idx);
209 } 215 }
210 216
211 for (idx = 1; idx < pevent->nr_events; idx++) { 217 for (idx = 1; idx < events_count; idx++) {
212 if (event == pevent->events[idx - 1]) 218 if (event == (all_events + (idx - 1)))
213 return pevent->events[idx]; 219 return (all_events + idx);
214 } 220 }
215 return NULL; 221 return NULL;
216} 222}
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index 3dfc1db6b25b..76f12c705ef9 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -102,7 +102,7 @@ static unsigned int read4(struct tep_handle *pevent)
102 102
103 if (do_read(&data, 4) < 0) 103 if (do_read(&data, 4) < 0)
104 return 0; 104 return 0;
105 return __data2host4(pevent, data); 105 return __tep_data2host4(pevent, data);
106} 106}
107 107
108static unsigned long long read8(struct tep_handle *pevent) 108static unsigned long long read8(struct tep_handle *pevent)
@@ -111,7 +111,7 @@ static unsigned long long read8(struct tep_handle *pevent)
111 111
112 if (do_read(&data, 8) < 0) 112 if (do_read(&data, 8) < 0)
113 return 0; 113 return 0;
114 return __data2host8(pevent, data); 114 return __tep_data2host8(pevent, data);
115} 115}
116 116
117static char *read_string(void) 117static char *read_string(void)
@@ -241,7 +241,7 @@ static int read_header_files(struct tep_handle *pevent)
241 * The commit field in the page is of type long, 241 * The commit field in the page is of type long,
242 * use that instead, since it represents the kernel. 242 * use that instead, since it represents the kernel.
243 */ 243 */
244 tep_set_long_size(pevent, pevent->header_page_size_size); 244 tep_set_long_size(pevent, tep_get_header_page_size(pevent));
245 } 245 }
246 free(header_page); 246 free(header_page);
247 247
@@ -297,10 +297,8 @@ static int read_event_file(struct tep_handle *pevent, char *sys,
297 } 297 }
298 298
299 ret = do_read(buf, size); 299 ret = do_read(buf, size);
300 if (ret < 0) { 300 if (ret < 0)
301 free(buf);
302 goto out; 301 goto out;
303 }
304 302
305 ret = parse_event_file(pevent, buf, size, sys); 303 ret = parse_event_file(pevent, buf, size, sys);
306 if (ret < 0) 304 if (ret < 0)
@@ -349,9 +347,12 @@ static int read_event_files(struct tep_handle *pevent)
349 for (x=0; x < count; x++) { 347 for (x=0; x < count; x++) {
350 size = read8(pevent); 348 size = read8(pevent);
351 ret = read_event_file(pevent, sys, size); 349 ret = read_event_file(pevent, sys, size);
352 if (ret) 350 if (ret) {
351 free(sys);
353 return ret; 352 return ret;
353 }
354 } 354 }
355 free(sys);
355 } 356 }
356 return 0; 357 return 0;
357} 358}
diff --git a/tools/perf/util/trace-event.c b/tools/perf/util/trace-event.c
index 58bb72f266f3..95664b2f771e 100644
--- a/tools/perf/util/trace-event.c
+++ b/tools/perf/util/trace-event.c
@@ -72,12 +72,12 @@ void trace_event__cleanup(struct trace_event *t)
72/* 72/*
73 * Returns pointer with encoded error via <linux/err.h> interface. 73 * Returns pointer with encoded error via <linux/err.h> interface.
74 */ 74 */
75static struct event_format* 75static struct tep_event_format*
76tp_format(const char *sys, const char *name) 76tp_format(const char *sys, const char *name)
77{ 77{
78 char *tp_dir = get_events_file(sys); 78 char *tp_dir = get_events_file(sys);
79 struct tep_handle *pevent = tevent.pevent; 79 struct tep_handle *pevent = tevent.pevent;
80 struct event_format *event = NULL; 80 struct tep_event_format *event = NULL;
81 char path[PATH_MAX]; 81 char path[PATH_MAX];
82 size_t size; 82 size_t size;
83 char *data; 83 char *data;
@@ -102,7 +102,7 @@ tp_format(const char *sys, const char *name)
102/* 102/*
103 * Returns pointer with encoded error via <linux/err.h> interface. 103 * Returns pointer with encoded error via <linux/err.h> interface.
104 */ 104 */
105struct event_format* 105struct tep_event_format*
106trace_event__tp_format(const char *sys, const char *name) 106trace_event__tp_format(const char *sys, const char *name)
107{ 107{
108 if (!tevent_initialized && trace_event__init2()) 108 if (!tevent_initialized && trace_event__init2())
@@ -111,7 +111,7 @@ trace_event__tp_format(const char *sys, const char *name)
111 return tp_format(sys, name); 111 return tp_format(sys, name);
112} 112}
113 113
114struct event_format *trace_event__tp_format_id(int id) 114struct tep_event_format *trace_event__tp_format_id(int id)
115{ 115{
116 if (!tevent_initialized && trace_event__init2()) 116 if (!tevent_initialized && trace_event__init2())
117 return ERR_PTR(-ENOMEM); 117 return ERR_PTR(-ENOMEM);
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index 40204ec3a7a2..f024d73bfc40 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -3,6 +3,7 @@
3#define _PERF_UTIL_TRACE_EVENT_H 3#define _PERF_UTIL_TRACE_EVENT_H
4 4
5#include <traceevent/event-parse.h> 5#include <traceevent/event-parse.h>
6#include <traceevent/trace-seq.h>
6#include "parse-events.h" 7#include "parse-events.h"
7 8
8struct machine; 9struct machine;
@@ -10,28 +11,28 @@ struct perf_sample;
10union perf_event; 11union perf_event;
11struct perf_tool; 12struct perf_tool;
12struct thread; 13struct thread;
13struct plugin_list; 14struct tep_plugin_list;
14 15
15struct trace_event { 16struct trace_event {
16 struct tep_handle *pevent; 17 struct tep_handle *pevent;
17 struct plugin_list *plugin_list; 18 struct tep_plugin_list *plugin_list;
18}; 19};
19 20
20int trace_event__init(struct trace_event *t); 21int trace_event__init(struct trace_event *t);
21void trace_event__cleanup(struct trace_event *t); 22void trace_event__cleanup(struct trace_event *t);
22int trace_event__register_resolver(struct machine *machine, 23int trace_event__register_resolver(struct machine *machine,
23 tep_func_resolver_t *func); 24 tep_func_resolver_t *func);
24struct event_format* 25struct tep_event_format*
25trace_event__tp_format(const char *sys, const char *name); 26trace_event__tp_format(const char *sys, const char *name);
26 27
27struct event_format *trace_event__tp_format_id(int id); 28struct tep_event_format *trace_event__tp_format_id(int id);
28 29
29int bigendian(void); 30int bigendian(void);
30 31
31void event_format__fprintf(struct event_format *event, 32void event_format__fprintf(struct tep_event_format *event,
32 int cpu, void *data, int size, FILE *fp); 33 int cpu, void *data, int size, FILE *fp);
33 34
34void event_format__print(struct event_format *event, 35void event_format__print(struct tep_event_format *event,
35 int cpu, void *data, int size); 36 int cpu, void *data, int size);
36 37
37int parse_ftrace_file(struct tep_handle *pevent, char *buf, unsigned long size); 38int parse_ftrace_file(struct tep_handle *pevent, char *buf, unsigned long size);
@@ -39,7 +40,7 @@ int parse_event_file(struct tep_handle *pevent,
39 char *buf, unsigned long size, char *sys); 40 char *buf, unsigned long size, char *sys);
40 41
41unsigned long long 42unsigned long long
42raw_field_value(struct event_format *event, const char *name, void *data); 43raw_field_value(struct tep_event_format *event, const char *name, void *data);
43 44
44void parse_proc_kallsyms(struct tep_handle *pevent, char *file, unsigned int size); 45void parse_proc_kallsyms(struct tep_handle *pevent, char *file, unsigned int size);
45void parse_ftrace_printk(struct tep_handle *pevent, char *file, unsigned int size); 46void parse_ftrace_printk(struct tep_handle *pevent, char *file, unsigned int size);
@@ -47,9 +48,9 @@ void parse_saved_cmdline(struct tep_handle *pevent, char *file, unsigned int siz
47 48
48ssize_t trace_report(int fd, struct trace_event *tevent, bool repipe); 49ssize_t trace_report(int fd, struct trace_event *tevent, bool repipe);
49 50
50struct event_format *trace_find_next_event(struct tep_handle *pevent, 51struct tep_event_format *trace_find_next_event(struct tep_handle *pevent,
51 struct event_format *event); 52 struct tep_event_format *event);
52unsigned long long read_size(struct event_format *event, void *ptr, int size); 53unsigned long long read_size(struct tep_event_format *event, void *ptr, int size);
53unsigned long long eval_flag(const char *flag); 54unsigned long long eval_flag(const char *flag);
54 55
55int read_tracing_data(int fd, struct list_head *pattrs); 56int read_tracing_data(int fd, struct list_head *pattrs);
diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
index 6f318b15950e..5eff9bfc5758 100644
--- a/tools/perf/util/unwind-libdw.c
+++ b/tools/perf/util/unwind-libdw.c
@@ -45,13 +45,13 @@ static int __report_module(struct addr_location *al, u64 ip,
45 Dwarf_Addr s; 45 Dwarf_Addr s;
46 46
47 dwfl_module_info(mod, NULL, &s, NULL, NULL, NULL, NULL, NULL); 47 dwfl_module_info(mod, NULL, &s, NULL, NULL, NULL, NULL, NULL);
48 if (s != al->map->start) 48 if (s != al->map->start - al->map->pgoff)
49 mod = 0; 49 mod = 0;
50 } 50 }
51 51
52 if (!mod) 52 if (!mod)
53 mod = dwfl_report_elf(ui->dwfl, dso->short_name, 53 mod = dwfl_report_elf(ui->dwfl, dso->short_name,
54 (dso->symsrc_filename ? dso->symsrc_filename : dso->long_name), -1, al->map->start, 54 (dso->symsrc_filename ? dso->symsrc_filename : dso->long_name), -1, al->map->start - al->map->pgoff,
55 false); 55 false);
56 56
57 return mod && dwfl_addrmodule(ui->dwfl, ip) == mod ? 0 : -1; 57 return mod && dwfl_addrmodule(ui->dwfl, ip) == mod ? 0 : -1;
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index eac5b858a371..093352e93d50 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -221,7 +221,7 @@ out:
221 return err; 221 return err;
222} 222}
223 223
224static int copyfile_offset(int ifd, loff_t off_in, int ofd, loff_t off_out, u64 size) 224int copyfile_offset(int ifd, loff_t off_in, int ofd, loff_t off_out, u64 size)
225{ 225{
226 void *ptr; 226 void *ptr;
227 loff_t pgoff; 227 loff_t pgoff;
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index dc58254a2b69..14508ee7707a 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -6,6 +6,7 @@
6/* glibc 2.20 deprecates _BSD_SOURCE in favour of _DEFAULT_SOURCE */ 6/* glibc 2.20 deprecates _BSD_SOURCE in favour of _DEFAULT_SOURCE */
7#define _DEFAULT_SOURCE 1 7#define _DEFAULT_SOURCE 1
8 8
9#include <fcntl.h>
9#include <stdbool.h> 10#include <stdbool.h>
10#include <stddef.h> 11#include <stddef.h>
11#include <stdlib.h> 12#include <stdlib.h>
@@ -35,6 +36,7 @@ bool lsdir_no_dot_filter(const char *name, struct dirent *d);
35int copyfile(const char *from, const char *to); 36int copyfile(const char *from, const char *to);
36int copyfile_mode(const char *from, const char *to, mode_t mode); 37int copyfile_mode(const char *from, const char *to, mode_t mode);
37int copyfile_ns(const char *from, const char *to, struct nsinfo *nsi); 38int copyfile_ns(const char *from, const char *to, struct nsinfo *nsi);
39int copyfile_offset(int ifd, loff_t off_in, int ofd, loff_t off_out, u64 size);
38 40
39ssize_t readn(int fd, void *buf, size_t n); 41ssize_t readn(int fd, void *buf, size_t n);
40ssize_t writen(int fd, const void *buf, size_t n); 42ssize_t writen(int fd, const void *buf, size_t n);