aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/Makefile63
-rw-r--r--tools/build/Makefile2
-rw-r--r--tools/build/Makefile.feature44
-rw-r--r--tools/build/Makefile.include2
-rw-r--r--tools/build/feature/Makefile93
-rw-r--r--tools/build/feature/test-all.c5
-rw-r--r--tools/build/feature/test-bpf.c20
-rw-r--r--tools/hv/hv_fcopy_daemon.c24
-rw-r--r--tools/hv/hv_vss_daemon.c2
-rw-r--r--tools/include/linux/bitmap.h (renamed from tools/perf/util/include/linux/bitmap.h)2
-rw-r--r--tools/include/linux/list.h753
-rw-r--r--tools/include/linux/string.h15
-rw-r--r--tools/lib/bitmap.c (renamed from tools/perf/util/bitmap.c)0
-rw-r--r--tools/lib/bpf/Makefile32
-rw-r--r--tools/lib/bpf/bpf.c18
-rw-r--r--tools/lib/bpf/bpf.h2
-rw-r--r--tools/lib/bpf/libbpf.c412
-rw-r--r--tools/lib/bpf/libbpf.h88
-rw-r--r--tools/lib/find_bit.c84
-rw-r--r--tools/lib/lockdep/Makefile2
-rw-r--r--tools/lib/string.c89
-rw-r--r--tools/lib/subcmd/Build7
-rw-r--r--tools/lib/subcmd/Makefile48
-rw-r--r--tools/lib/subcmd/exec-cmd.c209
-rw-r--r--tools/lib/subcmd/exec-cmd.h16
-rw-r--r--tools/lib/subcmd/help.c (renamed from tools/perf/util/help.c)179
-rw-r--r--tools/lib/subcmd/help.h (renamed from tools/perf/util/help.h)13
-rw-r--r--tools/lib/subcmd/pager.c (renamed from tools/perf/util/pager.c)23
-rw-r--r--tools/lib/subcmd/pager.h9
-rw-r--r--tools/lib/subcmd/parse-options.c (renamed from tools/perf/util/parse-options.c)250
-rw-r--r--tools/lib/subcmd/parse-options.h (renamed from tools/perf/util/parse-options.h)30
-rw-r--r--tools/lib/subcmd/run-command.c (renamed from tools/perf/util/run-command.c)24
-rw-r--r--tools/lib/subcmd/run-command.h (renamed from tools/perf/util/run-command.h)12
-rw-r--r--tools/lib/subcmd/sigchain.c (renamed from tools/perf/util/sigchain.c)3
-rw-r--r--tools/lib/subcmd/sigchain.h (renamed from tools/perf/util/sigchain.h)6
-rw-r--r--tools/lib/subcmd/subcmd-config.c11
-rw-r--r--tools/lib/subcmd/subcmd-config.h14
-rw-r--r--tools/lib/subcmd/subcmd-util.h91
-rw-r--r--tools/lib/traceevent/event-parse.c136
-rw-r--r--tools/lib/traceevent/event-parse.h4
-rw-r--r--tools/lib/util/find_next_bit.c89
-rw-r--r--tools/net/Makefile7
-rw-r--r--tools/perf/Build9
-rw-r--r--tools/perf/Documentation/perf-config.txt103
-rw-r--r--tools/perf/Documentation/perf-evlist.txt3
-rw-r--r--tools/perf/Documentation/perf-record.txt27
-rw-r--r--tools/perf/Documentation/perf-report.txt41
-rw-r--r--tools/perf/Documentation/perf-stat.txt34
-rw-r--r--tools/perf/Documentation/perf-top.txt3
-rw-r--r--tools/perf/Documentation/tips.txt29
-rw-r--r--tools/perf/MANIFEST9
-rw-r--r--tools/perf/Makefile.perf67
-rw-r--r--tools/perf/arch/x86/include/arch-tests.h8
-rw-r--r--tools/perf/arch/x86/tests/insn-x86.c2
-rw-r--r--tools/perf/arch/x86/tests/intel-cqm.c6
-rw-r--r--tools/perf/arch/x86/tests/perf-time-to-tsc.c3
-rw-r--r--tools/perf/arch/x86/tests/rdpmc.c2
-rw-r--r--tools/perf/arch/x86/util/Build1
-rw-r--r--tools/perf/arch/x86/util/intel-bts.c4
-rw-r--r--tools/perf/arch/x86/util/intel-pt.c6
-rw-r--r--tools/perf/bench/futex-hash.c2
-rw-r--r--tools/perf/bench/futex-lock-pi.c2
-rw-r--r--tools/perf/bench/futex-requeue.c2
-rw-r--r--tools/perf/bench/futex-wake-parallel.c2
-rw-r--r--tools/perf/bench/futex-wake.c2
-rw-r--r--tools/perf/bench/mem-functions.c2
-rw-r--r--tools/perf/bench/numa.c2
-rw-r--r--tools/perf/bench/sched-messaging.c2
-rw-r--r--tools/perf/bench/sched-pipe.c2
-rw-r--r--tools/perf/builtin-annotate.c44
-rw-r--r--tools/perf/builtin-bench.c2
-rw-r--r--tools/perf/builtin-buildid-cache.c2
-rw-r--r--tools/perf/builtin-buildid-list.c4
-rw-r--r--tools/perf/builtin-config.c66
-rw-r--r--tools/perf/builtin-data.c2
-rw-r--r--tools/perf/builtin-diff.c15
-rw-r--r--tools/perf/builtin-evlist.c13
-rw-r--r--tools/perf/builtin-help.c10
-rw-r--r--tools/perf/builtin-inject.c3
-rw-r--r--tools/perf/builtin-kmem.c2
-rw-r--r--tools/perf/builtin-kvm.c5
-rw-r--r--tools/perf/builtin-list.c2
-rw-r--r--tools/perf/builtin-lock.c2
-rw-r--r--tools/perf/builtin-mem.c2
-rw-r--r--tools/perf/builtin-probe.c17
-rw-r--r--tools/perf/builtin-record.c74
-rw-r--r--tools/perf/builtin-report.c66
-rw-r--r--tools/perf/builtin-sched.c2
-rw-r--r--tools/perf/builtin-script.c245
-rw-r--r--tools/perf/builtin-stat.c679
-rw-r--r--tools/perf/builtin-timechart.c2
-rw-r--r--tools/perf/builtin-top.c75
-rw-r--r--tools/perf/builtin-trace.c4
-rw-r--r--tools/perf/builtin-version.c10
-rw-r--r--tools/perf/builtin.h1
-rw-r--r--tools/perf/command-list.txt3
-rw-r--r--tools/perf/config/Makefile35
-rw-r--r--tools/perf/config/utilities.mak19
-rw-r--r--tools/perf/perf.c24
-rw-r--r--tools/perf/scripts/python/stat-cpi.py77
-rw-r--r--tools/perf/tests/.gitignore1
-rw-r--r--tools/perf/tests/Build16
-rw-r--r--tools/perf/tests/attr.c6
-rw-r--r--tools/perf/tests/bp_signal.c2
-rw-r--r--tools/perf/tests/bp_signal_overflow.c2
-rw-r--r--tools/perf/tests/bpf-script-test-prologue.c35
-rw-r--r--tools/perf/tests/bpf.c93
-rw-r--r--tools/perf/tests/builtin-test.c141
-rw-r--r--tools/perf/tests/code-reading.c16
-rw-r--r--tools/perf/tests/cpumap.c88
-rw-r--r--tools/perf/tests/dso-data.c6
-rw-r--r--tools/perf/tests/dwarf-unwind.c37
-rw-r--r--tools/perf/tests/event_update.c117
-rw-r--r--tools/perf/tests/evsel-roundtrip-name.c5
-rw-r--r--tools/perf/tests/evsel-tp-sched.c2
-rw-r--r--tools/perf/tests/fdarray.c4
-rw-r--r--tools/perf/tests/hists_common.c1
-rw-r--r--tools/perf/tests/hists_cumulate.c11
-rw-r--r--tools/perf/tests/hists_filter.c5
-rw-r--r--tools/perf/tests/hists_link.c11
-rw-r--r--tools/perf/tests/hists_output.c13
-rw-r--r--tools/perf/tests/keep-tracking.c5
-rw-r--r--tools/perf/tests/kmod-path.c2
-rw-r--r--tools/perf/tests/llvm.c75
-rw-r--r--tools/perf/tests/llvm.h2
-rw-r--r--tools/perf/tests/make76
-rw-r--r--tools/perf/tests/mmap-basic.c2
-rw-r--r--tools/perf/tests/mmap-thread-lookup.c8
-rw-r--r--tools/perf/tests/openat-syscall-all-cpus.c2
-rw-r--r--tools/perf/tests/openat-syscall-tp-fields.c2
-rw-r--r--tools/perf/tests/openat-syscall.c2
-rw-r--r--tools/perf/tests/parse-events.c2
-rw-r--r--tools/perf/tests/parse-no-sample-id-all.c2
-rw-r--r--tools/perf/tests/perf-record.c8
-rw-r--r--tools/perf/tests/pmu.c2
-rw-r--r--tools/perf/tests/python-use.c3
-rw-r--r--tools/perf/tests/sample-parsing.c2
-rw-r--r--tools/perf/tests/stat.c111
-rw-r--r--tools/perf/tests/sw-clock.c2
-rw-r--r--tools/perf/tests/switch-tracking.c8
-rw-r--r--tools/perf/tests/task-exit.c2
-rw-r--r--tools/perf/tests/tests.h95
-rw-r--r--tools/perf/tests/thread-map.c45
-rw-r--r--tools/perf/tests/thread-mg-share.c2
-rw-r--r--tools/perf/tests/topology.c2
-rw-r--r--tools/perf/tests/vmlinux-kallsyms.c2
-rw-r--r--tools/perf/ui/browser.c2
-rw-r--r--tools/perf/ui/browsers/annotate.c4
-rw-r--r--tools/perf/ui/browsers/hists.c344
-rw-r--r--tools/perf/ui/gtk/hists.c152
-rw-r--r--tools/perf/ui/hist.c14
-rw-r--r--tools/perf/ui/stdio/hist.c100
-rw-r--r--tools/perf/util/Build28
-rw-r--r--tools/perf/util/annotate.c23
-rw-r--r--tools/perf/util/auxtrace.c2
-rw-r--r--tools/perf/util/bpf-loader.c433
-rw-r--r--tools/perf/util/bpf-loader.h4
-rw-r--r--tools/perf/util/bpf-prologue.c455
-rw-r--r--tools/perf/util/bpf-prologue.h34
-rw-r--r--tools/perf/util/build-id.c3
-rw-r--r--tools/perf/util/cache.h14
-rw-r--r--tools/perf/util/callchain.c164
-rw-r--r--tools/perf/util/callchain.h30
-rw-r--r--tools/perf/util/cgroup.c2
-rw-r--r--tools/perf/util/color.c2
-rw-r--r--tools/perf/util/config.c2
-rw-r--r--tools/perf/util/cpumap.c51
-rw-r--r--tools/perf/util/cpumap.h1
-rw-r--r--tools/perf/util/data-convert-bt.c2
-rw-r--r--tools/perf/util/dso.c19
-rw-r--r--tools/perf/util/dso.h1
-rw-r--r--tools/perf/util/env.c9
-rw-r--r--tools/perf/util/environment.c8
-rw-r--r--tools/perf/util/event.c312
-rw-r--r--tools/perf/util/event.h150
-rw-r--r--tools/perf/util/evlist.c112
-rw-r--r--tools/perf/util/evlist.h10
-rw-r--r--tools/perf/util/evsel.c53
-rw-r--r--tools/perf/util/evsel.h4
-rw-r--r--tools/perf/util/exec_cmd.c148
-rw-r--r--tools/perf/util/exec_cmd.h12
-rwxr-xr-xtools/perf/util/generate-cmdlist.sh15
-rw-r--r--tools/perf/util/header.c207
-rw-r--r--tools/perf/util/header.h17
-rw-r--r--tools/perf/util/help-unknown-cmd.c103
-rw-r--r--tools/perf/util/help-unknown-cmd.h0
-rw-r--r--tools/perf/util/hist.c120
-rw-r--r--tools/perf/util/hist.h24
-rw-r--r--tools/perf/util/include/linux/string.h3
-rw-r--r--tools/perf/util/intel-pt.c4
-rw-r--r--tools/perf/util/machine.c75
-rw-r--r--tools/perf/util/map.c7
-rw-r--r--tools/perf/util/parse-branch-options.c2
-rw-r--r--tools/perf/util/parse-events.c10
-rw-r--r--tools/perf/util/parse-regs-options.c2
-rw-r--r--tools/perf/util/path.c18
-rw-r--r--tools/perf/util/pmu.c1
-rw-r--r--tools/perf/util/probe-event.c7
-rw-r--r--tools/perf/util/probe-finder.c30
-rw-r--r--tools/perf/util/python-ext-sources2
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c115
-rw-r--r--tools/perf/util/session.c202
-rw-r--r--tools/perf/util/session.h2
-rw-r--r--tools/perf/util/sort.c601
-rw-r--r--tools/perf/util/sort.h14
-rw-r--r--tools/perf/util/stat.c63
-rw-r--r--tools/perf/util/stat.h10
-rw-r--r--tools/perf/util/string.c16
-rw-r--r--tools/perf/util/strlist.c8
-rw-r--r--tools/perf/util/strlist.h9
-rw-r--r--tools/perf/util/symbol-elf.c9
-rw-r--r--tools/perf/util/symbol.c102
-rw-r--r--tools/perf/util/symbol.h5
-rw-r--r--tools/perf/util/term.c35
-rw-r--r--tools/perf/util/term.h10
-rw-r--r--tools/perf/util/thread.c10
-rw-r--r--tools/perf/util/thread_map.c28
-rw-r--r--tools/perf/util/thread_map.h3
-rw-r--r--tools/perf/util/tool.h8
-rw-r--r--tools/perf/util/trace-event-parse.c2
-rw-r--r--tools/perf/util/trace-event.h4
-rw-r--r--tools/perf/util/unwind-libdw.c63
-rw-r--r--tools/perf/util/unwind-libdw.h2
-rw-r--r--tools/perf/util/unwind-libunwind.c80
-rw-r--r--tools/perf/util/util.c68
-rw-r--r--tools/perf/util/util.h20
-rw-r--r--tools/power/acpi/Makefile16
-rw-r--r--tools/power/acpi/common/cmfsize.c2
-rw-r--r--tools/power/acpi/common/getopt.c4
-rw-r--r--tools/power/acpi/os_specific/service_layers/oslibcfs.c5
-rw-r--r--tools/power/acpi/os_specific/service_layers/oslinuxtbl.c2
-rw-r--r--tools/power/acpi/os_specific/service_layers/osunixdir.c2
-rw-r--r--tools/power/acpi/os_specific/service_layers/osunixmap.c2
-rw-r--r--tools/power/acpi/os_specific/service_layers/osunixxf.c2
-rw-r--r--tools/power/acpi/tools/acpidbg/Makefile27
-rw-r--r--tools/power/acpi/tools/acpidbg/acpidbg.c438
-rw-r--r--tools/power/acpi/tools/acpidump/acpidump.h2
-rw-r--r--tools/power/acpi/tools/acpidump/apdump.c2
-rw-r--r--tools/power/acpi/tools/acpidump/apfiles.c15
-rw-r--r--tools/power/acpi/tools/acpidump/apmain.c2
-rw-r--r--tools/power/cpupower/Makefile19
-rw-r--r--tools/power/cpupower/bench/Makefile8
-rw-r--r--tools/power/cpupower/utils/cpufreq-info.c247
-rw-r--r--tools/power/cpupower/utils/cpuidle-info.c16
-rw-r--r--tools/power/cpupower/utils/cpupower-info.c9
-rw-r--r--tools/power/cpupower/utils/cpupower-set.c10
-rw-r--r--tools/power/cpupower/utils/helpers/topology.c2
-rw-r--r--tools/power/x86/turbostat/turbostat.c8
-rw-r--r--tools/scripts/Makefile.arch (renamed from tools/perf/config/Makefile.arch)0
-rw-r--r--tools/spi/.gitignore2
-rw-r--r--tools/spi/Makefile4
-rw-r--r--tools/spi/spidev_fdx.c158
-rw-r--r--tools/spi/spidev_test.c399
-rw-r--r--tools/testing/nvdimm/Kbuild2
-rw-r--r--tools/testing/nvdimm/test/iomap.c93
-rw-r--r--tools/testing/nvdimm/test/nfit.c60
-rw-r--r--tools/testing/selftests/Makefile2
-rw-r--r--tools/testing/selftests/breakpoints/.gitignore1
-rw-r--r--tools/testing/selftests/capabilities/Makefile21
-rwxr-xr-xtools/testing/selftests/firmware/fw_filesystem.sh29
-rw-r--r--tools/testing/selftests/ftrace/test.d/instances/instance.tc90
-rw-r--r--tools/testing/selftests/futex/README2
-rw-r--r--tools/testing/selftests/intel_pstate/Makefile15
-rw-r--r--tools/testing/selftests/intel_pstate/aperf.c80
-rw-r--r--tools/testing/selftests/intel_pstate/msr.c39
-rwxr-xr-xtools/testing/selftests/intel_pstate/run.sh113
-rw-r--r--tools/testing/selftests/net/.gitignore1
-rw-r--r--tools/testing/selftests/net/Makefile2
-rw-r--r--tools/testing/selftests/net/reuseport_bpf.c514
-rw-r--r--tools/testing/selftests/powerpc/benchmarks/.gitignore1
-rw-r--r--tools/testing/selftests/powerpc/benchmarks/Makefile5
-rw-r--r--tools/testing/selftests/powerpc/benchmarks/context_switch.c466
-rw-r--r--tools/testing/selftests/powerpc/dscr/dscr_inherit_exec_test.c8
-rw-r--r--tools/testing/selftests/powerpc/dscr/dscr_inherit_test.c8
-rw-r--r--tools/testing/selftests/powerpc/harness.c43
-rw-r--r--tools/testing/selftests/powerpc/pmu/Makefile4
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/Makefile3
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/ebb.c3
-rw-r--r--tools/testing/selftests/powerpc/pmu/lib.c26
-rw-r--r--tools/testing/selftests/powerpc/pmu/lib.h1
-rwxr-xr-xtools/testing/selftests/powerpc/scripts/hmi.sh89
-rw-r--r--tools/testing/selftests/powerpc/tm/.gitignore3
-rw-r--r--tools/testing/selftests/powerpc/tm/Makefile4
-rw-r--r--tools/testing/selftests/powerpc/tm/tm-resched-dscr.c3
-rw-r--r--tools/testing/selftests/powerpc/tm/tm-signal-msr-resv.c74
-rw-r--r--tools/testing/selftests/powerpc/tm/tm-signal-stack.c76
-rw-r--r--tools/testing/selftests/powerpc/tm/tm-syscall.c13
-rw-r--r--tools/testing/selftests/powerpc/tm/tm-vmxcopy.c103
-rw-r--r--tools/testing/selftests/powerpc/tm/tm.h34
-rw-r--r--tools/testing/selftests/powerpc/utils.c87
-rw-r--r--tools/testing/selftests/powerpc/utils.h7
-rw-r--r--tools/testing/selftests/ptrace/.gitignore1
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh9
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm.sh22
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/parse-console.sh41
-rw-r--r--tools/testing/selftests/rcutorture/doc/TINY_RCU.txt1
-rw-r--r--tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt4
-rw-r--r--tools/testing/selftests/seccomp/seccomp_bpf.c38
-rw-r--r--tools/testing/selftests/seccomp/test_harness.h5
-rw-r--r--tools/testing/selftests/timers/.gitignore1
-rw-r--r--tools/testing/selftests/timers/clocksource-switch.c2
-rw-r--r--tools/testing/selftests/timers/valid-adjtimex.c139
-rw-r--r--tools/testing/selftests/vm/.gitignore5
-rw-r--r--tools/testing/selftests/x86/Makefile6
-rw-r--r--tools/testing/selftests/x86/vdso_restorer.c88
-rw-r--r--tools/virtio/asm/barrier.h22
-rw-r--r--tools/virtio/linux/compiler.h9
-rw-r--r--tools/virtio/linux/kernel.h7
-rw-r--r--tools/virtio/linux/virtio.h6
-rw-r--r--tools/virtio/linux/virtio_config.h20
-rw-r--r--tools/virtio/ringtest/Makefile22
-rw-r--r--tools/virtio/ringtest/README2
-rw-r--r--tools/virtio/ringtest/main.c366
-rw-r--r--tools/virtio/ringtest/main.h119
-rw-r--r--tools/virtio/ringtest/ring.c272
-rwxr-xr-xtools/virtio/ringtest/run-on-all.sh24
-rw-r--r--tools/virtio/ringtest/virtio_ring_0_9.c316
-rw-r--r--tools/virtio/ringtest/virtio_ring_poll.c2
-rw-r--r--tools/vm/page-types.c1
319 files changed, 13632 insertions, 2177 deletions
diff --git a/tools/Makefile b/tools/Makefile
index d6f307dfb1a3..6339f6ac3ccb 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -8,23 +8,24 @@ include scripts/Makefile.include
8help: 8help:
9 @echo 'Possible targets:' 9 @echo 'Possible targets:'
10 @echo '' 10 @echo ''
11 @echo ' acpi - ACPI tools' 11 @echo ' acpi - ACPI tools'
12 @echo ' cgroup - cgroup tools' 12 @echo ' cgroup - cgroup tools'
13 @echo ' cpupower - a tool for all things x86 CPU power' 13 @echo ' cpupower - a tool for all things x86 CPU power'
14 @echo ' firewire - the userspace part of nosy, an IEEE-1394 traffic sniffer' 14 @echo ' firewire - the userspace part of nosy, an IEEE-1394 traffic sniffer'
15 @echo ' hv - tools used when in Hyper-V clients' 15 @echo ' freefall - laptop accelerometer program for disk protection'
16 @echo ' iio - IIO tools' 16 @echo ' hv - tools used when in Hyper-V clients'
17 @echo ' lguest - a minimal 32-bit x86 hypervisor' 17 @echo ' iio - IIO tools'
18 @echo ' perf - Linux performance measurement and analysis tool' 18 @echo ' lguest - a minimal 32-bit x86 hypervisor'
19 @echo ' selftests - various kernel selftests' 19 @echo ' net - misc networking tools'
20 @echo ' turbostat - Intel CPU idle stats and freq reporting tool' 20 @echo ' perf - Linux performance measurement and analysis tool'
21 @echo ' usb - USB testing tools' 21 @echo ' selftests - various kernel selftests'
22 @echo ' virtio - vhost test module' 22 @echo ' spi - spi tools'
23 @echo ' net - misc networking tools' 23 @echo ' tmon - thermal monitoring and tuning tool'
24 @echo ' vm - misc vm tools' 24 @echo ' turbostat - Intel CPU idle stats and freq reporting tool'
25 @echo ' usb - USB testing tools'
26 @echo ' virtio - vhost test module'
27 @echo ' vm - misc vm tools'
25 @echo ' x86_energy_perf_policy - Intel energy policy tool' 28 @echo ' x86_energy_perf_policy - Intel energy policy tool'
26 @echo ' tmon - thermal monitoring and tuning tool'
27 @echo ' freefall - laptop accelerometer program for disk protection'
28 @echo '' 29 @echo ''
29 @echo 'You can do:' 30 @echo 'You can do:'
30 @echo ' $$ make -C tools/ <tool>_install' 31 @echo ' $$ make -C tools/ <tool>_install'
@@ -32,6 +33,10 @@ help:
32 @echo ' from the kernel command line to build and install one of' 33 @echo ' from the kernel command line to build and install one of'
33 @echo ' the tools above' 34 @echo ' the tools above'
34 @echo '' 35 @echo ''
36 @echo ' $$ make tools/all'
37 @echo ''
38 @echo ' builds all tools.'
39 @echo ''
35 @echo ' $$ make tools/install' 40 @echo ' $$ make tools/install'
36 @echo '' 41 @echo ''
37 @echo ' installs all tools.' 42 @echo ' installs all tools.'
@@ -48,7 +53,7 @@ acpi: FORCE
48cpupower: FORCE 53cpupower: FORCE
49 $(call descend,power/$@) 54 $(call descend,power/$@)
50 55
51cgroup firewire hv guest usb virtio vm net iio: FORCE 56cgroup firewire hv guest spi usb virtio vm net iio: FORCE
52 $(call descend,$@) 57 $(call descend,$@)
53 58
54liblockdep: FORCE 59liblockdep: FORCE
@@ -77,6 +82,11 @@ tmon: FORCE
77freefall: FORCE 82freefall: FORCE
78 $(call descend,laptop/$@) 83 $(call descend,laptop/$@)
79 84
85all: acpi cgroup cpupower hv firewire lguest \
86 perf selftests turbostat usb \
87 virtio vm net x86_energy_perf_policy \
88 tmon freefall
89
80acpi_install: 90acpi_install:
81 $(call descend,power/$(@:_install=),install) 91 $(call descend,power/$(@:_install=),install)
82 92
@@ -87,7 +97,7 @@ cgroup_install firewire_install hv_install lguest_install perf_install usb_insta
87 $(call descend,$(@:_install=),install) 97 $(call descend,$(@:_install=),install)
88 98
89selftests_install: 99selftests_install:
90 $(call descend,testing/$(@:_clean=),install) 100 $(call descend,testing/$(@:_install=),install)
91 101
92turbostat_install x86_energy_perf_policy_install: 102turbostat_install x86_energy_perf_policy_install:
93 $(call descend,power/x86/$(@:_install=),install) 103 $(call descend,power/x86/$(@:_install=),install)
@@ -101,7 +111,7 @@ freefall_install:
101install: acpi_install cgroup_install cpupower_install hv_install firewire_install lguest_install \ 111install: acpi_install cgroup_install cpupower_install hv_install firewire_install lguest_install \
102 perf_install selftests_install turbostat_install usb_install \ 112 perf_install selftests_install turbostat_install usb_install \
103 virtio_install vm_install net_install x86_energy_perf_policy_install \ 113 virtio_install vm_install net_install x86_energy_perf_policy_install \
104 tmon freefall_install 114 tmon_install freefall_install
105 115
106acpi_clean: 116acpi_clean:
107 $(call descend,power/acpi,clean) 117 $(call descend,power/acpi,clean)
@@ -109,7 +119,7 @@ acpi_clean:
109cpupower_clean: 119cpupower_clean:
110 $(call descend,power/cpupower,clean) 120 $(call descend,power/cpupower,clean)
111 121
112cgroup_clean hv_clean firewire_clean lguest_clean usb_clean virtio_clean vm_clean net_clean iio_clean: 122cgroup_clean hv_clean firewire_clean lguest_clean spi_clean usb_clean virtio_clean vm_clean net_clean iio_clean:
113 $(call descend,$(@:_clean=),clean) 123 $(call descend,$(@:_clean=),clean)
114 124
115liblockdep_clean: 125liblockdep_clean:
@@ -118,6 +128,12 @@ liblockdep_clean:
118libapi_clean: 128libapi_clean:
119 $(call descend,lib/api,clean) 129 $(call descend,lib/api,clean)
120 130
131libbpf_clean:
132 $(call descend,lib/bpf,clean)
133
134libsubcmd_clean:
135 $(call descend,lib/subcmd,clean)
136
121perf_clean: 137perf_clean:
122 $(call descend,$(@:_clean=),clean) 138 $(call descend,$(@:_clean=),clean)
123 139
@@ -133,9 +149,12 @@ tmon_clean:
133freefall_clean: 149freefall_clean:
134 $(call descend,laptop/freefall,clean) 150 $(call descend,laptop/freefall,clean)
135 151
152build_clean:
153 $(call descend,build,clean)
154
136clean: acpi_clean cgroup_clean cpupower_clean hv_clean firewire_clean lguest_clean \ 155clean: acpi_clean cgroup_clean cpupower_clean hv_clean firewire_clean lguest_clean \
137 perf_clean selftests_clean turbostat_clean usb_clean virtio_clean \ 156 perf_clean selftests_clean turbostat_clean spi_clean usb_clean virtio_clean \
138 vm_clean net_clean iio_clean x86_energy_perf_policy_clean tmon_clean \ 157 vm_clean net_clean iio_clean x86_energy_perf_policy_clean tmon_clean \
139 freefall_clean 158 freefall_clean build_clean libbpf_clean libsubcmd_clean liblockdep_clean
140 159
141.PHONY: FORCE 160.PHONY: FORCE
diff --git a/tools/build/Makefile b/tools/build/Makefile
index a93036272d43..0d5a0e3a8fa9 100644
--- a/tools/build/Makefile
+++ b/tools/build/Makefile
@@ -25,7 +25,7 @@ export Q srctree CC LD
25MAKEFLAGS := --no-print-directory 25MAKEFLAGS := --no-print-directory
26build := -f $(srctree)/tools/build/Makefile.build dir=. obj 26build := -f $(srctree)/tools/build/Makefile.build dir=. obj
27 27
28all: fixdep 28all: $(OUTPUT)fixdep
29 29
30clean: 30clean:
31 $(call QUIET_CLEAN, fixdep) 31 $(call QUIET_CLEAN, fixdep)
diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature
index 37ff4c9f92f1..02db3cdff20f 100644
--- a/tools/build/Makefile.feature
+++ b/tools/build/Makefile.feature
@@ -7,7 +7,7 @@ endif
7 7
8feature_check = $(eval $(feature_check_code)) 8feature_check = $(eval $(feature_check_code))
9define feature_check_code 9define feature_check_code
10 feature-$(1) := $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS) $(FEATURE_CHECK_CFLAGS-$(1))" LDFLAGS="$(LDFLAGS) $(FEATURE_CHECK_LDFLAGS-$(1))" -C $(feature_dir) test-$1.bin >/dev/null 2>/dev/null && echo 1 || echo 0) 10 feature-$(1) := $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS) $(FEATURE_CHECK_CFLAGS-$(1))" LDFLAGS="$(LDFLAGS) $(FEATURE_CHECK_LDFLAGS-$(1))" -C $(feature_dir) $(OUTPUT_FEATURES)test-$1.bin >/dev/null 2>/dev/null && echo 1 || echo 0)
11endef 11endef
12 12
13feature_set = $(eval $(feature_set_code)) 13feature_set = $(eval $(feature_set_code))
@@ -101,7 +101,6 @@ ifeq ($(feature-all), 1)
101 # 101 #
102 $(foreach feat,$(FEATURE_TESTS),$(call feature_set,$(feat))) 102 $(foreach feat,$(FEATURE_TESTS),$(call feature_set,$(feat)))
103else 103else
104 $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS)" LDFLAGS=$(LDFLAGS) -i -j -C $(feature_dir) $(addsuffix .bin,$(FEATURE_TESTS)) >/dev/null 2>&1)
105 $(foreach feat,$(FEATURE_TESTS),$(call feature_check,$(feat))) 104 $(foreach feat,$(FEATURE_TESTS),$(call feature_check,$(feat)))
106endif 105endif
107 106
@@ -123,13 +122,31 @@ define feature_print_text_code
123 MSG = $(shell printf '...%30s: %s' $(1) $(2)) 122 MSG = $(shell printf '...%30s: %s' $(1) $(2))
124endef 123endef
125 124
125#
126# generates feature value assignment for name, like:
127# $(call feature_assign,dwarf) == feature-dwarf=1
128#
129feature_assign = feature-$(1)=$(feature-$(1))
130
126FEATURE_DUMP_FILENAME = $(OUTPUT)FEATURE-DUMP$(FEATURE_USER) 131FEATURE_DUMP_FILENAME = $(OUTPUT)FEATURE-DUMP$(FEATURE_USER)
127FEATURE_DUMP := $(foreach feat,$(FEATURE_DISPLAY),feature-$(feat)($(feature-$(feat)))) 132FEATURE_DUMP := $(shell touch $(FEATURE_DUMP_FILENAME); cat $(FEATURE_DUMP_FILENAME))
128FEATURE_DUMP_FILE := $(shell touch $(FEATURE_DUMP_FILENAME); cat $(FEATURE_DUMP_FILENAME))
129 133
130ifeq ($(dwarf-post-unwind),1) 134feature_dump_check = $(eval $(feature_dump_check_code))
131 FEATURE_DUMP += dwarf-post-unwind($(dwarf-post-unwind-text)) 135define feature_dump_check_code
132endif 136 ifeq ($(findstring $(1),$(FEATURE_DUMP)),)
137 $(2) := 1
138 endif
139endef
140
141#
142# First check if any test from FEATURE_DISPLAY
143# and set feature_display := 1 if it does
144$(foreach feat,$(FEATURE_DISPLAY),$(call feature_dump_check,$(call feature_assign,$(feat)),feature_display))
145
146#
147# Now also check if any other test changed,
148# so we force FEATURE-DUMP generation
149$(foreach feat,$(FEATURE_TESTS),$(call feature_dump_check,$(call feature_assign,$(feat)),feature_dump_changed))
133 150
134# The $(feature_display) controls the default detection message 151# The $(feature_display) controls the default detection message
135# output. It's set if: 152# output. It's set if:
@@ -138,13 +155,13 @@ endif
138# - one of the $(FEATURE_DISPLAY) is not detected 155# - one of the $(FEATURE_DISPLAY) is not detected
139# - VF is enabled 156# - VF is enabled
140 157
141ifneq ("$(FEATURE_DUMP)","$(FEATURE_DUMP_FILE)") 158ifeq ($(feature_dump_changed),1)
142 $(shell echo "$(FEATURE_DUMP)" > $(FEATURE_DUMP_FILENAME)) 159 $(shell rm -f $(FEATURE_DUMP_FILENAME))
143 feature_display := 1 160 $(foreach feat,$(FEATURE_TESTS),$(shell echo "$(call feature_assign,$(feat))" >> $(FEATURE_DUMP_FILENAME)))
144endif 161endif
145 162
146feature_display_check = $(eval $(feature_check_display_code)) 163feature_display_check = $(eval $(feature_check_display_code))
147define feature_display_check_code 164define feature_check_display_code
148 ifneq ($(feature-$(1)), 1) 165 ifneq ($(feature-$(1)), 1)
149 feature_display := 1 166 feature_display := 1
150 endif 167 endif
@@ -161,11 +178,6 @@ ifeq ($(feature_display),1)
161 $(info ) 178 $(info )
162 $(info Auto-detecting system features:) 179 $(info Auto-detecting system features:)
163 $(foreach feat,$(FEATURE_DISPLAY),$(call feature_print_status,$(feat),)) 180 $(foreach feat,$(FEATURE_DISPLAY),$(call feature_print_status,$(feat),))
164
165 ifeq ($(dwarf-post-unwind),1)
166 $(call feature_print_text,"DWARF post unwind library", $(dwarf-post-unwind-text))
167 endif
168
169 ifneq ($(feature_verbose),1) 181 ifneq ($(feature_verbose),1)
170 $(info ) 182 $(info )
171 endif 183 endif
diff --git a/tools/build/Makefile.include b/tools/build/Makefile.include
index 4e09ad617a60..be630bed66d2 100644
--- a/tools/build/Makefile.include
+++ b/tools/build/Makefile.include
@@ -4,7 +4,7 @@ ifdef CROSS_COMPILE
4fixdep: 4fixdep:
5else 5else
6fixdep: 6fixdep:
7 $(Q)$(MAKE) -C $(srctree)/tools/build fixdep 7 $(Q)$(MAKE) -C $(srctree)/tools/build CFLAGS= LDFLAGS= $(OUTPUT)fixdep
8endif 8endif
9 9
10.PHONY: fixdep 10.PHONY: fixdep
diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile
index cea04ce9f35c..bf8f0352264d 100644
--- a/tools/build/feature/Makefile
+++ b/tools/build/feature/Makefile
@@ -1,4 +1,3 @@
1
2FILES= \ 1FILES= \
3 test-all.bin \ 2 test-all.bin \
4 test-backtrace.bin \ 3 test-backtrace.bin \
@@ -38,38 +37,40 @@ FILES= \
38 test-bpf.bin \ 37 test-bpf.bin \
39 test-get_cpuid.bin 38 test-get_cpuid.bin
40 39
40FILES := $(addprefix $(OUTPUT),$(FILES))
41
41CC := $(CROSS_COMPILE)gcc -MD 42CC := $(CROSS_COMPILE)gcc -MD
42PKG_CONFIG := $(CROSS_COMPILE)pkg-config 43PKG_CONFIG := $(CROSS_COMPILE)pkg-config
43 44
44all: $(FILES) 45all: $(FILES)
45 46
46__BUILD = $(CC) $(CFLAGS) -Wall -Werror -o $(OUTPUT)$@ $(patsubst %.bin,%.c,$@) $(LDFLAGS) 47__BUILD = $(CC) $(CFLAGS) -Wall -Werror -o $@ $(patsubst %.bin,%.c,$(@F)) $(LDFLAGS)
47 BUILD = $(__BUILD) > $(OUTPUT)$(@:.bin=.make.output) 2>&1 48 BUILD = $(__BUILD) > $(@:.bin=.make.output) 2>&1
48 49
49############################### 50###############################
50 51
51test-all.bin: 52$(OUTPUT)test-all.bin:
52 $(BUILD) -fstack-protector-all -O2 -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -laudit -I/usr/include/slang -lslang $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl -lz -llzma 53 $(BUILD) -fstack-protector-all -O2 -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -laudit -I/usr/include/slang -lslang $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl -lz -llzma
53 54
54test-hello.bin: 55$(OUTPUT)test-hello.bin:
55 $(BUILD) 56 $(BUILD)
56 57
57test-pthread-attr-setaffinity-np.bin: 58$(OUTPUT)test-pthread-attr-setaffinity-np.bin:
58 $(BUILD) -D_GNU_SOURCE -lpthread 59 $(BUILD) -D_GNU_SOURCE -lpthread
59 60
60test-stackprotector-all.bin: 61$(OUTPUT)test-stackprotector-all.bin:
61 $(BUILD) -fstack-protector-all 62 $(BUILD) -fstack-protector-all
62 63
63test-fortify-source.bin: 64$(OUTPUT)test-fortify-source.bin:
64 $(BUILD) -O2 -D_FORTIFY_SOURCE=2 65 $(BUILD) -O2 -D_FORTIFY_SOURCE=2
65 66
66test-bionic.bin: 67$(OUTPUT)test-bionic.bin:
67 $(BUILD) 68 $(BUILD)
68 69
69test-libelf.bin: 70$(OUTPUT)test-libelf.bin:
70 $(BUILD) -lelf 71 $(BUILD) -lelf
71 72
72test-glibc.bin: 73$(OUTPUT)test-glibc.bin:
73 $(BUILD) 74 $(BUILD)
74 75
75DWARFLIBS := -ldw 76DWARFLIBS := -ldw
@@ -77,37 +78,37 @@ ifeq ($(findstring -static,${LDFLAGS}),-static)
77DWARFLIBS += -lelf -lebl -lz -llzma -lbz2 78DWARFLIBS += -lelf -lebl -lz -llzma -lbz2
78endif 79endif
79 80
80test-dwarf.bin: 81$(OUTPUT)test-dwarf.bin:
81 $(BUILD) $(DWARFLIBS) 82 $(BUILD) $(DWARFLIBS)
82 83
83test-libelf-mmap.bin: 84$(OUTPUT)test-libelf-mmap.bin:
84 $(BUILD) -lelf 85 $(BUILD) -lelf
85 86
86test-libelf-getphdrnum.bin: 87$(OUTPUT)test-libelf-getphdrnum.bin:
87 $(BUILD) -lelf 88 $(BUILD) -lelf
88 89
89test-libnuma.bin: 90$(OUTPUT)test-libnuma.bin:
90 $(BUILD) -lnuma 91 $(BUILD) -lnuma
91 92
92test-numa_num_possible_cpus.bin: 93$(OUTPUT)test-numa_num_possible_cpus.bin:
93 $(BUILD) -lnuma 94 $(BUILD) -lnuma
94 95
95test-libunwind.bin: 96$(OUTPUT)test-libunwind.bin:
96 $(BUILD) -lelf 97 $(BUILD) -lelf
97 98
98test-libunwind-debug-frame.bin: 99$(OUTPUT)test-libunwind-debug-frame.bin:
99 $(BUILD) -lelf 100 $(BUILD) -lelf
100 101
101test-libaudit.bin: 102$(OUTPUT)test-libaudit.bin:
102 $(BUILD) -laudit 103 $(BUILD) -laudit
103 104
104test-libslang.bin: 105$(OUTPUT)test-libslang.bin:
105 $(BUILD) -I/usr/include/slang -lslang 106 $(BUILD) -I/usr/include/slang -lslang
106 107
107test-gtk2.bin: 108$(OUTPUT)test-gtk2.bin:
108 $(BUILD) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) 109 $(BUILD) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null)
109 110
110test-gtk2-infobar.bin: 111$(OUTPUT)test-gtk2-infobar.bin:
111 $(BUILD) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) 112 $(BUILD) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null)
112 113
113grep-libs = $(filter -l%,$(1)) 114grep-libs = $(filter -l%,$(1))
@@ -119,63 +120,63 @@ PERL_EMBED_LIBADD = $(call grep-libs,$(PERL_EMBED_LDOPTS))
119PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null` 120PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
120FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS) 121FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
121 122
122test-libperl.bin: 123$(OUTPUT)test-libperl.bin:
123 $(BUILD) $(FLAGS_PERL_EMBED) 124 $(BUILD) $(FLAGS_PERL_EMBED)
124 125
125test-libpython.bin: 126$(OUTPUT)test-libpython.bin:
126 $(BUILD) 127 $(BUILD)
127 128
128test-libpython-version.bin: 129$(OUTPUT)test-libpython-version.bin:
129 $(BUILD) 130 $(BUILD)
130 131
131test-libbfd.bin: 132$(OUTPUT)test-libbfd.bin:
132 $(BUILD) -DPACKAGE='"perf"' -lbfd -lz -liberty -ldl 133 $(BUILD) -DPACKAGE='"perf"' -lbfd -lz -liberty -ldl
133 134
134test-liberty.bin: 135$(OUTPUT)test-liberty.bin:
135 $(CC) $(CFLAGS) -Wall -Werror -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' $(LDFLAGS) -lbfd -ldl -liberty 136 $(CC) $(CFLAGS) -Wall -Werror -o $@ test-libbfd.c -DPACKAGE='"perf"' $(LDFLAGS) -lbfd -ldl -liberty
136 137
137test-liberty-z.bin: 138$(OUTPUT)test-liberty-z.bin:
138 $(CC) $(CFLAGS) -Wall -Werror -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' $(LDFLAGS) -lbfd -ldl -liberty -lz 139 $(CC) $(CFLAGS) -Wall -Werror -o $@ test-libbfd.c -DPACKAGE='"perf"' $(LDFLAGS) -lbfd -ldl -liberty -lz
139 140
140test-cplus-demangle.bin: 141$(OUTPUT)test-cplus-demangle.bin:
141 $(BUILD) -liberty 142 $(BUILD) -liberty
142 143
143test-backtrace.bin: 144$(OUTPUT)test-backtrace.bin:
144 $(BUILD) 145 $(BUILD)
145 146
146test-timerfd.bin: 147$(OUTPUT)test-timerfd.bin:
147 $(BUILD) 148 $(BUILD)
148 149
149test-libdw-dwarf-unwind.bin: 150$(OUTPUT)test-libdw-dwarf-unwind.bin:
150 $(BUILD) # -ldw provided by $(FEATURE_CHECK_LDFLAGS-libdw-dwarf-unwind) 151 $(BUILD) # -ldw provided by $(FEATURE_CHECK_LDFLAGS-libdw-dwarf-unwind)
151 152
152test-libbabeltrace.bin: 153$(OUTPUT)test-libbabeltrace.bin:
153 $(BUILD) # -lbabeltrace provided by $(FEATURE_CHECK_LDFLAGS-libbabeltrace) 154 $(BUILD) # -lbabeltrace provided by $(FEATURE_CHECK_LDFLAGS-libbabeltrace)
154 155
155test-sync-compare-and-swap.bin: 156$(OUTPUT)test-sync-compare-and-swap.bin:
156 $(BUILD) 157 $(BUILD)
157 158
158test-compile-32.bin: 159$(OUTPUT)test-compile-32.bin:
159 $(CC) -m32 -o $(OUTPUT)$@ test-compile.c 160 $(CC) -m32 -o $@ test-compile.c
160 161
161test-compile-x32.bin: 162$(OUTPUT)test-compile-x32.bin:
162 $(CC) -mx32 -o $(OUTPUT)$@ test-compile.c 163 $(CC) -mx32 -o $@ test-compile.c
163 164
164test-zlib.bin: 165$(OUTPUT)test-zlib.bin:
165 $(BUILD) -lz 166 $(BUILD) -lz
166 167
167test-lzma.bin: 168$(OUTPUT)test-lzma.bin:
168 $(BUILD) -llzma 169 $(BUILD) -llzma
169 170
170test-get_cpuid.bin: 171$(OUTPUT)test-get_cpuid.bin:
171 $(BUILD) 172 $(BUILD)
172 173
173test-bpf.bin: 174$(OUTPUT)test-bpf.bin:
174 $(BUILD) 175 $(BUILD)
175 176
176-include *.d 177-include $(OUTPUT)*.d
177 178
178############################### 179###############################
179 180
180clean: 181clean:
181 rm -f $(FILES) *.d $(FILES:.bin=.make.output) 182 rm -f $(FILES) $(OUTPUT)*.d $(FILES:.bin=.make.output)
diff --git a/tools/build/feature/test-all.c b/tools/build/feature/test-all.c
index 33cf6f20bd4e..81025cade45f 100644
--- a/tools/build/feature/test-all.c
+++ b/tools/build/feature/test-all.c
@@ -125,6 +125,10 @@
125# include "test-get_cpuid.c" 125# include "test-get_cpuid.c"
126#undef main 126#undef main
127 127
128#define main main_test_bpf
129# include "test-bpf.c"
130#undef main
131
128int main(int argc, char *argv[]) 132int main(int argc, char *argv[])
129{ 133{
130 main_test_libpython(); 134 main_test_libpython();
@@ -153,6 +157,7 @@ int main(int argc, char *argv[])
153 main_test_pthread_attr_setaffinity_np(); 157 main_test_pthread_attr_setaffinity_np();
154 main_test_lzma(); 158 main_test_lzma();
155 main_test_get_cpuid(); 159 main_test_get_cpuid();
160 main_test_bpf();
156 161
157 return 0; 162 return 0;
158} 163}
diff --git a/tools/build/feature/test-bpf.c b/tools/build/feature/test-bpf.c
index 062bac811af9..b389026839b9 100644
--- a/tools/build/feature/test-bpf.c
+++ b/tools/build/feature/test-bpf.c
@@ -1,9 +1,23 @@
1#include <asm/unistd.h>
1#include <linux/bpf.h> 2#include <linux/bpf.h>
3#include <unistd.h>
4
5#ifndef __NR_bpf
6# if defined(__i386__)
7# define __NR_bpf 357
8# elif defined(__x86_64__)
9# define __NR_bpf 321
10# elif defined(__aarch64__)
11# define __NR_bpf 280
12# error __NR_bpf not defined. libbpf does not support your arch.
13# endif
14#endif
2 15
3int main(void) 16int main(void)
4{ 17{
5 union bpf_attr attr; 18 union bpf_attr attr;
6 19
20 /* Check fields in attr */
7 attr.prog_type = BPF_PROG_TYPE_KPROBE; 21 attr.prog_type = BPF_PROG_TYPE_KPROBE;
8 attr.insn_cnt = 0; 22 attr.insn_cnt = 0;
9 attr.insns = 0; 23 attr.insns = 0;
@@ -14,5 +28,9 @@ int main(void)
14 attr.kern_version = 0; 28 attr.kern_version = 0;
15 29
16 attr = attr; 30 attr = attr;
17 return 0; 31 /*
32 * Test existence of __NR_bpf and BPF_PROG_LOAD.
33 * This call should fail if we run the testcase.
34 */
35 return syscall(__NR_bpf, BPF_PROG_LOAD, attr, sizeof(attr));
18} 36}
diff --git a/tools/hv/hv_fcopy_daemon.c b/tools/hv/hv_fcopy_daemon.c
index 5480e4e424eb..fdc9ca4c0356 100644
--- a/tools/hv/hv_fcopy_daemon.c
+++ b/tools/hv/hv_fcopy_daemon.c
@@ -37,12 +37,14 @@
37 37
38static int target_fd; 38static int target_fd;
39static char target_fname[W_MAX_PATH]; 39static char target_fname[W_MAX_PATH];
40static unsigned long long filesize;
40 41
41static int hv_start_fcopy(struct hv_start_fcopy *smsg) 42static int hv_start_fcopy(struct hv_start_fcopy *smsg)
42{ 43{
43 int error = HV_E_FAIL; 44 int error = HV_E_FAIL;
44 char *q, *p; 45 char *q, *p;
45 46
47 filesize = 0;
46 p = (char *)smsg->path_name; 48 p = (char *)smsg->path_name;
47 snprintf(target_fname, sizeof(target_fname), "%s/%s", 49 snprintf(target_fname, sizeof(target_fname), "%s/%s",
48 (char *)smsg->path_name, (char *)smsg->file_name); 50 (char *)smsg->path_name, (char *)smsg->file_name);
@@ -98,14 +100,26 @@ done:
98static int hv_copy_data(struct hv_do_fcopy *cpmsg) 100static int hv_copy_data(struct hv_do_fcopy *cpmsg)
99{ 101{
100 ssize_t bytes_written; 102 ssize_t bytes_written;
103 int ret = 0;
101 104
102 bytes_written = pwrite(target_fd, cpmsg->data, cpmsg->size, 105 bytes_written = pwrite(target_fd, cpmsg->data, cpmsg->size,
103 cpmsg->offset); 106 cpmsg->offset);
104 107
105 if (bytes_written != cpmsg->size) 108 filesize += cpmsg->size;
106 return HV_E_FAIL; 109 if (bytes_written != cpmsg->size) {
110 switch (errno) {
111 case ENOSPC:
112 ret = HV_ERROR_DISK_FULL;
113 break;
114 default:
115 ret = HV_E_FAIL;
116 break;
117 }
118 syslog(LOG_ERR, "pwrite failed to write %llu bytes: %ld (%s)",
119 filesize, (long)bytes_written, strerror(errno));
120 }
107 121
108 return 0; 122 return ret;
109} 123}
110 124
111static int hv_copy_finished(void) 125static int hv_copy_finished(void)
@@ -165,7 +179,7 @@ int main(int argc, char *argv[])
165 } 179 }
166 180
167 openlog("HV_FCOPY", 0, LOG_USER); 181 openlog("HV_FCOPY", 0, LOG_USER);
168 syslog(LOG_INFO, "HV_FCOPY starting; pid is:%d", getpid()); 182 syslog(LOG_INFO, "starting; pid is:%d", getpid());
169 183
170 fcopy_fd = open("/dev/vmbus/hv_fcopy", O_RDWR); 184 fcopy_fd = open("/dev/vmbus/hv_fcopy", O_RDWR);
171 185
@@ -201,7 +215,7 @@ int main(int argc, char *argv[])
201 } 215 }
202 kernel_modver = *(__u32 *)buffer; 216 kernel_modver = *(__u32 *)buffer;
203 in_handshake = 0; 217 in_handshake = 0;
204 syslog(LOG_INFO, "HV_FCOPY: kernel module version: %d", 218 syslog(LOG_INFO, "kernel module version: %d",
205 kernel_modver); 219 kernel_modver);
206 continue; 220 continue;
207 } 221 }
diff --git a/tools/hv/hv_vss_daemon.c b/tools/hv/hv_vss_daemon.c
index 96234b638249..5d51d6ff08e6 100644
--- a/tools/hv/hv_vss_daemon.c
+++ b/tools/hv/hv_vss_daemon.c
@@ -254,7 +254,7 @@ int main(int argc, char *argv[])
254 syslog(LOG_ERR, "Illegal op:%d\n", op); 254 syslog(LOG_ERR, "Illegal op:%d\n", op);
255 } 255 }
256 vss_msg->error = error; 256 vss_msg->error = error;
257 len = write(vss_fd, &error, sizeof(struct hv_vss_msg)); 257 len = write(vss_fd, vss_msg, sizeof(struct hv_vss_msg));
258 if (len != sizeof(struct hv_vss_msg)) { 258 if (len != sizeof(struct hv_vss_msg)) {
259 syslog(LOG_ERR, "write failed; error: %d %s", errno, 259 syslog(LOG_ERR, "write failed; error: %d %s", errno,
260 strerror(errno)); 260 strerror(errno));
diff --git a/tools/perf/util/include/linux/bitmap.h b/tools/include/linux/bitmap.h
index 40bd21488032..28f5493da491 100644
--- a/tools/perf/util/include/linux/bitmap.h
+++ b/tools/include/linux/bitmap.h
@@ -11,6 +11,8 @@ int __bitmap_weight(const unsigned long *bitmap, int bits);
11void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1, 11void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
12 const unsigned long *bitmap2, int bits); 12 const unsigned long *bitmap2, int bits);
13 13
14#define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) & (BITS_PER_LONG - 1)))
15
14#define BITMAP_LAST_WORD_MASK(nbits) \ 16#define BITMAP_LAST_WORD_MASK(nbits) \
15( \ 17( \
16 ((nbits) % BITS_PER_LONG) ? \ 18 ((nbits) % BITS_PER_LONG) ? \
diff --git a/tools/include/linux/list.h b/tools/include/linux/list.h
index a017f1595676..1da423820ad4 100644
--- a/tools/include/linux/list.h
+++ b/tools/include/linux/list.h
@@ -1,11 +1,751 @@
1#include <linux/compiler.h> 1#ifndef __TOOLS_LINUX_LIST_H
2#include <linux/kernel.h> 2#define __TOOLS_LINUX_LIST_H
3
3#include <linux/types.h> 4#include <linux/types.h>
5#include <linux/poison.h>
6#include <linux/kernel.h>
7#include <linux/compiler.h>
8
9/*
10 * Simple doubly linked list implementation.
11 *
12 * Some of the internal functions ("__xxx") are useful when
13 * manipulating whole lists rather than single entries, as
14 * sometimes we already know the next/prev entries and we can
15 * generate better code by using them directly rather than
16 * using the generic single-entry routines.
17 */
18
19#define LIST_HEAD_INIT(name) { &(name), &(name) }
20
21#define LIST_HEAD(name) \
22 struct list_head name = LIST_HEAD_INIT(name)
23
24static inline void INIT_LIST_HEAD(struct list_head *list)
25{
26 list->next = list;
27 list->prev = list;
28}
29
30/*
31 * Insert a new entry between two known consecutive entries.
32 *
33 * This is only for internal list manipulation where we know
34 * the prev/next entries already!
35 */
36#ifndef CONFIG_DEBUG_LIST
37static inline void __list_add(struct list_head *new,
38 struct list_head *prev,
39 struct list_head *next)
40{
41 next->prev = new;
42 new->next = next;
43 new->prev = prev;
44 prev->next = new;
45}
46#else
47extern void __list_add(struct list_head *new,
48 struct list_head *prev,
49 struct list_head *next);
50#endif
51
52/**
53 * list_add - add a new entry
54 * @new: new entry to be added
55 * @head: list head to add it after
56 *
57 * Insert a new entry after the specified head.
58 * This is good for implementing stacks.
59 */
60static inline void list_add(struct list_head *new, struct list_head *head)
61{
62 __list_add(new, head, head->next);
63}
64
65
66/**
67 * list_add_tail - add a new entry
68 * @new: new entry to be added
69 * @head: list head to add it before
70 *
71 * Insert a new entry before the specified head.
72 * This is useful for implementing queues.
73 */
74static inline void list_add_tail(struct list_head *new, struct list_head *head)
75{
76 __list_add(new, head->prev, head);
77}
78
79/*
80 * Delete a list entry by making the prev/next entries
81 * point to each other.
82 *
83 * This is only for internal list manipulation where we know
84 * the prev/next entries already!
85 */
86static inline void __list_del(struct list_head * prev, struct list_head * next)
87{
88 next->prev = prev;
89 WRITE_ONCE(prev->next, next);
90}
91
92/**
93 * list_del - deletes entry from list.
94 * @entry: the element to delete from the list.
95 * Note: list_empty() on entry does not return true after this, the entry is
96 * in an undefined state.
97 */
98#ifndef CONFIG_DEBUG_LIST
99static inline void __list_del_entry(struct list_head *entry)
100{
101 __list_del(entry->prev, entry->next);
102}
103
104static inline void list_del(struct list_head *entry)
105{
106 __list_del(entry->prev, entry->next);
107 entry->next = LIST_POISON1;
108 entry->prev = LIST_POISON2;
109}
110#else
111extern void __list_del_entry(struct list_head *entry);
112extern void list_del(struct list_head *entry);
113#endif
114
115/**
116 * list_replace - replace old entry by new one
117 * @old : the element to be replaced
118 * @new : the new element to insert
119 *
120 * If @old was empty, it will be overwritten.
121 */
122static inline void list_replace(struct list_head *old,
123 struct list_head *new)
124{
125 new->next = old->next;
126 new->next->prev = new;
127 new->prev = old->prev;
128 new->prev->next = new;
129}
130
131static inline void list_replace_init(struct list_head *old,
132 struct list_head *new)
133{
134 list_replace(old, new);
135 INIT_LIST_HEAD(old);
136}
137
138/**
139 * list_del_init - deletes entry from list and reinitialize it.
140 * @entry: the element to delete from the list.
141 */
142static inline void list_del_init(struct list_head *entry)
143{
144 __list_del_entry(entry);
145 INIT_LIST_HEAD(entry);
146}
147
148/**
149 * list_move - delete from one list and add as another's head
150 * @list: the entry to move
151 * @head: the head that will precede our entry
152 */
153static inline void list_move(struct list_head *list, struct list_head *head)
154{
155 __list_del_entry(list);
156 list_add(list, head);
157}
158
159/**
160 * list_move_tail - delete from one list and add as another's tail
161 * @list: the entry to move
162 * @head: the head that will follow our entry
163 */
164static inline void list_move_tail(struct list_head *list,
165 struct list_head *head)
166{
167 __list_del_entry(list);
168 list_add_tail(list, head);
169}
170
171/**
172 * list_is_last - tests whether @list is the last entry in list @head
173 * @list: the entry to test
174 * @head: the head of the list
175 */
176static inline int list_is_last(const struct list_head *list,
177 const struct list_head *head)
178{
179 return list->next == head;
180}
181
182/**
183 * list_empty - tests whether a list is empty
184 * @head: the list to test.
185 */
186static inline int list_empty(const struct list_head *head)
187{
188 return head->next == head;
189}
190
191/**
192 * list_empty_careful - tests whether a list is empty and not being modified
193 * @head: the list to test
194 *
195 * Description:
196 * tests whether a list is empty _and_ checks that no other CPU might be
197 * in the process of modifying either member (next or prev)
198 *
199 * NOTE: using list_empty_careful() without synchronization
200 * can only be safe if the only activity that can happen
201 * to the list entry is list_del_init(). Eg. it cannot be used
202 * if another CPU could re-list_add() it.
203 */
204static inline int list_empty_careful(const struct list_head *head)
205{
206 struct list_head *next = head->next;
207 return (next == head) && (next == head->prev);
208}
209
210/**
211 * list_rotate_left - rotate the list to the left
212 * @head: the head of the list
213 */
214static inline void list_rotate_left(struct list_head *head)
215{
216 struct list_head *first;
217
218 if (!list_empty(head)) {
219 first = head->next;
220 list_move_tail(first, head);
221 }
222}
223
224/**
225 * list_is_singular - tests whether a list has just one entry.
226 * @head: the list to test.
227 */
228static inline int list_is_singular(const struct list_head *head)
229{
230 return !list_empty(head) && (head->next == head->prev);
231}
232
233static inline void __list_cut_position(struct list_head *list,
234 struct list_head *head, struct list_head *entry)
235{
236 struct list_head *new_first = entry->next;
237 list->next = head->next;
238 list->next->prev = list;
239 list->prev = entry;
240 entry->next = list;
241 head->next = new_first;
242 new_first->prev = head;
243}
244
245/**
246 * list_cut_position - cut a list into two
247 * @list: a new list to add all removed entries
248 * @head: a list with entries
249 * @entry: an entry within head, could be the head itself
250 * and if so we won't cut the list
251 *
252 * This helper moves the initial part of @head, up to and
253 * including @entry, from @head to @list. You should
254 * pass on @entry an element you know is on @head. @list
255 * should be an empty list or a list you do not care about
256 * losing its data.
257 *
258 */
259static inline void list_cut_position(struct list_head *list,
260 struct list_head *head, struct list_head *entry)
261{
262 if (list_empty(head))
263 return;
264 if (list_is_singular(head) &&
265 (head->next != entry && head != entry))
266 return;
267 if (entry == head)
268 INIT_LIST_HEAD(list);
269 else
270 __list_cut_position(list, head, entry);
271}
272
273static inline void __list_splice(const struct list_head *list,
274 struct list_head *prev,
275 struct list_head *next)
276{
277 struct list_head *first = list->next;
278 struct list_head *last = list->prev;
279
280 first->prev = prev;
281 prev->next = first;
282
283 last->next = next;
284 next->prev = last;
285}
286
287/**
288 * list_splice - join two lists, this is designed for stacks
289 * @list: the new list to add.
290 * @head: the place to add it in the first list.
291 */
292static inline void list_splice(const struct list_head *list,
293 struct list_head *head)
294{
295 if (!list_empty(list))
296 __list_splice(list, head, head->next);
297}
298
299/**
300 * list_splice_tail - join two lists, each list being a queue
301 * @list: the new list to add.
302 * @head: the place to add it in the first list.
303 */
304static inline void list_splice_tail(struct list_head *list,
305 struct list_head *head)
306{
307 if (!list_empty(list))
308 __list_splice(list, head->prev, head);
309}
310
311/**
312 * list_splice_init - join two lists and reinitialise the emptied list.
313 * @list: the new list to add.
314 * @head: the place to add it in the first list.
315 *
316 * The list at @list is reinitialised
317 */
318static inline void list_splice_init(struct list_head *list,
319 struct list_head *head)
320{
321 if (!list_empty(list)) {
322 __list_splice(list, head, head->next);
323 INIT_LIST_HEAD(list);
324 }
325}
326
327/**
328 * list_splice_tail_init - join two lists and reinitialise the emptied list
329 * @list: the new list to add.
330 * @head: the place to add it in the first list.
331 *
332 * Each of the lists is a queue.
333 * The list at @list is reinitialised
334 */
335static inline void list_splice_tail_init(struct list_head *list,
336 struct list_head *head)
337{
338 if (!list_empty(list)) {
339 __list_splice(list, head->prev, head);
340 INIT_LIST_HEAD(list);
341 }
342}
343
344/**
345 * list_entry - get the struct for this entry
346 * @ptr: the &struct list_head pointer.
347 * @type: the type of the struct this is embedded in.
348 * @member: the name of the list_head within the struct.
349 */
350#define list_entry(ptr, type, member) \
351 container_of(ptr, type, member)
352
353/**
354 * list_first_entry - get the first element from a list
355 * @ptr: the list head to take the element from.
356 * @type: the type of the struct this is embedded in.
357 * @member: the name of the list_head within the struct.
358 *
359 * Note, that list is expected to be not empty.
360 */
361#define list_first_entry(ptr, type, member) \
362 list_entry((ptr)->next, type, member)
363
364/**
365 * list_last_entry - get the last element from a list
366 * @ptr: the list head to take the element from.
367 * @type: the type of the struct this is embedded in.
368 * @member: the name of the list_head within the struct.
369 *
370 * Note, that list is expected to be not empty.
371 */
372#define list_last_entry(ptr, type, member) \
373 list_entry((ptr)->prev, type, member)
374
375/**
376 * list_first_entry_or_null - get the first element from a list
377 * @ptr: the list head to take the element from.
378 * @type: the type of the struct this is embedded in.
379 * @member: the name of the list_head within the struct.
380 *
381 * Note that if the list is empty, it returns NULL.
382 */
383#define list_first_entry_or_null(ptr, type, member) \
384 (!list_empty(ptr) ? list_first_entry(ptr, type, member) : NULL)
385
386/**
387 * list_next_entry - get the next element in list
388 * @pos: the type * to cursor
389 * @member: the name of the list_head within the struct.
390 */
391#define list_next_entry(pos, member) \
392 list_entry((pos)->member.next, typeof(*(pos)), member)
393
394/**
395 * list_prev_entry - get the prev element in list
396 * @pos: the type * to cursor
397 * @member: the name of the list_head within the struct.
398 */
399#define list_prev_entry(pos, member) \
400 list_entry((pos)->member.prev, typeof(*(pos)), member)
401
402/**
403 * list_for_each - iterate over a list
404 * @pos: the &struct list_head to use as a loop cursor.
405 * @head: the head for your list.
406 */
407#define list_for_each(pos, head) \
408 for (pos = (head)->next; pos != (head); pos = pos->next)
409
410/**
411 * list_for_each_prev - iterate over a list backwards
412 * @pos: the &struct list_head to use as a loop cursor.
413 * @head: the head for your list.
414 */
415#define list_for_each_prev(pos, head) \
416 for (pos = (head)->prev; pos != (head); pos = pos->prev)
417
418/**
419 * list_for_each_safe - iterate over a list safe against removal of list entry
420 * @pos: the &struct list_head to use as a loop cursor.
421 * @n: another &struct list_head to use as temporary storage
422 * @head: the head for your list.
423 */
424#define list_for_each_safe(pos, n, head) \
425 for (pos = (head)->next, n = pos->next; pos != (head); \
426 pos = n, n = pos->next)
427
428/**
429 * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
430 * @pos: the &struct list_head to use as a loop cursor.
431 * @n: another &struct list_head to use as temporary storage
432 * @head: the head for your list.
433 */
434#define list_for_each_prev_safe(pos, n, head) \
435 for (pos = (head)->prev, n = pos->prev; \
436 pos != (head); \
437 pos = n, n = pos->prev)
438
439/**
440 * list_for_each_entry - iterate over list of given type
441 * @pos: the type * to use as a loop cursor.
442 * @head: the head for your list.
443 * @member: the name of the list_head within the struct.
444 */
445#define list_for_each_entry(pos, head, member) \
446 for (pos = list_first_entry(head, typeof(*pos), member); \
447 &pos->member != (head); \
448 pos = list_next_entry(pos, member))
449
450/**
451 * list_for_each_entry_reverse - iterate backwards over list of given type.
452 * @pos: the type * to use as a loop cursor.
453 * @head: the head for your list.
454 * @member: the name of the list_head within the struct.
455 */
456#define list_for_each_entry_reverse(pos, head, member) \
457 for (pos = list_last_entry(head, typeof(*pos), member); \
458 &pos->member != (head); \
459 pos = list_prev_entry(pos, member))
460
461/**
462 * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue()
463 * @pos: the type * to use as a start point
464 * @head: the head of the list
465 * @member: the name of the list_head within the struct.
466 *
467 * Prepares a pos entry for use as a start point in list_for_each_entry_continue().
468 */
469#define list_prepare_entry(pos, head, member) \
470 ((pos) ? : list_entry(head, typeof(*pos), member))
471
472/**
473 * list_for_each_entry_continue - continue iteration over list of given type
474 * @pos: the type * to use as a loop cursor.
475 * @head: the head for your list.
476 * @member: the name of the list_head within the struct.
477 *
478 * Continue to iterate over list of given type, continuing after
479 * the current position.
480 */
481#define list_for_each_entry_continue(pos, head, member) \
482 for (pos = list_next_entry(pos, member); \
483 &pos->member != (head); \
484 pos = list_next_entry(pos, member))
485
486/**
487 * list_for_each_entry_continue_reverse - iterate backwards from the given point
488 * @pos: the type * to use as a loop cursor.
489 * @head: the head for your list.
490 * @member: the name of the list_head within the struct.
491 *
492 * Start to iterate over list of given type backwards, continuing after
493 * the current position.
494 */
495#define list_for_each_entry_continue_reverse(pos, head, member) \
496 for (pos = list_prev_entry(pos, member); \
497 &pos->member != (head); \
498 pos = list_prev_entry(pos, member))
499
500/**
501 * list_for_each_entry_from - iterate over list of given type from the current point
502 * @pos: the type * to use as a loop cursor.
503 * @head: the head for your list.
504 * @member: the name of the list_head within the struct.
505 *
506 * Iterate over list of given type, continuing from current position.
507 */
508#define list_for_each_entry_from(pos, head, member) \
509 for (; &pos->member != (head); \
510 pos = list_next_entry(pos, member))
511
512/**
513 * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
514 * @pos: the type * to use as a loop cursor.
515 * @n: another type * to use as temporary storage
516 * @head: the head for your list.
517 * @member: the name of the list_head within the struct.
518 */
519#define list_for_each_entry_safe(pos, n, head, member) \
520 for (pos = list_first_entry(head, typeof(*pos), member), \
521 n = list_next_entry(pos, member); \
522 &pos->member != (head); \
523 pos = n, n = list_next_entry(n, member))
524
525/**
526 * list_for_each_entry_safe_continue - continue list iteration safe against removal
527 * @pos: the type * to use as a loop cursor.
528 * @n: another type * to use as temporary storage
529 * @head: the head for your list.
530 * @member: the name of the list_head within the struct.
531 *
532 * Iterate over list of given type, continuing after current point,
533 * safe against removal of list entry.
534 */
535#define list_for_each_entry_safe_continue(pos, n, head, member) \
536 for (pos = list_next_entry(pos, member), \
537 n = list_next_entry(pos, member); \
538 &pos->member != (head); \
539 pos = n, n = list_next_entry(n, member))
540
541/**
542 * list_for_each_entry_safe_from - iterate over list from current point safe against removal
543 * @pos: the type * to use as a loop cursor.
544 * @n: another type * to use as temporary storage
545 * @head: the head for your list.
546 * @member: the name of the list_head within the struct.
547 *
548 * Iterate over list of given type from current point, safe against
549 * removal of list entry.
550 */
551#define list_for_each_entry_safe_from(pos, n, head, member) \
552 for (n = list_next_entry(pos, member); \
553 &pos->member != (head); \
554 pos = n, n = list_next_entry(n, member))
555
556/**
557 * list_for_each_entry_safe_reverse - iterate backwards over list safe against removal
558 * @pos: the type * to use as a loop cursor.
559 * @n: another type * to use as temporary storage
560 * @head: the head for your list.
561 * @member: the name of the list_head within the struct.
562 *
563 * Iterate backwards over list of given type, safe against removal
564 * of list entry.
565 */
566#define list_for_each_entry_safe_reverse(pos, n, head, member) \
567 for (pos = list_last_entry(head, typeof(*pos), member), \
568 n = list_prev_entry(pos, member); \
569 &pos->member != (head); \
570 pos = n, n = list_prev_entry(n, member))
4 571
5#include "../../../include/linux/list.h" 572/**
573 * list_safe_reset_next - reset a stale list_for_each_entry_safe loop
574 * @pos: the loop cursor used in the list_for_each_entry_safe loop
575 * @n: temporary storage used in list_for_each_entry_safe
576 * @member: the name of the list_head within the struct.
577 *
578 * list_safe_reset_next is not safe to use in general if the list may be
579 * modified concurrently (eg. the lock is dropped in the loop body). An
580 * exception to this is if the cursor element (pos) is pinned in the list,
581 * and list_safe_reset_next is called after re-taking the lock and before
582 * completing the current iteration of the loop body.
583 */
584#define list_safe_reset_next(pos, n, member) \
585 n = list_next_entry(pos, member)
586
587/*
588 * Double linked lists with a single pointer list head.
589 * Mostly useful for hash tables where the two pointer list head is
590 * too wasteful.
591 * You lose the ability to access the tail in O(1).
592 */
593
594#define HLIST_HEAD_INIT { .first = NULL }
595#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
596#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
597static inline void INIT_HLIST_NODE(struct hlist_node *h)
598{
599 h->next = NULL;
600 h->pprev = NULL;
601}
602
603static inline int hlist_unhashed(const struct hlist_node *h)
604{
605 return !h->pprev;
606}
607
608static inline int hlist_empty(const struct hlist_head *h)
609{
610 return !h->first;
611}
612
613static inline void __hlist_del(struct hlist_node *n)
614{
615 struct hlist_node *next = n->next;
616 struct hlist_node **pprev = n->pprev;
617
618 WRITE_ONCE(*pprev, next);
619 if (next)
620 next->pprev = pprev;
621}
622
623static inline void hlist_del(struct hlist_node *n)
624{
625 __hlist_del(n);
626 n->next = LIST_POISON1;
627 n->pprev = LIST_POISON2;
628}
629
630static inline void hlist_del_init(struct hlist_node *n)
631{
632 if (!hlist_unhashed(n)) {
633 __hlist_del(n);
634 INIT_HLIST_NODE(n);
635 }
636}
637
638static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
639{
640 struct hlist_node *first = h->first;
641 n->next = first;
642 if (first)
643 first->pprev = &n->next;
644 h->first = n;
645 n->pprev = &h->first;
646}
647
648/* next must be != NULL */
649static inline void hlist_add_before(struct hlist_node *n,
650 struct hlist_node *next)
651{
652 n->pprev = next->pprev;
653 n->next = next;
654 next->pprev = &n->next;
655 *(n->pprev) = n;
656}
657
658static inline void hlist_add_behind(struct hlist_node *n,
659 struct hlist_node *prev)
660{
661 n->next = prev->next;
662 prev->next = n;
663 n->pprev = &prev->next;
664
665 if (n->next)
666 n->next->pprev = &n->next;
667}
668
669/* after that we'll appear to be on some hlist and hlist_del will work */
670static inline void hlist_add_fake(struct hlist_node *n)
671{
672 n->pprev = &n->next;
673}
674
675static inline bool hlist_fake(struct hlist_node *h)
676{
677 return h->pprev == &h->next;
678}
679
680/*
681 * Move a list from one list head to another. Fixup the pprev
682 * reference of the first entry if it exists.
683 */
684static inline void hlist_move_list(struct hlist_head *old,
685 struct hlist_head *new)
686{
687 new->first = old->first;
688 if (new->first)
689 new->first->pprev = &new->first;
690 old->first = NULL;
691}
692
693#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
694
695#define hlist_for_each(pos, head) \
696 for (pos = (head)->first; pos ; pos = pos->next)
697
698#define hlist_for_each_safe(pos, n, head) \
699 for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
700 pos = n)
701
702#define hlist_entry_safe(ptr, type, member) \
703 ({ typeof(ptr) ____ptr = (ptr); \
704 ____ptr ? hlist_entry(____ptr, type, member) : NULL; \
705 })
706
707/**
708 * hlist_for_each_entry - iterate over list of given type
709 * @pos: the type * to use as a loop cursor.
710 * @head: the head for your list.
711 * @member: the name of the hlist_node within the struct.
712 */
713#define hlist_for_each_entry(pos, head, member) \
714 for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\
715 pos; \
716 pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
717
718/**
719 * hlist_for_each_entry_continue - iterate over a hlist continuing after current point
720 * @pos: the type * to use as a loop cursor.
721 * @member: the name of the hlist_node within the struct.
722 */
723#define hlist_for_each_entry_continue(pos, member) \
724 for (pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member);\
725 pos; \
726 pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
727
728/**
729 * hlist_for_each_entry_from - iterate over a hlist continuing from current point
730 * @pos: the type * to use as a loop cursor.
731 * @member: the name of the hlist_node within the struct.
732 */
733#define hlist_for_each_entry_from(pos, member) \
734 for (; pos; \
735 pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
736
737/**
738 * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
739 * @pos: the type * to use as a loop cursor.
740 * @n: another &struct hlist_node to use as temporary storage
741 * @head: the head for your list.
742 * @member: the name of the hlist_node within the struct.
743 */
744#define hlist_for_each_entry_safe(pos, n, head, member) \
745 for (pos = hlist_entry_safe((head)->first, typeof(*pos), member);\
746 pos && ({ n = pos->member.next; 1; }); \
747 pos = hlist_entry_safe(n, typeof(*pos), member))
6 748
7#ifndef TOOLS_LIST_H
8#define TOOLS_LIST_H
9/** 749/**
10 * list_del_range - deletes range of entries from list. 750 * list_del_range - deletes range of entries from list.
11 * @begin: first element in the range to delete from the list. 751 * @begin: first element in the range to delete from the list.
@@ -27,4 +767,5 @@ static inline void list_del_range(struct list_head *begin,
27 */ 767 */
28#define list_for_each_from(pos, head) \ 768#define list_for_each_from(pos, head) \
29 for (; pos != (head); pos = pos->next) 769 for (; pos != (head); pos = pos->next)
30#endif 770
771#endif /* __TOOLS_LINUX_LIST_H */
diff --git a/tools/include/linux/string.h b/tools/include/linux/string.h
new file mode 100644
index 000000000000..e26223f1f287
--- /dev/null
+++ b/tools/include/linux/string.h
@@ -0,0 +1,15 @@
1#ifndef _TOOLS_LINUX_STRING_H_
2#define _TOOLS_LINUX_STRING_H_
3
4
5#include <linux/types.h> /* for size_t */
6
7void *memdup(const void *src, size_t len);
8
9int strtobool(const char *s, bool *res);
10
11#ifndef __UCLIBC__
12extern size_t strlcpy(char *dest, const char *src, size_t size);
13#endif
14
15#endif /* _LINUX_STRING_H_ */
diff --git a/tools/perf/util/bitmap.c b/tools/lib/bitmap.c
index 0a1adc1111fd..0a1adc1111fd 100644
--- a/tools/perf/util/bitmap.c
+++ b/tools/lib/bitmap.c
diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile
index a3caaf3eafbd..fc1bc75ae56d 100644
--- a/tools/lib/bpf/Makefile
+++ b/tools/lib/bpf/Makefile
@@ -6,6 +6,12 @@ BPF_EXTRAVERSION = 1
6 6
7MAKEFLAGS += --no-print-directory 7MAKEFLAGS += --no-print-directory
8 8
9ifeq ($(srctree),)
10srctree := $(patsubst %/,%,$(dir $(shell pwd)))
11srctree := $(patsubst %/,%,$(dir $(srctree)))
12srctree := $(patsubst %/,%,$(dir $(srctree)))
13#$(info Determined 'srctree' to be $(srctree))
14endif
9 15
10# Makefiles suck: This macro sets a default value of $(2) for the 16# Makefiles suck: This macro sets a default value of $(2) for the
11# variable named by $(1), unless the variable has been set by 17# variable named by $(1), unless the variable has been set by
@@ -31,7 +37,8 @@ INSTALL = install
31DESTDIR ?= 37DESTDIR ?=
32DESTDIR_SQ = '$(subst ','\'',$(DESTDIR))' 38DESTDIR_SQ = '$(subst ','\'',$(DESTDIR))'
33 39
34LP64 := $(shell echo __LP64__ | ${CC} ${CFLAGS} -E -x c - | tail -n 1) 40include $(srctree)/tools/scripts/Makefile.arch
41
35ifeq ($(LP64), 1) 42ifeq ($(LP64), 1)
36 libdir_relative = lib64 43 libdir_relative = lib64
37else 44else
@@ -57,13 +64,6 @@ ifndef VERBOSE
57 VERBOSE = 0 64 VERBOSE = 0
58endif 65endif
59 66
60ifeq ($(srctree),)
61srctree := $(patsubst %/,%,$(dir $(shell pwd)))
62srctree := $(patsubst %/,%,$(dir $(srctree)))
63srctree := $(patsubst %/,%,$(dir $(srctree)))
64#$(info Determined 'srctree' to be $(srctree))
65endif
66
67FEATURE_USER = .libbpf 67FEATURE_USER = .libbpf
68FEATURE_TESTS = libelf libelf-getphdrnum libelf-mmap bpf 68FEATURE_TESTS = libelf libelf-getphdrnum libelf-mmap bpf
69FEATURE_DISPLAY = libelf bpf 69FEATURE_DISPLAY = libelf bpf
@@ -71,7 +71,21 @@ FEATURE_DISPLAY = libelf bpf
71INCLUDES = -I. -I$(srctree)/tools/include -I$(srctree)/arch/$(ARCH)/include/uapi -I$(srctree)/include/uapi 71INCLUDES = -I. -I$(srctree)/tools/include -I$(srctree)/arch/$(ARCH)/include/uapi -I$(srctree)/include/uapi
72FEATURE_CHECK_CFLAGS-bpf = $(INCLUDES) 72FEATURE_CHECK_CFLAGS-bpf = $(INCLUDES)
73 73
74check_feat := 1
75NON_CHECK_FEAT_TARGETS := clean TAGS tags cscope help
76ifdef MAKECMDGOALS
77ifeq ($(filter-out $(NON_CHECK_FEAT_TARGETS),$(MAKECMDGOALS)),)
78 check_feat := 0
79endif
80endif
81
82ifeq ($(check_feat),1)
83ifeq ($(FEATURES_DUMP),)
74include $(srctree)/tools/build/Makefile.feature 84include $(srctree)/tools/build/Makefile.feature
85else
86include $(FEATURES_DUMP)
87endif
88endif
75 89
76export prefix libdir src obj 90export prefix libdir src obj
77 91
@@ -178,7 +192,7 @@ config-clean:
178 $(Q)$(MAKE) -C $(srctree)/tools/build/feature/ clean >/dev/null 192 $(Q)$(MAKE) -C $(srctree)/tools/build/feature/ clean >/dev/null
179 193
180clean: 194clean:
181 $(call QUIET_CLEAN, libbpf) $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d \ 195 $(call QUIET_CLEAN, libbpf) $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d .*.cmd \
182 $(RM) LIBBPF-CFLAGS 196 $(RM) LIBBPF-CFLAGS
183 $(call QUIET_CLEAN, core-gen) $(RM) $(OUTPUT)FEATURE-DUMP.libbpf 197 $(call QUIET_CLEAN, core-gen) $(RM) $(OUTPUT)FEATURE-DUMP.libbpf
184 198
diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index a6331050ab79..1f91cc941b7c 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -14,8 +14,8 @@
14#include "bpf.h" 14#include "bpf.h"
15 15
16/* 16/*
17 * When building perf, unistd.h is override. Define __NR_bpf is 17 * When building perf, unistd.h is overrided. __NR_bpf is
18 * required to be defined. 18 * required to be defined explicitly.
19 */ 19 */
20#ifndef __NR_bpf 20#ifndef __NR_bpf
21# if defined(__i386__) 21# if defined(__i386__)
@@ -83,3 +83,17 @@ int bpf_load_program(enum bpf_prog_type type, struct bpf_insn *insns,
83 log_buf[0] = 0; 83 log_buf[0] = 0;
84 return sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); 84 return sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
85} 85}
86
87int bpf_map_update_elem(int fd, void *key, void *value,
88 u64 flags)
89{
90 union bpf_attr attr;
91
92 bzero(&attr, sizeof(attr));
93 attr.map_fd = fd;
94 attr.key = ptr_to_u64(key);
95 attr.value = ptr_to_u64(value);
96 attr.flags = flags;
97
98 return sys_bpf(BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr));
99}
diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
index 854b7361b784..a76465541292 100644
--- a/tools/lib/bpf/bpf.h
+++ b/tools/lib/bpf/bpf.h
@@ -20,4 +20,6 @@ int bpf_load_program(enum bpf_prog_type type, struct bpf_insn *insns,
20 u32 kern_version, char *log_buf, 20 u32 kern_version, char *log_buf,
21 size_t log_buf_sz); 21 size_t log_buf_sz);
22 22
23int bpf_map_update_elem(int fd, void *key, void *value,
24 u64 flags);
23#endif 25#endif
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index e176bad19bcb..8334a5a9d5d7 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -152,29 +152,36 @@ struct bpf_program {
152 } *reloc_desc; 152 } *reloc_desc;
153 int nr_reloc; 153 int nr_reloc;
154 154
155 int fd; 155 struct {
156 int nr;
157 int *fds;
158 } instances;
159 bpf_program_prep_t preprocessor;
156 160
157 struct bpf_object *obj; 161 struct bpf_object *obj;
158 void *priv; 162 void *priv;
159 bpf_program_clear_priv_t clear_priv; 163 bpf_program_clear_priv_t clear_priv;
160}; 164};
161 165
166struct bpf_map {
167 int fd;
168 char *name;
169 struct bpf_map_def def;
170 void *priv;
171 bpf_map_clear_priv_t clear_priv;
172};
173
162static LIST_HEAD(bpf_objects_list); 174static LIST_HEAD(bpf_objects_list);
163 175
164struct bpf_object { 176struct bpf_object {
165 char license[64]; 177 char license[64];
166 u32 kern_version; 178 u32 kern_version;
167 void *maps_buf;
168 size_t maps_buf_sz;
169 179
170 struct bpf_program *programs; 180 struct bpf_program *programs;
171 size_t nr_programs; 181 size_t nr_programs;
172 int *map_fds; 182 struct bpf_map *maps;
173 /* 183 size_t nr_maps;
174 * This field is required because maps_buf will be freed and 184
175 * maps_buf_sz will be set to 0 after loaded.
176 */
177 size_t nr_map_fds;
178 bool loaded; 185 bool loaded;
179 186
180 /* 187 /*
@@ -188,6 +195,7 @@ struct bpf_object {
188 Elf *elf; 195 Elf *elf;
189 GElf_Ehdr ehdr; 196 GElf_Ehdr ehdr;
190 Elf_Data *symbols; 197 Elf_Data *symbols;
198 size_t strtabidx;
191 struct { 199 struct {
192 GElf_Shdr shdr; 200 GElf_Shdr shdr;
193 Elf_Data *data; 201 Elf_Data *data;
@@ -206,10 +214,25 @@ struct bpf_object {
206 214
207static void bpf_program__unload(struct bpf_program *prog) 215static void bpf_program__unload(struct bpf_program *prog)
208{ 216{
217 int i;
218
209 if (!prog) 219 if (!prog)
210 return; 220 return;
211 221
212 zclose(prog->fd); 222 /*
223 * If the object is opened but the program was never loaded,
224 * it is possible that prog->instances.nr == -1.
225 */
226 if (prog->instances.nr > 0) {
227 for (i = 0; i < prog->instances.nr; i++)
228 zclose(prog->instances.fds[i]);
229 } else if (prog->instances.nr != -1) {
230 pr_warning("Internal error: instances.nr is %d\n",
231 prog->instances.nr);
232 }
233
234 prog->instances.nr = -1;
235 zfree(&prog->instances.fds);
213} 236}
214 237
215static void bpf_program__exit(struct bpf_program *prog) 238static void bpf_program__exit(struct bpf_program *prog)
@@ -260,7 +283,8 @@ bpf_program__init(void *data, size_t size, char *name, int idx,
260 memcpy(prog->insns, data, 283 memcpy(prog->insns, data,
261 prog->insns_cnt * sizeof(struct bpf_insn)); 284 prog->insns_cnt * sizeof(struct bpf_insn));
262 prog->idx = idx; 285 prog->idx = idx;
263 prog->fd = -1; 286 prog->instances.fds = NULL;
287 prog->instances.nr = -1;
264 288
265 return 0; 289 return 0;
266errout: 290errout:
@@ -469,21 +493,77 @@ static int
469bpf_object__init_maps(struct bpf_object *obj, void *data, 493bpf_object__init_maps(struct bpf_object *obj, void *data,
470 size_t size) 494 size_t size)
471{ 495{
472 if (size == 0) { 496 size_t nr_maps;
497 int i;
498
499 nr_maps = size / sizeof(struct bpf_map_def);
500 if (!data || !nr_maps) {
473 pr_debug("%s doesn't need map definition\n", 501 pr_debug("%s doesn't need map definition\n",
474 obj->path); 502 obj->path);
475 return 0; 503 return 0;
476 } 504 }
477 505
478 obj->maps_buf = malloc(size); 506 pr_debug("maps in %s: %zd bytes\n", obj->path, size);
479 if (!obj->maps_buf) { 507
480 pr_warning("malloc maps failed: %s\n", obj->path); 508 obj->maps = calloc(nr_maps, sizeof(obj->maps[0]));
509 if (!obj->maps) {
510 pr_warning("alloc maps for object failed\n");
481 return -ENOMEM; 511 return -ENOMEM;
482 } 512 }
513 obj->nr_maps = nr_maps;
483 514
484 obj->maps_buf_sz = size; 515 for (i = 0; i < nr_maps; i++) {
485 memcpy(obj->maps_buf, data, size); 516 struct bpf_map_def *def = &obj->maps[i].def;
486 pr_debug("maps in %s: %ld bytes\n", obj->path, (long)size); 517
518 /*
519 * fill all fd with -1 so won't close incorrect
520 * fd (fd=0 is stdin) when failure (zclose won't close
521 * negative fd)).
522 */
523 obj->maps[i].fd = -1;
524
525 /* Save map definition into obj->maps */
526 *def = ((struct bpf_map_def *)data)[i];
527 }
528 return 0;
529}
530
531static int
532bpf_object__init_maps_name(struct bpf_object *obj, int maps_shndx)
533{
534 int i;
535 Elf_Data *symbols = obj->efile.symbols;
536
537 if (!symbols || maps_shndx < 0)
538 return -EINVAL;
539
540 for (i = 0; i < symbols->d_size / sizeof(GElf_Sym); i++) {
541 GElf_Sym sym;
542 size_t map_idx;
543 const char *map_name;
544
545 if (!gelf_getsym(symbols, i, &sym))
546 continue;
547 if (sym.st_shndx != maps_shndx)
548 continue;
549
550 map_name = elf_strptr(obj->efile.elf,
551 obj->efile.strtabidx,
552 sym.st_name);
553 map_idx = sym.st_value / sizeof(struct bpf_map_def);
554 if (map_idx >= obj->nr_maps) {
555 pr_warning("index of map \"%s\" is buggy: %zu > %zu\n",
556 map_name, map_idx, obj->nr_maps);
557 continue;
558 }
559 obj->maps[map_idx].name = strdup(map_name);
560 if (!obj->maps[map_idx].name) {
561 pr_warning("failed to alloc map name\n");
562 return -ENOMEM;
563 }
564 pr_debug("map %zu is \"%s\"\n", map_idx,
565 obj->maps[map_idx].name);
566 }
487 return 0; 567 return 0;
488} 568}
489 569
@@ -492,7 +572,7 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
492 Elf *elf = obj->efile.elf; 572 Elf *elf = obj->efile.elf;
493 GElf_Ehdr *ep = &obj->efile.ehdr; 573 GElf_Ehdr *ep = &obj->efile.ehdr;
494 Elf_Scn *scn = NULL; 574 Elf_Scn *scn = NULL;
495 int idx = 0, err = 0; 575 int idx = 0, err = 0, maps_shndx = -1;
496 576
497 /* Elf is corrupted/truncated, avoid calling elf_strptr. */ 577 /* Elf is corrupted/truncated, avoid calling elf_strptr. */
498 if (!elf_rawdata(elf_getscn(elf, ep->e_shstrndx), NULL)) { 578 if (!elf_rawdata(elf_getscn(elf, ep->e_shstrndx), NULL)) {
@@ -542,16 +622,19 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
542 err = bpf_object__init_kversion(obj, 622 err = bpf_object__init_kversion(obj,
543 data->d_buf, 623 data->d_buf,
544 data->d_size); 624 data->d_size);
545 else if (strcmp(name, "maps") == 0) 625 else if (strcmp(name, "maps") == 0) {
546 err = bpf_object__init_maps(obj, data->d_buf, 626 err = bpf_object__init_maps(obj, data->d_buf,
547 data->d_size); 627 data->d_size);
548 else if (sh.sh_type == SHT_SYMTAB) { 628 maps_shndx = idx;
629 } else if (sh.sh_type == SHT_SYMTAB) {
549 if (obj->efile.symbols) { 630 if (obj->efile.symbols) {
550 pr_warning("bpf: multiple SYMTAB in %s\n", 631 pr_warning("bpf: multiple SYMTAB in %s\n",
551 obj->path); 632 obj->path);
552 err = -LIBBPF_ERRNO__FORMAT; 633 err = -LIBBPF_ERRNO__FORMAT;
553 } else 634 } else {
554 obj->efile.symbols = data; 635 obj->efile.symbols = data;
636 obj->efile.strtabidx = sh.sh_link;
637 }
555 } else if ((sh.sh_type == SHT_PROGBITS) && 638 } else if ((sh.sh_type == SHT_PROGBITS) &&
556 (sh.sh_flags & SHF_EXECINSTR) && 639 (sh.sh_flags & SHF_EXECINSTR) &&
557 (data->d_size > 0)) { 640 (data->d_size > 0)) {
@@ -586,6 +669,13 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
586 if (err) 669 if (err)
587 goto out; 670 goto out;
588 } 671 }
672
673 if (!obj->efile.strtabidx || obj->efile.strtabidx >= idx) {
674 pr_warning("Corrupted ELF file: index of strtab invalid\n");
675 return LIBBPF_ERRNO__FORMAT;
676 }
677 if (maps_shndx >= 0)
678 err = bpf_object__init_maps_name(obj, maps_shndx);
589out: 679out:
590 return err; 680 return err;
591} 681}
@@ -668,37 +758,15 @@ static int
668bpf_object__create_maps(struct bpf_object *obj) 758bpf_object__create_maps(struct bpf_object *obj)
669{ 759{
670 unsigned int i; 760 unsigned int i;
671 size_t nr_maps;
672 int *pfd;
673
674 nr_maps = obj->maps_buf_sz / sizeof(struct bpf_map_def);
675 if (!obj->maps_buf || !nr_maps) {
676 pr_debug("don't need create maps for %s\n",
677 obj->path);
678 return 0;
679 }
680
681 obj->map_fds = malloc(sizeof(int) * nr_maps);
682 if (!obj->map_fds) {
683 pr_warning("realloc perf_bpf_map_fds failed\n");
684 return -ENOMEM;
685 }
686 obj->nr_map_fds = nr_maps;
687 761
688 /* fill all fd with -1 */ 762 for (i = 0; i < obj->nr_maps; i++) {
689 memset(obj->map_fds, -1, sizeof(int) * nr_maps); 763 struct bpf_map_def *def = &obj->maps[i].def;
690 764 int *pfd = &obj->maps[i].fd;
691 pfd = obj->map_fds;
692 for (i = 0; i < nr_maps; i++) {
693 struct bpf_map_def def;
694 765
695 def = *(struct bpf_map_def *)(obj->maps_buf + 766 *pfd = bpf_create_map(def->type,
696 i * sizeof(struct bpf_map_def)); 767 def->key_size,
697 768 def->value_size,
698 *pfd = bpf_create_map(def.type, 769 def->max_entries);
699 def.key_size,
700 def.value_size,
701 def.max_entries);
702 if (*pfd < 0) { 770 if (*pfd < 0) {
703 size_t j; 771 size_t j;
704 int err = *pfd; 772 int err = *pfd;
@@ -706,22 +774,17 @@ bpf_object__create_maps(struct bpf_object *obj)
706 pr_warning("failed to create map: %s\n", 774 pr_warning("failed to create map: %s\n",
707 strerror(errno)); 775 strerror(errno));
708 for (j = 0; j < i; j++) 776 for (j = 0; j < i; j++)
709 zclose(obj->map_fds[j]); 777 zclose(obj->maps[j].fd);
710 obj->nr_map_fds = 0;
711 zfree(&obj->map_fds);
712 return err; 778 return err;
713 } 779 }
714 pr_debug("create map: fd=%d\n", *pfd); 780 pr_debug("create map: fd=%d\n", *pfd);
715 pfd++;
716 } 781 }
717 782
718 zfree(&obj->maps_buf);
719 obj->maps_buf_sz = 0;
720 return 0; 783 return 0;
721} 784}
722 785
723static int 786static int
724bpf_program__relocate(struct bpf_program *prog, int *map_fds) 787bpf_program__relocate(struct bpf_program *prog, struct bpf_object *obj)
725{ 788{
726 int i; 789 int i;
727 790
@@ -741,7 +804,7 @@ bpf_program__relocate(struct bpf_program *prog, int *map_fds)
741 return -LIBBPF_ERRNO__RELOC; 804 return -LIBBPF_ERRNO__RELOC;
742 } 805 }
743 insns[insn_idx].src_reg = BPF_PSEUDO_MAP_FD; 806 insns[insn_idx].src_reg = BPF_PSEUDO_MAP_FD;
744 insns[insn_idx].imm = map_fds[map_idx]; 807 insns[insn_idx].imm = obj->maps[map_idx].fd;
745 } 808 }
746 809
747 zfree(&prog->reloc_desc); 810 zfree(&prog->reloc_desc);
@@ -760,7 +823,7 @@ bpf_object__relocate(struct bpf_object *obj)
760 for (i = 0; i < obj->nr_programs; i++) { 823 for (i = 0; i < obj->nr_programs; i++) {
761 prog = &obj->programs[i]; 824 prog = &obj->programs[i];
762 825
763 err = bpf_program__relocate(prog, obj->map_fds); 826 err = bpf_program__relocate(prog, obj);
764 if (err) { 827 if (err) {
765 pr_warning("failed to relocate '%s'\n", 828 pr_warning("failed to relocate '%s'\n",
766 prog->section_name); 829 prog->section_name);
@@ -784,8 +847,7 @@ static int bpf_object__collect_reloc(struct bpf_object *obj)
784 Elf_Data *data = obj->efile.reloc[i].data; 847 Elf_Data *data = obj->efile.reloc[i].data;
785 int idx = shdr->sh_info; 848 int idx = shdr->sh_info;
786 struct bpf_program *prog; 849 struct bpf_program *prog;
787 size_t nr_maps = obj->maps_buf_sz / 850 size_t nr_maps = obj->nr_maps;
788 sizeof(struct bpf_map_def);
789 851
790 if (shdr->sh_type != SHT_REL) { 852 if (shdr->sh_type != SHT_REL) {
791 pr_warning("internal error at %d\n", __LINE__); 853 pr_warning("internal error at %d\n", __LINE__);
@@ -860,13 +922,73 @@ static int
860bpf_program__load(struct bpf_program *prog, 922bpf_program__load(struct bpf_program *prog,
861 char *license, u32 kern_version) 923 char *license, u32 kern_version)
862{ 924{
863 int err, fd; 925 int err = 0, fd, i;
864 926
865 err = load_program(prog->insns, prog->insns_cnt, 927 if (prog->instances.nr < 0 || !prog->instances.fds) {
866 license, kern_version, &fd); 928 if (prog->preprocessor) {
867 if (!err) 929 pr_warning("Internal error: can't load program '%s'\n",
868 prog->fd = fd; 930 prog->section_name);
931 return -LIBBPF_ERRNO__INTERNAL;
932 }
933
934 prog->instances.fds = malloc(sizeof(int));
935 if (!prog->instances.fds) {
936 pr_warning("Not enough memory for BPF fds\n");
937 return -ENOMEM;
938 }
939 prog->instances.nr = 1;
940 prog->instances.fds[0] = -1;
941 }
942
943 if (!prog->preprocessor) {
944 if (prog->instances.nr != 1) {
945 pr_warning("Program '%s' is inconsistent: nr(%d) != 1\n",
946 prog->section_name, prog->instances.nr);
947 }
948 err = load_program(prog->insns, prog->insns_cnt,
949 license, kern_version, &fd);
950 if (!err)
951 prog->instances.fds[0] = fd;
952 goto out;
953 }
954
955 for (i = 0; i < prog->instances.nr; i++) {
956 struct bpf_prog_prep_result result;
957 bpf_program_prep_t preprocessor = prog->preprocessor;
958
959 bzero(&result, sizeof(result));
960 err = preprocessor(prog, i, prog->insns,
961 prog->insns_cnt, &result);
962 if (err) {
963 pr_warning("Preprocessing the %dth instance of program '%s' failed\n",
964 i, prog->section_name);
965 goto out;
966 }
967
968 if (!result.new_insn_ptr || !result.new_insn_cnt) {
969 pr_debug("Skip loading the %dth instance of program '%s'\n",
970 i, prog->section_name);
971 prog->instances.fds[i] = -1;
972 if (result.pfd)
973 *result.pfd = -1;
974 continue;
975 }
976
977 err = load_program(result.new_insn_ptr,
978 result.new_insn_cnt,
979 license, kern_version, &fd);
980
981 if (err) {
982 pr_warning("Loading the %dth instance of program '%s' failed\n",
983 i, prog->section_name);
984 goto out;
985 }
869 986
987 if (result.pfd)
988 *result.pfd = fd;
989 prog->instances.fds[i] = fd;
990 }
991out:
870 if (err) 992 if (err)
871 pr_warning("failed to load program '%s'\n", 993 pr_warning("failed to load program '%s'\n",
872 prog->section_name); 994 prog->section_name);
@@ -970,10 +1092,8 @@ int bpf_object__unload(struct bpf_object *obj)
970 if (!obj) 1092 if (!obj)
971 return -EINVAL; 1093 return -EINVAL;
972 1094
973 for (i = 0; i < obj->nr_map_fds; i++) 1095 for (i = 0; i < obj->nr_maps; i++)
974 zclose(obj->map_fds[i]); 1096 zclose(obj->maps[i].fd);
975 zfree(&obj->map_fds);
976 obj->nr_map_fds = 0;
977 1097
978 for (i = 0; i < obj->nr_programs; i++) 1098 for (i = 0; i < obj->nr_programs; i++)
979 bpf_program__unload(&obj->programs[i]); 1099 bpf_program__unload(&obj->programs[i]);
@@ -1016,7 +1136,16 @@ void bpf_object__close(struct bpf_object *obj)
1016 bpf_object__elf_finish(obj); 1136 bpf_object__elf_finish(obj);
1017 bpf_object__unload(obj); 1137 bpf_object__unload(obj);
1018 1138
1019 zfree(&obj->maps_buf); 1139 for (i = 0; i < obj->nr_maps; i++) {
1140 zfree(&obj->maps[i].name);
1141 if (obj->maps[i].clear_priv)
1142 obj->maps[i].clear_priv(&obj->maps[i],
1143 obj->maps[i].priv);
1144 obj->maps[i].priv = NULL;
1145 obj->maps[i].clear_priv = NULL;
1146 }
1147 zfree(&obj->maps);
1148 obj->nr_maps = 0;
1020 1149
1021 if (obj->programs && obj->nr_programs) { 1150 if (obj->programs && obj->nr_programs) {
1022 for (i = 0; i < obj->nr_programs; i++) 1151 for (i = 0; i < obj->nr_programs; i++)
@@ -1121,5 +1250,142 @@ const char *bpf_program__title(struct bpf_program *prog, bool needs_copy)
1121 1250
1122int bpf_program__fd(struct bpf_program *prog) 1251int bpf_program__fd(struct bpf_program *prog)
1123{ 1252{
1124 return prog->fd; 1253 return bpf_program__nth_fd(prog, 0);
1254}
1255
1256int bpf_program__set_prep(struct bpf_program *prog, int nr_instances,
1257 bpf_program_prep_t prep)
1258{
1259 int *instances_fds;
1260
1261 if (nr_instances <= 0 || !prep)
1262 return -EINVAL;
1263
1264 if (prog->instances.nr > 0 || prog->instances.fds) {
1265 pr_warning("Can't set pre-processor after loading\n");
1266 return -EINVAL;
1267 }
1268
1269 instances_fds = malloc(sizeof(int) * nr_instances);
1270 if (!instances_fds) {
1271 pr_warning("alloc memory failed for fds\n");
1272 return -ENOMEM;
1273 }
1274
1275 /* fill all fd with -1 */
1276 memset(instances_fds, -1, sizeof(int) * nr_instances);
1277
1278 prog->instances.nr = nr_instances;
1279 prog->instances.fds = instances_fds;
1280 prog->preprocessor = prep;
1281 return 0;
1282}
1283
1284int bpf_program__nth_fd(struct bpf_program *prog, int n)
1285{
1286 int fd;
1287
1288 if (n >= prog->instances.nr || n < 0) {
1289 pr_warning("Can't get the %dth fd from program %s: only %d instances\n",
1290 n, prog->section_name, prog->instances.nr);
1291 return -EINVAL;
1292 }
1293
1294 fd = prog->instances.fds[n];
1295 if (fd < 0) {
1296 pr_warning("%dth instance of program '%s' is invalid\n",
1297 n, prog->section_name);
1298 return -ENOENT;
1299 }
1300
1301 return fd;
1302}
1303
1304int bpf_map__get_fd(struct bpf_map *map)
1305{
1306 if (!map)
1307 return -EINVAL;
1308
1309 return map->fd;
1310}
1311
1312int bpf_map__get_def(struct bpf_map *map, struct bpf_map_def *pdef)
1313{
1314 if (!map || !pdef)
1315 return -EINVAL;
1316
1317 *pdef = map->def;
1318 return 0;
1319}
1320
1321const char *bpf_map__get_name(struct bpf_map *map)
1322{
1323 if (!map)
1324 return NULL;
1325 return map->name;
1326}
1327
1328int bpf_map__set_private(struct bpf_map *map, void *priv,
1329 bpf_map_clear_priv_t clear_priv)
1330{
1331 if (!map)
1332 return -EINVAL;
1333
1334 if (map->priv) {
1335 if (map->clear_priv)
1336 map->clear_priv(map, map->priv);
1337 }
1338
1339 map->priv = priv;
1340 map->clear_priv = clear_priv;
1341 return 0;
1342}
1343
1344int bpf_map__get_private(struct bpf_map *map, void **ppriv)
1345{
1346 if (!map)
1347 return -EINVAL;
1348
1349 if (ppriv)
1350 *ppriv = map->priv;
1351 return 0;
1352}
1353
1354struct bpf_map *
1355bpf_map__next(struct bpf_map *prev, struct bpf_object *obj)
1356{
1357 size_t idx;
1358 struct bpf_map *s, *e;
1359
1360 if (!obj || !obj->maps)
1361 return NULL;
1362
1363 s = obj->maps;
1364 e = obj->maps + obj->nr_maps;
1365
1366 if (prev == NULL)
1367 return s;
1368
1369 if ((prev < s) || (prev >= e)) {
1370 pr_warning("error in %s: map handler doesn't belong to object\n",
1371 __func__);
1372 return NULL;
1373 }
1374
1375 idx = (prev - obj->maps) + 1;
1376 if (idx >= obj->nr_maps)
1377 return NULL;
1378 return &obj->maps[idx];
1379}
1380
1381struct bpf_map *
1382bpf_object__get_map_by_name(struct bpf_object *obj, const char *name)
1383{
1384 struct bpf_map *pos;
1385
1386 bpf_map__for_each(pos, obj) {
1387 if (pos->name && !strcmp(pos->name, name))
1388 return pos;
1389 }
1390 return NULL;
1125} 1391}
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index c9a9aef2806c..a51594c7b518 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -88,6 +88,70 @@ const char *bpf_program__title(struct bpf_program *prog, bool needs_copy);
88 88
89int bpf_program__fd(struct bpf_program *prog); 89int bpf_program__fd(struct bpf_program *prog);
90 90
91struct bpf_insn;
92
93/*
94 * Libbpf allows callers to adjust BPF programs before being loaded
95 * into kernel. One program in an object file can be transform into
96 * multiple variants to be attached to different code.
97 *
98 * bpf_program_prep_t, bpf_program__set_prep and bpf_program__nth_fd
99 * are APIs for this propose.
100 *
101 * - bpf_program_prep_t:
102 * It defines 'preprocessor', which is a caller defined function
103 * passed to libbpf through bpf_program__set_prep(), and will be
104 * called before program is loaded. The processor should adjust
105 * the program one time for each instances according to the number
106 * passed to it.
107 *
108 * - bpf_program__set_prep:
109 * Attachs a preprocessor to a BPF program. The number of instances
110 * whould be created is also passed through this function.
111 *
112 * - bpf_program__nth_fd:
113 * After the program is loaded, get resuling fds from bpf program for
114 * each instances.
115 *
116 * If bpf_program__set_prep() is not used, the program whould be loaded
117 * without adjustment during bpf_object__load(). The program has only
118 * one instance. In this case bpf_program__fd(prog) is equal to
119 * bpf_program__nth_fd(prog, 0).
120 */
121
122struct bpf_prog_prep_result {
123 /*
124 * If not NULL, load new instruction array.
125 * If set to NULL, don't load this instance.
126 */
127 struct bpf_insn *new_insn_ptr;
128 int new_insn_cnt;
129
130 /* If not NULL, result fd is set to it */
131 int *pfd;
132};
133
134/*
135 * Parameters of bpf_program_prep_t:
136 * - prog: The bpf_program being loaded.
137 * - n: Index of instance being generated.
138 * - insns: BPF instructions array.
139 * - insns_cnt:Number of instructions in insns.
140 * - res: Output parameter, result of transformation.
141 *
142 * Return value:
143 * - Zero: pre-processing success.
144 * - Non-zero: pre-processing, stop loading.
145 */
146typedef int (*bpf_program_prep_t)(struct bpf_program *prog, int n,
147 struct bpf_insn *insns, int insns_cnt,
148 struct bpf_prog_prep_result *res);
149
150int bpf_program__set_prep(struct bpf_program *prog, int nr_instance,
151 bpf_program_prep_t prep);
152
153int bpf_program__nth_fd(struct bpf_program *prog, int n);
154
91/* 155/*
92 * We don't need __attribute__((packed)) now since it is 156 * We don't need __attribute__((packed)) now since it is
93 * unnecessary for 'bpf_map_def' because they are all aligned. 157 * unnecessary for 'bpf_map_def' because they are all aligned.
@@ -101,4 +165,28 @@ struct bpf_map_def {
101 unsigned int max_entries; 165 unsigned int max_entries;
102}; 166};
103 167
168/*
169 * There is another 'struct bpf_map' in include/linux/map.h. However,
170 * it is not a uapi header so no need to consider name clash.
171 */
172struct bpf_map;
173struct bpf_map *
174bpf_object__get_map_by_name(struct bpf_object *obj, const char *name);
175
176struct bpf_map *
177bpf_map__next(struct bpf_map *map, struct bpf_object *obj);
178#define bpf_map__for_each(pos, obj) \
179 for ((pos) = bpf_map__next(NULL, (obj)); \
180 (pos) != NULL; \
181 (pos) = bpf_map__next((pos), (obj)))
182
183int bpf_map__get_fd(struct bpf_map *map);
184int bpf_map__get_def(struct bpf_map *map, struct bpf_map_def *pdef);
185const char *bpf_map__get_name(struct bpf_map *map);
186
187typedef void (*bpf_map_clear_priv_t)(struct bpf_map *, void *);
188int bpf_map__set_private(struct bpf_map *map, void *priv,
189 bpf_map_clear_priv_t clear_priv);
190int bpf_map__get_private(struct bpf_map *map, void **ppriv);
191
104#endif 192#endif
diff --git a/tools/lib/find_bit.c b/tools/lib/find_bit.c
new file mode 100644
index 000000000000..9122a9e80046
--- /dev/null
+++ b/tools/lib/find_bit.c
@@ -0,0 +1,84 @@
1/* bit search implementation
2 *
3 * Copied from lib/find_bit.c to tools/lib/find_bit.c
4 *
5 * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
6 * Written by David Howells (dhowells@redhat.com)
7 *
8 * Copyright (C) 2008 IBM Corporation
9 * 'find_last_bit' is written by Rusty Russell <rusty@rustcorp.com.au>
10 * (Inspired by David Howell's find_next_bit implementation)
11 *
12 * Rewritten by Yury Norov <yury.norov@gmail.com> to decrease
13 * size and improve performance, 2015.
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version
18 * 2 of the License, or (at your option) any later version.
19 */
20
21#include <linux/bitops.h>
22#include <linux/bitmap.h>
23#include <linux/kernel.h>
24
25#if !defined(find_next_bit)
26
27/*
28 * This is a common helper function for find_next_bit and
29 * find_next_zero_bit. The difference is the "invert" argument, which
30 * is XORed with each fetched word before searching it for one bits.
31 */
32static unsigned long _find_next_bit(const unsigned long *addr,
33 unsigned long nbits, unsigned long start, unsigned long invert)
34{
35 unsigned long tmp;
36
37 if (!nbits || start >= nbits)
38 return nbits;
39
40 tmp = addr[start / BITS_PER_LONG] ^ invert;
41
42 /* Handle 1st word. */
43 tmp &= BITMAP_FIRST_WORD_MASK(start);
44 start = round_down(start, BITS_PER_LONG);
45
46 while (!tmp) {
47 start += BITS_PER_LONG;
48 if (start >= nbits)
49 return nbits;
50
51 tmp = addr[start / BITS_PER_LONG] ^ invert;
52 }
53
54 return min(start + __ffs(tmp), nbits);
55}
56#endif
57
58#ifndef find_next_bit
59/*
60 * Find the next set bit in a memory region.
61 */
62unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
63 unsigned long offset)
64{
65 return _find_next_bit(addr, size, offset, 0UL);
66}
67#endif
68
69#ifndef find_first_bit
70/*
71 * Find the first set bit in a memory region.
72 */
73unsigned long find_first_bit(const unsigned long *addr, unsigned long size)
74{
75 unsigned long idx;
76
77 for (idx = 0; idx * BITS_PER_LONG < size; idx++) {
78 if (addr[idx])
79 return min(idx * BITS_PER_LONG + __ffs(addr[idx]), size);
80 }
81
82 return size;
83}
84#endif
diff --git a/tools/lib/lockdep/Makefile b/tools/lib/lockdep/Makefile
index 7e319afac78a..90d2baeb621a 100644
--- a/tools/lib/lockdep/Makefile
+++ b/tools/lib/lockdep/Makefile
@@ -149,7 +149,7 @@ install_lib: all_cmd
149install: install_lib 149install: install_lib
150 150
151clean: 151clean:
152 $(RM) *.o *~ $(TARGETS) *.a *liblockdep*.so* $(VERSION_FILES) .*.d 152 $(RM) *.o *~ $(TARGETS) *.a *liblockdep*.so* $(VERSION_FILES) .*.d .*.cmd
153 $(RM) tags TAGS 153 $(RM) tags TAGS
154 154
155PHONY += force 155PHONY += force
diff --git a/tools/lib/string.c b/tools/lib/string.c
new file mode 100644
index 000000000000..bd239bc1d557
--- /dev/null
+++ b/tools/lib/string.c
@@ -0,0 +1,89 @@
1/*
2 * linux/tools/lib/string.c
3 *
4 * Copied from linux/lib/string.c, where it is:
5 *
6 * Copyright (C) 1991, 1992 Linus Torvalds
7 *
8 * More specifically, the first copied function was strtobool, which
9 * was introduced by:
10 *
11 * d0f1fed29e6e ("Add a strtobool function matching semantics of existing in kernel equivalents")
12 * Author: Jonathan Cameron <jic23@cam.ac.uk>
13 */
14
15#include <stdlib.h>
16#include <string.h>
17#include <errno.h>
18#include <linux/string.h>
19#include <linux/compiler.h>
20
21/**
22 * memdup - duplicate region of memory
23 *
24 * @src: memory region to duplicate
25 * @len: memory region length
26 */
27void *memdup(const void *src, size_t len)
28{
29 void *p = malloc(len);
30
31 if (p)
32 memcpy(p, src, len);
33
34 return p;
35}
36
37/**
38 * strtobool - convert common user inputs into boolean values
39 * @s: input string
40 * @res: result
41 *
42 * This routine returns 0 iff the first character is one of 'Yy1Nn0'.
43 * Otherwise it will return -EINVAL. Value pointed to by res is
44 * updated upon finding a match.
45 */
46int strtobool(const char *s, bool *res)
47{
48 switch (s[0]) {
49 case 'y':
50 case 'Y':
51 case '1':
52 *res = true;
53 break;
54 case 'n':
55 case 'N':
56 case '0':
57 *res = false;
58 break;
59 default:
60 return -EINVAL;
61 }
62 return 0;
63}
64
65/**
66 * strlcpy - Copy a C-string into a sized buffer
67 * @dest: Where to copy the string to
68 * @src: Where to copy the string from
69 * @size: size of destination buffer
70 *
71 * Compatible with *BSD: the result is always a valid
72 * NUL-terminated string that fits in the buffer (unless,
73 * of course, the buffer size is zero). It does not pad
74 * out the result like strncpy() does.
75 *
76 * If libc has strlcpy() then that version will override this
77 * implementation:
78 */
79size_t __weak strlcpy(char *dest, const char *src, size_t size)
80{
81 size_t ret = strlen(src);
82
83 if (size) {
84 size_t len = (ret >= size) ? size - 1 : ret;
85 memcpy(dest, src, len);
86 dest[len] = '\0';
87 }
88 return ret;
89}
diff --git a/tools/lib/subcmd/Build b/tools/lib/subcmd/Build
new file mode 100644
index 000000000000..ee31288788c1
--- /dev/null
+++ b/tools/lib/subcmd/Build
@@ -0,0 +1,7 @@
1libsubcmd-y += exec-cmd.o
2libsubcmd-y += help.o
3libsubcmd-y += pager.o
4libsubcmd-y += parse-options.o
5libsubcmd-y += run-command.o
6libsubcmd-y += sigchain.o
7libsubcmd-y += subcmd-config.o
diff --git a/tools/lib/subcmd/Makefile b/tools/lib/subcmd/Makefile
new file mode 100644
index 000000000000..629cf8c14e68
--- /dev/null
+++ b/tools/lib/subcmd/Makefile
@@ -0,0 +1,48 @@
1include ../../scripts/Makefile.include
2include ../../perf/config/utilities.mak # QUIET_CLEAN
3
4ifeq ($(srctree),)
5srctree := $(patsubst %/,%,$(dir $(shell pwd)))
6srctree := $(patsubst %/,%,$(dir $(srctree)))
7srctree := $(patsubst %/,%,$(dir $(srctree)))
8#$(info Determined 'srctree' to be $(srctree))
9endif
10
11CC = $(CROSS_COMPILE)gcc
12AR = $(CROSS_COMPILE)ar
13RM = rm -f
14
15MAKEFLAGS += --no-print-directory
16
17LIBFILE = $(OUTPUT)libsubcmd.a
18
19CFLAGS := $(EXTRA_WARNINGS) $(EXTRA_CFLAGS)
20CFLAGS += -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -fPIC
21CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
22
23CFLAGS += -I$(srctree)/tools/include/
24CFLAGS += -I$(srctree)/include/uapi
25CFLAGS += -I$(srctree)/include
26
27SUBCMD_IN := $(OUTPUT)libsubcmd-in.o
28
29all:
30
31export srctree OUTPUT CC LD CFLAGS V
32include $(srctree)/tools/build/Makefile.include
33
34all: fixdep $(LIBFILE)
35
36$(SUBCMD_IN): FORCE
37 @$(MAKE) $(build)=libsubcmd
38
39$(LIBFILE): $(SUBCMD_IN)
40 $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(SUBCMD_IN)
41
42clean:
43 $(call QUIET_CLEAN, libsubcmd) $(RM) $(LIBFILE); \
44 find $(if $(OUTPUT),$(OUTPUT),.) -name \*.o -or -name \*.o.cmd -or -name \*.o.d | xargs $(RM)
45
46FORCE:
47
48.PHONY: clean FORCE
diff --git a/tools/lib/subcmd/exec-cmd.c b/tools/lib/subcmd/exec-cmd.c
new file mode 100644
index 000000000000..1ae833af1a4a
--- /dev/null
+++ b/tools/lib/subcmd/exec-cmd.c
@@ -0,0 +1,209 @@
1#include <linux/compiler.h>
2#include <linux/string.h>
3#include <sys/types.h>
4#include <sys/stat.h>
5#include <unistd.h>
6#include <string.h>
7#include <stdlib.h>
8#include <stdio.h>
9#include "subcmd-util.h"
10#include "exec-cmd.h"
11#include "subcmd-config.h"
12
13#define MAX_ARGS 32
14#define PATH_MAX 4096
15
16static const char *argv_exec_path;
17static const char *argv0_path;
18
19void exec_cmd_init(const char *exec_name, const char *prefix,
20 const char *exec_path, const char *exec_path_env)
21{
22 subcmd_config.exec_name = exec_name;
23 subcmd_config.prefix = prefix;
24 subcmd_config.exec_path = exec_path;
25 subcmd_config.exec_path_env = exec_path_env;
26}
27
28#define is_dir_sep(c) ((c) == '/')
29
30static int is_absolute_path(const char *path)
31{
32 return path[0] == '/';
33}
34
35static const char *get_pwd_cwd(void)
36{
37 static char cwd[PATH_MAX + 1];
38 char *pwd;
39 struct stat cwd_stat, pwd_stat;
40 if (getcwd(cwd, PATH_MAX) == NULL)
41 return NULL;
42 pwd = getenv("PWD");
43 if (pwd && strcmp(pwd, cwd)) {
44 stat(cwd, &cwd_stat);
45 if (!stat(pwd, &pwd_stat) &&
46 pwd_stat.st_dev == cwd_stat.st_dev &&
47 pwd_stat.st_ino == cwd_stat.st_ino) {
48 strlcpy(cwd, pwd, PATH_MAX);
49 }
50 }
51 return cwd;
52}
53
54static const char *make_nonrelative_path(const char *path)
55{
56 static char buf[PATH_MAX + 1];
57
58 if (is_absolute_path(path)) {
59 if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
60 die("Too long path: %.*s", 60, path);
61 } else {
62 const char *cwd = get_pwd_cwd();
63 if (!cwd)
64 die("Cannot determine the current working directory");
65 if (snprintf(buf, PATH_MAX, "%s/%s", cwd, path) >= PATH_MAX)
66 die("Too long path: %.*s", 60, path);
67 }
68 return buf;
69}
70
71char *system_path(const char *path)
72{
73 char *buf = NULL;
74
75 if (is_absolute_path(path))
76 return strdup(path);
77
78 astrcatf(&buf, "%s/%s", subcmd_config.prefix, path);
79
80 return buf;
81}
82
83const char *extract_argv0_path(const char *argv0)
84{
85 const char *slash;
86
87 if (!argv0 || !*argv0)
88 return NULL;
89 slash = argv0 + strlen(argv0);
90
91 while (argv0 <= slash && !is_dir_sep(*slash))
92 slash--;
93
94 if (slash >= argv0) {
95 argv0_path = strndup(argv0, slash - argv0);
96 return argv0_path ? slash + 1 : NULL;
97 }
98
99 return argv0;
100}
101
102void set_argv_exec_path(const char *exec_path)
103{
104 argv_exec_path = exec_path;
105 /*
106 * Propagate this setting to external programs.
107 */
108 setenv(subcmd_config.exec_path_env, exec_path, 1);
109}
110
111
112/* Returns the highest-priority location to look for subprograms. */
113char *get_argv_exec_path(void)
114{
115 char *env;
116
117 if (argv_exec_path)
118 return strdup(argv_exec_path);
119
120 env = getenv(subcmd_config.exec_path_env);
121 if (env && *env)
122 return strdup(env);
123
124 return system_path(subcmd_config.exec_path);
125}
126
127static void add_path(char **out, const char *path)
128{
129 if (path && *path) {
130 if (is_absolute_path(path))
131 astrcat(out, path);
132 else
133 astrcat(out, make_nonrelative_path(path));
134
135 astrcat(out, ":");
136 }
137}
138
139void setup_path(void)
140{
141 const char *old_path = getenv("PATH");
142 char *new_path = NULL;
143 char *tmp = get_argv_exec_path();
144
145 add_path(&new_path, tmp);
146 add_path(&new_path, argv0_path);
147 free(tmp);
148
149 if (old_path)
150 astrcat(&new_path, old_path);
151 else
152 astrcat(&new_path, "/usr/local/bin:/usr/bin:/bin");
153
154 setenv("PATH", new_path, 1);
155
156 free(new_path);
157}
158
159static const char **prepare_exec_cmd(const char **argv)
160{
161 int argc;
162 const char **nargv;
163
164 for (argc = 0; argv[argc]; argc++)
165 ; /* just counting */
166 nargv = malloc(sizeof(*nargv) * (argc + 2));
167
168 nargv[0] = subcmd_config.exec_name;
169 for (argc = 0; argv[argc]; argc++)
170 nargv[argc + 1] = argv[argc];
171 nargv[argc + 1] = NULL;
172 return nargv;
173}
174
175int execv_cmd(const char **argv) {
176 const char **nargv = prepare_exec_cmd(argv);
177
178 /* execvp() can only ever return if it fails */
179 execvp(subcmd_config.exec_name, (char **)nargv);
180
181 free(nargv);
182 return -1;
183}
184
185
186int execl_cmd(const char *cmd,...)
187{
188 int argc;
189 const char *argv[MAX_ARGS + 1];
190 const char *arg;
191 va_list param;
192
193 va_start(param, cmd);
194 argv[0] = cmd;
195 argc = 1;
196 while (argc < MAX_ARGS) {
197 arg = argv[argc++] = va_arg(param, char *);
198 if (!arg)
199 break;
200 }
201 va_end(param);
202 if (MAX_ARGS <= argc) {
203 fprintf(stderr, " Error: too many args to run %s\n", cmd);
204 return -1;
205 }
206
207 argv[argc] = NULL;
208 return execv_cmd(argv);
209}
diff --git a/tools/lib/subcmd/exec-cmd.h b/tools/lib/subcmd/exec-cmd.h
new file mode 100644
index 000000000000..5d08bda31d90
--- /dev/null
+++ b/tools/lib/subcmd/exec-cmd.h
@@ -0,0 +1,16 @@
1#ifndef __SUBCMD_EXEC_CMD_H
2#define __SUBCMD_EXEC_CMD_H
3
4extern void exec_cmd_init(const char *exec_name, const char *prefix,
5 const char *exec_path, const char *exec_path_env);
6
7extern void set_argv_exec_path(const char *exec_path);
8extern const char *extract_argv0_path(const char *path);
9extern void setup_path(void);
10extern int execv_cmd(const char **argv); /* NULL terminated */
11extern int execl_cmd(const char *cmd, ...);
12/* get_argv_exec_path and system_path return malloc'd string, caller must free it */
13extern char *get_argv_exec_path(void);
14extern char *system_path(const char *path);
15
16#endif /* __SUBCMD_EXEC_CMD_H */
diff --git a/tools/perf/util/help.c b/tools/lib/subcmd/help.c
index 86c37c472263..e228c3cb3716 100644
--- a/tools/perf/util/help.c
+++ b/tools/lib/subcmd/help.c
@@ -1,9 +1,15 @@
1#include "cache.h" 1#include <stdio.h>
2#include "../builtin.h" 2#include <stdlib.h>
3#include "exec_cmd.h" 3#include <string.h>
4#include "levenshtein.h"
5#include "help.h"
6#include <termios.h> 4#include <termios.h>
5#include <sys/ioctl.h>
6#include <sys/types.h>
7#include <sys/stat.h>
8#include <unistd.h>
9#include <dirent.h>
10#include "subcmd-util.h"
11#include "help.h"
12#include "exec-cmd.h"
7 13
8void add_cmdname(struct cmdnames *cmds, const char *name, size_t len) 14void add_cmdname(struct cmdnames *cmds, const char *name, size_t len)
9{ 15{
@@ -17,7 +23,7 @@ void add_cmdname(struct cmdnames *cmds, const char *name, size_t len)
17 cmds->names[cmds->cnt++] = ent; 23 cmds->names[cmds->cnt++] = ent;
18} 24}
19 25
20static void clean_cmdnames(struct cmdnames *cmds) 26void clean_cmdnames(struct cmdnames *cmds)
21{ 27{
22 unsigned int i; 28 unsigned int i;
23 29
@@ -28,14 +34,14 @@ static void clean_cmdnames(struct cmdnames *cmds)
28 cmds->alloc = 0; 34 cmds->alloc = 0;
29} 35}
30 36
31static int cmdname_compare(const void *a_, const void *b_) 37int cmdname_compare(const void *a_, const void *b_)
32{ 38{
33 struct cmdname *a = *(struct cmdname **)a_; 39 struct cmdname *a = *(struct cmdname **)a_;
34 struct cmdname *b = *(struct cmdname **)b_; 40 struct cmdname *b = *(struct cmdname **)b_;
35 return strcmp(a->name, b->name); 41 return strcmp(a->name, b->name);
36} 42}
37 43
38static void uniq(struct cmdnames *cmds) 44void uniq(struct cmdnames *cmds)
39{ 45{
40 unsigned int i, j; 46 unsigned int i, j;
41 47
@@ -71,6 +77,28 @@ void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes)
71 cmds->cnt = cj; 77 cmds->cnt = cj;
72} 78}
73 79
80static void get_term_dimensions(struct winsize *ws)
81{
82 char *s = getenv("LINES");
83
84 if (s != NULL) {
85 ws->ws_row = atoi(s);
86 s = getenv("COLUMNS");
87 if (s != NULL) {
88 ws->ws_col = atoi(s);
89 if (ws->ws_row && ws->ws_col)
90 return;
91 }
92 }
93#ifdef TIOCGWINSZ
94 if (ioctl(1, TIOCGWINSZ, ws) == 0 &&
95 ws->ws_row && ws->ws_col)
96 return;
97#endif
98 ws->ws_row = 25;
99 ws->ws_col = 80;
100}
101
74static void pretty_print_string_list(struct cmdnames *cmds, int longest) 102static void pretty_print_string_list(struct cmdnames *cmds, int longest)
75{ 103{
76 int cols = 1, rows; 104 int cols = 1, rows;
@@ -114,6 +142,14 @@ static int is_executable(const char *name)
114 return st.st_mode & S_IXUSR; 142 return st.st_mode & S_IXUSR;
115} 143}
116 144
145static int has_extension(const char *filename, const char *ext)
146{
147 size_t len = strlen(filename);
148 size_t extlen = strlen(ext);
149
150 return len > extlen && !memcmp(filename + len - extlen, ext, extlen);
151}
152
117static void list_commands_in_dir(struct cmdnames *cmds, 153static void list_commands_in_dir(struct cmdnames *cmds,
118 const char *path, 154 const char *path,
119 const char *prefix) 155 const char *prefix)
@@ -121,8 +157,7 @@ static void list_commands_in_dir(struct cmdnames *cmds,
121 int prefix_len; 157 int prefix_len;
122 DIR *dir = opendir(path); 158 DIR *dir = opendir(path);
123 struct dirent *de; 159 struct dirent *de;
124 struct strbuf buf = STRBUF_INIT; 160 char *buf = NULL;
125 int len;
126 161
127 if (!dir) 162 if (!dir)
128 return; 163 return;
@@ -130,8 +165,7 @@ static void list_commands_in_dir(struct cmdnames *cmds,
130 prefix = "perf-"; 165 prefix = "perf-";
131 prefix_len = strlen(prefix); 166 prefix_len = strlen(prefix);
132 167
133 strbuf_addf(&buf, "%s/", path); 168 astrcatf(&buf, "%s/", path);
134 len = buf.len;
135 169
136 while ((de = readdir(dir)) != NULL) { 170 while ((de = readdir(dir)) != NULL) {
137 int entlen; 171 int entlen;
@@ -139,9 +173,8 @@ static void list_commands_in_dir(struct cmdnames *cmds,
139 if (prefixcmp(de->d_name, prefix)) 173 if (prefixcmp(de->d_name, prefix))
140 continue; 174 continue;
141 175
142 strbuf_setlen(&buf, len); 176 astrcat(&buf, de->d_name);
143 strbuf_addstr(&buf, de->d_name); 177 if (!is_executable(buf))
144 if (!is_executable(buf.buf))
145 continue; 178 continue;
146 179
147 entlen = strlen(de->d_name) - prefix_len; 180 entlen = strlen(de->d_name) - prefix_len;
@@ -151,7 +184,7 @@ static void list_commands_in_dir(struct cmdnames *cmds,
151 add_cmdname(cmds, de->d_name + prefix_len, entlen); 184 add_cmdname(cmds, de->d_name + prefix_len, entlen);
152 } 185 }
153 closedir(dir); 186 closedir(dir);
154 strbuf_release(&buf); 187 free(buf);
155} 188}
156 189
157void load_command_list(const char *prefix, 190void load_command_list(const char *prefix,
@@ -159,7 +192,7 @@ void load_command_list(const char *prefix,
159 struct cmdnames *other_cmds) 192 struct cmdnames *other_cmds)
160{ 193{
161 const char *env_path = getenv("PATH"); 194 const char *env_path = getenv("PATH");
162 const char *exec_path = perf_exec_path(); 195 char *exec_path = get_argv_exec_path();
163 196
164 if (exec_path) { 197 if (exec_path) {
165 list_commands_in_dir(main_cmds, exec_path, prefix); 198 list_commands_in_dir(main_cmds, exec_path, prefix);
@@ -172,7 +205,7 @@ void load_command_list(const char *prefix,
172 char *paths, *path, *colon; 205 char *paths, *path, *colon;
173 path = paths = strdup(env_path); 206 path = paths = strdup(env_path);
174 while (1) { 207 while (1) {
175 if ((colon = strchr(path, PATH_SEP))) 208 if ((colon = strchr(path, ':')))
176 *colon = 0; 209 *colon = 0;
177 if (!exec_path || strcmp(path, exec_path)) 210 if (!exec_path || strcmp(path, exec_path))
178 list_commands_in_dir(other_cmds, path, prefix); 211 list_commands_in_dir(other_cmds, path, prefix);
@@ -187,6 +220,7 @@ void load_command_list(const char *prefix,
187 sizeof(*other_cmds->names), cmdname_compare); 220 sizeof(*other_cmds->names), cmdname_compare);
188 uniq(other_cmds); 221 uniq(other_cmds);
189 } 222 }
223 free(exec_path);
190 exclude_cmds(other_cmds, main_cmds); 224 exclude_cmds(other_cmds, main_cmds);
191} 225}
192 226
@@ -203,13 +237,14 @@ void list_commands(const char *title, struct cmdnames *main_cmds,
203 longest = other_cmds->names[i]->len; 237 longest = other_cmds->names[i]->len;
204 238
205 if (main_cmds->cnt) { 239 if (main_cmds->cnt) {
206 const char *exec_path = perf_exec_path(); 240 char *exec_path = get_argv_exec_path();
207 printf("available %s in '%s'\n", title, exec_path); 241 printf("available %s in '%s'\n", title, exec_path);
208 printf("----------------"); 242 printf("----------------");
209 mput_char('-', strlen(title) + strlen(exec_path)); 243 mput_char('-', strlen(title) + strlen(exec_path));
210 putchar('\n'); 244 putchar('\n');
211 pretty_print_string_list(main_cmds, longest); 245 pretty_print_string_list(main_cmds, longest);
212 putchar('\n'); 246 putchar('\n');
247 free(exec_path);
213 } 248 }
214 249
215 if (other_cmds->cnt) { 250 if (other_cmds->cnt) {
@@ -231,109 +266,3 @@ int is_in_cmdlist(struct cmdnames *c, const char *s)
231 return 1; 266 return 1;
232 return 0; 267 return 0;
233} 268}
234
235static int autocorrect;
236static struct cmdnames aliases;
237
238static int perf_unknown_cmd_config(const char *var, const char *value, void *cb)
239{
240 if (!strcmp(var, "help.autocorrect"))
241 autocorrect = perf_config_int(var,value);
242 /* Also use aliases for command lookup */
243 if (!prefixcmp(var, "alias."))
244 add_cmdname(&aliases, var + 6, strlen(var + 6));
245
246 return perf_default_config(var, value, cb);
247}
248
249static int levenshtein_compare(const void *p1, const void *p2)
250{
251 const struct cmdname *const *c1 = p1, *const *c2 = p2;
252 const char *s1 = (*c1)->name, *s2 = (*c2)->name;
253 int l1 = (*c1)->len;
254 int l2 = (*c2)->len;
255 return l1 != l2 ? l1 - l2 : strcmp(s1, s2);
256}
257
258static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old)
259{
260 unsigned int i;
261
262 ALLOC_GROW(cmds->names, cmds->cnt + old->cnt, cmds->alloc);
263
264 for (i = 0; i < old->cnt; i++)
265 cmds->names[cmds->cnt++] = old->names[i];
266 zfree(&old->names);
267 old->cnt = 0;
268}
269
270const char *help_unknown_cmd(const char *cmd)
271{
272 unsigned int i, n = 0, best_similarity = 0;
273 struct cmdnames main_cmds, other_cmds;
274
275 memset(&main_cmds, 0, sizeof(main_cmds));
276 memset(&other_cmds, 0, sizeof(main_cmds));
277 memset(&aliases, 0, sizeof(aliases));
278
279 perf_config(perf_unknown_cmd_config, NULL);
280
281 load_command_list("perf-", &main_cmds, &other_cmds);
282
283 add_cmd_list(&main_cmds, &aliases);
284 add_cmd_list(&main_cmds, &other_cmds);
285 qsort(main_cmds.names, main_cmds.cnt,
286 sizeof(main_cmds.names), cmdname_compare);
287 uniq(&main_cmds);
288
289 if (main_cmds.cnt) {
290 /* This reuses cmdname->len for similarity index */
291 for (i = 0; i < main_cmds.cnt; ++i)
292 main_cmds.names[i]->len =
293 levenshtein(cmd, main_cmds.names[i]->name, 0, 2, 1, 4);
294
295 qsort(main_cmds.names, main_cmds.cnt,
296 sizeof(*main_cmds.names), levenshtein_compare);
297
298 best_similarity = main_cmds.names[0]->len;
299 n = 1;
300 while (n < main_cmds.cnt && best_similarity == main_cmds.names[n]->len)
301 ++n;
302 }
303
304 if (autocorrect && n == 1) {
305 const char *assumed = main_cmds.names[0]->name;
306
307 main_cmds.names[0] = NULL;
308 clean_cmdnames(&main_cmds);
309 fprintf(stderr, "WARNING: You called a perf program named '%s', "
310 "which does not exist.\n"
311 "Continuing under the assumption that you meant '%s'\n",
312 cmd, assumed);
313 if (autocorrect > 0) {
314 fprintf(stderr, "in %0.1f seconds automatically...\n",
315 (float)autocorrect/10.0);
316 poll(NULL, 0, autocorrect * 100);
317 }
318 return assumed;
319 }
320
321 fprintf(stderr, "perf: '%s' is not a perf-command. See 'perf --help'.\n", cmd);
322
323 if (main_cmds.cnt && best_similarity < 6) {
324 fprintf(stderr, "\nDid you mean %s?\n",
325 n < 2 ? "this": "one of these");
326
327 for (i = 0; i < n; i++)
328 fprintf(stderr, "\t%s\n", main_cmds.names[i]->name);
329 }
330
331 exit(1);
332}
333
334int cmd_version(int argc __maybe_unused, const char **argv __maybe_unused,
335 const char *prefix __maybe_unused)
336{
337 printf("perf version %s\n", perf_version_string);
338 return 0;
339}
diff --git a/tools/perf/util/help.h b/tools/lib/subcmd/help.h
index 7f5c6dedd714..e145a020780c 100644
--- a/tools/perf/util/help.h
+++ b/tools/lib/subcmd/help.h
@@ -1,12 +1,14 @@
1#ifndef __PERF_HELP_H 1#ifndef __SUBCMD_HELP_H
2#define __PERF_HELP_H 2#define __SUBCMD_HELP_H
3
4#include <sys/types.h>
3 5
4struct cmdnames { 6struct cmdnames {
5 size_t alloc; 7 size_t alloc;
6 size_t cnt; 8 size_t cnt;
7 struct cmdname { 9 struct cmdname {
8 size_t len; /* also used for similarity index in help.c */ 10 size_t len; /* also used for similarity index in help.c */
9 char name[FLEX_ARRAY]; 11 char name[];
10 } **names; 12 } **names;
11}; 13};
12 14
@@ -20,10 +22,13 @@ void load_command_list(const char *prefix,
20 struct cmdnames *main_cmds, 22 struct cmdnames *main_cmds,
21 struct cmdnames *other_cmds); 23 struct cmdnames *other_cmds);
22void add_cmdname(struct cmdnames *cmds, const char *name, size_t len); 24void add_cmdname(struct cmdnames *cmds, const char *name, size_t len);
25void clean_cmdnames(struct cmdnames *cmds);
26int cmdname_compare(const void *a, const void *b);
27void uniq(struct cmdnames *cmds);
23/* Here we require that excludes is a sorted list. */ 28/* Here we require that excludes is a sorted list. */
24void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes); 29void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes);
25int is_in_cmdlist(struct cmdnames *c, const char *s); 30int is_in_cmdlist(struct cmdnames *c, const char *s);
26void list_commands(const char *title, struct cmdnames *main_cmds, 31void list_commands(const char *title, struct cmdnames *main_cmds,
27 struct cmdnames *other_cmds); 32 struct cmdnames *other_cmds);
28 33
29#endif /* __PERF_HELP_H */ 34#endif /* __SUBCMD_HELP_H */
diff --git a/tools/perf/util/pager.c b/tools/lib/subcmd/pager.c
index 53ef006a951c..d50f3b58606b 100644
--- a/tools/perf/util/pager.c
+++ b/tools/lib/subcmd/pager.c
@@ -1,6 +1,12 @@
1#include "cache.h" 1#include <sys/select.h>
2#include <stdlib.h>
3#include <stdio.h>
4#include <string.h>
5#include <signal.h>
6#include "pager.h"
2#include "run-command.h" 7#include "run-command.h"
3#include "sigchain.h" 8#include "sigchain.h"
9#include "subcmd-config.h"
4 10
5/* 11/*
6 * This is split up from the rest of git so that we can do 12 * This is split up from the rest of git so that we can do
@@ -9,6 +15,11 @@
9 15
10static int spawned_pager; 16static int spawned_pager;
11 17
18void pager_init(const char *pager_env)
19{
20 subcmd_config.pager_env = pager_env;
21}
22
12static void pager_preexec(void) 23static void pager_preexec(void)
13{ 24{
14 /* 25 /*
@@ -46,7 +57,7 @@ static void wait_for_pager_signal(int signo)
46 57
47void setup_pager(void) 58void setup_pager(void)
48{ 59{
49 const char *pager = getenv("PERF_PAGER"); 60 const char *pager = getenv(subcmd_config.pager_env);
50 61
51 if (!isatty(1)) 62 if (!isatty(1))
52 return; 63 return;
@@ -85,11 +96,5 @@ void setup_pager(void)
85 96
86int pager_in_use(void) 97int pager_in_use(void)
87{ 98{
88 const char *env; 99 return spawned_pager;
89
90 if (spawned_pager)
91 return 1;
92
93 env = getenv("PERF_PAGER_IN_USE");
94 return env ? perf_config_bool("PERF_PAGER_IN_USE", env) : 0;
95} 100}
diff --git a/tools/lib/subcmd/pager.h b/tools/lib/subcmd/pager.h
new file mode 100644
index 000000000000..8b83714ecf73
--- /dev/null
+++ b/tools/lib/subcmd/pager.h
@@ -0,0 +1,9 @@
1#ifndef __SUBCMD_PAGER_H
2#define __SUBCMD_PAGER_H
3
4extern void pager_init(const char *pager_env);
5
6extern void setup_pager(void);
7extern int pager_in_use(void);
8
9#endif /* __SUBCMD_PAGER_H */
diff --git a/tools/perf/util/parse-options.c b/tools/lib/subcmd/parse-options.c
index 9fca09296eb3..981bb4481fd5 100644
--- a/tools/perf/util/parse-options.c
+++ b/tools/lib/subcmd/parse-options.c
@@ -1,37 +1,66 @@
1#include "util.h" 1#include <linux/compiler.h>
2#include <linux/types.h>
3#include <stdio.h>
4#include <stdlib.h>
5#include <stdint.h>
6#include <string.h>
7#include <ctype.h>
8#include "subcmd-util.h"
2#include "parse-options.h" 9#include "parse-options.h"
3#include "cache.h" 10#include "subcmd-config.h"
4#include "header.h" 11#include "pager.h"
5#include <linux/string.h>
6 12
7#define OPT_SHORT 1 13#define OPT_SHORT 1
8#define OPT_UNSET 2 14#define OPT_UNSET 2
9 15
10static struct strbuf error_buf = STRBUF_INIT; 16char *error_buf;
11 17
12static int opterror(const struct option *opt, const char *reason, int flags) 18static int opterror(const struct option *opt, const char *reason, int flags)
13{ 19{
14 if (flags & OPT_SHORT) 20 if (flags & OPT_SHORT)
15 return error("switch `%c' %s", opt->short_name, reason); 21 fprintf(stderr, " Error: switch `%c' %s", opt->short_name, reason);
16 if (flags & OPT_UNSET) 22 else if (flags & OPT_UNSET)
17 return error("option `no-%s' %s", opt->long_name, reason); 23 fprintf(stderr, " Error: option `no-%s' %s", opt->long_name, reason);
18 return error("option `%s' %s", opt->long_name, reason); 24 else
25 fprintf(stderr, " Error: option `%s' %s", opt->long_name, reason);
26
27 return -1;
28}
29
30static const char *skip_prefix(const char *str, const char *prefix)
31{
32 size_t len = strlen(prefix);
33 return strncmp(str, prefix, len) ? NULL : str + len;
34}
35
36static void optwarning(const struct option *opt, const char *reason, int flags)
37{
38 if (flags & OPT_SHORT)
39 fprintf(stderr, " Warning: switch `%c' %s", opt->short_name, reason);
40 else if (flags & OPT_UNSET)
41 fprintf(stderr, " Warning: option `no-%s' %s", opt->long_name, reason);
42 else
43 fprintf(stderr, " Warning: option `%s' %s", opt->long_name, reason);
19} 44}
20 45
21static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt, 46static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt,
22 int flags, const char **arg) 47 int flags, const char **arg)
23{ 48{
49 const char *res;
50
24 if (p->opt) { 51 if (p->opt) {
25 *arg = p->opt; 52 res = p->opt;
26 p->opt = NULL; 53 p->opt = NULL;
27 } else if ((opt->flags & PARSE_OPT_LASTARG_DEFAULT) && (p->argc == 1 || 54 } else if ((opt->flags & PARSE_OPT_LASTARG_DEFAULT) && (p->argc == 1 ||
28 **(p->argv + 1) == '-')) { 55 **(p->argv + 1) == '-')) {
29 *arg = (const char *)opt->defval; 56 res = (const char *)opt->defval;
30 } else if (p->argc > 1) { 57 } else if (p->argc > 1) {
31 p->argc--; 58 p->argc--;
32 *arg = *++p->argv; 59 res = *++p->argv;
33 } else 60 } else
34 return opterror(opt, "requires a value", flags); 61 return opterror(opt, "requires a value", flags);
62 if (arg)
63 *arg = res;
35 return 0; 64 return 0;
36} 65}
37 66
@@ -55,11 +84,11 @@ static int get_value(struct parse_opt_ctx_t *p,
55 84
56 if (((flags & OPT_SHORT) && p->excl_opt->short_name) || 85 if (((flags & OPT_SHORT) && p->excl_opt->short_name) ||
57 p->excl_opt->long_name == NULL) { 86 p->excl_opt->long_name == NULL) {
58 scnprintf(msg, sizeof(msg), "cannot be used with switch `%c'", 87 snprintf(msg, sizeof(msg), "cannot be used with switch `%c'",
59 p->excl_opt->short_name); 88 p->excl_opt->short_name);
60 } else { 89 } else {
61 scnprintf(msg, sizeof(msg), "cannot be used with %s", 90 snprintf(msg, sizeof(msg), "cannot be used with %s",
62 p->excl_opt->long_name); 91 p->excl_opt->long_name);
63 } 92 }
64 opterror(opt, msg, flags); 93 opterror(opt, msg, flags);
65 return -3; 94 return -3;
@@ -91,6 +120,64 @@ static int get_value(struct parse_opt_ctx_t *p,
91 } 120 }
92 } 121 }
93 122
123 if (opt->flags & PARSE_OPT_NOBUILD) {
124 char reason[128];
125 bool noarg = false;
126
127 err = snprintf(reason, sizeof(reason),
128 opt->flags & PARSE_OPT_CANSKIP ?
129 "is being ignored because %s " :
130 "is not available because %s",
131 opt->build_opt);
132 reason[sizeof(reason) - 1] = '\0';
133
134 if (err < 0)
135 strncpy(reason, opt->flags & PARSE_OPT_CANSKIP ?
136 "is being ignored" :
137 "is not available",
138 sizeof(reason));
139
140 if (!(opt->flags & PARSE_OPT_CANSKIP))
141 return opterror(opt, reason, flags);
142
143 err = 0;
144 if (unset)
145 noarg = true;
146 if (opt->flags & PARSE_OPT_NOARG)
147 noarg = true;
148 if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
149 noarg = true;
150
151 switch (opt->type) {
152 case OPTION_BOOLEAN:
153 case OPTION_INCR:
154 case OPTION_BIT:
155 case OPTION_SET_UINT:
156 case OPTION_SET_PTR:
157 case OPTION_END:
158 case OPTION_ARGUMENT:
159 case OPTION_GROUP:
160 noarg = true;
161 break;
162 case OPTION_CALLBACK:
163 case OPTION_STRING:
164 case OPTION_INTEGER:
165 case OPTION_UINTEGER:
166 case OPTION_LONG:
167 case OPTION_U64:
168 default:
169 break;
170 }
171
172 if (!noarg)
173 err = get_arg(p, opt, flags, NULL);
174 if (err)
175 return err;
176
177 optwarning(opt, reason, flags);
178 return 0;
179 }
180
94 switch (opt->type) { 181 switch (opt->type) {
95 case OPTION_BIT: 182 case OPTION_BIT:
96 if (unset) 183 if (unset)
@@ -327,14 +414,16 @@ match:
327 return get_value(p, options, flags); 414 return get_value(p, options, flags);
328 } 415 }
329 416
330 if (ambiguous_option) 417 if (ambiguous_option) {
331 return error("Ambiguous option: %s " 418 fprintf(stderr,
332 "(could be --%s%s or --%s%s)", 419 " Error: Ambiguous option: %s (could be --%s%s or --%s%s)",
333 arg, 420 arg,
334 (ambiguous_flags & OPT_UNSET) ? "no-" : "", 421 (ambiguous_flags & OPT_UNSET) ? "no-" : "",
335 ambiguous_option->long_name, 422 ambiguous_option->long_name,
336 (abbrev_flags & OPT_UNSET) ? "no-" : "", 423 (abbrev_flags & OPT_UNSET) ? "no-" : "",
337 abbrev_option->long_name); 424 abbrev_option->long_name);
425 return -1;
426 }
338 if (abbrev_option) 427 if (abbrev_option)
339 return get_value(p, abbrev_option, abbrev_flags); 428 return get_value(p, abbrev_option, abbrev_flags);
340 return -2; 429 return -2;
@@ -346,7 +435,7 @@ static void check_typos(const char *arg, const struct option *options)
346 return; 435 return;
347 436
348 if (!prefixcmp(arg, "no-")) { 437 if (!prefixcmp(arg, "no-")) {
349 error ("did you mean `--%s` (with two dashes ?)", arg); 438 fprintf(stderr, " Error: did you mean `--%s` (with two dashes ?)", arg);
350 exit(129); 439 exit(129);
351 } 440 }
352 441
@@ -354,14 +443,14 @@ static void check_typos(const char *arg, const struct option *options)
354 if (!options->long_name) 443 if (!options->long_name)
355 continue; 444 continue;
356 if (!prefixcmp(options->long_name, arg)) { 445 if (!prefixcmp(options->long_name, arg)) {
357 error ("did you mean `--%s` (with two dashes ?)", arg); 446 fprintf(stderr, " Error: did you mean `--%s` (with two dashes ?)", arg);
358 exit(129); 447 exit(129);
359 } 448 }
360 } 449 }
361} 450}
362 451
363void parse_options_start(struct parse_opt_ctx_t *ctx, 452static void parse_options_start(struct parse_opt_ctx_t *ctx,
364 int argc, const char **argv, int flags) 453 int argc, const char **argv, int flags)
365{ 454{
366 memset(ctx, 0, sizeof(*ctx)); 455 memset(ctx, 0, sizeof(*ctx));
367 ctx->argc = argc - 1; 456 ctx->argc = argc - 1;
@@ -378,9 +467,9 @@ static int usage_with_options_internal(const char * const *,
378 const struct option *, int, 467 const struct option *, int,
379 struct parse_opt_ctx_t *); 468 struct parse_opt_ctx_t *);
380 469
381int parse_options_step(struct parse_opt_ctx_t *ctx, 470static int parse_options_step(struct parse_opt_ctx_t *ctx,
382 const struct option *options, 471 const struct option *options,
383 const char * const usagestr[]) 472 const char * const usagestr[])
384{ 473{
385 int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP); 474 int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP);
386 int excl_short_opt = 1; 475 int excl_short_opt = 1;
@@ -489,7 +578,7 @@ exclusive:
489 return PARSE_OPT_HELP; 578 return PARSE_OPT_HELP;
490} 579}
491 580
492int parse_options_end(struct parse_opt_ctx_t *ctx) 581static int parse_options_end(struct parse_opt_ctx_t *ctx)
493{ 582{
494 memmove(ctx->out + ctx->cpidx, ctx->argv, ctx->argc * sizeof(*ctx->out)); 583 memmove(ctx->out + ctx->cpidx, ctx->argv, ctx->argc * sizeof(*ctx->out));
495 ctx->out[ctx->cpidx + ctx->argc] = NULL; 584 ctx->out[ctx->cpidx + ctx->argc] = NULL;
@@ -501,22 +590,20 @@ int parse_options_subcommand(int argc, const char **argv, const struct option *o
501{ 590{
502 struct parse_opt_ctx_t ctx; 591 struct parse_opt_ctx_t ctx;
503 592
504 perf_env__set_cmdline(&perf_env, argc, argv);
505
506 /* build usage string if it's not provided */ 593 /* build usage string if it's not provided */
507 if (subcommands && !usagestr[0]) { 594 if (subcommands && !usagestr[0]) {
508 struct strbuf buf = STRBUF_INIT; 595 char *buf = NULL;
596
597 astrcatf(&buf, "%s %s [<options>] {", subcmd_config.exec_name, argv[0]);
509 598
510 strbuf_addf(&buf, "perf %s [<options>] {", argv[0]);
511 for (int i = 0; subcommands[i]; i++) { 599 for (int i = 0; subcommands[i]; i++) {
512 if (i) 600 if (i)
513 strbuf_addstr(&buf, "|"); 601 astrcat(&buf, "|");
514 strbuf_addstr(&buf, subcommands[i]); 602 astrcat(&buf, subcommands[i]);
515 } 603 }
516 strbuf_addstr(&buf, "}"); 604 astrcat(&buf, "}");
517 605
518 usagestr[0] = strdup(buf.buf); 606 usagestr[0] = buf;
519 strbuf_release(&buf);
520 } 607 }
521 608
522 parse_options_start(&ctx, argc, argv, flags); 609 parse_options_start(&ctx, argc, argv, flags);
@@ -541,13 +628,11 @@ int parse_options_subcommand(int argc, const char **argv, const struct option *o
541 putchar('\n'); 628 putchar('\n');
542 exit(130); 629 exit(130);
543 default: /* PARSE_OPT_UNKNOWN */ 630 default: /* PARSE_OPT_UNKNOWN */
544 if (ctx.argv[0][1] == '-') { 631 if (ctx.argv[0][1] == '-')
545 strbuf_addf(&error_buf, "unknown option `%s'", 632 astrcatf(&error_buf, "unknown option `%s'",
546 ctx.argv[0] + 2); 633 ctx.argv[0] + 2);
547 } else { 634 else
548 strbuf_addf(&error_buf, "unknown switch `%c'", 635 astrcatf(&error_buf, "unknown switch `%c'", *ctx.opt);
549 *ctx.opt);
550 }
551 usage_with_options(usagestr, options); 636 usage_with_options(usagestr, options);
552 } 637 }
553 638
@@ -647,6 +732,10 @@ static void print_option_help(const struct option *opts, int full)
647 pad = USAGE_OPTS_WIDTH; 732 pad = USAGE_OPTS_WIDTH;
648 } 733 }
649 fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help); 734 fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
735 if (opts->flags & PARSE_OPT_NOBUILD)
736 fprintf(stderr, "%*s(not built-in because %s)\n",
737 USAGE_OPTS_WIDTH + USAGE_GAP, "",
738 opts->build_opt);
650} 739}
651 740
652static int option__cmp(const void *va, const void *vb) 741static int option__cmp(const void *va, const void *vb)
@@ -672,16 +761,18 @@ static int option__cmp(const void *va, const void *vb)
672 761
673static struct option *options__order(const struct option *opts) 762static struct option *options__order(const struct option *opts)
674{ 763{
675 int nr_opts = 0; 764 int nr_opts = 0, len;
676 const struct option *o = opts; 765 const struct option *o = opts;
677 struct option *ordered; 766 struct option *ordered;
678 767
679 for (o = opts; o->type != OPTION_END; o++) 768 for (o = opts; o->type != OPTION_END; o++)
680 ++nr_opts; 769 ++nr_opts;
681 770
682 ordered = memdup(opts, sizeof(*o) * (nr_opts + 1)); 771 len = sizeof(*o) * (nr_opts + 1);
683 if (ordered == NULL) 772 ordered = malloc(len);
773 if (!ordered)
684 goto out; 774 goto out;
775 memcpy(ordered, opts, len);
685 776
686 qsort(ordered, nr_opts, sizeof(*o), option__cmp); 777 qsort(ordered, nr_opts, sizeof(*o), option__cmp);
687out: 778out:
@@ -719,9 +810,9 @@ static bool option__in_argv(const struct option *opt, const struct parse_opt_ctx
719 return false; 810 return false;
720} 811}
721 812
722int usage_with_options_internal(const char * const *usagestr, 813static int usage_with_options_internal(const char * const *usagestr,
723 const struct option *opts, int full, 814 const struct option *opts, int full,
724 struct parse_opt_ctx_t *ctx) 815 struct parse_opt_ctx_t *ctx)
725{ 816{
726 struct option *ordered; 817 struct option *ordered;
727 818
@@ -730,9 +821,9 @@ int usage_with_options_internal(const char * const *usagestr,
730 821
731 setup_pager(); 822 setup_pager();
732 823
733 if (strbuf_avail(&error_buf)) { 824 if (error_buf) {
734 fprintf(stderr, " Error: %s\n", error_buf.buf); 825 fprintf(stderr, " Error: %s\n", error_buf);
735 strbuf_release(&error_buf); 826 zfree(&error_buf);
736 } 827 }
737 828
738 fprintf(stderr, "\n Usage: %s\n", *usagestr++); 829 fprintf(stderr, "\n Usage: %s\n", *usagestr++);
@@ -768,7 +859,6 @@ int usage_with_options_internal(const char * const *usagestr,
768void usage_with_options(const char * const *usagestr, 859void usage_with_options(const char * const *usagestr,
769 const struct option *opts) 860 const struct option *opts)
770{ 861{
771 exit_browser(false);
772 usage_with_options_internal(usagestr, opts, 0, NULL); 862 usage_with_options_internal(usagestr, opts, 0, NULL);
773 exit(129); 863 exit(129);
774} 864}
@@ -777,13 +867,15 @@ void usage_with_options_msg(const char * const *usagestr,
777 const struct option *opts, const char *fmt, ...) 867 const struct option *opts, const char *fmt, ...)
778{ 868{
779 va_list ap; 869 va_list ap;
780 870 char *tmp = error_buf;
781 exit_browser(false);
782 871
783 va_start(ap, fmt); 872 va_start(ap, fmt);
784 strbuf_addv(&error_buf, fmt, ap); 873 if (vasprintf(&error_buf, fmt, ap) == -1)
874 die("vasprintf failed");
785 va_end(ap); 875 va_end(ap);
786 876
877 free(tmp);
878
787 usage_with_options_internal(usagestr, opts, 0, NULL); 879 usage_with_options_internal(usagestr, opts, 0, NULL);
788 exit(129); 880 exit(129);
789} 881}
@@ -853,15 +945,39 @@ int parse_opt_verbosity_cb(const struct option *opt,
853 return 0; 945 return 0;
854} 946}
855 947
856void set_option_flag(struct option *opts, int shortopt, const char *longopt, 948static struct option *
857 int flag) 949find_option(struct option *opts, int shortopt, const char *longopt)
858{ 950{
859 for (; opts->type != OPTION_END; opts++) { 951 for (; opts->type != OPTION_END; opts++) {
860 if ((shortopt && opts->short_name == shortopt) || 952 if ((shortopt && opts->short_name == shortopt) ||
861 (opts->long_name && longopt && 953 (opts->long_name && longopt &&
862 !strcmp(opts->long_name, longopt))) { 954 !strcmp(opts->long_name, longopt)))
863 opts->flags |= flag; 955 return opts;
864 break;
865 }
866 } 956 }
957 return NULL;
958}
959
960void set_option_flag(struct option *opts, int shortopt, const char *longopt,
961 int flag)
962{
963 struct option *opt = find_option(opts, shortopt, longopt);
964
965 if (opt)
966 opt->flags |= flag;
967 return;
968}
969
970void set_option_nobuild(struct option *opts, int shortopt,
971 const char *longopt,
972 const char *build_opt,
973 bool can_skip)
974{
975 struct option *opt = find_option(opts, shortopt, longopt);
976
977 if (!opt)
978 return;
979
980 opt->flags |= PARSE_OPT_NOBUILD;
981 opt->flags |= can_skip ? PARSE_OPT_CANSKIP : 0;
982 opt->build_opt = build_opt;
867} 983}
diff --git a/tools/perf/util/parse-options.h b/tools/lib/subcmd/parse-options.h
index a8e407bc251e..d60cab2726da 100644
--- a/tools/perf/util/parse-options.h
+++ b/tools/lib/subcmd/parse-options.h
@@ -1,8 +1,12 @@
1#ifndef __PERF_PARSE_OPTIONS_H 1#ifndef __SUBCMD_PARSE_OPTIONS_H
2#define __PERF_PARSE_OPTIONS_H 2#define __SUBCMD_PARSE_OPTIONS_H
3 3
4#include <linux/kernel.h>
5#include <stdbool.h> 4#include <stdbool.h>
5#include <stdint.h>
6
7#ifndef NORETURN
8#define NORETURN __attribute__((__noreturn__))
9#endif
6 10
7enum parse_opt_type { 11enum parse_opt_type {
8 /* special types */ 12 /* special types */
@@ -41,6 +45,8 @@ enum parse_opt_option_flags {
41 PARSE_OPT_DISABLED = 32, 45 PARSE_OPT_DISABLED = 32,
42 PARSE_OPT_EXCLUSIVE = 64, 46 PARSE_OPT_EXCLUSIVE = 64,
43 PARSE_OPT_NOEMPTY = 128, 47 PARSE_OPT_NOEMPTY = 128,
48 PARSE_OPT_NOBUILD = 256,
49 PARSE_OPT_CANSKIP = 512,
44}; 50};
45 51
46struct option; 52struct option;
@@ -96,6 +102,7 @@ struct option {
96 void *value; 102 void *value;
97 const char *argh; 103 const char *argh;
98 const char *help; 104 const char *help;
105 const char *build_opt;
99 106
100 int flags; 107 int flags;
101 parse_opt_cb *callback; 108 parse_opt_cb *callback;
@@ -149,6 +156,9 @@ struct option {
149/* parse_options() will filter out the processed options and leave the 156/* parse_options() will filter out the processed options and leave the
150 * non-option argments in argv[]. 157 * non-option argments in argv[].
151 * Returns the number of arguments left in argv[]. 158 * Returns the number of arguments left in argv[].
159 *
160 * NOTE: parse_options() and parse_options_subcommand() may call exit() in the
161 * case of an error (or for 'special' options like --list-cmds or --list-opts).
152 */ 162 */
153extern int parse_options(int argc, const char **argv, 163extern int parse_options(int argc, const char **argv,
154 const struct option *options, 164 const struct option *options,
@@ -195,15 +205,6 @@ extern int parse_options_usage(const char * const *usagestr,
195 const char *optstr, 205 const char *optstr,
196 bool short_opt); 206 bool short_opt);
197 207
198extern void parse_options_start(struct parse_opt_ctx_t *ctx,
199 int argc, const char **argv, int flags);
200
201extern int parse_options_step(struct parse_opt_ctx_t *ctx,
202 const struct option *options,
203 const char * const usagestr[]);
204
205extern int parse_options_end(struct parse_opt_ctx_t *ctx);
206
207 208
208/*----- some often used options -----*/ 209/*----- some often used options -----*/
209extern int parse_opt_abbrev_cb(const struct option *, const char *, int); 210extern int parse_opt_abbrev_cb(const struct option *, const char *, int);
@@ -226,4 +227,7 @@ extern int parse_opt_verbosity_cb(const struct option *, const char *, int);
226extern const char *parse_options_fix_filename(const char *prefix, const char *file); 227extern const char *parse_options_fix_filename(const char *prefix, const char *file);
227 228
228void set_option_flag(struct option *opts, int sopt, const char *lopt, int flag); 229void set_option_flag(struct option *opts, int sopt, const char *lopt, int flag);
229#endif /* __PERF_PARSE_OPTIONS_H */ 230void set_option_nobuild(struct option *opts, int shortopt, const char *longopt,
231 const char *build_opt, bool can_skip);
232
233#endif /* __SUBCMD_PARSE_OPTIONS_H */
diff --git a/tools/perf/util/run-command.c b/tools/lib/subcmd/run-command.c
index 34622b53e733..f4f6c9eb8e59 100644
--- a/tools/perf/util/run-command.c
+++ b/tools/lib/subcmd/run-command.c
@@ -1,7 +1,15 @@
1#include "cache.h" 1#include <unistd.h>
2#include <sys/types.h>
3#include <sys/stat.h>
4#include <fcntl.h>
5#include <string.h>
6#include <errno.h>
7#include <sys/wait.h>
8#include "subcmd-util.h"
2#include "run-command.h" 9#include "run-command.h"
3#include "exec_cmd.h" 10#include "exec-cmd.h"
4#include "debug.h" 11
12#define STRERR_BUFSIZE 128
5 13
6static inline void close_pair(int fd[2]) 14static inline void close_pair(int fd[2])
7{ 15{
@@ -112,8 +120,8 @@ int start_command(struct child_process *cmd)
112 } 120 }
113 if (cmd->preexec_cb) 121 if (cmd->preexec_cb)
114 cmd->preexec_cb(); 122 cmd->preexec_cb();
115 if (cmd->perf_cmd) { 123 if (cmd->exec_cmd) {
116 execv_perf_cmd(cmd->argv); 124 execv_cmd(cmd->argv);
117 } else { 125 } else {
118 execvp(cmd->argv[0], (char *const*) cmd->argv); 126 execvp(cmd->argv[0], (char *const*) cmd->argv);
119 } 127 }
@@ -164,8 +172,8 @@ static int wait_or_whine(pid_t pid)
164 if (waiting < 0) { 172 if (waiting < 0) {
165 if (errno == EINTR) 173 if (errno == EINTR)
166 continue; 174 continue;
167 error("waitpid failed (%s)", 175 fprintf(stderr, " Error: waitpid failed (%s)",
168 strerror_r(errno, sbuf, sizeof(sbuf))); 176 strerror_r(errno, sbuf, sizeof(sbuf)));
169 return -ERR_RUN_COMMAND_WAITPID; 177 return -ERR_RUN_COMMAND_WAITPID;
170 } 178 }
171 if (waiting != pid) 179 if (waiting != pid)
@@ -207,7 +215,7 @@ static void prepare_run_command_v_opt(struct child_process *cmd,
207 memset(cmd, 0, sizeof(*cmd)); 215 memset(cmd, 0, sizeof(*cmd));
208 cmd->argv = argv; 216 cmd->argv = argv;
209 cmd->no_stdin = opt & RUN_COMMAND_NO_STDIN ? 1 : 0; 217 cmd->no_stdin = opt & RUN_COMMAND_NO_STDIN ? 1 : 0;
210 cmd->perf_cmd = opt & RUN_PERF_CMD ? 1 : 0; 218 cmd->exec_cmd = opt & RUN_EXEC_CMD ? 1 : 0;
211 cmd->stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0; 219 cmd->stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0;
212} 220}
213 221
diff --git a/tools/perf/util/run-command.h b/tools/lib/subcmd/run-command.h
index 1ef264d5069c..fe2befea1e73 100644
--- a/tools/perf/util/run-command.h
+++ b/tools/lib/subcmd/run-command.h
@@ -1,5 +1,7 @@
1#ifndef __PERF_RUN_COMMAND_H 1#ifndef __SUBCMD_RUN_COMMAND_H
2#define __PERF_RUN_COMMAND_H 2#define __SUBCMD_RUN_COMMAND_H
3
4#include <unistd.h>
3 5
4enum { 6enum {
5 ERR_RUN_COMMAND_FORK = 10000, 7 ERR_RUN_COMMAND_FORK = 10000,
@@ -41,7 +43,7 @@ struct child_process {
41 unsigned no_stdin:1; 43 unsigned no_stdin:1;
42 unsigned no_stdout:1; 44 unsigned no_stdout:1;
43 unsigned no_stderr:1; 45 unsigned no_stderr:1;
44 unsigned perf_cmd:1; /* if this is to be perf sub-command */ 46 unsigned exec_cmd:1; /* if this is to be external sub-command */
45 unsigned stdout_to_stderr:1; 47 unsigned stdout_to_stderr:1;
46 void (*preexec_cb)(void); 48 void (*preexec_cb)(void);
47}; 49};
@@ -51,8 +53,8 @@ int finish_command(struct child_process *);
51int run_command(struct child_process *); 53int run_command(struct child_process *);
52 54
53#define RUN_COMMAND_NO_STDIN 1 55#define RUN_COMMAND_NO_STDIN 1
54#define RUN_PERF_CMD 2 /*If this is to be perf sub-command */ 56#define RUN_EXEC_CMD 2 /*If this is to be external sub-command */
55#define RUN_COMMAND_STDOUT_TO_STDERR 4 57#define RUN_COMMAND_STDOUT_TO_STDERR 4
56int run_command_v_opt(const char **argv, int opt); 58int run_command_v_opt(const char **argv, int opt);
57 59
58#endif /* __PERF_RUN_COMMAND_H */ 60#endif /* __SUBCMD_RUN_COMMAND_H */
diff --git a/tools/perf/util/sigchain.c b/tools/lib/subcmd/sigchain.c
index ba785e9b1841..3537c348a18e 100644
--- a/tools/perf/util/sigchain.c
+++ b/tools/lib/subcmd/sigchain.c
@@ -1,5 +1,6 @@
1#include <signal.h>
2#include "subcmd-util.h"
1#include "sigchain.h" 3#include "sigchain.h"
2#include "cache.h"
3 4
4#define SIGCHAIN_MAX_SIGNALS 32 5#define SIGCHAIN_MAX_SIGNALS 32
5 6
diff --git a/tools/perf/util/sigchain.h b/tools/lib/subcmd/sigchain.h
index 959d64eb5557..0c919f2874ca 100644
--- a/tools/perf/util/sigchain.h
+++ b/tools/lib/subcmd/sigchain.h
@@ -1,5 +1,5 @@
1#ifndef __PERF_SIGCHAIN_H 1#ifndef __SUBCMD_SIGCHAIN_H
2#define __PERF_SIGCHAIN_H 2#define __SUBCMD_SIGCHAIN_H
3 3
4typedef void (*sigchain_fun)(int); 4typedef void (*sigchain_fun)(int);
5 5
@@ -7,4 +7,4 @@ int sigchain_pop(int sig);
7 7
8void sigchain_push_common(sigchain_fun f); 8void sigchain_push_common(sigchain_fun f);
9 9
10#endif /* __PERF_SIGCHAIN_H */ 10#endif /* __SUBCMD_SIGCHAIN_H */
diff --git a/tools/lib/subcmd/subcmd-config.c b/tools/lib/subcmd/subcmd-config.c
new file mode 100644
index 000000000000..d017c728bd1b
--- /dev/null
+++ b/tools/lib/subcmd/subcmd-config.c
@@ -0,0 +1,11 @@
1#include "subcmd-config.h"
2
3#define UNDEFINED "SUBCMD_HAS_NOT_BEEN_INITIALIZED"
4
5struct subcmd_config subcmd_config = {
6 .exec_name = UNDEFINED,
7 .prefix = UNDEFINED,
8 .exec_path = UNDEFINED,
9 .exec_path_env = UNDEFINED,
10 .pager_env = UNDEFINED,
11};
diff --git a/tools/lib/subcmd/subcmd-config.h b/tools/lib/subcmd/subcmd-config.h
new file mode 100644
index 000000000000..cc8514030b5c
--- /dev/null
+++ b/tools/lib/subcmd/subcmd-config.h
@@ -0,0 +1,14 @@
1#ifndef __PERF_SUBCMD_CONFIG_H
2#define __PERF_SUBCMD_CONFIG_H
3
4struct subcmd_config {
5 const char *exec_name;
6 const char *prefix;
7 const char *exec_path;
8 const char *exec_path_env;
9 const char *pager_env;
10};
11
12extern struct subcmd_config subcmd_config;
13
14#endif /* __PERF_SUBCMD_CONFIG_H */
diff --git a/tools/lib/subcmd/subcmd-util.h b/tools/lib/subcmd/subcmd-util.h
new file mode 100644
index 000000000000..fc2e45d8aaf1
--- /dev/null
+++ b/tools/lib/subcmd/subcmd-util.h
@@ -0,0 +1,91 @@
1#ifndef __SUBCMD_UTIL_H
2#define __SUBCMD_UTIL_H
3
4#include <stdarg.h>
5#include <stdlib.h>
6#include <stdio.h>
7
8#define NORETURN __attribute__((__noreturn__))
9
10static inline void report(const char *prefix, const char *err, va_list params)
11{
12 char msg[1024];
13 vsnprintf(msg, sizeof(msg), err, params);
14 fprintf(stderr, " %s%s\n", prefix, msg);
15}
16
17static NORETURN inline void die(const char *err, ...)
18{
19 va_list params;
20
21 va_start(params, err);
22 report(" Fatal: ", err, params);
23 exit(128);
24 va_end(params);
25}
26
27#define zfree(ptr) ({ free(*ptr); *ptr = NULL; })
28
29#define alloc_nr(x) (((x)+16)*3/2)
30
31/*
32 * Realloc the buffer pointed at by variable 'x' so that it can hold
33 * at least 'nr' entries; the number of entries currently allocated
34 * is 'alloc', using the standard growing factor alloc_nr() macro.
35 *
36 * DO NOT USE any expression with side-effect for 'x' or 'alloc'.
37 */
38#define ALLOC_GROW(x, nr, alloc) \
39 do { \
40 if ((nr) > alloc) { \
41 if (alloc_nr(alloc) < (nr)) \
42 alloc = (nr); \
43 else \
44 alloc = alloc_nr(alloc); \
45 x = xrealloc((x), alloc * sizeof(*(x))); \
46 } \
47 } while(0)
48
49static inline void *xrealloc(void *ptr, size_t size)
50{
51 void *ret = realloc(ptr, size);
52 if (!ret && !size)
53 ret = realloc(ptr, 1);
54 if (!ret) {
55 ret = realloc(ptr, size);
56 if (!ret && !size)
57 ret = realloc(ptr, 1);
58 if (!ret)
59 die("Out of memory, realloc failed");
60 }
61 return ret;
62}
63
64#define astrcatf(out, fmt, ...) \
65({ \
66 char *tmp = *(out); \
67 if (asprintf((out), "%s" fmt, tmp ?: "", ## __VA_ARGS__) == -1) \
68 die("asprintf failed"); \
69 free(tmp); \
70})
71
72static inline void astrcat(char **out, const char *add)
73{
74 char *tmp = *out;
75
76 if (asprintf(out, "%s%s", tmp ?: "", add) == -1)
77 die("asprintf failed");
78
79 free(tmp);
80}
81
82static inline int prefixcmp(const char *str, const char *prefix)
83{
84 for (; ; str++, prefix++)
85 if (!*prefix)
86 return 0;
87 else if (*str != *prefix)
88 return (unsigned char)*prefix - (unsigned char)*str;
89}
90
91#endif /* __SUBCMD_UTIL_H */
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c
index 2a912df6771b..c3bd294a63d1 100644
--- a/tools/lib/traceevent/event-parse.c
+++ b/tools/lib/traceevent/event-parse.c
@@ -3746,7 +3746,7 @@ static const struct flag flags[] = {
3746 { "NET_TX_SOFTIRQ", 2 }, 3746 { "NET_TX_SOFTIRQ", 2 },
3747 { "NET_RX_SOFTIRQ", 3 }, 3747 { "NET_RX_SOFTIRQ", 3 },
3748 { "BLOCK_SOFTIRQ", 4 }, 3748 { "BLOCK_SOFTIRQ", 4 },
3749 { "BLOCK_IOPOLL_SOFTIRQ", 5 }, 3749 { "IRQ_POLL_SOFTIRQ", 5 },
3750 { "TASKLET_SOFTIRQ", 6 }, 3750 { "TASKLET_SOFTIRQ", 6 },
3751 { "SCHED_SOFTIRQ", 7 }, 3751 { "SCHED_SOFTIRQ", 7 },
3752 { "HRTIMER_SOFTIRQ", 8 }, 3752 { "HRTIMER_SOFTIRQ", 8 },
@@ -4735,73 +4735,80 @@ static int is_printable_array(char *p, unsigned int len)
4735 return 1; 4735 return 1;
4736} 4736}
4737 4737
4738static void print_event_fields(struct trace_seq *s, void *data, 4738void pevent_print_field(struct trace_seq *s, void *data,
4739 int size __maybe_unused, 4739 struct format_field *field)
4740 struct event_format *event)
4741{ 4740{
4742 struct format_field *field;
4743 unsigned long long val; 4741 unsigned long long val;
4744 unsigned int offset, len, i; 4742 unsigned int offset, len, i;
4745 4743 struct pevent *pevent = field->event->pevent;
4746 field = event->format.fields; 4744
4747 while (field) { 4745 if (field->flags & FIELD_IS_ARRAY) {
4748 trace_seq_printf(s, " %s=", field->name); 4746 offset = field->offset;
4749 if (field->flags & FIELD_IS_ARRAY) { 4747 len = field->size;
4750 offset = field->offset; 4748 if (field->flags & FIELD_IS_DYNAMIC) {
4751 len = field->size; 4749 val = pevent_read_number(pevent, data + offset, len);
4752 if (field->flags & FIELD_IS_DYNAMIC) { 4750 offset = val;
4753 val = pevent_read_number(event->pevent, data + offset, len); 4751 len = offset >> 16;
4754 offset = val; 4752 offset &= 0xffff;
4755 len = offset >> 16; 4753 }
4756 offset &= 0xffff; 4754 if (field->flags & FIELD_IS_STRING &&
4757 } 4755 is_printable_array(data + offset, len)) {
4758 if (field->flags & FIELD_IS_STRING && 4756 trace_seq_printf(s, "%s", (char *)data + offset);
4759 is_printable_array(data + offset, len)) {
4760 trace_seq_printf(s, "%s", (char *)data + offset);
4761 } else {
4762 trace_seq_puts(s, "ARRAY[");
4763 for (i = 0; i < len; i++) {
4764 if (i)
4765 trace_seq_puts(s, ", ");
4766 trace_seq_printf(s, "%02x",
4767 *((unsigned char *)data + offset + i));
4768 }
4769 trace_seq_putc(s, ']');
4770 field->flags &= ~FIELD_IS_STRING;
4771 }
4772 } else { 4757 } else {
4773 val = pevent_read_number(event->pevent, data + field->offset, 4758 trace_seq_puts(s, "ARRAY[");
4774 field->size); 4759 for (i = 0; i < len; i++) {
4775 if (field->flags & FIELD_IS_POINTER) { 4760 if (i)
4776 trace_seq_printf(s, "0x%llx", val); 4761 trace_seq_puts(s, ", ");
4777 } else if (field->flags & FIELD_IS_SIGNED) { 4762 trace_seq_printf(s, "%02x",
4778 switch (field->size) { 4763 *((unsigned char *)data + offset + i));
4779 case 4: 4764 }
4780 /* 4765 trace_seq_putc(s, ']');
4781 * If field is long then print it in hex. 4766 field->flags &= ~FIELD_IS_STRING;
4782 * A long usually stores pointers. 4767 }
4783 */ 4768 } else {
4784 if (field->flags & FIELD_IS_LONG) 4769 val = pevent_read_number(pevent, data + field->offset,
4785 trace_seq_printf(s, "0x%x", (int)val); 4770 field->size);
4786 else 4771 if (field->flags & FIELD_IS_POINTER) {
4787 trace_seq_printf(s, "%d", (int)val); 4772 trace_seq_printf(s, "0x%llx", val);
4788 break; 4773 } else if (field->flags & FIELD_IS_SIGNED) {
4789 case 2: 4774 switch (field->size) {
4790 trace_seq_printf(s, "%2d", (short)val); 4775 case 4:
4791 break; 4776 /*
4792 case 1: 4777 * If field is long then print it in hex.
4793 trace_seq_printf(s, "%1d", (char)val); 4778 * A long usually stores pointers.
4794 break; 4779 */
4795 default:
4796 trace_seq_printf(s, "%lld", val);
4797 }
4798 } else {
4799 if (field->flags & FIELD_IS_LONG) 4780 if (field->flags & FIELD_IS_LONG)
4800 trace_seq_printf(s, "0x%llx", val); 4781 trace_seq_printf(s, "0x%x", (int)val);
4801 else 4782 else
4802 trace_seq_printf(s, "%llu", val); 4783 trace_seq_printf(s, "%d", (int)val);
4784 break;
4785 case 2:
4786 trace_seq_printf(s, "%2d", (short)val);
4787 break;
4788 case 1:
4789 trace_seq_printf(s, "%1d", (char)val);
4790 break;
4791 default:
4792 trace_seq_printf(s, "%lld", val);
4803 } 4793 }
4794 } else {
4795 if (field->flags & FIELD_IS_LONG)
4796 trace_seq_printf(s, "0x%llx", val);
4797 else
4798 trace_seq_printf(s, "%llu", val);
4804 } 4799 }
4800 }
4801}
4802
4803void pevent_print_fields(struct trace_seq *s, void *data,
4804 int size __maybe_unused, struct event_format *event)
4805{
4806 struct format_field *field;
4807
4808 field = event->format.fields;
4809 while (field) {
4810 trace_seq_printf(s, " %s=", field->name);
4811 pevent_print_field(s, data, field);
4805 field = field->next; 4812 field = field->next;
4806 } 4813 }
4807} 4814}
@@ -4827,7 +4834,7 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event
4827 4834
4828 if (event->flags & EVENT_FL_FAILED) { 4835 if (event->flags & EVENT_FL_FAILED) {
4829 trace_seq_printf(s, "[FAILED TO PARSE]"); 4836 trace_seq_printf(s, "[FAILED TO PARSE]");
4830 print_event_fields(s, data, size, event); 4837 pevent_print_fields(s, data, size, event);
4831 return; 4838 return;
4832 } 4839 }
4833 4840
@@ -4968,13 +4975,12 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event
4968 sizeof(long) != 8) { 4975 sizeof(long) != 8) {
4969 char *p; 4976 char *p;
4970 4977
4971 ls = 2;
4972 /* make %l into %ll */ 4978 /* make %l into %ll */
4973 p = strchr(format, 'l'); 4979 if (ls == 1 && (p = strchr(format, 'l')))
4974 if (p)
4975 memmove(p+1, p, strlen(p)+1); 4980 memmove(p+1, p, strlen(p)+1);
4976 else if (strcmp(format, "%p") == 0) 4981 else if (strcmp(format, "%p") == 0)
4977 strcpy(format, "0x%llx"); 4982 strcpy(format, "0x%llx");
4983 ls = 2;
4978 } 4984 }
4979 switch (ls) { 4985 switch (ls) {
4980 case -2: 4986 case -2:
@@ -5302,7 +5308,7 @@ void pevent_event_info(struct trace_seq *s, struct event_format *event,
5302 int print_pretty = 1; 5308 int print_pretty = 1;
5303 5309
5304 if (event->pevent->print_raw || (event->flags & EVENT_FL_PRINTRAW)) 5310 if (event->pevent->print_raw || (event->flags & EVENT_FL_PRINTRAW))
5305 print_event_fields(s, record->data, record->size, event); 5311 pevent_print_fields(s, record->data, record->size, event);
5306 else { 5312 else {
5307 5313
5308 if (event->handler && !(event->flags & EVENT_FL_NOHANDLE)) 5314 if (event->handler && !(event->flags & EVENT_FL_NOHANDLE))
diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h
index 6fc83c7edbe9..706d9bc24066 100644
--- a/tools/lib/traceevent/event-parse.h
+++ b/tools/lib/traceevent/event-parse.h
@@ -705,6 +705,10 @@ struct cmdline *pevent_data_pid_from_comm(struct pevent *pevent, const char *com
705 struct cmdline *next); 705 struct cmdline *next);
706int pevent_cmdline_pid(struct pevent *pevent, struct cmdline *cmdline); 706int pevent_cmdline_pid(struct pevent *pevent, struct cmdline *cmdline);
707 707
708void pevent_print_field(struct trace_seq *s, void *data,
709 struct format_field *field);
710void pevent_print_fields(struct trace_seq *s, void *data,
711 int size __maybe_unused, struct event_format *event);
708void pevent_event_info(struct trace_seq *s, struct event_format *event, 712void pevent_event_info(struct trace_seq *s, struct event_format *event,
709 struct pevent_record *record); 713 struct pevent_record *record);
710int pevent_strerror(struct pevent *pevent, enum pevent_errno errnum, 714int pevent_strerror(struct pevent *pevent, enum pevent_errno errnum,
diff --git a/tools/lib/util/find_next_bit.c b/tools/lib/util/find_next_bit.c
deleted file mode 100644
index 41b44f65a79e..000000000000
--- a/tools/lib/util/find_next_bit.c
+++ /dev/null
@@ -1,89 +0,0 @@
1/* find_next_bit.c: fallback find next bit implementation
2 *
3 * Copied from lib/find_next_bit.c to tools/lib/next_bit.c
4 *
5 * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
6 * Written by David Howells (dhowells@redhat.com)
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 */
13
14#include <linux/bitops.h>
15#include <asm/types.h>
16#include <asm/byteorder.h>
17
18#define BITOP_WORD(nr) ((nr) / BITS_PER_LONG)
19
20#ifndef find_next_bit
21/*
22 * Find the next set bit in a memory region.
23 */
24unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
25 unsigned long offset)
26{
27 const unsigned long *p = addr + BITOP_WORD(offset);
28 unsigned long result = offset & ~(BITS_PER_LONG-1);
29 unsigned long tmp;
30
31 if (offset >= size)
32 return size;
33 size -= result;
34 offset %= BITS_PER_LONG;
35 if (offset) {
36 tmp = *(p++);
37 tmp &= (~0UL << offset);
38 if (size < BITS_PER_LONG)
39 goto found_first;
40 if (tmp)
41 goto found_middle;
42 size -= BITS_PER_LONG;
43 result += BITS_PER_LONG;
44 }
45 while (size & ~(BITS_PER_LONG-1)) {
46 if ((tmp = *(p++)))
47 goto found_middle;
48 result += BITS_PER_LONG;
49 size -= BITS_PER_LONG;
50 }
51 if (!size)
52 return result;
53 tmp = *p;
54
55found_first:
56 tmp &= (~0UL >> (BITS_PER_LONG - size));
57 if (tmp == 0UL) /* Are any bits set? */
58 return result + size; /* Nope. */
59found_middle:
60 return result + __ffs(tmp);
61}
62#endif
63
64#ifndef find_first_bit
65/*
66 * Find the first set bit in a memory region.
67 */
68unsigned long find_first_bit(const unsigned long *addr, unsigned long size)
69{
70 const unsigned long *p = addr;
71 unsigned long result = 0;
72 unsigned long tmp;
73
74 while (size & ~(BITS_PER_LONG-1)) {
75 if ((tmp = *(p++)))
76 goto found;
77 result += BITS_PER_LONG;
78 size -= BITS_PER_LONG;
79 }
80 if (!size)
81 return result;
82
83 tmp = (*p) & (~0UL >> (BITS_PER_LONG - size));
84 if (tmp == 0UL) /* Are any bits set? */
85 return result + size; /* Nope. */
86found:
87 return result + __ffs(tmp);
88}
89#endif
diff --git a/tools/net/Makefile b/tools/net/Makefile
index ee577ea03ba5..ddf888010652 100644
--- a/tools/net/Makefile
+++ b/tools/net/Makefile
@@ -4,6 +4,9 @@ CC = gcc
4LEX = flex 4LEX = flex
5YACC = bison 5YACC = bison
6 6
7CFLAGS += -Wall -O2
8CFLAGS += -D__EXPORTED_HEADERS__ -I../../include/uapi -I../../include
9
7%.yacc.c: %.y 10%.yacc.c: %.y
8 $(YACC) -o $@ -d $< 11 $(YACC) -o $@ -d $<
9 12
@@ -12,15 +15,13 @@ YACC = bison
12 15
13all : bpf_jit_disasm bpf_dbg bpf_asm 16all : bpf_jit_disasm bpf_dbg bpf_asm
14 17
15bpf_jit_disasm : CFLAGS = -Wall -O2 -DPACKAGE='bpf_jit_disasm' 18bpf_jit_disasm : CFLAGS += -DPACKAGE='bpf_jit_disasm'
16bpf_jit_disasm : LDLIBS = -lopcodes -lbfd -ldl 19bpf_jit_disasm : LDLIBS = -lopcodes -lbfd -ldl
17bpf_jit_disasm : bpf_jit_disasm.o 20bpf_jit_disasm : bpf_jit_disasm.o
18 21
19bpf_dbg : CFLAGS = -Wall -O2
20bpf_dbg : LDLIBS = -lreadline 22bpf_dbg : LDLIBS = -lreadline
21bpf_dbg : bpf_dbg.o 23bpf_dbg : bpf_dbg.o
22 24
23bpf_asm : CFLAGS = -Wall -O2 -I.
24bpf_asm : LDLIBS = 25bpf_asm : LDLIBS =
25bpf_asm : bpf_asm.o bpf_exp.yacc.o bpf_exp.lex.o 26bpf_asm : bpf_asm.o bpf_exp.yacc.o bpf_exp.lex.o
26bpf_exp.lex.o : bpf_exp.yacc.c 27bpf_exp.lex.o : bpf_exp.yacc.c
diff --git a/tools/perf/Build b/tools/perf/Build
index 72237455b400..a43fae7f439a 100644
--- a/tools/perf/Build
+++ b/tools/perf/Build
@@ -1,5 +1,6 @@
1perf-y += builtin-bench.o 1perf-y += builtin-bench.o
2perf-y += builtin-annotate.o 2perf-y += builtin-annotate.o
3perf-y += builtin-config.o
3perf-y += builtin-diff.o 4perf-y += builtin-diff.o
4perf-y += builtin-evlist.o 5perf-y += builtin-evlist.o
5perf-y += builtin-help.o 6perf-y += builtin-help.o
@@ -19,6 +20,7 @@ perf-y += builtin-kvm.o
19perf-y += builtin-inject.o 20perf-y += builtin-inject.o
20perf-y += builtin-mem.o 21perf-y += builtin-mem.o
21perf-y += builtin-data.o 22perf-y += builtin-data.o
23perf-y += builtin-version.o
22 24
23perf-$(CONFIG_AUDIT) += builtin-trace.o 25perf-$(CONFIG_AUDIT) += builtin-trace.o
24perf-$(CONFIG_LIBELF) += builtin-probe.o 26perf-$(CONFIG_LIBELF) += builtin-probe.o
@@ -34,8 +36,13 @@ paths += -DPERF_MAN_PATH="BUILD_STR($(mandir_SQ))"
34 36
35CFLAGS_builtin-help.o += $(paths) 37CFLAGS_builtin-help.o += $(paths)
36CFLAGS_builtin-timechart.o += $(paths) 38CFLAGS_builtin-timechart.o += $(paths)
37CFLAGS_perf.o += -DPERF_HTML_PATH="BUILD_STR($(htmldir_SQ))" -include $(OUTPUT)PERF-VERSION-FILE 39CFLAGS_perf.o += -DPERF_HTML_PATH="BUILD_STR($(htmldir_SQ))" \
40 -DPERF_EXEC_PATH="BUILD_STR($(perfexecdir_SQ))" \
41 -DPREFIX="BUILD_STR($(prefix_SQ))" \
42 -include $(OUTPUT)PERF-VERSION-FILE
38CFLAGS_builtin-trace.o += -DSTRACE_GROUPS_DIR="BUILD_STR($(STRACE_GROUPS_DIR_SQ))" 43CFLAGS_builtin-trace.o += -DSTRACE_GROUPS_DIR="BUILD_STR($(STRACE_GROUPS_DIR_SQ))"
44CFLAGS_builtin-report.o += -DTIPDIR="BUILD_STR($(tipdir_SQ))"
45CFLAGS_builtin-report.o += -DDOCDIR="BUILD_STR($(srcdir_SQ)/Documentation)"
39 46
40libperf-y += util/ 47libperf-y += util/
41libperf-y += arch/ 48libperf-y += arch/
diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt
new file mode 100644
index 000000000000..b9ca1e304158
--- /dev/null
+++ b/tools/perf/Documentation/perf-config.txt
@@ -0,0 +1,103 @@
1perf-config(1)
2==============
3
4NAME
5----
6perf-config - Get and set variables in a configuration file.
7
8SYNOPSIS
9--------
10[verse]
11'perf config' -l | --list
12
13DESCRIPTION
14-----------
15You can manage variables in a configuration file with this command.
16
17OPTIONS
18-------
19
20-l::
21--list::
22 Show current config variables, name and value, for all sections.
23
24CONFIGURATION FILE
25------------------
26
27The perf configuration file contains many variables to change various
28aspects of each of its tools, including output, disk usage, etc.
29The '$HOME/.perfconfig' file is used to store a per-user configuration.
30The file '$(sysconfdir)/perfconfig' can be used to
31store a system-wide default configuration.
32
33Syntax
34~~~~~~
35
36The file consist of sections. A section starts with its name
37surrounded by square brackets and continues till the next section
38begins. Each variable must be in a section, and have the form
39'name = value', for example:
40
41 [section]
42 name1 = value1
43 name2 = value2
44
45Section names are case sensitive and can contain any characters except
46newline (double quote `"` and backslash have to be escaped as `\"` and `\\`,
47respectively). Section headers can't span multiple lines.
48
49Example
50~~~~~~~
51
52Given a $HOME/.perfconfig like this:
53
54#
55# This is the config file, and
56# a '#' and ';' character indicates a comment
57#
58
59 [colors]
60 # Color variables
61 top = red, default
62 medium = green, default
63 normal = lightgray, default
64 selected = white, lightgray
65 code = blue, default
66 addr = magenta, default
67 root = white, blue
68
69 [tui]
70 # Defaults if linked with libslang
71 report = on
72 annotate = on
73 top = on
74
75 [buildid]
76 # Default, disable using /dev/null
77 dir = ~/.debug
78
79 [annotate]
80 # Defaults
81 hide_src_code = false
82 use_offset = true
83 jump_arrows = true
84 show_nr_jumps = false
85
86 [help]
87 # Format can be man, info, web or html
88 format = man
89 autocorrect = 0
90
91 [ui]
92 show-headers = true
93
94 [call-graph]
95 # fp (framepointer), dwarf
96 record-mode = fp
97 print-type = graph
98 order = caller
99 sort-key = function
100
101SEE ALSO
102--------
103linkperf:perf[1]
diff --git a/tools/perf/Documentation/perf-evlist.txt b/tools/perf/Documentation/perf-evlist.txt
index 1ceb3700ffbb..6f7200fb85cf 100644
--- a/tools/perf/Documentation/perf-evlist.txt
+++ b/tools/perf/Documentation/perf-evlist.txt
@@ -32,6 +32,9 @@ OPTIONS
32--group:: 32--group::
33 Show event group information. 33 Show event group information.
34 34
35--trace-fields::
36 Show tracepoint field names.
37
35SEE ALSO 38SEE ALSO
36-------- 39--------
37linkperf:perf-record[1], linkperf:perf-list[1], 40linkperf:perf-record[1], linkperf:perf-list[1],
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index e630a7d2c348..fbceb631387c 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -207,11 +207,23 @@ comma-separated list with no space: 0,1. Ranges of CPUs are specified with -: 0-
207In per-thread mode with inheritance mode on (default), samples are captured only when 207In per-thread mode with inheritance mode on (default), samples are captured only when
208the thread executes on the designated CPUs. Default is to monitor all CPUs. 208the thread executes on the designated CPUs. Default is to monitor all CPUs.
209 209
210-B::
211--no-buildid::
212Do not save the build ids of binaries in the perf.data files. This skips
213post processing after recording, which sometimes makes the final step in
214the recording process to take a long time, as it needs to process all
215events looking for mmap records. The downside is that it can misresolve
216symbols if the workload binaries used when recording get locally rebuilt
217or upgraded, because the only key available in this case is the
218pathname. You can also set the "record.build-id" config variable to
219'skip to have this behaviour permanently.
220
210-N:: 221-N::
211--no-buildid-cache:: 222--no-buildid-cache::
212Do not update the buildid cache. This saves some overhead in situations 223Do not update the buildid cache. This saves some overhead in situations
213where the information in the perf.data file (which includes buildids) 224where the information in the perf.data file (which includes buildids)
214is sufficient. 225is sufficient. You can also set the "record.build-id" config variable to
226'no-cache' to have the same effect.
215 227
216-G name,...:: 228-G name,...::
217--cgroup name,...:: 229--cgroup name,...::
@@ -314,11 +326,20 @@ This option sets the time out limit. The default value is 500 ms.
314Record context switch events i.e. events of type PERF_RECORD_SWITCH or 326Record context switch events i.e. events of type PERF_RECORD_SWITCH or
315PERF_RECORD_SWITCH_CPU_WIDE. 327PERF_RECORD_SWITCH_CPU_WIDE.
316 328
317--clang-path:: 329--clang-path=PATH::
318Path to clang binary to use for compiling BPF scriptlets. 330Path to clang binary to use for compiling BPF scriptlets.
331(enabled when BPF support is on)
319 332
320--clang-opt:: 333--clang-opt=OPTIONS::
321Options passed to clang when compiling BPF scriptlets. 334Options passed to clang when compiling BPF scriptlets.
335(enabled when BPF support is on)
336
337--vmlinux=PATH::
338Specify vmlinux path which has debuginfo.
339(enabled when BPF prologue is on)
340
341--buildid-all::
342Record build-id of all DSOs regardless whether it's actually hit or not.
322 343
323SEE ALSO 344SEE ALSO
324-------- 345--------
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 5ce8da1e1256..8a301f6afb37 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -117,6 +117,30 @@ OPTIONS
117 And default sort keys are changed to comm, dso_from, symbol_from, dso_to 117 And default sort keys are changed to comm, dso_from, symbol_from, dso_to
118 and symbol_to, see '--branch-stack'. 118 and symbol_to, see '--branch-stack'.
119 119
120 If the data file has tracepoint event(s), following (dynamic) sort keys
121 are also available:
122 trace, trace_fields, [<event>.]<field>[/raw]
123
124 - trace: pretty printed trace output in a single column
125 - trace_fields: fields in tracepoints in separate columns
126 - <field name>: optional event and field name for a specific field
127
128 The last form consists of event and field names. If event name is
129 omitted, it searches all events for matching field name. The matched
130 field will be shown only for the event has the field. The event name
131 supports substring match so user doesn't need to specify full subsystem
132 and event name everytime. For example, 'sched:sched_switch' event can
133 be shortened to 'switch' as long as it's not ambiguous. Also event can
134 be specified by its index (starting from 1) preceded by the '%'.
135 So '%1' is the first event, '%2' is the second, and so on.
136
137 The field name can have '/raw' suffix which disables pretty printing
138 and shows raw field value like hex numbers. The --raw-trace option
139 has the same effect for all dynamic sort keys.
140
141 The default sort keys are changed to 'trace' if all events in the data
142 file are tracepoint.
143
120-F:: 144-F::
121--fields=:: 145--fields=::
122 Specify output field - multiple keys can be specified in CSV format. 146 Specify output field - multiple keys can be specified in CSV format.
@@ -170,17 +194,18 @@ OPTIONS
170 Dump raw trace in ASCII. 194 Dump raw trace in ASCII.
171 195
172-g:: 196-g::
173--call-graph=<print_type,threshold[,print_limit],order,sort_key,branch>:: 197--call-graph=<print_type,threshold[,print_limit],order,sort_key[,branch],value>::
174 Display call chains using type, min percent threshold, print limit, 198 Display call chains using type, min percent threshold, print limit,
175 call order, sort key and branch. Note that ordering of parameters is not 199 call order, sort key, optional branch and value. Note that ordering of
176 fixed so any parement can be given in an arbitraty order. One exception 200 parameters is not fixed so any parement can be given in an arbitraty order.
177 is the print_limit which should be preceded by threshold. 201 One exception is the print_limit which should be preceded by threshold.
178 202
179 print_type can be either: 203 print_type can be either:
180 - flat: single column, linear exposure of call chains. 204 - flat: single column, linear exposure of call chains.
181 - graph: use a graph tree, displaying absolute overhead rates. (default) 205 - graph: use a graph tree, displaying absolute overhead rates. (default)
182 - fractal: like graph, but displays relative rates. Each branch of 206 - fractal: like graph, but displays relative rates. Each branch of
183 the tree is considered as a new profiled object. 207 the tree is considered as a new profiled object.
208 - folded: call chains are displayed in a line, separated by semicolons
184 - none: disable call chain display. 209 - none: disable call chain display.
185 210
186 threshold is a percentage value which specifies a minimum percent to be 211 threshold is a percentage value which specifies a minimum percent to be
@@ -204,6 +229,11 @@ OPTIONS
204 - branch: include last branch information in callgraph when available. 229 - branch: include last branch information in callgraph when available.
205 Usually more convenient to use --branch-history for this. 230 Usually more convenient to use --branch-history for this.
206 231
232 value can be:
233 - percent: diplay overhead percent (default)
234 - period: display event period
235 - count: display event count
236
207--children:: 237--children::
208 Accumulate callchain of children to parent entry so that then can 238 Accumulate callchain of children to parent entry so that then can
209 show up in the output. The output will have a new "Children" column 239 show up in the output. The output will have a new "Children" column
@@ -365,6 +395,9 @@ include::itrace.txt[]
365--socket-filter:: 395--socket-filter::
366 Only report the samples on the processor socket that match with this filter 396 Only report the samples on the processor socket that match with this filter
367 397
398--raw-trace::
399 When displaying traceevent output, do not use print fmt or plugins.
400
368include::callchain-overhead-calculation.txt[] 401include::callchain-overhead-calculation.txt[]
369 402
370SEE ALSO 403SEE ALSO
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index 4e074a660826..52ef7a9d50aa 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -10,6 +10,8 @@ SYNOPSIS
10[verse] 10[verse]
11'perf stat' [-e <EVENT> | --event=EVENT] [-a] <command> 11'perf stat' [-e <EVENT> | --event=EVENT] [-a] <command>
12'perf stat' [-e <EVENT> | --event=EVENT] [-a] -- <command> [<options>] 12'perf stat' [-e <EVENT> | --event=EVENT] [-a] -- <command> [<options>]
13'perf stat' [-e <EVENT> | --event=EVENT] [-a] record [-o file] -- <command> [<options>]
14'perf stat' report [-i file]
13 15
14DESCRIPTION 16DESCRIPTION
15----------- 17-----------
@@ -22,6 +24,11 @@ OPTIONS
22<command>...:: 24<command>...::
23 Any command you can specify in a shell. 25 Any command you can specify in a shell.
24 26
27record::
28 See STAT RECORD.
29
30report::
31 See STAT REPORT.
25 32
26-e:: 33-e::
27--event=:: 34--event=::
@@ -159,6 +166,33 @@ filter out the startup phase of the program, which is often very different.
159 166
160Print statistics of transactional execution if supported. 167Print statistics of transactional execution if supported.
161 168
169STAT RECORD
170-----------
171Stores stat data into perf data file.
172
173-o file::
174--output file::
175Output file name.
176
177STAT REPORT
178-----------
179Reads and reports stat data from perf data file.
180
181-i file::
182--input file::
183Input file name.
184
185--per-socket::
186Aggregate counts per processor socket for system-wide mode measurements.
187
188--per-core::
189Aggregate counts per physical processor for system-wide mode measurements.
190
191-A::
192--no-aggr::
193Do not aggregate counts across all monitored CPUs.
194
195
162EXAMPLES 196EXAMPLES
163-------- 197--------
164 198
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index 556cec09bf50..b0e60e17db38 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -230,6 +230,9 @@ Default is to monitor all CPUS.
230 The various filters must be specified as a comma separated list: --branch-filter any_ret,u,k 230 The various filters must be specified as a comma separated list: --branch-filter any_ret,u,k
231 Note that this feature may not be available on all processors. 231 Note that this feature may not be available on all processors.
232 232
233--raw-trace::
234 When displaying traceevent output, do not use print fmt or plugins.
235
233INTERACTIVE PROMPTING KEYS 236INTERACTIVE PROMPTING KEYS
234-------------------------- 237--------------------------
235 238
diff --git a/tools/perf/Documentation/tips.txt b/tools/perf/Documentation/tips.txt
new file mode 100644
index 000000000000..e0ce9573b79b
--- /dev/null
+++ b/tools/perf/Documentation/tips.txt
@@ -0,0 +1,29 @@
1For a higher level overview, try: perf report --sort comm,dso
2Sample related events with: perf record -e '{cycles,instructions}:S'
3Compare performance results with: perf diff [<old file> <new file>]
4Boolean options have negative forms, e.g.: perf report --no-children
5Customize output of perf script with: perf script -F event,ip,sym
6Generate a script for your data: perf script -g <lang>
7Save output of perf stat using: perf stat record <target workload>
8Create an archive with symtabs to analyse on other machine: perf archive
9Search options using a keyword: perf report -h <keyword>
10Use parent filter to see specific call path: perf report -p <regex>
11List events using substring match: perf list <keyword>
12To see list of saved events and attributes: perf evlist -v
13Use --symfs <dir> if your symbol files are in non-standard locations
14To see callchains in a more compact form: perf report -g folded
15Show individual samples with: perf script
16Limit to show entries above 5% only: perf report --percent-limit 5
17Profiling branch (mis)predictions with: perf record -b / perf report
18Treat branches as callchains: perf report --branch-history
19To count events in every 1000 msec: perf stat -I 1000
20Print event counts in CSV format with: perf stat -x,
21If you have debuginfo enabled, try: perf report -s sym,srcline
22For memory address profiling, try: perf mem record / perf mem report
23For tracepoint events, try: perf report -s trace_fields
24To record callchains for each sample: perf record -g
25To record every process run by an user: perf record -u <user>
26Skip collecing build-id when recording: perf record -B
27To change sampling frequency to 100 Hz: perf record -F 100
28See assembly instructions with percentage: perf annotate <symbol>
29If you prefer Intel style assembly, try: perf annotate -M intel
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST
index 39c38cb45b00..2e1fa2357528 100644
--- a/tools/perf/MANIFEST
+++ b/tools/perf/MANIFEST
@@ -1,6 +1,7 @@
1tools/perf 1tools/perf
2tools/arch/alpha/include/asm/barrier.h 2tools/arch/alpha/include/asm/barrier.h
3tools/arch/arm/include/asm/barrier.h 3tools/arch/arm/include/asm/barrier.h
4tools/arch/arm64/include/asm/barrier.h
4tools/arch/ia64/include/asm/barrier.h 5tools/arch/ia64/include/asm/barrier.h
5tools/arch/mips/include/asm/barrier.h 6tools/arch/mips/include/asm/barrier.h
6tools/arch/powerpc/include/asm/barrier.h 7tools/arch/powerpc/include/asm/barrier.h
@@ -20,14 +21,18 @@ tools/lib/traceevent
20tools/lib/bpf 21tools/lib/bpf
21tools/lib/api 22tools/lib/api
22tools/lib/bpf 23tools/lib/bpf
24tools/lib/subcmd
23tools/lib/hweight.c 25tools/lib/hweight.c
24tools/lib/rbtree.c 26tools/lib/rbtree.c
27tools/lib/string.c
25tools/lib/symbol/kallsyms.c 28tools/lib/symbol/kallsyms.c
26tools/lib/symbol/kallsyms.h 29tools/lib/symbol/kallsyms.h
27tools/lib/util/find_next_bit.c 30tools/lib/find_bit.c
31tools/lib/bitmap.c
28tools/include/asm/atomic.h 32tools/include/asm/atomic.h
29tools/include/asm/barrier.h 33tools/include/asm/barrier.h
30tools/include/asm/bug.h 34tools/include/asm/bug.h
35tools/include/asm-generic/atomic-gcc.h
31tools/include/asm-generic/barrier.h 36tools/include/asm-generic/barrier.h
32tools/include/asm-generic/bitops/arch_hweight.h 37tools/include/asm-generic/bitops/arch_hweight.h
33tools/include/asm-generic/bitops/atomic.h 38tools/include/asm-generic/bitops/atomic.h
@@ -50,8 +55,10 @@ tools/include/linux/log2.h
50tools/include/linux/poison.h 55tools/include/linux/poison.h
51tools/include/linux/rbtree.h 56tools/include/linux/rbtree.h
52tools/include/linux/rbtree_augmented.h 57tools/include/linux/rbtree_augmented.h
58tools/include/linux/string.h
53tools/include/linux/types.h 59tools/include/linux/types.h
54tools/include/linux/err.h 60tools/include/linux/err.h
61tools/include/linux/bitmap.h
55include/asm-generic/bitops/arch_hweight.h 62include/asm-generic/bitops/arch_hweight.h
56include/asm-generic/bitops/const_hweight.h 63include/asm-generic/bitops/const_hweight.h
57include/asm-generic/bitops/fls64.h 64include/asm-generic/bitops/fls64.h
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 0d19d5447d6c..5d34815c7ccb 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -77,6 +77,9 @@ include config/utilities.mak
77# Define NO_AUXTRACE if you do not want AUX area tracing support 77# Define NO_AUXTRACE if you do not want AUX area tracing support
78# 78#
79# Define NO_LIBBPF if you do not want BPF support 79# Define NO_LIBBPF if you do not want BPF support
80#
81# Define FEATURES_DUMP to provide features detection dump file
82# and bypass the feature detection
80 83
81# As per kernel Makefile, avoid funny character set dependencies 84# As per kernel Makefile, avoid funny character set dependencies
82unexport LC_ALL 85unexport LC_ALL
@@ -145,9 +148,10 @@ BISON = bison
145STRIP = strip 148STRIP = strip
146AWK = awk 149AWK = awk
147 150
148LIB_DIR = $(srctree)/tools/lib/api/ 151LIB_DIR = $(srctree)/tools/lib/api/
149TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/ 152TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/
150BPF_DIR = $(srctree)/tools/lib/bpf/ 153BPF_DIR = $(srctree)/tools/lib/bpf/
154SUBCMD_DIR = $(srctree)/tools/lib/subcmd/
151 155
152# include config/Makefile by default and rule out 156# include config/Makefile by default and rule out
153# non-config cases 157# non-config cases
@@ -165,6 +169,15 @@ ifeq ($(config),1)
165include config/Makefile 169include config/Makefile
166endif 170endif
167 171
172# The FEATURE_DUMP_EXPORT holds location of the actual
173# FEATURE_DUMP file to be used to bypass feature detection
174# (for bpf or any other subproject)
175ifeq ($(FEATURES_DUMP),)
176FEATURE_DUMP_EXPORT := $(realpath $(OUTPUT)FEATURE-DUMP)
177else
178FEATURE_DUMP_EXPORT := $(FEATURES_DUMP)
179endif
180
168export prefix bindir sharedir sysconfdir DESTDIR 181export prefix bindir sharedir sysconfdir DESTDIR
169 182
170# sparse is architecture-neutral, which means that we need to tell it 183# sparse is architecture-neutral, which means that we need to tell it
@@ -184,15 +197,17 @@ strip-libs = $(filter-out -l%,$(1))
184ifneq ($(OUTPUT),) 197ifneq ($(OUTPUT),)
185 TE_PATH=$(OUTPUT) 198 TE_PATH=$(OUTPUT)
186 BPF_PATH=$(OUTPUT) 199 BPF_PATH=$(OUTPUT)
200 SUBCMD_PATH=$(OUTPUT)
187ifneq ($(subdir),) 201ifneq ($(subdir),)
188 LIB_PATH=$(OUTPUT)/../lib/api/ 202 API_PATH=$(OUTPUT)/../lib/api/
189else 203else
190 LIB_PATH=$(OUTPUT) 204 API_PATH=$(OUTPUT)
191endif 205endif
192else 206else
193 TE_PATH=$(TRACE_EVENT_DIR) 207 TE_PATH=$(TRACE_EVENT_DIR)
194 LIB_PATH=$(LIB_DIR) 208 API_PATH=$(LIB_DIR)
195 BPF_PATH=$(BPF_DIR) 209 BPF_PATH=$(BPF_DIR)
210 SUBCMD_PATH=$(SUBCMD_DIR)
196endif 211endif
197 212
198LIBTRACEEVENT = $(TE_PATH)libtraceevent.a 213LIBTRACEEVENT = $(TE_PATH)libtraceevent.a
@@ -201,11 +216,13 @@ export LIBTRACEEVENT
201LIBTRACEEVENT_DYNAMIC_LIST = $(TE_PATH)libtraceevent-dynamic-list 216LIBTRACEEVENT_DYNAMIC_LIST = $(TE_PATH)libtraceevent-dynamic-list
202LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS = -Xlinker --dynamic-list=$(LIBTRACEEVENT_DYNAMIC_LIST) 217LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS = -Xlinker --dynamic-list=$(LIBTRACEEVENT_DYNAMIC_LIST)
203 218
204LIBAPI = $(LIB_PATH)libapi.a 219LIBAPI = $(API_PATH)libapi.a
205export LIBAPI 220export LIBAPI
206 221
207LIBBPF = $(BPF_PATH)libbpf.a 222LIBBPF = $(BPF_PATH)libbpf.a
208 223
224LIBSUBCMD = $(SUBCMD_PATH)libsubcmd.a
225
209# python extension build directories 226# python extension build directories
210PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/ 227PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/
211PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/ 228PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/
@@ -257,7 +274,7 @@ export PERL_PATH
257 274
258LIB_FILE=$(OUTPUT)libperf.a 275LIB_FILE=$(OUTPUT)libperf.a
259 276
260PERFLIBS = $(LIB_FILE) $(LIBAPI) $(LIBTRACEEVENT) 277PERFLIBS = $(LIB_FILE) $(LIBAPI) $(LIBTRACEEVENT) $(LIBSUBCMD)
261ifndef NO_LIBBPF 278ifndef NO_LIBBPF
262 PERFLIBS += $(LIBBPF) 279 PERFLIBS += $(LIBBPF)
263endif 280endif
@@ -420,7 +437,7 @@ $(LIBTRACEEVENT)-clean:
420 $(call QUIET_CLEAN, libtraceevent) 437 $(call QUIET_CLEAN, libtraceevent)
421 $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) O=$(OUTPUT) clean >/dev/null 438 $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) O=$(OUTPUT) clean >/dev/null
422 439
423install-traceevent-plugins: $(LIBTRACEEVENT) 440install-traceevent-plugins: libtraceevent_plugins
424 $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) install_plugins 441 $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) install_plugins
425 442
426$(LIBAPI): fixdep FORCE 443$(LIBAPI): fixdep FORCE
@@ -431,12 +448,19 @@ $(LIBAPI)-clean:
431 $(Q)$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) clean >/dev/null 448 $(Q)$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) clean >/dev/null
432 449
433$(LIBBPF): fixdep FORCE 450$(LIBBPF): fixdep FORCE
434 $(Q)$(MAKE) -C $(BPF_DIR) O=$(OUTPUT) $(OUTPUT)libbpf.a 451 $(Q)$(MAKE) -C $(BPF_DIR) O=$(OUTPUT) $(OUTPUT)libbpf.a FEATURES_DUMP=$(FEATURE_DUMP_EXPORT)
435 452
436$(LIBBPF)-clean: 453$(LIBBPF)-clean:
437 $(call QUIET_CLEAN, libbpf) 454 $(call QUIET_CLEAN, libbpf)
438 $(Q)$(MAKE) -C $(BPF_DIR) O=$(OUTPUT) clean >/dev/null 455 $(Q)$(MAKE) -C $(BPF_DIR) O=$(OUTPUT) clean >/dev/null
439 456
457$(LIBSUBCMD): fixdep FORCE
458 $(Q)$(MAKE) -C $(SUBCMD_DIR) O=$(OUTPUT) $(OUTPUT)libsubcmd.a
459
460$(LIBSUBCMD)-clean:
461 $(call QUIET_CLEAN, libsubcmd)
462 $(Q)$(MAKE) -C $(SUBCMD_DIR) O=$(OUTPUT) clean
463
440help: 464help:
441 @echo 'Perf make targets:' 465 @echo 'Perf make targets:'
442 @echo ' doc - make *all* documentation (see below)' 466 @echo ' doc - make *all* documentation (see below)'
@@ -476,7 +500,7 @@ INSTALL_DOC_TARGETS += quick-install-doc quick-install-man quick-install-html
476$(DOC_TARGETS): 500$(DOC_TARGETS):
477 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:doc=all) 501 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:doc=all)
478 502
479TAG_FOLDERS= . ../lib/traceevent ../lib/api ../lib/symbol ../include ../lib/bpf 503TAG_FOLDERS= . ../lib ../include
480TAG_FILES= ../../include/uapi/linux/perf_event.h 504TAG_FILES= ../../include/uapi/linux/perf_event.h
481 505
482TAGS: 506TAGS:
@@ -555,6 +579,9 @@ endif
555 $(call QUIET_INSTALL, perf_completion-script) \ 579 $(call QUIET_INSTALL, perf_completion-script) \
556 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d'; \ 580 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d'; \
557 $(INSTALL) perf-completion.sh '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d/perf' 581 $(INSTALL) perf-completion.sh '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d/perf'
582 $(call QUIET_INSTALL, perf-tip) \
583 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(tip_instdir_SQ)'; \
584 $(INSTALL) Documentation/tips.txt -t '$(DESTDIR_SQ)$(tip_instdir_SQ)'
558 585
559install-tests: all install-gtk 586install-tests: all install-gtk
560 $(call QUIET_INSTALL, tests) \ 587 $(call QUIET_INSTALL, tests) \
@@ -582,19 +609,31 @@ $(INSTALL_DOC_TARGETS):
582# 609#
583config-clean: 610config-clean:
584 $(call QUIET_CLEAN, config) 611 $(call QUIET_CLEAN, config)
585 $(Q)$(MAKE) -C $(srctree)/tools/build/feature/ clean >/dev/null 612 $(Q)$(MAKE) -C $(srctree)/tools/build/feature/ $(if $(OUTPUT),OUTPUT=$(OUTPUT)feature/,) clean >/dev/null
586 613
587clean: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean config-clean 614clean: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clean config-clean
588 $(call QUIET_CLEAN, core-objs) $(RM) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(LANG_BINDINGS) 615 $(call QUIET_CLEAN, core-objs) $(RM) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(LANG_BINDINGS)
589 $(Q)find . -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete 616 $(Q)find $(if $(OUTPUT),$(OUTPUT),.) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete
590 $(Q)$(RM) $(OUTPUT).config-detected 617 $(Q)$(RM) $(OUTPUT).config-detected
591 $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32 618 $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32
592 $(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)FEATURE-DUMP $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex* \ 619 $(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)FEATURE-DUMP $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex* \
593 $(OUTPUT)util/intel-pt-decoder/inat-tables.c 620 $(OUTPUT)util/intel-pt-decoder/inat-tables.c $(OUTPUT)fixdep \
621 $(OUTPUT)tests/llvm-src-{base,kbuild,prologue}.c
594 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean 622 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
595 $(python-clean) 623 $(python-clean)
596 624
597# 625#
626# To provide FEATURE-DUMP into $(FEATURE_DUMP_COPY)
627# file if defined, with no further action.
628feature-dump:
629ifdef FEATURE_DUMP_COPY
630 @cp $(OUTPUT)FEATURE-DUMP $(FEATURE_DUMP_COPY)
631 @echo "FEATURE-DUMP file copied into $(FEATURE_DUMP_COPY)"
632else
633 @echo "FEATURE-DUMP file available in $(OUTPUT)FEATURE-DUMP"
634endif
635
636#
598# Trick: if ../../.git does not exist - we are building out of tree for example, 637# Trick: if ../../.git does not exist - we are building out of tree for example,
599# then force version regeneration: 638# then force version regeneration:
600# 639#
diff --git a/tools/perf/arch/x86/include/arch-tests.h b/tools/perf/arch/x86/include/arch-tests.h
index 7ed00f4b0908..b48de2f5813c 100644
--- a/tools/perf/arch/x86/include/arch-tests.h
+++ b/tools/perf/arch/x86/include/arch-tests.h
@@ -2,10 +2,10 @@
2#define ARCH_TESTS_H 2#define ARCH_TESTS_H
3 3
4/* Tests */ 4/* Tests */
5int test__rdpmc(void); 5int test__rdpmc(int subtest);
6int test__perf_time_to_tsc(void); 6int test__perf_time_to_tsc(int subtest);
7int test__insn_x86(void); 7int test__insn_x86(int subtest);
8int test__intel_cqm_count_nmi_context(void); 8int test__intel_cqm_count_nmi_context(int subtest);
9 9
10#ifdef HAVE_DWARF_UNWIND_SUPPORT 10#ifdef HAVE_DWARF_UNWIND_SUPPORT
11struct thread; 11struct thread;
diff --git a/tools/perf/arch/x86/tests/insn-x86.c b/tools/perf/arch/x86/tests/insn-x86.c
index b6115dfd28f0..08d9b2bc185c 100644
--- a/tools/perf/arch/x86/tests/insn-x86.c
+++ b/tools/perf/arch/x86/tests/insn-x86.c
@@ -171,7 +171,7 @@ static int test_data_set(struct test_data *dat_set, int x86_64)
171 * verbose (-v) option to see all the instructions and whether or not they 171 * verbose (-v) option to see all the instructions and whether or not they
172 * decoded successfuly. 172 * decoded successfuly.
173 */ 173 */
174int test__insn_x86(void) 174int test__insn_x86(int subtest __maybe_unused)
175{ 175{
176 int ret = 0; 176 int ret = 0;
177 177
diff --git a/tools/perf/arch/x86/tests/intel-cqm.c b/tools/perf/arch/x86/tests/intel-cqm.c
index d28c1b6a3b54..7f064eb37158 100644
--- a/tools/perf/arch/x86/tests/intel-cqm.c
+++ b/tools/perf/arch/x86/tests/intel-cqm.c
@@ -17,7 +17,7 @@ static pid_t spawn(void)
17 if (pid) 17 if (pid)
18 return pid; 18 return pid;
19 19
20 while(1); 20 while(1)
21 sleep(5); 21 sleep(5);
22 return 0; 22 return 0;
23} 23}
@@ -33,7 +33,7 @@ static pid_t spawn(void)
33 * the last read counter value to avoid triggering a WARN_ON_ONCE() in 33 * the last read counter value to avoid triggering a WARN_ON_ONCE() in
34 * smp_call_function_many() caused by sending IPIs from NMI context. 34 * smp_call_function_many() caused by sending IPIs from NMI context.
35 */ 35 */
36int test__intel_cqm_count_nmi_context(void) 36int test__intel_cqm_count_nmi_context(int subtest __maybe_unused)
37{ 37{
38 struct perf_evlist *evlist = NULL; 38 struct perf_evlist *evlist = NULL;
39 struct perf_evsel *evsel = NULL; 39 struct perf_evsel *evsel = NULL;
@@ -54,7 +54,7 @@ int test__intel_cqm_count_nmi_context(void)
54 54
55 ret = parse_events(evlist, "intel_cqm/llc_occupancy/", NULL); 55 ret = parse_events(evlist, "intel_cqm/llc_occupancy/", NULL);
56 if (ret) { 56 if (ret) {
57 pr_debug("parse_events failed\n"); 57 pr_debug("parse_events failed, is \"intel_cqm/llc_occupancy/\" available?\n");
58 err = TEST_SKIP; 58 err = TEST_SKIP;
59 goto out; 59 goto out;
60 } 60 }
diff --git a/tools/perf/arch/x86/tests/perf-time-to-tsc.c b/tools/perf/arch/x86/tests/perf-time-to-tsc.c
index 658cd200af74..9d29ee283ac5 100644
--- a/tools/perf/arch/x86/tests/perf-time-to-tsc.c
+++ b/tools/perf/arch/x86/tests/perf-time-to-tsc.c
@@ -35,13 +35,12 @@
35 * %0 is returned, otherwise %-1 is returned. If TSC conversion is not 35 * %0 is returned, otherwise %-1 is returned. If TSC conversion is not
36 * supported then then the test passes but " (not supported)" is printed. 36 * supported then then the test passes but " (not supported)" is printed.
37 */ 37 */
38int test__perf_time_to_tsc(void) 38int test__perf_time_to_tsc(int subtest __maybe_unused)
39{ 39{
40 struct record_opts opts = { 40 struct record_opts opts = {
41 .mmap_pages = UINT_MAX, 41 .mmap_pages = UINT_MAX,
42 .user_freq = UINT_MAX, 42 .user_freq = UINT_MAX,
43 .user_interval = ULLONG_MAX, 43 .user_interval = ULLONG_MAX,
44 .freq = 4000,
45 .target = { 44 .target = {
46 .uses_mmap = true, 45 .uses_mmap = true,
47 }, 46 },
diff --git a/tools/perf/arch/x86/tests/rdpmc.c b/tools/perf/arch/x86/tests/rdpmc.c
index e7688214c7cf..7bb0d13c235f 100644
--- a/tools/perf/arch/x86/tests/rdpmc.c
+++ b/tools/perf/arch/x86/tests/rdpmc.c
@@ -149,7 +149,7 @@ out_close:
149 return 0; 149 return 0;
150} 150}
151 151
152int test__rdpmc(void) 152int test__rdpmc(int subtest __maybe_unused)
153{ 153{
154 int status = 0; 154 int status = 0;
155 int wret = 0; 155 int wret = 0;
diff --git a/tools/perf/arch/x86/util/Build b/tools/perf/arch/x86/util/Build
index ff63649fa9ac..465970370f3e 100644
--- a/tools/perf/arch/x86/util/Build
+++ b/tools/perf/arch/x86/util/Build
@@ -5,6 +5,7 @@ libperf-y += kvm-stat.o
5libperf-y += perf_regs.o 5libperf-y += perf_regs.o
6 6
7libperf-$(CONFIG_DWARF) += dwarf-regs.o 7libperf-$(CONFIG_DWARF) += dwarf-regs.o
8libperf-$(CONFIG_BPF_PROLOGUE) += dwarf-regs.o
8 9
9libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o 10libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o
10libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o 11libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
diff --git a/tools/perf/arch/x86/util/intel-bts.c b/tools/perf/arch/x86/util/intel-bts.c
index 9b94ce520917..8d8150f1cf9b 100644
--- a/tools/perf/arch/x86/util/intel-bts.c
+++ b/tools/perf/arch/x86/util/intel-bts.c
@@ -327,7 +327,7 @@ static int intel_bts_snapshot_start(struct auxtrace_record *itr)
327 327
328 evlist__for_each(btsr->evlist, evsel) { 328 evlist__for_each(btsr->evlist, evsel) {
329 if (evsel->attr.type == btsr->intel_bts_pmu->type) 329 if (evsel->attr.type == btsr->intel_bts_pmu->type)
330 return perf_evlist__disable_event(btsr->evlist, evsel); 330 return perf_evsel__disable(evsel);
331 } 331 }
332 return -EINVAL; 332 return -EINVAL;
333} 333}
@@ -340,7 +340,7 @@ static int intel_bts_snapshot_finish(struct auxtrace_record *itr)
340 340
341 evlist__for_each(btsr->evlist, evsel) { 341 evlist__for_each(btsr->evlist, evsel) {
342 if (evsel->attr.type == btsr->intel_bts_pmu->type) 342 if (evsel->attr.type == btsr->intel_bts_pmu->type)
343 return perf_evlist__enable_event(btsr->evlist, evsel); 343 return perf_evsel__enable(evsel);
344 } 344 }
345 return -EINVAL; 345 return -EINVAL;
346} 346}
diff --git a/tools/perf/arch/x86/util/intel-pt.c b/tools/perf/arch/x86/util/intel-pt.c
index b02af064f0f9..f05daacc9e78 100644
--- a/tools/perf/arch/x86/util/intel-pt.c
+++ b/tools/perf/arch/x86/util/intel-pt.c
@@ -26,7 +26,7 @@
26#include "../../util/evlist.h" 26#include "../../util/evlist.h"
27#include "../../util/evsel.h" 27#include "../../util/evsel.h"
28#include "../../util/cpumap.h" 28#include "../../util/cpumap.h"
29#include "../../util/parse-options.h" 29#include <subcmd/parse-options.h>
30#include "../../util/parse-events.h" 30#include "../../util/parse-events.h"
31#include "../../util/pmu.h" 31#include "../../util/pmu.h"
32#include "../../util/debug.h" 32#include "../../util/debug.h"
@@ -725,7 +725,7 @@ static int intel_pt_snapshot_start(struct auxtrace_record *itr)
725 725
726 evlist__for_each(ptr->evlist, evsel) { 726 evlist__for_each(ptr->evlist, evsel) {
727 if (evsel->attr.type == ptr->intel_pt_pmu->type) 727 if (evsel->attr.type == ptr->intel_pt_pmu->type)
728 return perf_evlist__disable_event(ptr->evlist, evsel); 728 return perf_evsel__disable(evsel);
729 } 729 }
730 return -EINVAL; 730 return -EINVAL;
731} 731}
@@ -738,7 +738,7 @@ static int intel_pt_snapshot_finish(struct auxtrace_record *itr)
738 738
739 evlist__for_each(ptr->evlist, evsel) { 739 evlist__for_each(ptr->evlist, evsel) {
740 if (evsel->attr.type == ptr->intel_pt_pmu->type) 740 if (evsel->attr.type == ptr->intel_pt_pmu->type)
741 return perf_evlist__enable_event(ptr->evlist, evsel); 741 return perf_evsel__enable(evsel);
742 } 742 }
743 return -EINVAL; 743 return -EINVAL;
744} 744}
diff --git a/tools/perf/bench/futex-hash.c b/tools/perf/bench/futex-hash.c
index fc9bebd2cca0..0999ac536d86 100644
--- a/tools/perf/bench/futex-hash.c
+++ b/tools/perf/bench/futex-hash.c
@@ -11,7 +11,7 @@
11#include "../perf.h" 11#include "../perf.h"
12#include "../util/util.h" 12#include "../util/util.h"
13#include "../util/stat.h" 13#include "../util/stat.h"
14#include "../util/parse-options.h" 14#include <subcmd/parse-options.h>
15#include "../util/header.h" 15#include "../util/header.h"
16#include "bench.h" 16#include "bench.h"
17#include "futex.h" 17#include "futex.h"
diff --git a/tools/perf/bench/futex-lock-pi.c b/tools/perf/bench/futex-lock-pi.c
index bc6a16adbca8..6a18ce21f865 100644
--- a/tools/perf/bench/futex-lock-pi.c
+++ b/tools/perf/bench/futex-lock-pi.c
@@ -5,7 +5,7 @@
5#include "../perf.h" 5#include "../perf.h"
6#include "../util/util.h" 6#include "../util/util.h"
7#include "../util/stat.h" 7#include "../util/stat.h"
8#include "../util/parse-options.h" 8#include <subcmd/parse-options.h>
9#include "../util/header.h" 9#include "../util/header.h"
10#include "bench.h" 10#include "bench.h"
11#include "futex.h" 11#include "futex.h"
diff --git a/tools/perf/bench/futex-requeue.c b/tools/perf/bench/futex-requeue.c
index ad0d9b5342fb..718238683013 100644
--- a/tools/perf/bench/futex-requeue.c
+++ b/tools/perf/bench/futex-requeue.c
@@ -11,7 +11,7 @@
11#include "../perf.h" 11#include "../perf.h"
12#include "../util/util.h" 12#include "../util/util.h"
13#include "../util/stat.h" 13#include "../util/stat.h"
14#include "../util/parse-options.h" 14#include <subcmd/parse-options.h>
15#include "../util/header.h" 15#include "../util/header.h"
16#include "bench.h" 16#include "bench.h"
17#include "futex.h" 17#include "futex.h"
diff --git a/tools/perf/bench/futex-wake-parallel.c b/tools/perf/bench/futex-wake-parallel.c
index 6d8c9fa2a16c..91aaf2a1fa90 100644
--- a/tools/perf/bench/futex-wake-parallel.c
+++ b/tools/perf/bench/futex-wake-parallel.c
@@ -10,7 +10,7 @@
10#include "../perf.h" 10#include "../perf.h"
11#include "../util/util.h" 11#include "../util/util.h"
12#include "../util/stat.h" 12#include "../util/stat.h"
13#include "../util/parse-options.h" 13#include <subcmd/parse-options.h>
14#include "../util/header.h" 14#include "../util/header.h"
15#include "bench.h" 15#include "bench.h"
16#include "futex.h" 16#include "futex.h"
diff --git a/tools/perf/bench/futex-wake.c b/tools/perf/bench/futex-wake.c
index e5e41d3bdce7..f416bd705f66 100644
--- a/tools/perf/bench/futex-wake.c
+++ b/tools/perf/bench/futex-wake.c
@@ -11,7 +11,7 @@
11#include "../perf.h" 11#include "../perf.h"
12#include "../util/util.h" 12#include "../util/util.h"
13#include "../util/stat.h" 13#include "../util/stat.h"
14#include "../util/parse-options.h" 14#include <subcmd/parse-options.h>
15#include "../util/header.h" 15#include "../util/header.h"
16#include "bench.h" 16#include "bench.h"
17#include "futex.h" 17#include "futex.h"
diff --git a/tools/perf/bench/mem-functions.c b/tools/perf/bench/mem-functions.c
index 9419b944220f..a91aa85d80ff 100644
--- a/tools/perf/bench/mem-functions.c
+++ b/tools/perf/bench/mem-functions.c
@@ -8,7 +8,7 @@
8 8
9#include "../perf.h" 9#include "../perf.h"
10#include "../util/util.h" 10#include "../util/util.h"
11#include "../util/parse-options.h" 11#include <subcmd/parse-options.h>
12#include "../util/header.h" 12#include "../util/header.h"
13#include "../util/cloexec.h" 13#include "../util/cloexec.h"
14#include "bench.h" 14#include "bench.h"
diff --git a/tools/perf/bench/numa.c b/tools/perf/bench/numa.c
index 492df2752a2d..5049d6357a46 100644
--- a/tools/perf/bench/numa.c
+++ b/tools/perf/bench/numa.c
@@ -7,7 +7,7 @@
7#include "../perf.h" 7#include "../perf.h"
8#include "../builtin.h" 8#include "../builtin.h"
9#include "../util/util.h" 9#include "../util/util.h"
10#include "../util/parse-options.h" 10#include <subcmd/parse-options.h>
11#include "../util/cloexec.h" 11#include "../util/cloexec.h"
12 12
13#include "bench.h" 13#include "bench.h"
diff --git a/tools/perf/bench/sched-messaging.c b/tools/perf/bench/sched-messaging.c
index d4ff1b539cfd..bfaf9503de8e 100644
--- a/tools/perf/bench/sched-messaging.c
+++ b/tools/perf/bench/sched-messaging.c
@@ -11,7 +11,7 @@
11 11
12#include "../perf.h" 12#include "../perf.h"
13#include "../util/util.h" 13#include "../util/util.h"
14#include "../util/parse-options.h" 14#include <subcmd/parse-options.h>
15#include "../builtin.h" 15#include "../builtin.h"
16#include "bench.h" 16#include "bench.h"
17 17
diff --git a/tools/perf/bench/sched-pipe.c b/tools/perf/bench/sched-pipe.c
index 005cc283790c..1dc2d13cc272 100644
--- a/tools/perf/bench/sched-pipe.c
+++ b/tools/perf/bench/sched-pipe.c
@@ -10,7 +10,7 @@
10 */ 10 */
11#include "../perf.h" 11#include "../perf.h"
12#include "../util/util.h" 12#include "../util/util.h"
13#include "../util/parse-options.h" 13#include <subcmd/parse-options.h>
14#include "../builtin.h" 14#include "../builtin.h"
15#include "bench.h" 15#include "bench.h"
16 16
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 2bf9b3fd9e61..cc5c1267c738 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -21,7 +21,7 @@
21#include "util/evsel.h" 21#include "util/evsel.h"
22#include "util/annotate.h" 22#include "util/annotate.h"
23#include "util/event.h" 23#include "util/event.h"
24#include "util/parse-options.h" 24#include <subcmd/parse-options.h>
25#include "util/parse-events.h" 25#include "util/parse-events.h"
26#include "util/thread.h" 26#include "util/thread.h"
27#include "util/sort.h" 27#include "util/sort.h"
@@ -47,7 +47,7 @@ struct perf_annotate {
47}; 47};
48 48
49static int perf_evsel__add_sample(struct perf_evsel *evsel, 49static int perf_evsel__add_sample(struct perf_evsel *evsel,
50 struct perf_sample *sample __maybe_unused, 50 struct perf_sample *sample,
51 struct addr_location *al, 51 struct addr_location *al,
52 struct perf_annotate *ann) 52 struct perf_annotate *ann)
53{ 53{
@@ -72,7 +72,10 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel,
72 return 0; 72 return 0;
73 } 73 }
74 74
75 he = __hists__add_entry(hists, al, NULL, NULL, NULL, 1, 1, 0, true); 75 sample->period = 1;
76 sample->weight = 1;
77
78 he = __hists__add_entry(hists, al, NULL, NULL, NULL, sample, true);
76 if (he == NULL) 79 if (he == NULL)
77 return -ENOMEM; 80 return -ENOMEM;
78 81
@@ -343,18 +346,19 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
343 return ret; 346 return ret;
344 347
345 argc = parse_options(argc, argv, options, annotate_usage, 0); 348 argc = parse_options(argc, argv, options, annotate_usage, 0);
349 if (argc) {
350 /*
351 * Special case: if there's an argument left then assume that
352 * it's a symbol filter:
353 */
354 if (argc > 1)
355 usage_with_options(annotate_usage, options);
346 356
347 if (annotate.use_stdio) 357 annotate.sym_hist_filter = argv[0];
348 use_browser = 0; 358 }
349 else if (annotate.use_tui)
350 use_browser = 1;
351 else if (annotate.use_gtk)
352 use_browser = 2;
353 359
354 file.path = input_name; 360 file.path = input_name;
355 361
356 setup_browser(true);
357
358 annotate.session = perf_session__new(&file, false, &annotate.tool); 362 annotate.session = perf_session__new(&file, false, &annotate.tool);
359 if (annotate.session == NULL) 363 if (annotate.session == NULL)
360 return -1; 364 return -1;
@@ -366,19 +370,17 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
366 if (ret < 0) 370 if (ret < 0)
367 goto out_delete; 371 goto out_delete;
368 372
369 if (setup_sorting() < 0) 373 if (setup_sorting(NULL) < 0)
370 usage_with_options(annotate_usage, options); 374 usage_with_options(annotate_usage, options);
371 375
372 if (argc) { 376 if (annotate.use_stdio)
373 /* 377 use_browser = 0;
374 * Special case: if there's an argument left then assume that 378 else if (annotate.use_tui)
375 * it's a symbol filter: 379 use_browser = 1;
376 */ 380 else if (annotate.use_gtk)
377 if (argc > 1) 381 use_browser = 2;
378 usage_with_options(annotate_usage, options);
379 382
380 annotate.sym_hist_filter = argv[0]; 383 setup_browser(true);
381 }
382 384
383 ret = __cmd_annotate(&annotate); 385 ret = __cmd_annotate(&annotate);
384 386
diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c
index b17aed36ca16..a1cddc6bbf0f 100644
--- a/tools/perf/builtin-bench.c
+++ b/tools/perf/builtin-bench.c
@@ -16,7 +16,7 @@
16 */ 16 */
17#include "perf.h" 17#include "perf.h"
18#include "util/util.h" 18#include "util/util.h"
19#include "util/parse-options.h" 19#include <subcmd/parse-options.h>
20#include "builtin.h" 20#include "builtin.h"
21#include "bench/bench.h" 21#include "bench/bench.h"
22 22
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c
index 7b8450cd33c2..d93bff7fc0e4 100644
--- a/tools/perf/builtin-buildid-cache.c
+++ b/tools/perf/builtin-buildid-cache.c
@@ -16,7 +16,7 @@
16#include "util/cache.h" 16#include "util/cache.h"
17#include "util/debug.h" 17#include "util/debug.h"
18#include "util/header.h" 18#include "util/header.h"
19#include "util/parse-options.h" 19#include <subcmd/parse-options.h>
20#include "util/strlist.h" 20#include "util/strlist.h"
21#include "util/build-id.h" 21#include "util/build-id.h"
22#include "util/session.h" 22#include "util/session.h"
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index 918b4de29de4..5e914ee79eb3 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -12,7 +12,7 @@
12#include "util/build-id.h" 12#include "util/build-id.h"
13#include "util/cache.h" 13#include "util/cache.h"
14#include "util/debug.h" 14#include "util/debug.h"
15#include "util/parse-options.h" 15#include <subcmd/parse-options.h>
16#include "util/session.h" 16#include "util/session.h"
17#include "util/symbol.h" 17#include "util/symbol.h"
18#include "util/data.h" 18#include "util/data.h"
@@ -110,7 +110,7 @@ int cmd_buildid_list(int argc, const char **argv,
110 setup_pager(); 110 setup_pager();
111 111
112 if (show_kernel) 112 if (show_kernel)
113 return sysfs__fprintf_build_id(stdout); 113 return !(sysfs__fprintf_build_id(stdout) > 0);
114 114
115 return perf_session__list_build_ids(force, with_hits); 115 return perf_session__list_build_ids(force, with_hits);
116} 116}
diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c
new file mode 100644
index 000000000000..f04e804a9fad
--- /dev/null
+++ b/tools/perf/builtin-config.c
@@ -0,0 +1,66 @@
1/*
2 * builtin-config.c
3 *
4 * Copyright (C) 2015, Taeung Song <treeze.taeung@gmail.com>
5 *
6 */
7#include "builtin.h"
8
9#include "perf.h"
10
11#include "util/cache.h"
12#include <subcmd/parse-options.h>
13#include "util/util.h"
14#include "util/debug.h"
15
16static const char * const config_usage[] = {
17 "perf config [options]",
18 NULL
19};
20
21enum actions {
22 ACTION_LIST = 1
23} actions;
24
25static struct option config_options[] = {
26 OPT_SET_UINT('l', "list", &actions,
27 "show current config variables", ACTION_LIST),
28 OPT_END()
29};
30
31static int show_config(const char *key, const char *value,
32 void *cb __maybe_unused)
33{
34 if (value)
35 printf("%s=%s\n", key, value);
36 else
37 printf("%s\n", key);
38
39 return 0;
40}
41
42int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
43{
44 int ret = 0;
45
46 argc = parse_options(argc, argv, config_options, config_usage,
47 PARSE_OPT_STOP_AT_NON_OPTION);
48
49 switch (actions) {
50 case ACTION_LIST:
51 if (argc) {
52 pr_err("Error: takes no arguments\n");
53 parse_options_usage(config_usage, config_options, "l", 1);
54 } else {
55 ret = perf_config(show_config, NULL);
56 if (ret < 0)
57 pr_err("Nothing configured, "
58 "please check your ~/.perfconfig file\n");
59 }
60 break;
61 default:
62 usage_with_options(config_usage, config_options);
63 }
64
65 return ret;
66}
diff --git a/tools/perf/builtin-data.c b/tools/perf/builtin-data.c
index d6525bc54d13..b97bc1518b44 100644
--- a/tools/perf/builtin-data.c
+++ b/tools/perf/builtin-data.c
@@ -2,7 +2,7 @@
2#include "builtin.h" 2#include "builtin.h"
3#include "perf.h" 3#include "perf.h"
4#include "debug.h" 4#include "debug.h"
5#include "parse-options.h" 5#include <subcmd/parse-options.h>
6#include "data-convert-bt.h" 6#include "data-convert-bt.h"
7 7
8typedef int (*data_cmd_fn_t)(int argc, const char **argv, const char *prefix); 8typedef int (*data_cmd_fn_t)(int argc, const char **argv, const char *prefix);
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 0b180a885ba3..36ccc2b8827f 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -311,11 +311,11 @@ static int formula_fprintf(struct hist_entry *he, struct hist_entry *pair,
311} 311}
312 312
313static int hists__add_entry(struct hists *hists, 313static int hists__add_entry(struct hists *hists,
314 struct addr_location *al, u64 period, 314 struct addr_location *al,
315 u64 weight, u64 transaction) 315 struct perf_sample *sample)
316{ 316{
317 if (__hists__add_entry(hists, al, NULL, NULL, NULL, period, weight, 317 if (__hists__add_entry(hists, al, NULL, NULL, NULL,
318 transaction, true) != NULL) 318 sample, true) != NULL)
319 return 0; 319 return 0;
320 return -ENOMEM; 320 return -ENOMEM;
321} 321}
@@ -336,8 +336,7 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused,
336 return -1; 336 return -1;
337 } 337 }
338 338
339 if (hists__add_entry(hists, &al, sample->period, 339 if (hists__add_entry(hists, &al, sample)) {
340 sample->weight, sample->transaction)) {
341 pr_warning("problem incrementing symbol period, skipping event\n"); 340 pr_warning("problem incrementing symbol period, skipping event\n");
342 goto out_put; 341 goto out_put;
343 } 342 }
@@ -1208,7 +1207,7 @@ static int ui_init(void)
1208 BUG_ON(1); 1207 BUG_ON(1);
1209 } 1208 }
1210 1209
1211 list_add(&fmt->sort_list, &perf_hpp__sort_list); 1210 perf_hpp__register_sort_field(fmt);
1212 return 0; 1211 return 0;
1213} 1212}
1214 1213
@@ -1280,7 +1279,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
1280 1279
1281 sort__mode = SORT_MODE__DIFF; 1280 sort__mode = SORT_MODE__DIFF;
1282 1281
1283 if (setup_sorting() < 0) 1282 if (setup_sorting(NULL) < 0)
1284 usage_with_options(diff_usage, options); 1283 usage_with_options(diff_usage, options);
1285 1284
1286 setup_pager(); 1285 setup_pager();
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c
index f4d62510acbb..8a31f511e1a0 100644
--- a/tools/perf/builtin-evlist.c
+++ b/tools/perf/builtin-evlist.c
@@ -12,7 +12,7 @@
12#include "util/evlist.h" 12#include "util/evlist.h"
13#include "util/evsel.h" 13#include "util/evsel.h"
14#include "util/parse-events.h" 14#include "util/parse-events.h"
15#include "util/parse-options.h" 15#include <subcmd/parse-options.h>
16#include "util/session.h" 16#include "util/session.h"
17#include "util/data.h" 17#include "util/data.h"
18#include "util/debug.h" 18#include "util/debug.h"
@@ -26,14 +26,22 @@ static int __cmd_evlist(const char *file_name, struct perf_attr_details *details
26 .mode = PERF_DATA_MODE_READ, 26 .mode = PERF_DATA_MODE_READ,
27 .force = details->force, 27 .force = details->force,
28 }; 28 };
29 bool has_tracepoint = false;
29 30
30 session = perf_session__new(&file, 0, NULL); 31 session = perf_session__new(&file, 0, NULL);
31 if (session == NULL) 32 if (session == NULL)
32 return -1; 33 return -1;
33 34
34 evlist__for_each(session->evlist, pos) 35 evlist__for_each(session->evlist, pos) {
35 perf_evsel__fprintf(pos, details, stdout); 36 perf_evsel__fprintf(pos, details, stdout);
36 37
38 if (pos->attr.type == PERF_TYPE_TRACEPOINT)
39 has_tracepoint = true;
40 }
41
42 if (has_tracepoint && !details->trace_fields)
43 printf("# Tip: use 'perf evlist --trace-fields' to show fields for tracepoint events\n");
44
37 perf_session__delete(session); 45 perf_session__delete(session);
38 return 0; 46 return 0;
39} 47}
@@ -49,6 +57,7 @@ int cmd_evlist(int argc, const char **argv, const char *prefix __maybe_unused)
49 OPT_BOOLEAN('g', "group", &details.event_group, 57 OPT_BOOLEAN('g', "group", &details.event_group,
50 "Show event group information"), 58 "Show event group information"),
51 OPT_BOOLEAN('f', "force", &details.force, "don't complain, do it"), 59 OPT_BOOLEAN('f', "force", &details.force, "don't complain, do it"),
60 OPT_BOOLEAN(0, "trace-fields", &details.trace_fields, "Show tracepoint fields"),
52 OPT_END() 61 OPT_END()
53 }; 62 };
54 const char * const evlist_usage[] = { 63 const char * const evlist_usage[] = {
diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c
index a7d588bf3cdd..96c1a4cfbbbf 100644
--- a/tools/perf/builtin-help.c
+++ b/tools/perf/builtin-help.c
@@ -6,11 +6,11 @@
6#include "perf.h" 6#include "perf.h"
7#include "util/cache.h" 7#include "util/cache.h"
8#include "builtin.h" 8#include "builtin.h"
9#include "util/exec_cmd.h" 9#include <subcmd/exec-cmd.h>
10#include "common-cmds.h" 10#include "common-cmds.h"
11#include "util/parse-options.h" 11#include <subcmd/parse-options.h>
12#include "util/run-command.h" 12#include <subcmd/run-command.h>
13#include "util/help.h" 13#include <subcmd/help.h>
14#include "util/debug.h" 14#include "util/debug.h"
15 15
16static struct man_viewer_list { 16static struct man_viewer_list {
@@ -407,7 +407,7 @@ static int get_html_page_path(struct strbuf *page_path, const char *page)
407#ifndef open_html 407#ifndef open_html
408static void open_html(const char *path) 408static void open_html(const char *path)
409{ 409{
410 execl_perf_cmd("web--browse", "-c", "help.browser", path, NULL); 410 execl_cmd("web--browse", "-c", "help.browser", path, NULL);
411} 411}
412#endif 412#endif
413 413
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 0a945d2e8ca5..0022e02ed31a 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -18,7 +18,7 @@
18#include "util/data.h" 18#include "util/data.h"
19#include "util/auxtrace.h" 19#include "util/auxtrace.h"
20 20
21#include "util/parse-options.h" 21#include <subcmd/parse-options.h>
22 22
23#include <linux/list.h> 23#include <linux/list.h>
24 24
@@ -675,6 +675,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
675 .fork = perf_event__repipe, 675 .fork = perf_event__repipe,
676 .exit = perf_event__repipe, 676 .exit = perf_event__repipe,
677 .lost = perf_event__repipe, 677 .lost = perf_event__repipe,
678 .lost_samples = perf_event__repipe,
678 .aux = perf_event__repipe, 679 .aux = perf_event__repipe,
679 .itrace_start = perf_event__repipe, 680 .itrace_start = perf_event__repipe,
680 .context_switch = perf_event__repipe, 681 .context_switch = perf_event__repipe,
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 93ce665f976f..118010553d0c 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -12,7 +12,7 @@
12#include "util/tool.h" 12#include "util/tool.h"
13#include "util/callchain.h" 13#include "util/callchain.h"
14 14
15#include "util/parse-options.h" 15#include <subcmd/parse-options.h>
16#include "util/trace-event.h" 16#include "util/trace-event.h"
17#include "util/data.h" 17#include "util/data.h"
18#include "util/cpumap.h" 18#include "util/cpumap.h"
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index dd94b4ca2213..4418d9214872 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -10,7 +10,7 @@
10#include "util/header.h" 10#include "util/header.h"
11#include "util/session.h" 11#include "util/session.h"
12#include "util/intlist.h" 12#include "util/intlist.h"
13#include "util/parse-options.h" 13#include <subcmd/parse-options.h>
14#include "util/trace-event.h" 14#include "util/trace-event.h"
15#include "util/debug.h" 15#include "util/debug.h"
16#include "util/tool.h" 16#include "util/tool.h"
@@ -1351,7 +1351,6 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
1351 disable_buildid_cache(); 1351 disable_buildid_cache();
1352 1352
1353 use_browser = 0; 1353 use_browser = 0;
1354 setup_browser(false);
1355 1354
1356 if (argc) { 1355 if (argc) {
1357 argc = parse_options(argc, argv, live_options, 1356 argc = parse_options(argc, argv, live_options,
@@ -1409,8 +1408,6 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
1409 err = kvm_events_live_report(kvm); 1408 err = kvm_events_live_report(kvm);
1410 1409
1411out: 1410out:
1412 exit_browser(0);
1413
1414 if (kvm->session) 1411 if (kvm->session)
1415 perf_session__delete(kvm->session); 1412 perf_session__delete(kvm->session);
1416 kvm->session = NULL; 1413 kvm->session = NULL;
diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c
index bf679e2c978b..5e22db4684b8 100644
--- a/tools/perf/builtin-list.c
+++ b/tools/perf/builtin-list.c
@@ -14,7 +14,7 @@
14#include "util/parse-events.h" 14#include "util/parse-events.h"
15#include "util/cache.h" 15#include "util/cache.h"
16#include "util/pmu.h" 16#include "util/pmu.h"
17#include "util/parse-options.h" 17#include <subcmd/parse-options.h>
18 18
19int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused) 19int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
20{ 20{
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index de16aaed516e..ce3bfb48b26f 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -9,7 +9,7 @@
9#include "util/thread.h" 9#include "util/thread.h"
10#include "util/header.h" 10#include "util/header.h"
11 11
12#include "util/parse-options.h" 12#include <subcmd/parse-options.h>
13#include "util/trace-event.h" 13#include "util/trace-event.h"
14 14
15#include "util/debug.h" 15#include "util/debug.h"
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c
index 80170aace5d4..390170041696 100644
--- a/tools/perf/builtin-mem.c
+++ b/tools/perf/builtin-mem.c
@@ -1,7 +1,7 @@
1#include "builtin.h" 1#include "builtin.h"
2#include "perf.h" 2#include "perf.h"
3 3
4#include "util/parse-options.h" 4#include <subcmd/parse-options.h>
5#include "util/trace-event.h" 5#include "util/trace-event.h"
6#include "util/tool.h" 6#include "util/tool.h"
7#include "util/session.h" 7#include "util/session.h"
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 132afc97676c..9af859b28b15 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -37,7 +37,7 @@
37#include "util/strfilter.h" 37#include "util/strfilter.h"
38#include "util/symbol.h" 38#include "util/symbol.h"
39#include "util/debug.h" 39#include "util/debug.h"
40#include "util/parse-options.h" 40#include <subcmd/parse-options.h>
41#include "util/probe-finder.h" 41#include "util/probe-finder.h"
42#include "util/probe-event.h" 42#include "util/probe-event.h"
43#include "util/probe-file.h" 43#include "util/probe-file.h"
@@ -249,6 +249,9 @@ static int opt_show_vars(const struct option *opt,
249 249
250 return ret; 250 return ret;
251} 251}
252#else
253# define opt_show_lines NULL
254# define opt_show_vars NULL
252#endif 255#endif
253static int opt_add_probe_event(const struct option *opt, 256static int opt_add_probe_event(const struct option *opt,
254 const char *str, int unset __maybe_unused) 257 const char *str, int unset __maybe_unused)
@@ -473,7 +476,6 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
473 opt_add_probe_event), 476 opt_add_probe_event),
474 OPT_BOOLEAN('f', "force", &probe_conf.force_add, "forcibly add events" 477 OPT_BOOLEAN('f', "force", &probe_conf.force_add, "forcibly add events"
475 " with existing name"), 478 " with existing name"),
476#ifdef HAVE_DWARF_SUPPORT
477 OPT_CALLBACK('L', "line", NULL, 479 OPT_CALLBACK('L', "line", NULL,
478 "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]", 480 "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]",
479 "Show source code lines.", opt_show_lines), 481 "Show source code lines.", opt_show_lines),
@@ -490,7 +492,6 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
490 "directory", "path to kernel source"), 492 "directory", "path to kernel source"),
491 OPT_BOOLEAN('\0', "no-inlines", &probe_conf.no_inlines, 493 OPT_BOOLEAN('\0', "no-inlines", &probe_conf.no_inlines,
492 "Don't search inlined functions"), 494 "Don't search inlined functions"),
493#endif
494 OPT__DRY_RUN(&probe_event_dry_run), 495 OPT__DRY_RUN(&probe_event_dry_run),
495 OPT_INTEGER('\0', "max-probes", &probe_conf.max_probes, 496 OPT_INTEGER('\0', "max-probes", &probe_conf.max_probes,
496 "Set how many probe points can be found for a probe."), 497 "Set how many probe points can be found for a probe."),
@@ -521,6 +522,16 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
521#ifdef HAVE_DWARF_SUPPORT 522#ifdef HAVE_DWARF_SUPPORT
522 set_option_flag(options, 'L', "line", PARSE_OPT_EXCLUSIVE); 523 set_option_flag(options, 'L', "line", PARSE_OPT_EXCLUSIVE);
523 set_option_flag(options, 'V', "vars", PARSE_OPT_EXCLUSIVE); 524 set_option_flag(options, 'V', "vars", PARSE_OPT_EXCLUSIVE);
525#else
526# define set_nobuild(s, l, c) set_option_nobuild(options, s, l, "NO_DWARF=1", c)
527 set_nobuild('L', "line", false);
528 set_nobuild('V', "vars", false);
529 set_nobuild('\0', "externs", false);
530 set_nobuild('\0', "range", false);
531 set_nobuild('k', "vmlinux", true);
532 set_nobuild('s', "source", true);
533 set_nobuild('\0', "no-inlines", true);
534# undef set_nobuild
524#endif 535#endif
525 set_option_flag(options, 'F', "funcs", PARSE_OPT_EXCLUSIVE); 536 set_option_flag(options, 'F', "funcs", PARSE_OPT_EXCLUSIVE);
526 537
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 199fc31e3919..319712a4e02b 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -11,7 +11,7 @@
11 11
12#include "util/build-id.h" 12#include "util/build-id.h"
13#include "util/util.h" 13#include "util/util.h"
14#include "util/parse-options.h" 14#include <subcmd/parse-options.h>
15#include "util/parse-events.h" 15#include "util/parse-events.h"
16 16
17#include "util/callchain.h" 17#include "util/callchain.h"
@@ -50,6 +50,7 @@ struct record {
50 int realtime_prio; 50 int realtime_prio;
51 bool no_buildid; 51 bool no_buildid;
52 bool no_buildid_cache; 52 bool no_buildid_cache;
53 bool buildid_all;
53 unsigned long long samples; 54 unsigned long long samples;
54}; 55};
55 56
@@ -362,6 +363,13 @@ static int process_buildids(struct record *rec)
362 */ 363 */
363 symbol_conf.ignore_vmlinux_buildid = true; 364 symbol_conf.ignore_vmlinux_buildid = true;
364 365
366 /*
367 * If --buildid-all is given, it marks all DSO regardless of hits,
368 * so no need to process samples.
369 */
370 if (rec->buildid_all)
371 rec->tool.sample = NULL;
372
365 return perf_session__process_events(session); 373 return perf_session__process_events(session);
366} 374}
367 375
@@ -452,6 +460,8 @@ static void record__init_features(struct record *rec)
452 460
453 if (!rec->opts.full_auxtrace) 461 if (!rec->opts.full_auxtrace)
454 perf_header__clear_feat(&session->header, HEADER_AUXTRACE); 462 perf_header__clear_feat(&session->header, HEADER_AUXTRACE);
463
464 perf_header__clear_feat(&session->header, HEADER_STAT);
455} 465}
456 466
457static volatile int workload_exec_errno; 467static volatile int workload_exec_errno;
@@ -754,12 +764,8 @@ out_child:
754 764
755 if (!rec->no_buildid) { 765 if (!rec->no_buildid) {
756 process_buildids(rec); 766 process_buildids(rec);
757 /* 767
758 * We take all buildids when the file contains 768 if (rec->buildid_all)
759 * AUX area tracing data because we do not decode the
760 * trace because it would take too long.
761 */
762 if (rec->opts.full_auxtrace)
763 dsos__hit_all(rec->session); 769 dsos__hit_all(rec->session);
764 } 770 }
765 perf_session__write_header(rec->session, rec->evlist, fd, true); 771 perf_session__write_header(rec->session, rec->evlist, fd, true);
@@ -813,8 +819,12 @@ int record_parse_callchain_opt(const struct option *opt,
813 } 819 }
814 820
815 ret = parse_callchain_record_opt(arg, &callchain_param); 821 ret = parse_callchain_record_opt(arg, &callchain_param);
816 if (!ret) 822 if (!ret) {
823 /* Enable data address sampling for DWARF unwind. */
824 if (callchain_param.record_mode == CALLCHAIN_DWARF)
825 record->sample_address = true;
817 callchain_debug(); 826 callchain_debug();
827 }
818 828
819 return ret; 829 return ret;
820} 830}
@@ -837,6 +847,19 @@ int record_callchain_opt(const struct option *opt,
837 847
838static int perf_record_config(const char *var, const char *value, void *cb) 848static int perf_record_config(const char *var, const char *value, void *cb)
839{ 849{
850 struct record *rec = cb;
851
852 if (!strcmp(var, "record.build-id")) {
853 if (!strcmp(value, "cache"))
854 rec->no_buildid_cache = false;
855 else if (!strcmp(value, "no-cache"))
856 rec->no_buildid_cache = true;
857 else if (!strcmp(value, "skip"))
858 rec->no_buildid = true;
859 else
860 return -1;
861 return 0;
862 }
840 if (!strcmp(var, "record.call-graph")) 863 if (!strcmp(var, "record.call-graph"))
841 var = "call-graph.record-mode"; /* fall-through */ 864 var = "call-graph.record-mode"; /* fall-through */
842 865
@@ -1113,12 +1136,14 @@ struct option __record_options[] = {
1113 "per thread proc mmap processing timeout in ms"), 1136 "per thread proc mmap processing timeout in ms"),
1114 OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events, 1137 OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events,
1115 "Record context switch events"), 1138 "Record context switch events"),
1116#ifdef HAVE_LIBBPF_SUPPORT
1117 OPT_STRING(0, "clang-path", &llvm_param.clang_path, "clang path", 1139 OPT_STRING(0, "clang-path", &llvm_param.clang_path, "clang path",
1118 "clang binary to use for compiling BPF scriptlets"), 1140 "clang binary to use for compiling BPF scriptlets"),
1119 OPT_STRING(0, "clang-opt", &llvm_param.clang_opt, "clang options", 1141 OPT_STRING(0, "clang-opt", &llvm_param.clang_opt, "clang options",
1120 "options passed to clang when compiling BPF scriptlets"), 1142 "options passed to clang when compiling BPF scriptlets"),
1121#endif 1143 OPT_STRING(0, "vmlinux", &symbol_conf.vmlinux_name,
1144 "file", "vmlinux pathname"),
1145 OPT_BOOLEAN(0, "buildid-all", &record.buildid_all,
1146 "Record build-id of all DSOs regardless of hits"),
1122 OPT_END() 1147 OPT_END()
1123}; 1148};
1124 1149
@@ -1130,6 +1155,27 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
1130 struct record *rec = &record; 1155 struct record *rec = &record;
1131 char errbuf[BUFSIZ]; 1156 char errbuf[BUFSIZ];
1132 1157
1158#ifndef HAVE_LIBBPF_SUPPORT
1159# define set_nobuild(s, l, c) set_option_nobuild(record_options, s, l, "NO_LIBBPF=1", c)
1160 set_nobuild('\0', "clang-path", true);
1161 set_nobuild('\0', "clang-opt", true);
1162# undef set_nobuild
1163#endif
1164
1165#ifndef HAVE_BPF_PROLOGUE
1166# if !defined (HAVE_DWARF_SUPPORT)
1167# define REASON "NO_DWARF=1"
1168# elif !defined (HAVE_LIBBPF_SUPPORT)
1169# define REASON "NO_LIBBPF=1"
1170# else
1171# define REASON "this architecture doesn't support BPF prologue"
1172# endif
1173# define set_nobuild(s, l, c) set_option_nobuild(record_options, s, l, REASON, c)
1174 set_nobuild('\0', "vmlinux", true);
1175# undef set_nobuild
1176# undef REASON
1177#endif
1178
1133 rec->evlist = perf_evlist__new(); 1179 rec->evlist = perf_evlist__new();
1134 if (rec->evlist == NULL) 1180 if (rec->evlist == NULL)
1135 return -ENOMEM; 1181 return -ENOMEM;
@@ -1215,6 +1261,14 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
1215 if (err) 1261 if (err)
1216 goto out_symbol_exit; 1262 goto out_symbol_exit;
1217 1263
1264 /*
1265 * We take all buildids when the file contains
1266 * AUX area tracing data because we do not decode the
1267 * trace because it would take too long.
1268 */
1269 if (rec->opts.full_auxtrace)
1270 rec->buildid_all = true;
1271
1218 if (record_opts__config(&rec->opts)) { 1272 if (record_opts__config(&rec->opts)) {
1219 err = -EINVAL; 1273 err = -EINVAL;
1220 goto out_symbol_exit; 1274 goto out_symbol_exit;
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 2853ad2bd435..2bf537f190a0 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -27,7 +27,8 @@
27#include "util/session.h" 27#include "util/session.h"
28#include "util/tool.h" 28#include "util/tool.h"
29 29
30#include "util/parse-options.h" 30#include <subcmd/parse-options.h>
31#include <subcmd/exec-cmd.h>
31#include "util/parse-events.h" 32#include "util/parse-events.h"
32 33
33#include "util/thread.h" 34#include "util/thread.h"
@@ -44,8 +45,7 @@
44struct report { 45struct report {
45 struct perf_tool tool; 46 struct perf_tool tool;
46 struct perf_session *session; 47 struct perf_session *session;
47 bool force, use_tui, use_gtk, use_stdio; 48 bool use_tui, use_gtk, use_stdio;
48 bool hide_unresolved;
49 bool dont_use_callchains; 49 bool dont_use_callchains;
50 bool show_full_info; 50 bool show_full_info;
51 bool show_threads; 51 bool show_threads;
@@ -146,7 +146,7 @@ static int process_sample_event(struct perf_tool *tool,
146 struct hist_entry_iter iter = { 146 struct hist_entry_iter iter = {
147 .evsel = evsel, 147 .evsel = evsel,
148 .sample = sample, 148 .sample = sample,
149 .hide_unresolved = rep->hide_unresolved, 149 .hide_unresolved = symbol_conf.hide_unresolved,
150 .add_entry_cb = hist_iter__report_callback, 150 .add_entry_cb = hist_iter__report_callback,
151 }; 151 };
152 int ret = 0; 152 int ret = 0;
@@ -157,7 +157,7 @@ static int process_sample_event(struct perf_tool *tool,
157 return -1; 157 return -1;
158 } 158 }
159 159
160 if (rep->hide_unresolved && al.sym == NULL) 160 if (symbol_conf.hide_unresolved && al.sym == NULL)
161 goto out_put; 161 goto out_put;
162 162
163 if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap)) 163 if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
@@ -434,7 +434,14 @@ static int report__browse_hists(struct report *rep)
434 int ret; 434 int ret;
435 struct perf_session *session = rep->session; 435 struct perf_session *session = rep->session;
436 struct perf_evlist *evlist = session->evlist; 436 struct perf_evlist *evlist = session->evlist;
437 const char *help = "For a higher level overview, try: perf report --sort comm,dso"; 437 const char *help = perf_tip(system_path(TIPDIR));
438
439 if (help == NULL) {
440 /* fallback for people who don't install perf ;-) */
441 help = perf_tip(DOCDIR);
442 if (help == NULL)
443 help = "Cannot load tips.txt file, please install perf!";
444 }
438 445
439 switch (use_browser) { 446 switch (use_browser) {
440 case 1: 447 case 1:
@@ -514,20 +521,26 @@ static int __cmd_report(struct report *rep)
514 if (rep->cpu_list) { 521 if (rep->cpu_list) {
515 ret = perf_session__cpu_bitmap(session, rep->cpu_list, 522 ret = perf_session__cpu_bitmap(session, rep->cpu_list,
516 rep->cpu_bitmap); 523 rep->cpu_bitmap);
517 if (ret) 524 if (ret) {
525 ui__error("failed to set cpu bitmap\n");
518 return ret; 526 return ret;
527 }
519 } 528 }
520 529
521 if (rep->show_threads) 530 if (rep->show_threads)
522 perf_read_values_init(&rep->show_threads_values); 531 perf_read_values_init(&rep->show_threads_values);
523 532
524 ret = report__setup_sample_type(rep); 533 ret = report__setup_sample_type(rep);
525 if (ret) 534 if (ret) {
535 /* report__setup_sample_type() already showed error message */
526 return ret; 536 return ret;
537 }
527 538
528 ret = perf_session__process_events(session); 539 ret = perf_session__process_events(session);
529 if (ret) 540 if (ret) {
541 ui__error("failed to process sample\n");
530 return ret; 542 return ret;
543 }
531 544
532 report__warn_kptr_restrict(rep); 545 report__warn_kptr_restrict(rep);
533 546
@@ -625,7 +638,7 @@ parse_percent_limit(const struct option *opt, const char *str,
625 return 0; 638 return 0;
626} 639}
627 640
628#define CALLCHAIN_DEFAULT_OPT "graph,0.5,caller,function" 641#define CALLCHAIN_DEFAULT_OPT "graph,0.5,caller,function,percent"
629 642
630const char report_callchain_help[] = "Display call graph (stack chain/backtrace):\n\n" 643const char report_callchain_help[] = "Display call graph (stack chain/backtrace):\n\n"
631 CALLCHAIN_REPORT_HELP 644 CALLCHAIN_REPORT_HELP
@@ -678,7 +691,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
678 "file", "vmlinux pathname"), 691 "file", "vmlinux pathname"),
679 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, 692 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
680 "file", "kallsyms pathname"), 693 "file", "kallsyms pathname"),
681 OPT_BOOLEAN('f', "force", &report.force, "don't complain, do it"), 694 OPT_BOOLEAN('f', "force", &symbol_conf.force, "don't complain, do it"),
682 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, 695 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
683 "load module symbols - WARNING: use only with -k and LIVE kernel"), 696 "load module symbols - WARNING: use only with -k and LIVE kernel"),
684 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, 697 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
@@ -708,7 +721,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
708 OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other, 721 OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other,
709 "Only display entries with parent-match"), 722 "Only display entries with parent-match"),
710 OPT_CALLBACK_DEFAULT('g', "call-graph", &report, 723 OPT_CALLBACK_DEFAULT('g', "call-graph", &report,
711 "print_type,threshold[,print_limit],order,sort_key[,branch]", 724 "print_type,threshold[,print_limit],order,sort_key[,branch],value",
712 report_callchain_help, &report_parse_callchain_opt, 725 report_callchain_help, &report_parse_callchain_opt,
713 callchain_default_opt), 726 callchain_default_opt),
714 OPT_BOOLEAN(0, "children", &symbol_conf.cumulate_callchain, 727 OPT_BOOLEAN(0, "children", &symbol_conf.cumulate_callchain,
@@ -740,7 +753,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
740 OPT_STRING_NOEMPTY('t', "field-separator", &symbol_conf.field_sep, "separator", 753 OPT_STRING_NOEMPTY('t', "field-separator", &symbol_conf.field_sep, "separator",
741 "separator for columns, no spaces will be added between " 754 "separator for columns, no spaces will be added between "
742 "columns '.' is reserved."), 755 "columns '.' is reserved."),
743 OPT_BOOLEAN('U', "hide-unresolved", &report.hide_unresolved, 756 OPT_BOOLEAN('U', "hide-unresolved", &symbol_conf.hide_unresolved,
744 "Only display entries resolved to a symbol"), 757 "Only display entries resolved to a symbol"),
745 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", 758 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
746 "Look for files with symbols relative to this directory"), 759 "Look for files with symbols relative to this directory"),
@@ -783,6 +796,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
783 "Show callgraph from reference event"), 796 "Show callgraph from reference event"),
784 OPT_INTEGER(0, "socket-filter", &report.socket_filter, 797 OPT_INTEGER(0, "socket-filter", &report.socket_filter,
785 "only show processor socket that match with this filter"), 798 "only show processor socket that match with this filter"),
799 OPT_BOOLEAN(0, "raw-trace", &symbol_conf.raw_trace,
800 "Show raw trace event output (do not use print fmt or plugins)"),
786 OPT_END() 801 OPT_END()
787 }; 802 };
788 struct perf_data_file file = { 803 struct perf_data_file file = {
@@ -796,6 +811,16 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
796 perf_config(report__config, &report); 811 perf_config(report__config, &report);
797 812
798 argc = parse_options(argc, argv, options, report_usage, 0); 813 argc = parse_options(argc, argv, options, report_usage, 0);
814 if (argc) {
815 /*
816 * Special case: if there's an argument left then assume that
817 * it's a symbol filter:
818 */
819 if (argc > 1)
820 usage_with_options(report_usage, options);
821
822 report.symbol_filter_str = argv[0];
823 }
799 824
800 if (symbol_conf.vmlinux_name && 825 if (symbol_conf.vmlinux_name &&
801 access(symbol_conf.vmlinux_name, R_OK)) { 826 access(symbol_conf.vmlinux_name, R_OK)) {
@@ -832,7 +857,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
832 } 857 }
833 858
834 file.path = input_name; 859 file.path = input_name;
835 file.force = report.force; 860 file.force = symbol_conf.force;
836 861
837repeat: 862repeat:
838 session = perf_session__new(&file, false, &report.tool); 863 session = perf_session__new(&file, false, &report.tool);
@@ -882,7 +907,7 @@ repeat:
882 symbol_conf.cumulate_callchain = false; 907 symbol_conf.cumulate_callchain = false;
883 } 908 }
884 909
885 if (setup_sorting() < 0) { 910 if (setup_sorting(session->evlist) < 0) {
886 if (sort_order) 911 if (sort_order)
887 parse_options_usage(report_usage, options, "s", 1); 912 parse_options_usage(report_usage, options, "s", 1);
888 if (field_order) 913 if (field_order)
@@ -941,17 +966,6 @@ repeat:
941 if (symbol__init(&session->header.env) < 0) 966 if (symbol__init(&session->header.env) < 0)
942 goto error; 967 goto error;
943 968
944 if (argc) {
945 /*
946 * Special case: if there's an argument left then assume that
947 * it's a symbol filter:
948 */
949 if (argc > 1)
950 usage_with_options(report_usage, options);
951
952 report.symbol_filter_str = argv[0];
953 }
954
955 sort__setup_elide(stdout); 969 sort__setup_elide(stdout);
956 970
957 ret = __cmd_report(&report); 971 ret = __cmd_report(&report);
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index e3d3e32c0a93..871b55ae22a4 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -12,7 +12,7 @@
12#include "util/tool.h" 12#include "util/tool.h"
13#include "util/cloexec.h" 13#include "util/cloexec.h"
14 14
15#include "util/parse-options.h" 15#include <subcmd/parse-options.h>
16#include "util/trace-event.h" 16#include "util/trace-event.h"
17 17
18#include "util/debug.h" 18#include "util/debug.h"
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 72b5deb4bd79..c691214d820f 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -3,9 +3,9 @@
3#include "perf.h" 3#include "perf.h"
4#include "util/cache.h" 4#include "util/cache.h"
5#include "util/debug.h" 5#include "util/debug.h"
6#include "util/exec_cmd.h" 6#include <subcmd/exec-cmd.h>
7#include "util/header.h" 7#include "util/header.h"
8#include "util/parse-options.h" 8#include <subcmd/parse-options.h>
9#include "util/perf_regs.h" 9#include "util/perf_regs.h"
10#include "util/session.h" 10#include "util/session.h"
11#include "util/tool.h" 11#include "util/tool.h"
@@ -18,7 +18,11 @@
18#include "util/sort.h" 18#include "util/sort.h"
19#include "util/data.h" 19#include "util/data.h"
20#include "util/auxtrace.h" 20#include "util/auxtrace.h"
21#include "util/cpumap.h"
22#include "util/thread_map.h"
23#include "util/stat.h"
21#include <linux/bitmap.h> 24#include <linux/bitmap.h>
25#include "asm/bug.h"
22 26
23static char const *script_name; 27static char const *script_name;
24static char const *generate_script_lang; 28static char const *generate_script_lang;
@@ -32,6 +36,7 @@ static bool print_flags;
32static bool nanosecs; 36static bool nanosecs;
33static const char *cpu_list; 37static const char *cpu_list;
34static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 38static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
39static struct perf_stat_config stat_config;
35 40
36unsigned int scripting_max_stack = PERF_MAX_STACK_DEPTH; 41unsigned int scripting_max_stack = PERF_MAX_STACK_DEPTH;
37 42
@@ -130,6 +135,18 @@ static struct {
130 135
131 .invalid_fields = PERF_OUTPUT_TRACE, 136 .invalid_fields = PERF_OUTPUT_TRACE,
132 }, 137 },
138
139 [PERF_TYPE_BREAKPOINT] = {
140 .user_set = false,
141
142 .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
143 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
144 PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
145 PERF_OUTPUT_SYM | PERF_OUTPUT_DSO |
146 PERF_OUTPUT_PERIOD,
147
148 .invalid_fields = PERF_OUTPUT_TRACE,
149 },
133}; 150};
134 151
135static bool output_set_by_user(void) 152static bool output_set_by_user(void)
@@ -204,6 +221,9 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
204 struct perf_event_attr *attr = &evsel->attr; 221 struct perf_event_attr *attr = &evsel->attr;
205 bool allow_user_set; 222 bool allow_user_set;
206 223
224 if (perf_header__has_feat(&session->header, HEADER_STAT))
225 return 0;
226
207 allow_user_set = perf_header__has_feat(&session->header, 227 allow_user_set = perf_header__has_feat(&session->header,
208 HEADER_AUXTRACE); 228 HEADER_AUXTRACE);
209 229
@@ -588,8 +608,35 @@ static void print_sample_flags(u32 flags)
588 printf(" %-4s ", str); 608 printf(" %-4s ", str);
589} 609}
590 610
591static void process_event(union perf_event *event, struct perf_sample *sample, 611struct perf_script {
592 struct perf_evsel *evsel, struct addr_location *al) 612 struct perf_tool tool;
613 struct perf_session *session;
614 bool show_task_events;
615 bool show_mmap_events;
616 bool show_switch_events;
617 bool allocated;
618 struct cpu_map *cpus;
619 struct thread_map *threads;
620 int name_width;
621};
622
623static int perf_evlist__max_name_len(struct perf_evlist *evlist)
624{
625 struct perf_evsel *evsel;
626 int max = 0;
627
628 evlist__for_each(evlist, evsel) {
629 int len = strlen(perf_evsel__name(evsel));
630
631 max = MAX(len, max);
632 }
633
634 return max;
635}
636
637static void process_event(struct perf_script *script, union perf_event *event,
638 struct perf_sample *sample, struct perf_evsel *evsel,
639 struct addr_location *al)
593{ 640{
594 struct thread *thread = al->thread; 641 struct thread *thread = al->thread;
595 struct perf_event_attr *attr = &evsel->attr; 642 struct perf_event_attr *attr = &evsel->attr;
@@ -604,7 +651,12 @@ static void process_event(union perf_event *event, struct perf_sample *sample,
604 651
605 if (PRINT_FIELD(EVNAME)) { 652 if (PRINT_FIELD(EVNAME)) {
606 const char *evname = perf_evsel__name(evsel); 653 const char *evname = perf_evsel__name(evsel);
607 printf("%s: ", evname ? evname : "[unknown]"); 654
655 if (!script->name_width)
656 script->name_width = perf_evlist__max_name_len(script->session->evlist);
657
658 printf("%*s: ", script->name_width,
659 evname ? evname : "[unknown]");
608 } 660 }
609 661
610 if (print_flags) 662 if (print_flags)
@@ -643,65 +695,81 @@ static void process_event(union perf_event *event, struct perf_sample *sample,
643 printf("\n"); 695 printf("\n");
644} 696}
645 697
646static int default_start_script(const char *script __maybe_unused, 698static struct scripting_ops *scripting_ops;
647 int argc __maybe_unused,
648 const char **argv __maybe_unused)
649{
650 return 0;
651}
652 699
653static int default_flush_script(void) 700static void __process_stat(struct perf_evsel *counter, u64 tstamp)
654{ 701{
655 return 0; 702 int nthreads = thread_map__nr(counter->threads);
703 int ncpus = perf_evsel__nr_cpus(counter);
704 int cpu, thread;
705 static int header_printed;
706
707 if (counter->system_wide)
708 nthreads = 1;
709
710 if (!header_printed) {
711 printf("%3s %8s %15s %15s %15s %15s %s\n",
712 "CPU", "THREAD", "VAL", "ENA", "RUN", "TIME", "EVENT");
713 header_printed = 1;
714 }
715
716 for (thread = 0; thread < nthreads; thread++) {
717 for (cpu = 0; cpu < ncpus; cpu++) {
718 struct perf_counts_values *counts;
719
720 counts = perf_counts(counter->counts, cpu, thread);
721
722 printf("%3d %8d %15" PRIu64 " %15" PRIu64 " %15" PRIu64 " %15" PRIu64 " %s\n",
723 counter->cpus->map[cpu],
724 thread_map__pid(counter->threads, thread),
725 counts->val,
726 counts->ena,
727 counts->run,
728 tstamp,
729 perf_evsel__name(counter));
730 }
731 }
656} 732}
657 733
658static int default_stop_script(void) 734static void process_stat(struct perf_evsel *counter, u64 tstamp)
659{ 735{
660 return 0; 736 if (scripting_ops && scripting_ops->process_stat)
737 scripting_ops->process_stat(&stat_config, counter, tstamp);
738 else
739 __process_stat(counter, tstamp);
661} 740}
662 741
663static int default_generate_script(struct pevent *pevent __maybe_unused, 742static void process_stat_interval(u64 tstamp)
664 const char *outfile __maybe_unused)
665{ 743{
666 return 0; 744 if (scripting_ops && scripting_ops->process_stat_interval)
745 scripting_ops->process_stat_interval(tstamp);
667} 746}
668 747
669static struct scripting_ops default_scripting_ops = {
670 .start_script = default_start_script,
671 .flush_script = default_flush_script,
672 .stop_script = default_stop_script,
673 .process_event = process_event,
674 .generate_script = default_generate_script,
675};
676
677static struct scripting_ops *scripting_ops;
678
679static void setup_scripting(void) 748static void setup_scripting(void)
680{ 749{
681 setup_perl_scripting(); 750 setup_perl_scripting();
682 setup_python_scripting(); 751 setup_python_scripting();
683
684 scripting_ops = &default_scripting_ops;
685} 752}
686 753
687static int flush_scripting(void) 754static int flush_scripting(void)
688{ 755{
689 return scripting_ops->flush_script(); 756 return scripting_ops ? scripting_ops->flush_script() : 0;
690} 757}
691 758
692static int cleanup_scripting(void) 759static int cleanup_scripting(void)
693{ 760{
694 pr_debug("\nperf script stopped\n"); 761 pr_debug("\nperf script stopped\n");
695 762
696 return scripting_ops->stop_script(); 763 return scripting_ops ? scripting_ops->stop_script() : 0;
697} 764}
698 765
699static int process_sample_event(struct perf_tool *tool __maybe_unused, 766static int process_sample_event(struct perf_tool *tool,
700 union perf_event *event, 767 union perf_event *event,
701 struct perf_sample *sample, 768 struct perf_sample *sample,
702 struct perf_evsel *evsel, 769 struct perf_evsel *evsel,
703 struct machine *machine) 770 struct machine *machine)
704{ 771{
772 struct perf_script *scr = container_of(tool, struct perf_script, tool);
705 struct addr_location al; 773 struct addr_location al;
706 774
707 if (debug_mode) { 775 if (debug_mode) {
@@ -727,20 +795,16 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
727 if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) 795 if (cpu_list && !test_bit(sample->cpu, cpu_bitmap))
728 goto out_put; 796 goto out_put;
729 797
730 scripting_ops->process_event(event, sample, evsel, &al); 798 if (scripting_ops)
799 scripting_ops->process_event(event, sample, evsel, &al);
800 else
801 process_event(scr, event, sample, evsel, &al);
802
731out_put: 803out_put:
732 addr_location__put(&al); 804 addr_location__put(&al);
733 return 0; 805 return 0;
734} 806}
735 807
736struct perf_script {
737 struct perf_tool tool;
738 struct perf_session *session;
739 bool show_task_events;
740 bool show_mmap_events;
741 bool show_switch_events;
742};
743
744static int process_attr(struct perf_tool *tool, union perf_event *event, 808static int process_attr(struct perf_tool *tool, union perf_event *event,
745 struct perf_evlist **pevlist) 809 struct perf_evlist **pevlist)
746{ 810{
@@ -1156,6 +1220,8 @@ static int parse_output_fields(const struct option *opt __maybe_unused,
1156 type = PERF_TYPE_TRACEPOINT; 1220 type = PERF_TYPE_TRACEPOINT;
1157 else if (!strcmp(str, "raw")) 1221 else if (!strcmp(str, "raw"))
1158 type = PERF_TYPE_RAW; 1222 type = PERF_TYPE_RAW;
1223 else if (!strcmp(str, "break"))
1224 type = PERF_TYPE_BREAKPOINT;
1159 else { 1225 else {
1160 fprintf(stderr, "Invalid event type in field string.\n"); 1226 fprintf(stderr, "Invalid event type in field string.\n");
1161 rc = -EINVAL; 1227 rc = -EINVAL;
@@ -1421,7 +1487,7 @@ static int list_available_scripts(const struct option *opt __maybe_unused,
1421 char first_half[BUFSIZ]; 1487 char first_half[BUFSIZ];
1422 char *script_root; 1488 char *script_root;
1423 1489
1424 snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path()); 1490 snprintf(scripts_path, MAXPATHLEN, "%s/scripts", get_argv_exec_path());
1425 1491
1426 scripts_dir = opendir(scripts_path); 1492 scripts_dir = opendir(scripts_path);
1427 if (!scripts_dir) 1493 if (!scripts_dir)
@@ -1542,7 +1608,7 @@ int find_scripts(char **scripts_array, char **scripts_path_array)
1542 if (!session) 1608 if (!session)
1543 return -1; 1609 return -1;
1544 1610
1545 snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path()); 1611 snprintf(scripts_path, MAXPATHLEN, "%s/scripts", get_argv_exec_path());
1546 1612
1547 scripts_dir = opendir(scripts_path); 1613 scripts_dir = opendir(scripts_path);
1548 if (!scripts_dir) { 1614 if (!scripts_dir) {
@@ -1600,7 +1666,7 @@ static char *get_script_path(const char *script_root, const char *suffix)
1600 char lang_path[MAXPATHLEN]; 1666 char lang_path[MAXPATHLEN];
1601 char *__script_root; 1667 char *__script_root;
1602 1668
1603 snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path()); 1669 snprintf(scripts_path, MAXPATHLEN, "%s/scripts", get_argv_exec_path());
1604 1670
1605 scripts_dir = opendir(scripts_path); 1671 scripts_dir = opendir(scripts_path);
1606 if (!scripts_dir) 1672 if (!scripts_dir)
@@ -1695,6 +1761,87 @@ static void script__setup_sample_type(struct perf_script *script)
1695 } 1761 }
1696} 1762}
1697 1763
1764static int process_stat_round_event(struct perf_tool *tool __maybe_unused,
1765 union perf_event *event,
1766 struct perf_session *session)
1767{
1768 struct stat_round_event *round = &event->stat_round;
1769 struct perf_evsel *counter;
1770
1771 evlist__for_each(session->evlist, counter) {
1772 perf_stat_process_counter(&stat_config, counter);
1773 process_stat(counter, round->time);
1774 }
1775
1776 process_stat_interval(round->time);
1777 return 0;
1778}
1779
1780static int process_stat_config_event(struct perf_tool *tool __maybe_unused,
1781 union perf_event *event,
1782 struct perf_session *session __maybe_unused)
1783{
1784 perf_event__read_stat_config(&stat_config, &event->stat_config);
1785 return 0;
1786}
1787
1788static int set_maps(struct perf_script *script)
1789{
1790 struct perf_evlist *evlist = script->session->evlist;
1791
1792 if (!script->cpus || !script->threads)
1793 return 0;
1794
1795 if (WARN_ONCE(script->allocated, "stats double allocation\n"))
1796 return -EINVAL;
1797
1798 perf_evlist__set_maps(evlist, script->cpus, script->threads);
1799
1800 if (perf_evlist__alloc_stats(evlist, true))
1801 return -ENOMEM;
1802
1803 script->allocated = true;
1804 return 0;
1805}
1806
1807static
1808int process_thread_map_event(struct perf_tool *tool,
1809 union perf_event *event,
1810 struct perf_session *session __maybe_unused)
1811{
1812 struct perf_script *script = container_of(tool, struct perf_script, tool);
1813
1814 if (script->threads) {
1815 pr_warning("Extra thread map event, ignoring.\n");
1816 return 0;
1817 }
1818
1819 script->threads = thread_map__new_event(&event->thread_map);
1820 if (!script->threads)
1821 return -ENOMEM;
1822
1823 return set_maps(script);
1824}
1825
1826static
1827int process_cpu_map_event(struct perf_tool *tool __maybe_unused,
1828 union perf_event *event,
1829 struct perf_session *session __maybe_unused)
1830{
1831 struct perf_script *script = container_of(tool, struct perf_script, tool);
1832
1833 if (script->cpus) {
1834 pr_warning("Extra cpu map event, ignoring.\n");
1835 return 0;
1836 }
1837
1838 script->cpus = cpu_map__new_data(&event->cpu_map.data);
1839 if (!script->cpus)
1840 return -ENOMEM;
1841
1842 return set_maps(script);
1843}
1844
1698int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) 1845int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1699{ 1846{
1700 bool show_full_info = false; 1847 bool show_full_info = false;
@@ -1723,6 +1870,11 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1723 .auxtrace_info = perf_event__process_auxtrace_info, 1870 .auxtrace_info = perf_event__process_auxtrace_info,
1724 .auxtrace = perf_event__process_auxtrace, 1871 .auxtrace = perf_event__process_auxtrace,
1725 .auxtrace_error = perf_event__process_auxtrace_error, 1872 .auxtrace_error = perf_event__process_auxtrace_error,
1873 .stat = perf_event__process_stat_event,
1874 .stat_round = process_stat_round_event,
1875 .stat_config = process_stat_config_event,
1876 .thread_map = process_thread_map_event,
1877 .cpu_map = process_cpu_map_event,
1726 .ordered_events = true, 1878 .ordered_events = true,
1727 .ordering_requires_timestamps = true, 1879 .ordering_requires_timestamps = true,
1728 }, 1880 },
@@ -1836,7 +1988,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1836 scripting_max_stack = itrace_synth_opts.callchain_sz; 1988 scripting_max_stack = itrace_synth_opts.callchain_sz;
1837 1989
1838 /* make sure PERF_EXEC_PATH is set for scripts */ 1990 /* make sure PERF_EXEC_PATH is set for scripts */
1839 perf_set_argv_exec_path(perf_exec_path()); 1991 set_argv_exec_path(get_argv_exec_path());
1840 1992
1841 if (argc && !script_name && !rec_script_path && !rep_script_path) { 1993 if (argc && !script_name && !rec_script_path && !rep_script_path) {
1842 int live_pipe[2]; 1994 int live_pipe[2];
@@ -2076,6 +2228,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
2076 flush_scripting(); 2228 flush_scripting();
2077 2229
2078out_delete: 2230out_delete:
2231 perf_evlist__free_stats(session->evlist);
2079 perf_session__delete(session); 2232 perf_session__delete(session);
2080 2233
2081 if (script_started) 2234 if (script_started)
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index e77880b5094d..038e877081b6 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -45,7 +45,7 @@
45#include "builtin.h" 45#include "builtin.h"
46#include "util/cgroup.h" 46#include "util/cgroup.h"
47#include "util/util.h" 47#include "util/util.h"
48#include "util/parse-options.h" 48#include <subcmd/parse-options.h>
49#include "util/parse-events.h" 49#include "util/parse-events.h"
50#include "util/pmu.h" 50#include "util/pmu.h"
51#include "util/event.h" 51#include "util/event.h"
@@ -59,6 +59,9 @@
59#include "util/thread.h" 59#include "util/thread.h"
60#include "util/thread_map.h" 60#include "util/thread_map.h"
61#include "util/counts.h" 61#include "util/counts.h"
62#include "util/session.h"
63#include "util/tool.h"
64#include "asm/bug.h"
62 65
63#include <stdlib.h> 66#include <stdlib.h>
64#include <sys/prctl.h> 67#include <sys/prctl.h>
@@ -126,6 +129,21 @@ static bool append_file;
126static const char *output_name; 129static const char *output_name;
127static int output_fd; 130static int output_fd;
128 131
132struct perf_stat {
133 bool record;
134 struct perf_data_file file;
135 struct perf_session *session;
136 u64 bytes_written;
137 struct perf_tool tool;
138 bool maps_allocated;
139 struct cpu_map *cpus;
140 struct thread_map *threads;
141 enum aggr_mode aggr_mode;
142};
143
144static struct perf_stat perf_stat;
145#define STAT_RECORD perf_stat.record
146
129static volatile int done = 0; 147static volatile int done = 0;
130 148
131static struct perf_stat_config stat_config = { 149static struct perf_stat_config stat_config = {
@@ -161,15 +179,43 @@ static int create_perf_stat_counter(struct perf_evsel *evsel)
161 179
162 attr->inherit = !no_inherit; 180 attr->inherit = !no_inherit;
163 181
164 if (target__has_cpu(&target)) 182 /*
165 return perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel)); 183 * Some events get initialized with sample_(period/type) set,
184 * like tracepoints. Clear it up for counting.
185 */
186 attr->sample_period = 0;
187
188 /*
189 * But set sample_type to PERF_SAMPLE_IDENTIFIER, which should be harmless
190 * while avoiding that older tools show confusing messages.
191 *
192 * However for pipe sessions we need to keep it zero,
193 * because script's perf_evsel__check_attr is triggered
194 * by attr->sample_type != 0, and we can't run it on
195 * stat sessions.
196 */
197 if (!(STAT_RECORD && perf_stat.file.is_pipe))
198 attr->sample_type = PERF_SAMPLE_IDENTIFIER;
166 199
167 if (!target__has_task(&target) && perf_evsel__is_group_leader(evsel)) { 200 /*
201 * Disabling all counters initially, they will be enabled
202 * either manually by us or by kernel via enable_on_exec
203 * set later.
204 */
205 if (perf_evsel__is_group_leader(evsel)) {
168 attr->disabled = 1; 206 attr->disabled = 1;
169 if (!initial_delay) 207
208 /*
209 * In case of initial_delay we enable tracee
210 * events manually.
211 */
212 if (target__none(&target) && !initial_delay)
170 attr->enable_on_exec = 1; 213 attr->enable_on_exec = 1;
171 } 214 }
172 215
216 if (target__has_cpu(&target))
217 return perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel));
218
173 return perf_evsel__open_per_thread(evsel, evsel_list->threads); 219 return perf_evsel__open_per_thread(evsel, evsel_list->threads);
174} 220}
175 221
@@ -185,6 +231,42 @@ static inline int nsec_counter(struct perf_evsel *evsel)
185 return 0; 231 return 0;
186} 232}
187 233
234static int process_synthesized_event(struct perf_tool *tool __maybe_unused,
235 union perf_event *event,
236 struct perf_sample *sample __maybe_unused,
237 struct machine *machine __maybe_unused)
238{
239 if (perf_data_file__write(&perf_stat.file, event, event->header.size) < 0) {
240 pr_err("failed to write perf data, error: %m\n");
241 return -1;
242 }
243
244 perf_stat.bytes_written += event->header.size;
245 return 0;
246}
247
248static int write_stat_round_event(u64 tm, u64 type)
249{
250 return perf_event__synthesize_stat_round(NULL, tm, type,
251 process_synthesized_event,
252 NULL);
253}
254
255#define WRITE_STAT_ROUND_EVENT(time, interval) \
256 write_stat_round_event(time, PERF_STAT_ROUND_TYPE__ ## interval)
257
258#define SID(e, x, y) xyarray__entry(e->sample_id, x, y)
259
260static int
261perf_evsel__write_stat_event(struct perf_evsel *counter, u32 cpu, u32 thread,
262 struct perf_counts_values *count)
263{
264 struct perf_sample_id *sid = SID(counter, cpu, thread);
265
266 return perf_event__synthesize_stat(NULL, cpu, thread, sid->id, count,
267 process_synthesized_event, NULL);
268}
269
188/* 270/*
189 * Read out the results of a single counter: 271 * Read out the results of a single counter:
190 * do not aggregate counts across CPUs in system-wide mode 272 * do not aggregate counts across CPUs in system-wide mode
@@ -208,6 +290,13 @@ static int read_counter(struct perf_evsel *counter)
208 count = perf_counts(counter->counts, cpu, thread); 290 count = perf_counts(counter->counts, cpu, thread);
209 if (perf_evsel__read(counter, cpu, thread, count)) 291 if (perf_evsel__read(counter, cpu, thread, count))
210 return -1; 292 return -1;
293
294 if (STAT_RECORD) {
295 if (perf_evsel__write_stat_event(counter, cpu, thread, count)) {
296 pr_err("failed to write stat event\n");
297 return -1;
298 }
299 }
211 } 300 }
212 } 301 }
213 302
@@ -241,21 +330,26 @@ static void process_interval(void)
241 clock_gettime(CLOCK_MONOTONIC, &ts); 330 clock_gettime(CLOCK_MONOTONIC, &ts);
242 diff_timespec(&rs, &ts, &ref_time); 331 diff_timespec(&rs, &ts, &ref_time);
243 332
333 if (STAT_RECORD) {
334 if (WRITE_STAT_ROUND_EVENT(rs.tv_sec * NSECS_PER_SEC + rs.tv_nsec, INTERVAL))
335 pr_err("failed to write stat round event\n");
336 }
337
244 print_counters(&rs, 0, NULL); 338 print_counters(&rs, 0, NULL);
245} 339}
246 340
247static void handle_initial_delay(void) 341static void enable_counters(void)
248{ 342{
249 struct perf_evsel *counter; 343 if (initial_delay)
250
251 if (initial_delay) {
252 const int ncpus = cpu_map__nr(evsel_list->cpus),
253 nthreads = thread_map__nr(evsel_list->threads);
254
255 usleep(initial_delay * 1000); 344 usleep(initial_delay * 1000);
256 evlist__for_each(evsel_list, counter) 345
257 perf_evsel__enable(counter, ncpus, nthreads); 346 /*
258 } 347 * We need to enable counters only if:
348 * - we don't have tracee (attaching to task or cpu)
349 * - we have initial delay configured
350 */
351 if (!target__none(&target) || initial_delay)
352 perf_evlist__enable(evsel_list);
259} 353}
260 354
261static volatile int workload_exec_errno; 355static volatile int workload_exec_errno;
@@ -271,6 +365,135 @@ static void workload_exec_failed_signal(int signo __maybe_unused, siginfo_t *inf
271 workload_exec_errno = info->si_value.sival_int; 365 workload_exec_errno = info->si_value.sival_int;
272} 366}
273 367
368static bool has_unit(struct perf_evsel *counter)
369{
370 return counter->unit && *counter->unit;
371}
372
373static bool has_scale(struct perf_evsel *counter)
374{
375 return counter->scale != 1;
376}
377
378static int perf_stat_synthesize_config(bool is_pipe)
379{
380 struct perf_evsel *counter;
381 int err;
382
383 if (is_pipe) {
384 err = perf_event__synthesize_attrs(NULL, perf_stat.session,
385 process_synthesized_event);
386 if (err < 0) {
387 pr_err("Couldn't synthesize attrs.\n");
388 return err;
389 }
390 }
391
392 /*
393 * Synthesize other events stuff not carried within
394 * attr event - unit, scale, name
395 */
396 evlist__for_each(evsel_list, counter) {
397 if (!counter->supported)
398 continue;
399
400 /*
401 * Synthesize unit and scale only if it's defined.
402 */
403 if (has_unit(counter)) {
404 err = perf_event__synthesize_event_update_unit(NULL, counter, process_synthesized_event);
405 if (err < 0) {
406 pr_err("Couldn't synthesize evsel unit.\n");
407 return err;
408 }
409 }
410
411 if (has_scale(counter)) {
412 err = perf_event__synthesize_event_update_scale(NULL, counter, process_synthesized_event);
413 if (err < 0) {
414 pr_err("Couldn't synthesize evsel scale.\n");
415 return err;
416 }
417 }
418
419 if (counter->own_cpus) {
420 err = perf_event__synthesize_event_update_cpus(NULL, counter, process_synthesized_event);
421 if (err < 0) {
422 pr_err("Couldn't synthesize evsel scale.\n");
423 return err;
424 }
425 }
426
427 /*
428 * Name is needed only for pipe output,
429 * perf.data carries event names.
430 */
431 if (is_pipe) {
432 err = perf_event__synthesize_event_update_name(NULL, counter, process_synthesized_event);
433 if (err < 0) {
434 pr_err("Couldn't synthesize evsel name.\n");
435 return err;
436 }
437 }
438 }
439
440 err = perf_event__synthesize_thread_map2(NULL, evsel_list->threads,
441 process_synthesized_event,
442 NULL);
443 if (err < 0) {
444 pr_err("Couldn't synthesize thread map.\n");
445 return err;
446 }
447
448 err = perf_event__synthesize_cpu_map(NULL, evsel_list->cpus,
449 process_synthesized_event, NULL);
450 if (err < 0) {
451 pr_err("Couldn't synthesize thread map.\n");
452 return err;
453 }
454
455 err = perf_event__synthesize_stat_config(NULL, &stat_config,
456 process_synthesized_event, NULL);
457 if (err < 0) {
458 pr_err("Couldn't synthesize config.\n");
459 return err;
460 }
461
462 return 0;
463}
464
465#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
466
467static int __store_counter_ids(struct perf_evsel *counter,
468 struct cpu_map *cpus,
469 struct thread_map *threads)
470{
471 int cpu, thread;
472
473 for (cpu = 0; cpu < cpus->nr; cpu++) {
474 for (thread = 0; thread < threads->nr; thread++) {
475 int fd = FD(counter, cpu, thread);
476
477 if (perf_evlist__id_add_fd(evsel_list, counter,
478 cpu, thread, fd) < 0)
479 return -1;
480 }
481 }
482
483 return 0;
484}
485
486static int store_counter_ids(struct perf_evsel *counter)
487{
488 struct cpu_map *cpus = counter->cpus;
489 struct thread_map *threads = counter->threads;
490
491 if (perf_evsel__alloc_id(counter, cpus->nr, threads->nr))
492 return -ENOMEM;
493
494 return __store_counter_ids(counter, cpus, threads);
495}
496
274static int __run_perf_stat(int argc, const char **argv) 497static int __run_perf_stat(int argc, const char **argv)
275{ 498{
276 int interval = stat_config.interval; 499 int interval = stat_config.interval;
@@ -281,6 +504,7 @@ static int __run_perf_stat(int argc, const char **argv)
281 size_t l; 504 size_t l;
282 int status = 0; 505 int status = 0;
283 const bool forks = (argc > 0); 506 const bool forks = (argc > 0);
507 bool is_pipe = STAT_RECORD ? perf_stat.file.is_pipe : false;
284 508
285 if (interval) { 509 if (interval) {
286 ts.tv_sec = interval / 1000; 510 ts.tv_sec = interval / 1000;
@@ -291,7 +515,7 @@ static int __run_perf_stat(int argc, const char **argv)
291 } 515 }
292 516
293 if (forks) { 517 if (forks) {
294 if (perf_evlist__prepare_workload(evsel_list, &target, argv, false, 518 if (perf_evlist__prepare_workload(evsel_list, &target, argv, is_pipe,
295 workload_exec_failed_signal) < 0) { 519 workload_exec_failed_signal) < 0) {
296 perror("failed to prepare workload"); 520 perror("failed to prepare workload");
297 return -1; 521 return -1;
@@ -335,6 +559,9 @@ static int __run_perf_stat(int argc, const char **argv)
335 l = strlen(counter->unit); 559 l = strlen(counter->unit);
336 if (l > unit_width) 560 if (l > unit_width)
337 unit_width = l; 561 unit_width = l;
562
563 if (STAT_RECORD && store_counter_ids(counter))
564 return -1;
338 } 565 }
339 566
340 if (perf_evlist__apply_filters(evsel_list, &counter)) { 567 if (perf_evlist__apply_filters(evsel_list, &counter)) {
@@ -344,6 +571,24 @@ static int __run_perf_stat(int argc, const char **argv)
344 return -1; 571 return -1;
345 } 572 }
346 573
574 if (STAT_RECORD) {
575 int err, fd = perf_data_file__fd(&perf_stat.file);
576
577 if (is_pipe) {
578 err = perf_header__write_pipe(perf_data_file__fd(&perf_stat.file));
579 } else {
580 err = perf_session__write_header(perf_stat.session, evsel_list,
581 fd, false);
582 }
583
584 if (err < 0)
585 return err;
586
587 err = perf_stat_synthesize_config(is_pipe);
588 if (err < 0)
589 return err;
590 }
591
347 /* 592 /*
348 * Enable counters and exec the command: 593 * Enable counters and exec the command:
349 */ 594 */
@@ -352,7 +597,7 @@ static int __run_perf_stat(int argc, const char **argv)
352 597
353 if (forks) { 598 if (forks) {
354 perf_evlist__start_workload(evsel_list); 599 perf_evlist__start_workload(evsel_list);
355 handle_initial_delay(); 600 enable_counters();
356 601
357 if (interval) { 602 if (interval) {
358 while (!waitpid(child_pid, &status, WNOHANG)) { 603 while (!waitpid(child_pid, &status, WNOHANG)) {
@@ -371,7 +616,7 @@ static int __run_perf_stat(int argc, const char **argv)
371 if (WIFSIGNALED(status)) 616 if (WIFSIGNALED(status))
372 psignal(WTERMSIG(status), argv[0]); 617 psignal(WTERMSIG(status), argv[0]);
373 } else { 618 } else {
374 handle_initial_delay(); 619 enable_counters();
375 while (!done) { 620 while (!done) {
376 nanosleep(&ts, NULL); 621 nanosleep(&ts, NULL);
377 if (interval) 622 if (interval)
@@ -810,8 +1055,8 @@ static void print_header(int argc, const char **argv)
810 else if (target.cpu_list) 1055 else if (target.cpu_list)
811 fprintf(output, "\'CPU(s) %s", target.cpu_list); 1056 fprintf(output, "\'CPU(s) %s", target.cpu_list);
812 else if (!target__has_task(&target)) { 1057 else if (!target__has_task(&target)) {
813 fprintf(output, "\'%s", argv[0]); 1058 fprintf(output, "\'%s", argv ? argv[0] : "pipe");
814 for (i = 1; i < argc; i++) 1059 for (i = 1; argv && (i < argc); i++)
815 fprintf(output, " %s", argv[i]); 1060 fprintf(output, " %s", argv[i]);
816 } else if (target.pid) 1061 } else if (target.pid)
817 fprintf(output, "process id \'%s", target.pid); 1062 fprintf(output, "process id \'%s", target.pid);
@@ -847,6 +1092,10 @@ static void print_counters(struct timespec *ts, int argc, const char **argv)
847 struct perf_evsel *counter; 1092 struct perf_evsel *counter;
848 char buf[64], *prefix = NULL; 1093 char buf[64], *prefix = NULL;
849 1094
1095 /* Do not print anything if we record to the pipe. */
1096 if (STAT_RECORD && perf_stat.file.is_pipe)
1097 return;
1098
850 if (interval) 1099 if (interval)
851 print_interval(prefix = buf, ts); 1100 print_interval(prefix = buf, ts);
852 else 1101 else
@@ -1077,6 +1326,109 @@ static int perf_stat_init_aggr_mode(void)
1077 return cpus_aggr_map ? 0 : -ENOMEM; 1326 return cpus_aggr_map ? 0 : -ENOMEM;
1078} 1327}
1079 1328
1329static void perf_stat__exit_aggr_mode(void)
1330{
1331 cpu_map__put(aggr_map);
1332 cpu_map__put(cpus_aggr_map);
1333 aggr_map = NULL;
1334 cpus_aggr_map = NULL;
1335}
1336
1337static inline int perf_env__get_cpu(struct perf_env *env, struct cpu_map *map, int idx)
1338{
1339 int cpu;
1340
1341 if (idx > map->nr)
1342 return -1;
1343
1344 cpu = map->map[idx];
1345
1346 if (cpu >= env->nr_cpus_online)
1347 return -1;
1348
1349 return cpu;
1350}
1351
1352static int perf_env__get_socket(struct cpu_map *map, int idx, void *data)
1353{
1354 struct perf_env *env = data;
1355 int cpu = perf_env__get_cpu(env, map, idx);
1356
1357 return cpu == -1 ? -1 : env->cpu[cpu].socket_id;
1358}
1359
1360static int perf_env__get_core(struct cpu_map *map, int idx, void *data)
1361{
1362 struct perf_env *env = data;
1363 int core = -1, cpu = perf_env__get_cpu(env, map, idx);
1364
1365 if (cpu != -1) {
1366 int socket_id = env->cpu[cpu].socket_id;
1367
1368 /*
1369 * Encode socket in upper 16 bits
1370 * core_id is relative to socket, and
1371 * we need a global id. So we combine
1372 * socket + core id.
1373 */
1374 core = (socket_id << 16) | (env->cpu[cpu].core_id & 0xffff);
1375 }
1376
1377 return core;
1378}
1379
1380static int perf_env__build_socket_map(struct perf_env *env, struct cpu_map *cpus,
1381 struct cpu_map **sockp)
1382{
1383 return cpu_map__build_map(cpus, sockp, perf_env__get_socket, env);
1384}
1385
1386static int perf_env__build_core_map(struct perf_env *env, struct cpu_map *cpus,
1387 struct cpu_map **corep)
1388{
1389 return cpu_map__build_map(cpus, corep, perf_env__get_core, env);
1390}
1391
1392static int perf_stat__get_socket_file(struct cpu_map *map, int idx)
1393{
1394 return perf_env__get_socket(map, idx, &perf_stat.session->header.env);
1395}
1396
1397static int perf_stat__get_core_file(struct cpu_map *map, int idx)
1398{
1399 return perf_env__get_core(map, idx, &perf_stat.session->header.env);
1400}
1401
1402static int perf_stat_init_aggr_mode_file(struct perf_stat *st)
1403{
1404 struct perf_env *env = &st->session->header.env;
1405
1406 switch (stat_config.aggr_mode) {
1407 case AGGR_SOCKET:
1408 if (perf_env__build_socket_map(env, evsel_list->cpus, &aggr_map)) {
1409 perror("cannot build socket map");
1410 return -1;
1411 }
1412 aggr_get_id = perf_stat__get_socket_file;
1413 break;
1414 case AGGR_CORE:
1415 if (perf_env__build_core_map(env, evsel_list->cpus, &aggr_map)) {
1416 perror("cannot build core map");
1417 return -1;
1418 }
1419 aggr_get_id = perf_stat__get_core_file;
1420 break;
1421 case AGGR_NONE:
1422 case AGGR_GLOBAL:
1423 case AGGR_THREAD:
1424 case AGGR_UNSET:
1425 default:
1426 break;
1427 }
1428
1429 return 0;
1430}
1431
1080/* 1432/*
1081 * Add default attributes, if there were no attributes specified or 1433 * Add default attributes, if there were no attributes specified or
1082 * if -d/--detailed, -d -d or -d -d -d is used: 1434 * if -d/--detailed, -d -d or -d -d -d is used:
@@ -1236,6 +1588,225 @@ static int add_default_attributes(void)
1236 return perf_evlist__add_default_attrs(evsel_list, very_very_detailed_attrs); 1588 return perf_evlist__add_default_attrs(evsel_list, very_very_detailed_attrs);
1237} 1589}
1238 1590
1591static const char * const stat_record_usage[] = {
1592 "perf stat record [<options>]",
1593 NULL,
1594};
1595
1596static void init_features(struct perf_session *session)
1597{
1598 int feat;
1599
1600 for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
1601 perf_header__set_feat(&session->header, feat);
1602
1603 perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
1604 perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
1605 perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
1606 perf_header__clear_feat(&session->header, HEADER_AUXTRACE);
1607}
1608
1609static int __cmd_record(int argc, const char **argv)
1610{
1611 struct perf_session *session;
1612 struct perf_data_file *file = &perf_stat.file;
1613
1614 argc = parse_options(argc, argv, stat_options, stat_record_usage,
1615 PARSE_OPT_STOP_AT_NON_OPTION);
1616
1617 if (output_name)
1618 file->path = output_name;
1619
1620 if (run_count != 1 || forever) {
1621 pr_err("Cannot use -r option with perf stat record.\n");
1622 return -1;
1623 }
1624
1625 session = perf_session__new(file, false, NULL);
1626 if (session == NULL) {
1627 pr_err("Perf session creation failed.\n");
1628 return -1;
1629 }
1630
1631 init_features(session);
1632
1633 session->evlist = evsel_list;
1634 perf_stat.session = session;
1635 perf_stat.record = true;
1636 return argc;
1637}
1638
1639static int process_stat_round_event(struct perf_tool *tool __maybe_unused,
1640 union perf_event *event,
1641 struct perf_session *session)
1642{
1643 struct stat_round_event *round = &event->stat_round;
1644 struct perf_evsel *counter;
1645 struct timespec tsh, *ts = NULL;
1646 const char **argv = session->header.env.cmdline_argv;
1647 int argc = session->header.env.nr_cmdline;
1648
1649 evlist__for_each(evsel_list, counter)
1650 perf_stat_process_counter(&stat_config, counter);
1651
1652 if (round->type == PERF_STAT_ROUND_TYPE__FINAL)
1653 update_stats(&walltime_nsecs_stats, round->time);
1654
1655 if (stat_config.interval && round->time) {
1656 tsh.tv_sec = round->time / NSECS_PER_SEC;
1657 tsh.tv_nsec = round->time % NSECS_PER_SEC;
1658 ts = &tsh;
1659 }
1660
1661 print_counters(ts, argc, argv);
1662 return 0;
1663}
1664
1665static
1666int process_stat_config_event(struct perf_tool *tool __maybe_unused,
1667 union perf_event *event,
1668 struct perf_session *session __maybe_unused)
1669{
1670 struct perf_stat *st = container_of(tool, struct perf_stat, tool);
1671
1672 perf_event__read_stat_config(&stat_config, &event->stat_config);
1673
1674 if (cpu_map__empty(st->cpus)) {
1675 if (st->aggr_mode != AGGR_UNSET)
1676 pr_warning("warning: processing task data, aggregation mode not set\n");
1677 return 0;
1678 }
1679
1680 if (st->aggr_mode != AGGR_UNSET)
1681 stat_config.aggr_mode = st->aggr_mode;
1682
1683 if (perf_stat.file.is_pipe)
1684 perf_stat_init_aggr_mode();
1685 else
1686 perf_stat_init_aggr_mode_file(st);
1687
1688 return 0;
1689}
1690
1691static int set_maps(struct perf_stat *st)
1692{
1693 if (!st->cpus || !st->threads)
1694 return 0;
1695
1696 if (WARN_ONCE(st->maps_allocated, "stats double allocation\n"))
1697 return -EINVAL;
1698
1699 perf_evlist__set_maps(evsel_list, st->cpus, st->threads);
1700
1701 if (perf_evlist__alloc_stats(evsel_list, true))
1702 return -ENOMEM;
1703
1704 st->maps_allocated = true;
1705 return 0;
1706}
1707
1708static
1709int process_thread_map_event(struct perf_tool *tool __maybe_unused,
1710 union perf_event *event,
1711 struct perf_session *session __maybe_unused)
1712{
1713 struct perf_stat *st = container_of(tool, struct perf_stat, tool);
1714
1715 if (st->threads) {
1716 pr_warning("Extra thread map event, ignoring.\n");
1717 return 0;
1718 }
1719
1720 st->threads = thread_map__new_event(&event->thread_map);
1721 if (!st->threads)
1722 return -ENOMEM;
1723
1724 return set_maps(st);
1725}
1726
1727static
1728int process_cpu_map_event(struct perf_tool *tool __maybe_unused,
1729 union perf_event *event,
1730 struct perf_session *session __maybe_unused)
1731{
1732 struct perf_stat *st = container_of(tool, struct perf_stat, tool);
1733 struct cpu_map *cpus;
1734
1735 if (st->cpus) {
1736 pr_warning("Extra cpu map event, ignoring.\n");
1737 return 0;
1738 }
1739
1740 cpus = cpu_map__new_data(&event->cpu_map.data);
1741 if (!cpus)
1742 return -ENOMEM;
1743
1744 st->cpus = cpus;
1745 return set_maps(st);
1746}
1747
1748static const char * const stat_report_usage[] = {
1749 "perf stat report [<options>]",
1750 NULL,
1751};
1752
1753static struct perf_stat perf_stat = {
1754 .tool = {
1755 .attr = perf_event__process_attr,
1756 .event_update = perf_event__process_event_update,
1757 .thread_map = process_thread_map_event,
1758 .cpu_map = process_cpu_map_event,
1759 .stat_config = process_stat_config_event,
1760 .stat = perf_event__process_stat_event,
1761 .stat_round = process_stat_round_event,
1762 },
1763 .aggr_mode = AGGR_UNSET,
1764};
1765
1766static int __cmd_report(int argc, const char **argv)
1767{
1768 struct perf_session *session;
1769 const struct option options[] = {
1770 OPT_STRING('i', "input", &input_name, "file", "input file name"),
1771 OPT_SET_UINT(0, "per-socket", &perf_stat.aggr_mode,
1772 "aggregate counts per processor socket", AGGR_SOCKET),
1773 OPT_SET_UINT(0, "per-core", &perf_stat.aggr_mode,
1774 "aggregate counts per physical processor core", AGGR_CORE),
1775 OPT_SET_UINT('A', "no-aggr", &perf_stat.aggr_mode,
1776 "disable CPU count aggregation", AGGR_NONE),
1777 OPT_END()
1778 };
1779 struct stat st;
1780 int ret;
1781
1782 argc = parse_options(argc, argv, options, stat_report_usage, 0);
1783
1784 if (!input_name || !strlen(input_name)) {
1785 if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode))
1786 input_name = "-";
1787 else
1788 input_name = "perf.data";
1789 }
1790
1791 perf_stat.file.path = input_name;
1792 perf_stat.file.mode = PERF_DATA_MODE_READ;
1793
1794 session = perf_session__new(&perf_stat.file, false, &perf_stat.tool);
1795 if (session == NULL)
1796 return -1;
1797
1798 perf_stat.session = session;
1799 stat_config.output = stderr;
1800 evsel_list = session->evlist;
1801
1802 ret = perf_session__process_events(session);
1803 if (ret)
1804 return ret;
1805
1806 perf_session__delete(session);
1807 return 0;
1808}
1809
1239int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) 1810int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1240{ 1811{
1241 const char * const stat_usage[] = { 1812 const char * const stat_usage[] = {
@@ -1246,6 +1817,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1246 const char *mode; 1817 const char *mode;
1247 FILE *output = stderr; 1818 FILE *output = stderr;
1248 unsigned int interval; 1819 unsigned int interval;
1820 const char * const stat_subcommands[] = { "record", "report" };
1249 1821
1250 setlocale(LC_ALL, ""); 1822 setlocale(LC_ALL, "");
1251 1823
@@ -1253,12 +1825,30 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1253 if (evsel_list == NULL) 1825 if (evsel_list == NULL)
1254 return -ENOMEM; 1826 return -ENOMEM;
1255 1827
1256 argc = parse_options(argc, argv, stat_options, stat_usage, 1828 argc = parse_options_subcommand(argc, argv, stat_options, stat_subcommands,
1257 PARSE_OPT_STOP_AT_NON_OPTION); 1829 (const char **) stat_usage,
1830 PARSE_OPT_STOP_AT_NON_OPTION);
1831
1832 if (csv_sep) {
1833 csv_output = true;
1834 if (!strcmp(csv_sep, "\\t"))
1835 csv_sep = "\t";
1836 } else
1837 csv_sep = DEFAULT_SEPARATOR;
1838
1839 if (argc && !strncmp(argv[0], "rec", 3)) {
1840 argc = __cmd_record(argc, argv);
1841 if (argc < 0)
1842 return -1;
1843 } else if (argc && !strncmp(argv[0], "rep", 3))
1844 return __cmd_report(argc, argv);
1258 1845
1259 interval = stat_config.interval; 1846 interval = stat_config.interval;
1260 1847
1261 if (output_name && strcmp(output_name, "-")) 1848 /*
1849 * For record command the -o is already taken care of.
1850 */
1851 if (!STAT_RECORD && output_name && strcmp(output_name, "-"))
1262 output = NULL; 1852 output = NULL;
1263 1853
1264 if (output_name && output_fd) { 1854 if (output_name && output_fd) {
@@ -1296,13 +1886,6 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1296 1886
1297 stat_config.output = output; 1887 stat_config.output = output;
1298 1888
1299 if (csv_sep) {
1300 csv_output = true;
1301 if (!strcmp(csv_sep, "\\t"))
1302 csv_sep = "\t";
1303 } else
1304 csv_sep = DEFAULT_SEPARATOR;
1305
1306 /* 1889 /*
1307 * let the spreadsheet do the pretty-printing 1890 * let the spreadsheet do the pretty-printing
1308 */ 1891 */
@@ -1425,6 +2008,42 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1425 if (!forever && status != -1 && !interval) 2008 if (!forever && status != -1 && !interval)
1426 print_counters(NULL, argc, argv); 2009 print_counters(NULL, argc, argv);
1427 2010
2011 if (STAT_RECORD) {
2012 /*
2013 * We synthesize the kernel mmap record just so that older tools
2014 * don't emit warnings about not being able to resolve symbols
2015 * due to /proc/sys/kernel/kptr_restrict settings and instear provide
2016 * a saner message about no samples being in the perf.data file.
2017 *
2018 * This also serves to suppress a warning about f_header.data.size == 0
2019 * in header.c at the moment 'perf stat record' gets introduced, which
2020 * is not really needed once we start adding the stat specific PERF_RECORD_
2021 * records, but the need to suppress the kptr_restrict messages in older
2022 * tools remain -acme
2023 */
2024 int fd = perf_data_file__fd(&perf_stat.file);
2025 int err = perf_event__synthesize_kernel_mmap((void *)&perf_stat,
2026 process_synthesized_event,
2027 &perf_stat.session->machines.host);
2028 if (err) {
2029 pr_warning("Couldn't synthesize the kernel mmap record, harmless, "
2030 "older tools may produce warnings about this file\n.");
2031 }
2032
2033 if (!interval) {
2034 if (WRITE_STAT_ROUND_EVENT(walltime_nsecs_stats.max, FINAL))
2035 pr_err("failed to write stat round event\n");
2036 }
2037
2038 if (!perf_stat.file.is_pipe) {
2039 perf_stat.session->header.data_size += perf_stat.bytes_written;
2040 perf_session__write_header(perf_stat.session, evsel_list, fd, true);
2041 }
2042
2043 perf_session__delete(perf_stat.session);
2044 }
2045
2046 perf_stat__exit_aggr_mode();
1428 perf_evlist__free_stats(evsel_list); 2047 perf_evlist__free_stats(evsel_list);
1429out: 2048out:
1430 perf_evlist__delete(evsel_list); 2049 perf_evlist__delete(evsel_list);
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 30e59620179d..bd7a7757176f 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -30,7 +30,7 @@
30 30
31#include "perf.h" 31#include "perf.h"
32#include "util/header.h" 32#include "util/header.h"
33#include "util/parse-options.h" 33#include <subcmd/parse-options.h>
34#include "util/parse-events.h" 34#include "util/parse-events.h"
35#include "util/event.h" 35#include "util/event.h"
36#include "util/session.h" 36#include "util/session.h"
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 7e2e72e6d9d1..bf01cbb0ef23 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -34,7 +34,7 @@
34#include "util/top.h" 34#include "util/top.h"
35#include "util/util.h" 35#include "util/util.h"
36#include <linux/rbtree.h> 36#include <linux/rbtree.h>
37#include "util/parse-options.h" 37#include <subcmd/parse-options.h>
38#include "util/parse-events.h" 38#include "util/parse-events.h"
39#include "util/cpumap.h" 39#include "util/cpumap.h"
40#include "util/xyarray.h" 40#include "util/xyarray.h"
@@ -175,42 +175,40 @@ static void perf_top__record_precise_ip(struct perf_top *top,
175 int counter, u64 ip) 175 int counter, u64 ip)
176{ 176{
177 struct annotation *notes; 177 struct annotation *notes;
178 struct symbol *sym; 178 struct symbol *sym = he->ms.sym;
179 int err = 0; 179 int err = 0;
180 180
181 if (he == NULL || he->ms.sym == NULL || 181 if (sym == NULL || (use_browser == 0 &&
182 ((top->sym_filter_entry == NULL || 182 (top->sym_filter_entry == NULL ||
183 top->sym_filter_entry->ms.sym != he->ms.sym) && use_browser != 1)) 183 top->sym_filter_entry->ms.sym != sym)))
184 return; 184 return;
185 185
186 sym = he->ms.sym;
187 notes = symbol__annotation(sym); 186 notes = symbol__annotation(sym);
188 187
189 if (pthread_mutex_trylock(&notes->lock)) 188 if (pthread_mutex_trylock(&notes->lock))
190 return; 189 return;
191 190
192 ip = he->ms.map->map_ip(he->ms.map, ip); 191 err = hist_entry__inc_addr_samples(he, counter, ip);
193
194 if (ui__has_annotation())
195 err = hist_entry__inc_addr_samples(he, counter, ip);
196 192
197 pthread_mutex_unlock(&notes->lock); 193 pthread_mutex_unlock(&notes->lock);
198 194
199 /* 195 if (unlikely(err)) {
200 * This function is now called with he->hists->lock held. 196 /*
201 * Release it before going to sleep. 197 * This function is now called with he->hists->lock held.
202 */ 198 * Release it before going to sleep.
203 pthread_mutex_unlock(&he->hists->lock); 199 */
200 pthread_mutex_unlock(&he->hists->lock);
201
202 if (err == -ERANGE && !he->ms.map->erange_warned)
203 ui__warn_map_erange(he->ms.map, sym, ip);
204 else if (err == -ENOMEM) {
205 pr_err("Not enough memory for annotating '%s' symbol!\n",
206 sym->name);
207 sleep(1);
208 }
204 209
205 if (err == -ERANGE && !he->ms.map->erange_warned) 210 pthread_mutex_lock(&he->hists->lock);
206 ui__warn_map_erange(he->ms.map, sym, ip);
207 else if (err == -ENOMEM) {
208 pr_err("Not enough memory for annotating '%s' symbol!\n",
209 sym->name);
210 sleep(1);
211 } 211 }
212
213 pthread_mutex_lock(&he->hists->lock);
214} 212}
215 213
216static void perf_top__show_details(struct perf_top *top) 214static void perf_top__show_details(struct perf_top *top)
@@ -687,14 +685,8 @@ static int hist_iter__top_callback(struct hist_entry_iter *iter,
687 struct hist_entry *he = iter->he; 685 struct hist_entry *he = iter->he;
688 struct perf_evsel *evsel = iter->evsel; 686 struct perf_evsel *evsel = iter->evsel;
689 687
690 if (sort__has_sym && single) { 688 if (sort__has_sym && single)
691 u64 ip = al->addr; 689 perf_top__record_precise_ip(top, he, evsel->idx, al->addr);
692
693 if (al->map)
694 ip = al->map->unmap_ip(al->map, ip);
695
696 perf_top__record_precise_ip(top, he, evsel->idx, ip);
697 }
698 690
699 hist__account_cycles(iter->sample->branch_stack, al, iter->sample, 691 hist__account_cycles(iter->sample->branch_stack, al, iter->sample,
700 !(top->record_opts.branch_stack & PERF_SAMPLE_BRANCH_ANY)); 692 !(top->record_opts.branch_stack & PERF_SAMPLE_BRANCH_ANY));
@@ -964,7 +956,7 @@ static int __cmd_top(struct perf_top *top)
964 if (ret) 956 if (ret)
965 goto out_delete; 957 goto out_delete;
966 958
967 if (perf_session__register_idle_thread(top->session) == NULL) 959 if (perf_session__register_idle_thread(top->session) < 0)
968 goto out_delete; 960 goto out_delete;
969 961
970 machine__synthesize_threads(&top->session->machines.host, &opts->target, 962 machine__synthesize_threads(&top->session->machines.host, &opts->target,
@@ -1218,6 +1210,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1218 OPT_CALLBACK('j', "branch-filter", &opts->branch_stack, 1210 OPT_CALLBACK('j', "branch-filter", &opts->branch_stack,
1219 "branch filter mask", "branch stack filter modes", 1211 "branch filter mask", "branch stack filter modes",
1220 parse_branch_stack), 1212 parse_branch_stack),
1213 OPT_BOOLEAN(0, "raw-trace", &symbol_conf.raw_trace,
1214 "Show raw trace event output (do not use print fmt or plugins)"),
1221 OPT_END() 1215 OPT_END()
1222 }; 1216 };
1223 const char * const top_usage[] = { 1217 const char * const top_usage[] = {
@@ -1239,11 +1233,17 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1239 if (argc) 1233 if (argc)
1240 usage_with_options(top_usage, options); 1234 usage_with_options(top_usage, options);
1241 1235
1236 if (!top.evlist->nr_entries &&
1237 perf_evlist__add_default(top.evlist) < 0) {
1238 pr_err("Not enough memory for event selector list\n");
1239 goto out_delete_evlist;
1240 }
1241
1242 sort__mode = SORT_MODE__TOP; 1242 sort__mode = SORT_MODE__TOP;
1243 /* display thread wants entries to be collapsed in a different tree */ 1243 /* display thread wants entries to be collapsed in a different tree */
1244 sort__need_collapse = 1; 1244 sort__need_collapse = 1;
1245 1245
1246 if (setup_sorting() < 0) { 1246 if (setup_sorting(top.evlist) < 0) {
1247 if (sort_order) 1247 if (sort_order)
1248 parse_options_usage(top_usage, options, "s", 1); 1248 parse_options_usage(top_usage, options, "s", 1);
1249 if (field_order) 1249 if (field_order)
@@ -1279,12 +1279,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1279 if (target__none(target)) 1279 if (target__none(target))
1280 target->system_wide = true; 1280 target->system_wide = true;
1281 1281
1282 if (perf_evlist__create_maps(top.evlist, target) < 0) 1282 if (perf_evlist__create_maps(top.evlist, target) < 0) {
1283 usage_with_options(top_usage, options); 1283 ui__error("Couldn't create thread/CPU maps: %s\n",
1284 1284 errno == ENOENT ? "No such process" : strerror_r(errno, errbuf, sizeof(errbuf)));
1285 if (!top.evlist->nr_entries &&
1286 perf_evlist__add_default(top.evlist) < 0) {
1287 ui__error("Not enough memory for event selector list\n");
1288 goto out_delete_evlist; 1285 goto out_delete_evlist;
1289 } 1286 }
1290 1287
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index c783d8fd3a80..20916dd77aac 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -22,11 +22,11 @@
22#include "util/color.h" 22#include "util/color.h"
23#include "util/debug.h" 23#include "util/debug.h"
24#include "util/evlist.h" 24#include "util/evlist.h"
25#include "util/exec_cmd.h" 25#include <subcmd/exec-cmd.h>
26#include "util/machine.h" 26#include "util/machine.h"
27#include "util/session.h" 27#include "util/session.h"
28#include "util/thread.h" 28#include "util/thread.h"
29#include "util/parse-options.h" 29#include <subcmd/parse-options.h>
30#include "util/strlist.h" 30#include "util/strlist.h"
31#include "util/intlist.h" 31#include "util/intlist.h"
32#include "util/thread_map.h" 32#include "util/thread_map.h"
diff --git a/tools/perf/builtin-version.c b/tools/perf/builtin-version.c
new file mode 100644
index 000000000000..9b10cda6b6dc
--- /dev/null
+++ b/tools/perf/builtin-version.c
@@ -0,0 +1,10 @@
1#include "util/util.h"
2#include "builtin.h"
3#include "perf.h"
4
5int cmd_version(int argc __maybe_unused, const char **argv __maybe_unused,
6 const char *prefix __maybe_unused)
7{
8 printf("perf version %s\n", perf_version_string);
9 return 0;
10}
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h
index 3688ad29085f..3f871b54e261 100644
--- a/tools/perf/builtin.h
+++ b/tools/perf/builtin.h
@@ -17,6 +17,7 @@ extern int cmd_annotate(int argc, const char **argv, const char *prefix);
17extern int cmd_bench(int argc, const char **argv, const char *prefix); 17extern int cmd_bench(int argc, const char **argv, const char *prefix);
18extern int cmd_buildid_cache(int argc, const char **argv, const char *prefix); 18extern int cmd_buildid_cache(int argc, const char **argv, const char *prefix);
19extern int cmd_buildid_list(int argc, const char **argv, const char *prefix); 19extern int cmd_buildid_list(int argc, const char **argv, const char *prefix);
20extern int cmd_config(int argc, const char **argv, const char *prefix);
20extern int cmd_diff(int argc, const char **argv, const char *prefix); 21extern int cmd_diff(int argc, const char **argv, const char *prefix);
21extern int cmd_evlist(int argc, const char **argv, const char *prefix); 22extern int cmd_evlist(int argc, const char **argv, const char *prefix);
22extern int cmd_help(int argc, const char **argv, const char *prefix); 23extern int cmd_help(int argc, const char **argv, const char *prefix);
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt
index 00fcaf8a5b8d..ab5cbaa170d0 100644
--- a/tools/perf/command-list.txt
+++ b/tools/perf/command-list.txt
@@ -9,6 +9,7 @@ perf-buildid-cache mainporcelain common
9perf-buildid-list mainporcelain common 9perf-buildid-list mainporcelain common
10perf-data mainporcelain common 10perf-data mainporcelain common
11perf-diff mainporcelain common 11perf-diff mainporcelain common
12perf-config mainporcelain common
12perf-evlist mainporcelain common 13perf-evlist mainporcelain common
13perf-inject mainporcelain common 14perf-inject mainporcelain common
14perf-kmem mainporcelain common 15perf-kmem mainporcelain common
@@ -25,4 +26,4 @@ perf-stat mainporcelain common
25perf-test mainporcelain common 26perf-test mainporcelain common
26perf-timechart mainporcelain common 27perf-timechart mainporcelain common
27perf-top mainporcelain common 28perf-top mainporcelain common
28perf-trace mainporcelain common 29perf-trace mainporcelain audit
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index de89ec574361..511141b102e8 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -17,7 +17,7 @@ detected_var = $(shell echo "$(1)=$($(1))" >> $(OUTPUT).config-detected)
17 17
18CFLAGS := $(EXTRA_CFLAGS) $(EXTRA_WARNINGS) 18CFLAGS := $(EXTRA_CFLAGS) $(EXTRA_WARNINGS)
19 19
20include $(src-perf)/config/Makefile.arch 20include $(srctree)/tools/scripts/Makefile.arch
21 21
22$(call detected_var,ARCH) 22$(call detected_var,ARCH)
23 23
@@ -135,8 +135,6 @@ endif
135 135
136ifeq ($(DEBUG),0) 136ifeq ($(DEBUG),0)
137 CFLAGS += -O6 137 CFLAGS += -O6
138else
139 CFLAGS += $(call cc-option,-Og,-O0)
140endif 138endif
141 139
142ifdef PARSER_DEBUG 140ifdef PARSER_DEBUG
@@ -183,7 +181,11 @@ LDFLAGS += -Wl,-z,noexecstack
183 181
184EXTLIBS = -lpthread -lrt -lm -ldl 182EXTLIBS = -lpthread -lrt -lm -ldl
185 183
184ifeq ($(FEATURES_DUMP),)
186include $(srctree)/tools/build/Makefile.feature 185include $(srctree)/tools/build/Makefile.feature
186else
187include $(FEATURES_DUMP)
188endif
187 189
188ifeq ($(feature-stackprotector-all), 1) 190ifeq ($(feature-stackprotector-all), 1)
189 CFLAGS += -fstack-protector-all 191 CFLAGS += -fstack-protector-all
@@ -318,6 +320,18 @@ ifndef NO_LIBELF
318 CFLAGS += -DHAVE_LIBBPF_SUPPORT 320 CFLAGS += -DHAVE_LIBBPF_SUPPORT
319 $(call detected,CONFIG_LIBBPF) 321 $(call detected,CONFIG_LIBBPF)
320 endif 322 endif
323
324 ifndef NO_DWARF
325 ifdef PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET
326 CFLAGS += -DHAVE_BPF_PROLOGUE
327 $(call detected,CONFIG_BPF_PROLOGUE)
328 else
329 msg := $(warning BPF prologue is not supported by architecture $(ARCH), missing regs_query_register_offset());
330 endif
331 else
332 msg := $(warning DWARF support is off, BPF prologue is disabled);
333 endif
334
321 endif # NO_LIBBPF 335 endif # NO_LIBBPF
322endif # NO_LIBELF 336endif # NO_LIBELF
323 337
@@ -483,7 +497,7 @@ else
483 497
484 PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null) 498 PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null)
485 PYTHON_EMBED_LDFLAGS := $(call strip-libs,$(PYTHON_EMBED_LDOPTS)) 499 PYTHON_EMBED_LDFLAGS := $(call strip-libs,$(PYTHON_EMBED_LDOPTS))
486 PYTHON_EMBED_LIBADD := $(call grep-libs,$(PYTHON_EMBED_LDOPTS)) 500 PYTHON_EMBED_LIBADD := $(call grep-libs,$(PYTHON_EMBED_LDOPTS)) -lutil
487 PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null) 501 PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
488 FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS) 502 FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
489 503
@@ -681,6 +695,8 @@ sharedir = $(prefix)/share
681template_dir = share/perf-core/templates 695template_dir = share/perf-core/templates
682STRACE_GROUPS_DIR = share/perf-core/strace/groups 696STRACE_GROUPS_DIR = share/perf-core/strace/groups
683htmldir = share/doc/perf-doc 697htmldir = share/doc/perf-doc
698tipdir = share/doc/perf-tip
699srcdir = $(srctree)/tools/perf
684ifeq ($(prefix),/usr) 700ifeq ($(prefix),/usr)
685sysconfdir = /etc 701sysconfdir = /etc
686ETC_PERFCONFIG = $(sysconfdir)/perfconfig 702ETC_PERFCONFIG = $(sysconfdir)/perfconfig
@@ -707,19 +723,24 @@ infodir_SQ = $(subst ','\'',$(infodir))
707perfexecdir_SQ = $(subst ','\'',$(perfexecdir)) 723perfexecdir_SQ = $(subst ','\'',$(perfexecdir))
708template_dir_SQ = $(subst ','\'',$(template_dir)) 724template_dir_SQ = $(subst ','\'',$(template_dir))
709htmldir_SQ = $(subst ','\'',$(htmldir)) 725htmldir_SQ = $(subst ','\'',$(htmldir))
726tipdir_SQ = $(subst ','\'',$(tipdir))
710prefix_SQ = $(subst ','\'',$(prefix)) 727prefix_SQ = $(subst ','\'',$(prefix))
711sysconfdir_SQ = $(subst ','\'',$(sysconfdir)) 728sysconfdir_SQ = $(subst ','\'',$(sysconfdir))
712libdir_SQ = $(subst ','\'',$(libdir)) 729libdir_SQ = $(subst ','\'',$(libdir))
730srcdir_SQ = $(subst ','\'',$(srcdir))
713 731
714ifneq ($(filter /%,$(firstword $(perfexecdir))),) 732ifneq ($(filter /%,$(firstword $(perfexecdir))),)
715perfexec_instdir = $(perfexecdir) 733perfexec_instdir = $(perfexecdir)
716STRACE_GROUPS_INSTDIR = $(STRACE_GROUPS_DIR) 734STRACE_GROUPS_INSTDIR = $(STRACE_GROUPS_DIR)
735tip_instdir = $(tipdir)
717else 736else
718perfexec_instdir = $(prefix)/$(perfexecdir) 737perfexec_instdir = $(prefix)/$(perfexecdir)
719STRACE_GROUPS_INSTDIR = $(prefix)/$(STRACE_GROUPS_DIR) 738STRACE_GROUPS_INSTDIR = $(prefix)/$(STRACE_GROUPS_DIR)
739tip_instdir = $(prefix)/$(tipdir)
720endif 740endif
721perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir)) 741perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir))
722STRACE_GROUPS_INSTDIR_SQ = $(subst ','\'',$(STRACE_GROUPS_INSTDIR)) 742STRACE_GROUPS_INSTDIR_SQ = $(subst ','\'',$(STRACE_GROUPS_INSTDIR))
743tip_instdir_SQ = $(subst ','\'',$(tip_instdir))
723 744
724# If we install to $(HOME) we keep the traceevent default: 745# If we install to $(HOME) we keep the traceevent default:
725# $(HOME)/.traceevent/plugins 746# $(HOME)/.traceevent/plugins
@@ -741,6 +762,10 @@ ifeq ($(VF),1)
741 $(call print_var,sysconfdir) 762 $(call print_var,sysconfdir)
742 $(call print_var,LIBUNWIND_DIR) 763 $(call print_var,LIBUNWIND_DIR)
743 $(call print_var,LIBDW_DIR) 764 $(call print_var,LIBDW_DIR)
765
766 ifeq ($(dwarf-post-unwind),1)
767 $(call feature_print_text,"DWARF post unwind library", $(dwarf-post-unwind-text))
768 endif
744 $(info ) 769 $(info )
745endif 770endif
746 771
@@ -756,6 +781,8 @@ $(call detected_var,ETC_PERFCONFIG_SQ)
756$(call detected_var,STRACE_GROUPS_DIR_SQ) 781$(call detected_var,STRACE_GROUPS_DIR_SQ)
757$(call detected_var,prefix_SQ) 782$(call detected_var,prefix_SQ)
758$(call detected_var,perfexecdir_SQ) 783$(call detected_var,perfexecdir_SQ)
784$(call detected_var,tipdir_SQ)
785$(call detected_var,srcdir_SQ)
759$(call detected_var,LIBDIR) 786$(call detected_var,LIBDIR)
760$(call detected_var,GTK_CFLAGS) 787$(call detected_var,GTK_CFLAGS)
761$(call detected_var,PERL_EMBED_CCOPTS) 788$(call detected_var,PERL_EMBED_CCOPTS)
diff --git a/tools/perf/config/utilities.mak b/tools/perf/config/utilities.mak
index 0ebef09c0842..c16ce833079c 100644
--- a/tools/perf/config/utilities.mak
+++ b/tools/perf/config/utilities.mak
@@ -177,22 +177,3 @@ $(if $($(1)),$(call _ge_attempt,$($(1)),$(1)),$(call _ge_attempt,$(2)))
177endef 177endef
178_ge_attempt = $(if $(get-executable),$(get-executable),$(call _gea_err,$(2))) 178_ge_attempt = $(if $(get-executable),$(get-executable),$(call _gea_err,$(2)))
179_gea_err = $(if $(1),$(error Please set '$(1)' appropriately)) 179_gea_err = $(if $(1),$(error Please set '$(1)' appropriately))
180
181# try-run
182# Usage: option = $(call try-run, $(CC)...-o "$$TMP",option-ok,otherwise)
183# Exit code chooses option. "$$TMP" is can be used as temporary file and
184# is automatically cleaned up.
185try-run = $(shell set -e; \
186 TMP="$(TMPOUT).$$$$.tmp"; \
187 TMPO="$(TMPOUT).$$$$.o"; \
188 if ($(1)) >/dev/null 2>&1; \
189 then echo "$(2)"; \
190 else echo "$(3)"; \
191 fi; \
192 rm -f "$$TMP" "$$TMPO")
193
194# cc-option
195# Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586)
196
197cc-option = $(call try-run,\
198 $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -x c /dev/null -o "$$TMP",$(1),$(2))
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 3d4c7c09adea..a929618b8eb6 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -9,16 +9,18 @@
9#include "builtin.h" 9#include "builtin.h"
10 10
11#include "util/env.h" 11#include "util/env.h"
12#include "util/exec_cmd.h" 12#include <subcmd/exec-cmd.h>
13#include "util/cache.h" 13#include "util/cache.h"
14#include "util/quote.h" 14#include "util/quote.h"
15#include "util/run-command.h" 15#include <subcmd/run-command.h>
16#include "util/parse-events.h" 16#include "util/parse-events.h"
17#include "util/parse-options.h" 17#include <subcmd/parse-options.h>
18#include "util/bpf-loader.h" 18#include "util/bpf-loader.h"
19#include "util/debug.h" 19#include "util/debug.h"
20#include <api/fs/tracing_path.h> 20#include <api/fs/tracing_path.h>
21#include <pthread.h> 21#include <pthread.h>
22#include <stdlib.h>
23#include <time.h>
22 24
23const char perf_usage_string[] = 25const char perf_usage_string[] =
24 "perf [--version] [--help] [OPTIONS] COMMAND [ARGS]"; 26 "perf [--version] [--help] [OPTIONS] COMMAND [ARGS]";
@@ -39,6 +41,7 @@ struct cmd_struct {
39static struct cmd_struct commands[] = { 41static struct cmd_struct commands[] = {
40 { "buildid-cache", cmd_buildid_cache, 0 }, 42 { "buildid-cache", cmd_buildid_cache, 0 },
41 { "buildid-list", cmd_buildid_list, 0 }, 43 { "buildid-list", cmd_buildid_list, 0 },
44 { "config", cmd_config, 0 },
42 { "diff", cmd_diff, 0 }, 45 { "diff", cmd_diff, 0 },
43 { "evlist", cmd_evlist, 0 }, 46 { "evlist", cmd_evlist, 0 },
44 { "help", cmd_help, 0 }, 47 { "help", cmd_help, 0 },
@@ -118,7 +121,7 @@ static void commit_pager_choice(void)
118{ 121{
119 switch (use_pager) { 122 switch (use_pager) {
120 case 0: 123 case 0:
121 setenv("PERF_PAGER", "cat", 1); 124 setenv(PERF_PAGER_ENVIRONMENT, "cat", 1);
122 break; 125 break;
123 case 1: 126 case 1:
124 /* setup_pager(); */ 127 /* setup_pager(); */
@@ -182,9 +185,9 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
182 if (!prefixcmp(cmd, CMD_EXEC_PATH)) { 185 if (!prefixcmp(cmd, CMD_EXEC_PATH)) {
183 cmd += strlen(CMD_EXEC_PATH); 186 cmd += strlen(CMD_EXEC_PATH);
184 if (*cmd == '=') 187 if (*cmd == '=')
185 perf_set_argv_exec_path(cmd + 1); 188 set_argv_exec_path(cmd + 1);
186 else { 189 else {
187 puts(perf_exec_path()); 190 puts(get_argv_exec_path());
188 exit(0); 191 exit(0);
189 } 192 }
190 } else if (!strcmp(cmd, "--html-path")) { 193 } else if (!strcmp(cmd, "--html-path")) {
@@ -383,6 +386,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
383 use_pager = 1; 386 use_pager = 1;
384 commit_pager_choice(); 387 commit_pager_choice();
385 388
389 perf_env__set_cmdline(&perf_env, argc, argv);
386 status = p->fn(argc, argv, prefix); 390 status = p->fn(argc, argv, prefix);
387 exit_browser(status); 391 exit_browser(status);
388 perf_env__exit(&perf_env); 392 perf_env__exit(&perf_env);
@@ -528,14 +532,20 @@ int main(int argc, const char **argv)
528 const char *cmd; 532 const char *cmd;
529 char sbuf[STRERR_BUFSIZE]; 533 char sbuf[STRERR_BUFSIZE];
530 534
535 /* libsubcmd init */
536 exec_cmd_init("perf", PREFIX, PERF_EXEC_PATH, EXEC_PATH_ENVIRONMENT);
537 pager_init(PERF_PAGER_ENVIRONMENT);
538
531 /* The page_size is placed in util object. */ 539 /* The page_size is placed in util object. */
532 page_size = sysconf(_SC_PAGE_SIZE); 540 page_size = sysconf(_SC_PAGE_SIZE);
533 cacheline_size = sysconf(_SC_LEVEL1_DCACHE_LINESIZE); 541 cacheline_size = sysconf(_SC_LEVEL1_DCACHE_LINESIZE);
534 542
535 cmd = perf_extract_argv0_path(argv[0]); 543 cmd = extract_argv0_path(argv[0]);
536 if (!cmd) 544 if (!cmd)
537 cmd = "perf-help"; 545 cmd = "perf-help";
538 546
547 srandom(time(NULL));
548
539 /* get debugfs/tracefs mount point from /proc/mounts */ 549 /* get debugfs/tracefs mount point from /proc/mounts */
540 tracing_path_mount(); 550 tracing_path_mount();
541 551
diff --git a/tools/perf/scripts/python/stat-cpi.py b/tools/perf/scripts/python/stat-cpi.py
new file mode 100644
index 000000000000..8b60f343dd07
--- /dev/null
+++ b/tools/perf/scripts/python/stat-cpi.py
@@ -0,0 +1,77 @@
1#!/usr/bin/env python
2
3data = {}
4times = []
5threads = []
6cpus = []
7
8def get_key(time, event, cpu, thread):
9 return "%d-%s-%d-%d" % (time, event, cpu, thread)
10
11def store_key(time, cpu, thread):
12 if (time not in times):
13 times.append(time)
14
15 if (cpu not in cpus):
16 cpus.append(cpu)
17
18 if (thread not in threads):
19 threads.append(thread)
20
21def store(time, event, cpu, thread, val, ena, run):
22 #print "event %s cpu %d, thread %d, time %d, val %d, ena %d, run %d" % \
23 # (event, cpu, thread, time, val, ena, run)
24
25 store_key(time, cpu, thread)
26 key = get_key(time, event, cpu, thread)
27 data[key] = [ val, ena, run]
28
29def get(time, event, cpu, thread):
30 key = get_key(time, event, cpu, thread)
31 return data[key][0]
32
33def stat__cycles_k(cpu, thread, time, val, ena, run):
34 store(time, "cycles", cpu, thread, val, ena, run);
35
36def stat__instructions_k(cpu, thread, time, val, ena, run):
37 store(time, "instructions", cpu, thread, val, ena, run);
38
39def stat__cycles_u(cpu, thread, time, val, ena, run):
40 store(time, "cycles", cpu, thread, val, ena, run);
41
42def stat__instructions_u(cpu, thread, time, val, ena, run):
43 store(time, "instructions", cpu, thread, val, ena, run);
44
45def stat__cycles(cpu, thread, time, val, ena, run):
46 store(time, "cycles", cpu, thread, val, ena, run);
47
48def stat__instructions(cpu, thread, time, val, ena, run):
49 store(time, "instructions", cpu, thread, val, ena, run);
50
51def stat__interval(time):
52 for cpu in cpus:
53 for thread in threads:
54 cyc = get(time, "cycles", cpu, thread)
55 ins = get(time, "instructions", cpu, thread)
56 cpi = 0
57
58 if ins != 0:
59 cpi = cyc/float(ins)
60
61 print "%15f: cpu %d, thread %d -> cpi %f (%d/%d)" % (time/(float(1000000000)), cpu, thread, cpi, cyc, ins)
62
63def trace_end():
64 pass
65# XXX trace_end callback could be used as an alternative place
66# to compute same values as in the script above:
67#
68# for time in times:
69# for cpu in cpus:
70# for thread in threads:
71# cyc = get(time, "cycles", cpu, thread)
72# ins = get(time, "instructions", cpu, thread)
73#
74# if ins != 0:
75# cpi = cyc/float(ins)
76#
77# print "time %.9f, cpu %d, thread %d -> cpi %f" % (time/(float(1000000000)), cpu, thread, cpi)
diff --git a/tools/perf/tests/.gitignore b/tools/perf/tests/.gitignore
index 489fc9ffbcb0..bf016c439fbd 100644
--- a/tools/perf/tests/.gitignore
+++ b/tools/perf/tests/.gitignore
@@ -1,2 +1,3 @@
1llvm-src-base.c 1llvm-src-base.c
2llvm-src-kbuild.c 2llvm-src-kbuild.c
3llvm-src-prologue.c
diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build
index f41ebf8849fe..614899b88b37 100644
--- a/tools/perf/tests/Build
+++ b/tools/perf/tests/Build
@@ -31,24 +31,34 @@ perf-y += sample-parsing.o
31perf-y += parse-no-sample-id-all.o 31perf-y += parse-no-sample-id-all.o
32perf-y += kmod-path.o 32perf-y += kmod-path.o
33perf-y += thread-map.o 33perf-y += thread-map.o
34perf-y += llvm.o llvm-src-base.o llvm-src-kbuild.o 34perf-y += llvm.o llvm-src-base.o llvm-src-kbuild.o llvm-src-prologue.o
35perf-y += bpf.o 35perf-y += bpf.o
36perf-y += topology.o 36perf-y += topology.o
37perf-y += cpumap.o
38perf-y += stat.o
39perf-y += event_update.o
37 40
38$(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c 41$(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c tests/Build
39 $(call rule_mkdir) 42 $(call rule_mkdir)
40 $(Q)echo '#include <tests/llvm.h>' > $@ 43 $(Q)echo '#include <tests/llvm.h>' > $@
41 $(Q)echo 'const char test_llvm__bpf_base_prog[] =' >> $@ 44 $(Q)echo 'const char test_llvm__bpf_base_prog[] =' >> $@
42 $(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@ 45 $(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@
43 $(Q)echo ';' >> $@ 46 $(Q)echo ';' >> $@
44 47
45$(OUTPUT)tests/llvm-src-kbuild.c: tests/bpf-script-test-kbuild.c 48$(OUTPUT)tests/llvm-src-kbuild.c: tests/bpf-script-test-kbuild.c tests/Build
46 $(call rule_mkdir) 49 $(call rule_mkdir)
47 $(Q)echo '#include <tests/llvm.h>' > $@ 50 $(Q)echo '#include <tests/llvm.h>' > $@
48 $(Q)echo 'const char test_llvm__bpf_test_kbuild_prog[] =' >> $@ 51 $(Q)echo 'const char test_llvm__bpf_test_kbuild_prog[] =' >> $@
49 $(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@ 52 $(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@
50 $(Q)echo ';' >> $@ 53 $(Q)echo ';' >> $@
51 54
55$(OUTPUT)tests/llvm-src-prologue.c: tests/bpf-script-test-prologue.c tests/Build
56 $(call rule_mkdir)
57 $(Q)echo '#include <tests/llvm.h>' > $@
58 $(Q)echo 'const char test_llvm__bpf_test_prologue_prog[] =' >> $@
59 $(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@
60 $(Q)echo ';' >> $@
61
52ifeq ($(ARCH),$(filter $(ARCH),x86 arm arm64)) 62ifeq ($(ARCH),$(filter $(ARCH),x86 arm arm64))
53perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o 63perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o
54endif 64endif
diff --git a/tools/perf/tests/attr.c b/tools/perf/tests/attr.c
index 638875a0960a..28d1605b0338 100644
--- a/tools/perf/tests/attr.c
+++ b/tools/perf/tests/attr.c
@@ -24,7 +24,7 @@
24#include <linux/kernel.h> 24#include <linux/kernel.h>
25#include "../perf.h" 25#include "../perf.h"
26#include "util.h" 26#include "util.h"
27#include "exec_cmd.h" 27#include <subcmd/exec-cmd.h>
28#include "tests.h" 28#include "tests.h"
29 29
30#define ENV "PERF_TEST_ATTR" 30#define ENV "PERF_TEST_ATTR"
@@ -153,7 +153,7 @@ static int run_dir(const char *d, const char *perf)
153 return system(cmd); 153 return system(cmd);
154} 154}
155 155
156int test__attr(void) 156int test__attr(int subtest __maybe_unused)
157{ 157{
158 struct stat st; 158 struct stat st;
159 char path_perf[PATH_MAX]; 159 char path_perf[PATH_MAX];
@@ -164,7 +164,7 @@ int test__attr(void)
164 return run_dir("./tests", "./perf"); 164 return run_dir("./tests", "./perf");
165 165
166 /* Then installed path. */ 166 /* Then installed path. */
167 snprintf(path_dir, PATH_MAX, "%s/tests", perf_exec_path()); 167 snprintf(path_dir, PATH_MAX, "%s/tests", get_argv_exec_path());
168 snprintf(path_perf, PATH_MAX, "%s/perf", BINDIR); 168 snprintf(path_perf, PATH_MAX, "%s/perf", BINDIR);
169 169
170 if (!lstat(path_dir, &st) && 170 if (!lstat(path_dir, &st) &&
diff --git a/tools/perf/tests/bp_signal.c b/tools/perf/tests/bp_signal.c
index a02b035fd5aa..fb80c9eb6a95 100644
--- a/tools/perf/tests/bp_signal.c
+++ b/tools/perf/tests/bp_signal.c
@@ -111,7 +111,7 @@ static long long bp_count(int fd)
111 return count; 111 return count;
112} 112}
113 113
114int test__bp_signal(void) 114int test__bp_signal(int subtest __maybe_unused)
115{ 115{
116 struct sigaction sa; 116 struct sigaction sa;
117 long long count1, count2; 117 long long count1, count2;
diff --git a/tools/perf/tests/bp_signal_overflow.c b/tools/perf/tests/bp_signal_overflow.c
index e76537724491..89f92fa67cc4 100644
--- a/tools/perf/tests/bp_signal_overflow.c
+++ b/tools/perf/tests/bp_signal_overflow.c
@@ -58,7 +58,7 @@ static long long bp_count(int fd)
58#define EXECUTIONS 10000 58#define EXECUTIONS 10000
59#define THRESHOLD 100 59#define THRESHOLD 100
60 60
61int test__bp_signal_overflow(void) 61int test__bp_signal_overflow(int subtest __maybe_unused)
62{ 62{
63 struct perf_event_attr pe; 63 struct perf_event_attr pe;
64 struct sigaction sa; 64 struct sigaction sa;
diff --git a/tools/perf/tests/bpf-script-test-prologue.c b/tools/perf/tests/bpf-script-test-prologue.c
new file mode 100644
index 000000000000..7230e62c70fc
--- /dev/null
+++ b/tools/perf/tests/bpf-script-test-prologue.c
@@ -0,0 +1,35 @@
1/*
2 * bpf-script-test-prologue.c
3 * Test BPF prologue
4 */
5#ifndef LINUX_VERSION_CODE
6# error Need LINUX_VERSION_CODE
7# error Example: for 4.2 kernel, put 'clang-opt="-DLINUX_VERSION_CODE=0x40200" into llvm section of ~/.perfconfig'
8#endif
9#define SEC(NAME) __attribute__((section(NAME), used))
10
11#include <uapi/linux/fs.h>
12
13#define FMODE_READ 0x1
14#define FMODE_WRITE 0x2
15
16static void (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) =
17 (void *) 6;
18
19SEC("func=null_lseek file->f_mode offset orig")
20int bpf_func__null_lseek(void *ctx, int err, unsigned long f_mode,
21 unsigned long offset, unsigned long orig)
22{
23 if (err)
24 return 0;
25 if (f_mode & FMODE_WRITE)
26 return 0;
27 if (offset & 1)
28 return 0;
29 if (orig == SEEK_CUR)
30 return 0;
31 return 1;
32}
33
34char _license[] SEC("license") = "GPL";
35int _version SEC("version") = LINUX_VERSION_CODE;
diff --git a/tools/perf/tests/bpf.c b/tools/perf/tests/bpf.c
index ec16f7812c8b..33689a0cf821 100644
--- a/tools/perf/tests/bpf.c
+++ b/tools/perf/tests/bpf.c
@@ -19,6 +19,29 @@ static int epoll_pwait_loop(void)
19 return 0; 19 return 0;
20} 20}
21 21
22#ifdef HAVE_BPF_PROLOGUE
23
24static int llseek_loop(void)
25{
26 int fds[2], i;
27
28 fds[0] = open("/dev/null", O_RDONLY);
29 fds[1] = open("/dev/null", O_RDWR);
30
31 if (fds[0] < 0 || fds[1] < 0)
32 return -1;
33
34 for (i = 0; i < NR_ITERS; i++) {
35 lseek(fds[i % 2], i, (i / 2) % 2 ? SEEK_CUR : SEEK_SET);
36 lseek(fds[(i + 1) % 2], i, (i / 2) % 2 ? SEEK_CUR : SEEK_SET);
37 }
38 close(fds[0]);
39 close(fds[1]);
40 return 0;
41}
42
43#endif
44
22static struct { 45static struct {
23 enum test_llvm__testcase prog_id; 46 enum test_llvm__testcase prog_id;
24 const char *desc; 47 const char *desc;
@@ -37,6 +60,17 @@ static struct {
37 &epoll_pwait_loop, 60 &epoll_pwait_loop,
38 (NR_ITERS + 1) / 2, 61 (NR_ITERS + 1) / 2,
39 }, 62 },
63#ifdef HAVE_BPF_PROLOGUE
64 {
65 LLVM_TESTCASE_BPF_PROLOGUE,
66 "Test BPF prologue generation",
67 "[bpf_prologue_test]",
68 "fix kbuild first",
69 "check your vmlinux setting?",
70 &llseek_loop,
71 (NR_ITERS + 1) / 4,
72 },
73#endif
40}; 74};
41 75
42static int do_test(struct bpf_object *obj, int (*func)(void), 76static int do_test(struct bpf_object *obj, int (*func)(void),
@@ -68,8 +102,7 @@ static int do_test(struct bpf_object *obj, int (*func)(void),
68 err = parse_events_load_bpf_obj(&parse_evlist, &parse_evlist.list, obj); 102 err = parse_events_load_bpf_obj(&parse_evlist, &parse_evlist.list, obj);
69 if (err || list_empty(&parse_evlist.list)) { 103 if (err || list_empty(&parse_evlist.list)) {
70 pr_debug("Failed to add events selected by BPF\n"); 104 pr_debug("Failed to add events selected by BPF\n");
71 if (!err) 105 return TEST_FAIL;
72 return TEST_FAIL;
73 } 106 }
74 107
75 snprintf(pid, sizeof(pid), "%d", getpid()); 108 snprintf(pid, sizeof(pid), "%d", getpid());
@@ -123,8 +156,10 @@ static int do_test(struct bpf_object *obj, int (*func)(void),
123 } 156 }
124 } 157 }
125 158
126 if (count != expect) 159 if (count != expect) {
127 pr_debug("BPF filter result incorrect\n"); 160 pr_debug("BPF filter result incorrect\n");
161 goto out_delete_evlist;
162 }
128 163
129 ret = TEST_OK; 164 ret = TEST_OK;
130 165
@@ -146,7 +181,7 @@ prepare_bpf(void *obj_buf, size_t obj_buf_sz, const char *name)
146 return obj; 181 return obj;
147} 182}
148 183
149static int __test__bpf(int index) 184static int __test__bpf(int idx)
150{ 185{
151 int ret; 186 int ret;
152 void *obj_buf; 187 void *obj_buf;
@@ -154,54 +189,72 @@ static int __test__bpf(int index)
154 struct bpf_object *obj; 189 struct bpf_object *obj;
155 190
156 ret = test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz, 191 ret = test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz,
157 bpf_testcase_table[index].prog_id, 192 bpf_testcase_table[idx].prog_id,
158 true); 193 true);
159 if (ret != TEST_OK || !obj_buf || !obj_buf_sz) { 194 if (ret != TEST_OK || !obj_buf || !obj_buf_sz) {
160 pr_debug("Unable to get BPF object, %s\n", 195 pr_debug("Unable to get BPF object, %s\n",
161 bpf_testcase_table[index].msg_compile_fail); 196 bpf_testcase_table[idx].msg_compile_fail);
162 if (index == 0) 197 if (idx == 0)
163 return TEST_SKIP; 198 return TEST_SKIP;
164 else 199 else
165 return TEST_FAIL; 200 return TEST_FAIL;
166 } 201 }
167 202
168 obj = prepare_bpf(obj_buf, obj_buf_sz, 203 obj = prepare_bpf(obj_buf, obj_buf_sz,
169 bpf_testcase_table[index].name); 204 bpf_testcase_table[idx].name);
170 if (!obj) { 205 if (!obj) {
171 ret = TEST_FAIL; 206 ret = TEST_FAIL;
172 goto out; 207 goto out;
173 } 208 }
174 209
175 ret = do_test(obj, 210 ret = do_test(obj,
176 bpf_testcase_table[index].target_func, 211 bpf_testcase_table[idx].target_func,
177 bpf_testcase_table[index].expect_result); 212 bpf_testcase_table[idx].expect_result);
178out: 213out:
179 bpf__clear(); 214 bpf__clear();
180 return ret; 215 return ret;
181} 216}
182 217
183int test__bpf(void) 218int test__bpf_subtest_get_nr(void)
219{
220 return (int)ARRAY_SIZE(bpf_testcase_table);
221}
222
223const char *test__bpf_subtest_get_desc(int i)
224{
225 if (i < 0 || i >= (int)ARRAY_SIZE(bpf_testcase_table))
226 return NULL;
227 return bpf_testcase_table[i].desc;
228}
229
230int test__bpf(int i)
184{ 231{
185 unsigned int i;
186 int err; 232 int err;
187 233
234 if (i < 0 || i >= (int)ARRAY_SIZE(bpf_testcase_table))
235 return TEST_FAIL;
236
188 if (geteuid() != 0) { 237 if (geteuid() != 0) {
189 pr_debug("Only root can run BPF test\n"); 238 pr_debug("Only root can run BPF test\n");
190 return TEST_SKIP; 239 return TEST_SKIP;
191 } 240 }
192 241
193 for (i = 0; i < ARRAY_SIZE(bpf_testcase_table); i++) { 242 err = __test__bpf(i);
194 err = __test__bpf(i); 243 return err;
244}
195 245
196 if (err != TEST_OK) 246#else
197 return err; 247int test__bpf_subtest_get_nr(void)
198 } 248{
249 return 0;
250}
199 251
200 return TEST_OK; 252const char *test__bpf_subtest_get_desc(int i __maybe_unused)
253{
254 return NULL;
201} 255}
202 256
203#else 257int test__bpf(int i __maybe_unused)
204int test__bpf(void)
205{ 258{
206 pr_debug("Skip BPF test because BPF support is not compiled\n"); 259 pr_debug("Skip BPF test because BPF support is not compiled\n");
207 return TEST_SKIP; 260 return TEST_SKIP;
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index 80c442eab767..f2b1dcac45d3 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -11,7 +11,7 @@
11#include "tests.h" 11#include "tests.h"
12#include "debug.h" 12#include "debug.h"
13#include "color.h" 13#include "color.h"
14#include "parse-options.h" 14#include <subcmd/parse-options.h>
15#include "symbol.h" 15#include "symbol.h"
16 16
17struct test __weak arch_tests[] = { 17struct test __weak arch_tests[] = {
@@ -160,6 +160,11 @@ static struct test generic_tests[] = {
160 { 160 {
161 .desc = "Test LLVM searching and compiling", 161 .desc = "Test LLVM searching and compiling",
162 .func = test__llvm, 162 .func = test__llvm,
163 .subtest = {
164 .skip_if_fail = true,
165 .get_nr = test__llvm_subtest_get_nr,
166 .get_desc = test__llvm_subtest_get_desc,
167 },
163 }, 168 },
164 { 169 {
165 .desc = "Test topology in session", 170 .desc = "Test topology in session",
@@ -168,6 +173,35 @@ static struct test generic_tests[] = {
168 { 173 {
169 .desc = "Test BPF filter", 174 .desc = "Test BPF filter",
170 .func = test__bpf, 175 .func = test__bpf,
176 .subtest = {
177 .skip_if_fail = true,
178 .get_nr = test__bpf_subtest_get_nr,
179 .get_desc = test__bpf_subtest_get_desc,
180 },
181 },
182 {
183 .desc = "Test thread map synthesize",
184 .func = test__thread_map_synthesize,
185 },
186 {
187 .desc = "Test cpu map synthesize",
188 .func = test__cpu_map_synthesize,
189 },
190 {
191 .desc = "Test stat config synthesize",
192 .func = test__synthesize_stat_config,
193 },
194 {
195 .desc = "Test stat synthesize",
196 .func = test__synthesize_stat,
197 },
198 {
199 .desc = "Test stat round synthesize",
200 .func = test__synthesize_stat_round,
201 },
202 {
203 .desc = "Test attr update synthesize",
204 .func = test__event_update,
171 }, 205 },
172 { 206 {
173 .func = NULL, 207 .func = NULL,
@@ -203,7 +237,7 @@ static bool perf_test__matches(struct test *test, int curr, int argc, const char
203 return false; 237 return false;
204} 238}
205 239
206static int run_test(struct test *test) 240static int run_test(struct test *test, int subtest)
207{ 241{
208 int status, err = -1, child = fork(); 242 int status, err = -1, child = fork();
209 char sbuf[STRERR_BUFSIZE]; 243 char sbuf[STRERR_BUFSIZE];
@@ -216,7 +250,22 @@ static int run_test(struct test *test)
216 250
217 if (!child) { 251 if (!child) {
218 pr_debug("test child forked, pid %d\n", getpid()); 252 pr_debug("test child forked, pid %d\n", getpid());
219 err = test->func(); 253 if (!verbose) {
254 int nullfd = open("/dev/null", O_WRONLY);
255 if (nullfd >= 0) {
256 close(STDERR_FILENO);
257 close(STDOUT_FILENO);
258
259 dup2(nullfd, STDOUT_FILENO);
260 dup2(STDOUT_FILENO, STDERR_FILENO);
261 close(nullfd);
262 }
263 } else {
264 signal(SIGSEGV, sighandler_dump_stack);
265 signal(SIGFPE, sighandler_dump_stack);
266 }
267
268 err = test->func(subtest);
220 exit(err); 269 exit(err);
221 } 270 }
222 271
@@ -237,6 +286,40 @@ static int run_test(struct test *test)
237 for (j = 0; j < ARRAY_SIZE(tests); j++) \ 286 for (j = 0; j < ARRAY_SIZE(tests); j++) \
238 for (t = &tests[j][0]; t->func; t++) 287 for (t = &tests[j][0]; t->func; t++)
239 288
289static int test_and_print(struct test *t, bool force_skip, int subtest)
290{
291 int err;
292
293 if (!force_skip) {
294 pr_debug("\n--- start ---\n");
295 err = run_test(t, subtest);
296 pr_debug("---- end ----\n");
297 } else {
298 pr_debug("\n--- force skipped ---\n");
299 err = TEST_SKIP;
300 }
301
302 if (!t->subtest.get_nr)
303 pr_debug("%s:", t->desc);
304 else
305 pr_debug("%s subtest %d:", t->desc, subtest);
306
307 switch (err) {
308 case TEST_OK:
309 pr_info(" Ok\n");
310 break;
311 case TEST_SKIP:
312 color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip\n");
313 break;
314 case TEST_FAIL:
315 default:
316 color_fprintf(stderr, PERF_COLOR_RED, " FAILED!\n");
317 break;
318 }
319
320 return err;
321}
322
240static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist) 323static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist)
241{ 324{
242 struct test *t; 325 struct test *t;
@@ -264,21 +347,43 @@ static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist)
264 continue; 347 continue;
265 } 348 }
266 349
267 pr_debug("\n--- start ---\n"); 350 if (!t->subtest.get_nr) {
268 err = run_test(t); 351 test_and_print(t, false, -1);
269 pr_debug("---- end ----\n%s:", t->desc); 352 } else {
270 353 int subn = t->subtest.get_nr();
271 switch (err) { 354 /*
272 case TEST_OK: 355 * minus 2 to align with normal testcases.
273 pr_info(" Ok\n"); 356 * For subtest we print additional '.x' in number.
274 break; 357 * for example:
275 case TEST_SKIP: 358 *
276 color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip\n"); 359 * 35: Test LLVM searching and compiling :
277 break; 360 * 35.1: Basic BPF llvm compiling test : Ok
278 case TEST_FAIL: 361 */
279 default: 362 int subw = width > 2 ? width - 2 : width;
280 color_fprintf(stderr, PERF_COLOR_RED, " FAILED!\n"); 363 bool skip = false;
281 break; 364 int subi;
365
366 if (subn <= 0) {
367 color_fprintf(stderr, PERF_COLOR_YELLOW,
368 " Skip (not compiled in)\n");
369 continue;
370 }
371 pr_info("\n");
372
373 for (subi = 0; subi < subn; subi++) {
374 int len = strlen(t->subtest.get_desc(subi));
375
376 if (subw < len)
377 subw = len;
378 }
379
380 for (subi = 0; subi < subn; subi++) {
381 pr_info("%2d.%1d: %-*s:", i, subi + 1, subw,
382 t->subtest.get_desc(subi));
383 err = test_and_print(t, skip, subi);
384 if (err != TEST_OK && t->subtest.skip_if_fail)
385 skip = true;
386 }
282 } 387 }
283 } 388 }
284 389
diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c
index a767a6400c5c..313a48c6b2bc 100644
--- a/tools/perf/tests/code-reading.c
+++ b/tools/perf/tests/code-reading.c
@@ -433,7 +433,6 @@ enum {
433 433
434static int do_test_code_reading(bool try_kcore) 434static int do_test_code_reading(bool try_kcore)
435{ 435{
436 struct machines machines;
437 struct machine *machine; 436 struct machine *machine;
438 struct thread *thread; 437 struct thread *thread;
439 struct record_opts opts = { 438 struct record_opts opts = {
@@ -459,8 +458,7 @@ static int do_test_code_reading(bool try_kcore)
459 458
460 pid = getpid(); 459 pid = getpid();
461 460
462 machines__init(&machines); 461 machine = machine__new_host();
463 machine = &machines.host;
464 462
465 ret = machine__create_kernel_maps(machine); 463 ret = machine__create_kernel_maps(machine);
466 if (ret < 0) { 464 if (ret < 0) {
@@ -549,6 +547,13 @@ static int do_test_code_reading(bool try_kcore)
549 if (ret < 0) { 547 if (ret < 0) {
550 if (!excl_kernel) { 548 if (!excl_kernel) {
551 excl_kernel = true; 549 excl_kernel = true;
550 /*
551 * Both cpus and threads are now owned by evlist
552 * and will be freed by following perf_evlist__set_maps
553 * call. Getting refference to keep them alive.
554 */
555 cpu_map__get(cpus);
556 thread_map__get(threads);
552 perf_evlist__set_maps(evlist, NULL, NULL); 557 perf_evlist__set_maps(evlist, NULL, NULL);
553 perf_evlist__delete(evlist); 558 perf_evlist__delete(evlist);
554 evlist = NULL; 559 evlist = NULL;
@@ -594,14 +599,13 @@ out_err:
594 cpu_map__put(cpus); 599 cpu_map__put(cpus);
595 thread_map__put(threads); 600 thread_map__put(threads);
596 } 601 }
597 machines__destroy_kernel_maps(&machines);
598 machine__delete_threads(machine); 602 machine__delete_threads(machine);
599 machines__exit(&machines); 603 machine__delete(machine);
600 604
601 return err; 605 return err;
602} 606}
603 607
604int test__code_reading(void) 608int test__code_reading(int subtest __maybe_unused)
605{ 609{
606 int ret; 610 int ret;
607 611
diff --git a/tools/perf/tests/cpumap.c b/tools/perf/tests/cpumap.c
new file mode 100644
index 000000000000..4cb6418a8ffc
--- /dev/null
+++ b/tools/perf/tests/cpumap.c
@@ -0,0 +1,88 @@
1#include "tests.h"
2#include "cpumap.h"
3
4static int process_event_mask(struct perf_tool *tool __maybe_unused,
5 union perf_event *event,
6 struct perf_sample *sample __maybe_unused,
7 struct machine *machine __maybe_unused)
8{
9 struct cpu_map_event *map_event = &event->cpu_map;
10 struct cpu_map_mask *mask;
11 struct cpu_map_data *data;
12 struct cpu_map *map;
13 int i;
14
15 data = &map_event->data;
16
17 TEST_ASSERT_VAL("wrong type", data->type == PERF_CPU_MAP__MASK);
18
19 mask = (struct cpu_map_mask *)data->data;
20
21 TEST_ASSERT_VAL("wrong nr", mask->nr == 1);
22
23 for (i = 0; i < 20; i++) {
24 TEST_ASSERT_VAL("wrong cpu", test_bit(i, mask->mask));
25 }
26
27 map = cpu_map__new_data(data);
28 TEST_ASSERT_VAL("wrong nr", map->nr == 20);
29
30 for (i = 0; i < 20; i++) {
31 TEST_ASSERT_VAL("wrong cpu", map->map[i] == i);
32 }
33
34 cpu_map__put(map);
35 return 0;
36}
37
38static int process_event_cpus(struct perf_tool *tool __maybe_unused,
39 union perf_event *event,
40 struct perf_sample *sample __maybe_unused,
41 struct machine *machine __maybe_unused)
42{
43 struct cpu_map_event *map_event = &event->cpu_map;
44 struct cpu_map_entries *cpus;
45 struct cpu_map_data *data;
46 struct cpu_map *map;
47
48 data = &map_event->data;
49
50 TEST_ASSERT_VAL("wrong type", data->type == PERF_CPU_MAP__CPUS);
51
52 cpus = (struct cpu_map_entries *)data->data;
53
54 TEST_ASSERT_VAL("wrong nr", cpus->nr == 2);
55 TEST_ASSERT_VAL("wrong cpu", cpus->cpu[0] == 1);
56 TEST_ASSERT_VAL("wrong cpu", cpus->cpu[1] == 256);
57
58 map = cpu_map__new_data(data);
59 TEST_ASSERT_VAL("wrong nr", map->nr == 2);
60 TEST_ASSERT_VAL("wrong cpu", map->map[0] == 1);
61 TEST_ASSERT_VAL("wrong cpu", map->map[1] == 256);
62 TEST_ASSERT_VAL("wrong refcnt", atomic_read(&map->refcnt) == 1);
63 cpu_map__put(map);
64 return 0;
65}
66
67
68int test__cpu_map_synthesize(int subtest __maybe_unused)
69{
70 struct cpu_map *cpus;
71
72 /* This one is better stores in mask. */
73 cpus = cpu_map__new("0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19");
74
75 TEST_ASSERT_VAL("failed to synthesize map",
76 !perf_event__synthesize_cpu_map(NULL, cpus, process_event_mask, NULL));
77
78 cpu_map__put(cpus);
79
80 /* This one is better stores in cpu values. */
81 cpus = cpu_map__new("1,256");
82
83 TEST_ASSERT_VAL("failed to synthesize map",
84 !perf_event__synthesize_cpu_map(NULL, cpus, process_event_cpus, NULL));
85
86 cpu_map__put(cpus);
87 return 0;
88}
diff --git a/tools/perf/tests/dso-data.c b/tools/perf/tests/dso-data.c
index a218aeaf56a0..dc673ff7c437 100644
--- a/tools/perf/tests/dso-data.c
+++ b/tools/perf/tests/dso-data.c
@@ -110,7 +110,7 @@ static int dso__data_fd(struct dso *dso, struct machine *machine)
110 return fd; 110 return fd;
111} 111}
112 112
113int test__dso_data(void) 113int test__dso_data(int subtest __maybe_unused)
114{ 114{
115 struct machine machine; 115 struct machine machine;
116 struct dso *dso; 116 struct dso *dso;
@@ -245,7 +245,7 @@ static int set_fd_limit(int n)
245 return setrlimit(RLIMIT_NOFILE, &rlim); 245 return setrlimit(RLIMIT_NOFILE, &rlim);
246} 246}
247 247
248int test__dso_data_cache(void) 248int test__dso_data_cache(int subtest __maybe_unused)
249{ 249{
250 struct machine machine; 250 struct machine machine;
251 long nr_end, nr = open_files_cnt(); 251 long nr_end, nr = open_files_cnt();
@@ -302,7 +302,7 @@ int test__dso_data_cache(void)
302 return 0; 302 return 0;
303} 303}
304 304
305int test__dso_data_reopen(void) 305int test__dso_data_reopen(int subtest __maybe_unused)
306{ 306{
307 struct machine machine; 307 struct machine machine;
308 long nr_end, nr = open_files_cnt(); 308 long nr_end, nr = open_files_cnt();
diff --git a/tools/perf/tests/dwarf-unwind.c b/tools/perf/tests/dwarf-unwind.c
index 07221793a3ac..1c5c0221cea2 100644
--- a/tools/perf/tests/dwarf-unwind.c
+++ b/tools/perf/tests/dwarf-unwind.c
@@ -51,6 +51,12 @@ static int unwind_entry(struct unwind_entry *entry, void *arg)
51 "krava_1", 51 "krava_1",
52 "test__dwarf_unwind" 52 "test__dwarf_unwind"
53 }; 53 };
54 /*
55 * The funcs[MAX_STACK] array index, based on the
56 * callchain order setup.
57 */
58 int idx = callchain_param.order == ORDER_CALLER ?
59 MAX_STACK - *cnt - 1 : *cnt;
54 60
55 if (*cnt >= MAX_STACK) { 61 if (*cnt >= MAX_STACK) {
56 pr_debug("failed: crossed the max stack value %d\n", MAX_STACK); 62 pr_debug("failed: crossed the max stack value %d\n", MAX_STACK);
@@ -63,8 +69,10 @@ static int unwind_entry(struct unwind_entry *entry, void *arg)
63 return -1; 69 return -1;
64 } 70 }
65 71
66 pr_debug("got: %s 0x%" PRIx64 "\n", symbol, entry->ip); 72 (*cnt)++;
67 return strcmp((const char *) symbol, funcs[(*cnt)++]); 73 pr_debug("got: %s 0x%" PRIx64 ", expecting %s\n",
74 symbol, entry->ip, funcs[idx]);
75 return strcmp((const char *) symbol, funcs[idx]);
68} 76}
69 77
70__attribute__ ((noinline)) 78__attribute__ ((noinline))
@@ -105,8 +113,16 @@ static int compare(void *p1, void *p2)
105 /* Any possible value should be 'thread' */ 113 /* Any possible value should be 'thread' */
106 struct thread *thread = *(struct thread **)p1; 114 struct thread *thread = *(struct thread **)p1;
107 115
108 if (global_unwind_retval == -INT_MAX) 116 if (global_unwind_retval == -INT_MAX) {
117 /* Call unwinder twice for both callchain orders. */
118 callchain_param.order = ORDER_CALLER;
119
109 global_unwind_retval = unwind_thread(thread); 120 global_unwind_retval = unwind_thread(thread);
121 if (!global_unwind_retval) {
122 callchain_param.order = ORDER_CALLEE;
123 global_unwind_retval = unwind_thread(thread);
124 }
125 }
110 126
111 return p1 - p2; 127 return p1 - p2;
112} 128}
@@ -142,21 +158,23 @@ static int krava_1(struct thread *thread)
142 return krava_2(thread); 158 return krava_2(thread);
143} 159}
144 160
145int test__dwarf_unwind(void) 161int test__dwarf_unwind(int subtest __maybe_unused)
146{ 162{
147 struct machines machines;
148 struct machine *machine; 163 struct machine *machine;
149 struct thread *thread; 164 struct thread *thread;
150 int err = -1; 165 int err = -1;
151 166
152 machines__init(&machines); 167 machine = machine__new_host();
153
154 machine = machines__find(&machines, HOST_KERNEL_ID);
155 if (!machine) { 168 if (!machine) {
156 pr_err("Could not get machine\n"); 169 pr_err("Could not get machine\n");
157 return -1; 170 return -1;
158 } 171 }
159 172
173 if (machine__create_kernel_maps(machine)) {
174 pr_err("Failed to create kernel maps\n");
175 return -1;
176 }
177
160 callchain_param.record_mode = CALLCHAIN_DWARF; 178 callchain_param.record_mode = CALLCHAIN_DWARF;
161 179
162 if (init_live_machine(machine)) { 180 if (init_live_machine(machine)) {
@@ -178,7 +196,6 @@ int test__dwarf_unwind(void)
178 196
179 out: 197 out:
180 machine__delete_threads(machine); 198 machine__delete_threads(machine);
181 machine__exit(machine); 199 machine__delete(machine);
182 machines__exit(&machines);
183 return err; 200 return err;
184} 201}
diff --git a/tools/perf/tests/event_update.c b/tools/perf/tests/event_update.c
new file mode 100644
index 000000000000..012eab5d1df1
--- /dev/null
+++ b/tools/perf/tests/event_update.c
@@ -0,0 +1,117 @@
1#include <linux/compiler.h>
2#include "evlist.h"
3#include "evsel.h"
4#include "machine.h"
5#include "tests.h"
6#include "debug.h"
7
8static int process_event_unit(struct perf_tool *tool __maybe_unused,
9 union perf_event *event,
10 struct perf_sample *sample __maybe_unused,
11 struct machine *machine __maybe_unused)
12{
13 struct event_update_event *ev = (struct event_update_event *) event;
14
15 TEST_ASSERT_VAL("wrong id", ev->id == 123);
16 TEST_ASSERT_VAL("wrong id", ev->type == PERF_EVENT_UPDATE__UNIT);
17 TEST_ASSERT_VAL("wrong unit", !strcmp(ev->data, "KRAVA"));
18 return 0;
19}
20
21static int process_event_scale(struct perf_tool *tool __maybe_unused,
22 union perf_event *event,
23 struct perf_sample *sample __maybe_unused,
24 struct machine *machine __maybe_unused)
25{
26 struct event_update_event *ev = (struct event_update_event *) event;
27 struct event_update_event_scale *ev_data;
28
29 ev_data = (struct event_update_event_scale *) ev->data;
30
31 TEST_ASSERT_VAL("wrong id", ev->id == 123);
32 TEST_ASSERT_VAL("wrong id", ev->type == PERF_EVENT_UPDATE__SCALE);
33 TEST_ASSERT_VAL("wrong scale", ev_data->scale = 0.123);
34 return 0;
35}
36
37struct event_name {
38 struct perf_tool tool;
39 const char *name;
40};
41
42static int process_event_name(struct perf_tool *tool,
43 union perf_event *event,
44 struct perf_sample *sample __maybe_unused,
45 struct machine *machine __maybe_unused)
46{
47 struct event_name *tmp = container_of(tool, struct event_name, tool);
48 struct event_update_event *ev = (struct event_update_event*) event;
49
50 TEST_ASSERT_VAL("wrong id", ev->id == 123);
51 TEST_ASSERT_VAL("wrong id", ev->type == PERF_EVENT_UPDATE__NAME);
52 TEST_ASSERT_VAL("wrong name", !strcmp(ev->data, tmp->name));
53 return 0;
54}
55
56static int process_event_cpus(struct perf_tool *tool __maybe_unused,
57 union perf_event *event,
58 struct perf_sample *sample __maybe_unused,
59 struct machine *machine __maybe_unused)
60{
61 struct event_update_event *ev = (struct event_update_event*) event;
62 struct event_update_event_cpus *ev_data;
63 struct cpu_map *map;
64
65 ev_data = (struct event_update_event_cpus*) ev->data;
66
67 map = cpu_map__new_data(&ev_data->cpus);
68
69 TEST_ASSERT_VAL("wrong id", ev->id == 123);
70 TEST_ASSERT_VAL("wrong type", ev->type == PERF_EVENT_UPDATE__CPUS);
71 TEST_ASSERT_VAL("wrong cpus", map->nr == 3);
72 TEST_ASSERT_VAL("wrong cpus", map->map[0] == 1);
73 TEST_ASSERT_VAL("wrong cpus", map->map[1] == 2);
74 TEST_ASSERT_VAL("wrong cpus", map->map[2] == 3);
75 cpu_map__put(map);
76 return 0;
77}
78
79int test__event_update(int subtest __maybe_unused)
80{
81 struct perf_evlist *evlist;
82 struct perf_evsel *evsel;
83 struct event_name tmp;
84
85 evlist = perf_evlist__new_default();
86 TEST_ASSERT_VAL("failed to get evlist", evlist);
87
88 evsel = perf_evlist__first(evlist);
89
90 TEST_ASSERT_VAL("failed to allos ids",
91 !perf_evsel__alloc_id(evsel, 1, 1));
92
93 perf_evlist__id_add(evlist, evsel, 0, 0, 123);
94
95 evsel->unit = strdup("KRAVA");
96
97 TEST_ASSERT_VAL("failed to synthesize attr update unit",
98 !perf_event__synthesize_event_update_unit(NULL, evsel, process_event_unit));
99
100 evsel->scale = 0.123;
101
102 TEST_ASSERT_VAL("failed to synthesize attr update scale",
103 !perf_event__synthesize_event_update_scale(NULL, evsel, process_event_scale));
104
105 tmp.name = perf_evsel__name(evsel);
106
107 TEST_ASSERT_VAL("failed to synthesize attr update name",
108 !perf_event__synthesize_event_update_name(&tmp.tool, evsel, process_event_name));
109
110 evsel->own_cpus = cpu_map__new("1,2,3");
111
112 TEST_ASSERT_VAL("failed to synthesize attr update cpus",
113 !perf_event__synthesize_event_update_cpus(&tmp.tool, evsel, process_event_cpus));
114
115 cpu_map__put(evsel->own_cpus);
116 return 0;
117}
diff --git a/tools/perf/tests/evsel-roundtrip-name.c b/tools/perf/tests/evsel-roundtrip-name.c
index 3fa715987a5e..2de4a4f2c3ed 100644
--- a/tools/perf/tests/evsel-roundtrip-name.c
+++ b/tools/perf/tests/evsel-roundtrip-name.c
@@ -95,7 +95,7 @@ out_delete_evlist:
95#define perf_evsel__name_array_test(names) \ 95#define perf_evsel__name_array_test(names) \
96 __perf_evsel__name_array_test(names, ARRAY_SIZE(names)) 96 __perf_evsel__name_array_test(names, ARRAY_SIZE(names))
97 97
98int test__perf_evsel__roundtrip_name_test(void) 98int test__perf_evsel__roundtrip_name_test(int subtest __maybe_unused)
99{ 99{
100 int err = 0, ret = 0; 100 int err = 0, ret = 0;
101 101
@@ -103,7 +103,8 @@ int test__perf_evsel__roundtrip_name_test(void)
103 if (err) 103 if (err)
104 ret = err; 104 ret = err;
105 105
106 err = perf_evsel__name_array_test(perf_evsel__sw_names); 106 err = __perf_evsel__name_array_test(perf_evsel__sw_names,
107 PERF_COUNT_SW_DUMMY + 1);
107 if (err) 108 if (err)
108 ret = err; 109 ret = err;
109 110
diff --git a/tools/perf/tests/evsel-tp-sched.c b/tools/perf/tests/evsel-tp-sched.c
index 790e413d9a1f..1984b3bbfe15 100644
--- a/tools/perf/tests/evsel-tp-sched.c
+++ b/tools/perf/tests/evsel-tp-sched.c
@@ -32,7 +32,7 @@ static int perf_evsel__test_field(struct perf_evsel *evsel, const char *name,
32 return ret; 32 return ret;
33} 33}
34 34
35int test__perf_evsel__tp_sched_test(void) 35int test__perf_evsel__tp_sched_test(int subtest __maybe_unused)
36{ 36{
37 struct perf_evsel *evsel = perf_evsel__newtp("sched", "sched_switch"); 37 struct perf_evsel *evsel = perf_evsel__newtp("sched", "sched_switch");
38 int ret = 0; 38 int ret = 0;
diff --git a/tools/perf/tests/fdarray.c b/tools/perf/tests/fdarray.c
index d24b837951d4..c809463edbe5 100644
--- a/tools/perf/tests/fdarray.c
+++ b/tools/perf/tests/fdarray.c
@@ -25,7 +25,7 @@ static int fdarray__fprintf_prefix(struct fdarray *fda, const char *prefix, FILE
25 return printed + fdarray__fprintf(fda, fp); 25 return printed + fdarray__fprintf(fda, fp);
26} 26}
27 27
28int test__fdarray__filter(void) 28int test__fdarray__filter(int subtest __maybe_unused)
29{ 29{
30 int nr_fds, expected_fd[2], fd, err = TEST_FAIL; 30 int nr_fds, expected_fd[2], fd, err = TEST_FAIL;
31 struct fdarray *fda = fdarray__new(5, 5); 31 struct fdarray *fda = fdarray__new(5, 5);
@@ -103,7 +103,7 @@ out:
103 return err; 103 return err;
104} 104}
105 105
106int test__fdarray__add(void) 106int test__fdarray__add(int subtest __maybe_unused)
107{ 107{
108 int err = TEST_FAIL; 108 int err = TEST_FAIL;
109 struct fdarray *fda = fdarray__new(2, 2); 109 struct fdarray *fda = fdarray__new(2, 2);
diff --git a/tools/perf/tests/hists_common.c b/tools/perf/tests/hists_common.c
index ce80b274b097..071a8b5f5232 100644
--- a/tools/perf/tests/hists_common.c
+++ b/tools/perf/tests/hists_common.c
@@ -150,7 +150,6 @@ struct machine *setup_fake_machine(struct machines *machines)
150out: 150out:
151 pr_debug("Not enough memory for machine setup\n"); 151 pr_debug("Not enough memory for machine setup\n");
152 machine__delete_threads(machine); 152 machine__delete_threads(machine);
153 machine__delete(machine);
154 return NULL; 153 return NULL;
155} 154}
156 155
diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c
index 7ed737019de7..5e6a86e50fb9 100644
--- a/tools/perf/tests/hists_cumulate.c
+++ b/tools/perf/tests/hists_cumulate.c
@@ -281,7 +281,7 @@ static int test1(struct perf_evsel *evsel, struct machine *machine)
281 symbol_conf.cumulate_callchain = false; 281 symbol_conf.cumulate_callchain = false;
282 perf_evsel__reset_sample_bit(evsel, CALLCHAIN); 282 perf_evsel__reset_sample_bit(evsel, CALLCHAIN);
283 283
284 setup_sorting(); 284 setup_sorting(NULL);
285 callchain_register_param(&callchain_param); 285 callchain_register_param(&callchain_param);
286 286
287 err = add_hist_entries(hists, machine); 287 err = add_hist_entries(hists, machine);
@@ -428,7 +428,7 @@ static int test2(struct perf_evsel *evsel, struct machine *machine)
428 symbol_conf.cumulate_callchain = false; 428 symbol_conf.cumulate_callchain = false;
429 perf_evsel__set_sample_bit(evsel, CALLCHAIN); 429 perf_evsel__set_sample_bit(evsel, CALLCHAIN);
430 430
431 setup_sorting(); 431 setup_sorting(NULL);
432 callchain_register_param(&callchain_param); 432 callchain_register_param(&callchain_param);
433 433
434 err = add_hist_entries(hists, machine); 434 err = add_hist_entries(hists, machine);
@@ -486,7 +486,7 @@ static int test3(struct perf_evsel *evsel, struct machine *machine)
486 symbol_conf.cumulate_callchain = true; 486 symbol_conf.cumulate_callchain = true;
487 perf_evsel__reset_sample_bit(evsel, CALLCHAIN); 487 perf_evsel__reset_sample_bit(evsel, CALLCHAIN);
488 488
489 setup_sorting(); 489 setup_sorting(NULL);
490 callchain_register_param(&callchain_param); 490 callchain_register_param(&callchain_param);
491 491
492 err = add_hist_entries(hists, machine); 492 err = add_hist_entries(hists, machine);
@@ -670,7 +670,7 @@ static int test4(struct perf_evsel *evsel, struct machine *machine)
670 symbol_conf.cumulate_callchain = true; 670 symbol_conf.cumulate_callchain = true;
671 perf_evsel__set_sample_bit(evsel, CALLCHAIN); 671 perf_evsel__set_sample_bit(evsel, CALLCHAIN);
672 672
673 setup_sorting(); 673 setup_sorting(NULL);
674 callchain_register_param(&callchain_param); 674 callchain_register_param(&callchain_param);
675 675
676 err = add_hist_entries(hists, machine); 676 err = add_hist_entries(hists, machine);
@@ -686,7 +686,7 @@ out:
686 return err; 686 return err;
687} 687}
688 688
689int test__hists_cumulate(void) 689int test__hists_cumulate(int subtest __maybe_unused)
690{ 690{
691 int err = TEST_FAIL; 691 int err = TEST_FAIL;
692 struct machines machines; 692 struct machines machines;
@@ -706,6 +706,7 @@ int test__hists_cumulate(void)
706 err = parse_events(evlist, "cpu-clock", NULL); 706 err = parse_events(evlist, "cpu-clock", NULL);
707 if (err) 707 if (err)
708 goto out; 708 goto out;
709 err = TEST_FAIL;
709 710
710 machines__init(&machines); 711 machines__init(&machines);
711 712
diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c
index 818acf875dd0..351a42463444 100644
--- a/tools/perf/tests/hists_filter.c
+++ b/tools/perf/tests/hists_filter.c
@@ -104,7 +104,7 @@ out:
104 return TEST_FAIL; 104 return TEST_FAIL;
105} 105}
106 106
107int test__hists_filter(void) 107int test__hists_filter(int subtest __maybe_unused)
108{ 108{
109 int err = TEST_FAIL; 109 int err = TEST_FAIL;
110 struct machines machines; 110 struct machines machines;
@@ -120,9 +120,10 @@ int test__hists_filter(void)
120 err = parse_events(evlist, "task-clock", NULL); 120 err = parse_events(evlist, "task-clock", NULL);
121 if (err) 121 if (err)
122 goto out; 122 goto out;
123 err = TEST_FAIL;
123 124
124 /* default sort order (comm,dso,sym) will be used */ 125 /* default sort order (comm,dso,sym) will be used */
125 if (setup_sorting() < 0) 126 if (setup_sorting(NULL) < 0)
126 goto out; 127 goto out;
127 128
128 machines__init(&machines); 129 machines__init(&machines);
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c
index 8c102b011424..64b257d8d557 100644
--- a/tools/perf/tests/hists_link.c
+++ b/tools/perf/tests/hists_link.c
@@ -64,7 +64,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
64 struct perf_evsel *evsel; 64 struct perf_evsel *evsel;
65 struct addr_location al; 65 struct addr_location al;
66 struct hist_entry *he; 66 struct hist_entry *he;
67 struct perf_sample sample = { .period = 1, }; 67 struct perf_sample sample = { .period = 1, .weight = 1, };
68 size_t i = 0, k; 68 size_t i = 0, k;
69 69
70 /* 70 /*
@@ -90,7 +90,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
90 goto out; 90 goto out;
91 91
92 he = __hists__add_entry(hists, &al, NULL, 92 he = __hists__add_entry(hists, &al, NULL,
93 NULL, NULL, 1, 1, 0, true); 93 NULL, NULL, &sample, true);
94 if (he == NULL) { 94 if (he == NULL) {
95 addr_location__put(&al); 95 addr_location__put(&al);
96 goto out; 96 goto out;
@@ -116,7 +116,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
116 goto out; 116 goto out;
117 117
118 he = __hists__add_entry(hists, &al, NULL, 118 he = __hists__add_entry(hists, &al, NULL,
119 NULL, NULL, 1, 1, 0, true); 119 NULL, NULL, &sample, true);
120 if (he == NULL) { 120 if (he == NULL) {
121 addr_location__put(&al); 121 addr_location__put(&al);
122 goto out; 122 goto out;
@@ -274,7 +274,7 @@ static int validate_link(struct hists *leader, struct hists *other)
274 return __validate_link(leader, 0) || __validate_link(other, 1); 274 return __validate_link(leader, 0) || __validate_link(other, 1);
275} 275}
276 276
277int test__hists_link(void) 277int test__hists_link(int subtest __maybe_unused)
278{ 278{
279 int err = -1; 279 int err = -1;
280 struct hists *hists, *first_hists; 280 struct hists *hists, *first_hists;
@@ -293,8 +293,9 @@ int test__hists_link(void)
293 if (err) 293 if (err)
294 goto out; 294 goto out;
295 295
296 err = TEST_FAIL;
296 /* default sort order (comm,dso,sym) will be used */ 297 /* default sort order (comm,dso,sym) will be used */
297 if (setup_sorting() < 0) 298 if (setup_sorting(NULL) < 0)
298 goto out; 299 goto out;
299 300
300 machines__init(&machines); 301 machines__init(&machines);
diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c
index adbebc852cc8..b231265148d8 100644
--- a/tools/perf/tests/hists_output.c
+++ b/tools/perf/tests/hists_output.c
@@ -134,7 +134,7 @@ static int test1(struct perf_evsel *evsel, struct machine *machine)
134 field_order = NULL; 134 field_order = NULL;
135 sort_order = NULL; /* equivalent to sort_order = "comm,dso,sym" */ 135 sort_order = NULL; /* equivalent to sort_order = "comm,dso,sym" */
136 136
137 setup_sorting(); 137 setup_sorting(NULL);
138 138
139 /* 139 /*
140 * expected output: 140 * expected output:
@@ -236,7 +236,7 @@ static int test2(struct perf_evsel *evsel, struct machine *machine)
236 field_order = "overhead,cpu"; 236 field_order = "overhead,cpu";
237 sort_order = "pid"; 237 sort_order = "pid";
238 238
239 setup_sorting(); 239 setup_sorting(NULL);
240 240
241 /* 241 /*
242 * expected output: 242 * expected output:
@@ -292,7 +292,7 @@ static int test3(struct perf_evsel *evsel, struct machine *machine)
292 field_order = "comm,overhead,dso"; 292 field_order = "comm,overhead,dso";
293 sort_order = NULL; 293 sort_order = NULL;
294 294
295 setup_sorting(); 295 setup_sorting(NULL);
296 296
297 /* 297 /*
298 * expected output: 298 * expected output:
@@ -366,7 +366,7 @@ static int test4(struct perf_evsel *evsel, struct machine *machine)
366 field_order = "dso,sym,comm,overhead,dso"; 366 field_order = "dso,sym,comm,overhead,dso";
367 sort_order = "sym"; 367 sort_order = "sym";
368 368
369 setup_sorting(); 369 setup_sorting(NULL);
370 370
371 /* 371 /*
372 * expected output: 372 * expected output:
@@ -468,7 +468,7 @@ static int test5(struct perf_evsel *evsel, struct machine *machine)
468 field_order = "cpu,pid,comm,dso,sym"; 468 field_order = "cpu,pid,comm,dso,sym";
469 sort_order = "dso,pid"; 469 sort_order = "dso,pid";
470 470
471 setup_sorting(); 471 setup_sorting(NULL);
472 472
473 /* 473 /*
474 * expected output: 474 * expected output:
@@ -576,7 +576,7 @@ out:
576 return err; 576 return err;
577} 577}
578 578
579int test__hists_output(void) 579int test__hists_output(int subtest __maybe_unused)
580{ 580{
581 int err = TEST_FAIL; 581 int err = TEST_FAIL;
582 struct machines machines; 582 struct machines machines;
@@ -597,6 +597,7 @@ int test__hists_output(void)
597 err = parse_events(evlist, "cpu-clock", NULL); 597 err = parse_events(evlist, "cpu-clock", NULL);
598 if (err) 598 if (err)
599 goto out; 599 goto out;
600 err = TEST_FAIL;
600 601
601 machines__init(&machines); 602 machines__init(&machines);
602 603
diff --git a/tools/perf/tests/keep-tracking.c b/tools/perf/tests/keep-tracking.c
index a2e2269aa093..ddb78fae064a 100644
--- a/tools/perf/tests/keep-tracking.c
+++ b/tools/perf/tests/keep-tracking.c
@@ -49,13 +49,12 @@ static int find_comm(struct perf_evlist *evlist, const char *comm)
49 * when an event is disabled but a dummy software event is not disabled. If the 49 * when an event is disabled but a dummy software event is not disabled. If the
50 * test passes %0 is returned, otherwise %-1 is returned. 50 * test passes %0 is returned, otherwise %-1 is returned.
51 */ 51 */
52int test__keep_tracking(void) 52int test__keep_tracking(int subtest __maybe_unused)
53{ 53{
54 struct record_opts opts = { 54 struct record_opts opts = {
55 .mmap_pages = UINT_MAX, 55 .mmap_pages = UINT_MAX,
56 .user_freq = UINT_MAX, 56 .user_freq = UINT_MAX,
57 .user_interval = ULLONG_MAX, 57 .user_interval = ULLONG_MAX,
58 .freq = 4000,
59 .target = { 58 .target = {
60 .uses_mmap = true, 59 .uses_mmap = true,
61 }, 60 },
@@ -124,7 +123,7 @@ int test__keep_tracking(void)
124 123
125 evsel = perf_evlist__last(evlist); 124 evsel = perf_evlist__last(evlist);
126 125
127 CHECK__(perf_evlist__disable_event(evlist, evsel)); 126 CHECK__(perf_evsel__disable(evsel));
128 127
129 comm = "Test COMM 2"; 128 comm = "Test COMM 2";
130 CHECK__(prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0)); 129 CHECK__(prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0));
diff --git a/tools/perf/tests/kmod-path.c b/tools/perf/tests/kmod-path.c
index 08c433b4bf4f..d2af78193153 100644
--- a/tools/perf/tests/kmod-path.c
+++ b/tools/perf/tests/kmod-path.c
@@ -49,7 +49,7 @@ static int test_is_kernel_module(const char *path, int cpumode, bool expect)
49#define M(path, c, e) \ 49#define M(path, c, e) \
50 TEST_ASSERT_VAL("failed", !test_is_kernel_module(path, c, e)) 50 TEST_ASSERT_VAL("failed", !test_is_kernel_module(path, c, e))
51 51
52int test__kmod_path__parse(void) 52int test__kmod_path__parse(int subtest __maybe_unused)
53{ 53{
54 /* path alloc_name alloc_ext kmod comp name ext */ 54 /* path alloc_name alloc_ext kmod comp name ext */
55 T("/xxxx/xxxx/x-x.ko", true , true , true, false, "[x_x]", NULL); 55 T("/xxxx/xxxx/x-x.ko", true , true , true, false, "[x_x]", NULL);
diff --git a/tools/perf/tests/llvm.c b/tools/perf/tests/llvm.c
index bc4cf507cde5..06f45c1d4256 100644
--- a/tools/perf/tests/llvm.c
+++ b/tools/perf/tests/llvm.c
@@ -44,13 +44,17 @@ static struct {
44 .source = test_llvm__bpf_test_kbuild_prog, 44 .source = test_llvm__bpf_test_kbuild_prog,
45 .desc = "Test kbuild searching", 45 .desc = "Test kbuild searching",
46 }, 46 },
47 [LLVM_TESTCASE_BPF_PROLOGUE] = {
48 .source = test_llvm__bpf_test_prologue_prog,
49 .desc = "Compile source for BPF prologue generation test",
50 },
47}; 51};
48 52
49 53
50int 54int
51test_llvm__fetch_bpf_obj(void **p_obj_buf, 55test_llvm__fetch_bpf_obj(void **p_obj_buf,
52 size_t *p_obj_buf_sz, 56 size_t *p_obj_buf_sz,
53 enum test_llvm__testcase index, 57 enum test_llvm__testcase idx,
54 bool force) 58 bool force)
55{ 59{
56 const char *source; 60 const char *source;
@@ -59,11 +63,11 @@ test_llvm__fetch_bpf_obj(void **p_obj_buf,
59 char *tmpl_new = NULL, *clang_opt_new = NULL; 63 char *tmpl_new = NULL, *clang_opt_new = NULL;
60 int err, old_verbose, ret = TEST_FAIL; 64 int err, old_verbose, ret = TEST_FAIL;
61 65
62 if (index >= __LLVM_TESTCASE_MAX) 66 if (idx >= __LLVM_TESTCASE_MAX)
63 return TEST_FAIL; 67 return TEST_FAIL;
64 68
65 source = bpf_source_table[index].source; 69 source = bpf_source_table[idx].source;
66 desc = bpf_source_table[index].desc; 70 desc = bpf_source_table[idx].desc;
67 71
68 perf_config(perf_config_cb, NULL); 72 perf_config(perf_config_cb, NULL);
69 73
@@ -127,44 +131,39 @@ out:
127 return ret; 131 return ret;
128} 132}
129 133
130int test__llvm(void) 134int test__llvm(int subtest)
131{ 135{
132 enum test_llvm__testcase i; 136 int ret;
137 void *obj_buf = NULL;
138 size_t obj_buf_sz = 0;
133 139
134 for (i = 0; i < __LLVM_TESTCASE_MAX; i++) { 140 if ((subtest < 0) || (subtest >= __LLVM_TESTCASE_MAX))
135 int ret; 141 return TEST_FAIL;
136 void *obj_buf = NULL;
137 size_t obj_buf_sz = 0;
138 142
139 ret = test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz, 143 ret = test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz,
140 i, false); 144 subtest, false);
141 145
142 if (ret == TEST_OK) { 146 if (ret == TEST_OK) {
143 ret = test__bpf_parsing(obj_buf, obj_buf_sz); 147 ret = test__bpf_parsing(obj_buf, obj_buf_sz);
144 if (ret != TEST_OK) 148 if (ret != TEST_OK) {
145 pr_debug("Failed to parse test case '%s'\n", 149 pr_debug("Failed to parse test case '%s'\n",
146 bpf_source_table[i].desc); 150 bpf_source_table[subtest].desc);
147 }
148 free(obj_buf);
149
150 switch (ret) {
151 case TEST_SKIP:
152 return TEST_SKIP;
153 case TEST_OK:
154 break;
155 default:
156 /*
157 * Test 0 is the basic LLVM test. If test 0
158 * fail, the basic LLVM support not functional
159 * so the whole test should fail. If other test
160 * case fail, it can be fixed by adjusting
161 * config so don't report error.
162 */
163 if (i == 0)
164 return TEST_FAIL;
165 else
166 return TEST_SKIP;
167 } 151 }
168 } 152 }
169 return TEST_OK; 153 free(obj_buf);
154
155 return ret;
156}
157
158int test__llvm_subtest_get_nr(void)
159{
160 return __LLVM_TESTCASE_MAX;
161}
162
163const char *test__llvm_subtest_get_desc(int subtest)
164{
165 if ((subtest < 0) || (subtest >= __LLVM_TESTCASE_MAX))
166 return NULL;
167
168 return bpf_source_table[subtest].desc;
170} 169}
diff --git a/tools/perf/tests/llvm.h b/tools/perf/tests/llvm.h
index d91d8f44efee..5150b4d6ef50 100644
--- a/tools/perf/tests/llvm.h
+++ b/tools/perf/tests/llvm.h
@@ -6,10 +6,12 @@
6 6
7extern const char test_llvm__bpf_base_prog[]; 7extern const char test_llvm__bpf_base_prog[];
8extern const char test_llvm__bpf_test_kbuild_prog[]; 8extern const char test_llvm__bpf_test_kbuild_prog[];
9extern const char test_llvm__bpf_test_prologue_prog[];
9 10
10enum test_llvm__testcase { 11enum test_llvm__testcase {
11 LLVM_TESTCASE_BASE, 12 LLVM_TESTCASE_BASE,
12 LLVM_TESTCASE_KBUILD, 13 LLVM_TESTCASE_KBUILD,
14 LLVM_TESTCASE_BPF_PROLOGUE,
13 __LLVM_TESTCASE_MAX, 15 __LLVM_TESTCASE_MAX,
14}; 16};
15 17
diff --git a/tools/perf/tests/make b/tools/perf/tests/make
index 8ea3dffc5065..f918015512af 100644
--- a/tools/perf/tests/make
+++ b/tools/perf/tests/make
@@ -1,9 +1,11 @@
1include ../scripts/Makefile.include
2
1ifndef MK 3ifndef MK
2ifeq ($(MAKECMDGOALS),) 4ifeq ($(MAKECMDGOALS),)
3# no target specified, trigger the whole suite 5# no target specified, trigger the whole suite
4all: 6all:
5 @echo "Testing Makefile"; $(MAKE) -sf tests/make MK=Makefile 7 @echo "Testing Makefile"; $(MAKE) -sf tests/make MK=Makefile
6 @echo "Testing Makefile.perf"; $(MAKE) -sf tests/make MK=Makefile.perf 8 @echo "Testing Makefile.perf"; $(MAKE) -sf tests/make MK=Makefile.perf SET_PARALLEL=1 SET_O=1
7else 9else
8# run only specific test over 'Makefile' 10# run only specific test over 'Makefile'
9%: 11%:
@@ -11,8 +13,40 @@ else
11endif 13endif
12else 14else
13PERF := . 15PERF := .
16PERF_O := $(PERF)
17O_OPT :=
18
19ifneq ($(O),)
20 FULL_O := $(shell readlink -f $(O) || echo $(O))
21 PERF_O := $(FULL_O)
22 ifeq ($(SET_O),1)
23 O_OPT := 'O=$(FULL_O)'
24 endif
25 K_O_OPT := 'O=$(FULL_O)'
26endif
27
28PARALLEL_OPT=
29ifeq ($(SET_PARALLEL),1)
30 cores := $(shell (getconf _NPROCESSORS_ONLN || egrep -c '^processor|^CPU[0-9]' /proc/cpuinfo) 2>/dev/null)
31 ifeq ($(cores),0)
32 cores := 1
33 endif
34 PARALLEL_OPT="-j$(cores)"
35endif
36
37# As per kernel Makefile, avoid funny character set dependencies
38unexport LC_ALL
39LC_COLLATE=C
40LC_NUMERIC=C
41export LC_COLLATE LC_NUMERIC
14 42
15include config/Makefile.arch 43ifeq ($(srctree),)
44srctree := $(patsubst %/,%,$(dir $(shell pwd)))
45srctree := $(patsubst %/,%,$(dir $(srctree)))
46#$(info Determined 'srctree' to be $(srctree))
47endif
48
49include $(srctree)/tools/scripts/Makefile.arch
16 50
17# FIXME looks like x86 is the only arch running tests ;-) 51# FIXME looks like x86 is the only arch running tests ;-)
18# we need some IS_(32/64) flag to make this generic 52# we need some IS_(32/64) flag to make this generic
@@ -142,11 +176,11 @@ test_make_doc := $(test_ok)
142test_make_help_O := $(test_ok) 176test_make_help_O := $(test_ok)
143test_make_doc_O := $(test_ok) 177test_make_doc_O := $(test_ok)
144 178
145test_make_python_perf_so := test -f $(PERF)/python/perf.so 179test_make_python_perf_so := test -f $(PERF_O)/python/perf.so
146 180
147test_make_perf_o := test -f $(PERF)/perf.o 181test_make_perf_o := test -f $(PERF_O)/perf.o
148test_make_util_map_o := test -f $(PERF)/util/map.o 182test_make_util_map_o := test -f $(PERF_O)/util/map.o
149test_make_util_pmu_bison_o := test -f $(PERF)/util/pmu-bison.o 183test_make_util_pmu_bison_o := test -f $(PERF_O)/util/pmu-bison.o
150 184
151define test_dest_files 185define test_dest_files
152 for file in $(1); do \ 186 for file in $(1); do \
@@ -213,7 +247,7 @@ test_make_perf_o_O := test -f $$TMP_O/perf.o
213test_make_util_map_o_O := test -f $$TMP_O/util/map.o 247test_make_util_map_o_O := test -f $$TMP_O/util/map.o
214test_make_util_pmu_bison_o_O := test -f $$TMP_O/util/pmu-bison.o 248test_make_util_pmu_bison_o_O := test -f $$TMP_O/util/pmu-bison.o
215 249
216test_default = test -x $(PERF)/perf 250test_default = test -x $(PERF_O)/perf
217test = $(if $(test_$1),$(test_$1),$(test_default)) 251test = $(if $(test_$1),$(test_$1),$(test_default))
218 252
219test_default_O = test -x $$TMP_O/perf 253test_default_O = test -x $$TMP_O/perf
@@ -233,12 +267,12 @@ endif
233 267
234MAKEFLAGS := --no-print-directory 268MAKEFLAGS := --no-print-directory
235 269
236clean := @(cd $(PERF); make -s -f $(MK) clean >/dev/null) 270clean := @(cd $(PERF); make -s -f $(MK) $(O_OPT) clean >/dev/null)
237 271
238$(run): 272$(run):
239 $(call clean) 273 $(call clean)
240 @TMP_DEST=$$(mktemp -d); \ 274 @TMP_DEST=$$(mktemp -d); \
241 cmd="cd $(PERF) && make -f $(MK) DESTDIR=$$TMP_DEST $($@)"; \ 275 cmd="cd $(PERF) && make -f $(MK) $(PARALLEL_OPT) $(O_OPT) DESTDIR=$$TMP_DEST $($@)"; \
242 echo "- $@: $$cmd" && echo $$cmd > $@ && \ 276 echo "- $@: $$cmd" && echo $$cmd > $@ && \
243 ( eval $$cmd ) >> $@ 2>&1; \ 277 ( eval $$cmd ) >> $@ 2>&1; \
244 echo " test: $(call test,$@)" >> $@ 2>&1; \ 278 echo " test: $(call test,$@)" >> $@ 2>&1; \
@@ -249,7 +283,7 @@ $(run_O):
249 $(call clean) 283 $(call clean)
250 @TMP_O=$$(mktemp -d); \ 284 @TMP_O=$$(mktemp -d); \
251 TMP_DEST=$$(mktemp -d); \ 285 TMP_DEST=$$(mktemp -d); \
252 cmd="cd $(PERF) && make -f $(MK) O=$$TMP_O DESTDIR=$$TMP_DEST $($(patsubst %_O,%,$@))"; \ 286 cmd="cd $(PERF) && make -f $(MK) $(PARALLEL_OPT) O=$$TMP_O DESTDIR=$$TMP_DEST $($(patsubst %_O,%,$@))"; \
253 echo "- $@: $$cmd" && echo $$cmd > $@ && \ 287 echo "- $@: $$cmd" && echo $$cmd > $@ && \
254 ( eval $$cmd ) >> $@ 2>&1 && \ 288 ( eval $$cmd ) >> $@ 2>&1 && \
255 echo " test: $(call test_O,$@)" >> $@ 2>&1; \ 289 echo " test: $(call test_O,$@)" >> $@ 2>&1; \
@@ -259,19 +293,25 @@ $(run_O):
259tarpkg: 293tarpkg:
260 @cmd="$(PERF)/tests/perf-targz-src-pkg $(PERF)"; \ 294 @cmd="$(PERF)/tests/perf-targz-src-pkg $(PERF)"; \
261 echo "- $@: $$cmd" && echo $$cmd > $@ && \ 295 echo "- $@: $$cmd" && echo $$cmd > $@ && \
262 ( eval $$cmd ) >> $@ 2>&1 296 ( eval $$cmd ) >> $@ 2>&1 && \
297 rm -f $@
298
299KERNEL_O := ../..
300ifneq ($(O),)
301 KERNEL_O := $(O)
302endif
263 303
264make_kernelsrc: 304make_kernelsrc:
265 @echo "- make -C <kernelsrc> tools/perf" 305 @echo "- make -C <kernelsrc> $(PARALLEL_OPT) $(K_O_OPT) tools/perf"
266 $(call clean); \ 306 $(call clean); \
267 (make -C ../.. tools/perf) > $@ 2>&1 && \ 307 (make -C ../.. $(PARALLEL_OPT) $(K_O_OPT) tools/perf) > $@ 2>&1 && \
268 test -x perf && rm -f $@ || (cat $@ ; false) 308 test -x $(KERNEL_O)/tools/perf/perf && rm -f $@ || (cat $@ ; false)
269 309
270make_kernelsrc_tools: 310make_kernelsrc_tools:
271 @echo "- make -C <kernelsrc>/tools perf" 311 @echo "- make -C <kernelsrc>/tools $(PARALLEL_OPT) $(K_O_OPT) perf"
272 $(call clean); \ 312 $(call clean); \
273 (make -C ../../tools perf) > $@ 2>&1 && \ 313 (make -C ../../tools $(PARALLEL_OPT) $(K_O_OPT) perf) > $@ 2>&1 && \
274 test -x perf && rm -f $@ || (cat $@ ; false) 314 test -x $(KERNEL_O)/tools/perf/perf && rm -f $@ || (cat $@ ; false)
275 315
276all: $(run) $(run_O) tarpkg make_kernelsrc make_kernelsrc_tools 316all: $(run) $(run_O) tarpkg make_kernelsrc make_kernelsrc_tools
277 @echo OK 317 @echo OK
@@ -279,5 +319,5 @@ all: $(run) $(run_O) tarpkg make_kernelsrc make_kernelsrc_tools
279out: $(run_O) 319out: $(run_O)
280 @echo OK 320 @echo OK
281 321
282.PHONY: all $(run) $(run_O) tarpkg clean 322.PHONY: all $(run) $(run_O) tarpkg clean make_kernelsrc make_kernelsrc_tools
283endif # ifndef MK 323endif # ifndef MK
diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c
index 4495493c9431..359e98fcd94c 100644
--- a/tools/perf/tests/mmap-basic.c
+++ b/tools/perf/tests/mmap-basic.c
@@ -16,7 +16,7 @@
16 * Then it checks if the number of syscalls reported as perf events by 16 * Then it checks if the number of syscalls reported as perf events by
17 * the kernel corresponds to the number of syscalls made. 17 * the kernel corresponds to the number of syscalls made.
18 */ 18 */
19int test__basic_mmap(void) 19int test__basic_mmap(int subtest __maybe_unused)
20{ 20{
21 int err = -1; 21 int err = -1;
22 union perf_event *event; 22 union perf_event *event;
diff --git a/tools/perf/tests/mmap-thread-lookup.c b/tools/perf/tests/mmap-thread-lookup.c
index 145050e2e544..0c5ce44f723f 100644
--- a/tools/perf/tests/mmap-thread-lookup.c
+++ b/tools/perf/tests/mmap-thread-lookup.c
@@ -149,7 +149,6 @@ static int synth_process(struct machine *machine)
149 149
150static int mmap_events(synth_cb synth) 150static int mmap_events(synth_cb synth)
151{ 151{
152 struct machines machines;
153 struct machine *machine; 152 struct machine *machine;
154 int err, i; 153 int err, i;
155 154
@@ -162,8 +161,7 @@ static int mmap_events(synth_cb synth)
162 */ 161 */
163 TEST_ASSERT_VAL("failed to create threads", !threads_create()); 162 TEST_ASSERT_VAL("failed to create threads", !threads_create());
164 163
165 machines__init(&machines); 164 machine = machine__new_host();
166 machine = &machines.host;
167 165
168 dump_trace = verbose > 1 ? 1 : 0; 166 dump_trace = verbose > 1 ? 1 : 0;
169 167
@@ -203,7 +201,7 @@ static int mmap_events(synth_cb synth)
203 } 201 }
204 202
205 machine__delete_threads(machine); 203 machine__delete_threads(machine);
206 machines__exit(&machines); 204 machine__delete(machine);
207 return err; 205 return err;
208} 206}
209 207
@@ -221,7 +219,7 @@ static int mmap_events(synth_cb synth)
221 * 219 *
222 * by using all thread objects. 220 * by using all thread objects.
223 */ 221 */
224int test__mmap_thread_lookup(void) 222int test__mmap_thread_lookup(int subtest __maybe_unused)
225{ 223{
226 /* perf_event__synthesize_threads synthesize */ 224 /* perf_event__synthesize_threads synthesize */
227 TEST_ASSERT_VAL("failed with sythesizing all", 225 TEST_ASSERT_VAL("failed with sythesizing all",
diff --git a/tools/perf/tests/openat-syscall-all-cpus.c b/tools/perf/tests/openat-syscall-all-cpus.c
index 2006485a2859..53c2273e8859 100644
--- a/tools/perf/tests/openat-syscall-all-cpus.c
+++ b/tools/perf/tests/openat-syscall-all-cpus.c
@@ -7,7 +7,7 @@
7#include "debug.h" 7#include "debug.h"
8#include "stat.h" 8#include "stat.h"
9 9
10int test__openat_syscall_event_on_all_cpus(void) 10int test__openat_syscall_event_on_all_cpus(int subtest __maybe_unused)
11{ 11{
12 int err = -1, fd, cpu; 12 int err = -1, fd, cpu;
13 struct cpu_map *cpus; 13 struct cpu_map *cpus;
diff --git a/tools/perf/tests/openat-syscall-tp-fields.c b/tools/perf/tests/openat-syscall-tp-fields.c
index 5e811cd8f1c3..eb99a105f31c 100644
--- a/tools/perf/tests/openat-syscall-tp-fields.c
+++ b/tools/perf/tests/openat-syscall-tp-fields.c
@@ -6,7 +6,7 @@
6#include "tests.h" 6#include "tests.h"
7#include "debug.h" 7#include "debug.h"
8 8
9int test__syscall_openat_tp_fields(void) 9int test__syscall_openat_tp_fields(int subtest __maybe_unused)
10{ 10{
11 struct record_opts opts = { 11 struct record_opts opts = {
12 .target = { 12 .target = {
diff --git a/tools/perf/tests/openat-syscall.c b/tools/perf/tests/openat-syscall.c
index 033b54797b8a..1184f9ba6499 100644
--- a/tools/perf/tests/openat-syscall.c
+++ b/tools/perf/tests/openat-syscall.c
@@ -5,7 +5,7 @@
5#include "debug.h" 5#include "debug.h"
6#include "tests.h" 6#include "tests.h"
7 7
8int test__openat_syscall_event(void) 8int test__openat_syscall_event(int subtest __maybe_unused)
9{ 9{
10 int err = -1, fd; 10 int err = -1, fd;
11 struct perf_evsel *evsel; 11 struct perf_evsel *evsel;
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
index 636d7b42d844..abe8849d1d70 100644
--- a/tools/perf/tests/parse-events.c
+++ b/tools/perf/tests/parse-events.c
@@ -1765,7 +1765,7 @@ static void debug_warn(const char *warn, va_list params)
1765 fprintf(stderr, " Warning: %s\n", msg); 1765 fprintf(stderr, " Warning: %s\n", msg);
1766} 1766}
1767 1767
1768int test__parse_events(void) 1768int test__parse_events(int subtest __maybe_unused)
1769{ 1769{
1770 int ret1, ret2 = 0; 1770 int ret1, ret2 = 0;
1771 1771
diff --git a/tools/perf/tests/parse-no-sample-id-all.c b/tools/perf/tests/parse-no-sample-id-all.c
index 2c63ea658541..294c76b01b41 100644
--- a/tools/perf/tests/parse-no-sample-id-all.c
+++ b/tools/perf/tests/parse-no-sample-id-all.c
@@ -67,7 +67,7 @@ struct test_attr_event {
67 * 67 *
68 * Return: %0 on success, %-1 if the test fails. 68 * Return: %0 on success, %-1 if the test fails.
69 */ 69 */
70int test__parse_no_sample_id_all(void) 70int test__parse_no_sample_id_all(int subtest __maybe_unused)
71{ 71{
72 int err; 72 int err;
73 73
diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c
index 7a228a2a070b..1cc78cefe399 100644
--- a/tools/perf/tests/perf-record.c
+++ b/tools/perf/tests/perf-record.c
@@ -32,7 +32,7 @@ realloc:
32 return cpu; 32 return cpu;
33} 33}
34 34
35int test__PERF_RECORD(void) 35int test__PERF_RECORD(int subtest __maybe_unused)
36{ 36{
37 struct record_opts opts = { 37 struct record_opts opts = {
38 .target = { 38 .target = {
@@ -40,12 +40,11 @@ int test__PERF_RECORD(void)
40 .uses_mmap = true, 40 .uses_mmap = true,
41 }, 41 },
42 .no_buffering = true, 42 .no_buffering = true,
43 .freq = 10,
44 .mmap_pages = 256, 43 .mmap_pages = 256,
45 }; 44 };
46 cpu_set_t cpu_mask; 45 cpu_set_t cpu_mask;
47 size_t cpu_mask_size = sizeof(cpu_mask); 46 size_t cpu_mask_size = sizeof(cpu_mask);
48 struct perf_evlist *evlist = perf_evlist__new_default(); 47 struct perf_evlist *evlist = perf_evlist__new_dummy();
49 struct perf_evsel *evsel; 48 struct perf_evsel *evsel;
50 struct perf_sample sample; 49 struct perf_sample sample;
51 const char *cmd = "sleep"; 50 const char *cmd = "sleep";
@@ -61,6 +60,9 @@ int test__PERF_RECORD(void)
61 int total_events = 0, nr_events[PERF_RECORD_MAX] = { 0, }; 60 int total_events = 0, nr_events[PERF_RECORD_MAX] = { 0, };
62 char sbuf[STRERR_BUFSIZE]; 61 char sbuf[STRERR_BUFSIZE];
63 62
63 if (evlist == NULL) /* Fallback for kernels lacking PERF_COUNT_SW_DUMMY */
64 evlist = perf_evlist__new_default();
65
64 if (evlist == NULL || argv == NULL) { 66 if (evlist == NULL || argv == NULL) {
65 pr_debug("Not enough memory to create evlist\n"); 67 pr_debug("Not enough memory to create evlist\n");
66 goto out; 68 goto out;
diff --git a/tools/perf/tests/pmu.c b/tools/perf/tests/pmu.c
index faa04e9d5d5f..1e2ba2602930 100644
--- a/tools/perf/tests/pmu.c
+++ b/tools/perf/tests/pmu.c
@@ -133,7 +133,7 @@ static struct list_head *test_terms_list(void)
133 return &terms; 133 return &terms;
134} 134}
135 135
136int test__pmu(void) 136int test__pmu(int subtest __maybe_unused)
137{ 137{
138 char *format = test_format_dir_get(); 138 char *format = test_format_dir_get();
139 LIST_HEAD(formats); 139 LIST_HEAD(formats);
diff --git a/tools/perf/tests/python-use.c b/tools/perf/tests/python-use.c
index 7760277c6def..7a52834ee0d0 100644
--- a/tools/perf/tests/python-use.c
+++ b/tools/perf/tests/python-use.c
@@ -4,11 +4,12 @@
4 4
5#include <stdio.h> 5#include <stdio.h>
6#include <stdlib.h> 6#include <stdlib.h>
7#include <linux/compiler.h>
7#include "tests.h" 8#include "tests.h"
8 9
9extern int verbose; 10extern int verbose;
10 11
11int test__python_use(void) 12int test__python_use(int subtest __maybe_unused)
12{ 13{
13 char *cmd; 14 char *cmd;
14 int ret; 15 int ret;
diff --git a/tools/perf/tests/sample-parsing.c b/tools/perf/tests/sample-parsing.c
index 30c02181e78b..5f23710b9fee 100644
--- a/tools/perf/tests/sample-parsing.c
+++ b/tools/perf/tests/sample-parsing.c
@@ -290,7 +290,7 @@ out_free:
290 * checks sample format bits separately and together. If the test passes %0 is 290 * checks sample format bits separately and together. If the test passes %0 is
291 * returned, otherwise %-1 is returned. 291 * returned, otherwise %-1 is returned.
292 */ 292 */
293int test__sample_parsing(void) 293int test__sample_parsing(int subtest __maybe_unused)
294{ 294{
295 const u64 rf[] = {4, 5, 6, 7, 12, 13, 14, 15}; 295 const u64 rf[] = {4, 5, 6, 7, 12, 13, 14, 15};
296 u64 sample_type; 296 u64 sample_type;
diff --git a/tools/perf/tests/stat.c b/tools/perf/tests/stat.c
new file mode 100644
index 000000000000..6a20ff2326bb
--- /dev/null
+++ b/tools/perf/tests/stat.c
@@ -0,0 +1,111 @@
1#include <linux/compiler.h>
2#include "event.h"
3#include "tests.h"
4#include "stat.h"
5#include "counts.h"
6#include "debug.h"
7
8static bool has_term(struct stat_config_event *config,
9 u64 tag, u64 val)
10{
11 unsigned i;
12
13 for (i = 0; i < config->nr; i++) {
14 if ((config->data[i].tag == tag) &&
15 (config->data[i].val == val))
16 return true;
17 }
18
19 return false;
20}
21
22static int process_stat_config_event(struct perf_tool *tool __maybe_unused,
23 union perf_event *event,
24 struct perf_sample *sample __maybe_unused,
25 struct machine *machine __maybe_unused)
26{
27 struct stat_config_event *config = &event->stat_config;
28 struct perf_stat_config stat_config;
29
30#define HAS(term, val) \
31 has_term(config, PERF_STAT_CONFIG_TERM__##term, val)
32
33 TEST_ASSERT_VAL("wrong nr", config->nr == PERF_STAT_CONFIG_TERM__MAX);
34 TEST_ASSERT_VAL("wrong aggr_mode", HAS(AGGR_MODE, AGGR_CORE));
35 TEST_ASSERT_VAL("wrong scale", HAS(SCALE, 1));
36 TEST_ASSERT_VAL("wrong interval", HAS(INTERVAL, 1));
37
38#undef HAS
39
40 perf_event__read_stat_config(&stat_config, config);
41
42 TEST_ASSERT_VAL("wrong aggr_mode", stat_config.aggr_mode == AGGR_CORE);
43 TEST_ASSERT_VAL("wrong scale", stat_config.scale == 1);
44 TEST_ASSERT_VAL("wrong interval", stat_config.interval == 1);
45 return 0;
46}
47
48int test__synthesize_stat_config(int subtest __maybe_unused)
49{
50 struct perf_stat_config stat_config = {
51 .aggr_mode = AGGR_CORE,
52 .scale = 1,
53 .interval = 1,
54 };
55
56 TEST_ASSERT_VAL("failed to synthesize stat_config",
57 !perf_event__synthesize_stat_config(NULL, &stat_config, process_stat_config_event, NULL));
58
59 return 0;
60}
61
62static int process_stat_event(struct perf_tool *tool __maybe_unused,
63 union perf_event *event,
64 struct perf_sample *sample __maybe_unused,
65 struct machine *machine __maybe_unused)
66{
67 struct stat_event *st = &event->stat;
68
69 TEST_ASSERT_VAL("wrong cpu", st->cpu == 1);
70 TEST_ASSERT_VAL("wrong thread", st->thread == 2);
71 TEST_ASSERT_VAL("wrong id", st->id == 3);
72 TEST_ASSERT_VAL("wrong val", st->val == 100);
73 TEST_ASSERT_VAL("wrong run", st->ena == 200);
74 TEST_ASSERT_VAL("wrong ena", st->run == 300);
75 return 0;
76}
77
78int test__synthesize_stat(int subtest __maybe_unused)
79{
80 struct perf_counts_values count;
81
82 count.val = 100;
83 count.ena = 200;
84 count.run = 300;
85
86 TEST_ASSERT_VAL("failed to synthesize stat_config",
87 !perf_event__synthesize_stat(NULL, 1, 2, 3, &count, process_stat_event, NULL));
88
89 return 0;
90}
91
92static int process_stat_round_event(struct perf_tool *tool __maybe_unused,
93 union perf_event *event,
94 struct perf_sample *sample __maybe_unused,
95 struct machine *machine __maybe_unused)
96{
97 struct stat_round_event *stat_round = &event->stat_round;
98
99 TEST_ASSERT_VAL("wrong time", stat_round->time == 0xdeadbeef);
100 TEST_ASSERT_VAL("wrong type", stat_round->type == PERF_STAT_ROUND_TYPE__INTERVAL);
101 return 0;
102}
103
104int test__synthesize_stat_round(int subtest __maybe_unused)
105{
106 TEST_ASSERT_VAL("failed to synthesize stat_config",
107 !perf_event__synthesize_stat_round(NULL, 0xdeadbeef, PERF_STAT_ROUND_TYPE__INTERVAL,
108 process_stat_round_event, NULL));
109
110 return 0;
111}
diff --git a/tools/perf/tests/sw-clock.c b/tools/perf/tests/sw-clock.c
index 5b83f56a3b6f..36e8ce1550e3 100644
--- a/tools/perf/tests/sw-clock.c
+++ b/tools/perf/tests/sw-clock.c
@@ -122,7 +122,7 @@ out_delete_evlist:
122 return err; 122 return err;
123} 123}
124 124
125int test__sw_clock_freq(void) 125int test__sw_clock_freq(int subtest __maybe_unused)
126{ 126{
127 int ret; 127 int ret;
128 128
diff --git a/tools/perf/tests/switch-tracking.c b/tools/perf/tests/switch-tracking.c
index a02af503100c..ebd80168d51e 100644
--- a/tools/perf/tests/switch-tracking.c
+++ b/tools/perf/tests/switch-tracking.c
@@ -305,7 +305,7 @@ out_free_nodes:
305 * evsel->system_wide and evsel->tracking flags (respectively) with other events 305 * evsel->system_wide and evsel->tracking flags (respectively) with other events
306 * sometimes enabled or disabled. 306 * sometimes enabled or disabled.
307 */ 307 */
308int test__switch_tracking(void) 308int test__switch_tracking(int subtest __maybe_unused)
309{ 309{
310 const char *sched_switch = "sched:sched_switch"; 310 const char *sched_switch = "sched:sched_switch";
311 struct switch_tracking switch_tracking = { .tids = NULL, }; 311 struct switch_tracking switch_tracking = { .tids = NULL, };
@@ -455,7 +455,7 @@ int test__switch_tracking(void)
455 455
456 perf_evlist__enable(evlist); 456 perf_evlist__enable(evlist);
457 457
458 err = perf_evlist__disable_event(evlist, cpu_clocks_evsel); 458 err = perf_evsel__disable(cpu_clocks_evsel);
459 if (err) { 459 if (err) {
460 pr_debug("perf_evlist__disable_event failed!\n"); 460 pr_debug("perf_evlist__disable_event failed!\n");
461 goto out_err; 461 goto out_err;
@@ -474,7 +474,7 @@ int test__switch_tracking(void)
474 goto out_err; 474 goto out_err;
475 } 475 }
476 476
477 err = perf_evlist__disable_event(evlist, cycles_evsel); 477 err = perf_evsel__disable(cycles_evsel);
478 if (err) { 478 if (err) {
479 pr_debug("perf_evlist__disable_event failed!\n"); 479 pr_debug("perf_evlist__disable_event failed!\n");
480 goto out_err; 480 goto out_err;
@@ -500,7 +500,7 @@ int test__switch_tracking(void)
500 goto out_err; 500 goto out_err;
501 } 501 }
502 502
503 err = perf_evlist__enable_event(evlist, cycles_evsel); 503 err = perf_evsel__enable(cycles_evsel);
504 if (err) { 504 if (err) {
505 pr_debug("perf_evlist__disable_event failed!\n"); 505 pr_debug("perf_evlist__disable_event failed!\n");
506 goto out_err; 506 goto out_err;
diff --git a/tools/perf/tests/task-exit.c b/tools/perf/tests/task-exit.c
index add16385f13e..2dfff7ac8ef3 100644
--- a/tools/perf/tests/task-exit.c
+++ b/tools/perf/tests/task-exit.c
@@ -31,7 +31,7 @@ static void workload_exec_failed_signal(int signo __maybe_unused,
31 * if the number of exit event reported by the kernel is 1 or not 31 * if the number of exit event reported by the kernel is 1 or not
32 * in order to check the kernel returns correct number of event. 32 * in order to check the kernel returns correct number of event.
33 */ 33 */
34int test__task_exit(void) 34int test__task_exit(int subtest __maybe_unused)
35{ 35{
36 int err = -1; 36 int err = -1;
37 union perf_event *event; 37 union perf_event *event;
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index 3c8734a3abbc..82b2b5e6ba7c 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -1,6 +1,8 @@
1#ifndef TESTS_H 1#ifndef TESTS_H
2#define TESTS_H 2#define TESTS_H
3 3
4#include <stdbool.h>
5
4#define TEST_ASSERT_VAL(text, cond) \ 6#define TEST_ASSERT_VAL(text, cond) \
5do { \ 7do { \
6 if (!(cond)) { \ 8 if (!(cond)) { \
@@ -26,48 +28,63 @@ enum {
26 28
27struct test { 29struct test {
28 const char *desc; 30 const char *desc;
29 int (*func)(void); 31 int (*func)(int subtest);
32 struct {
33 bool skip_if_fail;
34 int (*get_nr)(void);
35 const char *(*get_desc)(int subtest);
36 } subtest;
30}; 37};
31 38
32/* Tests */ 39/* Tests */
33int test__vmlinux_matches_kallsyms(void); 40int test__vmlinux_matches_kallsyms(int subtest);
34int test__openat_syscall_event(void); 41int test__openat_syscall_event(int subtest);
35int test__openat_syscall_event_on_all_cpus(void); 42int test__openat_syscall_event_on_all_cpus(int subtest);
36int test__basic_mmap(void); 43int test__basic_mmap(int subtest);
37int test__PERF_RECORD(void); 44int test__PERF_RECORD(int subtest);
38int test__perf_evsel__roundtrip_name_test(void); 45int test__perf_evsel__roundtrip_name_test(int subtest);
39int test__perf_evsel__tp_sched_test(void); 46int test__perf_evsel__tp_sched_test(int subtest);
40int test__syscall_openat_tp_fields(void); 47int test__syscall_openat_tp_fields(int subtest);
41int test__pmu(void); 48int test__pmu(int subtest);
42int test__attr(void); 49int test__attr(int subtest);
43int test__dso_data(void); 50int test__dso_data(int subtest);
44int test__dso_data_cache(void); 51int test__dso_data_cache(int subtest);
45int test__dso_data_reopen(void); 52int test__dso_data_reopen(int subtest);
46int test__parse_events(void); 53int test__parse_events(int subtest);
47int test__hists_link(void); 54int test__hists_link(int subtest);
48int test__python_use(void); 55int test__python_use(int subtest);
49int test__bp_signal(void); 56int test__bp_signal(int subtest);
50int test__bp_signal_overflow(void); 57int test__bp_signal_overflow(int subtest);
51int test__task_exit(void); 58int test__task_exit(int subtest);
52int test__sw_clock_freq(void); 59int test__sw_clock_freq(int subtest);
53int test__code_reading(void); 60int test__code_reading(int subtest);
54int test__sample_parsing(void); 61int test__sample_parsing(int subtest);
55int test__keep_tracking(void); 62int test__keep_tracking(int subtest);
56int test__parse_no_sample_id_all(void); 63int test__parse_no_sample_id_all(int subtest);
57int test__dwarf_unwind(void); 64int test__dwarf_unwind(int subtest);
58int test__hists_filter(void); 65int test__hists_filter(int subtest);
59int test__mmap_thread_lookup(void); 66int test__mmap_thread_lookup(int subtest);
60int test__thread_mg_share(void); 67int test__thread_mg_share(int subtest);
61int test__hists_output(void); 68int test__hists_output(int subtest);
62int test__hists_cumulate(void); 69int test__hists_cumulate(int subtest);
63int test__switch_tracking(void); 70int test__switch_tracking(int subtest);
64int test__fdarray__filter(void); 71int test__fdarray__filter(int subtest);
65int test__fdarray__add(void); 72int test__fdarray__add(int subtest);
66int test__kmod_path__parse(void); 73int test__kmod_path__parse(int subtest);
67int test__thread_map(void); 74int test__thread_map(int subtest);
68int test__llvm(void); 75int test__llvm(int subtest);
69int test__bpf(void); 76const char *test__llvm_subtest_get_desc(int subtest);
70int test_session_topology(void); 77int test__llvm_subtest_get_nr(void);
78int test__bpf(int subtest);
79const char *test__bpf_subtest_get_desc(int subtest);
80int test__bpf_subtest_get_nr(void);
81int test_session_topology(int subtest);
82int test__thread_map_synthesize(int subtest);
83int test__cpu_map_synthesize(int subtest);
84int test__synthesize_stat_config(int subtest);
85int test__synthesize_stat(int subtest);
86int test__synthesize_stat_round(int subtest);
87int test__event_update(int subtest);
71 88
72#if defined(__arm__) || defined(__aarch64__) 89#if defined(__arm__) || defined(__aarch64__)
73#ifdef HAVE_DWARF_UNWIND_SUPPORT 90#ifdef HAVE_DWARF_UNWIND_SUPPORT
diff --git a/tools/perf/tests/thread-map.c b/tools/perf/tests/thread-map.c
index 138a0e3431fa..fccde848fe9c 100644
--- a/tools/perf/tests/thread-map.c
+++ b/tools/perf/tests/thread-map.c
@@ -4,7 +4,7 @@
4#include "thread_map.h" 4#include "thread_map.h"
5#include "debug.h" 5#include "debug.h"
6 6
7int test__thread_map(void) 7int test__thread_map(int subtest __maybe_unused)
8{ 8{
9 struct thread_map *map; 9 struct thread_map *map;
10 10
@@ -40,3 +40,46 @@ int test__thread_map(void)
40 thread_map__put(map); 40 thread_map__put(map);
41 return 0; 41 return 0;
42} 42}
43
44static int process_event(struct perf_tool *tool __maybe_unused,
45 union perf_event *event,
46 struct perf_sample *sample __maybe_unused,
47 struct machine *machine __maybe_unused)
48{
49 struct thread_map_event *map = &event->thread_map;
50 struct thread_map *threads;
51
52 TEST_ASSERT_VAL("wrong nr", map->nr == 1);
53 TEST_ASSERT_VAL("wrong pid", map->entries[0].pid == (u64) getpid());
54 TEST_ASSERT_VAL("wrong comm", !strcmp(map->entries[0].comm, "perf"));
55
56 threads = thread_map__new_event(&event->thread_map);
57 TEST_ASSERT_VAL("failed to alloc map", threads);
58
59 TEST_ASSERT_VAL("wrong nr", threads->nr == 1);
60 TEST_ASSERT_VAL("wrong pid",
61 thread_map__pid(threads, 0) == getpid());
62 TEST_ASSERT_VAL("wrong comm",
63 thread_map__comm(threads, 0) &&
64 !strcmp(thread_map__comm(threads, 0), "perf"));
65 TEST_ASSERT_VAL("wrong refcnt",
66 atomic_read(&threads->refcnt) == 1);
67 thread_map__put(threads);
68 return 0;
69}
70
71int test__thread_map_synthesize(int subtest __maybe_unused)
72{
73 struct thread_map *threads;
74
75 /* test map on current pid */
76 threads = thread_map__new_by_pid(getpid());
77 TEST_ASSERT_VAL("failed to alloc map", threads);
78
79 thread_map__read_comms(threads);
80
81 TEST_ASSERT_VAL("failed to synthesize map",
82 !perf_event__synthesize_thread_map2(NULL, threads, process_event, NULL));
83
84 return 0;
85}
diff --git a/tools/perf/tests/thread-mg-share.c b/tools/perf/tests/thread-mg-share.c
index 01fabb19d746..188b63140fc8 100644
--- a/tools/perf/tests/thread-mg-share.c
+++ b/tools/perf/tests/thread-mg-share.c
@@ -4,7 +4,7 @@
4#include "map.h" 4#include "map.h"
5#include "debug.h" 5#include "debug.h"
6 6
7int test__thread_mg_share(void) 7int test__thread_mg_share(int subtest __maybe_unused)
8{ 8{
9 struct machines machines; 9 struct machines machines;
10 struct machine *machine; 10 struct machine *machine;
diff --git a/tools/perf/tests/topology.c b/tools/perf/tests/topology.c
index f5bb096c3bd9..98fe69ac553c 100644
--- a/tools/perf/tests/topology.c
+++ b/tools/perf/tests/topology.c
@@ -84,7 +84,7 @@ static int check_cpu_topology(char *path, struct cpu_map *map)
84 return 0; 84 return 0;
85} 85}
86 86
87int test_session_topology(void) 87int test_session_topology(int subtest __maybe_unused)
88{ 88{
89 char path[PATH_MAX]; 89 char path[PATH_MAX];
90 struct cpu_map *map; 90 struct cpu_map *map;
diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c
index d677e018e504..f0bfc9e8fd9f 100644
--- a/tools/perf/tests/vmlinux-kallsyms.c
+++ b/tools/perf/tests/vmlinux-kallsyms.c
@@ -18,7 +18,7 @@ static int vmlinux_matches_kallsyms_filter(struct map *map __maybe_unused,
18 18
19#define UM(x) kallsyms_map->unmap_ip(kallsyms_map, (x)) 19#define UM(x) kallsyms_map->unmap_ip(kallsyms_map, (x))
20 20
21int test__vmlinux_matches_kallsyms(void) 21int test__vmlinux_matches_kallsyms(int subtest __maybe_unused)
22{ 22{
23 int err = -1; 23 int err = -1;
24 struct rb_node *nd; 24 struct rb_node *nd;
diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c
index e9703c0829f1..d37202121689 100644
--- a/tools/perf/ui/browser.c
+++ b/tools/perf/ui/browser.c
@@ -528,7 +528,7 @@ static struct ui_browser_colorset {
528 .colorset = HE_COLORSET_SELECTED, 528 .colorset = HE_COLORSET_SELECTED,
529 .name = "selected", 529 .name = "selected",
530 .fg = "black", 530 .fg = "black",
531 .bg = "lightgray", 531 .bg = "yellow",
532 }, 532 },
533 { 533 {
534 .colorset = HE_COLORSET_CODE, 534 .colorset = HE_COLORSET_CODE,
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
index d4d7cc27252f..718bd46d47fa 100644
--- a/tools/perf/ui/browsers/annotate.c
+++ b/tools/perf/ui/browsers/annotate.c
@@ -755,11 +755,11 @@ static int annotate_browser__run(struct annotate_browser *browser,
755 nd = browser->curr_hot; 755 nd = browser->curr_hot;
756 break; 756 break;
757 case K_UNTAB: 757 case K_UNTAB:
758 if (nd != NULL) 758 if (nd != NULL) {
759 nd = rb_next(nd); 759 nd = rb_next(nd);
760 if (nd == NULL) 760 if (nd == NULL)
761 nd = rb_first(&browser->entries); 761 nd = rb_first(&browser->entries);
762 else 762 } else
763 nd = browser->curr_hot; 763 nd = browser->curr_hot;
764 break; 764 break;
765 case K_F1: 765 case K_F1:
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index e5afb8936040..08c09ad755d2 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -178,12 +178,51 @@ static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
178 return n; 178 return n;
179} 179}
180 180
181static int callchain_node__count_flat_rows(struct callchain_node *node)
182{
183 struct callchain_list *chain;
184 char folded_sign = 0;
185 int n = 0;
186
187 list_for_each_entry(chain, &node->parent_val, list) {
188 if (!folded_sign) {
189 /* only check first chain list entry */
190 folded_sign = callchain_list__folded(chain);
191 if (folded_sign == '+')
192 return 1;
193 }
194 n++;
195 }
196
197 list_for_each_entry(chain, &node->val, list) {
198 if (!folded_sign) {
199 /* node->parent_val list might be empty */
200 folded_sign = callchain_list__folded(chain);
201 if (folded_sign == '+')
202 return 1;
203 }
204 n++;
205 }
206
207 return n;
208}
209
210static int callchain_node__count_folded_rows(struct callchain_node *node __maybe_unused)
211{
212 return 1;
213}
214
181static int callchain_node__count_rows(struct callchain_node *node) 215static int callchain_node__count_rows(struct callchain_node *node)
182{ 216{
183 struct callchain_list *chain; 217 struct callchain_list *chain;
184 bool unfolded = false; 218 bool unfolded = false;
185 int n = 0; 219 int n = 0;
186 220
221 if (callchain_param.mode == CHAIN_FLAT)
222 return callchain_node__count_flat_rows(node);
223 else if (callchain_param.mode == CHAIN_FOLDED)
224 return callchain_node__count_folded_rows(node);
225
187 list_for_each_entry(chain, &node->val, list) { 226 list_for_each_entry(chain, &node->val, list) {
188 ++n; 227 ++n;
189 unfolded = chain->unfolded; 228 unfolded = chain->unfolded;
@@ -263,7 +302,7 @@ static void callchain_node__init_have_children(struct callchain_node *node,
263 chain = list_entry(node->val.next, struct callchain_list, list); 302 chain = list_entry(node->val.next, struct callchain_list, list);
264 chain->has_children = has_sibling; 303 chain->has_children = has_sibling;
265 304
266 if (!list_empty(&node->val)) { 305 if (node->val.next != node->val.prev) {
267 chain = list_entry(node->val.prev, struct callchain_list, list); 306 chain = list_entry(node->val.prev, struct callchain_list, list);
268 chain->has_children = !RB_EMPTY_ROOT(&node->rb_root); 307 chain->has_children = !RB_EMPTY_ROOT(&node->rb_root);
269 } 308 }
@@ -279,6 +318,9 @@ static void callchain__init_have_children(struct rb_root *root)
279 for (nd = rb_first(root); nd; nd = rb_next(nd)) { 318 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
280 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 319 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
281 callchain_node__init_have_children(node, has_sibling); 320 callchain_node__init_have_children(node, has_sibling);
321 if (callchain_param.mode == CHAIN_FLAT ||
322 callchain_param.mode == CHAIN_FOLDED)
323 callchain_node__make_parent_list(node);
282 } 324 }
283} 325}
284 326
@@ -298,6 +340,9 @@ static bool hist_browser__toggle_fold(struct hist_browser *browser)
298 struct callchain_list *cl = container_of(ms, struct callchain_list, ms); 340 struct callchain_list *cl = container_of(ms, struct callchain_list, ms);
299 bool has_children; 341 bool has_children;
300 342
343 if (!he || !ms)
344 return false;
345
301 if (ms == &he->ms) 346 if (ms == &he->ms)
302 has_children = hist_entry__toggle_fold(he); 347 has_children = hist_entry__toggle_fold(he);
303 else 348 else
@@ -435,7 +480,7 @@ static int hist_browser__run(struct hist_browser *browser, const char *help)
435 480
436 hists__browser_title(browser->hists, hbt, title, sizeof(title)); 481 hists__browser_title(browser->hists, hbt, title, sizeof(title));
437 482
438 if (ui_browser__show(&browser->b, title, help) < 0) 483 if (ui_browser__show(&browser->b, title, "%s", help) < 0)
439 return -1; 484 return -1;
440 485
441 while (1) { 486 while (1) {
@@ -574,6 +619,231 @@ static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_u
574 619
575#define LEVEL_OFFSET_STEP 3 620#define LEVEL_OFFSET_STEP 3
576 621
622static int hist_browser__show_callchain_list(struct hist_browser *browser,
623 struct callchain_node *node,
624 struct callchain_list *chain,
625 unsigned short row, u64 total,
626 bool need_percent, int offset,
627 print_callchain_entry_fn print,
628 struct callchain_print_arg *arg)
629{
630 char bf[1024], *alloc_str;
631 const char *str;
632
633 if (arg->row_offset != 0) {
634 arg->row_offset--;
635 return 0;
636 }
637
638 alloc_str = NULL;
639 str = callchain_list__sym_name(chain, bf, sizeof(bf),
640 browser->show_dso);
641
642 if (need_percent) {
643 char buf[64];
644
645 callchain_node__scnprintf_value(node, buf, sizeof(buf),
646 total);
647
648 if (asprintf(&alloc_str, "%s %s", buf, str) < 0)
649 str = "Not enough memory!";
650 else
651 str = alloc_str;
652 }
653
654 print(browser, chain, str, offset, row, arg);
655
656 free(alloc_str);
657 return 1;
658}
659
660static int hist_browser__show_callchain_flat(struct hist_browser *browser,
661 struct rb_root *root,
662 unsigned short row, u64 total,
663 print_callchain_entry_fn print,
664 struct callchain_print_arg *arg,
665 check_output_full_fn is_output_full)
666{
667 struct rb_node *node;
668 int first_row = row, offset = LEVEL_OFFSET_STEP;
669 bool need_percent;
670
671 node = rb_first(root);
672 need_percent = node && rb_next(node);
673
674 while (node) {
675 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
676 struct rb_node *next = rb_next(node);
677 struct callchain_list *chain;
678 char folded_sign = ' ';
679 int first = true;
680 int extra_offset = 0;
681
682 list_for_each_entry(chain, &child->parent_val, list) {
683 bool was_first = first;
684
685 if (first)
686 first = false;
687 else if (need_percent)
688 extra_offset = LEVEL_OFFSET_STEP;
689
690 folded_sign = callchain_list__folded(chain);
691
692 row += hist_browser__show_callchain_list(browser, child,
693 chain, row, total,
694 was_first && need_percent,
695 offset + extra_offset,
696 print, arg);
697
698 if (is_output_full(browser, row))
699 goto out;
700
701 if (folded_sign == '+')
702 goto next;
703 }
704
705 list_for_each_entry(chain, &child->val, list) {
706 bool was_first = first;
707
708 if (first)
709 first = false;
710 else if (need_percent)
711 extra_offset = LEVEL_OFFSET_STEP;
712
713 folded_sign = callchain_list__folded(chain);
714
715 row += hist_browser__show_callchain_list(browser, child,
716 chain, row, total,
717 was_first && need_percent,
718 offset + extra_offset,
719 print, arg);
720
721 if (is_output_full(browser, row))
722 goto out;
723
724 if (folded_sign == '+')
725 break;
726 }
727
728next:
729 if (is_output_full(browser, row))
730 break;
731 node = next;
732 }
733out:
734 return row - first_row;
735}
736
737static char *hist_browser__folded_callchain_str(struct hist_browser *browser,
738 struct callchain_list *chain,
739 char *value_str, char *old_str)
740{
741 char bf[1024];
742 const char *str;
743 char *new;
744
745 str = callchain_list__sym_name(chain, bf, sizeof(bf),
746 browser->show_dso);
747 if (old_str) {
748 if (asprintf(&new, "%s%s%s", old_str,
749 symbol_conf.field_sep ?: ";", str) < 0)
750 new = NULL;
751 } else {
752 if (value_str) {
753 if (asprintf(&new, "%s %s", value_str, str) < 0)
754 new = NULL;
755 } else {
756 if (asprintf(&new, "%s", str) < 0)
757 new = NULL;
758 }
759 }
760 return new;
761}
762
763static int hist_browser__show_callchain_folded(struct hist_browser *browser,
764 struct rb_root *root,
765 unsigned short row, u64 total,
766 print_callchain_entry_fn print,
767 struct callchain_print_arg *arg,
768 check_output_full_fn is_output_full)
769{
770 struct rb_node *node;
771 int first_row = row, offset = LEVEL_OFFSET_STEP;
772 bool need_percent;
773
774 node = rb_first(root);
775 need_percent = node && rb_next(node);
776
777 while (node) {
778 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
779 struct rb_node *next = rb_next(node);
780 struct callchain_list *chain, *first_chain = NULL;
781 int first = true;
782 char *value_str = NULL, *value_str_alloc = NULL;
783 char *chain_str = NULL, *chain_str_alloc = NULL;
784
785 if (arg->row_offset != 0) {
786 arg->row_offset--;
787 goto next;
788 }
789
790 if (need_percent) {
791 char buf[64];
792
793 callchain_node__scnprintf_value(child, buf, sizeof(buf), total);
794 if (asprintf(&value_str, "%s", buf) < 0) {
795 value_str = (char *)"<...>";
796 goto do_print;
797 }
798 value_str_alloc = value_str;
799 }
800
801 list_for_each_entry(chain, &child->parent_val, list) {
802 chain_str = hist_browser__folded_callchain_str(browser,
803 chain, value_str, chain_str);
804 if (first) {
805 first = false;
806 first_chain = chain;
807 }
808
809 if (chain_str == NULL) {
810 chain_str = (char *)"Not enough memory!";
811 goto do_print;
812 }
813
814 chain_str_alloc = chain_str;
815 }
816
817 list_for_each_entry(chain, &child->val, list) {
818 chain_str = hist_browser__folded_callchain_str(browser,
819 chain, value_str, chain_str);
820 if (first) {
821 first = false;
822 first_chain = chain;
823 }
824
825 if (chain_str == NULL) {
826 chain_str = (char *)"Not enough memory!";
827 goto do_print;
828 }
829
830 chain_str_alloc = chain_str;
831 }
832
833do_print:
834 print(browser, first_chain, chain_str, offset, row++, arg);
835 free(value_str_alloc);
836 free(chain_str_alloc);
837
838next:
839 if (is_output_full(browser, row))
840 break;
841 node = next;
842 }
843
844 return row - first_row;
845}
846
577static int hist_browser__show_callchain(struct hist_browser *browser, 847static int hist_browser__show_callchain(struct hist_browser *browser,
578 struct rb_root *root, int level, 848 struct rb_root *root, int level,
579 unsigned short row, u64 total, 849 unsigned short row, u64 total,
@@ -592,15 +862,12 @@ static int hist_browser__show_callchain(struct hist_browser *browser,
592 while (node) { 862 while (node) {
593 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); 863 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
594 struct rb_node *next = rb_next(node); 864 struct rb_node *next = rb_next(node);
595 u64 cumul = callchain_cumul_hits(child);
596 struct callchain_list *chain; 865 struct callchain_list *chain;
597 char folded_sign = ' '; 866 char folded_sign = ' ';
598 int first = true; 867 int first = true;
599 int extra_offset = 0; 868 int extra_offset = 0;
600 869
601 list_for_each_entry(chain, &child->val, list) { 870 list_for_each_entry(chain, &child->val, list) {
602 char bf[1024], *alloc_str;
603 const char *str;
604 bool was_first = first; 871 bool was_first = first;
605 872
606 if (first) 873 if (first)
@@ -609,31 +876,16 @@ static int hist_browser__show_callchain(struct hist_browser *browser,
609 extra_offset = LEVEL_OFFSET_STEP; 876 extra_offset = LEVEL_OFFSET_STEP;
610 877
611 folded_sign = callchain_list__folded(chain); 878 folded_sign = callchain_list__folded(chain);
612 if (arg->row_offset != 0) {
613 arg->row_offset--;
614 goto do_next;
615 }
616
617 alloc_str = NULL;
618 str = callchain_list__sym_name(chain, bf, sizeof(bf),
619 browser->show_dso);
620
621 if (was_first && need_percent) {
622 double percent = cumul * 100.0 / total;
623 879
624 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0) 880 row += hist_browser__show_callchain_list(browser, child,
625 str = "Not enough memory!"; 881 chain, row, total,
626 else 882 was_first && need_percent,
627 str = alloc_str; 883 offset + extra_offset,
628 } 884 print, arg);
629
630 print(browser, chain, str, offset + extra_offset, row, arg);
631 885
632 free(alloc_str); 886 if (is_output_full(browser, row))
633
634 if (is_output_full(browser, ++row))
635 goto out; 887 goto out;
636do_next: 888
637 if (folded_sign == '+') 889 if (folded_sign == '+')
638 break; 890 break;
639 } 891 }
@@ -789,7 +1041,8 @@ static int hist_browser__show_entry(struct hist_browser *browser,
789 hist_browser__gotorc(browser, row, 0); 1041 hist_browser__gotorc(browser, row, 0);
790 1042
791 perf_hpp__for_each_format(fmt) { 1043 perf_hpp__for_each_format(fmt) {
792 if (perf_hpp__should_skip(fmt) || column++ < browser->b.horiz_scroll) 1044 if (perf_hpp__should_skip(fmt, entry->hists) ||
1045 column++ < browser->b.horiz_scroll)
793 continue; 1046 continue;
794 1047
795 if (current_entry && browser->b.navkeypressed) { 1048 if (current_entry && browser->b.navkeypressed) {
@@ -844,10 +1097,22 @@ static int hist_browser__show_entry(struct hist_browser *browser,
844 total = entry->stat.period; 1097 total = entry->stat.period;
845 } 1098 }
846 1099
847 printed += hist_browser__show_callchain(browser, 1100 if (callchain_param.mode == CHAIN_FLAT) {
1101 printed += hist_browser__show_callchain_flat(browser,
1102 &entry->sorted_chain, row, total,
1103 hist_browser__show_callchain_entry, &arg,
1104 hist_browser__check_output_full);
1105 } else if (callchain_param.mode == CHAIN_FOLDED) {
1106 printed += hist_browser__show_callchain_folded(browser,
1107 &entry->sorted_chain, row, total,
1108 hist_browser__show_callchain_entry, &arg,
1109 hist_browser__check_output_full);
1110 } else {
1111 printed += hist_browser__show_callchain(browser,
848 &entry->sorted_chain, 1, row, total, 1112 &entry->sorted_chain, 1, row, total,
849 hist_browser__show_callchain_entry, &arg, 1113 hist_browser__show_callchain_entry, &arg,
850 hist_browser__check_output_full); 1114 hist_browser__check_output_full);
1115 }
851 1116
852 if (arg.is_current_entry) 1117 if (arg.is_current_entry)
853 browser->he_selection = entry; 1118 browser->he_selection = entry;
@@ -880,7 +1145,7 @@ static int hists_browser__scnprintf_headers(struct hist_browser *browser, char *
880 } 1145 }
881 1146
882 perf_hpp__for_each_format(fmt) { 1147 perf_hpp__for_each_format(fmt) {
883 if (perf_hpp__should_skip(fmt) || column++ < browser->b.horiz_scroll) 1148 if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll)
884 continue; 1149 continue;
885 1150
886 ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists)); 1151 ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
@@ -928,6 +1193,8 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)
928 } 1193 }
929 1194
930 ui_browser__hists_init_top(browser); 1195 ui_browser__hists_init_top(browser);
1196 hb->he_selection = NULL;
1197 hb->selection = NULL;
931 1198
932 for (nd = browser->top; nd; nd = rb_next(nd)) { 1199 for (nd = browser->top; nd; nd = rb_next(nd)) {
933 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1200 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
@@ -1033,6 +1300,9 @@ static void ui_browser__hists_seek(struct ui_browser *browser,
1033 * and stop when we printed enough lines to fill the screen. 1300 * and stop when we printed enough lines to fill the screen.
1034 */ 1301 */
1035do_offset: 1302do_offset:
1303 if (!nd)
1304 return;
1305
1036 if (offset > 0) { 1306 if (offset > 0) {
1037 do { 1307 do {
1038 h = rb_entry(nd, struct hist_entry, rb_node); 1308 h = rb_entry(nd, struct hist_entry, rb_node);
@@ -1145,7 +1415,7 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser,
1145 printed += fprintf(fp, "%c ", folded_sign); 1415 printed += fprintf(fp, "%c ", folded_sign);
1146 1416
1147 perf_hpp__for_each_format(fmt) { 1417 perf_hpp__for_each_format(fmt) {
1148 if (perf_hpp__should_skip(fmt)) 1418 if (perf_hpp__should_skip(fmt, he->hists))
1149 continue; 1419 continue;
1150 1420
1151 if (!first) { 1421 if (!first) {
@@ -1430,7 +1700,6 @@ close_file_and_continue:
1430 1700
1431struct popup_action { 1701struct popup_action {
1432 struct thread *thread; 1702 struct thread *thread;
1433 struct dso *dso;
1434 struct map_symbol ms; 1703 struct map_symbol ms;
1435 int socket; 1704 int socket;
1436 1705
@@ -1565,7 +1834,6 @@ add_dso_opt(struct hist_browser *browser, struct popup_action *act,
1565 return 0; 1834 return 0;
1566 1835
1567 act->ms.map = map; 1836 act->ms.map = map;
1568 act->dso = map->dso;
1569 act->fn = do_zoom_dso; 1837 act->fn = do_zoom_dso;
1570 return 1; 1838 return 1;
1571} 1839}
@@ -1796,10 +2064,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1796 SLang_reset_tty(); 2064 SLang_reset_tty();
1797 SLang_init_tty(0, 0, 0); 2065 SLang_init_tty(0, 0, 0);
1798 2066
1799 if (min_pcnt) { 2067 if (min_pcnt)
1800 browser->min_pcnt = min_pcnt; 2068 browser->min_pcnt = min_pcnt;
1801 hist_browser__update_nr_entries(browser); 2069 hist_browser__update_nr_entries(browser);
1802 }
1803 2070
1804 browser->pstack = pstack__new(3); 2071 browser->pstack = pstack__new(3);
1805 if (browser->pstack == NULL) 2072 if (browser->pstack == NULL)
@@ -1827,7 +2094,6 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1827 2094
1828 while (1) { 2095 while (1) {
1829 struct thread *thread = NULL; 2096 struct thread *thread = NULL;
1830 struct dso *dso = NULL;
1831 struct map *map = NULL; 2097 struct map *map = NULL;
1832 int choice = 0; 2098 int choice = 0;
1833 int socked_id = -1; 2099 int socked_id = -1;
@@ -1839,8 +2105,6 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1839 if (browser->he_selection != NULL) { 2105 if (browser->he_selection != NULL) {
1840 thread = hist_browser__selected_thread(browser); 2106 thread = hist_browser__selected_thread(browser);
1841 map = browser->selection->map; 2107 map = browser->selection->map;
1842 if (map)
1843 dso = map->dso;
1844 socked_id = browser->he_selection->socket; 2108 socked_id = browser->he_selection->socket;
1845 } 2109 }
1846 switch (key) { 2110 switch (key) {
@@ -1874,7 +2138,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1874 hist_browser__dump(browser); 2138 hist_browser__dump(browser);
1875 continue; 2139 continue;
1876 case 'd': 2140 case 'd':
1877 actions->dso = dso; 2141 actions->ms.map = map;
1878 do_zoom_dso(browser, actions); 2142 do_zoom_dso(browser, actions);
1879 continue; 2143 continue;
1880 case 'V': 2144 case 'V':
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c
index 4b3585eed1e8..0f8dcfdfb10f 100644
--- a/tools/perf/ui/gtk/hists.c
+++ b/tools/perf/ui/gtk/hists.c
@@ -89,8 +89,8 @@ void perf_gtk__init_hpp(void)
89 perf_gtk__hpp_color_overhead_acc; 89 perf_gtk__hpp_color_overhead_acc;
90} 90}
91 91
92static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store, 92static void perf_gtk__add_callchain_flat(struct rb_root *root, GtkTreeStore *store,
93 GtkTreeIter *parent, int col, u64 total) 93 GtkTreeIter *parent, int col, u64 total)
94{ 94{
95 struct rb_node *nd; 95 struct rb_node *nd;
96 bool has_single_node = (rb_first(root) == rb_last(root)); 96 bool has_single_node = (rb_first(root) == rb_last(root));
@@ -100,13 +100,132 @@ static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store,
100 struct callchain_list *chain; 100 struct callchain_list *chain;
101 GtkTreeIter iter, new_parent; 101 GtkTreeIter iter, new_parent;
102 bool need_new_parent; 102 bool need_new_parent;
103 double percent;
104 u64 hits, child_total;
105 103
106 node = rb_entry(nd, struct callchain_node, rb_node); 104 node = rb_entry(nd, struct callchain_node, rb_node);
107 105
108 hits = callchain_cumul_hits(node); 106 new_parent = *parent;
109 percent = 100.0 * hits / total; 107 need_new_parent = !has_single_node;
108
109 callchain_node__make_parent_list(node);
110
111 list_for_each_entry(chain, &node->parent_val, list) {
112 char buf[128];
113
114 gtk_tree_store_append(store, &iter, &new_parent);
115
116 callchain_node__scnprintf_value(node, buf, sizeof(buf), total);
117 gtk_tree_store_set(store, &iter, 0, buf, -1);
118
119 callchain_list__sym_name(chain, buf, sizeof(buf), false);
120 gtk_tree_store_set(store, &iter, col, buf, -1);
121
122 if (need_new_parent) {
123 /*
124 * Only show the top-most symbol in a callchain
125 * if it's not the only callchain.
126 */
127 new_parent = iter;
128 need_new_parent = false;
129 }
130 }
131
132 list_for_each_entry(chain, &node->val, list) {
133 char buf[128];
134
135 gtk_tree_store_append(store, &iter, &new_parent);
136
137 callchain_node__scnprintf_value(node, buf, sizeof(buf), total);
138 gtk_tree_store_set(store, &iter, 0, buf, -1);
139
140 callchain_list__sym_name(chain, buf, sizeof(buf), false);
141 gtk_tree_store_set(store, &iter, col, buf, -1);
142
143 if (need_new_parent) {
144 /*
145 * Only show the top-most symbol in a callchain
146 * if it's not the only callchain.
147 */
148 new_parent = iter;
149 need_new_parent = false;
150 }
151 }
152 }
153}
154
155static void perf_gtk__add_callchain_folded(struct rb_root *root, GtkTreeStore *store,
156 GtkTreeIter *parent, int col, u64 total)
157{
158 struct rb_node *nd;
159
160 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
161 struct callchain_node *node;
162 struct callchain_list *chain;
163 GtkTreeIter iter;
164 char buf[64];
165 char *str, *str_alloc = NULL;
166 bool first = true;
167
168 node = rb_entry(nd, struct callchain_node, rb_node);
169
170 callchain_node__make_parent_list(node);
171
172 list_for_each_entry(chain, &node->parent_val, list) {
173 char name[1024];
174
175 callchain_list__sym_name(chain, name, sizeof(name), false);
176
177 if (asprintf(&str, "%s%s%s",
178 first ? "" : str_alloc,
179 first ? "" : symbol_conf.field_sep ?: "; ",
180 name) < 0)
181 return;
182
183 first = false;
184 free(str_alloc);
185 str_alloc = str;
186 }
187
188 list_for_each_entry(chain, &node->val, list) {
189 char name[1024];
190
191 callchain_list__sym_name(chain, name, sizeof(name), false);
192
193 if (asprintf(&str, "%s%s%s",
194 first ? "" : str_alloc,
195 first ? "" : symbol_conf.field_sep ?: "; ",
196 name) < 0)
197 return;
198
199 first = false;
200 free(str_alloc);
201 str_alloc = str;
202 }
203
204 gtk_tree_store_append(store, &iter, parent);
205
206 callchain_node__scnprintf_value(node, buf, sizeof(buf), total);
207 gtk_tree_store_set(store, &iter, 0, buf, -1);
208
209 gtk_tree_store_set(store, &iter, col, str, -1);
210
211 free(str_alloc);
212 }
213}
214
215static void perf_gtk__add_callchain_graph(struct rb_root *root, GtkTreeStore *store,
216 GtkTreeIter *parent, int col, u64 total)
217{
218 struct rb_node *nd;
219 bool has_single_node = (rb_first(root) == rb_last(root));
220
221 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
222 struct callchain_node *node;
223 struct callchain_list *chain;
224 GtkTreeIter iter, new_parent;
225 bool need_new_parent;
226 u64 child_total;
227
228 node = rb_entry(nd, struct callchain_node, rb_node);
110 229
111 new_parent = *parent; 230 new_parent = *parent;
112 need_new_parent = !has_single_node && (node->val_nr > 1); 231 need_new_parent = !has_single_node && (node->val_nr > 1);
@@ -116,7 +235,7 @@ static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store,
116 235
117 gtk_tree_store_append(store, &iter, &new_parent); 236 gtk_tree_store_append(store, &iter, &new_parent);
118 237
119 scnprintf(buf, sizeof(buf), "%5.2f%%", percent); 238 callchain_node__scnprintf_value(node, buf, sizeof(buf), total);
120 gtk_tree_store_set(store, &iter, 0, buf, -1); 239 gtk_tree_store_set(store, &iter, 0, buf, -1);
121 240
122 callchain_list__sym_name(chain, buf, sizeof(buf), false); 241 callchain_list__sym_name(chain, buf, sizeof(buf), false);
@@ -138,11 +257,22 @@ static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store,
138 child_total = total; 257 child_total = total;
139 258
140 /* Now 'iter' contains info of the last callchain_list */ 259 /* Now 'iter' contains info of the last callchain_list */
141 perf_gtk__add_callchain(&node->rb_root, store, &iter, col, 260 perf_gtk__add_callchain_graph(&node->rb_root, store, &iter, col,
142 child_total); 261 child_total);
143 } 262 }
144} 263}
145 264
265static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store,
266 GtkTreeIter *parent, int col, u64 total)
267{
268 if (callchain_param.mode == CHAIN_FLAT)
269 perf_gtk__add_callchain_flat(root, store, parent, col, total);
270 else if (callchain_param.mode == CHAIN_FOLDED)
271 perf_gtk__add_callchain_folded(root, store, parent, col, total);
272 else
273 perf_gtk__add_callchain_graph(root, store, parent, col, total);
274}
275
146static void on_row_activated(GtkTreeView *view, GtkTreePath *path, 276static void on_row_activated(GtkTreeView *view, GtkTreePath *path,
147 GtkTreeViewColumn *col __maybe_unused, 277 GtkTreeViewColumn *col __maybe_unused,
148 gpointer user_data __maybe_unused) 278 gpointer user_data __maybe_unused)
@@ -188,7 +318,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
188 col_idx = 0; 318 col_idx = 0;
189 319
190 perf_hpp__for_each_format(fmt) { 320 perf_hpp__for_each_format(fmt) {
191 if (perf_hpp__should_skip(fmt)) 321 if (perf_hpp__should_skip(fmt, hists))
192 continue; 322 continue;
193 323
194 /* 324 /*
@@ -238,7 +368,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
238 col_idx = 0; 368 col_idx = 0;
239 369
240 perf_hpp__for_each_format(fmt) { 370 perf_hpp__for_each_format(fmt) {
241 if (perf_hpp__should_skip(fmt)) 371 if (perf_hpp__should_skip(fmt, h->hists))
242 continue; 372 continue;
243 373
244 if (fmt->color) 374 if (fmt->color)
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index 5029ba2b55af..bf2a66e254ea 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -443,7 +443,6 @@ LIST_HEAD(perf_hpp__sort_list);
443 443
444void perf_hpp__init(void) 444void perf_hpp__init(void)
445{ 445{
446 struct list_head *list;
447 int i; 446 int i;
448 447
449 for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { 448 for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
@@ -484,17 +483,6 @@ void perf_hpp__init(void)
484 483
485 if (symbol_conf.show_total_period) 484 if (symbol_conf.show_total_period)
486 hpp_dimension__add_output(PERF_HPP__PERIOD); 485 hpp_dimension__add_output(PERF_HPP__PERIOD);
487
488 /* prepend overhead field for backward compatiblity. */
489 list = &perf_hpp__format[PERF_HPP__OVERHEAD].sort_list;
490 if (list_empty(list))
491 list_add(list, &perf_hpp__sort_list);
492
493 if (symbol_conf.cumulate_callchain) {
494 list = &perf_hpp__format[PERF_HPP__OVERHEAD_ACC].sort_list;
495 if (list_empty(list))
496 list_add(list, &perf_hpp__sort_list);
497 }
498} 486}
499 487
500void perf_hpp__column_register(struct perf_hpp_fmt *format) 488void perf_hpp__column_register(struct perf_hpp_fmt *format)
@@ -619,7 +607,7 @@ unsigned int hists__sort_list_width(struct hists *hists)
619 struct perf_hpp dummy_hpp; 607 struct perf_hpp dummy_hpp;
620 608
621 perf_hpp__for_each_format(fmt) { 609 perf_hpp__for_each_format(fmt) {
622 if (perf_hpp__should_skip(fmt)) 610 if (perf_hpp__should_skip(fmt, hists))
623 continue; 611 continue;
624 612
625 if (first) 613 if (first)
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index dfcbc90146ef..387110d50b00 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -34,10 +34,10 @@ static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
34 return ret; 34 return ret;
35} 35}
36 36
37static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, 37static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_node *node,
38 struct callchain_list *chain,
38 int depth, int depth_mask, int period, 39 int depth, int depth_mask, int period,
39 u64 total_samples, u64 hits, 40 u64 total_samples, int left_margin)
40 int left_margin)
41{ 41{
42 int i; 42 int i;
43 size_t ret = 0; 43 size_t ret = 0;
@@ -50,10 +50,9 @@ static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
50 else 50 else
51 ret += fprintf(fp, " "); 51 ret += fprintf(fp, " ");
52 if (!period && i == depth - 1) { 52 if (!period && i == depth - 1) {
53 double percent; 53 ret += fprintf(fp, "--");
54 54 ret += callchain_node__fprintf_value(node, fp, total_samples);
55 percent = hits * 100.0 / total_samples; 55 ret += fprintf(fp, "--");
56 ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
57 } else 56 } else
58 ret += fprintf(fp, "%s", " "); 57 ret += fprintf(fp, "%s", " ");
59 } 58 }
@@ -82,13 +81,14 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root,
82 int depth_mask, int left_margin) 81 int depth_mask, int left_margin)
83{ 82{
84 struct rb_node *node, *next; 83 struct rb_node *node, *next;
85 struct callchain_node *child; 84 struct callchain_node *child = NULL;
86 struct callchain_list *chain; 85 struct callchain_list *chain;
87 int new_depth_mask = depth_mask; 86 int new_depth_mask = depth_mask;
88 u64 remaining; 87 u64 remaining;
89 size_t ret = 0; 88 size_t ret = 0;
90 int i; 89 int i;
91 uint entries_printed = 0; 90 uint entries_printed = 0;
91 int cumul_count = 0;
92 92
93 remaining = total_samples; 93 remaining = total_samples;
94 94
@@ -100,6 +100,7 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root,
100 child = rb_entry(node, struct callchain_node, rb_node); 100 child = rb_entry(node, struct callchain_node, rb_node);
101 cumul = callchain_cumul_hits(child); 101 cumul = callchain_cumul_hits(child);
102 remaining -= cumul; 102 remaining -= cumul;
103 cumul_count += callchain_cumul_counts(child);
103 104
104 /* 105 /*
105 * The depth mask manages the output of pipes that show 106 * The depth mask manages the output of pipes that show
@@ -120,10 +121,9 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root,
120 left_margin); 121 left_margin);
121 i = 0; 122 i = 0;
122 list_for_each_entry(chain, &child->val, list) { 123 list_for_each_entry(chain, &child->val, list) {
123 ret += ipchain__fprintf_graph(fp, chain, depth, 124 ret += ipchain__fprintf_graph(fp, child, chain, depth,
124 new_depth_mask, i++, 125 new_depth_mask, i++,
125 total_samples, 126 total_samples,
126 cumul,
127 left_margin); 127 left_margin);
128 } 128 }
129 129
@@ -143,14 +143,23 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root,
143 143
144 if (callchain_param.mode == CHAIN_GRAPH_REL && 144 if (callchain_param.mode == CHAIN_GRAPH_REL &&
145 remaining && remaining != total_samples) { 145 remaining && remaining != total_samples) {
146 struct callchain_node rem_node = {
147 .hit = remaining,
148 };
146 149
147 if (!rem_sq_bracket) 150 if (!rem_sq_bracket)
148 return ret; 151 return ret;
149 152
153 if (callchain_param.value == CCVAL_COUNT && child && child->parent) {
154 rem_node.count = child->parent->children_count - cumul_count;
155 if (rem_node.count <= 0)
156 return ret;
157 }
158
150 new_depth_mask &= ~(1 << (depth - 1)); 159 new_depth_mask &= ~(1 << (depth - 1));
151 ret += ipchain__fprintf_graph(fp, &rem_hits, depth, 160 ret += ipchain__fprintf_graph(fp, &rem_node, &rem_hits, depth,
152 new_depth_mask, 0, total_samples, 161 new_depth_mask, 0, total_samples,
153 remaining, left_margin); 162 left_margin);
154 } 163 }
155 164
156 return ret; 165 return ret;
@@ -243,12 +252,11 @@ static size_t callchain__fprintf_flat(FILE *fp, struct rb_root *tree,
243 struct rb_node *rb_node = rb_first(tree); 252 struct rb_node *rb_node = rb_first(tree);
244 253
245 while (rb_node) { 254 while (rb_node) {
246 double percent;
247
248 chain = rb_entry(rb_node, struct callchain_node, rb_node); 255 chain = rb_entry(rb_node, struct callchain_node, rb_node);
249 percent = chain->hit * 100.0 / total_samples;
250 256
251 ret = percent_color_fprintf(fp, " %6.2f%%\n", percent); 257 ret += fprintf(fp, " ");
258 ret += callchain_node__fprintf_value(chain, fp, total_samples);
259 ret += fprintf(fp, "\n");
252 ret += __callchain__fprintf_flat(fp, chain, total_samples); 260 ret += __callchain__fprintf_flat(fp, chain, total_samples);
253 ret += fprintf(fp, "\n"); 261 ret += fprintf(fp, "\n");
254 if (++entries_printed == callchain_param.print_limit) 262 if (++entries_printed == callchain_param.print_limit)
@@ -260,6 +268,57 @@ static size_t callchain__fprintf_flat(FILE *fp, struct rb_root *tree,
260 return ret; 268 return ret;
261} 269}
262 270
271static size_t __callchain__fprintf_folded(FILE *fp, struct callchain_node *node)
272{
273 const char *sep = symbol_conf.field_sep ?: ";";
274 struct callchain_list *chain;
275 size_t ret = 0;
276 char bf[1024];
277 bool first;
278
279 if (!node)
280 return 0;
281
282 ret += __callchain__fprintf_folded(fp, node->parent);
283
284 first = (ret == 0);
285 list_for_each_entry(chain, &node->val, list) {
286 if (chain->ip >= PERF_CONTEXT_MAX)
287 continue;
288 ret += fprintf(fp, "%s%s", first ? "" : sep,
289 callchain_list__sym_name(chain,
290 bf, sizeof(bf), false));
291 first = false;
292 }
293
294 return ret;
295}
296
297static size_t callchain__fprintf_folded(FILE *fp, struct rb_root *tree,
298 u64 total_samples)
299{
300 size_t ret = 0;
301 u32 entries_printed = 0;
302 struct callchain_node *chain;
303 struct rb_node *rb_node = rb_first(tree);
304
305 while (rb_node) {
306
307 chain = rb_entry(rb_node, struct callchain_node, rb_node);
308
309 ret += callchain_node__fprintf_value(chain, fp, total_samples);
310 ret += fprintf(fp, " ");
311 ret += __callchain__fprintf_folded(fp, chain);
312 ret += fprintf(fp, "\n");
313 if (++entries_printed == callchain_param.print_limit)
314 break;
315
316 rb_node = rb_next(rb_node);
317 }
318
319 return ret;
320}
321
263static size_t hist_entry_callchain__fprintf(struct hist_entry *he, 322static size_t hist_entry_callchain__fprintf(struct hist_entry *he,
264 u64 total_samples, int left_margin, 323 u64 total_samples, int left_margin,
265 FILE *fp) 324 FILE *fp)
@@ -278,6 +337,9 @@ static size_t hist_entry_callchain__fprintf(struct hist_entry *he,
278 case CHAIN_FLAT: 337 case CHAIN_FLAT:
279 return callchain__fprintf_flat(fp, &he->sorted_chain, total_samples); 338 return callchain__fprintf_flat(fp, &he->sorted_chain, total_samples);
280 break; 339 break;
340 case CHAIN_FOLDED:
341 return callchain__fprintf_folded(fp, &he->sorted_chain, total_samples);
342 break;
281 case CHAIN_NONE: 343 case CHAIN_NONE:
282 break; 344 break;
283 default: 345 default:
@@ -323,7 +385,7 @@ static int hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp)
323 return 0; 385 return 0;
324 386
325 perf_hpp__for_each_format(fmt) { 387 perf_hpp__for_each_format(fmt) {
326 if (perf_hpp__should_skip(fmt)) 388 if (perf_hpp__should_skip(fmt, he->hists))
327 continue; 389 continue;
328 390
329 /* 391 /*
@@ -402,7 +464,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
402 fprintf(fp, "# "); 464 fprintf(fp, "# ");
403 465
404 perf_hpp__for_each_format(fmt) { 466 perf_hpp__for_each_format(fmt) {
405 if (perf_hpp__should_skip(fmt)) 467 if (perf_hpp__should_skip(fmt, hists))
406 continue; 468 continue;
407 469
408 if (!first) 470 if (!first)
@@ -428,7 +490,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
428 perf_hpp__for_each_format(fmt) { 490 perf_hpp__for_each_format(fmt) {
429 unsigned int i; 491 unsigned int i;
430 492
431 if (perf_hpp__should_skip(fmt)) 493 if (perf_hpp__should_skip(fmt, hists))
432 continue; 494 continue;
433 495
434 if (!first) 496 if (!first)
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index 591b3fe3ed49..5eec53a3f4ac 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -6,24 +6,20 @@ libperf-y += config.o
6libperf-y += ctype.o 6libperf-y += ctype.o
7libperf-y += db-export.o 7libperf-y += db-export.o
8libperf-y += env.o 8libperf-y += env.o
9libperf-y += environment.o
10libperf-y += event.o 9libperf-y += event.o
11libperf-y += evlist.o 10libperf-y += evlist.o
12libperf-y += evsel.o 11libperf-y += evsel.o
13libperf-y += exec_cmd.o 12libperf-y += find_bit.o
14libperf-y += find_next_bit.o
15libperf-y += help.o
16libperf-y += kallsyms.o 13libperf-y += kallsyms.o
17libperf-y += levenshtein.o 14libperf-y += levenshtein.o
18libperf-y += llvm-utils.o 15libperf-y += llvm-utils.o
19libperf-y += parse-options.o
20libperf-y += parse-events.o 16libperf-y += parse-events.o
21libperf-y += perf_regs.o 17libperf-y += perf_regs.o
22libperf-y += path.o 18libperf-y += path.o
23libperf-y += rbtree.o 19libperf-y += rbtree.o
20libperf-y += libstring.o
24libperf-y += bitmap.o 21libperf-y += bitmap.o
25libperf-y += hweight.o 22libperf-y += hweight.o
26libperf-y += run-command.o
27libperf-y += quote.o 23libperf-y += quote.o
28libperf-y += strbuf.o 24libperf-y += strbuf.o
29libperf-y += string.o 25libperf-y += string.o
@@ -32,11 +28,9 @@ libperf-y += strfilter.o
32libperf-y += top.o 28libperf-y += top.o
33libperf-y += usage.o 29libperf-y += usage.o
34libperf-y += wrapper.o 30libperf-y += wrapper.o
35libperf-y += sigchain.o
36libperf-y += dso.o 31libperf-y += dso.o
37libperf-y += symbol.o 32libperf-y += symbol.o
38libperf-y += color.o 33libperf-y += color.o
39libperf-y += pager.o
40libperf-y += header.o 34libperf-y += header.o
41libperf-y += callchain.o 35libperf-y += callchain.o
42libperf-y += values.o 36libperf-y += values.o
@@ -86,8 +80,11 @@ libperf-$(CONFIG_AUXTRACE) += intel-pt.o
86libperf-$(CONFIG_AUXTRACE) += intel-bts.o 80libperf-$(CONFIG_AUXTRACE) += intel-bts.o
87libperf-y += parse-branch-options.o 81libperf-y += parse-branch-options.o
88libperf-y += parse-regs-options.o 82libperf-y += parse-regs-options.o
83libperf-y += term.o
84libperf-y += help-unknown-cmd.o
89 85
90libperf-$(CONFIG_LIBBPF) += bpf-loader.o 86libperf-$(CONFIG_LIBBPF) += bpf-loader.o
87libperf-$(CONFIG_BPF_PROLOGUE) += bpf-prologue.o
91libperf-$(CONFIG_LIBELF) += symbol-elf.o 88libperf-$(CONFIG_LIBELF) += symbol-elf.o
92libperf-$(CONFIG_LIBELF) += probe-file.o 89libperf-$(CONFIG_LIBELF) += probe-file.o
93libperf-$(CONFIG_LIBELF) += probe-event.o 90libperf-$(CONFIG_LIBELF) += probe-event.o
@@ -110,7 +107,6 @@ libperf-$(CONFIG_ZLIB) += zlib.o
110libperf-$(CONFIG_LZMA) += lzma.o 107libperf-$(CONFIG_LZMA) += lzma.o
111 108
112CFLAGS_config.o += -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))" 109CFLAGS_config.o += -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
113CFLAGS_exec_cmd.o += -DPERF_EXEC_PATH="BUILD_STR($(perfexecdir_SQ))" -DPREFIX="BUILD_STR($(prefix_SQ))"
114 110
115$(OUTPUT)util/parse-events-flex.c: util/parse-events.l $(OUTPUT)util/parse-events-bison.c 111$(OUTPUT)util/parse-events-flex.c: util/parse-events.l $(OUTPUT)util/parse-events-bison.c
116 $(call rule_mkdir) 112 $(call rule_mkdir)
@@ -136,8 +132,10 @@ CFLAGS_pmu-bison.o += -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -w
136$(OUTPUT)util/parse-events.o: $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-bison.c 132$(OUTPUT)util/parse-events.o: $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-bison.c
137$(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c 133$(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c
138 134
139CFLAGS_find_next_bit.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))" 135CFLAGS_bitmap.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
136CFLAGS_find_bit.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
140CFLAGS_rbtree.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))" 137CFLAGS_rbtree.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
138CFLAGS_libstring.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
141CFLAGS_hweight.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))" 139CFLAGS_hweight.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
142CFLAGS_parse-events.o += -Wno-redundant-decls 140CFLAGS_parse-events.o += -Wno-redundant-decls
143 141
@@ -145,7 +143,11 @@ $(OUTPUT)util/kallsyms.o: ../lib/symbol/kallsyms.c FORCE
145 $(call rule_mkdir) 143 $(call rule_mkdir)
146 $(call if_changed_dep,cc_o_c) 144 $(call if_changed_dep,cc_o_c)
147 145
148$(OUTPUT)util/find_next_bit.o: ../lib/util/find_next_bit.c FORCE 146$(OUTPUT)util/bitmap.o: ../lib/bitmap.c FORCE
147 $(call rule_mkdir)
148 $(call if_changed_dep,cc_o_c)
149
150$(OUTPUT)util/find_bit.o: ../lib/find_bit.c FORCE
149 $(call rule_mkdir) 151 $(call rule_mkdir)
150 $(call if_changed_dep,cc_o_c) 152 $(call if_changed_dep,cc_o_c)
151 153
@@ -153,6 +155,10 @@ $(OUTPUT)util/rbtree.o: ../lib/rbtree.c FORCE
153 $(call rule_mkdir) 155 $(call rule_mkdir)
154 $(call if_changed_dep,cc_o_c) 156 $(call if_changed_dep,cc_o_c)
155 157
158$(OUTPUT)util/libstring.o: ../lib/string.c FORCE
159 $(call rule_mkdir)
160 $(call if_changed_dep,cc_o_c)
161
156$(OUTPUT)util/hweight.o: ../lib/hweight.c FORCE 162$(OUTPUT)util/hweight.o: ../lib/hweight.c FORCE
157 $(call rule_mkdir) 163 $(call rule_mkdir)
158 $(call if_changed_dep,cc_o_c) 164 $(call if_changed_dep,cc_o_c)
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 1dd1949b0e79..b795b6994144 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -65,6 +65,11 @@ static int call__parse(struct ins_operands *ops)
65 65
66 name++; 66 name++;
67 67
68#ifdef __arm__
69 if (strchr(name, '+'))
70 return -1;
71#endif
72
68 tok = strchr(name, '>'); 73 tok = strchr(name, '>');
69 if (tok == NULL) 74 if (tok == NULL)
70 return -1; 75 return -1;
@@ -246,7 +251,11 @@ static int mov__parse(struct ins_operands *ops)
246 return -1; 251 return -1;
247 252
248 target = ++s; 253 target = ++s;
254#ifdef __arm__
255 comment = strchr(s, ';');
256#else
249 comment = strchr(s, '#'); 257 comment = strchr(s, '#');
258#endif
250 259
251 if (comment != NULL) 260 if (comment != NULL)
252 s = comment - 1; 261 s = comment - 1;
@@ -354,6 +363,20 @@ static struct ins instructions[] = {
354 { .name = "addq", .ops = &mov_ops, }, 363 { .name = "addq", .ops = &mov_ops, },
355 { .name = "addw", .ops = &mov_ops, }, 364 { .name = "addw", .ops = &mov_ops, },
356 { .name = "and", .ops = &mov_ops, }, 365 { .name = "and", .ops = &mov_ops, },
366#ifdef __arm__
367 { .name = "b", .ops = &jump_ops, }, // might also be a call
368 { .name = "bcc", .ops = &jump_ops, },
369 { .name = "bcs", .ops = &jump_ops, },
370 { .name = "beq", .ops = &jump_ops, },
371 { .name = "bge", .ops = &jump_ops, },
372 { .name = "bgt", .ops = &jump_ops, },
373 { .name = "bhi", .ops = &jump_ops, },
374 { .name = "bl", .ops = &call_ops, },
375 { .name = "blt", .ops = &jump_ops, },
376 { .name = "bls", .ops = &jump_ops, },
377 { .name = "blx", .ops = &call_ops, },
378 { .name = "bne", .ops = &jump_ops, },
379#endif
357 { .name = "bts", .ops = &mov_ops, }, 380 { .name = "bts", .ops = &mov_ops, },
358 { .name = "call", .ops = &call_ops, }, 381 { .name = "call", .ops = &call_ops, },
359 { .name = "callq", .ops = &call_ops, }, 382 { .name = "callq", .ops = &call_ops, },
diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
index 7f10430af39c..360fda01f3b0 100644
--- a/tools/perf/util/auxtrace.c
+++ b/tools/perf/util/auxtrace.c
@@ -45,7 +45,7 @@
45#include "event.h" 45#include "event.h"
46#include "session.h" 46#include "session.h"
47#include "debug.h" 47#include "debug.h"
48#include "parse-options.h" 48#include <subcmd/parse-options.h>
49 49
50#include "intel-pt.h" 50#include "intel-pt.h"
51#include "intel-bts.h" 51#include "intel-bts.h"
diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index 4c50411371db..540a7efa657e 100644
--- a/tools/perf/util/bpf-loader.c
+++ b/tools/perf/util/bpf-loader.c
@@ -5,11 +5,15 @@
5 * Copyright (C) 2015 Huawei Inc. 5 * Copyright (C) 2015 Huawei Inc.
6 */ 6 */
7 7
8#include <linux/bpf.h>
8#include <bpf/libbpf.h> 9#include <bpf/libbpf.h>
9#include <linux/err.h> 10#include <linux/err.h>
11#include <linux/string.h>
10#include "perf.h" 12#include "perf.h"
11#include "debug.h" 13#include "debug.h"
12#include "bpf-loader.h" 14#include "bpf-loader.h"
15#include "bpf-prologue.h"
16#include "llvm-utils.h"
13#include "probe-event.h" 17#include "probe-event.h"
14#include "probe-finder.h" // for MAX_PROBES 18#include "probe-finder.h" // for MAX_PROBES
15#include "llvm-utils.h" 19#include "llvm-utils.h"
@@ -32,6 +36,10 @@ DEFINE_PRINT_FN(debug, 1)
32 36
33struct bpf_prog_priv { 37struct bpf_prog_priv {
34 struct perf_probe_event pev; 38 struct perf_probe_event pev;
39 bool need_prologue;
40 struct bpf_insn *insns_buf;
41 int nr_types;
42 int *type_mapping;
35}; 43};
36 44
37static bool libbpf_initialized; 45static bool libbpf_initialized;
@@ -106,10 +114,178 @@ bpf_prog_priv__clear(struct bpf_program *prog __maybe_unused,
106 struct bpf_prog_priv *priv = _priv; 114 struct bpf_prog_priv *priv = _priv;
107 115
108 cleanup_perf_probe_events(&priv->pev, 1); 116 cleanup_perf_probe_events(&priv->pev, 1);
117 zfree(&priv->insns_buf);
118 zfree(&priv->type_mapping);
109 free(priv); 119 free(priv);
110} 120}
111 121
112static int 122static int
123prog_config__exec(const char *value, struct perf_probe_event *pev)
124{
125 pev->uprobes = true;
126 pev->target = strdup(value);
127 if (!pev->target)
128 return -ENOMEM;
129 return 0;
130}
131
132static int
133prog_config__module(const char *value, struct perf_probe_event *pev)
134{
135 pev->uprobes = false;
136 pev->target = strdup(value);
137 if (!pev->target)
138 return -ENOMEM;
139 return 0;
140}
141
142static int
143prog_config__bool(const char *value, bool *pbool, bool invert)
144{
145 int err;
146 bool bool_value;
147
148 if (!pbool)
149 return -EINVAL;
150
151 err = strtobool(value, &bool_value);
152 if (err)
153 return err;
154
155 *pbool = invert ? !bool_value : bool_value;
156 return 0;
157}
158
159static int
160prog_config__inlines(const char *value,
161 struct perf_probe_event *pev __maybe_unused)
162{
163 return prog_config__bool(value, &probe_conf.no_inlines, true);
164}
165
166static int
167prog_config__force(const char *value,
168 struct perf_probe_event *pev __maybe_unused)
169{
170 return prog_config__bool(value, &probe_conf.force_add, false);
171}
172
173static struct {
174 const char *key;
175 const char *usage;
176 const char *desc;
177 int (*func)(const char *, struct perf_probe_event *);
178} bpf_prog_config_terms[] = {
179 {
180 .key = "exec",
181 .usage = "exec=<full path of file>",
182 .desc = "Set uprobe target",
183 .func = prog_config__exec,
184 },
185 {
186 .key = "module",
187 .usage = "module=<module name> ",
188 .desc = "Set kprobe module",
189 .func = prog_config__module,
190 },
191 {
192 .key = "inlines",
193 .usage = "inlines=[yes|no] ",
194 .desc = "Probe at inline symbol",
195 .func = prog_config__inlines,
196 },
197 {
198 .key = "force",
199 .usage = "force=[yes|no] ",
200 .desc = "Forcibly add events with existing name",
201 .func = prog_config__force,
202 },
203};
204
205static int
206do_prog_config(const char *key, const char *value,
207 struct perf_probe_event *pev)
208{
209 unsigned int i;
210
211 pr_debug("config bpf program: %s=%s\n", key, value);
212 for (i = 0; i < ARRAY_SIZE(bpf_prog_config_terms); i++)
213 if (strcmp(key, bpf_prog_config_terms[i].key) == 0)
214 return bpf_prog_config_terms[i].func(value, pev);
215
216 pr_debug("BPF: ERROR: invalid program config option: %s=%s\n",
217 key, value);
218
219 pr_debug("\nHint: Valid options are:\n");
220 for (i = 0; i < ARRAY_SIZE(bpf_prog_config_terms); i++)
221 pr_debug("\t%s:\t%s\n", bpf_prog_config_terms[i].usage,
222 bpf_prog_config_terms[i].desc);
223 pr_debug("\n");
224
225 return -BPF_LOADER_ERRNO__PROGCONF_TERM;
226}
227
228static const char *
229parse_prog_config_kvpair(const char *config_str, struct perf_probe_event *pev)
230{
231 char *text = strdup(config_str);
232 char *sep, *line;
233 const char *main_str = NULL;
234 int err = 0;
235
236 if (!text) {
237 pr_debug("No enough memory: dup config_str failed\n");
238 return ERR_PTR(-ENOMEM);
239 }
240
241 line = text;
242 while ((sep = strchr(line, ';'))) {
243 char *equ;
244
245 *sep = '\0';
246 equ = strchr(line, '=');
247 if (!equ) {
248 pr_warning("WARNING: invalid config in BPF object: %s\n",
249 line);
250 pr_warning("\tShould be 'key=value'.\n");
251 goto nextline;
252 }
253 *equ = '\0';
254
255 err = do_prog_config(line, equ + 1, pev);
256 if (err)
257 break;
258nextline:
259 line = sep + 1;
260 }
261
262 if (!err)
263 main_str = config_str + (line - text);
264 free(text);
265
266 return err ? ERR_PTR(err) : main_str;
267}
268
269static int
270parse_prog_config(const char *config_str, struct perf_probe_event *pev)
271{
272 int err;
273 const char *main_str = parse_prog_config_kvpair(config_str, pev);
274
275 if (IS_ERR(main_str))
276 return PTR_ERR(main_str);
277
278 err = parse_perf_probe_command(main_str, pev);
279 if (err < 0) {
280 pr_debug("bpf: '%s' is not a valid config string\n",
281 config_str);
282 /* parse failed, don't need clear pev. */
283 return -BPF_LOADER_ERRNO__CONFIG;
284 }
285 return 0;
286}
287
288static int
113config_bpf_program(struct bpf_program *prog) 289config_bpf_program(struct bpf_program *prog)
114{ 290{
115 struct perf_probe_event *pev = NULL; 291 struct perf_probe_event *pev = NULL;
@@ -117,6 +293,10 @@ config_bpf_program(struct bpf_program *prog)
117 const char *config_str; 293 const char *config_str;
118 int err; 294 int err;
119 295
296 /* Initialize per-program probing setting */
297 probe_conf.no_inlines = false;
298 probe_conf.force_add = false;
299
120 config_str = bpf_program__title(prog, false); 300 config_str = bpf_program__title(prog, false);
121 if (IS_ERR(config_str)) { 301 if (IS_ERR(config_str)) {
122 pr_debug("bpf: unable to get title for program\n"); 302 pr_debug("bpf: unable to get title for program\n");
@@ -131,13 +311,9 @@ config_bpf_program(struct bpf_program *prog)
131 pev = &priv->pev; 311 pev = &priv->pev;
132 312
133 pr_debug("bpf: config program '%s'\n", config_str); 313 pr_debug("bpf: config program '%s'\n", config_str);
134 err = parse_perf_probe_command(config_str, pev); 314 err = parse_prog_config(config_str, pev);
135 if (err < 0) { 315 if (err)
136 pr_debug("bpf: '%s' is not a valid config string\n",
137 config_str);
138 err = -BPF_LOADER_ERRNO__CONFIG;
139 goto errout; 316 goto errout;
140 }
141 317
142 if (pev->group && strcmp(pev->group, PERF_BPF_PROBE_GROUP)) { 318 if (pev->group && strcmp(pev->group, PERF_BPF_PROBE_GROUP)) {
143 pr_debug("bpf: '%s': group for event is set and not '%s'.\n", 319 pr_debug("bpf: '%s': group for event is set and not '%s'.\n",
@@ -197,6 +373,220 @@ static int bpf__prepare_probe(void)
197 return err; 373 return err;
198} 374}
199 375
376static int
377preproc_gen_prologue(struct bpf_program *prog, int n,
378 struct bpf_insn *orig_insns, int orig_insns_cnt,
379 struct bpf_prog_prep_result *res)
380{
381 struct probe_trace_event *tev;
382 struct perf_probe_event *pev;
383 struct bpf_prog_priv *priv;
384 struct bpf_insn *buf;
385 size_t prologue_cnt = 0;
386 int i, err;
387
388 err = bpf_program__get_private(prog, (void **)&priv);
389 if (err || !priv)
390 goto errout;
391
392 pev = &priv->pev;
393
394 if (n < 0 || n >= priv->nr_types)
395 goto errout;
396
397 /* Find a tev belongs to that type */
398 for (i = 0; i < pev->ntevs; i++) {
399 if (priv->type_mapping[i] == n)
400 break;
401 }
402
403 if (i >= pev->ntevs) {
404 pr_debug("Internal error: prologue type %d not found\n", n);
405 return -BPF_LOADER_ERRNO__PROLOGUE;
406 }
407
408 tev = &pev->tevs[i];
409
410 buf = priv->insns_buf;
411 err = bpf__gen_prologue(tev->args, tev->nargs,
412 buf, &prologue_cnt,
413 BPF_MAXINSNS - orig_insns_cnt);
414 if (err) {
415 const char *title;
416
417 title = bpf_program__title(prog, false);
418 if (!title)
419 title = "[unknown]";
420
421 pr_debug("Failed to generate prologue for program %s\n",
422 title);
423 return err;
424 }
425
426 memcpy(&buf[prologue_cnt], orig_insns,
427 sizeof(struct bpf_insn) * orig_insns_cnt);
428
429 res->new_insn_ptr = buf;
430 res->new_insn_cnt = prologue_cnt + orig_insns_cnt;
431 res->pfd = NULL;
432 return 0;
433
434errout:
435 pr_debug("Internal error in preproc_gen_prologue\n");
436 return -BPF_LOADER_ERRNO__PROLOGUE;
437}
438
439/*
440 * compare_tev_args is reflexive, transitive and antisymmetric.
441 * I can proof it but this margin is too narrow to contain.
442 */
443static int compare_tev_args(const void *ptev1, const void *ptev2)
444{
445 int i, ret;
446 const struct probe_trace_event *tev1 =
447 *(const struct probe_trace_event **)ptev1;
448 const struct probe_trace_event *tev2 =
449 *(const struct probe_trace_event **)ptev2;
450
451 ret = tev2->nargs - tev1->nargs;
452 if (ret)
453 return ret;
454
455 for (i = 0; i < tev1->nargs; i++) {
456 struct probe_trace_arg *arg1, *arg2;
457 struct probe_trace_arg_ref *ref1, *ref2;
458
459 arg1 = &tev1->args[i];
460 arg2 = &tev2->args[i];
461
462 ret = strcmp(arg1->value, arg2->value);
463 if (ret)
464 return ret;
465
466 ref1 = arg1->ref;
467 ref2 = arg2->ref;
468
469 while (ref1 && ref2) {
470 ret = ref2->offset - ref1->offset;
471 if (ret)
472 return ret;
473
474 ref1 = ref1->next;
475 ref2 = ref2->next;
476 }
477
478 if (ref1 || ref2)
479 return ref2 ? 1 : -1;
480 }
481
482 return 0;
483}
484
485/*
486 * Assign a type number to each tevs in a pev.
487 * mapping is an array with same slots as tevs in that pev.
488 * nr_types will be set to number of types.
489 */
490static int map_prologue(struct perf_probe_event *pev, int *mapping,
491 int *nr_types)
492{
493 int i, type = 0;
494 struct probe_trace_event **ptevs;
495
496 size_t array_sz = sizeof(*ptevs) * pev->ntevs;
497
498 ptevs = malloc(array_sz);
499 if (!ptevs) {
500 pr_debug("No ehough memory: alloc ptevs failed\n");
501 return -ENOMEM;
502 }
503
504 pr_debug("In map_prologue, ntevs=%d\n", pev->ntevs);
505 for (i = 0; i < pev->ntevs; i++)
506 ptevs[i] = &pev->tevs[i];
507
508 qsort(ptevs, pev->ntevs, sizeof(*ptevs),
509 compare_tev_args);
510
511 for (i = 0; i < pev->ntevs; i++) {
512 int n;
513
514 n = ptevs[i] - pev->tevs;
515 if (i == 0) {
516 mapping[n] = type;
517 pr_debug("mapping[%d]=%d\n", n, type);
518 continue;
519 }
520
521 if (compare_tev_args(ptevs + i, ptevs + i - 1) == 0)
522 mapping[n] = type;
523 else
524 mapping[n] = ++type;
525
526 pr_debug("mapping[%d]=%d\n", n, mapping[n]);
527 }
528 free(ptevs);
529 *nr_types = type + 1;
530
531 return 0;
532}
533
534static int hook_load_preprocessor(struct bpf_program *prog)
535{
536 struct perf_probe_event *pev;
537 struct bpf_prog_priv *priv;
538 bool need_prologue = false;
539 int err, i;
540
541 err = bpf_program__get_private(prog, (void **)&priv);
542 if (err || !priv) {
543 pr_debug("Internal error when hook preprocessor\n");
544 return -BPF_LOADER_ERRNO__INTERNAL;
545 }
546
547 pev = &priv->pev;
548 for (i = 0; i < pev->ntevs; i++) {
549 struct probe_trace_event *tev = &pev->tevs[i];
550
551 if (tev->nargs > 0) {
552 need_prologue = true;
553 break;
554 }
555 }
556
557 /*
558 * Since all tevs don't have argument, we don't need generate
559 * prologue.
560 */
561 if (!need_prologue) {
562 priv->need_prologue = false;
563 return 0;
564 }
565
566 priv->need_prologue = true;
567 priv->insns_buf = malloc(sizeof(struct bpf_insn) * BPF_MAXINSNS);
568 if (!priv->insns_buf) {
569 pr_debug("No enough memory: alloc insns_buf failed\n");
570 return -ENOMEM;
571 }
572
573 priv->type_mapping = malloc(sizeof(int) * pev->ntevs);
574 if (!priv->type_mapping) {
575 pr_debug("No enough memory: alloc type_mapping failed\n");
576 return -ENOMEM;
577 }
578 memset(priv->type_mapping, -1,
579 sizeof(int) * pev->ntevs);
580
581 err = map_prologue(pev, priv->type_mapping, &priv->nr_types);
582 if (err)
583 return err;
584
585 err = bpf_program__set_prep(prog, priv->nr_types,
586 preproc_gen_prologue);
587 return err;
588}
589
200int bpf__probe(struct bpf_object *obj) 590int bpf__probe(struct bpf_object *obj)
201{ 591{
202 int err = 0; 592 int err = 0;
@@ -231,6 +621,18 @@ int bpf__probe(struct bpf_object *obj)
231 pr_debug("bpf_probe: failed to apply perf probe events"); 621 pr_debug("bpf_probe: failed to apply perf probe events");
232 goto out; 622 goto out;
233 } 623 }
624
625 /*
626 * After probing, let's consider prologue, which
627 * adds program fetcher to BPF programs.
628 *
629 * hook_load_preprocessorr() hooks pre-processor
630 * to bpf_program, let it generate prologue
631 * dynamically during loading.
632 */
633 err = hook_load_preprocessor(prog);
634 if (err)
635 goto out;
234 } 636 }
235out: 637out:
236 return err < 0 ? err : 0; 638 return err < 0 ? err : 0;
@@ -314,7 +716,14 @@ int bpf__foreach_tev(struct bpf_object *obj,
314 for (i = 0; i < pev->ntevs; i++) { 716 for (i = 0; i < pev->ntevs; i++) {
315 tev = &pev->tevs[i]; 717 tev = &pev->tevs[i];
316 718
317 fd = bpf_program__fd(prog); 719 if (priv->need_prologue) {
720 int type = priv->type_mapping[i];
721
722 fd = bpf_program__nth_fd(prog, type);
723 } else {
724 fd = bpf_program__fd(prog);
725 }
726
318 if (fd < 0) { 727 if (fd < 0) {
319 pr_debug("bpf: failed to get file descriptor\n"); 728 pr_debug("bpf: failed to get file descriptor\n");
320 return fd; 729 return fd;
@@ -340,6 +749,10 @@ static const char *bpf_loader_strerror_table[NR_ERRNO] = {
340 [ERRCODE_OFFSET(EVENTNAME)] = "No event name found in config string", 749 [ERRCODE_OFFSET(EVENTNAME)] = "No event name found in config string",
341 [ERRCODE_OFFSET(INTERNAL)] = "BPF loader internal error", 750 [ERRCODE_OFFSET(INTERNAL)] = "BPF loader internal error",
342 [ERRCODE_OFFSET(COMPILE)] = "Error when compiling BPF scriptlet", 751 [ERRCODE_OFFSET(COMPILE)] = "Error when compiling BPF scriptlet",
752 [ERRCODE_OFFSET(PROGCONF_TERM)] = "Invalid program config term in config string",
753 [ERRCODE_OFFSET(PROLOGUE)] = "Failed to generate prologue",
754 [ERRCODE_OFFSET(PROLOGUE2BIG)] = "Prologue too big for program",
755 [ERRCODE_OFFSET(PROLOGUEOOB)] = "Offset out of bound for prologue",
343}; 756};
344 757
345static int 758static int
@@ -420,7 +833,11 @@ int bpf__strerror_probe(struct bpf_object *obj __maybe_unused,
420 int err, char *buf, size_t size) 833 int err, char *buf, size_t size)
421{ 834{
422 bpf__strerror_head(err, buf, size); 835 bpf__strerror_head(err, buf, size);
423 bpf__strerror_entry(EEXIST, "Probe point exist. Try use 'perf probe -d \"*\"'"); 836 case BPF_LOADER_ERRNO__PROGCONF_TERM: {
837 scnprintf(buf, size, "%s (add -v to see detail)", emsg);
838 break;
839 }
840 bpf__strerror_entry(EEXIST, "Probe point exist. Try 'perf probe -d \"*\"' and set 'force=yes'");
424 bpf__strerror_entry(EACCES, "You need to be root"); 841 bpf__strerror_entry(EACCES, "You need to be root");
425 bpf__strerror_entry(EPERM, "You need to be root, and /proc/sys/kernel/kptr_restrict should be 0"); 842 bpf__strerror_entry(EPERM, "You need to be root, and /proc/sys/kernel/kptr_restrict should be 0");
426 bpf__strerror_entry(ENOENT, "You need to check probing points in BPF file"); 843 bpf__strerror_entry(ENOENT, "You need to check probing points in BPF file");
diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h
index 9caf3ae4acf3..6fdc0457e2b6 100644
--- a/tools/perf/util/bpf-loader.h
+++ b/tools/perf/util/bpf-loader.h
@@ -20,6 +20,10 @@ enum bpf_loader_errno {
20 BPF_LOADER_ERRNO__EVENTNAME, /* Event name is missing */ 20 BPF_LOADER_ERRNO__EVENTNAME, /* Event name is missing */
21 BPF_LOADER_ERRNO__INTERNAL, /* BPF loader internal error */ 21 BPF_LOADER_ERRNO__INTERNAL, /* BPF loader internal error */
22 BPF_LOADER_ERRNO__COMPILE, /* Error when compiling BPF scriptlet */ 22 BPF_LOADER_ERRNO__COMPILE, /* Error when compiling BPF scriptlet */
23 BPF_LOADER_ERRNO__PROGCONF_TERM,/* Invalid program config term in config string */
24 BPF_LOADER_ERRNO__PROLOGUE, /* Failed to generate prologue */
25 BPF_LOADER_ERRNO__PROLOGUE2BIG, /* Prologue too big for program */
26 BPF_LOADER_ERRNO__PROLOGUEOOB, /* Offset out of bound for prologue */
23 __BPF_LOADER_ERRNO__END, 27 __BPF_LOADER_ERRNO__END,
24}; 28};
25 29
diff --git a/tools/perf/util/bpf-prologue.c b/tools/perf/util/bpf-prologue.c
new file mode 100644
index 000000000000..6cdbee119ceb
--- /dev/null
+++ b/tools/perf/util/bpf-prologue.c
@@ -0,0 +1,455 @@
1/*
2 * bpf-prologue.c
3 *
4 * Copyright (C) 2015 He Kuang <hekuang@huawei.com>
5 * Copyright (C) 2015 Wang Nan <wangnan0@huawei.com>
6 * Copyright (C) 2015 Huawei Inc.
7 */
8
9#include <bpf/libbpf.h>
10#include "perf.h"
11#include "debug.h"
12#include "bpf-loader.h"
13#include "bpf-prologue.h"
14#include "probe-finder.h"
15#include <dwarf-regs.h>
16#include <linux/filter.h>
17
18#define BPF_REG_SIZE 8
19
20#define JMP_TO_ERROR_CODE -1
21#define JMP_TO_SUCCESS_CODE -2
22#define JMP_TO_USER_CODE -3
23
24struct bpf_insn_pos {
25 struct bpf_insn *begin;
26 struct bpf_insn *end;
27 struct bpf_insn *pos;
28};
29
30static inline int
31pos_get_cnt(struct bpf_insn_pos *pos)
32{
33 return pos->pos - pos->begin;
34}
35
36static int
37append_insn(struct bpf_insn new_insn, struct bpf_insn_pos *pos)
38{
39 if (!pos->pos)
40 return -BPF_LOADER_ERRNO__PROLOGUE2BIG;
41
42 if (pos->pos + 1 >= pos->end) {
43 pr_err("bpf prologue: prologue too long\n");
44 pos->pos = NULL;
45 return -BPF_LOADER_ERRNO__PROLOGUE2BIG;
46 }
47
48 *(pos->pos)++ = new_insn;
49 return 0;
50}
51
52static int
53check_pos(struct bpf_insn_pos *pos)
54{
55 if (!pos->pos || pos->pos >= pos->end)
56 return -BPF_LOADER_ERRNO__PROLOGUE2BIG;
57 return 0;
58}
59
60/* Give it a shorter name */
61#define ins(i, p) append_insn((i), (p))
62
63/*
64 * Give a register name (in 'reg'), generate instruction to
65 * load register into an eBPF register rd:
66 * 'ldd target_reg, offset(ctx_reg)', where:
67 * ctx_reg is pre initialized to pointer of 'struct pt_regs'.
68 */
69static int
70gen_ldx_reg_from_ctx(struct bpf_insn_pos *pos, int ctx_reg,
71 const char *reg, int target_reg)
72{
73 int offset = regs_query_register_offset(reg);
74
75 if (offset < 0) {
76 pr_err("bpf: prologue: failed to get register %s\n",
77 reg);
78 return offset;
79 }
80 ins(BPF_LDX_MEM(BPF_DW, target_reg, ctx_reg, offset), pos);
81
82 return check_pos(pos);
83}
84
85/*
86 * Generate a BPF_FUNC_probe_read function call.
87 *
88 * src_base_addr_reg is a register holding base address,
89 * dst_addr_reg is a register holding dest address (on stack),
90 * result is:
91 *
92 * *[dst_addr_reg] = *([src_base_addr_reg] + offset)
93 *
94 * Arguments of BPF_FUNC_probe_read:
95 * ARG1: ptr to stack (dest)
96 * ARG2: size (8)
97 * ARG3: unsafe ptr (src)
98 */
99static int
100gen_read_mem(struct bpf_insn_pos *pos,
101 int src_base_addr_reg,
102 int dst_addr_reg,
103 long offset)
104{
105 /* mov arg3, src_base_addr_reg */
106 if (src_base_addr_reg != BPF_REG_ARG3)
107 ins(BPF_MOV64_REG(BPF_REG_ARG3, src_base_addr_reg), pos);
108 /* add arg3, #offset */
109 if (offset)
110 ins(BPF_ALU64_IMM(BPF_ADD, BPF_REG_ARG3, offset), pos);
111
112 /* mov arg2, #reg_size */
113 ins(BPF_ALU64_IMM(BPF_MOV, BPF_REG_ARG2, BPF_REG_SIZE), pos);
114
115 /* mov arg1, dst_addr_reg */
116 if (dst_addr_reg != BPF_REG_ARG1)
117 ins(BPF_MOV64_REG(BPF_REG_ARG1, dst_addr_reg), pos);
118
119 /* Call probe_read */
120 ins(BPF_EMIT_CALL(BPF_FUNC_probe_read), pos);
121 /*
122 * Error processing: if read fail, goto error code,
123 * will be relocated. Target should be the start of
124 * error processing code.
125 */
126 ins(BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, JMP_TO_ERROR_CODE),
127 pos);
128
129 return check_pos(pos);
130}
131
132/*
133 * Each arg should be bare register. Fetch and save them into argument
134 * registers (r3 - r5).
135 *
136 * BPF_REG_1 should have been initialized with pointer to
137 * 'struct pt_regs'.
138 */
139static int
140gen_prologue_fastpath(struct bpf_insn_pos *pos,
141 struct probe_trace_arg *args, int nargs)
142{
143 int i, err = 0;
144
145 for (i = 0; i < nargs; i++) {
146 err = gen_ldx_reg_from_ctx(pos, BPF_REG_1, args[i].value,
147 BPF_PROLOGUE_START_ARG_REG + i);
148 if (err)
149 goto errout;
150 }
151
152 return check_pos(pos);
153errout:
154 return err;
155}
156
157/*
158 * Slow path:
159 * At least one argument has the form of 'offset($rx)'.
160 *
161 * Following code first stores them into stack, then loads all of then
162 * to r2 - r5.
163 * Before final loading, the final result should be:
164 *
165 * low address
166 * BPF_REG_FP - 24 ARG3
167 * BPF_REG_FP - 16 ARG2
168 * BPF_REG_FP - 8 ARG1
169 * BPF_REG_FP
170 * high address
171 *
172 * For each argument (described as: offn(...off2(off1(reg)))),
173 * generates following code:
174 *
175 * r7 <- fp
176 * r7 <- r7 - stack_offset // Ideal code should initialize r7 using
177 * // fp before generating args. However,
178 * // eBPF won't regard r7 as stack pointer
179 * // if it is generated by minus 8 from
180 * // another stack pointer except fp.
181 * // This is why we have to set r7
182 * // to fp for each variable.
183 * r3 <- value of 'reg'-> generated using gen_ldx_reg_from_ctx()
184 * (r7) <- r3 // skip following instructions for bare reg
185 * r3 <- r3 + off1 . // skip if off1 == 0
186 * r2 <- 8 \
187 * r1 <- r7 |-> generated by gen_read_mem()
188 * call probe_read /
189 * jnei r0, 0, err ./
190 * r3 <- (r7)
191 * r3 <- r3 + off2 . // skip if off2 == 0
192 * r2 <- 8 \ // r2 may be broken by probe_read, so set again
193 * r1 <- r7 |-> generated by gen_read_mem()
194 * call probe_read /
195 * jnei r0, 0, err ./
196 * ...
197 */
198static int
199gen_prologue_slowpath(struct bpf_insn_pos *pos,
200 struct probe_trace_arg *args, int nargs)
201{
202 int err, i;
203
204 for (i = 0; i < nargs; i++) {
205 struct probe_trace_arg *arg = &args[i];
206 const char *reg = arg->value;
207 struct probe_trace_arg_ref *ref = NULL;
208 int stack_offset = (i + 1) * -8;
209
210 pr_debug("prologue: fetch arg %d, base reg is %s\n",
211 i, reg);
212
213 /* value of base register is stored into ARG3 */
214 err = gen_ldx_reg_from_ctx(pos, BPF_REG_CTX, reg,
215 BPF_REG_ARG3);
216 if (err) {
217 pr_err("prologue: failed to get offset of register %s\n",
218 reg);
219 goto errout;
220 }
221
222 /* Make r7 the stack pointer. */
223 ins(BPF_MOV64_REG(BPF_REG_7, BPF_REG_FP), pos);
224 /* r7 += -8 */
225 ins(BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, stack_offset), pos);
226 /*
227 * Store r3 (base register) onto stack
228 * Ensure fp[offset] is set.
229 * fp is the only valid base register when storing
230 * into stack. We are not allowed to use r7 as base
231 * register here.
232 */
233 ins(BPF_STX_MEM(BPF_DW, BPF_REG_FP, BPF_REG_ARG3,
234 stack_offset), pos);
235
236 ref = arg->ref;
237 while (ref) {
238 pr_debug("prologue: arg %d: offset %ld\n",
239 i, ref->offset);
240 err = gen_read_mem(pos, BPF_REG_3, BPF_REG_7,
241 ref->offset);
242 if (err) {
243 pr_err("prologue: failed to generate probe_read function call\n");
244 goto errout;
245 }
246
247 ref = ref->next;
248 /*
249 * Load previous result into ARG3. Use
250 * BPF_REG_FP instead of r7 because verifier
251 * allows FP based addressing only.
252 */
253 if (ref)
254 ins(BPF_LDX_MEM(BPF_DW, BPF_REG_ARG3,
255 BPF_REG_FP, stack_offset), pos);
256 }
257 }
258
259 /* Final pass: read to registers */
260 for (i = 0; i < nargs; i++)
261 ins(BPF_LDX_MEM(BPF_DW, BPF_PROLOGUE_START_ARG_REG + i,
262 BPF_REG_FP, -BPF_REG_SIZE * (i + 1)), pos);
263
264 ins(BPF_JMP_IMM(BPF_JA, BPF_REG_0, 0, JMP_TO_SUCCESS_CODE), pos);
265
266 return check_pos(pos);
267errout:
268 return err;
269}
270
271static int
272prologue_relocate(struct bpf_insn_pos *pos, struct bpf_insn *error_code,
273 struct bpf_insn *success_code, struct bpf_insn *user_code)
274{
275 struct bpf_insn *insn;
276
277 if (check_pos(pos))
278 return -BPF_LOADER_ERRNO__PROLOGUE2BIG;
279
280 for (insn = pos->begin; insn < pos->pos; insn++) {
281 struct bpf_insn *target;
282 u8 class = BPF_CLASS(insn->code);
283 u8 opcode;
284
285 if (class != BPF_JMP)
286 continue;
287 opcode = BPF_OP(insn->code);
288 if (opcode == BPF_CALL)
289 continue;
290
291 switch (insn->off) {
292 case JMP_TO_ERROR_CODE:
293 target = error_code;
294 break;
295 case JMP_TO_SUCCESS_CODE:
296 target = success_code;
297 break;
298 case JMP_TO_USER_CODE:
299 target = user_code;
300 break;
301 default:
302 pr_err("bpf prologue: internal error: relocation failed\n");
303 return -BPF_LOADER_ERRNO__PROLOGUE;
304 }
305
306 insn->off = target - (insn + 1);
307 }
308 return 0;
309}
310
311int bpf__gen_prologue(struct probe_trace_arg *args, int nargs,
312 struct bpf_insn *new_prog, size_t *new_cnt,
313 size_t cnt_space)
314{
315 struct bpf_insn *success_code = NULL;
316 struct bpf_insn *error_code = NULL;
317 struct bpf_insn *user_code = NULL;
318 struct bpf_insn_pos pos;
319 bool fastpath = true;
320 int err = 0, i;
321
322 if (!new_prog || !new_cnt)
323 return -EINVAL;
324
325 if (cnt_space > BPF_MAXINSNS)
326 cnt_space = BPF_MAXINSNS;
327
328 pos.begin = new_prog;
329 pos.end = new_prog + cnt_space;
330 pos.pos = new_prog;
331
332 if (!nargs) {
333 ins(BPF_ALU64_IMM(BPF_MOV, BPF_PROLOGUE_FETCH_RESULT_REG, 0),
334 &pos);
335
336 if (check_pos(&pos))
337 goto errout;
338
339 *new_cnt = pos_get_cnt(&pos);
340 return 0;
341 }
342
343 if (nargs > BPF_PROLOGUE_MAX_ARGS) {
344 pr_warning("bpf: prologue: %d arguments are dropped\n",
345 nargs - BPF_PROLOGUE_MAX_ARGS);
346 nargs = BPF_PROLOGUE_MAX_ARGS;
347 }
348
349 /* First pass: validation */
350 for (i = 0; i < nargs; i++) {
351 struct probe_trace_arg_ref *ref = args[i].ref;
352
353 if (args[i].value[0] == '@') {
354 /* TODO: fetch global variable */
355 pr_err("bpf: prologue: global %s%+ld not support\n",
356 args[i].value, ref ? ref->offset : 0);
357 return -ENOTSUP;
358 }
359
360 while (ref) {
361 /* fastpath is true if all args has ref == NULL */
362 fastpath = false;
363
364 /*
365 * Instruction encodes immediate value using
366 * s32, ref->offset is long. On systems which
367 * can't fill long in s32, refuse to process if
368 * ref->offset too large (or small).
369 */
370#ifdef __LP64__
371#define OFFSET_MAX ((1LL << 31) - 1)
372#define OFFSET_MIN ((1LL << 31) * -1)
373 if (ref->offset > OFFSET_MAX ||
374 ref->offset < OFFSET_MIN) {
375 pr_err("bpf: prologue: offset out of bound: %ld\n",
376 ref->offset);
377 return -BPF_LOADER_ERRNO__PROLOGUEOOB;
378 }
379#endif
380 ref = ref->next;
381 }
382 }
383 pr_debug("prologue: pass validation\n");
384
385 if (fastpath) {
386 /* If all variables are registers... */
387 pr_debug("prologue: fast path\n");
388 err = gen_prologue_fastpath(&pos, args, nargs);
389 if (err)
390 goto errout;
391 } else {
392 pr_debug("prologue: slow path\n");
393
394 /* Initialization: move ctx to a callee saved register. */
395 ins(BPF_MOV64_REG(BPF_REG_CTX, BPF_REG_ARG1), &pos);
396
397 err = gen_prologue_slowpath(&pos, args, nargs);
398 if (err)
399 goto errout;
400 /*
401 * start of ERROR_CODE (only slow pass needs error code)
402 * mov r2 <- 1 // r2 is error number
403 * mov r3 <- 0 // r3, r4... should be touched or
404 * // verifier would complain
405 * mov r4 <- 0
406 * ...
407 * goto usercode
408 */
409 error_code = pos.pos;
410 ins(BPF_ALU64_IMM(BPF_MOV, BPF_PROLOGUE_FETCH_RESULT_REG, 1),
411 &pos);
412
413 for (i = 0; i < nargs; i++)
414 ins(BPF_ALU64_IMM(BPF_MOV,
415 BPF_PROLOGUE_START_ARG_REG + i,
416 0),
417 &pos);
418 ins(BPF_JMP_IMM(BPF_JA, BPF_REG_0, 0, JMP_TO_USER_CODE),
419 &pos);
420 }
421
422 /*
423 * start of SUCCESS_CODE:
424 * mov r2 <- 0
425 * goto usercode // skip
426 */
427 success_code = pos.pos;
428 ins(BPF_ALU64_IMM(BPF_MOV, BPF_PROLOGUE_FETCH_RESULT_REG, 0), &pos);
429
430 /*
431 * start of USER_CODE:
432 * Restore ctx to r1
433 */
434 user_code = pos.pos;
435 if (!fastpath) {
436 /*
437 * Only slow path needs restoring of ctx. In fast path,
438 * register are loaded directly from r1.
439 */
440 ins(BPF_MOV64_REG(BPF_REG_ARG1, BPF_REG_CTX), &pos);
441 err = prologue_relocate(&pos, error_code, success_code,
442 user_code);
443 if (err)
444 goto errout;
445 }
446
447 err = check_pos(&pos);
448 if (err)
449 goto errout;
450
451 *new_cnt = pos_get_cnt(&pos);
452 return 0;
453errout:
454 return err;
455}
diff --git a/tools/perf/util/bpf-prologue.h b/tools/perf/util/bpf-prologue.h
new file mode 100644
index 000000000000..d94cbea12899
--- /dev/null
+++ b/tools/perf/util/bpf-prologue.h
@@ -0,0 +1,34 @@
1/*
2 * Copyright (C) 2015, He Kuang <hekuang@huawei.com>
3 * Copyright (C) 2015, Huawei Inc.
4 */
5#ifndef __BPF_PROLOGUE_H
6#define __BPF_PROLOGUE_H
7
8#include <linux/compiler.h>
9#include <linux/filter.h>
10#include "probe-event.h"
11
12#define BPF_PROLOGUE_MAX_ARGS 3
13#define BPF_PROLOGUE_START_ARG_REG BPF_REG_3
14#define BPF_PROLOGUE_FETCH_RESULT_REG BPF_REG_2
15
16#ifdef HAVE_BPF_PROLOGUE
17int bpf__gen_prologue(struct probe_trace_arg *args, int nargs,
18 struct bpf_insn *new_prog, size_t *new_cnt,
19 size_t cnt_space);
20#else
21static inline int
22bpf__gen_prologue(struct probe_trace_arg *args __maybe_unused,
23 int nargs __maybe_unused,
24 struct bpf_insn *new_prog __maybe_unused,
25 size_t *new_cnt,
26 size_t cnt_space __maybe_unused)
27{
28 if (!new_cnt)
29 return -EINVAL;
30 *new_cnt = 0;
31 return -ENOTSUP;
32}
33#endif
34#endif /* __BPF_PROLOGUE_H */
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index d909459fb54c..6a7e273a514a 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -76,6 +76,7 @@ struct perf_tool build_id__mark_dso_hit_ops = {
76 .exit = perf_event__exit_del_thread, 76 .exit = perf_event__exit_del_thread,
77 .attr = perf_event__process_attr, 77 .attr = perf_event__process_attr,
78 .build_id = perf_event__process_build_id, 78 .build_id = perf_event__process_build_id,
79 .ordered_events = true,
79}; 80};
80 81
81int build_id__sprintf(const u8 *build_id, int len, char *bf) 82int build_id__sprintf(const u8 *build_id, int len, char *bf)
@@ -90,7 +91,7 @@ int build_id__sprintf(const u8 *build_id, int len, char *bf)
90 bid += 2; 91 bid += 2;
91 } 92 }
92 93
93 return raw - build_id; 94 return (bid - bf) + 1;
94} 95}
95 96
96int sysfs__sprintf_build_id(const char *root_dir, char *sbuild_id) 97int sysfs__sprintf_build_id(const char *root_dir, char *sbuild_id)
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index c861373aaed3..07b5d63947b1 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -4,9 +4,12 @@
4#include <stdbool.h> 4#include <stdbool.h>
5#include "util.h" 5#include "util.h"
6#include "strbuf.h" 6#include "strbuf.h"
7#include <subcmd/pager.h>
7#include "../perf.h" 8#include "../perf.h"
8#include "../ui/ui.h" 9#include "../ui/ui.h"
9 10
11#include <linux/string.h>
12
10#define CMD_EXEC_PATH "--exec-path" 13#define CMD_EXEC_PATH "--exec-path"
11#define CMD_PERF_DIR "--perf-dir=" 14#define CMD_PERF_DIR "--perf-dir="
12#define CMD_WORK_TREE "--work-tree=" 15#define CMD_WORK_TREE "--work-tree="
@@ -18,6 +21,7 @@
18#define DEFAULT_PERF_DIR_ENVIRONMENT ".perf" 21#define DEFAULT_PERF_DIR_ENVIRONMENT ".perf"
19#define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR" 22#define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR"
20#define PERF_TRACEFS_ENVIRONMENT "PERF_TRACEFS_DIR" 23#define PERF_TRACEFS_ENVIRONMENT "PERF_TRACEFS_DIR"
24#define PERF_PAGER_ENVIRONMENT "PERF_PAGER"
21 25
22typedef int (*config_fn_t)(const char *, const char *, void *); 26typedef int (*config_fn_t)(const char *, const char *, void *);
23extern int perf_default_config(const char *, const char *, void *); 27extern int perf_default_config(const char *, const char *, void *);
@@ -28,11 +32,6 @@ extern int perf_config_bool(const char *, const char *);
28extern int config_error_nonbool(const char *); 32extern int config_error_nonbool(const char *);
29extern const char *perf_config_dirname(const char *, const char *); 33extern const char *perf_config_dirname(const char *, const char *);
30 34
31/* pager.c */
32extern void setup_pager(void);
33extern int pager_in_use(void);
34extern int pager_use_color;
35
36char *alias_lookup(const char *alias); 35char *alias_lookup(const char *alias);
37int split_cmdline(char *cmdline, const char ***argv); 36int split_cmdline(char *cmdline, const char ***argv);
38 37
@@ -71,9 +70,4 @@ extern char *perf_path(const char *fmt, ...) __attribute__((format (printf, 1, 2
71extern char *perf_pathdup(const char *fmt, ...) 70extern char *perf_pathdup(const char *fmt, ...)
72 __attribute__((format (printf, 1, 2))); 71 __attribute__((format (printf, 1, 2)));
73 72
74#ifndef __UCLIBC__
75/* Matches the libc/libbsd function attribute so we declare this unconditionally: */
76extern size_t strlcpy(char *dest, const char *src, size_t size);
77#endif
78
79#endif /* __PERF_CACHE_H */ 73#endif /* __PERF_CACHE_H */
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 735ad48e1858..53c43eb9489e 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -44,6 +44,10 @@ static int parse_callchain_mode(const char *value)
44 callchain_param.mode = CHAIN_GRAPH_REL; 44 callchain_param.mode = CHAIN_GRAPH_REL;
45 return 0; 45 return 0;
46 } 46 }
47 if (!strncmp(value, "folded", strlen(value))) {
48 callchain_param.mode = CHAIN_FOLDED;
49 return 0;
50 }
47 return -1; 51 return -1;
48} 52}
49 53
@@ -79,6 +83,23 @@ static int parse_callchain_sort_key(const char *value)
79 return -1; 83 return -1;
80} 84}
81 85
86static int parse_callchain_value(const char *value)
87{
88 if (!strncmp(value, "percent", strlen(value))) {
89 callchain_param.value = CCVAL_PERCENT;
90 return 0;
91 }
92 if (!strncmp(value, "period", strlen(value))) {
93 callchain_param.value = CCVAL_PERIOD;
94 return 0;
95 }
96 if (!strncmp(value, "count", strlen(value))) {
97 callchain_param.value = CCVAL_COUNT;
98 return 0;
99 }
100 return -1;
101}
102
82static int 103static int
83__parse_callchain_report_opt(const char *arg, bool allow_record_opt) 104__parse_callchain_report_opt(const char *arg, bool allow_record_opt)
84{ 105{
@@ -102,7 +123,8 @@ __parse_callchain_report_opt(const char *arg, bool allow_record_opt)
102 123
103 if (!parse_callchain_mode(tok) || 124 if (!parse_callchain_mode(tok) ||
104 !parse_callchain_order(tok) || 125 !parse_callchain_order(tok) ||
105 !parse_callchain_sort_key(tok)) { 126 !parse_callchain_sort_key(tok) ||
127 !parse_callchain_value(tok)) {
106 /* parsing ok - move on to the next */ 128 /* parsing ok - move on to the next */
107 try_stack_size = false; 129 try_stack_size = false;
108 goto next; 130 goto next;
@@ -218,6 +240,7 @@ rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
218 240
219 switch (mode) { 241 switch (mode) {
220 case CHAIN_FLAT: 242 case CHAIN_FLAT:
243 case CHAIN_FOLDED:
221 if (rnode->hit < chain->hit) 244 if (rnode->hit < chain->hit)
222 p = &(*p)->rb_left; 245 p = &(*p)->rb_left;
223 else 246 else
@@ -267,6 +290,7 @@ static void
267sort_chain_flat(struct rb_root *rb_root, struct callchain_root *root, 290sort_chain_flat(struct rb_root *rb_root, struct callchain_root *root,
268 u64 min_hit, struct callchain_param *param __maybe_unused) 291 u64 min_hit, struct callchain_param *param __maybe_unused)
269{ 292{
293 *rb_root = RB_ROOT;
270 __sort_chain_flat(rb_root, &root->node, min_hit); 294 __sort_chain_flat(rb_root, &root->node, min_hit);
271} 295}
272 296
@@ -338,6 +362,7 @@ int callchain_register_param(struct callchain_param *param)
338 param->sort = sort_chain_graph_rel; 362 param->sort = sort_chain_graph_rel;
339 break; 363 break;
340 case CHAIN_FLAT: 364 case CHAIN_FLAT:
365 case CHAIN_FOLDED:
341 param->sort = sort_chain_flat; 366 param->sort = sort_chain_flat;
342 break; 367 break;
343 case CHAIN_NONE: 368 case CHAIN_NONE:
@@ -363,6 +388,7 @@ create_child(struct callchain_node *parent, bool inherit_children)
363 } 388 }
364 new->parent = parent; 389 new->parent = parent;
365 INIT_LIST_HEAD(&new->val); 390 INIT_LIST_HEAD(&new->val);
391 INIT_LIST_HEAD(&new->parent_val);
366 392
367 if (inherit_children) { 393 if (inherit_children) {
368 struct rb_node *n; 394 struct rb_node *n;
@@ -431,6 +457,8 @@ add_child(struct callchain_node *parent,
431 457
432 new->children_hit = 0; 458 new->children_hit = 0;
433 new->hit = period; 459 new->hit = period;
460 new->children_count = 0;
461 new->count = 1;
434 return new; 462 return new;
435} 463}
436 464
@@ -478,6 +506,9 @@ split_add_child(struct callchain_node *parent,
478 parent->children_hit = callchain_cumul_hits(new); 506 parent->children_hit = callchain_cumul_hits(new);
479 new->val_nr = parent->val_nr - idx_local; 507 new->val_nr = parent->val_nr - idx_local;
480 parent->val_nr = idx_local; 508 parent->val_nr = idx_local;
509 new->count = parent->count;
510 new->children_count = parent->children_count;
511 parent->children_count = callchain_cumul_counts(new);
481 512
482 /* create a new child for the new branch if any */ 513 /* create a new child for the new branch if any */
483 if (idx_total < cursor->nr) { 514 if (idx_total < cursor->nr) {
@@ -488,6 +519,8 @@ split_add_child(struct callchain_node *parent,
488 519
489 parent->hit = 0; 520 parent->hit = 0;
490 parent->children_hit += period; 521 parent->children_hit += period;
522 parent->count = 0;
523 parent->children_count += 1;
491 524
492 node = callchain_cursor_current(cursor); 525 node = callchain_cursor_current(cursor);
493 new = add_child(parent, cursor, period); 526 new = add_child(parent, cursor, period);
@@ -510,6 +543,7 @@ split_add_child(struct callchain_node *parent,
510 rb_insert_color(&new->rb_node_in, &parent->rb_root_in); 543 rb_insert_color(&new->rb_node_in, &parent->rb_root_in);
511 } else { 544 } else {
512 parent->hit = period; 545 parent->hit = period;
546 parent->count = 1;
513 } 547 }
514} 548}
515 549
@@ -556,6 +590,7 @@ append_chain_children(struct callchain_node *root,
556 590
557inc_children_hit: 591inc_children_hit:
558 root->children_hit += period; 592 root->children_hit += period;
593 root->children_count++;
559} 594}
560 595
561static int 596static int
@@ -608,6 +643,7 @@ append_chain(struct callchain_node *root,
608 /* we match 100% of the path, increment the hit */ 643 /* we match 100% of the path, increment the hit */
609 if (matches == root->val_nr && cursor->pos == cursor->nr) { 644 if (matches == root->val_nr && cursor->pos == cursor->nr) {
610 root->hit += period; 645 root->hit += period;
646 root->count++;
611 return 0; 647 return 0;
612 } 648 }
613 649
@@ -799,12 +835,72 @@ char *callchain_list__sym_name(struct callchain_list *cl,
799 return bf; 835 return bf;
800} 836}
801 837
838char *callchain_node__scnprintf_value(struct callchain_node *node,
839 char *bf, size_t bfsize, u64 total)
840{
841 double percent = 0.0;
842 u64 period = callchain_cumul_hits(node);
843 unsigned count = callchain_cumul_counts(node);
844
845 if (callchain_param.mode == CHAIN_FOLDED) {
846 period = node->hit;
847 count = node->count;
848 }
849
850 switch (callchain_param.value) {
851 case CCVAL_PERIOD:
852 scnprintf(bf, bfsize, "%"PRIu64, period);
853 break;
854 case CCVAL_COUNT:
855 scnprintf(bf, bfsize, "%u", count);
856 break;
857 case CCVAL_PERCENT:
858 default:
859 if (total)
860 percent = period * 100.0 / total;
861 scnprintf(bf, bfsize, "%.2f%%", percent);
862 break;
863 }
864 return bf;
865}
866
867int callchain_node__fprintf_value(struct callchain_node *node,
868 FILE *fp, u64 total)
869{
870 double percent = 0.0;
871 u64 period = callchain_cumul_hits(node);
872 unsigned count = callchain_cumul_counts(node);
873
874 if (callchain_param.mode == CHAIN_FOLDED) {
875 period = node->hit;
876 count = node->count;
877 }
878
879 switch (callchain_param.value) {
880 case CCVAL_PERIOD:
881 return fprintf(fp, "%"PRIu64, period);
882 case CCVAL_COUNT:
883 return fprintf(fp, "%u", count);
884 case CCVAL_PERCENT:
885 default:
886 if (total)
887 percent = period * 100.0 / total;
888 return percent_color_fprintf(fp, "%.2f%%", percent);
889 }
890 return 0;
891}
892
802static void free_callchain_node(struct callchain_node *node) 893static void free_callchain_node(struct callchain_node *node)
803{ 894{
804 struct callchain_list *list, *tmp; 895 struct callchain_list *list, *tmp;
805 struct callchain_node *child; 896 struct callchain_node *child;
806 struct rb_node *n; 897 struct rb_node *n;
807 898
899 list_for_each_entry_safe(list, tmp, &node->parent_val, list) {
900 list_del(&list->list);
901 free(list);
902 }
903
808 list_for_each_entry_safe(list, tmp, &node->val, list) { 904 list_for_each_entry_safe(list, tmp, &node->val, list) {
809 list_del(&list->list); 905 list_del(&list->list);
810 free(list); 906 free(list);
@@ -828,3 +924,69 @@ void free_callchain(struct callchain_root *root)
828 924
829 free_callchain_node(&root->node); 925 free_callchain_node(&root->node);
830} 926}
927
928static u64 decay_callchain_node(struct callchain_node *node)
929{
930 struct callchain_node *child;
931 struct rb_node *n;
932 u64 child_hits = 0;
933
934 n = rb_first(&node->rb_root_in);
935 while (n) {
936 child = container_of(n, struct callchain_node, rb_node_in);
937
938 child_hits += decay_callchain_node(child);
939 n = rb_next(n);
940 }
941
942 node->hit = (node->hit * 7) / 8;
943 node->children_hit = child_hits;
944
945 return node->hit;
946}
947
948void decay_callchain(struct callchain_root *root)
949{
950 if (!symbol_conf.use_callchain)
951 return;
952
953 decay_callchain_node(&root->node);
954}
955
956int callchain_node__make_parent_list(struct callchain_node *node)
957{
958 struct callchain_node *parent = node->parent;
959 struct callchain_list *chain, *new;
960 LIST_HEAD(head);
961
962 while (parent) {
963 list_for_each_entry_reverse(chain, &parent->val, list) {
964 new = malloc(sizeof(*new));
965 if (new == NULL)
966 goto out;
967 *new = *chain;
968 new->has_children = false;
969 list_add_tail(&new->list, &head);
970 }
971 parent = parent->parent;
972 }
973
974 list_for_each_entry_safe_reverse(chain, new, &head, list)
975 list_move_tail(&chain->list, &node->parent_val);
976
977 if (!list_empty(&node->parent_val)) {
978 chain = list_first_entry(&node->parent_val, struct callchain_list, list);
979 chain->has_children = rb_prev(&node->rb_node) || rb_next(&node->rb_node);
980
981 chain = list_first_entry(&node->val, struct callchain_list, list);
982 chain->has_children = false;
983 }
984 return 0;
985
986out:
987 list_for_each_entry_safe(chain, new, &head, list) {
988 list_del(&chain->list);
989 free(chain);
990 }
991 return -ENOMEM;
992}
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index fce8161e54db..18dd22269764 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -24,12 +24,13 @@
24#define CALLCHAIN_RECORD_HELP CALLCHAIN_HELP RECORD_MODE_HELP RECORD_SIZE_HELP 24#define CALLCHAIN_RECORD_HELP CALLCHAIN_HELP RECORD_MODE_HELP RECORD_SIZE_HELP
25 25
26#define CALLCHAIN_REPORT_HELP \ 26#define CALLCHAIN_REPORT_HELP \
27 HELP_PAD "print_type:\tcall graph printing style (graph|flat|fractal|none)\n" \ 27 HELP_PAD "print_type:\tcall graph printing style (graph|flat|fractal|folded|none)\n" \
28 HELP_PAD "threshold:\tminimum call graph inclusion threshold (<percent>)\n" \ 28 HELP_PAD "threshold:\tminimum call graph inclusion threshold (<percent>)\n" \
29 HELP_PAD "print_limit:\tmaximum number of call graph entry (<number>)\n" \ 29 HELP_PAD "print_limit:\tmaximum number of call graph entry (<number>)\n" \
30 HELP_PAD "order:\t\tcall graph order (caller|callee)\n" \ 30 HELP_PAD "order:\t\tcall graph order (caller|callee)\n" \
31 HELP_PAD "sort_key:\tcall graph sort key (function|address)\n" \ 31 HELP_PAD "sort_key:\tcall graph sort key (function|address)\n" \
32 HELP_PAD "branch:\t\tinclude last branch info to call graph (branch)\n" 32 HELP_PAD "branch:\t\tinclude last branch info to call graph (branch)\n" \
33 HELP_PAD "value:\t\tcall graph value (percent|period|count)\n"
33 34
34enum perf_call_graph_mode { 35enum perf_call_graph_mode {
35 CALLCHAIN_NONE, 36 CALLCHAIN_NONE,
@@ -43,7 +44,8 @@ enum chain_mode {
43 CHAIN_NONE, 44 CHAIN_NONE,
44 CHAIN_FLAT, 45 CHAIN_FLAT,
45 CHAIN_GRAPH_ABS, 46 CHAIN_GRAPH_ABS,
46 CHAIN_GRAPH_REL 47 CHAIN_GRAPH_REL,
48 CHAIN_FOLDED,
47}; 49};
48 50
49enum chain_order { 51enum chain_order {
@@ -54,11 +56,14 @@ enum chain_order {
54struct callchain_node { 56struct callchain_node {
55 struct callchain_node *parent; 57 struct callchain_node *parent;
56 struct list_head val; 58 struct list_head val;
59 struct list_head parent_val;
57 struct rb_node rb_node_in; /* to insert nodes in an rbtree */ 60 struct rb_node rb_node_in; /* to insert nodes in an rbtree */
58 struct rb_node rb_node; /* to sort nodes in an output tree */ 61 struct rb_node rb_node; /* to sort nodes in an output tree */
59 struct rb_root rb_root_in; /* input tree of children */ 62 struct rb_root rb_root_in; /* input tree of children */
60 struct rb_root rb_root; /* sorted output tree of children */ 63 struct rb_root rb_root; /* sorted output tree of children */
61 unsigned int val_nr; 64 unsigned int val_nr;
65 unsigned int count;
66 unsigned int children_count;
62 u64 hit; 67 u64 hit;
63 u64 children_hit; 68 u64 children_hit;
64}; 69};
@@ -78,6 +83,12 @@ enum chain_key {
78 CCKEY_ADDRESS 83 CCKEY_ADDRESS
79}; 84};
80 85
86enum chain_value {
87 CCVAL_PERCENT,
88 CCVAL_PERIOD,
89 CCVAL_COUNT,
90};
91
81struct callchain_param { 92struct callchain_param {
82 bool enabled; 93 bool enabled;
83 enum perf_call_graph_mode record_mode; 94 enum perf_call_graph_mode record_mode;
@@ -90,6 +101,7 @@ struct callchain_param {
90 bool order_set; 101 bool order_set;
91 enum chain_key key; 102 enum chain_key key;
92 bool branch_callstack; 103 bool branch_callstack;
104 enum chain_value value;
93}; 105};
94 106
95extern struct callchain_param callchain_param; 107extern struct callchain_param callchain_param;
@@ -131,6 +143,7 @@ extern __thread struct callchain_cursor callchain_cursor;
131static inline void callchain_init(struct callchain_root *root) 143static inline void callchain_init(struct callchain_root *root)
132{ 144{
133 INIT_LIST_HEAD(&root->node.val); 145 INIT_LIST_HEAD(&root->node.val);
146 INIT_LIST_HEAD(&root->node.parent_val);
134 147
135 root->node.parent = NULL; 148 root->node.parent = NULL;
136 root->node.hit = 0; 149 root->node.hit = 0;
@@ -144,6 +157,11 @@ static inline u64 callchain_cumul_hits(struct callchain_node *node)
144 return node->hit + node->children_hit; 157 return node->hit + node->children_hit;
145} 158}
146 159
160static inline unsigned callchain_cumul_counts(struct callchain_node *node)
161{
162 return node->count + node->children_count;
163}
164
147int callchain_register_param(struct callchain_param *param); 165int callchain_register_param(struct callchain_param *param);
148int callchain_append(struct callchain_root *root, 166int callchain_append(struct callchain_root *root,
149 struct callchain_cursor *cursor, 167 struct callchain_cursor *cursor,
@@ -229,7 +247,13 @@ static inline int arch_skip_callchain_idx(struct thread *thread __maybe_unused,
229 247
230char *callchain_list__sym_name(struct callchain_list *cl, 248char *callchain_list__sym_name(struct callchain_list *cl,
231 char *bf, size_t bfsize, bool show_dso); 249 char *bf, size_t bfsize, bool show_dso);
250char *callchain_node__scnprintf_value(struct callchain_node *node,
251 char *bf, size_t bfsize, u64 total);
252int callchain_node__fprintf_value(struct callchain_node *node,
253 FILE *fp, u64 total);
232 254
233void free_callchain(struct callchain_root *root); 255void free_callchain(struct callchain_root *root);
256void decay_callchain(struct callchain_root *root);
257int callchain_node__make_parent_list(struct callchain_node *node);
234 258
235#endif /* __PERF_CALLCHAIN_H */ 259#endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c
index 32e12ecfe9c5..90aa1b46b2e5 100644
--- a/tools/perf/util/cgroup.c
+++ b/tools/perf/util/cgroup.c
@@ -1,6 +1,6 @@
1#include "util.h" 1#include "util.h"
2#include "../perf.h" 2#include "../perf.h"
3#include "parse-options.h" 3#include <subcmd/parse-options.h>
4#include "evsel.h" 4#include "evsel.h"
5#include "cgroup.h" 5#include "cgroup.h"
6#include "evlist.h" 6#include "evlist.h"
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c
index 9b9565416f90..e5fb88bab9e1 100644
--- a/tools/perf/util/color.c
+++ b/tools/perf/util/color.c
@@ -24,7 +24,7 @@ int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty)
24 auto_color: 24 auto_color:
25 if (stdout_is_tty < 0) 25 if (stdout_is_tty < 0)
26 stdout_is_tty = isatty(1); 26 stdout_is_tty = isatty(1);
27 if (stdout_is_tty || (pager_in_use() && pager_use_color)) { 27 if (stdout_is_tty || pager_in_use()) {
28 char *term = getenv("TERM"); 28 char *term = getenv("TERM");
29 if (term && strcmp(term, "dumb")) 29 if (term && strcmp(term, "dumb"))
30 return 1; 30 return 1;
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index 2e452ac1353d..d3e12e30e1d5 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -10,7 +10,7 @@
10 */ 10 */
11#include "util.h" 11#include "util.h"
12#include "cache.h" 12#include "cache.h"
13#include "exec_cmd.h" 13#include <subcmd/exec-cmd.h>
14#include "util/hist.h" /* perf_hist_config */ 14#include "util/hist.h" /* perf_hist_config */
15#include "util/llvm-utils.h" /* perf_llvm_config */ 15#include "util/llvm-utils.h" /* perf_llvm_config */
16 16
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
index 10af1e7524fb..fa935093a599 100644
--- a/tools/perf/util/cpumap.c
+++ b/tools/perf/util/cpumap.c
@@ -5,6 +5,7 @@
5#include <assert.h> 5#include <assert.h>
6#include <stdio.h> 6#include <stdio.h>
7#include <stdlib.h> 7#include <stdlib.h>
8#include <linux/bitmap.h>
8#include "asm/bug.h" 9#include "asm/bug.h"
9 10
10static struct cpu_map *cpu_map__default_new(void) 11static struct cpu_map *cpu_map__default_new(void)
@@ -179,6 +180,56 @@ out:
179 return cpus; 180 return cpus;
180} 181}
181 182
183static struct cpu_map *cpu_map__from_entries(struct cpu_map_entries *cpus)
184{
185 struct cpu_map *map;
186
187 map = cpu_map__empty_new(cpus->nr);
188 if (map) {
189 unsigned i;
190
191 for (i = 0; i < cpus->nr; i++) {
192 /*
193 * Special treatment for -1, which is not real cpu number,
194 * and we need to use (int) -1 to initialize map[i],
195 * otherwise it would become 65535.
196 */
197 if (cpus->cpu[i] == (u16) -1)
198 map->map[i] = -1;
199 else
200 map->map[i] = (int) cpus->cpu[i];
201 }
202 }
203
204 return map;
205}
206
207static struct cpu_map *cpu_map__from_mask(struct cpu_map_mask *mask)
208{
209 struct cpu_map *map;
210 int nr, nbits = mask->nr * mask->long_size * BITS_PER_BYTE;
211
212 nr = bitmap_weight(mask->mask, nbits);
213
214 map = cpu_map__empty_new(nr);
215 if (map) {
216 int cpu, i = 0;
217
218 for_each_set_bit(cpu, mask->mask, nbits)
219 map->map[i++] = cpu;
220 }
221 return map;
222
223}
224
225struct cpu_map *cpu_map__new_data(struct cpu_map_data *data)
226{
227 if (data->type == PERF_CPU_MAP__CPUS)
228 return cpu_map__from_entries((struct cpu_map_entries *)data->data);
229 else
230 return cpu_map__from_mask((struct cpu_map_mask *)data->data);
231}
232
182size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp) 233size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp)
183{ 234{
184 int i; 235 int i;
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
index 85f7772457fa..71c41b9efabb 100644
--- a/tools/perf/util/cpumap.h
+++ b/tools/perf/util/cpumap.h
@@ -17,6 +17,7 @@ struct cpu_map {
17struct cpu_map *cpu_map__new(const char *cpu_list); 17struct cpu_map *cpu_map__new(const char *cpu_list);
18struct cpu_map *cpu_map__empty_new(int nr); 18struct cpu_map *cpu_map__empty_new(int nr);
19struct cpu_map *cpu_map__dummy_new(void); 19struct cpu_map *cpu_map__dummy_new(void);
20struct cpu_map *cpu_map__new_data(struct cpu_map_data *data);
20struct cpu_map *cpu_map__read(FILE *file); 21struct cpu_map *cpu_map__read(FILE *file);
21size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); 22size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp);
22int cpu_map__get_socket_id(int cpu); 23int cpu_map__get_socket_id(int cpu);
diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c
index 5bfc1198ab46..34cd1e4039d3 100644
--- a/tools/perf/util/data-convert-bt.c
+++ b/tools/perf/util/data-convert-bt.c
@@ -63,6 +63,7 @@ struct ctf_writer {
63 struct bt_ctf_field_type *s32; 63 struct bt_ctf_field_type *s32;
64 struct bt_ctf_field_type *u32; 64 struct bt_ctf_field_type *u32;
65 struct bt_ctf_field_type *string; 65 struct bt_ctf_field_type *string;
66 struct bt_ctf_field_type *u32_hex;
66 struct bt_ctf_field_type *u64_hex; 67 struct bt_ctf_field_type *u64_hex;
67 }; 68 };
68 struct bt_ctf_field_type *array[6]; 69 struct bt_ctf_field_type *array[6];
@@ -982,6 +983,7 @@ do { \
982 CREATE_INT_TYPE(cw->data.u64, 64, false, false); 983 CREATE_INT_TYPE(cw->data.u64, 64, false, false);
983 CREATE_INT_TYPE(cw->data.s32, 32, true, false); 984 CREATE_INT_TYPE(cw->data.s32, 32, true, false);
984 CREATE_INT_TYPE(cw->data.u32, 32, false, false); 985 CREATE_INT_TYPE(cw->data.u32, 32, false, false);
986 CREATE_INT_TYPE(cw->data.u32_hex, 32, false, true);
985 CREATE_INT_TYPE(cw->data.u64_hex, 64, false, true); 987 CREATE_INT_TYPE(cw->data.u64_hex, 64, false, true);
986 988
987 cw->data.string = bt_ctf_field_type_string_create(); 989 cw->data.string = bt_ctf_field_type_string_create();
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index 7c0c08386a1d..e8e9a9dbf5e3 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -933,6 +933,7 @@ static struct dso *__dso__findlink_by_longname(struct rb_root *root,
933 /* Add new node and rebalance tree */ 933 /* Add new node and rebalance tree */
934 rb_link_node(&dso->rb_node, parent, p); 934 rb_link_node(&dso->rb_node, parent, p);
935 rb_insert_color(&dso->rb_node, root); 935 rb_insert_color(&dso->rb_node, root);
936 dso->root = root;
936 } 937 }
937 return NULL; 938 return NULL;
938} 939}
@@ -945,15 +946,30 @@ static inline struct dso *__dso__find_by_longname(struct rb_root *root,
945 946
946void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated) 947void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated)
947{ 948{
949 struct rb_root *root = dso->root;
950
948 if (name == NULL) 951 if (name == NULL)
949 return; 952 return;
950 953
951 if (dso->long_name_allocated) 954 if (dso->long_name_allocated)
952 free((char *)dso->long_name); 955 free((char *)dso->long_name);
953 956
957 if (root) {
958 rb_erase(&dso->rb_node, root);
959 /*
960 * __dso__findlink_by_longname() isn't guaranteed to add it
961 * back, so a clean removal is required here.
962 */
963 RB_CLEAR_NODE(&dso->rb_node);
964 dso->root = NULL;
965 }
966
954 dso->long_name = name; 967 dso->long_name = name;
955 dso->long_name_len = strlen(name); 968 dso->long_name_len = strlen(name);
956 dso->long_name_allocated = name_allocated; 969 dso->long_name_allocated = name_allocated;
970
971 if (root)
972 __dso__findlink_by_longname(root, dso, NULL);
957} 973}
958 974
959void dso__set_short_name(struct dso *dso, const char *name, bool name_allocated) 975void dso__set_short_name(struct dso *dso, const char *name, bool name_allocated)
@@ -1046,6 +1062,7 @@ struct dso *dso__new(const char *name)
1046 dso->kernel = DSO_TYPE_USER; 1062 dso->kernel = DSO_TYPE_USER;
1047 dso->needs_swap = DSO_SWAP__UNSET; 1063 dso->needs_swap = DSO_SWAP__UNSET;
1048 RB_CLEAR_NODE(&dso->rb_node); 1064 RB_CLEAR_NODE(&dso->rb_node);
1065 dso->root = NULL;
1049 INIT_LIST_HEAD(&dso->node); 1066 INIT_LIST_HEAD(&dso->node);
1050 INIT_LIST_HEAD(&dso->data.open_entry); 1067 INIT_LIST_HEAD(&dso->data.open_entry);
1051 pthread_mutex_init(&dso->lock, NULL); 1068 pthread_mutex_init(&dso->lock, NULL);
@@ -1226,6 +1243,8 @@ struct dso *__dsos__addnew(struct dsos *dsos, const char *name)
1226 if (dso != NULL) { 1243 if (dso != NULL) {
1227 __dsos__add(dsos, dso); 1244 __dsos__add(dsos, dso);
1228 dso__set_basename(dso); 1245 dso__set_basename(dso);
1246 /* Put dso here because __dsos_add already got it */
1247 dso__put(dso);
1229 } 1248 }
1230 return dso; 1249 return dso;
1231} 1250}
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index fc8db9c764ac..45ec4d0a50ed 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -135,6 +135,7 @@ struct dso {
135 pthread_mutex_t lock; 135 pthread_mutex_t lock;
136 struct list_head node; 136 struct list_head node;
137 struct rb_node rb_node; /* rbtree node sorted by long name */ 137 struct rb_node rb_node; /* rbtree node sorted by long name */
138 struct rb_root *root; /* root of rbtree that rb_node is in */
138 struct rb_root symbols[MAP__NR_TYPES]; 139 struct rb_root symbols[MAP__NR_TYPES];
139 struct rb_root symbol_names[MAP__NR_TYPES]; 140 struct rb_root symbol_names[MAP__NR_TYPES];
140 struct { 141 struct {
diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c
index 6af4f7c36820..7dd5939dea2e 100644
--- a/tools/perf/util/env.c
+++ b/tools/perf/util/env.c
@@ -25,15 +25,6 @@ int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[])
25{ 25{
26 int i; 26 int i;
27 27
28 /*
29 * If env->cmdline_argv has already been set, do not override it. This allows
30 * a command to set the cmdline, parse args and then call another
31 * builtin function that implements a command -- e.g, cmd_kvm calling
32 * cmd_record.
33 */
34 if (env->cmdline_argv != NULL)
35 return 0;
36
37 /* do not include NULL termination */ 28 /* do not include NULL termination */
38 env->cmdline_argv = calloc(argc, sizeof(char *)); 29 env->cmdline_argv = calloc(argc, sizeof(char *));
39 if (env->cmdline_argv == NULL) 30 if (env->cmdline_argv == NULL)
diff --git a/tools/perf/util/environment.c b/tools/perf/util/environment.c
deleted file mode 100644
index 7405123692f1..000000000000
--- a/tools/perf/util/environment.c
+++ /dev/null
@@ -1,8 +0,0 @@
1/*
2 * We put all the perf config variables in this same object
3 * file, so that programs can link against the config parser
4 * without having to link against all the rest of perf.
5 */
6#include "cache.h"
7
8int pager_use_color = 1;
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 8b10621b415c..85155e91b61b 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -10,6 +10,8 @@
10#include "thread.h" 10#include "thread.h"
11#include "thread_map.h" 11#include "thread_map.h"
12#include "symbol/kallsyms.h" 12#include "symbol/kallsyms.h"
13#include "asm/bug.h"
14#include "stat.h"
13 15
14static const char *perf_event__names[] = { 16static const char *perf_event__names[] = {
15 [0] = "TOTAL", 17 [0] = "TOTAL",
@@ -37,6 +39,12 @@ static const char *perf_event__names[] = {
37 [PERF_RECORD_AUXTRACE_INFO] = "AUXTRACE_INFO", 39 [PERF_RECORD_AUXTRACE_INFO] = "AUXTRACE_INFO",
38 [PERF_RECORD_AUXTRACE] = "AUXTRACE", 40 [PERF_RECORD_AUXTRACE] = "AUXTRACE",
39 [PERF_RECORD_AUXTRACE_ERROR] = "AUXTRACE_ERROR", 41 [PERF_RECORD_AUXTRACE_ERROR] = "AUXTRACE_ERROR",
42 [PERF_RECORD_THREAD_MAP] = "THREAD_MAP",
43 [PERF_RECORD_CPU_MAP] = "CPU_MAP",
44 [PERF_RECORD_STAT_CONFIG] = "STAT_CONFIG",
45 [PERF_RECORD_STAT] = "STAT",
46 [PERF_RECORD_STAT_ROUND] = "STAT_ROUND",
47 [PERF_RECORD_EVENT_UPDATE] = "EVENT_UPDATE",
40}; 48};
41 49
42const char *perf_event__name(unsigned int id) 50const char *perf_event__name(unsigned int id)
@@ -495,7 +503,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
495 if (comm_event == NULL) 503 if (comm_event == NULL)
496 goto out; 504 goto out;
497 505
498 mmap_event = malloc(sizeof(mmap_event->mmap) + machine->id_hdr_size); 506 mmap_event = malloc(sizeof(mmap_event->mmap2) + machine->id_hdr_size);
499 if (mmap_event == NULL) 507 if (mmap_event == NULL)
500 goto out_free_comm; 508 goto out_free_comm;
501 509
@@ -569,7 +577,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
569 if (comm_event == NULL) 577 if (comm_event == NULL)
570 goto out; 578 goto out;
571 579
572 mmap_event = malloc(sizeof(mmap_event->mmap) + machine->id_hdr_size); 580 mmap_event = malloc(sizeof(mmap_event->mmap2) + machine->id_hdr_size);
573 if (mmap_event == NULL) 581 if (mmap_event == NULL)
574 goto out_free_comm; 582 goto out_free_comm;
575 583
@@ -699,6 +707,274 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
699 return err; 707 return err;
700} 708}
701 709
710int perf_event__synthesize_thread_map2(struct perf_tool *tool,
711 struct thread_map *threads,
712 perf_event__handler_t process,
713 struct machine *machine)
714{
715 union perf_event *event;
716 int i, err, size;
717
718 size = sizeof(event->thread_map);
719 size += threads->nr * sizeof(event->thread_map.entries[0]);
720
721 event = zalloc(size);
722 if (!event)
723 return -ENOMEM;
724
725 event->header.type = PERF_RECORD_THREAD_MAP;
726 event->header.size = size;
727 event->thread_map.nr = threads->nr;
728
729 for (i = 0; i < threads->nr; i++) {
730 struct thread_map_event_entry *entry = &event->thread_map.entries[i];
731 char *comm = thread_map__comm(threads, i);
732
733 if (!comm)
734 comm = (char *) "";
735
736 entry->pid = thread_map__pid(threads, i);
737 strncpy((char *) &entry->comm, comm, sizeof(entry->comm));
738 }
739
740 err = process(tool, event, NULL, machine);
741
742 free(event);
743 return err;
744}
745
746static void synthesize_cpus(struct cpu_map_entries *cpus,
747 struct cpu_map *map)
748{
749 int i;
750
751 cpus->nr = map->nr;
752
753 for (i = 0; i < map->nr; i++)
754 cpus->cpu[i] = map->map[i];
755}
756
757static void synthesize_mask(struct cpu_map_mask *mask,
758 struct cpu_map *map, int max)
759{
760 int i;
761
762 mask->nr = BITS_TO_LONGS(max);
763 mask->long_size = sizeof(long);
764
765 for (i = 0; i < map->nr; i++)
766 set_bit(map->map[i], mask->mask);
767}
768
769static size_t cpus_size(struct cpu_map *map)
770{
771 return sizeof(struct cpu_map_entries) + map->nr * sizeof(u16);
772}
773
774static size_t mask_size(struct cpu_map *map, int *max)
775{
776 int i;
777
778 *max = 0;
779
780 for (i = 0; i < map->nr; i++) {
781 /* bit possition of the cpu is + 1 */
782 int bit = map->map[i] + 1;
783
784 if (bit > *max)
785 *max = bit;
786 }
787
788 return sizeof(struct cpu_map_mask) + BITS_TO_LONGS(*max) * sizeof(long);
789}
790
791void *cpu_map_data__alloc(struct cpu_map *map, size_t *size, u16 *type, int *max)
792{
793 size_t size_cpus, size_mask;
794 bool is_dummy = cpu_map__empty(map);
795
796 /*
797 * Both array and mask data have variable size based
798 * on the number of cpus and their actual values.
799 * The size of the 'struct cpu_map_data' is:
800 *
801 * array = size of 'struct cpu_map_entries' +
802 * number of cpus * sizeof(u64)
803 *
804 * mask = size of 'struct cpu_map_mask' +
805 * maximum cpu bit converted to size of longs
806 *
807 * and finaly + the size of 'struct cpu_map_data'.
808 */
809 size_cpus = cpus_size(map);
810 size_mask = mask_size(map, max);
811
812 if (is_dummy || (size_cpus < size_mask)) {
813 *size += size_cpus;
814 *type = PERF_CPU_MAP__CPUS;
815 } else {
816 *size += size_mask;
817 *type = PERF_CPU_MAP__MASK;
818 }
819
820 *size += sizeof(struct cpu_map_data);
821 return zalloc(*size);
822}
823
824void cpu_map_data__synthesize(struct cpu_map_data *data, struct cpu_map *map,
825 u16 type, int max)
826{
827 data->type = type;
828
829 switch (type) {
830 case PERF_CPU_MAP__CPUS:
831 synthesize_cpus((struct cpu_map_entries *) data->data, map);
832 break;
833 case PERF_CPU_MAP__MASK:
834 synthesize_mask((struct cpu_map_mask *) data->data, map, max);
835 default:
836 break;
837 };
838}
839
840static struct cpu_map_event* cpu_map_event__new(struct cpu_map *map)
841{
842 size_t size = sizeof(struct cpu_map_event);
843 struct cpu_map_event *event;
844 int max;
845 u16 type;
846
847 event = cpu_map_data__alloc(map, &size, &type, &max);
848 if (!event)
849 return NULL;
850
851 event->header.type = PERF_RECORD_CPU_MAP;
852 event->header.size = size;
853 event->data.type = type;
854
855 cpu_map_data__synthesize(&event->data, map, type, max);
856 return event;
857}
858
859int perf_event__synthesize_cpu_map(struct perf_tool *tool,
860 struct cpu_map *map,
861 perf_event__handler_t process,
862 struct machine *machine)
863{
864 struct cpu_map_event *event;
865 int err;
866
867 event = cpu_map_event__new(map);
868 if (!event)
869 return -ENOMEM;
870
871 err = process(tool, (union perf_event *) event, NULL, machine);
872
873 free(event);
874 return err;
875}
876
877int perf_event__synthesize_stat_config(struct perf_tool *tool,
878 struct perf_stat_config *config,
879 perf_event__handler_t process,
880 struct machine *machine)
881{
882 struct stat_config_event *event;
883 int size, i = 0, err;
884
885 size = sizeof(*event);
886 size += (PERF_STAT_CONFIG_TERM__MAX * sizeof(event->data[0]));
887
888 event = zalloc(size);
889 if (!event)
890 return -ENOMEM;
891
892 event->header.type = PERF_RECORD_STAT_CONFIG;
893 event->header.size = size;
894 event->nr = PERF_STAT_CONFIG_TERM__MAX;
895
896#define ADD(__term, __val) \
897 event->data[i].tag = PERF_STAT_CONFIG_TERM__##__term; \
898 event->data[i].val = __val; \
899 i++;
900
901 ADD(AGGR_MODE, config->aggr_mode)
902 ADD(INTERVAL, config->interval)
903 ADD(SCALE, config->scale)
904
905 WARN_ONCE(i != PERF_STAT_CONFIG_TERM__MAX,
906 "stat config terms unbalanced\n");
907#undef ADD
908
909 err = process(tool, (union perf_event *) event, NULL, machine);
910
911 free(event);
912 return err;
913}
914
915int perf_event__synthesize_stat(struct perf_tool *tool,
916 u32 cpu, u32 thread, u64 id,
917 struct perf_counts_values *count,
918 perf_event__handler_t process,
919 struct machine *machine)
920{
921 struct stat_event event;
922
923 event.header.type = PERF_RECORD_STAT;
924 event.header.size = sizeof(event);
925 event.header.misc = 0;
926
927 event.id = id;
928 event.cpu = cpu;
929 event.thread = thread;
930 event.val = count->val;
931 event.ena = count->ena;
932 event.run = count->run;
933
934 return process(tool, (union perf_event *) &event, NULL, machine);
935}
936
937int perf_event__synthesize_stat_round(struct perf_tool *tool,
938 u64 evtime, u64 type,
939 perf_event__handler_t process,
940 struct machine *machine)
941{
942 struct stat_round_event event;
943
944 event.header.type = PERF_RECORD_STAT_ROUND;
945 event.header.size = sizeof(event);
946 event.header.misc = 0;
947
948 event.time = evtime;
949 event.type = type;
950
951 return process(tool, (union perf_event *) &event, NULL, machine);
952}
953
954void perf_event__read_stat_config(struct perf_stat_config *config,
955 struct stat_config_event *event)
956{
957 unsigned i;
958
959 for (i = 0; i < event->nr; i++) {
960
961 switch (event->data[i].tag) {
962#define CASE(__term, __val) \
963 case PERF_STAT_CONFIG_TERM__##__term: \
964 config->__val = event->data[i].val; \
965 break;
966
967 CASE(AGGR_MODE, aggr_mode)
968 CASE(SCALE, scale)
969 CASE(INTERVAL, interval)
970#undef CASE
971 default:
972 pr_warning("unknown stat config term %" PRIu64 "\n",
973 event->data[i].tag);
974 }
975 }
976}
977
702size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp) 978size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp)
703{ 979{
704 const char *s; 980 const char *s;
@@ -783,6 +1059,38 @@ size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp)
783 event->mmap2.filename); 1059 event->mmap2.filename);
784} 1060}
785 1061
1062size_t perf_event__fprintf_thread_map(union perf_event *event, FILE *fp)
1063{
1064 struct thread_map *threads = thread_map__new_event(&event->thread_map);
1065 size_t ret;
1066
1067 ret = fprintf(fp, " nr: ");
1068
1069 if (threads)
1070 ret += thread_map__fprintf(threads, fp);
1071 else
1072 ret += fprintf(fp, "failed to get threads from event\n");
1073
1074 thread_map__put(threads);
1075 return ret;
1076}
1077
1078size_t perf_event__fprintf_cpu_map(union perf_event *event, FILE *fp)
1079{
1080 struct cpu_map *cpus = cpu_map__new_data(&event->cpu_map.data);
1081 size_t ret;
1082
1083 ret = fprintf(fp, " nr: ");
1084
1085 if (cpus)
1086 ret += cpu_map__fprintf(cpus, fp);
1087 else
1088 ret += fprintf(fp, "failed to get cpumap from event\n");
1089
1090 cpu_map__put(cpus);
1091 return ret;
1092}
1093
786int perf_event__process_mmap(struct perf_tool *tool __maybe_unused, 1094int perf_event__process_mmap(struct perf_tool *tool __maybe_unused,
787 union perf_event *event, 1095 union perf_event *event,
788 struct perf_sample *sample, 1096 struct perf_sample *sample,
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index a0dbcbd4f6d8..b7ffb7ee9971 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -226,6 +226,12 @@ enum perf_user_event_type { /* above any possible kernel type */
226 PERF_RECORD_AUXTRACE_INFO = 70, 226 PERF_RECORD_AUXTRACE_INFO = 70,
227 PERF_RECORD_AUXTRACE = 71, 227 PERF_RECORD_AUXTRACE = 71,
228 PERF_RECORD_AUXTRACE_ERROR = 72, 228 PERF_RECORD_AUXTRACE_ERROR = 72,
229 PERF_RECORD_THREAD_MAP = 73,
230 PERF_RECORD_CPU_MAP = 74,
231 PERF_RECORD_STAT_CONFIG = 75,
232 PERF_RECORD_STAT = 76,
233 PERF_RECORD_STAT_ROUND = 77,
234 PERF_RECORD_EVENT_UPDATE = 78,
229 PERF_RECORD_HEADER_MAX 235 PERF_RECORD_HEADER_MAX
230}; 236};
231 237
@@ -270,12 +276,61 @@ struct events_stats {
270 u32 nr_proc_map_timeout; 276 u32 nr_proc_map_timeout;
271}; 277};
272 278
279enum {
280 PERF_CPU_MAP__CPUS = 0,
281 PERF_CPU_MAP__MASK = 1,
282};
283
284struct cpu_map_entries {
285 u16 nr;
286 u16 cpu[];
287};
288
289struct cpu_map_mask {
290 u16 nr;
291 u16 long_size;
292 unsigned long mask[];
293};
294
295struct cpu_map_data {
296 u16 type;
297 char data[];
298};
299
300struct cpu_map_event {
301 struct perf_event_header header;
302 struct cpu_map_data data;
303};
304
273struct attr_event { 305struct attr_event {
274 struct perf_event_header header; 306 struct perf_event_header header;
275 struct perf_event_attr attr; 307 struct perf_event_attr attr;
276 u64 id[]; 308 u64 id[];
277}; 309};
278 310
311enum {
312 PERF_EVENT_UPDATE__UNIT = 0,
313 PERF_EVENT_UPDATE__SCALE = 1,
314 PERF_EVENT_UPDATE__NAME = 2,
315 PERF_EVENT_UPDATE__CPUS = 3,
316};
317
318struct event_update_event_cpus {
319 struct cpu_map_data cpus;
320};
321
322struct event_update_event_scale {
323 double scale;
324};
325
326struct event_update_event {
327 struct perf_event_header header;
328 u64 type;
329 u64 id;
330
331 char data[];
332};
333
279#define MAX_EVENT_NAME 64 334#define MAX_EVENT_NAME 64
280 335
281struct perf_trace_event_type { 336struct perf_trace_event_type {
@@ -356,6 +411,63 @@ struct context_switch_event {
356 u32 next_prev_tid; 411 u32 next_prev_tid;
357}; 412};
358 413
414struct thread_map_event_entry {
415 u64 pid;
416 char comm[16];
417};
418
419struct thread_map_event {
420 struct perf_event_header header;
421 u64 nr;
422 struct thread_map_event_entry entries[];
423};
424
425enum {
426 PERF_STAT_CONFIG_TERM__AGGR_MODE = 0,
427 PERF_STAT_CONFIG_TERM__INTERVAL = 1,
428 PERF_STAT_CONFIG_TERM__SCALE = 2,
429 PERF_STAT_CONFIG_TERM__MAX = 3,
430};
431
432struct stat_config_event_entry {
433 u64 tag;
434 u64 val;
435};
436
437struct stat_config_event {
438 struct perf_event_header header;
439 u64 nr;
440 struct stat_config_event_entry data[];
441};
442
443struct stat_event {
444 struct perf_event_header header;
445
446 u64 id;
447 u32 cpu;
448 u32 thread;
449
450 union {
451 struct {
452 u64 val;
453 u64 ena;
454 u64 run;
455 };
456 u64 values[3];
457 };
458};
459
460enum {
461 PERF_STAT_ROUND_TYPE__INTERVAL = 0,
462 PERF_STAT_ROUND_TYPE__FINAL = 1,
463};
464
465struct stat_round_event {
466 struct perf_event_header header;
467 u64 type;
468 u64 time;
469};
470
359union perf_event { 471union perf_event {
360 struct perf_event_header header; 472 struct perf_event_header header;
361 struct mmap_event mmap; 473 struct mmap_event mmap;
@@ -368,6 +480,7 @@ union perf_event {
368 struct throttle_event throttle; 480 struct throttle_event throttle;
369 struct sample_event sample; 481 struct sample_event sample;
370 struct attr_event attr; 482 struct attr_event attr;
483 struct event_update_event event_update;
371 struct event_type_event event_type; 484 struct event_type_event event_type;
372 struct tracing_data_event tracing_data; 485 struct tracing_data_event tracing_data;
373 struct build_id_event build_id; 486 struct build_id_event build_id;
@@ -378,12 +491,20 @@ union perf_event {
378 struct aux_event aux; 491 struct aux_event aux;
379 struct itrace_start_event itrace_start; 492 struct itrace_start_event itrace_start;
380 struct context_switch_event context_switch; 493 struct context_switch_event context_switch;
494 struct thread_map_event thread_map;
495 struct cpu_map_event cpu_map;
496 struct stat_config_event stat_config;
497 struct stat_event stat;
498 struct stat_round_event stat_round;
381}; 499};
382 500
383void perf_event__print_totals(void); 501void perf_event__print_totals(void);
384 502
385struct perf_tool; 503struct perf_tool;
386struct thread_map; 504struct thread_map;
505struct cpu_map;
506struct perf_stat_config;
507struct perf_counts_values;
387 508
388typedef int (*perf_event__handler_t)(struct perf_tool *tool, 509typedef int (*perf_event__handler_t)(struct perf_tool *tool,
389 union perf_event *event, 510 union perf_event *event,
@@ -395,6 +516,14 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
395 perf_event__handler_t process, 516 perf_event__handler_t process,
396 struct machine *machine, bool mmap_data, 517 struct machine *machine, bool mmap_data,
397 unsigned int proc_map_timeout); 518 unsigned int proc_map_timeout);
519int perf_event__synthesize_thread_map2(struct perf_tool *tool,
520 struct thread_map *threads,
521 perf_event__handler_t process,
522 struct machine *machine);
523int perf_event__synthesize_cpu_map(struct perf_tool *tool,
524 struct cpu_map *cpus,
525 perf_event__handler_t process,
526 struct machine *machine);
398int perf_event__synthesize_threads(struct perf_tool *tool, 527int perf_event__synthesize_threads(struct perf_tool *tool,
399 perf_event__handler_t process, 528 perf_event__handler_t process,
400 struct machine *machine, bool mmap_data, 529 struct machine *machine, bool mmap_data,
@@ -402,7 +531,21 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
402int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, 531int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
403 perf_event__handler_t process, 532 perf_event__handler_t process,
404 struct machine *machine); 533 struct machine *machine);
405 534int perf_event__synthesize_stat_config(struct perf_tool *tool,
535 struct perf_stat_config *config,
536 perf_event__handler_t process,
537 struct machine *machine);
538void perf_event__read_stat_config(struct perf_stat_config *config,
539 struct stat_config_event *event);
540int perf_event__synthesize_stat(struct perf_tool *tool,
541 u32 cpu, u32 thread, u64 id,
542 struct perf_counts_values *count,
543 perf_event__handler_t process,
544 struct machine *machine);
545int perf_event__synthesize_stat_round(struct perf_tool *tool,
546 u64 time, u64 type,
547 perf_event__handler_t process,
548 struct machine *machine);
406int perf_event__synthesize_modules(struct perf_tool *tool, 549int perf_event__synthesize_modules(struct perf_tool *tool,
407 perf_event__handler_t process, 550 perf_event__handler_t process,
408 struct machine *machine); 551 struct machine *machine);
@@ -499,9 +642,14 @@ size_t perf_event__fprintf_task(union perf_event *event, FILE *fp);
499size_t perf_event__fprintf_aux(union perf_event *event, FILE *fp); 642size_t perf_event__fprintf_aux(union perf_event *event, FILE *fp);
500size_t perf_event__fprintf_itrace_start(union perf_event *event, FILE *fp); 643size_t perf_event__fprintf_itrace_start(union perf_event *event, FILE *fp);
501size_t perf_event__fprintf_switch(union perf_event *event, FILE *fp); 644size_t perf_event__fprintf_switch(union perf_event *event, FILE *fp);
645size_t perf_event__fprintf_thread_map(union perf_event *event, FILE *fp);
646size_t perf_event__fprintf_cpu_map(union perf_event *event, FILE *fp);
502size_t perf_event__fprintf(union perf_event *event, FILE *fp); 647size_t perf_event__fprintf(union perf_event *event, FILE *fp);
503 648
504u64 kallsyms__get_function_start(const char *kallsyms_filename, 649u64 kallsyms__get_function_start(const char *kallsyms_filename,
505 const char *symbol_name); 650 const char *symbol_name);
506 651
652void *cpu_map_data__alloc(struct cpu_map *map, size_t *size, u16 *type, int *max);
653void cpu_map_data__synthesize(struct cpu_map_data *data, struct cpu_map *map,
654 u16 type, int max);
507#endif /* __PERF_RECORD_H */ 655#endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index d1392194a9a9..d81f13de2476 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -18,7 +18,7 @@
18#include <unistd.h> 18#include <unistd.h>
19 19
20#include "parse-events.h" 20#include "parse-events.h"
21#include "parse-options.h" 21#include <subcmd/parse-options.h>
22 22
23#include <sys/mman.h> 23#include <sys/mman.h>
24 24
@@ -68,6 +68,18 @@ struct perf_evlist *perf_evlist__new_default(void)
68 return evlist; 68 return evlist;
69} 69}
70 70
71struct perf_evlist *perf_evlist__new_dummy(void)
72{
73 struct perf_evlist *evlist = perf_evlist__new();
74
75 if (evlist && perf_evlist__add_dummy(evlist)) {
76 perf_evlist__delete(evlist);
77 evlist = NULL;
78 }
79
80 return evlist;
81}
82
71/** 83/**
72 * perf_evlist__set_id_pos - set the positions of event ids. 84 * perf_evlist__set_id_pos - set the positions of event ids.
73 * @evlist: selected event list 85 * @evlist: selected event list
@@ -248,6 +260,22 @@ error:
248 return -ENOMEM; 260 return -ENOMEM;
249} 261}
250 262
263int perf_evlist__add_dummy(struct perf_evlist *evlist)
264{
265 struct perf_event_attr attr = {
266 .type = PERF_TYPE_SOFTWARE,
267 .config = PERF_COUNT_SW_DUMMY,
268 .size = sizeof(attr), /* to capture ABI version */
269 };
270 struct perf_evsel *evsel = perf_evsel__new(&attr);
271
272 if (evsel == NULL)
273 return -ENOMEM;
274
275 perf_evlist__add(evlist, evsel);
276 return 0;
277}
278
251static int perf_evlist__add_attrs(struct perf_evlist *evlist, 279static int perf_evlist__add_attrs(struct perf_evlist *evlist,
252 struct perf_event_attr *attrs, size_t nr_attrs) 280 struct perf_event_attr *attrs, size_t nr_attrs)
253{ 281{
@@ -336,20 +364,12 @@ static int perf_evlist__nr_threads(struct perf_evlist *evlist,
336 364
337void perf_evlist__disable(struct perf_evlist *evlist) 365void perf_evlist__disable(struct perf_evlist *evlist)
338{ 366{
339 int cpu, thread;
340 struct perf_evsel *pos; 367 struct perf_evsel *pos;
341 int nr_cpus = cpu_map__nr(evlist->cpus);
342 int nr_threads;
343 368
344 for (cpu = 0; cpu < nr_cpus; cpu++) { 369 evlist__for_each(evlist, pos) {
345 evlist__for_each(evlist, pos) { 370 if (!perf_evsel__is_group_leader(pos) || !pos->fd)
346 if (!perf_evsel__is_group_leader(pos) || !pos->fd) 371 continue;
347 continue; 372 perf_evsel__disable(pos);
348 nr_threads = perf_evlist__nr_threads(evlist, pos);
349 for (thread = 0; thread < nr_threads; thread++)
350 ioctl(FD(pos, cpu, thread),
351 PERF_EVENT_IOC_DISABLE, 0);
352 }
353 } 373 }
354 374
355 evlist->enabled = false; 375 evlist->enabled = false;
@@ -357,20 +377,12 @@ void perf_evlist__disable(struct perf_evlist *evlist)
357 377
358void perf_evlist__enable(struct perf_evlist *evlist) 378void perf_evlist__enable(struct perf_evlist *evlist)
359{ 379{
360 int cpu, thread;
361 struct perf_evsel *pos; 380 struct perf_evsel *pos;
362 int nr_cpus = cpu_map__nr(evlist->cpus);
363 int nr_threads;
364 381
365 for (cpu = 0; cpu < nr_cpus; cpu++) { 382 evlist__for_each(evlist, pos) {
366 evlist__for_each(evlist, pos) { 383 if (!perf_evsel__is_group_leader(pos) || !pos->fd)
367 if (!perf_evsel__is_group_leader(pos) || !pos->fd) 384 continue;
368 continue; 385 perf_evsel__enable(pos);
369 nr_threads = perf_evlist__nr_threads(evlist, pos);
370 for (thread = 0; thread < nr_threads; thread++)
371 ioctl(FD(pos, cpu, thread),
372 PERF_EVENT_IOC_ENABLE, 0);
373 }
374 } 386 }
375 387
376 evlist->enabled = true; 388 evlist->enabled = true;
@@ -381,48 +393,6 @@ void perf_evlist__toggle_enable(struct perf_evlist *evlist)
381 (evlist->enabled ? perf_evlist__disable : perf_evlist__enable)(evlist); 393 (evlist->enabled ? perf_evlist__disable : perf_evlist__enable)(evlist);
382} 394}
383 395
384int perf_evlist__disable_event(struct perf_evlist *evlist,
385 struct perf_evsel *evsel)
386{
387 int cpu, thread, err;
388 int nr_cpus = cpu_map__nr(evlist->cpus);
389 int nr_threads = perf_evlist__nr_threads(evlist, evsel);
390
391 if (!evsel->fd)
392 return 0;
393
394 for (cpu = 0; cpu < nr_cpus; cpu++) {
395 for (thread = 0; thread < nr_threads; thread++) {
396 err = ioctl(FD(evsel, cpu, thread),
397 PERF_EVENT_IOC_DISABLE, 0);
398 if (err)
399 return err;
400 }
401 }
402 return 0;
403}
404
405int perf_evlist__enable_event(struct perf_evlist *evlist,
406 struct perf_evsel *evsel)
407{
408 int cpu, thread, err;
409 int nr_cpus = cpu_map__nr(evlist->cpus);
410 int nr_threads = perf_evlist__nr_threads(evlist, evsel);
411
412 if (!evsel->fd)
413 return -EINVAL;
414
415 for (cpu = 0; cpu < nr_cpus; cpu++) {
416 for (thread = 0; thread < nr_threads; thread++) {
417 err = ioctl(FD(evsel, cpu, thread),
418 PERF_EVENT_IOC_ENABLE, 0);
419 if (err)
420 return err;
421 }
422 }
423 return 0;
424}
425
426static int perf_evlist__enable_event_cpu(struct perf_evlist *evlist, 396static int perf_evlist__enable_event_cpu(struct perf_evlist *evlist,
427 struct perf_evsel *evsel, int cpu) 397 struct perf_evsel *evsel, int cpu)
428{ 398{
@@ -550,9 +520,9 @@ void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel,
550 evsel->id[evsel->ids++] = id; 520 evsel->id[evsel->ids++] = id;
551} 521}
552 522
553static int perf_evlist__id_add_fd(struct perf_evlist *evlist, 523int perf_evlist__id_add_fd(struct perf_evlist *evlist,
554 struct perf_evsel *evsel, 524 struct perf_evsel *evsel,
555 int cpu, int thread, int fd) 525 int cpu, int thread, int fd)
556{ 526{
557 u64 read_data[4] = { 0, }; 527 u64 read_data[4] = { 0, };
558 int id_idx = 1; /* The first entry is the counter value */ 528 int id_idx = 1; /* The first entry is the counter value */
@@ -1486,7 +1456,7 @@ int perf_evlist__open(struct perf_evlist *evlist)
1486 perf_evlist__update_id_pos(evlist); 1456 perf_evlist__update_id_pos(evlist);
1487 1457
1488 evlist__for_each(evlist, evsel) { 1458 evlist__for_each(evlist, evsel) {
1489 err = perf_evsel__open(evsel, evlist->cpus, evlist->threads); 1459 err = perf_evsel__open(evsel, evsel->cpus, evsel->threads);
1490 if (err < 0) 1460 if (err < 0)
1491 goto out_err; 1461 goto out_err;
1492 } 1462 }
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index a459fe71b452..7c4d9a206776 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -67,6 +67,7 @@ struct perf_evsel_str_handler {
67 67
68struct perf_evlist *perf_evlist__new(void); 68struct perf_evlist *perf_evlist__new(void);
69struct perf_evlist *perf_evlist__new_default(void); 69struct perf_evlist *perf_evlist__new_default(void);
70struct perf_evlist *perf_evlist__new_dummy(void);
70void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus, 71void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
71 struct thread_map *threads); 72 struct thread_map *threads);
72void perf_evlist__exit(struct perf_evlist *evlist); 73void perf_evlist__exit(struct perf_evlist *evlist);
@@ -81,6 +82,8 @@ int __perf_evlist__add_default_attrs(struct perf_evlist *evlist,
81#define perf_evlist__add_default_attrs(evlist, array) \ 82#define perf_evlist__add_default_attrs(evlist, array) \
82 __perf_evlist__add_default_attrs(evlist, array, ARRAY_SIZE(array)) 83 __perf_evlist__add_default_attrs(evlist, array, ARRAY_SIZE(array))
83 84
85int perf_evlist__add_dummy(struct perf_evlist *evlist);
86
84int perf_evlist__add_newtp(struct perf_evlist *evlist, 87int perf_evlist__add_newtp(struct perf_evlist *evlist,
85 const char *sys, const char *name, void *handler); 88 const char *sys, const char *name, void *handler);
86 89
@@ -97,6 +100,9 @@ perf_evlist__find_tracepoint_by_name(struct perf_evlist *evlist,
97 100
98void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel, 101void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel,
99 int cpu, int thread, u64 id); 102 int cpu, int thread, u64 id);
103int perf_evlist__id_add_fd(struct perf_evlist *evlist,
104 struct perf_evsel *evsel,
105 int cpu, int thread, int fd);
100 106
101int perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd); 107int perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd);
102int perf_evlist__alloc_pollfd(struct perf_evlist *evlist); 108int perf_evlist__alloc_pollfd(struct perf_evlist *evlist);
@@ -149,10 +155,6 @@ void perf_evlist__disable(struct perf_evlist *evlist);
149void perf_evlist__enable(struct perf_evlist *evlist); 155void perf_evlist__enable(struct perf_evlist *evlist);
150void perf_evlist__toggle_enable(struct perf_evlist *evlist); 156void perf_evlist__toggle_enable(struct perf_evlist *evlist);
151 157
152int perf_evlist__disable_event(struct perf_evlist *evlist,
153 struct perf_evsel *evsel);
154int perf_evlist__enable_event(struct perf_evlist *evlist,
155 struct perf_evsel *evsel);
156int perf_evlist__enable_event_idx(struct perf_evlist *evlist, 158int perf_evlist__enable_event_idx(struct perf_evlist *evlist,
157 struct perf_evsel *evsel, int idx); 159 struct perf_evsel *evsel, int idx);
158 160
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 397fb4ed3c97..cdbaf9b51e42 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -36,6 +36,7 @@ static struct {
36 bool cloexec; 36 bool cloexec;
37 bool clockid; 37 bool clockid;
38 bool clockid_wrong; 38 bool clockid_wrong;
39 bool lbr_flags;
39} perf_missing_features; 40} perf_missing_features;
40 41
41static clockid_t clockid; 42static clockid_t clockid;
@@ -574,7 +575,9 @@ perf_evsel__config_callgraph(struct perf_evsel *evsel,
574 } else { 575 } else {
575 perf_evsel__set_sample_bit(evsel, BRANCH_STACK); 576 perf_evsel__set_sample_bit(evsel, BRANCH_STACK);
576 attr->branch_sample_type = PERF_SAMPLE_BRANCH_USER | 577 attr->branch_sample_type = PERF_SAMPLE_BRANCH_USER |
577 PERF_SAMPLE_BRANCH_CALL_STACK; 578 PERF_SAMPLE_BRANCH_CALL_STACK |
579 PERF_SAMPLE_BRANCH_NO_CYCLES |
580 PERF_SAMPLE_BRANCH_NO_FLAGS;
578 } 581 }
579 } else 582 } else
580 pr_warning("Cannot use LBR callstack with branch stack. " 583 pr_warning("Cannot use LBR callstack with branch stack. "
@@ -981,13 +984,26 @@ int perf_evsel__append_filter(struct perf_evsel *evsel,
981 return -1; 984 return -1;
982} 985}
983 986
984int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads) 987int perf_evsel__enable(struct perf_evsel *evsel)
985{ 988{
989 int nthreads = thread_map__nr(evsel->threads);
990 int ncpus = cpu_map__nr(evsel->cpus);
991
986 return perf_evsel__run_ioctl(evsel, ncpus, nthreads, 992 return perf_evsel__run_ioctl(evsel, ncpus, nthreads,
987 PERF_EVENT_IOC_ENABLE, 993 PERF_EVENT_IOC_ENABLE,
988 0); 994 0);
989} 995}
990 996
997int perf_evsel__disable(struct perf_evsel *evsel)
998{
999 int nthreads = thread_map__nr(evsel->threads);
1000 int ncpus = cpu_map__nr(evsel->cpus);
1001
1002 return perf_evsel__run_ioctl(evsel, ncpus, nthreads,
1003 PERF_EVENT_IOC_DISABLE,
1004 0);
1005}
1006
991int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads) 1007int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
992{ 1008{
993 if (ncpus == 0 || nthreads == 0) 1009 if (ncpus == 0 || nthreads == 0)
@@ -1192,6 +1208,7 @@ static void __p_sample_type(char *buf, size_t size, u64 value)
1192 bit_name(PERIOD), bit_name(STREAM_ID), bit_name(RAW), 1208 bit_name(PERIOD), bit_name(STREAM_ID), bit_name(RAW),
1193 bit_name(BRANCH_STACK), bit_name(REGS_USER), bit_name(STACK_USER), 1209 bit_name(BRANCH_STACK), bit_name(REGS_USER), bit_name(STACK_USER),
1194 bit_name(IDENTIFIER), bit_name(REGS_INTR), bit_name(DATA_SRC), 1210 bit_name(IDENTIFIER), bit_name(REGS_INTR), bit_name(DATA_SRC),
1211 bit_name(WEIGHT),
1195 { .name = NULL, } 1212 { .name = NULL, }
1196 }; 1213 };
1197#undef bit_name 1214#undef bit_name
@@ -1323,6 +1340,9 @@ fallback_missing_features:
1323 evsel->attr.mmap2 = 0; 1340 evsel->attr.mmap2 = 0;
1324 if (perf_missing_features.exclude_guest) 1341 if (perf_missing_features.exclude_guest)
1325 evsel->attr.exclude_guest = evsel->attr.exclude_host = 0; 1342 evsel->attr.exclude_guest = evsel->attr.exclude_host = 0;
1343 if (perf_missing_features.lbr_flags)
1344 evsel->attr.branch_sample_type &= ~(PERF_SAMPLE_BRANCH_NO_FLAGS |
1345 PERF_SAMPLE_BRANCH_NO_CYCLES);
1326retry_sample_id: 1346retry_sample_id:
1327 if (perf_missing_features.sample_id_all) 1347 if (perf_missing_features.sample_id_all)
1328 evsel->attr.sample_id_all = 0; 1348 evsel->attr.sample_id_all = 0;
@@ -1441,6 +1461,12 @@ try_fallback:
1441 } else if (!perf_missing_features.sample_id_all) { 1461 } else if (!perf_missing_features.sample_id_all) {
1442 perf_missing_features.sample_id_all = true; 1462 perf_missing_features.sample_id_all = true;
1443 goto retry_sample_id; 1463 goto retry_sample_id;
1464 } else if (!perf_missing_features.lbr_flags &&
1465 (evsel->attr.branch_sample_type &
1466 (PERF_SAMPLE_BRANCH_NO_CYCLES |
1467 PERF_SAMPLE_BRANCH_NO_FLAGS))) {
1468 perf_missing_features.lbr_flags = true;
1469 goto fallback_missing_features;
1444 } 1470 }
1445 1471
1446out_close: 1472out_close:
@@ -2272,6 +2298,29 @@ int perf_evsel__fprintf(struct perf_evsel *evsel,
2272 printed += comma_fprintf(fp, &first, " %s=%" PRIu64, 2298 printed += comma_fprintf(fp, &first, " %s=%" PRIu64,
2273 term, (u64)evsel->attr.sample_freq); 2299 term, (u64)evsel->attr.sample_freq);
2274 } 2300 }
2301
2302 if (details->trace_fields) {
2303 struct format_field *field;
2304
2305 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) {
2306 printed += comma_fprintf(fp, &first, " (not a tracepoint)");
2307 goto out;
2308 }
2309
2310 field = evsel->tp_format->format.fields;
2311 if (field == NULL) {
2312 printed += comma_fprintf(fp, &first, " (no trace field)");
2313 goto out;
2314 }
2315
2316 printed += comma_fprintf(fp, &first, " trace_fields: %s", field->name);
2317
2318 field = field->next;
2319 while (field) {
2320 printed += comma_fprintf(fp, &first, "%s", field->name);
2321 field = field->next;
2322 }
2323 }
2275out: 2324out:
2276 fputc('\n', fp); 2325 fputc('\n', fp);
2277 return ++printed; 2326 return ++printed;
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 0e49bd742c63..8e75434bd01c 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -227,7 +227,8 @@ int perf_evsel__append_filter(struct perf_evsel *evsel,
227 const char *op, const char *filter); 227 const char *op, const char *filter);
228int perf_evsel__apply_filter(struct perf_evsel *evsel, int ncpus, int nthreads, 228int perf_evsel__apply_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
229 const char *filter); 229 const char *filter);
230int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads); 230int perf_evsel__enable(struct perf_evsel *evsel);
231int perf_evsel__disable(struct perf_evsel *evsel);
231 232
232int perf_evsel__open_per_cpu(struct perf_evsel *evsel, 233int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
233 struct cpu_map *cpus); 234 struct cpu_map *cpus);
@@ -368,6 +369,7 @@ struct perf_attr_details {
368 bool verbose; 369 bool verbose;
369 bool event_group; 370 bool event_group;
370 bool force; 371 bool force;
372 bool trace_fields;
371}; 373};
372 374
373int perf_evsel__fprintf(struct perf_evsel *evsel, 375int perf_evsel__fprintf(struct perf_evsel *evsel,
diff --git a/tools/perf/util/exec_cmd.c b/tools/perf/util/exec_cmd.c
deleted file mode 100644
index 7adf4ad15d8f..000000000000
--- a/tools/perf/util/exec_cmd.c
+++ /dev/null
@@ -1,148 +0,0 @@
1#include "cache.h"
2#include "exec_cmd.h"
3#include "quote.h"
4
5#include <string.h>
6
7#define MAX_ARGS 32
8
9static const char *argv_exec_path;
10static const char *argv0_path;
11
12const char *system_path(const char *path)
13{
14 static const char *prefix = PREFIX;
15 struct strbuf d = STRBUF_INIT;
16
17 if (is_absolute_path(path))
18 return path;
19
20 strbuf_addf(&d, "%s/%s", prefix, path);
21 path = strbuf_detach(&d, NULL);
22 return path;
23}
24
25const char *perf_extract_argv0_path(const char *argv0)
26{
27 const char *slash;
28
29 if (!argv0 || !*argv0)
30 return NULL;
31 slash = argv0 + strlen(argv0);
32
33 while (argv0 <= slash && !is_dir_sep(*slash))
34 slash--;
35
36 if (slash >= argv0) {
37 argv0_path = strndup(argv0, slash - argv0);
38 return argv0_path ? slash + 1 : NULL;
39 }
40
41 return argv0;
42}
43
44void perf_set_argv_exec_path(const char *exec_path)
45{
46 argv_exec_path = exec_path;
47 /*
48 * Propagate this setting to external programs.
49 */
50 setenv(EXEC_PATH_ENVIRONMENT, exec_path, 1);
51}
52
53
54/* Returns the highest-priority, location to look for perf programs. */
55const char *perf_exec_path(void)
56{
57 const char *env;
58
59 if (argv_exec_path)
60 return argv_exec_path;
61
62 env = getenv(EXEC_PATH_ENVIRONMENT);
63 if (env && *env) {
64 return env;
65 }
66
67 return system_path(PERF_EXEC_PATH);
68}
69
70static void add_path(struct strbuf *out, const char *path)
71{
72 if (path && *path) {
73 if (is_absolute_path(path))
74 strbuf_addstr(out, path);
75 else
76 strbuf_addstr(out, make_nonrelative_path(path));
77
78 strbuf_addch(out, PATH_SEP);
79 }
80}
81
82void setup_path(void)
83{
84 const char *old_path = getenv("PATH");
85 struct strbuf new_path = STRBUF_INIT;
86
87 add_path(&new_path, perf_exec_path());
88 add_path(&new_path, argv0_path);
89
90 if (old_path)
91 strbuf_addstr(&new_path, old_path);
92 else
93 strbuf_addstr(&new_path, "/usr/local/bin:/usr/bin:/bin");
94
95 setenv("PATH", new_path.buf, 1);
96
97 strbuf_release(&new_path);
98}
99
100static const char **prepare_perf_cmd(const char **argv)
101{
102 int argc;
103 const char **nargv;
104
105 for (argc = 0; argv[argc]; argc++)
106 ; /* just counting */
107 nargv = malloc(sizeof(*nargv) * (argc + 2));
108
109 nargv[0] = "perf";
110 for (argc = 0; argv[argc]; argc++)
111 nargv[argc + 1] = argv[argc];
112 nargv[argc + 1] = NULL;
113 return nargv;
114}
115
116int execv_perf_cmd(const char **argv) {
117 const char **nargv = prepare_perf_cmd(argv);
118
119 /* execvp() can only ever return if it fails */
120 execvp("perf", (char **)nargv);
121
122 free(nargv);
123 return -1;
124}
125
126
127int execl_perf_cmd(const char *cmd,...)
128{
129 int argc;
130 const char *argv[MAX_ARGS + 1];
131 const char *arg;
132 va_list param;
133
134 va_start(param, cmd);
135 argv[0] = cmd;
136 argc = 1;
137 while (argc < MAX_ARGS) {
138 arg = argv[argc++] = va_arg(param, char *);
139 if (!arg)
140 break;
141 }
142 va_end(param);
143 if (MAX_ARGS <= argc)
144 return error("too many args to run %s", cmd);
145
146 argv[argc] = NULL;
147 return execv_perf_cmd(argv);
148}
diff --git a/tools/perf/util/exec_cmd.h b/tools/perf/util/exec_cmd.h
deleted file mode 100644
index bc4b915963f5..000000000000
--- a/tools/perf/util/exec_cmd.h
+++ /dev/null
@@ -1,12 +0,0 @@
1#ifndef __PERF_EXEC_CMD_H
2#define __PERF_EXEC_CMD_H
3
4extern void perf_set_argv_exec_path(const char *exec_path);
5extern const char *perf_extract_argv0_path(const char *path);
6extern const char *perf_exec_path(void);
7extern void setup_path(void);
8extern int execv_perf_cmd(const char **argv); /* NULL terminated */
9extern int execl_perf_cmd(const char *cmd, ...);
10extern const char *system_path(const char *path);
11
12#endif /* __PERF_EXEC_CMD_H */
diff --git a/tools/perf/util/generate-cmdlist.sh b/tools/perf/util/generate-cmdlist.sh
index 36a885d2cd22..0ac2037c970c 100755
--- a/tools/perf/util/generate-cmdlist.sh
+++ b/tools/perf/util/generate-cmdlist.sh
@@ -36,4 +36,19 @@ do
36 }' "Documentation/perf-$cmd.txt" 36 }' "Documentation/perf-$cmd.txt"
37done 37done
38echo "#endif /* HAVE_LIBELF_SUPPORT */" 38echo "#endif /* HAVE_LIBELF_SUPPORT */"
39
40echo "#ifdef HAVE_LIBAUDIT_SUPPORT"
41sed -n -e 's/^perf-\([^ ]*\)[ ].* audit*/\1/p' command-list.txt |
42sort |
43while read cmd
44do
45 sed -n '
46 /^NAME/,/perf-'"$cmd"'/H
47 ${
48 x
49 s/.*perf-'"$cmd"' - \(.*\)/ {"'"$cmd"'", "\1"},/
50 p
51 }' "Documentation/perf-$cmd.txt"
52done
53echo "#endif /* HAVE_LIBELF_SUPPORT */"
39echo "};" 54echo "};"
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 43838003c1a1..f50b7235ecb6 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -724,7 +724,7 @@ static int write_numa_topology(int fd, struct perf_header *h __maybe_unused,
724done: 724done:
725 free(buf); 725 free(buf);
726 fclose(fp); 726 fclose(fp);
727 free(node_map); 727 cpu_map__put(node_map);
728 return ret; 728 return ret;
729} 729}
730 730
@@ -868,6 +868,13 @@ static int write_auxtrace(int fd, struct perf_header *h,
868 return err; 868 return err;
869} 869}
870 870
871static int write_stat(int fd __maybe_unused,
872 struct perf_header *h __maybe_unused,
873 struct perf_evlist *evlist __maybe_unused)
874{
875 return 0;
876}
877
871static void print_hostname(struct perf_header *ph, int fd __maybe_unused, 878static void print_hostname(struct perf_header *ph, int fd __maybe_unused,
872 FILE *fp) 879 FILE *fp)
873{ 880{
@@ -1159,6 +1166,12 @@ static void print_auxtrace(struct perf_header *ph __maybe_unused,
1159 fprintf(fp, "# contains AUX area data (e.g. instruction trace)\n"); 1166 fprintf(fp, "# contains AUX area data (e.g. instruction trace)\n");
1160} 1167}
1161 1168
1169static void print_stat(struct perf_header *ph __maybe_unused,
1170 int fd __maybe_unused, FILE *fp)
1171{
1172 fprintf(fp, "# contains stat data\n");
1173}
1174
1162static void print_pmu_mappings(struct perf_header *ph, int fd __maybe_unused, 1175static void print_pmu_mappings(struct perf_header *ph, int fd __maybe_unused,
1163 FILE *fp) 1176 FILE *fp)
1164{ 1177{
@@ -1948,6 +1961,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
1948 FEAT_OPP(HEADER_PMU_MAPPINGS, pmu_mappings), 1961 FEAT_OPP(HEADER_PMU_MAPPINGS, pmu_mappings),
1949 FEAT_OPP(HEADER_GROUP_DESC, group_desc), 1962 FEAT_OPP(HEADER_GROUP_DESC, group_desc),
1950 FEAT_OPP(HEADER_AUXTRACE, auxtrace), 1963 FEAT_OPP(HEADER_AUXTRACE, auxtrace),
1964 FEAT_OPA(HEADER_STAT, stat),
1951}; 1965};
1952 1966
1953struct header_print_data { 1967struct header_print_data {
@@ -2686,6 +2700,152 @@ int perf_event__synthesize_attr(struct perf_tool *tool,
2686 return err; 2700 return err;
2687} 2701}
2688 2702
2703static struct event_update_event *
2704event_update_event__new(size_t size, u64 type, u64 id)
2705{
2706 struct event_update_event *ev;
2707
2708 size += sizeof(*ev);
2709 size = PERF_ALIGN(size, sizeof(u64));
2710
2711 ev = zalloc(size);
2712 if (ev) {
2713 ev->header.type = PERF_RECORD_EVENT_UPDATE;
2714 ev->header.size = (u16)size;
2715 ev->type = type;
2716 ev->id = id;
2717 }
2718 return ev;
2719}
2720
2721int
2722perf_event__synthesize_event_update_unit(struct perf_tool *tool,
2723 struct perf_evsel *evsel,
2724 perf_event__handler_t process)
2725{
2726 struct event_update_event *ev;
2727 size_t size = strlen(evsel->unit);
2728 int err;
2729
2730 ev = event_update_event__new(size + 1, PERF_EVENT_UPDATE__UNIT, evsel->id[0]);
2731 if (ev == NULL)
2732 return -ENOMEM;
2733
2734 strncpy(ev->data, evsel->unit, size);
2735 err = process(tool, (union perf_event *)ev, NULL, NULL);
2736 free(ev);
2737 return err;
2738}
2739
2740int
2741perf_event__synthesize_event_update_scale(struct perf_tool *tool,
2742 struct perf_evsel *evsel,
2743 perf_event__handler_t process)
2744{
2745 struct event_update_event *ev;
2746 struct event_update_event_scale *ev_data;
2747 int err;
2748
2749 ev = event_update_event__new(sizeof(*ev_data), PERF_EVENT_UPDATE__SCALE, evsel->id[0]);
2750 if (ev == NULL)
2751 return -ENOMEM;
2752
2753 ev_data = (struct event_update_event_scale *) ev->data;
2754 ev_data->scale = evsel->scale;
2755 err = process(tool, (union perf_event*) ev, NULL, NULL);
2756 free(ev);
2757 return err;
2758}
2759
2760int
2761perf_event__synthesize_event_update_name(struct perf_tool *tool,
2762 struct perf_evsel *evsel,
2763 perf_event__handler_t process)
2764{
2765 struct event_update_event *ev;
2766 size_t len = strlen(evsel->name);
2767 int err;
2768
2769 ev = event_update_event__new(len + 1, PERF_EVENT_UPDATE__NAME, evsel->id[0]);
2770 if (ev == NULL)
2771 return -ENOMEM;
2772
2773 strncpy(ev->data, evsel->name, len);
2774 err = process(tool, (union perf_event*) ev, NULL, NULL);
2775 free(ev);
2776 return err;
2777}
2778
2779int
2780perf_event__synthesize_event_update_cpus(struct perf_tool *tool,
2781 struct perf_evsel *evsel,
2782 perf_event__handler_t process)
2783{
2784 size_t size = sizeof(struct event_update_event);
2785 struct event_update_event *ev;
2786 int max, err;
2787 u16 type;
2788
2789 if (!evsel->own_cpus)
2790 return 0;
2791
2792 ev = cpu_map_data__alloc(evsel->own_cpus, &size, &type, &max);
2793 if (!ev)
2794 return -ENOMEM;
2795
2796 ev->header.type = PERF_RECORD_EVENT_UPDATE;
2797 ev->header.size = (u16)size;
2798 ev->type = PERF_EVENT_UPDATE__CPUS;
2799 ev->id = evsel->id[0];
2800
2801 cpu_map_data__synthesize((struct cpu_map_data *) ev->data,
2802 evsel->own_cpus,
2803 type, max);
2804
2805 err = process(tool, (union perf_event*) ev, NULL, NULL);
2806 free(ev);
2807 return err;
2808}
2809
2810size_t perf_event__fprintf_event_update(union perf_event *event, FILE *fp)
2811{
2812 struct event_update_event *ev = &event->event_update;
2813 struct event_update_event_scale *ev_scale;
2814 struct event_update_event_cpus *ev_cpus;
2815 struct cpu_map *map;
2816 size_t ret;
2817
2818 ret = fprintf(fp, "\n... id: %" PRIu64 "\n", ev->id);
2819
2820 switch (ev->type) {
2821 case PERF_EVENT_UPDATE__SCALE:
2822 ev_scale = (struct event_update_event_scale *) ev->data;
2823 ret += fprintf(fp, "... scale: %f\n", ev_scale->scale);
2824 break;
2825 case PERF_EVENT_UPDATE__UNIT:
2826 ret += fprintf(fp, "... unit: %s\n", ev->data);
2827 break;
2828 case PERF_EVENT_UPDATE__NAME:
2829 ret += fprintf(fp, "... name: %s\n", ev->data);
2830 break;
2831 case PERF_EVENT_UPDATE__CPUS:
2832 ev_cpus = (struct event_update_event_cpus *) ev->data;
2833 ret += fprintf(fp, "... ");
2834
2835 map = cpu_map__new_data(&ev_cpus->cpus);
2836 if (map)
2837 ret += cpu_map__fprintf(map, fp);
2838 else
2839 ret += fprintf(fp, "failed to get cpus\n");
2840 break;
2841 default:
2842 ret += fprintf(fp, "... unknown type\n");
2843 break;
2844 }
2845
2846 return ret;
2847}
2848
2689int perf_event__synthesize_attrs(struct perf_tool *tool, 2849int perf_event__synthesize_attrs(struct perf_tool *tool,
2690 struct perf_session *session, 2850 struct perf_session *session,
2691 perf_event__handler_t process) 2851 perf_event__handler_t process)
@@ -2745,6 +2905,51 @@ int perf_event__process_attr(struct perf_tool *tool __maybe_unused,
2745 return 0; 2905 return 0;
2746} 2906}
2747 2907
2908int perf_event__process_event_update(struct perf_tool *tool __maybe_unused,
2909 union perf_event *event,
2910 struct perf_evlist **pevlist)
2911{
2912 struct event_update_event *ev = &event->event_update;
2913 struct event_update_event_scale *ev_scale;
2914 struct event_update_event_cpus *ev_cpus;
2915 struct perf_evlist *evlist;
2916 struct perf_evsel *evsel;
2917 struct cpu_map *map;
2918
2919 if (!pevlist || *pevlist == NULL)
2920 return -EINVAL;
2921
2922 evlist = *pevlist;
2923
2924 evsel = perf_evlist__id2evsel(evlist, ev->id);
2925 if (evsel == NULL)
2926 return -EINVAL;
2927
2928 switch (ev->type) {
2929 case PERF_EVENT_UPDATE__UNIT:
2930 evsel->unit = strdup(ev->data);
2931 break;
2932 case PERF_EVENT_UPDATE__NAME:
2933 evsel->name = strdup(ev->data);
2934 break;
2935 case PERF_EVENT_UPDATE__SCALE:
2936 ev_scale = (struct event_update_event_scale *) ev->data;
2937 evsel->scale = ev_scale->scale;
2938 case PERF_EVENT_UPDATE__CPUS:
2939 ev_cpus = (struct event_update_event_cpus *) ev->data;
2940
2941 map = cpu_map__new_data(&ev_cpus->cpus);
2942 if (map)
2943 evsel->own_cpus = map;
2944 else
2945 pr_err("failed to get event_update cpus\n");
2946 default:
2947 break;
2948 }
2949
2950 return 0;
2951}
2952
2748int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, 2953int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd,
2749 struct perf_evlist *evlist, 2954 struct perf_evlist *evlist,
2750 perf_event__handler_t process) 2955 perf_event__handler_t process)
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 05f27cb6b7e3..cff9892452ee 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -31,6 +31,7 @@ enum {
31 HEADER_PMU_MAPPINGS, 31 HEADER_PMU_MAPPINGS,
32 HEADER_GROUP_DESC, 32 HEADER_GROUP_DESC,
33 HEADER_AUXTRACE, 33 HEADER_AUXTRACE,
34 HEADER_STAT,
34 HEADER_LAST_FEATURE, 35 HEADER_LAST_FEATURE,
35 HEADER_FEAT_BITS = 256, 36 HEADER_FEAT_BITS = 256,
36}; 37};
@@ -105,8 +106,24 @@ int perf_event__synthesize_attr(struct perf_tool *tool,
105int perf_event__synthesize_attrs(struct perf_tool *tool, 106int perf_event__synthesize_attrs(struct perf_tool *tool,
106 struct perf_session *session, 107 struct perf_session *session,
107 perf_event__handler_t process); 108 perf_event__handler_t process);
109int perf_event__synthesize_event_update_unit(struct perf_tool *tool,
110 struct perf_evsel *evsel,
111 perf_event__handler_t process);
112int perf_event__synthesize_event_update_scale(struct perf_tool *tool,
113 struct perf_evsel *evsel,
114 perf_event__handler_t process);
115int perf_event__synthesize_event_update_name(struct perf_tool *tool,
116 struct perf_evsel *evsel,
117 perf_event__handler_t process);
118int perf_event__synthesize_event_update_cpus(struct perf_tool *tool,
119 struct perf_evsel *evsel,
120 perf_event__handler_t process);
108int perf_event__process_attr(struct perf_tool *tool, union perf_event *event, 121int perf_event__process_attr(struct perf_tool *tool, union perf_event *event,
109 struct perf_evlist **pevlist); 122 struct perf_evlist **pevlist);
123int perf_event__process_event_update(struct perf_tool *tool __maybe_unused,
124 union perf_event *event,
125 struct perf_evlist **pevlist);
126size_t perf_event__fprintf_event_update(union perf_event *event, FILE *fp);
110 127
111int perf_event__synthesize_tracing_data(struct perf_tool *tool, 128int perf_event__synthesize_tracing_data(struct perf_tool *tool,
112 int fd, struct perf_evlist *evlist, 129 int fd, struct perf_evlist *evlist,
diff --git a/tools/perf/util/help-unknown-cmd.c b/tools/perf/util/help-unknown-cmd.c
new file mode 100644
index 000000000000..dc1e41c9b054
--- /dev/null
+++ b/tools/perf/util/help-unknown-cmd.c
@@ -0,0 +1,103 @@
1#include "cache.h"
2#include <subcmd/help.h>
3#include "../builtin.h"
4#include "levenshtein.h"
5
6static int autocorrect;
7static struct cmdnames aliases;
8
9static int perf_unknown_cmd_config(const char *var, const char *value, void *cb)
10{
11 if (!strcmp(var, "help.autocorrect"))
12 autocorrect = perf_config_int(var,value);
13 /* Also use aliases for command lookup */
14 if (!prefixcmp(var, "alias."))
15 add_cmdname(&aliases, var + 6, strlen(var + 6));
16
17 return perf_default_config(var, value, cb);
18}
19
20static int levenshtein_compare(const void *p1, const void *p2)
21{
22 const struct cmdname *const *c1 = p1, *const *c2 = p2;
23 const char *s1 = (*c1)->name, *s2 = (*c2)->name;
24 int l1 = (*c1)->len;
25 int l2 = (*c2)->len;
26 return l1 != l2 ? l1 - l2 : strcmp(s1, s2);
27}
28
29static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old)
30{
31 unsigned int i;
32
33 ALLOC_GROW(cmds->names, cmds->cnt + old->cnt, cmds->alloc);
34
35 for (i = 0; i < old->cnt; i++)
36 cmds->names[cmds->cnt++] = old->names[i];
37 zfree(&old->names);
38 old->cnt = 0;
39}
40
41const char *help_unknown_cmd(const char *cmd)
42{
43 unsigned int i, n = 0, best_similarity = 0;
44 struct cmdnames main_cmds, other_cmds;
45
46 memset(&main_cmds, 0, sizeof(main_cmds));
47 memset(&other_cmds, 0, sizeof(main_cmds));
48 memset(&aliases, 0, sizeof(aliases));
49
50 perf_config(perf_unknown_cmd_config, NULL);
51
52 load_command_list("perf-", &main_cmds, &other_cmds);
53
54 add_cmd_list(&main_cmds, &aliases);
55 add_cmd_list(&main_cmds, &other_cmds);
56 qsort(main_cmds.names, main_cmds.cnt,
57 sizeof(main_cmds.names), cmdname_compare);
58 uniq(&main_cmds);
59
60 if (main_cmds.cnt) {
61 /* This reuses cmdname->len for similarity index */
62 for (i = 0; i < main_cmds.cnt; ++i)
63 main_cmds.names[i]->len =
64 levenshtein(cmd, main_cmds.names[i]->name, 0, 2, 1, 4);
65
66 qsort(main_cmds.names, main_cmds.cnt,
67 sizeof(*main_cmds.names), levenshtein_compare);
68
69 best_similarity = main_cmds.names[0]->len;
70 n = 1;
71 while (n < main_cmds.cnt && best_similarity == main_cmds.names[n]->len)
72 ++n;
73 }
74
75 if (autocorrect && n == 1) {
76 const char *assumed = main_cmds.names[0]->name;
77
78 main_cmds.names[0] = NULL;
79 clean_cmdnames(&main_cmds);
80 fprintf(stderr, "WARNING: You called a perf program named '%s', "
81 "which does not exist.\n"
82 "Continuing under the assumption that you meant '%s'\n",
83 cmd, assumed);
84 if (autocorrect > 0) {
85 fprintf(stderr, "in %0.1f seconds automatically...\n",
86 (float)autocorrect/10.0);
87 poll(NULL, 0, autocorrect * 100);
88 }
89 return assumed;
90 }
91
92 fprintf(stderr, "perf: '%s' is not a perf-command. See 'perf --help'.\n", cmd);
93
94 if (main_cmds.cnt && best_similarity < 6) {
95 fprintf(stderr, "\nDid you mean %s?\n",
96 n < 2 ? "this": "one of these");
97
98 for (i = 0; i < n; i++)
99 fprintf(stderr, "\t%s\n", main_cmds.names[i]->name);
100 }
101
102 exit(1);
103}
diff --git a/tools/perf/util/help-unknown-cmd.h b/tools/perf/util/help-unknown-cmd.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tools/perf/util/help-unknown-cmd.h
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 4fd37d6708cb..68a7612019dc 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -131,6 +131,8 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
131 symlen = unresolved_col_width + 4 + 2; 131 symlen = unresolved_col_width + 4 + 2;
132 hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL, 132 hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL,
133 symlen); 133 symlen);
134 hists__new_col_len(hists, HISTC_MEM_DCACHELINE,
135 symlen);
134 } 136 }
135 137
136 if (h->mem_info->iaddr.sym) { 138 if (h->mem_info->iaddr.sym) {
@@ -254,6 +256,7 @@ static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
254 he_stat__decay(&he->stat); 256 he_stat__decay(&he->stat);
255 if (symbol_conf.cumulate_callchain) 257 if (symbol_conf.cumulate_callchain)
256 he_stat__decay(he->stat_acc); 258 he_stat__decay(he->stat_acc);
259 decay_callchain(he->callchain);
257 260
258 diff = prev_period - he->stat.period; 261 diff = prev_period - he->stat.period;
259 262
@@ -270,6 +273,8 @@ static void hists__delete_entry(struct hists *hists, struct hist_entry *he)
270 273
271 if (sort__need_collapse) 274 if (sort__need_collapse)
272 rb_erase(&he->rb_node_in, &hists->entries_collapsed); 275 rb_erase(&he->rb_node_in, &hists->entries_collapsed);
276 else
277 rb_erase(&he->rb_node_in, hists->entries_in);
273 278
274 --hists->nr_entries; 279 --hists->nr_entries;
275 if (!he->filtered) 280 if (!he->filtered)
@@ -367,6 +372,25 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template,
367 if (symbol_conf.use_callchain) 372 if (symbol_conf.use_callchain)
368 callchain_init(he->callchain); 373 callchain_init(he->callchain);
369 374
375 if (he->raw_data) {
376 he->raw_data = memdup(he->raw_data, he->raw_size);
377
378 if (he->raw_data == NULL) {
379 map__put(he->ms.map);
380 if (he->branch_info) {
381 map__put(he->branch_info->from.map);
382 map__put(he->branch_info->to.map);
383 free(he->branch_info);
384 }
385 if (he->mem_info) {
386 map__put(he->mem_info->iaddr.map);
387 map__put(he->mem_info->daddr.map);
388 }
389 free(he->stat_acc);
390 free(he);
391 return NULL;
392 }
393 }
370 INIT_LIST_HEAD(&he->pairs.node); 394 INIT_LIST_HEAD(&he->pairs.node);
371 thread__get(he->thread); 395 thread__get(he->thread);
372 } 396 }
@@ -459,7 +483,7 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
459 struct symbol *sym_parent, 483 struct symbol *sym_parent,
460 struct branch_info *bi, 484 struct branch_info *bi,
461 struct mem_info *mi, 485 struct mem_info *mi,
462 u64 period, u64 weight, u64 transaction, 486 struct perf_sample *sample,
463 bool sample_self) 487 bool sample_self)
464{ 488{
465 struct hist_entry entry = { 489 struct hist_entry entry = {
@@ -476,15 +500,17 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
476 .level = al->level, 500 .level = al->level,
477 .stat = { 501 .stat = {
478 .nr_events = 1, 502 .nr_events = 1,
479 .period = period, 503 .period = sample->period,
480 .weight = weight, 504 .weight = sample->weight,
481 }, 505 },
482 .parent = sym_parent, 506 .parent = sym_parent,
483 .filtered = symbol__parent_filter(sym_parent) | al->filtered, 507 .filtered = symbol__parent_filter(sym_parent) | al->filtered,
484 .hists = hists, 508 .hists = hists,
485 .branch_info = bi, 509 .branch_info = bi,
486 .mem_info = mi, 510 .mem_info = mi,
487 .transaction = transaction, 511 .transaction = sample->transaction,
512 .raw_data = sample->raw_data,
513 .raw_size = sample->raw_size,
488 }; 514 };
489 515
490 return hists__findnew_entry(hists, &entry, al, sample_self); 516 return hists__findnew_entry(hists, &entry, al, sample_self);
@@ -524,12 +550,13 @@ iter_add_single_mem_entry(struct hist_entry_iter *iter, struct addr_location *al
524 u64 cost; 550 u64 cost;
525 struct mem_info *mi = iter->priv; 551 struct mem_info *mi = iter->priv;
526 struct hists *hists = evsel__hists(iter->evsel); 552 struct hists *hists = evsel__hists(iter->evsel);
553 struct perf_sample *sample = iter->sample;
527 struct hist_entry *he; 554 struct hist_entry *he;
528 555
529 if (mi == NULL) 556 if (mi == NULL)
530 return -EINVAL; 557 return -EINVAL;
531 558
532 cost = iter->sample->weight; 559 cost = sample->weight;
533 if (!cost) 560 if (!cost)
534 cost = 1; 561 cost = 1;
535 562
@@ -540,8 +567,10 @@ iter_add_single_mem_entry(struct hist_entry_iter *iter, struct addr_location *al
540 * and this is indirectly achieved by passing period=weight here 567 * and this is indirectly achieved by passing period=weight here
541 * and the he_stat__add_period() function. 568 * and the he_stat__add_period() function.
542 */ 569 */
570 sample->period = cost;
571
543 he = __hists__add_entry(hists, al, iter->parent, NULL, mi, 572 he = __hists__add_entry(hists, al, iter->parent, NULL, mi,
544 cost, cost, 0, true); 573 sample, true);
545 if (!he) 574 if (!he)
546 return -ENOMEM; 575 return -ENOMEM;
547 576
@@ -628,6 +657,7 @@ iter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *a
628 struct branch_info *bi; 657 struct branch_info *bi;
629 struct perf_evsel *evsel = iter->evsel; 658 struct perf_evsel *evsel = iter->evsel;
630 struct hists *hists = evsel__hists(evsel); 659 struct hists *hists = evsel__hists(evsel);
660 struct perf_sample *sample = iter->sample;
631 struct hist_entry *he = NULL; 661 struct hist_entry *he = NULL;
632 int i = iter->curr; 662 int i = iter->curr;
633 int err = 0; 663 int err = 0;
@@ -641,9 +671,11 @@ iter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *a
641 * The report shows the percentage of total branches captured 671 * The report shows the percentage of total branches captured
642 * and not events sampled. Thus we use a pseudo period of 1. 672 * and not events sampled. Thus we use a pseudo period of 1.
643 */ 673 */
674 sample->period = 1;
675 sample->weight = bi->flags.cycles ? bi->flags.cycles : 1;
676
644 he = __hists__add_entry(hists, al, iter->parent, &bi[i], NULL, 677 he = __hists__add_entry(hists, al, iter->parent, &bi[i], NULL,
645 1, bi->flags.cycles ? bi->flags.cycles : 1, 678 sample, true);
646 0, true);
647 if (he == NULL) 679 if (he == NULL)
648 return -ENOMEM; 680 return -ENOMEM;
649 681
@@ -680,8 +712,7 @@ iter_add_single_normal_entry(struct hist_entry_iter *iter, struct addr_location
680 struct hist_entry *he; 712 struct hist_entry *he;
681 713
682 he = __hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL, 714 he = __hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL,
683 sample->period, sample->weight, 715 sample, true);
684 sample->transaction, true);
685 if (he == NULL) 716 if (he == NULL)
686 return -ENOMEM; 717 return -ENOMEM;
687 718
@@ -742,8 +773,7 @@ iter_add_single_cumulative_entry(struct hist_entry_iter *iter,
742 int err = 0; 773 int err = 0;
743 774
744 he = __hists__add_entry(hists, al, iter->parent, NULL, NULL, 775 he = __hists__add_entry(hists, al, iter->parent, NULL, NULL,
745 sample->period, sample->weight, 776 sample, true);
746 sample->transaction, true);
747 if (he == NULL) 777 if (he == NULL)
748 return -ENOMEM; 778 return -ENOMEM;
749 779
@@ -795,6 +825,8 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter,
795 .sym = al->sym, 825 .sym = al->sym,
796 }, 826 },
797 .parent = iter->parent, 827 .parent = iter->parent,
828 .raw_data = sample->raw_data,
829 .raw_size = sample->raw_size,
798 }; 830 };
799 int i; 831 int i;
800 struct callchain_cursor cursor; 832 struct callchain_cursor cursor;
@@ -816,8 +848,7 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter,
816 } 848 }
817 849
818 he = __hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL, 850 he = __hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL,
819 sample->period, sample->weight, 851 sample, false);
820 sample->transaction, false);
821 if (he == NULL) 852 if (he == NULL)
822 return -ENOMEM; 853 return -ENOMEM;
823 854
@@ -924,9 +955,6 @@ hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
924 int64_t cmp = 0; 955 int64_t cmp = 0;
925 956
926 perf_hpp__for_each_sort_list(fmt) { 957 perf_hpp__for_each_sort_list(fmt) {
927 if (perf_hpp__should_skip(fmt))
928 continue;
929
930 cmp = fmt->cmp(fmt, left, right); 958 cmp = fmt->cmp(fmt, left, right);
931 if (cmp) 959 if (cmp)
932 break; 960 break;
@@ -942,9 +970,6 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
942 int64_t cmp = 0; 970 int64_t cmp = 0;
943 971
944 perf_hpp__for_each_sort_list(fmt) { 972 perf_hpp__for_each_sort_list(fmt) {
945 if (perf_hpp__should_skip(fmt))
946 continue;
947
948 cmp = fmt->collapse(fmt, left, right); 973 cmp = fmt->collapse(fmt, left, right);
949 if (cmp) 974 if (cmp)
950 break; 975 break;
@@ -975,6 +1000,8 @@ void hist_entry__delete(struct hist_entry *he)
975 if (he->srcfile && he->srcfile[0]) 1000 if (he->srcfile && he->srcfile[0])
976 free(he->srcfile); 1001 free(he->srcfile);
977 free_callchain(he->callchain); 1002 free_callchain(he->callchain);
1003 free(he->trace_output);
1004 free(he->raw_data);
978 free(he); 1005 free(he);
979} 1006}
980 1007
@@ -982,9 +1009,8 @@ void hist_entry__delete(struct hist_entry *he)
982 * collapse the histogram 1009 * collapse the histogram
983 */ 1010 */
984 1011
985static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused, 1012bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,
986 struct rb_root *root, 1013 struct rb_root *root, struct hist_entry *he)
987 struct hist_entry *he)
988{ 1014{
989 struct rb_node **p = &root->rb_node; 1015 struct rb_node **p = &root->rb_node;
990 struct rb_node *parent = NULL; 1016 struct rb_node *parent = NULL;
@@ -1024,7 +1050,7 @@ static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,
1024 return true; 1050 return true;
1025} 1051}
1026 1052
1027static struct rb_root *hists__get_rotate_entries_in(struct hists *hists) 1053struct rb_root *hists__get_rotate_entries_in(struct hists *hists)
1028{ 1054{
1029 struct rb_root *root; 1055 struct rb_root *root;
1030 1056
@@ -1088,7 +1114,7 @@ static int hist_entry__sort(struct hist_entry *a, struct hist_entry *b)
1088 int64_t cmp = 0; 1114 int64_t cmp = 0;
1089 1115
1090 perf_hpp__for_each_sort_list(fmt) { 1116 perf_hpp__for_each_sort_list(fmt) {
1091 if (perf_hpp__should_skip(fmt)) 1117 if (perf_hpp__should_skip(fmt, a->hists))
1092 continue; 1118 continue;
1093 1119
1094 cmp = fmt->sort(fmt, a, b); 1120 cmp = fmt->sort(fmt, a, b);
@@ -1559,10 +1585,8 @@ int perf_hist_config(const char *var, const char *value)
1559 return 0; 1585 return 0;
1560} 1586}
1561 1587
1562static int hists_evsel__init(struct perf_evsel *evsel) 1588int __hists__init(struct hists *hists)
1563{ 1589{
1564 struct hists *hists = evsel__hists(evsel);
1565
1566 memset(hists, 0, sizeof(*hists)); 1590 memset(hists, 0, sizeof(*hists));
1567 hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT; 1591 hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT;
1568 hists->entries_in = &hists->entries_in_array[0]; 1592 hists->entries_in = &hists->entries_in_array[0];
@@ -1573,6 +1597,43 @@ static int hists_evsel__init(struct perf_evsel *evsel)
1573 return 0; 1597 return 0;
1574} 1598}
1575 1599
1600static void hists__delete_remaining_entries(struct rb_root *root)
1601{
1602 struct rb_node *node;
1603 struct hist_entry *he;
1604
1605 while (!RB_EMPTY_ROOT(root)) {
1606 node = rb_first(root);
1607 rb_erase(node, root);
1608
1609 he = rb_entry(node, struct hist_entry, rb_node_in);
1610 hist_entry__delete(he);
1611 }
1612}
1613
1614static void hists__delete_all_entries(struct hists *hists)
1615{
1616 hists__delete_entries(hists);
1617 hists__delete_remaining_entries(&hists->entries_in_array[0]);
1618 hists__delete_remaining_entries(&hists->entries_in_array[1]);
1619 hists__delete_remaining_entries(&hists->entries_collapsed);
1620}
1621
1622static void hists_evsel__exit(struct perf_evsel *evsel)
1623{
1624 struct hists *hists = evsel__hists(evsel);
1625
1626 hists__delete_all_entries(hists);
1627}
1628
1629static int hists_evsel__init(struct perf_evsel *evsel)
1630{
1631 struct hists *hists = evsel__hists(evsel);
1632
1633 __hists__init(hists);
1634 return 0;
1635}
1636
1576/* 1637/*
1577 * XXX We probably need a hists_evsel__exit() to free the hist_entries 1638 * XXX We probably need a hists_evsel__exit() to free the hist_entries
1578 * stored in the rbtree... 1639 * stored in the rbtree...
@@ -1581,7 +1642,8 @@ static int hists_evsel__init(struct perf_evsel *evsel)
1581int hists__init(void) 1642int hists__init(void)
1582{ 1643{
1583 int err = perf_evsel__object_config(sizeof(struct hists_evsel), 1644 int err = perf_evsel__object_config(sizeof(struct hists_evsel),
1584 hists_evsel__init, NULL); 1645 hists_evsel__init,
1646 hists_evsel__exit);
1585 if (err) 1647 if (err)
1586 fputs("FATAL ERROR: Couldn't setup hists class\n", stderr); 1648 fputs("FATAL ERROR: Couldn't setup hists class\n", stderr);
1587 1649
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index a48a2078d288..d4ec4822a103 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -52,6 +52,7 @@ enum hist_column {
52 HISTC_MEM_IADDR_SYMBOL, 52 HISTC_MEM_IADDR_SYMBOL,
53 HISTC_TRANSACTION, 53 HISTC_TRANSACTION,
54 HISTC_CYCLES, 54 HISTC_CYCLES,
55 HISTC_TRACE,
55 HISTC_NR_COLS, /* Last entry */ 56 HISTC_NR_COLS, /* Last entry */
56}; 57};
57 58
@@ -114,8 +115,8 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
114 struct addr_location *al, 115 struct addr_location *al,
115 struct symbol *parent, 116 struct symbol *parent,
116 struct branch_info *bi, 117 struct branch_info *bi,
117 struct mem_info *mi, u64 period, 118 struct mem_info *mi,
118 u64 weight, u64 transaction, 119 struct perf_sample *sample,
119 bool sample_self); 120 bool sample_self);
120int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al, 121int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al,
121 int max_stack_depth, void *arg); 122 int max_stack_depth, void *arg);
@@ -184,6 +185,11 @@ static inline struct hists *evsel__hists(struct perf_evsel *evsel)
184} 185}
185 186
186int hists__init(void); 187int hists__init(void);
188int __hists__init(struct hists *hists);
189
190struct rb_root *hists__get_rotate_entries_in(struct hists *hists);
191bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,
192 struct rb_root *root, struct hist_entry *he);
187 193
188struct perf_hpp { 194struct perf_hpp {
189 char *buf; 195 char *buf;
@@ -261,10 +267,20 @@ void perf_hpp__append_sort_keys(void);
261 267
262bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format); 268bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format);
263bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b); 269bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b);
270bool perf_hpp__is_dynamic_entry(struct perf_hpp_fmt *format);
271bool perf_hpp__defined_dynamic_entry(struct perf_hpp_fmt *fmt, struct hists *hists);
264 272
265static inline bool perf_hpp__should_skip(struct perf_hpp_fmt *format) 273static inline bool perf_hpp__should_skip(struct perf_hpp_fmt *format,
274 struct hists *hists)
266{ 275{
267 return format->elide; 276 if (format->elide)
277 return true;
278
279 if (perf_hpp__is_dynamic_entry(format) &&
280 !perf_hpp__defined_dynamic_entry(format, hists))
281 return true;
282
283 return false;
268} 284}
269 285
270void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists); 286void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists);
diff --git a/tools/perf/util/include/linux/string.h b/tools/perf/util/include/linux/string.h
deleted file mode 100644
index 6f19c548ecc0..000000000000
--- a/tools/perf/util/include/linux/string.h
+++ /dev/null
@@ -1,3 +0,0 @@
1#include <string.h>
2
3void *memdup(const void *src, size_t len);
diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c
index 97f963a3dcb9..81a2eb77ba7f 100644
--- a/tools/perf/util/intel-pt.c
+++ b/tools/perf/util/intel-pt.c
@@ -1744,7 +1744,7 @@ static void intel_pt_free(struct perf_session *session)
1744 auxtrace_heap__free(&pt->heap); 1744 auxtrace_heap__free(&pt->heap);
1745 intel_pt_free_events(session); 1745 intel_pt_free_events(session);
1746 session->auxtrace = NULL; 1746 session->auxtrace = NULL;
1747 thread__delete(pt->unknown_thread); 1747 thread__put(pt->unknown_thread);
1748 free(pt); 1748 free(pt);
1749} 1749}
1750 1750
@@ -2153,7 +2153,7 @@ int intel_pt_process_auxtrace_info(union perf_event *event,
2153 return 0; 2153 return 0;
2154 2154
2155err_delete_thread: 2155err_delete_thread:
2156 thread__delete(pt->unknown_thread); 2156 thread__zput(pt->unknown_thread);
2157err_free_queues: 2157err_free_queues:
2158 intel_pt_log_disable(); 2158 intel_pt_log_disable();
2159 auxtrace_queues__free(&pt->queues); 2159 auxtrace_queues__free(&pt->queues);
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 5ef90be2a249..ad79297c76c8 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -25,6 +25,7 @@ static void dsos__init(struct dsos *dsos)
25 25
26int machine__init(struct machine *machine, const char *root_dir, pid_t pid) 26int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
27{ 27{
28 memset(machine, 0, sizeof(*machine));
28 map_groups__init(&machine->kmaps, machine); 29 map_groups__init(&machine->kmaps, machine);
29 RB_CLEAR_NODE(&machine->rb_node); 30 RB_CLEAR_NODE(&machine->rb_node);
30 dsos__init(&machine->dsos); 31 dsos__init(&machine->dsos);
@@ -44,6 +45,8 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
44 machine->comm_exec = false; 45 machine->comm_exec = false;
45 machine->kernel_start = 0; 46 machine->kernel_start = 0;
46 47
48 memset(machine->vmlinux_maps, 0, sizeof(machine->vmlinux_maps));
49
47 machine->root_dir = strdup(root_dir); 50 machine->root_dir = strdup(root_dir);
48 if (machine->root_dir == NULL) 51 if (machine->root_dir == NULL)
49 return -ENOMEM; 52 return -ENOMEM;
@@ -91,6 +94,7 @@ static void dsos__purge(struct dsos *dsos)
91 94
92 list_for_each_entry_safe(pos, n, &dsos->head, node) { 95 list_for_each_entry_safe(pos, n, &dsos->head, node) {
93 RB_CLEAR_NODE(&pos->rb_node); 96 RB_CLEAR_NODE(&pos->rb_node);
97 pos->root = NULL;
94 list_del_init(&pos->node); 98 list_del_init(&pos->node);
95 dso__put(pos); 99 dso__put(pos);
96 } 100 }
@@ -121,6 +125,7 @@ void machine__delete_threads(struct machine *machine)
121 125
122void machine__exit(struct machine *machine) 126void machine__exit(struct machine *machine)
123{ 127{
128 machine__destroy_kernel_maps(machine);
124 map_groups__exit(&machine->kmaps); 129 map_groups__exit(&machine->kmaps);
125 dsos__exit(&machine->dsos); 130 dsos__exit(&machine->dsos);
126 machine__exit_vdso(machine); 131 machine__exit_vdso(machine);
@@ -347,13 +352,18 @@ static void machine__update_thread_pid(struct machine *machine,
347 } 352 }
348 353
349 th->mg = map_groups__get(leader->mg); 354 th->mg = map_groups__get(leader->mg);
350 355out_put:
356 thread__put(leader);
351 return; 357 return;
352
353out_err: 358out_err:
354 pr_err("Failed to join map groups for %d:%d\n", th->pid_, th->tid); 359 pr_err("Failed to join map groups for %d:%d\n", th->pid_, th->tid);
360 goto out_put;
355} 361}
356 362
363/*
364 * Caller must eventually drop thread->refcnt returned with a successfull
365 * lookup/new thread inserted.
366 */
357static struct thread *____machine__findnew_thread(struct machine *machine, 367static struct thread *____machine__findnew_thread(struct machine *machine,
358 pid_t pid, pid_t tid, 368 pid_t pid, pid_t tid,
359 bool create) 369 bool create)
@@ -371,7 +381,7 @@ static struct thread *____machine__findnew_thread(struct machine *machine,
371 if (th != NULL) { 381 if (th != NULL) {
372 if (th->tid == tid) { 382 if (th->tid == tid) {
373 machine__update_thread_pid(machine, th, pid); 383 machine__update_thread_pid(machine, th, pid);
374 return th; 384 return thread__get(th);
375 } 385 }
376 386
377 machine->last_match = NULL; 387 machine->last_match = NULL;
@@ -384,7 +394,7 @@ static struct thread *____machine__findnew_thread(struct machine *machine,
384 if (th->tid == tid) { 394 if (th->tid == tid) {
385 machine->last_match = th; 395 machine->last_match = th;
386 machine__update_thread_pid(machine, th, pid); 396 machine__update_thread_pid(machine, th, pid);
387 return th; 397 return thread__get(th);
388 } 398 }
389 399
390 if (tid < th->tid) 400 if (tid < th->tid)
@@ -412,7 +422,7 @@ static struct thread *____machine__findnew_thread(struct machine *machine,
412 if (thread__init_map_groups(th, machine)) { 422 if (thread__init_map_groups(th, machine)) {
413 rb_erase_init(&th->rb_node, &machine->threads); 423 rb_erase_init(&th->rb_node, &machine->threads);
414 RB_CLEAR_NODE(&th->rb_node); 424 RB_CLEAR_NODE(&th->rb_node);
415 thread__delete(th); 425 thread__put(th);
416 return NULL; 426 return NULL;
417 } 427 }
418 /* 428 /*
@@ -436,7 +446,7 @@ struct thread *machine__findnew_thread(struct machine *machine, pid_t pid,
436 struct thread *th; 446 struct thread *th;
437 447
438 pthread_rwlock_wrlock(&machine->threads_lock); 448 pthread_rwlock_wrlock(&machine->threads_lock);
439 th = thread__get(__machine__findnew_thread(machine, pid, tid)); 449 th = __machine__findnew_thread(machine, pid, tid);
440 pthread_rwlock_unlock(&machine->threads_lock); 450 pthread_rwlock_unlock(&machine->threads_lock);
441 return th; 451 return th;
442} 452}
@@ -446,7 +456,7 @@ struct thread *machine__find_thread(struct machine *machine, pid_t pid,
446{ 456{
447 struct thread *th; 457 struct thread *th;
448 pthread_rwlock_rdlock(&machine->threads_lock); 458 pthread_rwlock_rdlock(&machine->threads_lock);
449 th = thread__get(____machine__findnew_thread(machine, pid, tid, false)); 459 th = ____machine__findnew_thread(machine, pid, tid, false);
450 pthread_rwlock_unlock(&machine->threads_lock); 460 pthread_rwlock_unlock(&machine->threads_lock);
451 return th; 461 return th;
452} 462}
@@ -559,11 +569,29 @@ int machine__process_switch_event(struct machine *machine __maybe_unused,
559 return 0; 569 return 0;
560} 570}
561 571
572static void dso__adjust_kmod_long_name(struct dso *dso, const char *filename)
573{
574 const char *dup_filename;
575
576 if (!filename || !dso || !dso->long_name)
577 return;
578 if (dso->long_name[0] != '[')
579 return;
580 if (!strchr(filename, '/'))
581 return;
582
583 dup_filename = strdup(filename);
584 if (!dup_filename)
585 return;
586
587 dso__set_long_name(dso, dup_filename, true);
588}
589
562struct map *machine__findnew_module_map(struct machine *machine, u64 start, 590struct map *machine__findnew_module_map(struct machine *machine, u64 start,
563 const char *filename) 591 const char *filename)
564{ 592{
565 struct map *map = NULL; 593 struct map *map = NULL;
566 struct dso *dso; 594 struct dso *dso = NULL;
567 struct kmod_path m; 595 struct kmod_path m;
568 596
569 if (kmod_path__parse_name(&m, filename)) 597 if (kmod_path__parse_name(&m, filename))
@@ -571,8 +599,15 @@ struct map *machine__findnew_module_map(struct machine *machine, u64 start,
571 599
572 map = map_groups__find_by_name(&machine->kmaps, MAP__FUNCTION, 600 map = map_groups__find_by_name(&machine->kmaps, MAP__FUNCTION,
573 m.name); 601 m.name);
574 if (map) 602 if (map) {
603 /*
604 * If the map's dso is an offline module, give dso__load()
605 * a chance to find the file path of that module by fixing
606 * long_name.
607 */
608 dso__adjust_kmod_long_name(map->dso, filename);
575 goto out; 609 goto out;
610 }
576 611
577 dso = machine__findnew_module_dso(machine, &m, filename); 612 dso = machine__findnew_module_dso(machine, &m, filename);
578 if (dso == NULL) 613 if (dso == NULL)
@@ -584,7 +619,11 @@ struct map *machine__findnew_module_map(struct machine *machine, u64 start,
584 619
585 map_groups__insert(&machine->kmaps, map); 620 map_groups__insert(&machine->kmaps, map);
586 621
622 /* Put the map here because map_groups__insert alread got it */
623 map__put(map);
587out: 624out:
625 /* put the dso here, corresponding to machine__findnew_module_dso */
626 dso__put(dso);
588 free(m.name); 627 free(m.name);
589 return map; 628 return map;
590} 629}
@@ -739,6 +778,9 @@ int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel)
739 enum map_type type; 778 enum map_type type;
740 u64 start = machine__get_running_kernel_start(machine, NULL); 779 u64 start = machine__get_running_kernel_start(machine, NULL);
741 780
781 /* In case of renewal the kernel map, destroy previous one */
782 machine__destroy_kernel_maps(machine);
783
742 for (type = 0; type < MAP__NR_TYPES; ++type) { 784 for (type = 0; type < MAP__NR_TYPES; ++type) {
743 struct kmap *kmap; 785 struct kmap *kmap;
744 struct map *map; 786 struct map *map;
@@ -787,6 +829,7 @@ void machine__destroy_kernel_maps(struct machine *machine)
787 kmap->ref_reloc_sym = NULL; 829 kmap->ref_reloc_sym = NULL;
788 } 830 }
789 831
832 map__put(machine->vmlinux_maps[type]);
790 machine->vmlinux_maps[type] = NULL; 833 machine->vmlinux_maps[type] = NULL;
791 } 834 }
792} 835}
@@ -1083,11 +1126,14 @@ int machine__create_kernel_maps(struct machine *machine)
1083 struct dso *kernel = machine__get_kernel(machine); 1126 struct dso *kernel = machine__get_kernel(machine);
1084 const char *name; 1127 const char *name;
1085 u64 addr = machine__get_running_kernel_start(machine, &name); 1128 u64 addr = machine__get_running_kernel_start(machine, &name);
1086 if (!addr) 1129 int ret;
1130
1131 if (!addr || kernel == NULL)
1087 return -1; 1132 return -1;
1088 1133
1089 if (kernel == NULL || 1134 ret = __machine__create_kernel_maps(machine, kernel);
1090 __machine__create_kernel_maps(machine, kernel) < 0) 1135 dso__put(kernel);
1136 if (ret < 0)
1091 return -1; 1137 return -1;
1092 1138
1093 if (symbol_conf.use_modules && machine__create_modules(machine) < 0) { 1139 if (symbol_conf.use_modules && machine__create_modules(machine) < 0) {
@@ -1608,6 +1654,8 @@ static int add_callchain_ip(struct thread *thread,
1608 } 1654 }
1609 } 1655 }
1610 1656
1657 if (symbol_conf.hide_unresolved && al.sym == NULL)
1658 return 0;
1611 return callchain_cursor_append(&callchain_cursor, al.addr, al.map, al.sym); 1659 return callchain_cursor_append(&callchain_cursor, al.addr, al.map, al.sym);
1612} 1660}
1613 1661
@@ -1862,6 +1910,9 @@ check_calls:
1862static int unwind_entry(struct unwind_entry *entry, void *arg) 1910static int unwind_entry(struct unwind_entry *entry, void *arg)
1863{ 1911{
1864 struct callchain_cursor *cursor = arg; 1912 struct callchain_cursor *cursor = arg;
1913
1914 if (symbol_conf.hide_unresolved && entry->sym == NULL)
1915 return 0;
1865 return callchain_cursor_append(cursor, entry->ip, 1916 return callchain_cursor_append(cursor, entry->ip,
1866 entry->map, entry->sym); 1917 entry->map, entry->sym);
1867} 1918}
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index afc6b56cf749..171b6d10a04b 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -26,8 +26,8 @@ const char *map_type__name[MAP__NR_TYPES] = {
26static inline int is_anon_memory(const char *filename) 26static inline int is_anon_memory(const char *filename)
27{ 27{
28 return !strcmp(filename, "//anon") || 28 return !strcmp(filename, "//anon") ||
29 !strcmp(filename, "/dev/zero (deleted)") || 29 !strncmp(filename, "/dev/zero", sizeof("/dev/zero") - 1) ||
30 !strcmp(filename, "/anon_hugepage (deleted)"); 30 !strncmp(filename, "/anon_hugepage", sizeof("/anon_hugepage") - 1);
31} 31}
32 32
33static inline int is_no_dso_memory(const char *filename) 33static inline int is_no_dso_memory(const char *filename)
@@ -691,6 +691,7 @@ static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp
691 __map_groups__insert(pos->groups, before); 691 __map_groups__insert(pos->groups, before);
692 if (verbose >= 2) 692 if (verbose >= 2)
693 map__fprintf(before, fp); 693 map__fprintf(before, fp);
694 map__put(before);
694 } 695 }
695 696
696 if (map->end < pos->end) { 697 if (map->end < pos->end) {
@@ -705,6 +706,7 @@ static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp
705 __map_groups__insert(pos->groups, after); 706 __map_groups__insert(pos->groups, after);
706 if (verbose >= 2) 707 if (verbose >= 2)
707 map__fprintf(after, fp); 708 map__fprintf(after, fp);
709 map__put(after);
708 } 710 }
709put_map: 711put_map:
710 map__put(pos); 712 map__put(pos);
@@ -742,6 +744,7 @@ int map_groups__clone(struct map_groups *mg,
742 if (new == NULL) 744 if (new == NULL)
743 goto out_unlock; 745 goto out_unlock;
744 map_groups__insert(mg, new); 746 map_groups__insert(mg, new);
747 map__put(new);
745 } 748 }
746 749
747 err = 0; 750 err = 0;
diff --git a/tools/perf/util/parse-branch-options.c b/tools/perf/util/parse-branch-options.c
index 355eecf6bf59..afc088dd7d20 100644
--- a/tools/perf/util/parse-branch-options.c
+++ b/tools/perf/util/parse-branch-options.c
@@ -1,7 +1,7 @@
1#include "perf.h" 1#include "perf.h"
2#include "util/util.h" 2#include "util/util.h"
3#include "util/debug.h" 3#include "util/debug.h"
4#include "util/parse-options.h" 4#include <subcmd/parse-options.h>
5#include "util/parse-branch-options.h" 5#include "util/parse-branch-options.h"
6 6
7#define BRANCH_OPT(n, m) \ 7#define BRANCH_OPT(n, m) \
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index e48d9da75707..4f7b0efdde2f 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -4,9 +4,9 @@
4#include "../perf.h" 4#include "../perf.h"
5#include "evlist.h" 5#include "evlist.h"
6#include "evsel.h" 6#include "evsel.h"
7#include "parse-options.h" 7#include <subcmd/parse-options.h>
8#include "parse-events.h" 8#include "parse-events.h"
9#include "exec_cmd.h" 9#include <subcmd/exec-cmd.h>
10#include "string.h" 10#include "string.h"
11#include "symbol.h" 11#include "symbol.h"
12#include "cache.h" 12#include "cache.h"
@@ -124,6 +124,10 @@ struct event_symbol event_symbols_sw[PERF_COUNT_SW_MAX] = {
124 .symbol = "dummy", 124 .symbol = "dummy",
125 .alias = "", 125 .alias = "",
126 }, 126 },
127 [PERF_COUNT_SW_BPF_OUTPUT] = {
128 .symbol = "bpf-output",
129 .alias = "",
130 },
127}; 131};
128 132
129#define __PERF_EVENT_FIELD(config, name) \ 133#define __PERF_EVENT_FIELD(config, name) \
@@ -1879,7 +1883,7 @@ restart:
1879 1883
1880 for (i = 0; i < max; i++, syms++) { 1884 for (i = 0; i < max; i++, syms++) {
1881 1885
1882 if (event_glob != NULL && 1886 if (event_glob != NULL && syms->symbol != NULL &&
1883 !(strglobmatch(syms->symbol, event_glob) || 1887 !(strglobmatch(syms->symbol, event_glob) ||
1884 (syms->alias && strglobmatch(syms->alias, event_glob)))) 1888 (syms->alias && strglobmatch(syms->alias, event_glob))))
1885 continue; 1889 continue;
diff --git a/tools/perf/util/parse-regs-options.c b/tools/perf/util/parse-regs-options.c
index 4f2c1c255d81..646ecf736aad 100644
--- a/tools/perf/util/parse-regs-options.c
+++ b/tools/perf/util/parse-regs-options.c
@@ -1,7 +1,7 @@
1#include "perf.h" 1#include "perf.h"
2#include "util/util.h" 2#include "util/util.h"
3#include "util/debug.h" 3#include "util/debug.h"
4#include "util/parse-options.h" 4#include <subcmd/parse-options.h>
5#include "util/parse-regs-options.h" 5#include "util/parse-regs-options.h"
6 6
7int 7int
diff --git a/tools/perf/util/path.c b/tools/perf/util/path.c
index 5d13cb45b317..3654d964e49d 100644
--- a/tools/perf/util/path.c
+++ b/tools/perf/util/path.c
@@ -22,24 +22,6 @@ static const char *get_perf_dir(void)
22 return "."; 22 return ".";
23} 23}
24 24
25/*
26 * If libc has strlcpy() then that version will override this
27 * implementation:
28 */
29size_t __weak strlcpy(char *dest, const char *src, size_t size)
30{
31 size_t ret = strlen(src);
32
33 if (size) {
34 size_t len = (ret >= size) ? size - 1 : ret;
35
36 memcpy(dest, src, len);
37 dest[len] = '\0';
38 }
39
40 return ret;
41}
42
43static char *get_pathname(void) 25static char *get_pathname(void)
44{ 26{
45 static char pathname_array[4][PATH_MAX]; 27 static char pathname_array[4][PATH_MAX];
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index e4b173dec4b9..b597bcc8fc78 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -220,6 +220,7 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
220 alias->scale = 1.0; 220 alias->scale = 1.0;
221 alias->unit[0] = '\0'; 221 alias->unit[0] = '\0';
222 alias->per_pkg = false; 222 alias->per_pkg = false;
223 alias->snapshot = false;
223 224
224 ret = parse_events_terms(&alias->terms, val); 225 ret = parse_events_terms(&alias->terms, val);
225 if (ret) { 226 if (ret) {
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 03875f9154e7..93996ec4bbe3 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -2326,8 +2326,11 @@ static int get_new_event_name(char *buf, size_t len, const char *base,
2326 goto out; 2326 goto out;
2327 2327
2328 if (!allow_suffix) { 2328 if (!allow_suffix) {
2329 pr_warning("Error: event \"%s\" already exists. " 2329 pr_warning("Error: event \"%s\" already exists.\n"
2330 "(Use -f to force duplicates.)\n", buf); 2330 " Hint: Remove existing event by 'perf probe -d'\n"
2331 " or force duplicates by 'perf probe -f'\n"
2332 " or set 'force=yes' in BPF source.\n",
2333 buf);
2331 ret = -EEXIST; 2334 ret = -EEXIST;
2332 goto out; 2335 goto out;
2333 } 2336 }
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index bd8f03de5e40..2be10fb27172 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -654,6 +654,7 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod,
654static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf) 654static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf)
655{ 655{
656 Dwarf_Attribute fb_attr; 656 Dwarf_Attribute fb_attr;
657 Dwarf_Frame *frame = NULL;
657 size_t nops; 658 size_t nops;
658 int ret; 659 int ret;
659 660
@@ -686,11 +687,11 @@ static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf)
686#if _ELFUTILS_PREREQ(0, 142) 687#if _ELFUTILS_PREREQ(0, 142)
687 } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa && 688 } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa &&
688 pf->cfi != NULL) { 689 pf->cfi != NULL) {
689 Dwarf_Frame *frame;
690 if (dwarf_cfi_addrframe(pf->cfi, pf->addr, &frame) != 0 || 690 if (dwarf_cfi_addrframe(pf->cfi, pf->addr, &frame) != 0 ||
691 dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) { 691 dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) {
692 pr_warning("Failed to get call frame on 0x%jx\n", 692 pr_warning("Failed to get call frame on 0x%jx\n",
693 (uintmax_t)pf->addr); 693 (uintmax_t)pf->addr);
694 free(frame);
694 return -ENOENT; 695 return -ENOENT;
695 } 696 }
696#endif 697#endif
@@ -699,7 +700,8 @@ static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf)
699 /* Call finder's callback handler */ 700 /* Call finder's callback handler */
700 ret = pf->callback(sc_die, pf); 701 ret = pf->callback(sc_die, pf);
701 702
702 /* *pf->fb_ops will be cached in libdw. Don't free it. */ 703 /* Since *pf->fb_ops can be a part of frame. we should free it here. */
704 free(frame);
703 pf->fb_ops = NULL; 705 pf->fb_ops = NULL;
704 706
705 return ret; 707 return ret;
@@ -1183,7 +1185,7 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
1183 container_of(pf, struct trace_event_finder, pf); 1185 container_of(pf, struct trace_event_finder, pf);
1184 struct perf_probe_point *pp = &pf->pev->point; 1186 struct perf_probe_point *pp = &pf->pev->point;
1185 struct probe_trace_event *tev; 1187 struct probe_trace_event *tev;
1186 struct perf_probe_arg *args; 1188 struct perf_probe_arg *args = NULL;
1187 int ret, i; 1189 int ret, i;
1188 1190
1189 /* Check number of tevs */ 1191 /* Check number of tevs */
@@ -1198,19 +1200,23 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
1198 ret = convert_to_trace_point(&pf->sp_die, tf->mod, pf->addr, 1200 ret = convert_to_trace_point(&pf->sp_die, tf->mod, pf->addr,
1199 pp->retprobe, pp->function, &tev->point); 1201 pp->retprobe, pp->function, &tev->point);
1200 if (ret < 0) 1202 if (ret < 0)
1201 return ret; 1203 goto end;
1202 1204
1203 tev->point.realname = strdup(dwarf_diename(sc_die)); 1205 tev->point.realname = strdup(dwarf_diename(sc_die));
1204 if (!tev->point.realname) 1206 if (!tev->point.realname) {
1205 return -ENOMEM; 1207 ret = -ENOMEM;
1208 goto end;
1209 }
1206 1210
1207 pr_debug("Probe point found: %s+%lu\n", tev->point.symbol, 1211 pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,
1208 tev->point.offset); 1212 tev->point.offset);
1209 1213
1210 /* Expand special probe argument if exist */ 1214 /* Expand special probe argument if exist */
1211 args = zalloc(sizeof(struct perf_probe_arg) * MAX_PROBE_ARGS); 1215 args = zalloc(sizeof(struct perf_probe_arg) * MAX_PROBE_ARGS);
1212 if (args == NULL) 1216 if (args == NULL) {
1213 return -ENOMEM; 1217 ret = -ENOMEM;
1218 goto end;
1219 }
1214 1220
1215 ret = expand_probe_args(sc_die, pf, args); 1221 ret = expand_probe_args(sc_die, pf, args);
1216 if (ret < 0) 1222 if (ret < 0)
@@ -1234,6 +1240,10 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
1234 } 1240 }
1235 1241
1236end: 1242end:
1243 if (ret) {
1244 clear_probe_trace_event(tev);
1245 tf->ntevs--;
1246 }
1237 free(args); 1247 free(args);
1238 return ret; 1248 return ret;
1239} 1249}
@@ -1246,7 +1256,7 @@ int debuginfo__find_trace_events(struct debuginfo *dbg,
1246 struct trace_event_finder tf = { 1256 struct trace_event_finder tf = {
1247 .pf = {.pev = pev, .callback = add_probe_trace_event}, 1257 .pf = {.pev = pev, .callback = add_probe_trace_event},
1248 .max_tevs = probe_conf.max_probes, .mod = dbg->mod}; 1258 .max_tevs = probe_conf.max_probes, .mod = dbg->mod};
1249 int ret; 1259 int ret, i;
1250 1260
1251 /* Allocate result tevs array */ 1261 /* Allocate result tevs array */
1252 *tevs = zalloc(sizeof(struct probe_trace_event) * tf.max_tevs); 1262 *tevs = zalloc(sizeof(struct probe_trace_event) * tf.max_tevs);
@@ -1258,6 +1268,8 @@ int debuginfo__find_trace_events(struct debuginfo *dbg,
1258 1268
1259 ret = debuginfo__find_probes(dbg, &tf.pf); 1269 ret = debuginfo__find_probes(dbg, &tf.pf);
1260 if (ret < 0) { 1270 if (ret < 0) {
1271 for (i = 0; i < tf.ntevs; i++)
1272 clear_probe_trace_event(&tf.tevs[i]);
1261 zfree(tevs); 1273 zfree(tevs);
1262 return ret; 1274 return ret;
1263 } 1275 }
diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources
index 51be28b1bca2..8162ba0e2e57 100644
--- a/tools/perf/util/python-ext-sources
+++ b/tools/perf/util/python-ext-sources
@@ -10,6 +10,8 @@ util/ctype.c
10util/evlist.c 10util/evlist.c
11util/evsel.c 11util/evsel.c
12util/cpumap.c 12util/cpumap.c
13../lib/bitmap.c
14../lib/find_bit.c
13../lib/hweight.c 15../lib/hweight.c
14util/thread_map.c 16util/thread_map.c
15util/util.c 17util/util.c
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index a8e825fca42a..d72fafc1c800 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -41,6 +41,9 @@
41#include "../thread-stack.h" 41#include "../thread-stack.h"
42#include "../trace-event.h" 42#include "../trace-event.h"
43#include "../machine.h" 43#include "../machine.h"
44#include "thread_map.h"
45#include "cpumap.h"
46#include "stat.h"
44 47
45PyMODINIT_FUNC initperf_trace_context(void); 48PyMODINIT_FUNC initperf_trace_context(void);
46 49
@@ -859,6 +862,104 @@ static void python_process_event(union perf_event *event,
859 } 862 }
860} 863}
861 864
865static void get_handler_name(char *str, size_t size,
866 struct perf_evsel *evsel)
867{
868 char *p = str;
869
870 scnprintf(str, size, "stat__%s", perf_evsel__name(evsel));
871
872 while ((p = strchr(p, ':'))) {
873 *p = '_';
874 p++;
875 }
876}
877
878static void
879process_stat(struct perf_evsel *counter, int cpu, int thread, u64 tstamp,
880 struct perf_counts_values *count)
881{
882 PyObject *handler, *t;
883 static char handler_name[256];
884 int n = 0;
885
886 t = PyTuple_New(MAX_FIELDS);
887 if (!t)
888 Py_FatalError("couldn't create Python tuple");
889
890 get_handler_name(handler_name, sizeof(handler_name),
891 counter);
892
893 handler = get_handler(handler_name);
894 if (!handler) {
895 pr_debug("can't find python handler %s\n", handler_name);
896 return;
897 }
898
899 PyTuple_SetItem(t, n++, PyInt_FromLong(cpu));
900 PyTuple_SetItem(t, n++, PyInt_FromLong(thread));
901
902 tuple_set_u64(t, n++, tstamp);
903 tuple_set_u64(t, n++, count->val);
904 tuple_set_u64(t, n++, count->ena);
905 tuple_set_u64(t, n++, count->run);
906
907 if (_PyTuple_Resize(&t, n) == -1)
908 Py_FatalError("error resizing Python tuple");
909
910 call_object(handler, t, handler_name);
911
912 Py_DECREF(t);
913}
914
915static void python_process_stat(struct perf_stat_config *config,
916 struct perf_evsel *counter, u64 tstamp)
917{
918 struct thread_map *threads = counter->threads;
919 struct cpu_map *cpus = counter->cpus;
920 int cpu, thread;
921
922 if (config->aggr_mode == AGGR_GLOBAL) {
923 process_stat(counter, -1, -1, tstamp,
924 &counter->counts->aggr);
925 return;
926 }
927
928 for (thread = 0; thread < threads->nr; thread++) {
929 for (cpu = 0; cpu < cpus->nr; cpu++) {
930 process_stat(counter, cpus->map[cpu],
931 thread_map__pid(threads, thread), tstamp,
932 perf_counts(counter->counts, cpu, thread));
933 }
934 }
935}
936
937static void python_process_stat_interval(u64 tstamp)
938{
939 PyObject *handler, *t;
940 static const char handler_name[] = "stat__interval";
941 int n = 0;
942
943 t = PyTuple_New(MAX_FIELDS);
944 if (!t)
945 Py_FatalError("couldn't create Python tuple");
946
947 handler = get_handler(handler_name);
948 if (!handler) {
949 pr_debug("can't find python handler %s\n", handler_name);
950 return;
951 }
952
953 tuple_set_u64(t, n++, tstamp);
954
955 if (_PyTuple_Resize(&t, n) == -1)
956 Py_FatalError("error resizing Python tuple");
957
958 call_object(handler, t, handler_name);
959
960 Py_DECREF(t);
961}
962
862static int run_start_sub(void) 963static int run_start_sub(void)
863{ 964{
864 main_module = PyImport_AddModule("__main__"); 965 main_module = PyImport_AddModule("__main__");
@@ -1201,10 +1302,12 @@ static int python_generate_script(struct pevent *pevent, const char *outfile)
1201} 1302}
1202 1303
1203struct scripting_ops python_scripting_ops = { 1304struct scripting_ops python_scripting_ops = {
1204 .name = "Python", 1305 .name = "Python",
1205 .start_script = python_start_script, 1306 .start_script = python_start_script,
1206 .flush_script = python_flush_script, 1307 .flush_script = python_flush_script,
1207 .stop_script = python_stop_script, 1308 .stop_script = python_stop_script,
1208 .process_event = python_process_event, 1309 .process_event = python_process_event,
1209 .generate_script = python_generate_script, 1310 .process_stat = python_process_stat,
1311 .process_stat_interval = python_process_stat_interval,
1312 .generate_script = python_generate_script,
1210}; 1313};
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index c35ffdd360fe..40b7a0d0905b 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -17,6 +17,7 @@
17#include "asm/bug.h" 17#include "asm/bug.h"
18#include "auxtrace.h" 18#include "auxtrace.h"
19#include "thread-stack.h" 19#include "thread-stack.h"
20#include "stat.h"
20 21
21static int perf_session__deliver_event(struct perf_session *session, 22static int perf_session__deliver_event(struct perf_session *session,
22 union perf_event *event, 23 union perf_event *event,
@@ -36,6 +37,9 @@ static int perf_session__open(struct perf_session *session)
36 if (perf_data_file__is_pipe(file)) 37 if (perf_data_file__is_pipe(file))
37 return 0; 38 return 0;
38 39
40 if (perf_header__has_feat(&session->header, HEADER_STAT))
41 return 0;
42
39 if (!perf_evlist__valid_sample_type(session->evlist)) { 43 if (!perf_evlist__valid_sample_type(session->evlist)) {
40 pr_err("non matching sample_type\n"); 44 pr_err("non matching sample_type\n");
41 return -1; 45 return -1;
@@ -205,6 +209,18 @@ static int process_event_synth_attr_stub(struct perf_tool *tool __maybe_unused,
205 return 0; 209 return 0;
206} 210}
207 211
212static int process_event_synth_event_update_stub(struct perf_tool *tool __maybe_unused,
213 union perf_event *event __maybe_unused,
214 struct perf_evlist **pevlist
215 __maybe_unused)
216{
217 if (dump_trace)
218 perf_event__fprintf_event_update(event, stdout);
219
220 dump_printf(": unhandled!\n");
221 return 0;
222}
223
208static int process_event_sample_stub(struct perf_tool *tool __maybe_unused, 224static int process_event_sample_stub(struct perf_tool *tool __maybe_unused,
209 union perf_event *event __maybe_unused, 225 union perf_event *event __maybe_unused,
210 struct perf_sample *sample __maybe_unused, 226 struct perf_sample *sample __maybe_unused,
@@ -296,6 +312,67 @@ int process_event_auxtrace_error_stub(struct perf_tool *tool __maybe_unused,
296 return 0; 312 return 0;
297} 313}
298 314
315
316static
317int process_event_thread_map_stub(struct perf_tool *tool __maybe_unused,
318 union perf_event *event __maybe_unused,
319 struct perf_session *session __maybe_unused)
320{
321 if (dump_trace)
322 perf_event__fprintf_thread_map(event, stdout);
323
324 dump_printf(": unhandled!\n");
325 return 0;
326}
327
328static
329int process_event_cpu_map_stub(struct perf_tool *tool __maybe_unused,
330 union perf_event *event __maybe_unused,
331 struct perf_session *session __maybe_unused)
332{
333 if (dump_trace)
334 perf_event__fprintf_cpu_map(event, stdout);
335
336 dump_printf(": unhandled!\n");
337 return 0;
338}
339
340static
341int process_event_stat_config_stub(struct perf_tool *tool __maybe_unused,
342 union perf_event *event __maybe_unused,
343 struct perf_session *session __maybe_unused)
344{
345 if (dump_trace)
346 perf_event__fprintf_stat_config(event, stdout);
347
348 dump_printf(": unhandled!\n");
349 return 0;
350}
351
352static int process_stat_stub(struct perf_tool *tool __maybe_unused,
353 union perf_event *event __maybe_unused,
354 struct perf_session *perf_session
355 __maybe_unused)
356{
357 if (dump_trace)
358 perf_event__fprintf_stat(event, stdout);
359
360 dump_printf(": unhandled!\n");
361 return 0;
362}
363
364static int process_stat_round_stub(struct perf_tool *tool __maybe_unused,
365 union perf_event *event __maybe_unused,
366 struct perf_session *perf_session
367 __maybe_unused)
368{
369 if (dump_trace)
370 perf_event__fprintf_stat_round(event, stdout);
371
372 dump_printf(": unhandled!\n");
373 return 0;
374}
375
299void perf_tool__fill_defaults(struct perf_tool *tool) 376void perf_tool__fill_defaults(struct perf_tool *tool)
300{ 377{
301 if (tool->sample == NULL) 378 if (tool->sample == NULL)
@@ -328,6 +405,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
328 tool->unthrottle = process_event_stub; 405 tool->unthrottle = process_event_stub;
329 if (tool->attr == NULL) 406 if (tool->attr == NULL)
330 tool->attr = process_event_synth_attr_stub; 407 tool->attr = process_event_synth_attr_stub;
408 if (tool->event_update == NULL)
409 tool->event_update = process_event_synth_event_update_stub;
331 if (tool->tracing_data == NULL) 410 if (tool->tracing_data == NULL)
332 tool->tracing_data = process_event_synth_tracing_data_stub; 411 tool->tracing_data = process_event_synth_tracing_data_stub;
333 if (tool->build_id == NULL) 412 if (tool->build_id == NULL)
@@ -346,6 +425,16 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
346 tool->auxtrace = process_event_auxtrace_stub; 425 tool->auxtrace = process_event_auxtrace_stub;
347 if (tool->auxtrace_error == NULL) 426 if (tool->auxtrace_error == NULL)
348 tool->auxtrace_error = process_event_auxtrace_error_stub; 427 tool->auxtrace_error = process_event_auxtrace_error_stub;
428 if (tool->thread_map == NULL)
429 tool->thread_map = process_event_thread_map_stub;
430 if (tool->cpu_map == NULL)
431 tool->cpu_map = process_event_cpu_map_stub;
432 if (tool->stat_config == NULL)
433 tool->stat_config = process_event_stat_config_stub;
434 if (tool->stat == NULL)
435 tool->stat = process_stat_stub;
436 if (tool->stat_round == NULL)
437 tool->stat_round = process_stat_round_stub;
349} 438}
350 439
351static void swap_sample_id_all(union perf_event *event, void *data) 440static void swap_sample_id_all(union perf_event *event, void *data)
@@ -569,6 +658,13 @@ static void perf_event__hdr_attr_swap(union perf_event *event,
569 mem_bswap_64(event->attr.id, size); 658 mem_bswap_64(event->attr.id, size);
570} 659}
571 660
661static void perf_event__event_update_swap(union perf_event *event,
662 bool sample_id_all __maybe_unused)
663{
664 event->event_update.type = bswap_64(event->event_update.type);
665 event->event_update.id = bswap_64(event->event_update.id);
666}
667
572static void perf_event__event_type_swap(union perf_event *event, 668static void perf_event__event_type_swap(union perf_event *event,
573 bool sample_id_all __maybe_unused) 669 bool sample_id_all __maybe_unused)
574{ 670{
@@ -616,6 +712,81 @@ static void perf_event__auxtrace_error_swap(union perf_event *event,
616 event->auxtrace_error.ip = bswap_64(event->auxtrace_error.ip); 712 event->auxtrace_error.ip = bswap_64(event->auxtrace_error.ip);
617} 713}
618 714
715static void perf_event__thread_map_swap(union perf_event *event,
716 bool sample_id_all __maybe_unused)
717{
718 unsigned i;
719
720 event->thread_map.nr = bswap_64(event->thread_map.nr);
721
722 for (i = 0; i < event->thread_map.nr; i++)
723 event->thread_map.entries[i].pid = bswap_64(event->thread_map.entries[i].pid);
724}
725
726static void perf_event__cpu_map_swap(union perf_event *event,
727 bool sample_id_all __maybe_unused)
728{
729 struct cpu_map_data *data = &event->cpu_map.data;
730 struct cpu_map_entries *cpus;
731 struct cpu_map_mask *mask;
732 unsigned i;
733
734 data->type = bswap_64(data->type);
735
736 switch (data->type) {
737 case PERF_CPU_MAP__CPUS:
738 cpus = (struct cpu_map_entries *)data->data;
739
740 cpus->nr = bswap_16(cpus->nr);
741
742 for (i = 0; i < cpus->nr; i++)
743 cpus->cpu[i] = bswap_16(cpus->cpu[i]);
744 break;
745 case PERF_CPU_MAP__MASK:
746 mask = (struct cpu_map_mask *) data->data;
747
748 mask->nr = bswap_16(mask->nr);
749 mask->long_size = bswap_16(mask->long_size);
750
751 switch (mask->long_size) {
752 case 4: mem_bswap_32(&mask->mask, mask->nr); break;
753 case 8: mem_bswap_64(&mask->mask, mask->nr); break;
754 default:
755 pr_err("cpu_map swap: unsupported long size\n");
756 }
757 default:
758 break;
759 }
760}
761
762static void perf_event__stat_config_swap(union perf_event *event,
763 bool sample_id_all __maybe_unused)
764{
765 u64 size;
766
767 size = event->stat_config.nr * sizeof(event->stat_config.data[0]);
768 size += 1; /* nr item itself */
769 mem_bswap_64(&event->stat_config.nr, size);
770}
771
772static void perf_event__stat_swap(union perf_event *event,
773 bool sample_id_all __maybe_unused)
774{
775 event->stat.id = bswap_64(event->stat.id);
776 event->stat.thread = bswap_32(event->stat.thread);
777 event->stat.cpu = bswap_32(event->stat.cpu);
778 event->stat.val = bswap_64(event->stat.val);
779 event->stat.ena = bswap_64(event->stat.ena);
780 event->stat.run = bswap_64(event->stat.run);
781}
782
783static void perf_event__stat_round_swap(union perf_event *event,
784 bool sample_id_all __maybe_unused)
785{
786 event->stat_round.type = bswap_64(event->stat_round.type);
787 event->stat_round.time = bswap_64(event->stat_round.time);
788}
789
619typedef void (*perf_event__swap_op)(union perf_event *event, 790typedef void (*perf_event__swap_op)(union perf_event *event,
620 bool sample_id_all); 791 bool sample_id_all);
621 792
@@ -643,6 +814,12 @@ static perf_event__swap_op perf_event__swap_ops[] = {
643 [PERF_RECORD_AUXTRACE_INFO] = perf_event__auxtrace_info_swap, 814 [PERF_RECORD_AUXTRACE_INFO] = perf_event__auxtrace_info_swap,
644 [PERF_RECORD_AUXTRACE] = perf_event__auxtrace_swap, 815 [PERF_RECORD_AUXTRACE] = perf_event__auxtrace_swap,
645 [PERF_RECORD_AUXTRACE_ERROR] = perf_event__auxtrace_error_swap, 816 [PERF_RECORD_AUXTRACE_ERROR] = perf_event__auxtrace_error_swap,
817 [PERF_RECORD_THREAD_MAP] = perf_event__thread_map_swap,
818 [PERF_RECORD_CPU_MAP] = perf_event__cpu_map_swap,
819 [PERF_RECORD_STAT_CONFIG] = perf_event__stat_config_swap,
820 [PERF_RECORD_STAT] = perf_event__stat_swap,
821 [PERF_RECORD_STAT_ROUND] = perf_event__stat_round_swap,
822 [PERF_RECORD_EVENT_UPDATE] = perf_event__event_update_swap,
646 [PERF_RECORD_HEADER_MAX] = NULL, 823 [PERF_RECORD_HEADER_MAX] = NULL,
647}; 824};
648 825
@@ -972,7 +1149,7 @@ static struct machine *machines__find_for_cpumode(struct machines *machines,
972 1149
973 machine = machines__find(machines, pid); 1150 machine = machines__find(machines, pid);
974 if (!machine) 1151 if (!machine)
975 machine = machines__find(machines, DEFAULT_GUEST_KERNEL_ID); 1152 machine = machines__findnew(machines, DEFAULT_GUEST_KERNEL_ID);
976 return machine; 1153 return machine;
977 } 1154 }
978 1155
@@ -1154,6 +1331,8 @@ static s64 perf_session__process_user_event(struct perf_session *session,
1154 perf_session__set_comm_exec(session); 1331 perf_session__set_comm_exec(session);
1155 } 1332 }
1156 return err; 1333 return err;
1334 case PERF_RECORD_EVENT_UPDATE:
1335 return tool->event_update(tool, event, &session->evlist);
1157 case PERF_RECORD_HEADER_EVENT_TYPE: 1336 case PERF_RECORD_HEADER_EVENT_TYPE:
1158 /* 1337 /*
1159 * Depreceated, but we need to handle it for sake 1338 * Depreceated, but we need to handle it for sake
@@ -1179,6 +1358,16 @@ static s64 perf_session__process_user_event(struct perf_session *session,
1179 case PERF_RECORD_AUXTRACE_ERROR: 1358 case PERF_RECORD_AUXTRACE_ERROR:
1180 perf_session__auxtrace_error_inc(session, event); 1359 perf_session__auxtrace_error_inc(session, event);
1181 return tool->auxtrace_error(tool, event, session); 1360 return tool->auxtrace_error(tool, event, session);
1361 case PERF_RECORD_THREAD_MAP:
1362 return tool->thread_map(tool, event, session);
1363 case PERF_RECORD_CPU_MAP:
1364 return tool->cpu_map(tool, event, session);
1365 case PERF_RECORD_STAT_CONFIG:
1366 return tool->stat_config(tool, event, session);
1367 case PERF_RECORD_STAT:
1368 return tool->stat(tool, event, session);
1369 case PERF_RECORD_STAT_ROUND:
1370 return tool->stat_round(tool, event, session);
1182 default: 1371 default:
1183 return -EINVAL; 1372 return -EINVAL;
1184 } 1373 }
@@ -1311,17 +1500,20 @@ struct thread *perf_session__findnew(struct perf_session *session, pid_t pid)
1311 return machine__findnew_thread(&session->machines.host, -1, pid); 1500 return machine__findnew_thread(&session->machines.host, -1, pid);
1312} 1501}
1313 1502
1314struct thread *perf_session__register_idle_thread(struct perf_session *session) 1503int perf_session__register_idle_thread(struct perf_session *session)
1315{ 1504{
1316 struct thread *thread; 1505 struct thread *thread;
1506 int err = 0;
1317 1507
1318 thread = machine__findnew_thread(&session->machines.host, 0, 0); 1508 thread = machine__findnew_thread(&session->machines.host, 0, 0);
1319 if (thread == NULL || thread__set_comm(thread, "swapper", 0)) { 1509 if (thread == NULL || thread__set_comm(thread, "swapper", 0)) {
1320 pr_err("problem inserting idle task.\n"); 1510 pr_err("problem inserting idle task.\n");
1321 thread = NULL; 1511 err = -1;
1322 } 1512 }
1323 1513
1324 return thread; 1514 /* machine__findnew_thread() got the thread, so put it */
1515 thread__put(thread);
1516 return err;
1325} 1517}
1326 1518
1327static void perf_session__warn_about_errors(const struct perf_session *session) 1519static void perf_session__warn_about_errors(const struct perf_session *session)
@@ -1676,7 +1868,7 @@ int perf_session__process_events(struct perf_session *session)
1676 u64 size = perf_data_file__size(session->file); 1868 u64 size = perf_data_file__size(session->file);
1677 int err; 1869 int err;
1678 1870
1679 if (perf_session__register_idle_thread(session) == NULL) 1871 if (perf_session__register_idle_thread(session) < 0)
1680 return -ENOMEM; 1872 return -ENOMEM;
1681 1873
1682 if (!perf_data_file__is_pipe(session->file)) 1874 if (!perf_data_file__is_pipe(session->file))
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 3e900c0efc73..5f792e35d4c1 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -89,7 +89,7 @@ struct machine *perf_session__findnew_machine(struct perf_session *session, pid_
89} 89}
90 90
91struct thread *perf_session__findnew(struct perf_session *session, pid_t pid); 91struct thread *perf_session__findnew(struct perf_session *session, pid_t pid);
92struct thread *perf_session__register_idle_thread(struct perf_session *session); 92int perf_session__register_idle_thread(struct perf_session *session);
93 93
94size_t perf_session__fprintf(struct perf_session *session, FILE *fp); 94size_t perf_session__fprintf(struct perf_session *session, FILE *fp);
95 95
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 2d8ccd4d9e1b..ec722346e6ff 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -4,6 +4,8 @@
4#include "comm.h" 4#include "comm.h"
5#include "symbol.h" 5#include "symbol.h"
6#include "evsel.h" 6#include "evsel.h"
7#include "evlist.h"
8#include <traceevent/event-parse.h>
7 9
8regex_t parent_regex; 10regex_t parent_regex;
9const char default_parent_pattern[] = "^sys_|^do_page_fault"; 11const char default_parent_pattern[] = "^sys_|^do_page_fault";
@@ -13,6 +15,7 @@ const char default_branch_sort_order[] = "comm,dso_from,symbol_from,symbol_to,cy
13const char default_mem_sort_order[] = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked"; 15const char default_mem_sort_order[] = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked";
14const char default_top_sort_order[] = "dso,symbol"; 16const char default_top_sort_order[] = "dso,symbol";
15const char default_diff_sort_order[] = "dso,symbol"; 17const char default_diff_sort_order[] = "dso,symbol";
18const char default_tracepoint_sort_order[] = "trace";
16const char *sort_order; 19const char *sort_order;
17const char *field_order; 20const char *field_order;
18regex_t ignore_callees_regex; 21regex_t ignore_callees_regex;
@@ -443,6 +446,70 @@ struct sort_entry sort_socket = {
443 .se_width_idx = HISTC_SOCKET, 446 .se_width_idx = HISTC_SOCKET,
444}; 447};
445 448
449/* --sort trace */
450
451static char *get_trace_output(struct hist_entry *he)
452{
453 struct trace_seq seq;
454 struct perf_evsel *evsel;
455 struct pevent_record rec = {
456 .data = he->raw_data,
457 .size = he->raw_size,
458 };
459
460 evsel = hists_to_evsel(he->hists);
461
462 trace_seq_init(&seq);
463 if (symbol_conf.raw_trace) {
464 pevent_print_fields(&seq, he->raw_data, he->raw_size,
465 evsel->tp_format);
466 } else {
467 pevent_event_info(&seq, evsel->tp_format, &rec);
468 }
469 return seq.buffer;
470}
471
472static int64_t
473sort__trace_cmp(struct hist_entry *left, struct hist_entry *right)
474{
475 struct perf_evsel *evsel;
476
477 evsel = hists_to_evsel(left->hists);
478 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
479 return 0;
480
481 if (left->trace_output == NULL)
482 left->trace_output = get_trace_output(left);
483 if (right->trace_output == NULL)
484 right->trace_output = get_trace_output(right);
485
486 hists__new_col_len(left->hists, HISTC_TRACE, strlen(left->trace_output));
487 hists__new_col_len(right->hists, HISTC_TRACE, strlen(right->trace_output));
488
489 return strcmp(right->trace_output, left->trace_output);
490}
491
492static int hist_entry__trace_snprintf(struct hist_entry *he, char *bf,
493 size_t size, unsigned int width)
494{
495 struct perf_evsel *evsel;
496
497 evsel = hists_to_evsel(he->hists);
498 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
499 return scnprintf(bf, size, "%-*.*s", width, width, "N/A");
500
501 if (he->trace_output == NULL)
502 he->trace_output = get_trace_output(he);
503 return repsep_snprintf(bf, size, "%-*.*s", width, width, he->trace_output);
504}
505
506struct sort_entry sort_trace = {
507 .se_header = "Trace output",
508 .se_cmp = sort__trace_cmp,
509 .se_snprintf = hist_entry__trace_snprintf,
510 .se_width_idx = HISTC_TRACE,
511};
512
446/* sort keys for branch stacks */ 513/* sort keys for branch stacks */
447 514
448static int64_t 515static int64_t
@@ -1312,6 +1379,7 @@ static struct sort_dimension common_sort_dimensions[] = {
1312 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight), 1379 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
1313 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight), 1380 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
1314 DIM(SORT_TRANSACTION, "transaction", sort_transaction), 1381 DIM(SORT_TRANSACTION, "transaction", sort_transaction),
1382 DIM(SORT_TRACE, "trace", sort_trace),
1315}; 1383};
1316 1384
1317#undef DIM 1385#undef DIM
@@ -1529,6 +1597,455 @@ static int __sort_dimension__add_hpp_output(struct sort_dimension *sd)
1529 return 0; 1597 return 0;
1530} 1598}
1531 1599
1600struct hpp_dynamic_entry {
1601 struct perf_hpp_fmt hpp;
1602 struct perf_evsel *evsel;
1603 struct format_field *field;
1604 unsigned dynamic_len;
1605 bool raw_trace;
1606};
1607
1608static int hde_width(struct hpp_dynamic_entry *hde)
1609{
1610 if (!hde->hpp.len) {
1611 int len = hde->dynamic_len;
1612 int namelen = strlen(hde->field->name);
1613 int fieldlen = hde->field->size;
1614
1615 if (namelen > len)
1616 len = namelen;
1617
1618 if (!(hde->field->flags & FIELD_IS_STRING)) {
1619 /* length for print hex numbers */
1620 fieldlen = hde->field->size * 2 + 2;
1621 }
1622 if (fieldlen > len)
1623 len = fieldlen;
1624
1625 hde->hpp.len = len;
1626 }
1627 return hde->hpp.len;
1628}
1629
1630static void update_dynamic_len(struct hpp_dynamic_entry *hde,
1631 struct hist_entry *he)
1632{
1633 char *str, *pos;
1634 struct format_field *field = hde->field;
1635 size_t namelen;
1636 bool last = false;
1637
1638 if (hde->raw_trace)
1639 return;
1640
1641 /* parse pretty print result and update max length */
1642 if (!he->trace_output)
1643 he->trace_output = get_trace_output(he);
1644
1645 namelen = strlen(field->name);
1646 str = he->trace_output;
1647
1648 while (str) {
1649 pos = strchr(str, ' ');
1650 if (pos == NULL) {
1651 last = true;
1652 pos = str + strlen(str);
1653 }
1654
1655 if (!strncmp(str, field->name, namelen)) {
1656 size_t len;
1657
1658 str += namelen + 1;
1659 len = pos - str;
1660
1661 if (len > hde->dynamic_len)
1662 hde->dynamic_len = len;
1663 break;
1664 }
1665
1666 if (last)
1667 str = NULL;
1668 else
1669 str = pos + 1;
1670 }
1671}
1672
1673static int __sort__hde_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1674 struct perf_evsel *evsel __maybe_unused)
1675{
1676 struct hpp_dynamic_entry *hde;
1677 size_t len = fmt->user_len;
1678
1679 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1680
1681 if (!len)
1682 len = hde_width(hde);
1683
1684 return scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, hde->field->name);
1685}
1686
1687static int __sort__hde_width(struct perf_hpp_fmt *fmt,
1688 struct perf_hpp *hpp __maybe_unused,
1689 struct perf_evsel *evsel __maybe_unused)
1690{
1691 struct hpp_dynamic_entry *hde;
1692 size_t len = fmt->user_len;
1693
1694 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1695
1696 if (!len)
1697 len = hde_width(hde);
1698
1699 return len;
1700}
1701
1702bool perf_hpp__defined_dynamic_entry(struct perf_hpp_fmt *fmt, struct hists *hists)
1703{
1704 struct hpp_dynamic_entry *hde;
1705
1706 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1707
1708 return hists_to_evsel(hists) == hde->evsel;
1709}
1710
1711static int __sort__hde_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1712 struct hist_entry *he)
1713{
1714 struct hpp_dynamic_entry *hde;
1715 size_t len = fmt->user_len;
1716 char *str, *pos;
1717 struct format_field *field;
1718 size_t namelen;
1719 bool last = false;
1720 int ret;
1721
1722 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1723
1724 if (!len)
1725 len = hde_width(hde);
1726
1727 if (hde->raw_trace)
1728 goto raw_field;
1729
1730 field = hde->field;
1731 namelen = strlen(field->name);
1732 str = he->trace_output;
1733
1734 while (str) {
1735 pos = strchr(str, ' ');
1736 if (pos == NULL) {
1737 last = true;
1738 pos = str + strlen(str);
1739 }
1740
1741 if (!strncmp(str, field->name, namelen)) {
1742 str += namelen + 1;
1743 str = strndup(str, pos - str);
1744
1745 if (str == NULL)
1746 return scnprintf(hpp->buf, hpp->size,
1747 "%*.*s", len, len, "ERROR");
1748 break;
1749 }
1750
1751 if (last)
1752 str = NULL;
1753 else
1754 str = pos + 1;
1755 }
1756
1757 if (str == NULL) {
1758 struct trace_seq seq;
1759raw_field:
1760 trace_seq_init(&seq);
1761 pevent_print_field(&seq, he->raw_data, hde->field);
1762 str = seq.buffer;
1763 }
1764
1765 ret = scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, str);
1766 free(str);
1767 return ret;
1768}
1769
1770static int64_t __sort__hde_cmp(struct perf_hpp_fmt *fmt,
1771 struct hist_entry *a, struct hist_entry *b)
1772{
1773 struct hpp_dynamic_entry *hde;
1774 struct format_field *field;
1775 unsigned offset, size;
1776
1777 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1778
1779 field = hde->field;
1780 if (field->flags & FIELD_IS_DYNAMIC) {
1781 unsigned long long dyn;
1782
1783 pevent_read_number_field(field, a->raw_data, &dyn);
1784 offset = dyn & 0xffff;
1785 size = (dyn >> 16) & 0xffff;
1786
1787 /* record max width for output */
1788 if (size > hde->dynamic_len)
1789 hde->dynamic_len = size;
1790 } else {
1791 offset = field->offset;
1792 size = field->size;
1793
1794 update_dynamic_len(hde, a);
1795 update_dynamic_len(hde, b);
1796 }
1797
1798 return memcmp(a->raw_data + offset, b->raw_data + offset, size);
1799}
1800
1801bool perf_hpp__is_dynamic_entry(struct perf_hpp_fmt *fmt)
1802{
1803 return fmt->cmp == __sort__hde_cmp;
1804}
1805
1806static struct hpp_dynamic_entry *
1807__alloc_dynamic_entry(struct perf_evsel *evsel, struct format_field *field)
1808{
1809 struct hpp_dynamic_entry *hde;
1810
1811 hde = malloc(sizeof(*hde));
1812 if (hde == NULL) {
1813 pr_debug("Memory allocation failed\n");
1814 return NULL;
1815 }
1816
1817 hde->evsel = evsel;
1818 hde->field = field;
1819 hde->dynamic_len = 0;
1820
1821 hde->hpp.name = field->name;
1822 hde->hpp.header = __sort__hde_header;
1823 hde->hpp.width = __sort__hde_width;
1824 hde->hpp.entry = __sort__hde_entry;
1825 hde->hpp.color = NULL;
1826
1827 hde->hpp.cmp = __sort__hde_cmp;
1828 hde->hpp.collapse = __sort__hde_cmp;
1829 hde->hpp.sort = __sort__hde_cmp;
1830
1831 INIT_LIST_HEAD(&hde->hpp.list);
1832 INIT_LIST_HEAD(&hde->hpp.sort_list);
1833 hde->hpp.elide = false;
1834 hde->hpp.len = 0;
1835 hde->hpp.user_len = 0;
1836
1837 return hde;
1838}
1839
1840static int parse_field_name(char *str, char **event, char **field, char **opt)
1841{
1842 char *event_name, *field_name, *opt_name;
1843
1844 event_name = str;
1845 field_name = strchr(str, '.');
1846
1847 if (field_name) {
1848 *field_name++ = '\0';
1849 } else {
1850 event_name = NULL;
1851 field_name = str;
1852 }
1853
1854 opt_name = strchr(field_name, '/');
1855 if (opt_name)
1856 *opt_name++ = '\0';
1857
1858 *event = event_name;
1859 *field = field_name;
1860 *opt = opt_name;
1861
1862 return 0;
1863}
1864
1865/* find match evsel using a given event name. The event name can be:
1866 * 1. '%' + event index (e.g. '%1' for first event)
1867 * 2. full event name (e.g. sched:sched_switch)
1868 * 3. partial event name (should not contain ':')
1869 */
1870static struct perf_evsel *find_evsel(struct perf_evlist *evlist, char *event_name)
1871{
1872 struct perf_evsel *evsel = NULL;
1873 struct perf_evsel *pos;
1874 bool full_name;
1875
1876 /* case 1 */
1877 if (event_name[0] == '%') {
1878 int nr = strtol(event_name+1, NULL, 0);
1879
1880 if (nr > evlist->nr_entries)
1881 return NULL;
1882
1883 evsel = perf_evlist__first(evlist);
1884 while (--nr > 0)
1885 evsel = perf_evsel__next(evsel);
1886
1887 return evsel;
1888 }
1889
1890 full_name = !!strchr(event_name, ':');
1891 evlist__for_each(evlist, pos) {
1892 /* case 2 */
1893 if (full_name && !strcmp(pos->name, event_name))
1894 return pos;
1895 /* case 3 */
1896 if (!full_name && strstr(pos->name, event_name)) {
1897 if (evsel) {
1898 pr_debug("'%s' event is ambiguous: it can be %s or %s\n",
1899 event_name, evsel->name, pos->name);
1900 return NULL;
1901 }
1902 evsel = pos;
1903 }
1904 }
1905
1906 return evsel;
1907}
1908
1909static int __dynamic_dimension__add(struct perf_evsel *evsel,
1910 struct format_field *field,
1911 bool raw_trace)
1912{
1913 struct hpp_dynamic_entry *hde;
1914
1915 hde = __alloc_dynamic_entry(evsel, field);
1916 if (hde == NULL)
1917 return -ENOMEM;
1918
1919 hde->raw_trace = raw_trace;
1920
1921 perf_hpp__register_sort_field(&hde->hpp);
1922 return 0;
1923}
1924
1925static int add_evsel_fields(struct perf_evsel *evsel, bool raw_trace)
1926{
1927 int ret;
1928 struct format_field *field;
1929
1930 field = evsel->tp_format->format.fields;
1931 while (field) {
1932 ret = __dynamic_dimension__add(evsel, field, raw_trace);
1933 if (ret < 0)
1934 return ret;
1935
1936 field = field->next;
1937 }
1938 return 0;
1939}
1940
1941static int add_all_dynamic_fields(struct perf_evlist *evlist, bool raw_trace)
1942{
1943 int ret;
1944 struct perf_evsel *evsel;
1945
1946 evlist__for_each(evlist, evsel) {
1947 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
1948 continue;
1949
1950 ret = add_evsel_fields(evsel, raw_trace);
1951 if (ret < 0)
1952 return ret;
1953 }
1954 return 0;
1955}
1956
1957static int add_all_matching_fields(struct perf_evlist *evlist,
1958 char *field_name, bool raw_trace)
1959{
1960 int ret = -ESRCH;
1961 struct perf_evsel *evsel;
1962 struct format_field *field;
1963
1964 evlist__for_each(evlist, evsel) {
1965 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
1966 continue;
1967
1968 field = pevent_find_any_field(evsel->tp_format, field_name);
1969 if (field == NULL)
1970 continue;
1971
1972 ret = __dynamic_dimension__add(evsel, field, raw_trace);
1973 if (ret < 0)
1974 break;
1975 }
1976 return ret;
1977}
1978
1979static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok)
1980{
1981 char *str, *event_name, *field_name, *opt_name;
1982 struct perf_evsel *evsel;
1983 struct format_field *field;
1984 bool raw_trace = symbol_conf.raw_trace;
1985 int ret = 0;
1986
1987 if (evlist == NULL)
1988 return -ENOENT;
1989
1990 str = strdup(tok);
1991 if (str == NULL)
1992 return -ENOMEM;
1993
1994 if (parse_field_name(str, &event_name, &field_name, &opt_name) < 0) {
1995 ret = -EINVAL;
1996 goto out;
1997 }
1998
1999 if (opt_name) {
2000 if (strcmp(opt_name, "raw")) {
2001 pr_debug("unsupported field option %s\n", opt_name);
2002 ret = -EINVAL;
2003 goto out;
2004 }
2005 raw_trace = true;
2006 }
2007
2008 if (!strcmp(field_name, "trace_fields")) {
2009 ret = add_all_dynamic_fields(evlist, raw_trace);
2010 goto out;
2011 }
2012
2013 if (event_name == NULL) {
2014 ret = add_all_matching_fields(evlist, field_name, raw_trace);
2015 goto out;
2016 }
2017
2018 evsel = find_evsel(evlist, event_name);
2019 if (evsel == NULL) {
2020 pr_debug("Cannot find event: %s\n", event_name);
2021 ret = -ENOENT;
2022 goto out;
2023 }
2024
2025 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) {
2026 pr_debug("%s is not a tracepoint event\n", event_name);
2027 ret = -EINVAL;
2028 goto out;
2029 }
2030
2031 if (!strcmp(field_name, "*")) {
2032 ret = add_evsel_fields(evsel, raw_trace);
2033 } else {
2034 field = pevent_find_any_field(evsel->tp_format, field_name);
2035 if (field == NULL) {
2036 pr_debug("Cannot find event field for %s.%s\n",
2037 event_name, field_name);
2038 return -ENOENT;
2039 }
2040
2041 ret = __dynamic_dimension__add(evsel, field, raw_trace);
2042 }
2043
2044out:
2045 free(str);
2046 return ret;
2047}
2048
1532static int __sort_dimension__add(struct sort_dimension *sd) 2049static int __sort_dimension__add(struct sort_dimension *sd)
1533{ 2050{
1534 if (sd->taken) 2051 if (sd->taken)
@@ -1583,7 +2100,8 @@ int hpp_dimension__add_output(unsigned col)
1583 return __hpp_dimension__add_output(&hpp_sort_dimensions[col]); 2100 return __hpp_dimension__add_output(&hpp_sort_dimensions[col]);
1584} 2101}
1585 2102
1586int sort_dimension__add(const char *tok) 2103static int sort_dimension__add(const char *tok,
2104 struct perf_evlist *evlist __maybe_unused)
1587{ 2105{
1588 unsigned int i; 2106 unsigned int i;
1589 2107
@@ -1664,10 +2182,13 @@ int sort_dimension__add(const char *tok)
1664 return 0; 2182 return 0;
1665 } 2183 }
1666 2184
2185 if (!add_dynamic_entry(evlist, tok))
2186 return 0;
2187
1667 return -ESRCH; 2188 return -ESRCH;
1668} 2189}
1669 2190
1670static const char *get_default_sort_order(void) 2191static const char *get_default_sort_order(struct perf_evlist *evlist)
1671{ 2192{
1672 const char *default_sort_orders[] = { 2193 const char *default_sort_orders[] = {
1673 default_sort_order, 2194 default_sort_order,
@@ -1675,14 +2196,33 @@ static const char *get_default_sort_order(void)
1675 default_mem_sort_order, 2196 default_mem_sort_order,
1676 default_top_sort_order, 2197 default_top_sort_order,
1677 default_diff_sort_order, 2198 default_diff_sort_order,
2199 default_tracepoint_sort_order,
1678 }; 2200 };
2201 bool use_trace = true;
2202 struct perf_evsel *evsel;
1679 2203
1680 BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders)); 2204 BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders));
1681 2205
2206 if (evlist == NULL)
2207 goto out_no_evlist;
2208
2209 evlist__for_each(evlist, evsel) {
2210 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) {
2211 use_trace = false;
2212 break;
2213 }
2214 }
2215
2216 if (use_trace) {
2217 sort__mode = SORT_MODE__TRACEPOINT;
2218 if (symbol_conf.raw_trace)
2219 return "trace_fields";
2220 }
2221out_no_evlist:
1682 return default_sort_orders[sort__mode]; 2222 return default_sort_orders[sort__mode];
1683} 2223}
1684 2224
1685static int setup_sort_order(void) 2225static int setup_sort_order(struct perf_evlist *evlist)
1686{ 2226{
1687 char *new_sort_order; 2227 char *new_sort_order;
1688 2228
@@ -1703,7 +2243,7 @@ static int setup_sort_order(void)
1703 * because it's checked over the rest of the code. 2243 * because it's checked over the rest of the code.
1704 */ 2244 */
1705 if (asprintf(&new_sort_order, "%s,%s", 2245 if (asprintf(&new_sort_order, "%s,%s",
1706 get_default_sort_order(), sort_order + 1) < 0) { 2246 get_default_sort_order(evlist), sort_order + 1) < 0) {
1707 error("Not enough memory to set up --sort"); 2247 error("Not enough memory to set up --sort");
1708 return -ENOMEM; 2248 return -ENOMEM;
1709 } 2249 }
@@ -1712,13 +2252,41 @@ static int setup_sort_order(void)
1712 return 0; 2252 return 0;
1713} 2253}
1714 2254
1715static int __setup_sorting(void) 2255/*
2256 * Adds 'pre,' prefix into 'str' is 'pre' is
2257 * not already part of 'str'.
2258 */
2259static char *prefix_if_not_in(const char *pre, char *str)
2260{
2261 char *n;
2262
2263 if (!str || strstr(str, pre))
2264 return str;
2265
2266 if (asprintf(&n, "%s,%s", pre, str) < 0)
2267 return NULL;
2268
2269 free(str);
2270 return n;
2271}
2272
2273static char *setup_overhead(char *keys)
2274{
2275 keys = prefix_if_not_in("overhead", keys);
2276
2277 if (symbol_conf.cumulate_callchain)
2278 keys = prefix_if_not_in("overhead_children", keys);
2279
2280 return keys;
2281}
2282
2283static int __setup_sorting(struct perf_evlist *evlist)
1716{ 2284{
1717 char *tmp, *tok, *str; 2285 char *tmp, *tok, *str;
1718 const char *sort_keys; 2286 const char *sort_keys;
1719 int ret = 0; 2287 int ret = 0;
1720 2288
1721 ret = setup_sort_order(); 2289 ret = setup_sort_order(evlist);
1722 if (ret) 2290 if (ret)
1723 return ret; 2291 return ret;
1724 2292
@@ -1732,7 +2300,7 @@ static int __setup_sorting(void)
1732 return 0; 2300 return 0;
1733 } 2301 }
1734 2302
1735 sort_keys = get_default_sort_order(); 2303 sort_keys = get_default_sort_order(evlist);
1736 } 2304 }
1737 2305
1738 str = strdup(sort_keys); 2306 str = strdup(sort_keys);
@@ -1741,9 +2309,20 @@ static int __setup_sorting(void)
1741 return -ENOMEM; 2309 return -ENOMEM;
1742 } 2310 }
1743 2311
2312 /*
2313 * Prepend overhead fields for backward compatibility.
2314 */
2315 if (!is_strict_order(field_order)) {
2316 str = setup_overhead(str);
2317 if (str == NULL) {
2318 error("Not enough memory to setup overhead keys");
2319 return -ENOMEM;
2320 }
2321 }
2322
1744 for (tok = strtok_r(str, ", ", &tmp); 2323 for (tok = strtok_r(str, ", ", &tmp);
1745 tok; tok = strtok_r(NULL, ", ", &tmp)) { 2324 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1746 ret = sort_dimension__add(tok); 2325 ret = sort_dimension__add(tok, evlist);
1747 if (ret == -EINVAL) { 2326 if (ret == -EINVAL) {
1748 error("Invalid --sort key: `%s'", tok); 2327 error("Invalid --sort key: `%s'", tok);
1749 break; 2328 break;
@@ -1954,16 +2533,16 @@ out:
1954 return ret; 2533 return ret;
1955} 2534}
1956 2535
1957int setup_sorting(void) 2536int setup_sorting(struct perf_evlist *evlist)
1958{ 2537{
1959 int err; 2538 int err;
1960 2539
1961 err = __setup_sorting(); 2540 err = __setup_sorting(evlist);
1962 if (err < 0) 2541 if (err < 0)
1963 return err; 2542 return err;
1964 2543
1965 if (parent_pattern != default_parent_pattern) { 2544 if (parent_pattern != default_parent_pattern) {
1966 err = sort_dimension__add("parent"); 2545 err = sort_dimension__add("parent", evlist);
1967 if (err < 0) 2546 if (err < 0)
1968 return err; 2547 return err;
1969 } 2548 }
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 31228851e397..687bbb124428 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -18,7 +18,7 @@
18#include "debug.h" 18#include "debug.h"
19#include "header.h" 19#include "header.h"
20 20
21#include "parse-options.h" 21#include <subcmd/parse-options.h>
22#include "parse-events.h" 22#include "parse-events.h"
23#include "hist.h" 23#include "hist.h"
24#include "thread.h" 24#include "thread.h"
@@ -122,6 +122,9 @@ struct hist_entry {
122 struct branch_info *branch_info; 122 struct branch_info *branch_info;
123 struct hists *hists; 123 struct hists *hists;
124 struct mem_info *mem_info; 124 struct mem_info *mem_info;
125 void *raw_data;
126 u32 raw_size;
127 void *trace_output;
125 struct callchain_root callchain[0]; /* must be last member */ 128 struct callchain_root callchain[0]; /* must be last member */
126}; 129};
127 130
@@ -164,6 +167,7 @@ enum sort_mode {
164 SORT_MODE__MEMORY, 167 SORT_MODE__MEMORY,
165 SORT_MODE__TOP, 168 SORT_MODE__TOP,
166 SORT_MODE__DIFF, 169 SORT_MODE__DIFF,
170 SORT_MODE__TRACEPOINT,
167}; 171};
168 172
169enum sort_type { 173enum sort_type {
@@ -180,6 +184,7 @@ enum sort_type {
180 SORT_LOCAL_WEIGHT, 184 SORT_LOCAL_WEIGHT,
181 SORT_GLOBAL_WEIGHT, 185 SORT_GLOBAL_WEIGHT,
182 SORT_TRANSACTION, 186 SORT_TRANSACTION,
187 SORT_TRACE,
183 188
184 /* branch stack specific sort keys */ 189 /* branch stack specific sort keys */
185 __SORT_BRANCH_STACK, 190 __SORT_BRANCH_STACK,
@@ -209,8 +214,6 @@ enum sort_type {
209 */ 214 */
210 215
211struct sort_entry { 216struct sort_entry {
212 struct list_head list;
213
214 const char *se_header; 217 const char *se_header;
215 218
216 int64_t (*se_cmp)(struct hist_entry *, struct hist_entry *); 219 int64_t (*se_cmp)(struct hist_entry *, struct hist_entry *);
@@ -224,10 +227,11 @@ struct sort_entry {
224extern struct sort_entry sort_thread; 227extern struct sort_entry sort_thread;
225extern struct list_head hist_entry__sort_list; 228extern struct list_head hist_entry__sort_list;
226 229
227int setup_sorting(void); 230struct perf_evlist;
231struct pevent;
232int setup_sorting(struct perf_evlist *evlist);
228int setup_output_field(void); 233int setup_output_field(void);
229void reset_output_field(void); 234void reset_output_field(void);
230extern int sort_dimension__add(const char *);
231void sort__setup_elide(FILE *fp); 235void sort__setup_elide(FILE *fp);
232void perf_hpp__set_elide(int idx, bool elide); 236void perf_hpp__set_elide(int idx, bool elide);
233 237
diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c
index 2d9d8306dbd3..2b58edccd56f 100644
--- a/tools/perf/util/stat.c
+++ b/tools/perf/util/stat.c
@@ -310,7 +310,6 @@ int perf_stat_process_counter(struct perf_stat_config *config,
310 int i, ret; 310 int i, ret;
311 311
312 aggr->val = aggr->ena = aggr->run = 0; 312 aggr->val = aggr->ena = aggr->run = 0;
313 init_stats(ps->res_stats);
314 313
315 if (counter->per_pkg) 314 if (counter->per_pkg)
316 zero_per_pkg(counter); 315 zero_per_pkg(counter);
@@ -341,3 +340,65 @@ int perf_stat_process_counter(struct perf_stat_config *config,
341 340
342 return 0; 341 return 0;
343} 342}
343
344int perf_event__process_stat_event(struct perf_tool *tool __maybe_unused,
345 union perf_event *event,
346 struct perf_session *session)
347{
348 struct perf_counts_values count;
349 struct stat_event *st = &event->stat;
350 struct perf_evsel *counter;
351
352 count.val = st->val;
353 count.ena = st->ena;
354 count.run = st->run;
355
356 counter = perf_evlist__id2evsel(session->evlist, st->id);
357 if (!counter) {
358 pr_err("Failed to resolve counter for stat event.\n");
359 return -EINVAL;
360 }
361
362 *perf_counts(counter->counts, st->cpu, st->thread) = count;
363 counter->supported = true;
364 return 0;
365}
366
367size_t perf_event__fprintf_stat(union perf_event *event, FILE *fp)
368{
369 struct stat_event *st = (struct stat_event *) event;
370 size_t ret;
371
372 ret = fprintf(fp, "\n... id %" PRIu64 ", cpu %d, thread %d\n",
373 st->id, st->cpu, st->thread);
374 ret += fprintf(fp, "... value %" PRIu64 ", enabled %" PRIu64 ", running %" PRIu64 "\n",
375 st->val, st->ena, st->run);
376
377 return ret;
378}
379
380size_t perf_event__fprintf_stat_round(union perf_event *event, FILE *fp)
381{
382 struct stat_round_event *rd = (struct stat_round_event *)event;
383 size_t ret;
384
385 ret = fprintf(fp, "\n... time %" PRIu64 ", type %s\n", rd->time,
386 rd->type == PERF_STAT_ROUND_TYPE__FINAL ? "FINAL" : "INTERVAL");
387
388 return ret;
389}
390
391size_t perf_event__fprintf_stat_config(union perf_event *event, FILE *fp)
392{
393 struct perf_stat_config sc;
394 size_t ret;
395
396 perf_event__read_stat_config(&sc, &event->stat_config);
397
398 ret = fprintf(fp, "\n");
399 ret += fprintf(fp, "... aggr_mode %d\n", sc.aggr_mode);
400 ret += fprintf(fp, "... scale %d\n", sc.scale);
401 ret += fprintf(fp, "... interval %u\n", sc.interval);
402
403 return ret;
404}
diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h
index da1d11c4f8c1..086f4e128d63 100644
--- a/tools/perf/util/stat.h
+++ b/tools/perf/util/stat.h
@@ -90,4 +90,14 @@ void perf_evlist__reset_stats(struct perf_evlist *evlist);
90 90
91int perf_stat_process_counter(struct perf_stat_config *config, 91int perf_stat_process_counter(struct perf_stat_config *config,
92 struct perf_evsel *counter); 92 struct perf_evsel *counter);
93struct perf_tool;
94union perf_event;
95struct perf_session;
96int perf_event__process_stat_event(struct perf_tool *tool,
97 union perf_event *event,
98 struct perf_session *session);
99
100size_t perf_event__fprintf_stat(union perf_event *event, FILE *fp);
101size_t perf_event__fprintf_stat_round(union perf_event *event, FILE *fp);
102size_t perf_event__fprintf_stat_config(union perf_event *event, FILE *fp);
93#endif 103#endif
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index fc8781de62db..7f7e072be746 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -342,22 +342,6 @@ char *rtrim(char *s)
342 return s; 342 return s;
343} 343}
344 344
345/**
346 * memdup - duplicate region of memory
347 * @src: memory region to duplicate
348 * @len: memory region length
349 */
350void *memdup(const void *src, size_t len)
351{
352 void *p;
353
354 p = malloc(len);
355 if (p)
356 memcpy(p, src, len);
357
358 return p;
359}
360
361char *asprintf_expr_inout_ints(const char *var, bool in, size_t nints, int *ints) 345char *asprintf_expr_inout_ints(const char *var, bool in, size_t nints, int *ints)
362{ 346{
363 /* 347 /*
diff --git a/tools/perf/util/strlist.c b/tools/perf/util/strlist.c
index bdf98f6f27bb..0d3dfcb919b4 100644
--- a/tools/perf/util/strlist.c
+++ b/tools/perf/util/strlist.c
@@ -126,6 +126,11 @@ static int strlist__parse_list_entry(struct strlist *slist, const char *s,
126 err = strlist__load(slist, subst); 126 err = strlist__load(slist, subst);
127 goto out; 127 goto out;
128 } 128 }
129
130 if (slist->file_only) {
131 err = -ENOENT;
132 goto out;
133 }
129 } 134 }
130 135
131 err = strlist__add(slist, s); 136 err = strlist__add(slist, s);
@@ -157,11 +162,13 @@ struct strlist *strlist__new(const char *list, const struct strlist_config *conf
157 162
158 if (slist != NULL) { 163 if (slist != NULL) {
159 bool dupstr = true; 164 bool dupstr = true;
165 bool file_only = false;
160 const char *dirname = NULL; 166 const char *dirname = NULL;
161 167
162 if (config) { 168 if (config) {
163 dupstr = !config->dont_dupstr; 169 dupstr = !config->dont_dupstr;
164 dirname = config->dirname; 170 dirname = config->dirname;
171 file_only = config->file_only;
165 } 172 }
166 173
167 rblist__init(&slist->rblist); 174 rblist__init(&slist->rblist);
@@ -170,6 +177,7 @@ struct strlist *strlist__new(const char *list, const struct strlist_config *conf
170 slist->rblist.node_delete = strlist__node_delete; 177 slist->rblist.node_delete = strlist__node_delete;
171 178
172 slist->dupstr = dupstr; 179 slist->dupstr = dupstr;
180 slist->file_only = file_only;
173 181
174 if (list && strlist__parse_list(slist, list, dirname) != 0) 182 if (list && strlist__parse_list(slist, list, dirname) != 0)
175 goto out_error; 183 goto out_error;
diff --git a/tools/perf/util/strlist.h b/tools/perf/util/strlist.h
index 297565aa7535..ca990029e243 100644
--- a/tools/perf/util/strlist.h
+++ b/tools/perf/util/strlist.h
@@ -13,11 +13,18 @@ struct str_node {
13 13
14struct strlist { 14struct strlist {
15 struct rblist rblist; 15 struct rblist rblist;
16 bool dupstr; 16 bool dupstr;
17 bool file_only;
17}; 18};
18 19
20/*
21 * @file_only: When dirname is present, only consider entries as filenames,
22 * that should not be added to the list if dirname/entry is not
23 * found
24 */
19struct strlist_config { 25struct strlist_config {
20 bool dont_dupstr; 26 bool dont_dupstr;
27 bool file_only;
21 const char *dirname; 28 const char *dirname;
22}; 29};
23 30
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 475d88d0a1c9..562b8ebeae5b 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -1026,8 +1026,8 @@ int dso__load_sym(struct dso *dso, struct map *map,
1026 curr_dso->long_name_len = dso->long_name_len; 1026 curr_dso->long_name_len = dso->long_name_len;
1027 curr_map = map__new2(start, curr_dso, 1027 curr_map = map__new2(start, curr_dso,
1028 map->type); 1028 map->type);
1029 dso__put(curr_dso);
1029 if (curr_map == NULL) { 1030 if (curr_map == NULL) {
1030 dso__put(curr_dso);
1031 goto out_elf_end; 1031 goto out_elf_end;
1032 } 1032 }
1033 if (adjust_kernel_syms) { 1033 if (adjust_kernel_syms) {
@@ -1042,7 +1042,14 @@ int dso__load_sym(struct dso *dso, struct map *map,
1042 } 1042 }
1043 curr_dso->symtab_type = dso->symtab_type; 1043 curr_dso->symtab_type = dso->symtab_type;
1044 map_groups__insert(kmaps, curr_map); 1044 map_groups__insert(kmaps, curr_map);
1045 /*
1046 * Add it before we drop the referece to curr_map,
1047 * i.e. while we still are sure to have a reference
1048 * to this DSO via curr_map->dso.
1049 */
1045 dsos__add(&map->groups->machine->dsos, curr_dso); 1050 dsos__add(&map->groups->machine->dsos, curr_dso);
1051 /* kmaps already got it */
1052 map__put(curr_map);
1046 dso__set_loaded(curr_dso, map->type); 1053 dso__set_loaded(curr_dso, map->type);
1047 } else 1054 } else
1048 curr_dso = curr_map->dso; 1055 curr_dso = curr_map->dso;
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index b4cc7662677e..ab02209a7cf3 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -39,6 +39,7 @@ struct symbol_conf symbol_conf = {
39 .cumulate_callchain = true, 39 .cumulate_callchain = true,
40 .show_hist_headers = true, 40 .show_hist_headers = true,
41 .symfs = "", 41 .symfs = "",
42 .event_group = true,
42}; 43};
43 44
44static enum dso_binary_type binary_type_symtab[] = { 45static enum dso_binary_type binary_type_symtab[] = {
@@ -654,19 +655,24 @@ static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map,
654 struct map_groups *kmaps = map__kmaps(map); 655 struct map_groups *kmaps = map__kmaps(map);
655 struct map *curr_map; 656 struct map *curr_map;
656 struct symbol *pos; 657 struct symbol *pos;
657 int count = 0, moved = 0; 658 int count = 0;
659 struct rb_root old_root = dso->symbols[map->type];
658 struct rb_root *root = &dso->symbols[map->type]; 660 struct rb_root *root = &dso->symbols[map->type];
659 struct rb_node *next = rb_first(root); 661 struct rb_node *next = rb_first(root);
660 662
661 if (!kmaps) 663 if (!kmaps)
662 return -1; 664 return -1;
663 665
666 *root = RB_ROOT;
667
664 while (next) { 668 while (next) {
665 char *module; 669 char *module;
666 670
667 pos = rb_entry(next, struct symbol, rb_node); 671 pos = rb_entry(next, struct symbol, rb_node);
668 next = rb_next(&pos->rb_node); 672 next = rb_next(&pos->rb_node);
669 673
674 rb_erase_init(&pos->rb_node, &old_root);
675
670 module = strchr(pos->name, '\t'); 676 module = strchr(pos->name, '\t');
671 if (module) 677 if (module)
672 *module = '\0'; 678 *module = '\0';
@@ -674,28 +680,21 @@ static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map,
674 curr_map = map_groups__find(kmaps, map->type, pos->start); 680 curr_map = map_groups__find(kmaps, map->type, pos->start);
675 681
676 if (!curr_map || (filter && filter(curr_map, pos))) { 682 if (!curr_map || (filter && filter(curr_map, pos))) {
677 rb_erase_init(&pos->rb_node, root);
678 symbol__delete(pos); 683 symbol__delete(pos);
679 } else { 684 continue;
680 pos->start -= curr_map->start - curr_map->pgoff;
681 if (pos->end)
682 pos->end -= curr_map->start - curr_map->pgoff;
683 if (curr_map->dso != map->dso) {
684 rb_erase_init(&pos->rb_node, root);
685 symbols__insert(
686 &curr_map->dso->symbols[curr_map->type],
687 pos);
688 ++moved;
689 } else {
690 ++count;
691 }
692 } 685 }
686
687 pos->start -= curr_map->start - curr_map->pgoff;
688 if (pos->end)
689 pos->end -= curr_map->start - curr_map->pgoff;
690 symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
691 ++count;
693 } 692 }
694 693
695 /* Symbols have been adjusted */ 694 /* Symbols have been adjusted */
696 dso->adjust_symbols = 1; 695 dso->adjust_symbols = 1;
697 696
698 return count + moved; 697 return count;
699} 698}
700 699
701/* 700/*
@@ -1438,9 +1437,9 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
1438 if (lstat(dso->name, &st) < 0) 1437 if (lstat(dso->name, &st) < 0)
1439 goto out; 1438 goto out;
1440 1439
1441 if (st.st_uid && (st.st_uid != geteuid())) { 1440 if (!symbol_conf.force && st.st_uid && (st.st_uid != geteuid())) {
1442 pr_warning("File %s not owned by current user or root, " 1441 pr_warning("File %s not owned by current user or root, "
1443 "ignoring it.\n", dso->name); 1442 "ignoring it (use -f to override).\n", dso->name);
1444 goto out; 1443 goto out;
1445 } 1444 }
1446 1445
@@ -1467,7 +1466,7 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
1467 * Read the build id if possible. This is required for 1466 * Read the build id if possible. This is required for
1468 * DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work 1467 * DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work
1469 */ 1468 */
1470 if (filename__read_build_id(dso->name, build_id, BUILD_ID_SIZE) > 0) 1469 if (filename__read_build_id(dso->long_name, build_id, BUILD_ID_SIZE) > 0)
1471 dso__set_build_id(dso, build_id); 1470 dso__set_build_id(dso, build_id);
1472 1471
1473 /* 1472 /*
@@ -1862,24 +1861,44 @@ static void vmlinux_path__exit(void)
1862 zfree(&vmlinux_path); 1861 zfree(&vmlinux_path);
1863} 1862}
1864 1863
1864static const char * const vmlinux_paths[] = {
1865 "vmlinux",
1866 "/boot/vmlinux"
1867};
1868
1869static const char * const vmlinux_paths_upd[] = {
1870 "/boot/vmlinux-%s",
1871 "/usr/lib/debug/boot/vmlinux-%s",
1872 "/lib/modules/%s/build/vmlinux",
1873 "/usr/lib/debug/lib/modules/%s/vmlinux",
1874 "/usr/lib/debug/boot/vmlinux-%s.debug"
1875};
1876
1877static int vmlinux_path__add(const char *new_entry)
1878{
1879 vmlinux_path[vmlinux_path__nr_entries] = strdup(new_entry);
1880 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1881 return -1;
1882 ++vmlinux_path__nr_entries;
1883
1884 return 0;
1885}
1886
1865static int vmlinux_path__init(struct perf_env *env) 1887static int vmlinux_path__init(struct perf_env *env)
1866{ 1888{
1867 struct utsname uts; 1889 struct utsname uts;
1868 char bf[PATH_MAX]; 1890 char bf[PATH_MAX];
1869 char *kernel_version; 1891 char *kernel_version;
1892 unsigned int i;
1870 1893
1871 vmlinux_path = malloc(sizeof(char *) * 6); 1894 vmlinux_path = malloc(sizeof(char *) * (ARRAY_SIZE(vmlinux_paths) +
1895 ARRAY_SIZE(vmlinux_paths_upd)));
1872 if (vmlinux_path == NULL) 1896 if (vmlinux_path == NULL)
1873 return -1; 1897 return -1;
1874 1898
1875 vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux"); 1899 for (i = 0; i < ARRAY_SIZE(vmlinux_paths); i++)
1876 if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1900 if (vmlinux_path__add(vmlinux_paths[i]) < 0)
1877 goto out_fail; 1901 goto out_fail;
1878 ++vmlinux_path__nr_entries;
1879 vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux");
1880 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1881 goto out_fail;
1882 ++vmlinux_path__nr_entries;
1883 1902
1884 /* only try kernel version if no symfs was given */ 1903 /* only try kernel version if no symfs was given */
1885 if (symbol_conf.symfs[0] != 0) 1904 if (symbol_conf.symfs[0] != 0)
@@ -1894,28 +1913,11 @@ static int vmlinux_path__init(struct perf_env *env)
1894 kernel_version = uts.release; 1913 kernel_version = uts.release;
1895 } 1914 }
1896 1915
1897 snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", kernel_version); 1916 for (i = 0; i < ARRAY_SIZE(vmlinux_paths_upd); i++) {
1898 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1917 snprintf(bf, sizeof(bf), vmlinux_paths_upd[i], kernel_version);
1899 if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1918 if (vmlinux_path__add(bf) < 0)
1900 goto out_fail; 1919 goto out_fail;
1901 ++vmlinux_path__nr_entries; 1920 }
1902 snprintf(bf, sizeof(bf), "/usr/lib/debug/boot/vmlinux-%s",
1903 kernel_version);
1904 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1905 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1906 goto out_fail;
1907 ++vmlinux_path__nr_entries;
1908 snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", kernel_version);
1909 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1910 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1911 goto out_fail;
1912 ++vmlinux_path__nr_entries;
1913 snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
1914 kernel_version);
1915 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1916 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1917 goto out_fail;
1918 ++vmlinux_path__nr_entries;
1919 1921
1920 return 0; 1922 return 0;
1921 1923
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 40073c60b83d..ccd1caa40e11 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -84,6 +84,7 @@ struct symbol_conf {
84 unsigned short priv_size; 84 unsigned short priv_size;
85 unsigned short nr_events; 85 unsigned short nr_events;
86 bool try_vmlinux_path, 86 bool try_vmlinux_path,
87 force,
87 ignore_vmlinux, 88 ignore_vmlinux,
88 ignore_vmlinux_buildid, 89 ignore_vmlinux_buildid,
89 show_kernel_path, 90 show_kernel_path,
@@ -107,7 +108,9 @@ struct symbol_conf {
107 show_hist_headers, 108 show_hist_headers,
108 branch_callstack, 109 branch_callstack,
109 has_filter, 110 has_filter,
110 show_ref_callgraph; 111 show_ref_callgraph,
112 hide_unresolved,
113 raw_trace;
111 const char *vmlinux_name, 114 const char *vmlinux_name,
112 *kallsyms_name, 115 *kallsyms_name,
113 *source_prefix, 116 *source_prefix,
diff --git a/tools/perf/util/term.c b/tools/perf/util/term.c
new file mode 100644
index 000000000000..90b47d8aa19c
--- /dev/null
+++ b/tools/perf/util/term.c
@@ -0,0 +1,35 @@
1#include "util.h"
2
3void get_term_dimensions(struct winsize *ws)
4{
5 char *s = getenv("LINES");
6
7 if (s != NULL) {
8 ws->ws_row = atoi(s);
9 s = getenv("COLUMNS");
10 if (s != NULL) {
11 ws->ws_col = atoi(s);
12 if (ws->ws_row && ws->ws_col)
13 return;
14 }
15 }
16#ifdef TIOCGWINSZ
17 if (ioctl(1, TIOCGWINSZ, ws) == 0 &&
18 ws->ws_row && ws->ws_col)
19 return;
20#endif
21 ws->ws_row = 25;
22 ws->ws_col = 80;
23}
24
25void set_term_quiet_input(struct termios *old)
26{
27 struct termios tc;
28
29 tcgetattr(0, old);
30 tc = *old;
31 tc.c_lflag &= ~(ICANON | ECHO);
32 tc.c_cc[VMIN] = 0;
33 tc.c_cc[VTIME] = 0;
34 tcsetattr(0, TCSANOW, &tc);
35}
diff --git a/tools/perf/util/term.h b/tools/perf/util/term.h
new file mode 100644
index 000000000000..2c06a61846a1
--- /dev/null
+++ b/tools/perf/util/term.h
@@ -0,0 +1,10 @@
1#ifndef __PERF_TERM_H
2#define __PERF_TERM_H
3
4struct termios;
5struct winsize;
6
7void get_term_dimensions(struct winsize *ws);
8void set_term_quiet_input(struct termios *old);
9
10#endif /* __PERF_TERM_H */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 0a9ae8014729..dfd00c6dad6e 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -19,8 +19,10 @@ int thread__init_map_groups(struct thread *thread, struct machine *machine)
19 thread->mg = map_groups__new(machine); 19 thread->mg = map_groups__new(machine);
20 } else { 20 } else {
21 leader = __machine__findnew_thread(machine, pid, pid); 21 leader = __machine__findnew_thread(machine, pid, pid);
22 if (leader) 22 if (leader) {
23 thread->mg = map_groups__get(leader->mg); 23 thread->mg = map_groups__get(leader->mg);
24 thread__put(leader);
25 }
24 } 26 }
25 27
26 return thread->mg ? 0 : -1; 28 return thread->mg ? 0 : -1;
@@ -53,7 +55,7 @@ struct thread *thread__new(pid_t pid, pid_t tid)
53 goto err_thread; 55 goto err_thread;
54 56
55 list_add(&comm->list, &thread->comm_list); 57 list_add(&comm->list, &thread->comm_list);
56 atomic_set(&thread->refcnt, 0); 58 atomic_set(&thread->refcnt, 1);
57 RB_CLEAR_NODE(&thread->rb_node); 59 RB_CLEAR_NODE(&thread->rb_node);
58 } 60 }
59 61
@@ -95,6 +97,10 @@ struct thread *thread__get(struct thread *thread)
95void thread__put(struct thread *thread) 97void thread__put(struct thread *thread)
96{ 98{
97 if (thread && atomic_dec_and_test(&thread->refcnt)) { 99 if (thread && atomic_dec_and_test(&thread->refcnt)) {
100 /*
101 * Remove it from the dead_threads list, as last reference
102 * is gone.
103 */
98 list_del_init(&thread->node); 104 list_del_init(&thread->node);
99 thread__delete(thread); 105 thread__delete(thread);
100 } 106 }
diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c
index 6ec3c5ca438f..08afc6909953 100644
--- a/tools/perf/util/thread_map.c
+++ b/tools/perf/util/thread_map.c
@@ -13,6 +13,7 @@
13#include "thread_map.h" 13#include "thread_map.h"
14#include "util.h" 14#include "util.h"
15#include "debug.h" 15#include "debug.h"
16#include "event.h"
16 17
17/* Skip "." and ".." directories */ 18/* Skip "." and ".." directories */
18static int filter(const struct dirent *dir) 19static int filter(const struct dirent *dir)
@@ -304,6 +305,7 @@ out:
304 305
305out_free_threads: 306out_free_threads:
306 zfree(&threads); 307 zfree(&threads);
308 strlist__delete(slist);
307 goto out; 309 goto out;
308} 310}
309 311
@@ -408,3 +410,29 @@ void thread_map__read_comms(struct thread_map *threads)
408 for (i = 0; i < threads->nr; ++i) 410 for (i = 0; i < threads->nr; ++i)
409 comm_init(threads, i); 411 comm_init(threads, i);
410} 412}
413
414static void thread_map__copy_event(struct thread_map *threads,
415 struct thread_map_event *event)
416{
417 unsigned i;
418
419 threads->nr = (int) event->nr;
420
421 for (i = 0; i < event->nr; i++) {
422 thread_map__set_pid(threads, i, (pid_t) event->entries[i].pid);
423 threads->map[i].comm = strndup(event->entries[i].comm, 16);
424 }
425
426 atomic_set(&threads->refcnt, 1);
427}
428
429struct thread_map *thread_map__new_event(struct thread_map_event *event)
430{
431 struct thread_map *threads;
432
433 threads = thread_map__alloc(event->nr);
434 if (threads)
435 thread_map__copy_event(threads, event);
436
437 return threads;
438}
diff --git a/tools/perf/util/thread_map.h b/tools/perf/util/thread_map.h
index af679d8a50f8..85e4c7c4fbde 100644
--- a/tools/perf/util/thread_map.h
+++ b/tools/perf/util/thread_map.h
@@ -16,11 +16,14 @@ struct thread_map {
16 struct thread_map_data map[]; 16 struct thread_map_data map[];
17}; 17};
18 18
19struct thread_map_event;
20
19struct thread_map *thread_map__new_dummy(void); 21struct thread_map *thread_map__new_dummy(void);
20struct thread_map *thread_map__new_by_pid(pid_t pid); 22struct thread_map *thread_map__new_by_pid(pid_t pid);
21struct thread_map *thread_map__new_by_tid(pid_t tid); 23struct thread_map *thread_map__new_by_tid(pid_t tid);
22struct thread_map *thread_map__new_by_uid(uid_t uid); 24struct thread_map *thread_map__new_by_uid(uid_t uid);
23struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid); 25struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid);
26struct thread_map *thread_map__new_event(struct thread_map_event *event);
24 27
25struct thread_map *thread_map__get(struct thread_map *map); 28struct thread_map *thread_map__get(struct thread_map *map);
26void thread_map__put(struct thread_map *map); 29void thread_map__put(struct thread_map *map);
diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h
index cab8cc24831b..55de4cffcd4e 100644
--- a/tools/perf/util/tool.h
+++ b/tools/perf/util/tool.h
@@ -50,12 +50,18 @@ struct perf_tool {
50 throttle, 50 throttle,
51 unthrottle; 51 unthrottle;
52 event_attr_op attr; 52 event_attr_op attr;
53 event_attr_op event_update;
53 event_op2 tracing_data; 54 event_op2 tracing_data;
54 event_oe finished_round; 55 event_oe finished_round;
55 event_op2 build_id, 56 event_op2 build_id,
56 id_index, 57 id_index,
57 auxtrace_info, 58 auxtrace_info,
58 auxtrace_error; 59 auxtrace_error,
60 thread_map,
61 cpu_map,
62 stat_config,
63 stat,
64 stat_round;
59 event_op3 auxtrace; 65 event_op3 auxtrace;
60 bool ordered_events; 66 bool ordered_events;
61 bool ordering_requires_timestamps; 67 bool ordering_requires_timestamps;
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index 8ff7d620d942..33b52eaa39db 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -209,7 +209,7 @@ static const struct flag flags[] = {
209 { "NET_TX_SOFTIRQ", 2 }, 209 { "NET_TX_SOFTIRQ", 2 },
210 { "NET_RX_SOFTIRQ", 3 }, 210 { "NET_RX_SOFTIRQ", 3 },
211 { "BLOCK_SOFTIRQ", 4 }, 211 { "BLOCK_SOFTIRQ", 4 },
212 { "BLOCK_IOPOLL_SOFTIRQ", 5 }, 212 { "IRQ_POLL_SOFTIRQ", 5 },
213 { "TASKLET_SOFTIRQ", 6 }, 213 { "TASKLET_SOFTIRQ", 6 },
214 { "SCHED_SOFTIRQ", 7 }, 214 { "SCHED_SOFTIRQ", 7 },
215 { "HRTIMER_SOFTIRQ", 8 }, 215 { "HRTIMER_SOFTIRQ", 8 },
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index b85ee55cca0c..bce5b1dac268 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -65,6 +65,7 @@ int tracing_data_put(struct tracing_data *tdata);
65struct addr_location; 65struct addr_location;
66 66
67struct perf_session; 67struct perf_session;
68struct perf_stat_config;
68 69
69struct scripting_ops { 70struct scripting_ops {
70 const char *name; 71 const char *name;
@@ -75,6 +76,9 @@ struct scripting_ops {
75 struct perf_sample *sample, 76 struct perf_sample *sample,
76 struct perf_evsel *evsel, 77 struct perf_evsel *evsel,
77 struct addr_location *al); 78 struct addr_location *al);
79 void (*process_stat)(struct perf_stat_config *config,
80 struct perf_evsel *evsel, u64 tstamp);
81 void (*process_stat_interval)(u64 tstamp);
78 int (*generate_script) (struct pevent *pevent, const char *outfile); 82 int (*generate_script) (struct pevent *pevent, const char *outfile);
79}; 83};
80 84
diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
index 2dcfe9a7c8d0..cf5e250bc78e 100644
--- a/tools/perf/util/unwind-libdw.c
+++ b/tools/perf/util/unwind-libdw.c
@@ -11,6 +11,7 @@
11#include <linux/types.h> 11#include <linux/types.h>
12#include "event.h" 12#include "event.h"
13#include "perf_regs.h" 13#include "perf_regs.h"
14#include "callchain.h"
14 15
15static char *debuginfo_path; 16static char *debuginfo_path;
16 17
@@ -52,25 +53,28 @@ static int report_module(u64 ip, struct unwind_info *ui)
52 return __report_module(&al, ip, ui); 53 return __report_module(&al, ip, ui);
53} 54}
54 55
56/*
57 * Store all entries within entries array,
58 * we will process it after we finish unwind.
59 */
55static int entry(u64 ip, struct unwind_info *ui) 60static int entry(u64 ip, struct unwind_info *ui)
56 61
57{ 62{
58 struct unwind_entry e; 63 struct unwind_entry *e = &ui->entries[ui->idx++];
59 struct addr_location al; 64 struct addr_location al;
60 65
61 if (__report_module(&al, ip, ui)) 66 if (__report_module(&al, ip, ui))
62 return -1; 67 return -1;
63 68
64 e.ip = ip; 69 e->ip = ip;
65 e.map = al.map; 70 e->map = al.map;
66 e.sym = al.sym; 71 e->sym = al.sym;
67 72
68 pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n", 73 pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n",
69 al.sym ? al.sym->name : "''", 74 al.sym ? al.sym->name : "''",
70 ip, 75 ip,
71 al.map ? al.map->map_ip(al.map, ip) : (u64) 0); 76 al.map ? al.map->map_ip(al.map, ip) : (u64) 0);
72 77 return 0;
73 return ui->cb(&e, ui->arg);
74} 78}
75 79
76static pid_t next_thread(Dwfl *dwfl, void *arg, void **thread_argp) 80static pid_t next_thread(Dwfl *dwfl, void *arg, void **thread_argp)
@@ -92,6 +96,16 @@ static int access_dso_mem(struct unwind_info *ui, Dwarf_Addr addr,
92 thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER, 96 thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER,
93 MAP__FUNCTION, addr, &al); 97 MAP__FUNCTION, addr, &al);
94 if (!al.map) { 98 if (!al.map) {
99 /*
100 * We've seen cases (softice) where DWARF unwinder went
101 * through non executable mmaps, which we need to lookup
102 * in MAP__VARIABLE tree.
103 */
104 thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER,
105 MAP__VARIABLE, addr, &al);
106 }
107
108 if (!al.map) {
95 pr_debug("unwind: no map for %lx\n", (unsigned long)addr); 109 pr_debug("unwind: no map for %lx\n", (unsigned long)addr);
96 return -1; 110 return -1;
97 } 111 }
@@ -168,7 +182,7 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
168 struct perf_sample *data, 182 struct perf_sample *data,
169 int max_stack) 183 int max_stack)
170{ 184{
171 struct unwind_info ui = { 185 struct unwind_info *ui, ui_buf = {
172 .sample = data, 186 .sample = data,
173 .thread = thread, 187 .thread = thread,
174 .machine = thread->mg->machine, 188 .machine = thread->mg->machine,
@@ -177,35 +191,54 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
177 .max_stack = max_stack, 191 .max_stack = max_stack,
178 }; 192 };
179 Dwarf_Word ip; 193 Dwarf_Word ip;
180 int err = -EINVAL; 194 int err = -EINVAL, i;
181 195
182 if (!data->user_regs.regs) 196 if (!data->user_regs.regs)
183 return -EINVAL; 197 return -EINVAL;
184 198
185 ui.dwfl = dwfl_begin(&offline_callbacks); 199 ui = zalloc(sizeof(ui_buf) + sizeof(ui_buf.entries[0]) * max_stack);
186 if (!ui.dwfl) 200 if (!ui)
201 return -ENOMEM;
202
203 *ui = ui_buf;
204
205 ui->dwfl = dwfl_begin(&offline_callbacks);
206 if (!ui->dwfl)
187 goto out; 207 goto out;
188 208
189 err = perf_reg_value(&ip, &data->user_regs, PERF_REG_IP); 209 err = perf_reg_value(&ip, &data->user_regs, PERF_REG_IP);
190 if (err) 210 if (err)
191 goto out; 211 goto out;
192 212
193 err = report_module(ip, &ui); 213 err = report_module(ip, ui);
194 if (err) 214 if (err)
195 goto out; 215 goto out;
196 216
197 if (!dwfl_attach_state(ui.dwfl, EM_NONE, thread->tid, &callbacks, &ui)) 217 if (!dwfl_attach_state(ui->dwfl, EM_NONE, thread->tid, &callbacks, ui))
198 goto out; 218 goto out;
199 219
200 err = dwfl_getthread_frames(ui.dwfl, thread->tid, frame_callback, &ui); 220 err = dwfl_getthread_frames(ui->dwfl, thread->tid, frame_callback, ui);
201 221
202 if (err && !ui.max_stack) 222 if (err && !ui->max_stack)
203 err = 0; 223 err = 0;
204 224
225 /*
226 * Display what we got based on the order setup.
227 */
228 for (i = 0; i < ui->idx && !err; i++) {
229 int j = i;
230
231 if (callchain_param.order == ORDER_CALLER)
232 j = ui->idx - i - 1;
233
234 err = ui->entries[j].ip ? ui->cb(&ui->entries[j], ui->arg) : 0;
235 }
236
205 out: 237 out:
206 if (err) 238 if (err)
207 pr_debug("unwind: failed with '%s'\n", dwfl_errmsg(-1)); 239 pr_debug("unwind: failed with '%s'\n", dwfl_errmsg(-1));
208 240
209 dwfl_end(ui.dwfl); 241 dwfl_end(ui->dwfl);
242 free(ui);
210 return 0; 243 return 0;
211} 244}
diff --git a/tools/perf/util/unwind-libdw.h b/tools/perf/util/unwind-libdw.h
index 417a1426f3ad..58328669ed16 100644
--- a/tools/perf/util/unwind-libdw.h
+++ b/tools/perf/util/unwind-libdw.h
@@ -16,6 +16,8 @@ struct unwind_info {
16 unwind_entry_cb_t cb; 16 unwind_entry_cb_t cb;
17 void *arg; 17 void *arg;
18 int max_stack; 18 int max_stack;
19 int idx;
20 struct unwind_entry entries[];
19}; 21};
20 22
21#endif /* __PERF_UNWIND_LIBDW_H */ 23#endif /* __PERF_UNWIND_LIBDW_H */
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
index c83832b555e5..ee7e372297e5 100644
--- a/tools/perf/util/unwind-libunwind.c
+++ b/tools/perf/util/unwind-libunwind.c
@@ -319,6 +319,15 @@ static struct map *find_map(unw_word_t ip, struct unwind_info *ui)
319 319
320 thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER, 320 thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER,
321 MAP__FUNCTION, ip, &al); 321 MAP__FUNCTION, ip, &al);
322 if (!al.map) {
323 /*
324 * We've seen cases (softice) where DWARF unwinder went
325 * through non executable mmaps, which we need to lookup
326 * in MAP__VARIABLE tree.
327 */
328 thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER,
329 MAP__VARIABLE, ip, &al);
330 }
322 return al.map; 331 return al.map;
323} 332}
324 333
@@ -416,20 +425,19 @@ get_proc_name(unw_addr_space_t __maybe_unused as,
416static int access_dso_mem(struct unwind_info *ui, unw_word_t addr, 425static int access_dso_mem(struct unwind_info *ui, unw_word_t addr,
417 unw_word_t *data) 426 unw_word_t *data)
418{ 427{
419 struct addr_location al; 428 struct map *map;
420 ssize_t size; 429 ssize_t size;
421 430
422 thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER, 431 map = find_map(addr, ui);
423 MAP__FUNCTION, addr, &al); 432 if (!map) {
424 if (!al.map) {
425 pr_debug("unwind: no map for %lx\n", (unsigned long)addr); 433 pr_debug("unwind: no map for %lx\n", (unsigned long)addr);
426 return -1; 434 return -1;
427 } 435 }
428 436
429 if (!al.map->dso) 437 if (!map->dso)
430 return -1; 438 return -1;
431 439
432 size = dso__data_read_addr(al.map->dso, al.map, ui->machine, 440 size = dso__data_read_addr(map->dso, map, ui->machine,
433 addr, (u8 *) data, sizeof(*data)); 441 addr, (u8 *) data, sizeof(*data));
434 442
435 return !(size == sizeof(*data)); 443 return !(size == sizeof(*data));
@@ -614,23 +622,48 @@ void unwind__finish_access(struct thread *thread)
614static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, 622static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
615 void *arg, int max_stack) 623 void *arg, int max_stack)
616{ 624{
625 u64 val;
626 unw_word_t ips[max_stack];
617 unw_addr_space_t addr_space; 627 unw_addr_space_t addr_space;
618 unw_cursor_t c; 628 unw_cursor_t c;
619 int ret; 629 int ret, i = 0;
620
621 addr_space = thread__priv(ui->thread);
622 if (addr_space == NULL)
623 return -1;
624 630
625 ret = unw_init_remote(&c, addr_space, ui); 631 ret = perf_reg_value(&val, &ui->sample->user_regs, PERF_REG_IP);
626 if (ret) 632 if (ret)
627 display_error(ret); 633 return ret;
628 634
629 while (!ret && (unw_step(&c) > 0) && max_stack--) { 635 ips[i++] = (unw_word_t) val;
630 unw_word_t ip;
631 636
632 unw_get_reg(&c, UNW_REG_IP, &ip); 637 /*
633 ret = ip ? entry(ip, ui->thread, cb, arg) : 0; 638 * If we need more than one entry, do the DWARF
639 * unwind itself.
640 */
641 if (max_stack - 1 > 0) {
642 addr_space = thread__priv(ui->thread);
643 if (addr_space == NULL)
644 return -1;
645
646 ret = unw_init_remote(&c, addr_space, ui);
647 if (ret)
648 display_error(ret);
649
650 while (!ret && (unw_step(&c) > 0) && i < max_stack) {
651 unw_get_reg(&c, UNW_REG_IP, &ips[i]);
652 ++i;
653 }
654
655 max_stack = i;
656 }
657
658 /*
659 * Display what we got based on the order setup.
660 */
661 for (i = 0; i < max_stack && !ret; i++) {
662 int j = i;
663
664 if (callchain_param.order == ORDER_CALLER)
665 j = max_stack - i - 1;
666 ret = ips[j] ? entry(ips[j], ui->thread, cb, arg) : 0;
634 } 667 }
635 668
636 return ret; 669 return ret;
@@ -640,24 +673,17 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
640 struct thread *thread, 673 struct thread *thread,
641 struct perf_sample *data, int max_stack) 674 struct perf_sample *data, int max_stack)
642{ 675{
643 u64 ip;
644 struct unwind_info ui = { 676 struct unwind_info ui = {
645 .sample = data, 677 .sample = data,
646 .thread = thread, 678 .thread = thread,
647 .machine = thread->mg->machine, 679 .machine = thread->mg->machine,
648 }; 680 };
649 int ret;
650 681
651 if (!data->user_regs.regs) 682 if (!data->user_regs.regs)
652 return -EINVAL; 683 return -EINVAL;
653 684
654 ret = perf_reg_value(&ip, &data->user_regs, PERF_REG_IP); 685 if (max_stack <= 0)
655 if (ret) 686 return -EINVAL;
656 return ret;
657
658 ret = entry(ip, thread, cb, arg);
659 if (ret)
660 return -ENOMEM;
661 687
662 return --max_stack > 0 ? get_entries(&ui, cb, arg, max_stack) : 0; 688 return get_entries(&ui, cb, arg, max_stack);
663} 689}
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 47b1e36c7ea0..ead9509835d2 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -16,12 +16,14 @@
16#include <linux/kernel.h> 16#include <linux/kernel.h>
17#include <unistd.h> 17#include <unistd.h>
18#include "callchain.h" 18#include "callchain.h"
19#include "strlist.h"
19 20
20struct callchain_param callchain_param = { 21struct callchain_param callchain_param = {
21 .mode = CHAIN_GRAPH_ABS, 22 .mode = CHAIN_GRAPH_ABS,
22 .min_percent = 0.5, 23 .min_percent = 0.5,
23 .order = ORDER_CALLEE, 24 .order = ORDER_CALLEE,
24 .key = CCKEY_FUNCTION 25 .key = CCKEY_FUNCTION,
26 .value = CCVAL_PERCENT,
25}; 27};
26 28
27/* 29/*
@@ -351,41 +353,8 @@ void sighandler_dump_stack(int sig)
351{ 353{
352 psignal(sig, "perf"); 354 psignal(sig, "perf");
353 dump_stack(); 355 dump_stack();
354 exit(sig); 356 signal(sig, SIG_DFL);
355} 357 raise(sig);
356
357void get_term_dimensions(struct winsize *ws)
358{
359 char *s = getenv("LINES");
360
361 if (s != NULL) {
362 ws->ws_row = atoi(s);
363 s = getenv("COLUMNS");
364 if (s != NULL) {
365 ws->ws_col = atoi(s);
366 if (ws->ws_row && ws->ws_col)
367 return;
368 }
369 }
370#ifdef TIOCGWINSZ
371 if (ioctl(1, TIOCGWINSZ, ws) == 0 &&
372 ws->ws_row && ws->ws_col)
373 return;
374#endif
375 ws->ws_row = 25;
376 ws->ws_col = 80;
377}
378
379void set_term_quiet_input(struct termios *old)
380{
381 struct termios tc;
382
383 tcgetattr(0, old);
384 tc = *old;
385 tc.c_lflag &= ~(ICANON | ECHO);
386 tc.c_cc[VMIN] = 0;
387 tc.c_cc[VTIME] = 0;
388 tcsetattr(0, TCSANOW, &tc);
389} 358}
390 359
391int parse_nsec_time(const char *str, u64 *ptime) 360int parse_nsec_time(const char *str, u64 *ptime)
@@ -695,3 +664,30 @@ fetch_kernel_version(unsigned int *puint, char *str,
695 *puint = (version << 16) + (patchlevel << 8) + sublevel; 664 *puint = (version << 16) + (patchlevel << 8) + sublevel;
696 return 0; 665 return 0;
697} 666}
667
668const char *perf_tip(const char *dirpath)
669{
670 struct strlist *tips;
671 struct str_node *node;
672 char *tip = NULL;
673 struct strlist_config conf = {
674 .dirname = dirpath,
675 .file_only = true,
676 };
677
678 tips = strlist__new("tips.txt", &conf);
679 if (tips == NULL)
680 return errno == ENOENT ? NULL : "Tip: get more memory! ;-p";
681
682 if (strlist__nr_entries(tips) == 0)
683 goto out;
684
685 node = strlist__entry(tips, random() % strlist__nr_entries(tips));
686 if (asprintf(&tip, "Tip: %s", node->s) < 0)
687 tip = (char *)"Tip: get more memory! ;-)";
688
689out:
690 strlist__delete(tips);
691
692 return tip;
693}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index dcc659017976..fe915e616f9b 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -53,6 +53,7 @@
53#include <stdlib.h> 53#include <stdlib.h>
54#include <stdarg.h> 54#include <stdarg.h>
55#include <string.h> 55#include <string.h>
56#include <term.h>
56#include <errno.h> 57#include <errno.h>
57#include <limits.h> 58#include <limits.h>
58#include <sys/param.h> 59#include <sys/param.h>
@@ -150,12 +151,6 @@ extern void set_warning_routine(void (*routine)(const char *err, va_list params)
150extern int prefixcmp(const char *str, const char *prefix); 151extern int prefixcmp(const char *str, const char *prefix);
151extern void set_buildid_dir(const char *dir); 152extern void set_buildid_dir(const char *dir);
152 153
153static inline const char *skip_prefix(const char *str, const char *prefix)
154{
155 size_t len = strlen(prefix);
156 return strncmp(str, prefix, len) ? NULL : str + len;
157}
158
159#ifdef __GLIBC_PREREQ 154#ifdef __GLIBC_PREREQ
160#if __GLIBC_PREREQ(2, 1) 155#if __GLIBC_PREREQ(2, 1)
161#define HAVE_STRCHRNUL 156#define HAVE_STRCHRNUL
@@ -186,14 +181,6 @@ static inline void *zalloc(size_t size)
186 181
187#define zfree(ptr) ({ free(*ptr); *ptr = NULL; }) 182#define zfree(ptr) ({ free(*ptr); *ptr = NULL; })
188 183
189static inline int has_extension(const char *filename, const char *ext)
190{
191 size_t len = strlen(filename);
192 size_t extlen = strlen(ext);
193
194 return len > extlen && !memcmp(filename + len - extlen, ext, extlen);
195}
196
197/* Sane ctype - no locale, and works with signed chars */ 184/* Sane ctype - no locale, and works with signed chars */
198#undef isascii 185#undef isascii
199#undef isspace 186#undef isspace
@@ -282,9 +269,6 @@ void sighandler_dump_stack(int sig);
282extern unsigned int page_size; 269extern unsigned int page_size;
283extern int cacheline_size; 270extern int cacheline_size;
284 271
285void get_term_dimensions(struct winsize *ws);
286void set_term_quiet_input(struct termios *old);
287
288struct parse_tag { 272struct parse_tag {
289 char tag; 273 char tag;
290 int mult; 274 int mult;
@@ -358,4 +342,6 @@ int fetch_kernel_version(unsigned int *puint,
358#define KVER_FMT "%d.%d.%d" 342#define KVER_FMT "%d.%d.%d"
359#define KVER_PARAM(x) KVER_VERSION(x), KVER_PATCHLEVEL(x), KVER_SUBLEVEL(x) 343#define KVER_PARAM(x) KVER_VERSION(x), KVER_PATCHLEVEL(x), KVER_SUBLEVEL(x)
360 344
345const char *perf_tip(const char *dirpath);
346
361#endif /* GIT_COMPAT_UTIL_H */ 347#endif /* GIT_COMPAT_UTIL_H */
diff --git a/tools/power/acpi/Makefile b/tools/power/acpi/Makefile
index e882c8320135..a8bf9081512b 100644
--- a/tools/power/acpi/Makefile
+++ b/tools/power/acpi/Makefile
@@ -10,18 +10,18 @@
10 10
11include ../../scripts/Makefile.include 11include ../../scripts/Makefile.include
12 12
13all: acpidump ec 13all: acpidbg acpidump ec
14clean: acpidump_clean ec_clean 14clean: acpidbg_clean acpidump_clean ec_clean
15install: acpidump_install ec_install 15install: acpidbg_install acpidump_install ec_install
16uninstall: acpidump_uninstall ec_uninstall 16uninstall: acpidbg_uninstall acpidump_uninstall ec_uninstall
17 17
18acpidump ec: FORCE 18acpidbg acpidump ec: FORCE
19 $(call descend,tools/$@,all) 19 $(call descend,tools/$@,all)
20acpidump_clean ec_clean: 20acpidbg_clean acpidump_clean ec_clean:
21 $(call descend,tools/$(@:_clean=),clean) 21 $(call descend,tools/$(@:_clean=),clean)
22acpidump_install ec_install: 22acpidbg_install acpidump_install ec_install:
23 $(call descend,tools/$(@:_install=),install) 23 $(call descend,tools/$(@:_install=),install)
24acpidump_uninstall ec_uninstall: 24acpidbg_uninstall acpidump_uninstall ec_uninstall:
25 $(call descend,tools/$(@:_uninstall=),uninstall) 25 $(call descend,tools/$(@:_uninstall=),uninstall)
26 26
27.PHONY: FORCE 27.PHONY: FORCE
diff --git a/tools/power/acpi/common/cmfsize.c b/tools/power/acpi/common/cmfsize.c
index eec688041500..e73a79fce015 100644
--- a/tools/power/acpi/common/cmfsize.c
+++ b/tools/power/acpi/common/cmfsize.c
@@ -5,7 +5,7 @@
5 *****************************************************************************/ 5 *****************************************************************************/
6 6
7/* 7/*
8 * Copyright (C) 2000 - 2015, Intel Corp. 8 * Copyright (C) 2000 - 2016, Intel Corp.
9 * All rights reserved. 9 * All rights reserved.
10 * 10 *
11 * Redistribution and use in source and binary forms, with or without 11 * Redistribution and use in source and binary forms, with or without
diff --git a/tools/power/acpi/common/getopt.c b/tools/power/acpi/common/getopt.c
index 326e826a5d20..0bd343f136a4 100644
--- a/tools/power/acpi/common/getopt.c
+++ b/tools/power/acpi/common/getopt.c
@@ -5,7 +5,7 @@
5 *****************************************************************************/ 5 *****************************************************************************/
6 6
7/* 7/*
8 * Copyright (C) 2000 - 2015, Intel Corp. 8 * Copyright (C) 2000 - 2016, Intel Corp.
9 * All rights reserved. 9 * All rights reserved.
10 * 10 *
11 * Redistribution and use in source and binary forms, with or without 11 * Redistribution and use in source and binary forms, with or without
@@ -47,6 +47,7 @@
47 * Option strings: 47 * Option strings:
48 * "f" - Option has no arguments 48 * "f" - Option has no arguments
49 * "f:" - Option requires an argument 49 * "f:" - Option requires an argument
50 * "f+" - Option has an optional argument
50 * "f^" - Option has optional single-char sub-options 51 * "f^" - Option has optional single-char sub-options
51 * "f|" - Option has required single-char sub-options 52 * "f|" - Option has required single-char sub-options
52 */ 53 */
@@ -85,6 +86,7 @@ static int current_char_ptr = 1;
85 86
86int acpi_getopt_argument(int argc, char **argv) 87int acpi_getopt_argument(int argc, char **argv)
87{ 88{
89
88 acpi_gbl_optind--; 90 acpi_gbl_optind--;
89 current_char_ptr++; 91 current_char_ptr++;
90 92
diff --git a/tools/power/acpi/os_specific/service_layers/oslibcfs.c b/tools/power/acpi/os_specific/service_layers/oslibcfs.c
index b51e40a9a120..11f4aba55aab 100644
--- a/tools/power/acpi/os_specific/service_layers/oslibcfs.c
+++ b/tools/power/acpi/os_specific/service_layers/oslibcfs.c
@@ -5,7 +5,7 @@
5 *****************************************************************************/ 5 *****************************************************************************/
6 6
7/* 7/*
8 * Copyright (C) 2000 - 2015, Intel Corp. 8 * Copyright (C) 2000 - 2016, Intel Corp.
9 * All rights reserved. 9 * All rights reserved.
10 * 10 *
11 * Redistribution and use in source and binary forms, with or without 11 * Redistribution and use in source and binary forms, with or without
@@ -73,6 +73,7 @@ ACPI_FILE acpi_os_open_file(const char *path, u8 modes)
73 if (modes & ACPI_FILE_WRITING) { 73 if (modes & ACPI_FILE_WRITING) {
74 modes_str[i++] = 'w'; 74 modes_str[i++] = 'w';
75 } 75 }
76
76 if (modes & ACPI_FILE_BINARY) { 77 if (modes & ACPI_FILE_BINARY) {
77 modes_str[i++] = 'b'; 78 modes_str[i++] = 'b';
78 } 79 }
@@ -101,6 +102,7 @@ ACPI_FILE acpi_os_open_file(const char *path, u8 modes)
101 102
102void acpi_os_close_file(ACPI_FILE file) 103void acpi_os_close_file(ACPI_FILE file)
103{ 104{
105
104 fclose(file); 106 fclose(file);
105} 107}
106 108
@@ -202,6 +204,7 @@ acpi_status acpi_os_set_file_offset(ACPI_FILE file, long offset, u8 from)
202 if (from == ACPI_FILE_BEGIN) { 204 if (from == ACPI_FILE_BEGIN) {
203 ret = fseek(file, offset, SEEK_SET); 205 ret = fseek(file, offset, SEEK_SET);
204 } 206 }
207
205 if (from == ACPI_FILE_END) { 208 if (from == ACPI_FILE_END) {
206 ret = fseek(file, offset, SEEK_END); 209 ret = fseek(file, offset, SEEK_END);
207 } 210 }
diff --git a/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c
index dd5008b0617a..d0e6b857d8d1 100644
--- a/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c
+++ b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c
@@ -5,7 +5,7 @@
5 *****************************************************************************/ 5 *****************************************************************************/
6 6
7/* 7/*
8 * Copyright (C) 2000 - 2015, Intel Corp. 8 * Copyright (C) 2000 - 2016, Intel Corp.
9 * All rights reserved. 9 * All rights reserved.
10 * 10 *
11 * Redistribution and use in source and binary forms, with or without 11 * Redistribution and use in source and binary forms, with or without
diff --git a/tools/power/acpi/os_specific/service_layers/osunixdir.c b/tools/power/acpi/os_specific/service_layers/osunixdir.c
index e153fcb12b1a..66c4badf03e5 100644
--- a/tools/power/acpi/os_specific/service_layers/osunixdir.c
+++ b/tools/power/acpi/os_specific/service_layers/osunixdir.c
@@ -5,7 +5,7 @@
5 *****************************************************************************/ 5 *****************************************************************************/
6 6
7/* 7/*
8 * Copyright (C) 2000 - 2015, Intel Corp. 8 * Copyright (C) 2000 - 2016, Intel Corp.
9 * All rights reserved. 9 * All rights reserved.
10 * 10 *
11 * Redistribution and use in source and binary forms, with or without 11 * Redistribution and use in source and binary forms, with or without
diff --git a/tools/power/acpi/os_specific/service_layers/osunixmap.c b/tools/power/acpi/os_specific/service_layers/osunixmap.c
index 44ad4889d468..3818fd07e50f 100644
--- a/tools/power/acpi/os_specific/service_layers/osunixmap.c
+++ b/tools/power/acpi/os_specific/service_layers/osunixmap.c
@@ -5,7 +5,7 @@
5 *****************************************************************************/ 5 *****************************************************************************/
6 6
7/* 7/*
8 * Copyright (C) 2000 - 2015, Intel Corp. 8 * Copyright (C) 2000 - 2016, Intel Corp.
9 * All rights reserved. 9 * All rights reserved.
10 * 10 *
11 * Redistribution and use in source and binary forms, with or without 11 * Redistribution and use in source and binary forms, with or without
diff --git a/tools/power/acpi/os_specific/service_layers/osunixxf.c b/tools/power/acpi/os_specific/service_layers/osunixxf.c
index 6858c0893c91..08cb8b2035f2 100644
--- a/tools/power/acpi/os_specific/service_layers/osunixxf.c
+++ b/tools/power/acpi/os_specific/service_layers/osunixxf.c
@@ -5,7 +5,7 @@
5 *****************************************************************************/ 5 *****************************************************************************/
6 6
7/* 7/*
8 * Copyright (C) 2000 - 2015, Intel Corp. 8 * Copyright (C) 2000 - 2016, Intel Corp.
9 * All rights reserved. 9 * All rights reserved.
10 * 10 *
11 * Redistribution and use in source and binary forms, with or without 11 * Redistribution and use in source and binary forms, with or without
diff --git a/tools/power/acpi/tools/acpidbg/Makefile b/tools/power/acpi/tools/acpidbg/Makefile
new file mode 100644
index 000000000000..352df4b41ae9
--- /dev/null
+++ b/tools/power/acpi/tools/acpidbg/Makefile
@@ -0,0 +1,27 @@
1# tools/power/acpi/tools/acpidbg/Makefile - ACPI tool Makefile
2#
3# Copyright (c) 2015, Intel Corporation
4# Author: Lv Zheng <lv.zheng@intel.com>
5#
6# This program is free software; you can redistribute it and/or
7# modify it under the terms of the GNU General Public License
8# as published by the Free Software Foundation; version 2
9# of the License.
10
11include ../../Makefile.config
12
13TOOL = acpidbg
14vpath %.c \
15 ../../../../../drivers/acpi/acpica\
16 ../../common\
17 ../../os_specific/service_layers\
18 .
19CFLAGS += -DACPI_APPLICATION -DACPI_SINGLE_THREAD -DACPI_DEBUGGER\
20 -I.\
21 -I../../../../../drivers/acpi/acpica\
22 -I../../../../../include
23LDFLAGS += -lpthread
24TOOL_OBJS = \
25 acpidbg.o
26
27include ../../Makefile.rules
diff --git a/tools/power/acpi/tools/acpidbg/acpidbg.c b/tools/power/acpi/tools/acpidbg/acpidbg.c
new file mode 100644
index 000000000000..d070fccdba6d
--- /dev/null
+++ b/tools/power/acpi/tools/acpidbg/acpidbg.c
@@ -0,0 +1,438 @@
1/*
2 * ACPI AML interfacing userspace utility
3 *
4 * Copyright (C) 2015, Intel Corporation
5 * Authors: Lv Zheng <lv.zheng@intel.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#include <acpi/acpi.h>
13
14/* Headers not included by include/acpi/platform/aclinux.h */
15#include <stdbool.h>
16#include <fcntl.h>
17#include <assert.h>
18#include <linux/circ_buf.h>
19
20#define ACPI_AML_FILE "/sys/kernel/debug/acpi/acpidbg"
21#define ACPI_AML_SEC_TICK 1
22#define ACPI_AML_USEC_PEEK 200
23#define ACPI_AML_BUF_SIZE 4096
24
25#define ACPI_AML_BATCH_WRITE_CMD 0x00 /* Write command to kernel */
26#define ACPI_AML_BATCH_READ_LOG 0x01 /* Read log from kernel */
27#define ACPI_AML_BATCH_WRITE_LOG 0x02 /* Write log to console */
28
29#define ACPI_AML_LOG_START 0x00
30#define ACPI_AML_PROMPT_START 0x01
31#define ACPI_AML_PROMPT_STOP 0x02
32#define ACPI_AML_LOG_STOP 0x03
33#define ACPI_AML_PROMPT_ROLL 0x04
34
35#define ACPI_AML_INTERACTIVE 0x00
36#define ACPI_AML_BATCH 0x01
37
38#define circ_count(circ) \
39 (CIRC_CNT((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE))
40#define circ_count_to_end(circ) \
41 (CIRC_CNT_TO_END((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE))
42#define circ_space(circ) \
43 (CIRC_SPACE((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE))
44#define circ_space_to_end(circ) \
45 (CIRC_SPACE_TO_END((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE))
46
47#define acpi_aml_cmd_count() circ_count(&acpi_aml_cmd_crc)
48#define acpi_aml_log_count() circ_count(&acpi_aml_log_crc)
49#define acpi_aml_cmd_space() circ_space(&acpi_aml_cmd_crc)
50#define acpi_aml_log_space() circ_space(&acpi_aml_log_crc)
51
52#define ACPI_AML_DO(_fd, _op, _buf, _ret) \
53 do { \
54 _ret = acpi_aml_##_op(_fd, &acpi_aml_##_buf##_crc); \
55 if (_ret == 0) { \
56 fprintf(stderr, \
57 "%s %s pipe closed.\n", #_buf, #_op); \
58 return; \
59 } \
60 } while (0)
61#define ACPI_AML_BATCH_DO(_fd, _op, _buf, _ret) \
62 do { \
63 _ret = acpi_aml_##_op##_batch_##_buf(_fd, \
64 &acpi_aml_##_buf##_crc); \
65 if (_ret == 0) \
66 return; \
67 } while (0)
68
69
70static char acpi_aml_cmd_buf[ACPI_AML_BUF_SIZE];
71static char acpi_aml_log_buf[ACPI_AML_BUF_SIZE];
72static struct circ_buf acpi_aml_cmd_crc = {
73 .buf = acpi_aml_cmd_buf,
74 .head = 0,
75 .tail = 0,
76};
77static struct circ_buf acpi_aml_log_crc = {
78 .buf = acpi_aml_log_buf,
79 .head = 0,
80 .tail = 0,
81};
82static const char *acpi_aml_file_path = ACPI_AML_FILE;
83static unsigned long acpi_aml_mode = ACPI_AML_INTERACTIVE;
84static bool acpi_aml_exit;
85
86static bool acpi_aml_batch_drain;
87static unsigned long acpi_aml_batch_state;
88static char acpi_aml_batch_prompt;
89static char acpi_aml_batch_roll;
90static unsigned long acpi_aml_log_state;
91static char *acpi_aml_batch_cmd = NULL;
92static char *acpi_aml_batch_pos = NULL;
93
94static int acpi_aml_set_fl(int fd, int flags)
95{
96 int ret;
97
98 ret = fcntl(fd, F_GETFL, 0);
99 if (ret < 0) {
100 perror("fcntl(F_GETFL)");
101 return ret;
102 }
103 flags |= ret;
104 ret = fcntl(fd, F_SETFL, flags);
105 if (ret < 0) {
106 perror("fcntl(F_SETFL)");
107 return ret;
108 }
109 return ret;
110}
111
112static int acpi_aml_set_fd(int fd, int maxfd, fd_set *set)
113{
114 if (fd > maxfd)
115 maxfd = fd;
116 FD_SET(fd, set);
117 return maxfd;
118}
119
120static int acpi_aml_read(int fd, struct circ_buf *crc)
121{
122 char *p;
123 int len;
124
125 p = &crc->buf[crc->head];
126 len = circ_space_to_end(crc);
127 len = read(fd, p, len);
128 if (len < 0)
129 perror("read");
130 else if (len > 0)
131 crc->head = (crc->head + len) & (ACPI_AML_BUF_SIZE - 1);
132 return len;
133}
134
135static int acpi_aml_read_batch_cmd(int unused, struct circ_buf *crc)
136{
137 char *p;
138 int len;
139 int remained = strlen(acpi_aml_batch_pos);
140
141 p = &crc->buf[crc->head];
142 len = circ_space_to_end(crc);
143 if (len > remained) {
144 memcpy(p, acpi_aml_batch_pos, remained);
145 acpi_aml_batch_pos += remained;
146 len = remained;
147 } else {
148 memcpy(p, acpi_aml_batch_pos, len);
149 acpi_aml_batch_pos += len;
150 }
151 if (len > 0)
152 crc->head = (crc->head + len) & (ACPI_AML_BUF_SIZE - 1);
153 return len;
154}
155
156static int acpi_aml_read_batch_log(int fd, struct circ_buf *crc)
157{
158 char *p;
159 int len;
160 int ret = 0;
161
162 p = &crc->buf[crc->head];
163 len = circ_space_to_end(crc);
164 while (ret < len && acpi_aml_log_state != ACPI_AML_LOG_STOP) {
165 if (acpi_aml_log_state == ACPI_AML_PROMPT_ROLL) {
166 *p = acpi_aml_batch_roll;
167 len = 1;
168 crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
169 ret += 1;
170 acpi_aml_log_state = ACPI_AML_LOG_START;
171 } else {
172 len = read(fd, p, 1);
173 if (len <= 0) {
174 if (len < 0)
175 perror("read");
176 ret = len;
177 break;
178 }
179 }
180 switch (acpi_aml_log_state) {
181 case ACPI_AML_LOG_START:
182 if (*p == '\n')
183 acpi_aml_log_state = ACPI_AML_PROMPT_START;
184 crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
185 ret += 1;
186 break;
187 case ACPI_AML_PROMPT_START:
188 if (*p == ACPI_DEBUGGER_COMMAND_PROMPT ||
189 *p == ACPI_DEBUGGER_EXECUTE_PROMPT) {
190 acpi_aml_batch_prompt = *p;
191 acpi_aml_log_state = ACPI_AML_PROMPT_STOP;
192 } else {
193 if (*p != '\n')
194 acpi_aml_log_state = ACPI_AML_LOG_START;
195 crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
196 ret += 1;
197 }
198 break;
199 case ACPI_AML_PROMPT_STOP:
200 if (*p == ' ') {
201 acpi_aml_log_state = ACPI_AML_LOG_STOP;
202 acpi_aml_exit = true;
203 } else {
204 /* Roll back */
205 acpi_aml_log_state = ACPI_AML_PROMPT_ROLL;
206 acpi_aml_batch_roll = *p;
207 *p = acpi_aml_batch_prompt;
208 crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
209 ret += 1;
210 }
211 break;
212 default:
213 assert(0);
214 break;
215 }
216 }
217 return ret;
218}
219
220static int acpi_aml_write(int fd, struct circ_buf *crc)
221{
222 char *p;
223 int len;
224
225 p = &crc->buf[crc->tail];
226 len = circ_count_to_end(crc);
227 len = write(fd, p, len);
228 if (len < 0)
229 perror("write");
230 else if (len > 0)
231 crc->tail = (crc->tail + len) & (ACPI_AML_BUF_SIZE - 1);
232 return len;
233}
234
235static int acpi_aml_write_batch_log(int fd, struct circ_buf *crc)
236{
237 char *p;
238 int len;
239
240 p = &crc->buf[crc->tail];
241 len = circ_count_to_end(crc);
242 if (!acpi_aml_batch_drain) {
243 len = write(fd, p, len);
244 if (len < 0)
245 perror("write");
246 }
247 if (len > 0)
248 crc->tail = (crc->tail + len) & (ACPI_AML_BUF_SIZE - 1);
249 return len;
250}
251
252static int acpi_aml_write_batch_cmd(int fd, struct circ_buf *crc)
253{
254 int len;
255
256 len = acpi_aml_write(fd, crc);
257 if (circ_count_to_end(crc) == 0)
258 acpi_aml_batch_state = ACPI_AML_BATCH_READ_LOG;
259 return len;
260}
261
262static void acpi_aml_loop(int fd)
263{
264 fd_set rfds;
265 fd_set wfds;
266 struct timeval tv;
267 int ret;
268 int maxfd = 0;
269
270 if (acpi_aml_mode == ACPI_AML_BATCH) {
271 acpi_aml_log_state = ACPI_AML_LOG_START;
272 acpi_aml_batch_pos = acpi_aml_batch_cmd;
273 if (acpi_aml_batch_drain)
274 acpi_aml_batch_state = ACPI_AML_BATCH_READ_LOG;
275 else
276 acpi_aml_batch_state = ACPI_AML_BATCH_WRITE_CMD;
277 }
278 acpi_aml_exit = false;
279 while (!acpi_aml_exit) {
280 tv.tv_sec = ACPI_AML_SEC_TICK;
281 tv.tv_usec = 0;
282 FD_ZERO(&rfds);
283 FD_ZERO(&wfds);
284
285 if (acpi_aml_cmd_space()) {
286 if (acpi_aml_mode == ACPI_AML_INTERACTIVE)
287 maxfd = acpi_aml_set_fd(STDIN_FILENO, maxfd, &rfds);
288 else if (strlen(acpi_aml_batch_pos) &&
289 acpi_aml_batch_state == ACPI_AML_BATCH_WRITE_CMD)
290 ACPI_AML_BATCH_DO(STDIN_FILENO, read, cmd, ret);
291 }
292 if (acpi_aml_cmd_count() &&
293 (acpi_aml_mode == ACPI_AML_INTERACTIVE ||
294 acpi_aml_batch_state == ACPI_AML_BATCH_WRITE_CMD))
295 maxfd = acpi_aml_set_fd(fd, maxfd, &wfds);
296 if (acpi_aml_log_space() &&
297 (acpi_aml_mode == ACPI_AML_INTERACTIVE ||
298 acpi_aml_batch_state == ACPI_AML_BATCH_READ_LOG))
299 maxfd = acpi_aml_set_fd(fd, maxfd, &rfds);
300 if (acpi_aml_log_count())
301 maxfd = acpi_aml_set_fd(STDOUT_FILENO, maxfd, &wfds);
302
303 ret = select(maxfd+1, &rfds, &wfds, NULL, &tv);
304 if (ret < 0) {
305 perror("select");
306 break;
307 }
308 if (ret > 0) {
309 if (FD_ISSET(STDIN_FILENO, &rfds))
310 ACPI_AML_DO(STDIN_FILENO, read, cmd, ret);
311 if (FD_ISSET(fd, &wfds)) {
312 if (acpi_aml_mode == ACPI_AML_BATCH)
313 ACPI_AML_BATCH_DO(fd, write, cmd, ret);
314 else
315 ACPI_AML_DO(fd, write, cmd, ret);
316 }
317 if (FD_ISSET(fd, &rfds)) {
318 if (acpi_aml_mode == ACPI_AML_BATCH)
319 ACPI_AML_BATCH_DO(fd, read, log, ret);
320 else
321 ACPI_AML_DO(fd, read, log, ret);
322 }
323 if (FD_ISSET(STDOUT_FILENO, &wfds)) {
324 if (acpi_aml_mode == ACPI_AML_BATCH)
325 ACPI_AML_BATCH_DO(STDOUT_FILENO, write, log, ret);
326 else
327 ACPI_AML_DO(STDOUT_FILENO, write, log, ret);
328 }
329 }
330 }
331}
332
333static bool acpi_aml_readable(int fd)
334{
335 fd_set rfds;
336 struct timeval tv;
337 int ret;
338 int maxfd = 0;
339
340 tv.tv_sec = 0;
341 tv.tv_usec = ACPI_AML_USEC_PEEK;
342 FD_ZERO(&rfds);
343 maxfd = acpi_aml_set_fd(fd, maxfd, &rfds);
344 ret = select(maxfd+1, &rfds, NULL, NULL, &tv);
345 if (ret < 0)
346 perror("select");
347 if (ret > 0 && FD_ISSET(fd, &rfds))
348 return true;
349 return false;
350}
351
352/*
353 * This is a userspace IO flush implementation, replying on the prompt
354 * characters and can be turned into a flush() call after kernel implements
355 * .flush() filesystem operation.
356 */
357static void acpi_aml_flush(int fd)
358{
359 while (acpi_aml_readable(fd)) {
360 acpi_aml_batch_drain = true;
361 acpi_aml_loop(fd);
362 acpi_aml_batch_drain = false;
363 }
364}
365
366void usage(FILE *file, char *progname)
367{
368 fprintf(file, "usage: %s [-b cmd] [-f file] [-h]\n", progname);
369 fprintf(file, "\nOptions:\n");
370 fprintf(file, " -b Specify command to be executed in batch mode\n");
371 fprintf(file, " -f Specify interface file other than");
372 fprintf(file, " /sys/kernel/debug/acpi/acpidbg\n");
373 fprintf(file, " -h Print this help message\n");
374}
375
376int main(int argc, char **argv)
377{
378 int fd = 0;
379 int ch;
380 int len;
381 int ret = EXIT_SUCCESS;
382
383 while ((ch = getopt(argc, argv, "b:f:h")) != -1) {
384 switch (ch) {
385 case 'b':
386 if (acpi_aml_batch_cmd) {
387 fprintf(stderr, "Already specify %s\n",
388 acpi_aml_batch_cmd);
389 ret = EXIT_FAILURE;
390 goto exit;
391 }
392 len = strlen(optarg);
393 acpi_aml_batch_cmd = calloc(len + 2, 1);
394 if (!acpi_aml_batch_cmd) {
395 perror("calloc");
396 ret = EXIT_FAILURE;
397 goto exit;
398 }
399 memcpy(acpi_aml_batch_cmd, optarg, len);
400 acpi_aml_batch_cmd[len] = '\n';
401 acpi_aml_mode = ACPI_AML_BATCH;
402 break;
403 case 'f':
404 acpi_aml_file_path = optarg;
405 break;
406 case 'h':
407 usage(stdout, argv[0]);
408 goto exit;
409 break;
410 case '?':
411 default:
412 usage(stderr, argv[0]);
413 ret = EXIT_FAILURE;
414 goto exit;
415 break;
416 }
417 }
418
419 fd = open(acpi_aml_file_path, O_RDWR | O_NONBLOCK);
420 if (fd < 0) {
421 perror("open");
422 ret = EXIT_FAILURE;
423 goto exit;
424 }
425 acpi_aml_set_fl(STDIN_FILENO, O_NONBLOCK);
426 acpi_aml_set_fl(STDOUT_FILENO, O_NONBLOCK);
427
428 if (acpi_aml_mode == ACPI_AML_BATCH)
429 acpi_aml_flush(fd);
430 acpi_aml_loop(fd);
431
432exit:
433 if (fd < 0)
434 close(fd);
435 if (acpi_aml_batch_cmd)
436 free(acpi_aml_batch_cmd);
437 return ret;
438}
diff --git a/tools/power/acpi/tools/acpidump/acpidump.h b/tools/power/acpi/tools/acpidump/acpidump.h
index eed534481434..025c232e920d 100644
--- a/tools/power/acpi/tools/acpidump/acpidump.h
+++ b/tools/power/acpi/tools/acpidump/acpidump.h
@@ -5,7 +5,7 @@
5 *****************************************************************************/ 5 *****************************************************************************/
6 6
7/* 7/*
8 * Copyright (C) 2000 - 2015, Intel Corp. 8 * Copyright (C) 2000 - 2016, Intel Corp.
9 * All rights reserved. 9 * All rights reserved.
10 * 10 *
11 * Redistribution and use in source and binary forms, with or without 11 * Redistribution and use in source and binary forms, with or without
diff --git a/tools/power/acpi/tools/acpidump/apdump.c b/tools/power/acpi/tools/acpidump/apdump.c
index 61d0de804b70..da44458d3b6c 100644
--- a/tools/power/acpi/tools/acpidump/apdump.c
+++ b/tools/power/acpi/tools/acpidump/apdump.c
@@ -5,7 +5,7 @@
5 *****************************************************************************/ 5 *****************************************************************************/
6 6
7/* 7/*
8 * Copyright (C) 2000 - 2015, Intel Corp. 8 * Copyright (C) 2000 - 2016, Intel Corp.
9 * All rights reserved. 9 * All rights reserved.
10 * 10 *
11 * Redistribution and use in source and binary forms, with or without 11 * Redistribution and use in source and binary forms, with or without
diff --git a/tools/power/acpi/tools/acpidump/apfiles.c b/tools/power/acpi/tools/acpidump/apfiles.c
index a1c62de42a3b..5fcd9700ac18 100644
--- a/tools/power/acpi/tools/acpidump/apfiles.c
+++ b/tools/power/acpi/tools/acpidump/apfiles.c
@@ -5,7 +5,7 @@
5 *****************************************************************************/ 5 *****************************************************************************/
6 6
7/* 7/*
8 * Copyright (C) 2000 - 2015, Intel Corp. 8 * Copyright (C) 2000 - 2016, Intel Corp.
9 * All rights reserved. 9 * All rights reserved.
10 * 10 *
11 * Redistribution and use in source and binary forms, with or without 11 * Redistribution and use in source and binary forms, with or without
@@ -48,6 +48,18 @@
48 48
49static int ap_is_existing_file(char *pathname); 49static int ap_is_existing_file(char *pathname);
50 50
51/******************************************************************************
52 *
53 * FUNCTION: ap_is_existing_file
54 *
55 * PARAMETERS: pathname - Output filename
56 *
57 * RETURN: 0 on success
58 *
59 * DESCRIPTION: Query for file overwrite if it already exists.
60 *
61 ******************************************************************************/
62
51static int ap_is_existing_file(char *pathname) 63static int ap_is_existing_file(char *pathname)
52{ 64{
53#ifndef _GNU_EFI 65#ifndef _GNU_EFI
@@ -136,6 +148,7 @@ int ap_write_to_binary_file(struct acpi_table_header *table, u32 instance)
136 } else { 148 } else {
137 ACPI_MOVE_NAME(filename, table->signature); 149 ACPI_MOVE_NAME(filename, table->signature);
138 } 150 }
151
139 filename[0] = (char)tolower((int)filename[0]); 152 filename[0] = (char)tolower((int)filename[0]);
140 filename[1] = (char)tolower((int)filename[1]); 153 filename[1] = (char)tolower((int)filename[1]);
141 filename[2] = (char)tolower((int)filename[2]); 154 filename[2] = (char)tolower((int)filename[2]);
diff --git a/tools/power/acpi/tools/acpidump/apmain.c b/tools/power/acpi/tools/acpidump/apmain.c
index 57620f66ae6c..c3c09152fac6 100644
--- a/tools/power/acpi/tools/acpidump/apmain.c
+++ b/tools/power/acpi/tools/acpidump/apmain.c
@@ -5,7 +5,7 @@
5 *****************************************************************************/ 5 *****************************************************************************/
6 6
7/* 7/*
8 * Copyright (C) 2000 - 2015, Intel Corp. 8 * Copyright (C) 2000 - 2016, Intel Corp.
9 * All rights reserved. 9 * All rights reserved.
10 * 10 *
11 * Redistribution and use in source and binary forms, with or without 11 * Redistribution and use in source and binary forms, with or without
diff --git a/tools/power/cpupower/Makefile b/tools/power/cpupower/Makefile
index 2e2ba2efa0d9..0adaf0c7c03a 100644
--- a/tools/power/cpupower/Makefile
+++ b/tools/power/cpupower/Makefile
@@ -47,6 +47,11 @@ NLS ?= true
47# cpufreq-bench benchmarking tool 47# cpufreq-bench benchmarking tool
48CPUFREQ_BENCH ?= true 48CPUFREQ_BENCH ?= true
49 49
50# Do not build libraries, but build the code in statically
51# Libraries are still built, otherwise the Makefile code would
52# be rather ugly.
53export STATIC ?= false
54
50# Prefix to the directories we're installing to 55# Prefix to the directories we're installing to
51DESTDIR ?= 56DESTDIR ?=
52 57
@@ -161,6 +166,12 @@ ifeq ($(strip $(CPUFREQ_BENCH)),true)
161 COMPILE_BENCH += compile-bench 166 COMPILE_BENCH += compile-bench
162endif 167endif
163 168
169ifeq ($(strip $(STATIC)),true)
170 UTIL_OBJS += $(LIB_OBJS)
171 UTIL_HEADERS += $(LIB_HEADERS)
172 UTIL_SRC += $(LIB_SRC)
173endif
174
164CFLAGS += $(WARNINGS) 175CFLAGS += $(WARNINGS)
165 176
166ifeq ($(strip $(V)),false) 177ifeq ($(strip $(V)),false)
@@ -209,7 +220,11 @@ $(OUTPUT)%.o: %.c
209 220
210$(OUTPUT)cpupower: $(UTIL_OBJS) $(OUTPUT)libcpupower.so.$(LIB_MAJ) 221$(OUTPUT)cpupower: $(UTIL_OBJS) $(OUTPUT)libcpupower.so.$(LIB_MAJ)
211 $(ECHO) " CC " $@ 222 $(ECHO) " CC " $@
223ifeq ($(strip $(STATIC)),true)
224 $(QUIET) $(CC) $(CFLAGS) $(LDFLAGS) $(UTIL_OBJS) -lrt -lpci -L$(OUTPUT) -o $@
225else
212 $(QUIET) $(CC) $(CFLAGS) $(LDFLAGS) $(UTIL_OBJS) -lcpupower -lrt -lpci -L$(OUTPUT) -o $@ 226 $(QUIET) $(CC) $(CFLAGS) $(LDFLAGS) $(UTIL_OBJS) -lcpupower -lrt -lpci -L$(OUTPUT) -o $@
227endif
213 $(QUIET) $(STRIPCMD) $@ 228 $(QUIET) $(STRIPCMD) $@
214 229
215$(OUTPUT)po/$(PACKAGE).pot: $(UTIL_SRC) 230$(OUTPUT)po/$(PACKAGE).pot: $(UTIL_SRC)
@@ -291,7 +306,11 @@ install-bench:
291 @#DESTDIR must be set from outside to survive 306 @#DESTDIR must be set from outside to survive
292 @sbindir=$(sbindir) bindir=$(bindir) docdir=$(docdir) confdir=$(confdir) $(MAKE) -C bench O=$(OUTPUT) install 307 @sbindir=$(sbindir) bindir=$(bindir) docdir=$(docdir) confdir=$(confdir) $(MAKE) -C bench O=$(OUTPUT) install
293 308
309ifeq ($(strip $(STATIC)),true)
310install: all install-tools install-man $(INSTALL_NLS) $(INSTALL_BENCH)
311else
294install: all install-lib install-tools install-man $(INSTALL_NLS) $(INSTALL_BENCH) 312install: all install-lib install-tools install-man $(INSTALL_NLS) $(INSTALL_BENCH)
313endif
295 314
296uninstall: 315uninstall:
297 - rm -f $(DESTDIR)${libdir}/libcpupower.* 316 - rm -f $(DESTDIR)${libdir}/libcpupower.*
diff --git a/tools/power/cpupower/bench/Makefile b/tools/power/cpupower/bench/Makefile
index 7ec7021a29cd..d0f879b223fc 100644
--- a/tools/power/cpupower/bench/Makefile
+++ b/tools/power/cpupower/bench/Makefile
@@ -5,9 +5,15 @@ ifneq ($(O),)
5endif 5endif
6endif 6endif
7 7
8ifeq ($(strip $(STATIC)),true)
9LIBS = -L../ -L$(OUTPUT) -lm
10OBJS = $(OUTPUT)main.o $(OUTPUT)parse.o $(OUTPUT)system.o $(OUTPUT)benchmark.o \
11 $(OUTPUT)../lib/cpufreq.o $(OUTPUT)../lib/sysfs.o
12else
8LIBS = -L../ -L$(OUTPUT) -lm -lcpupower 13LIBS = -L../ -L$(OUTPUT) -lm -lcpupower
9
10OBJS = $(OUTPUT)main.o $(OUTPUT)parse.o $(OUTPUT)system.o $(OUTPUT)benchmark.o 14OBJS = $(OUTPUT)main.o $(OUTPUT)parse.o $(OUTPUT)system.o $(OUTPUT)benchmark.o
15endif
16
11CFLAGS += -D_GNU_SOURCE -I../lib -DDEFAULT_CONFIG_FILE=\"$(confdir)/cpufreq-bench.conf\" 17CFLAGS += -D_GNU_SOURCE -I../lib -DDEFAULT_CONFIG_FILE=\"$(confdir)/cpufreq-bench.conf\"
12 18
13$(OUTPUT)%.o : %.c 19$(OUTPUT)%.o : %.c
diff --git a/tools/power/cpupower/utils/cpufreq-info.c b/tools/power/cpupower/utils/cpufreq-info.c
index 0e6764330241..590d12a25f6e 100644
--- a/tools/power/cpupower/utils/cpufreq-info.c
+++ b/tools/power/cpupower/utils/cpufreq-info.c
@@ -10,10 +10,12 @@
10#include <errno.h> 10#include <errno.h>
11#include <stdlib.h> 11#include <stdlib.h>
12#include <string.h> 12#include <string.h>
13#include <limits.h>
13 14
14#include <getopt.h> 15#include <getopt.h>
15 16
16#include "cpufreq.h" 17#include "cpufreq.h"
18#include "helpers/sysfs.h"
17#include "helpers/helpers.h" 19#include "helpers/helpers.h"
18#include "helpers/bitmask.h" 20#include "helpers/bitmask.h"
19 21
@@ -244,149 +246,21 @@ static int get_boost_mode(unsigned int cpu)
244 return 0; 246 return 0;
245} 247}
246 248
247static void debug_output_one(unsigned int cpu)
248{
249 char *driver;
250 struct cpufreq_affected_cpus *cpus;
251 struct cpufreq_available_frequencies *freqs;
252 unsigned long min, max, freq_kernel, freq_hardware;
253 unsigned long total_trans, latency;
254 unsigned long long total_time;
255 struct cpufreq_policy *policy;
256 struct cpufreq_available_governors *governors;
257 struct cpufreq_stats *stats;
258
259 if (cpufreq_cpu_exists(cpu))
260 return;
261
262 freq_kernel = cpufreq_get_freq_kernel(cpu);
263 freq_hardware = cpufreq_get_freq_hardware(cpu);
264
265 driver = cpufreq_get_driver(cpu);
266 if (!driver) {
267 printf(_(" no or unknown cpufreq driver is active on this CPU\n"));
268 } else {
269 printf(_(" driver: %s\n"), driver);
270 cpufreq_put_driver(driver);
271 }
272
273 cpus = cpufreq_get_related_cpus(cpu);
274 if (cpus) {
275 printf(_(" CPUs which run at the same hardware frequency: "));
276 while (cpus->next) {
277 printf("%d ", cpus->cpu);
278 cpus = cpus->next;
279 }
280 printf("%d\n", cpus->cpu);
281 cpufreq_put_related_cpus(cpus);
282 }
283
284 cpus = cpufreq_get_affected_cpus(cpu);
285 if (cpus) {
286 printf(_(" CPUs which need to have their frequency coordinated by software: "));
287 while (cpus->next) {
288 printf("%d ", cpus->cpu);
289 cpus = cpus->next;
290 }
291 printf("%d\n", cpus->cpu);
292 cpufreq_put_affected_cpus(cpus);
293 }
294
295 latency = cpufreq_get_transition_latency(cpu);
296 if (latency) {
297 printf(_(" maximum transition latency: "));
298 print_duration(latency);
299 printf(".\n");
300 }
301
302 if (!(cpufreq_get_hardware_limits(cpu, &min, &max))) {
303 printf(_(" hardware limits: "));
304 print_speed(min);
305 printf(" - ");
306 print_speed(max);
307 printf("\n");
308 }
309
310 freqs = cpufreq_get_available_frequencies(cpu);
311 if (freqs) {
312 printf(_(" available frequency steps: "));
313 while (freqs->next) {
314 print_speed(freqs->frequency);
315 printf(", ");
316 freqs = freqs->next;
317 }
318 print_speed(freqs->frequency);
319 printf("\n");
320 cpufreq_put_available_frequencies(freqs);
321 }
322
323 governors = cpufreq_get_available_governors(cpu);
324 if (governors) {
325 printf(_(" available cpufreq governors: "));
326 while (governors->next) {
327 printf("%s, ", governors->governor);
328 governors = governors->next;
329 }
330 printf("%s\n", governors->governor);
331 cpufreq_put_available_governors(governors);
332 }
333
334 policy = cpufreq_get_policy(cpu);
335 if (policy) {
336 printf(_(" current policy: frequency should be within "));
337 print_speed(policy->min);
338 printf(_(" and "));
339 print_speed(policy->max);
340
341 printf(".\n ");
342 printf(_("The governor \"%s\" may"
343 " decide which speed to use\n within this range.\n"),
344 policy->governor);
345 cpufreq_put_policy(policy);
346 }
347
348 if (freq_kernel || freq_hardware) {
349 printf(_(" current CPU frequency is "));
350 if (freq_hardware) {
351 print_speed(freq_hardware);
352 printf(_(" (asserted by call to hardware)"));
353 } else
354 print_speed(freq_kernel);
355 printf(".\n");
356 }
357 stats = cpufreq_get_stats(cpu, &total_time);
358 if (stats) {
359 printf(_(" cpufreq stats: "));
360 while (stats) {
361 print_speed(stats->frequency);
362 printf(":%.2f%%", (100.0 * stats->time_in_state) / total_time);
363 stats = stats->next;
364 if (stats)
365 printf(", ");
366 }
367 cpufreq_put_stats(stats);
368 total_trans = cpufreq_get_transitions(cpu);
369 if (total_trans)
370 printf(" (%lu)\n", total_trans);
371 else
372 printf("\n");
373 }
374 get_boost_mode(cpu);
375
376}
377
378/* --freq / -f */ 249/* --freq / -f */
379 250
380static int get_freq_kernel(unsigned int cpu, unsigned int human) 251static int get_freq_kernel(unsigned int cpu, unsigned int human)
381{ 252{
382 unsigned long freq = cpufreq_get_freq_kernel(cpu); 253 unsigned long freq = cpufreq_get_freq_kernel(cpu);
383 if (!freq) 254 printf(_(" current CPU frequency: "));
255 if (!freq) {
256 printf(_(" Unable to call to kernel\n"));
384 return -EINVAL; 257 return -EINVAL;
258 }
385 if (human) { 259 if (human) {
386 print_speed(freq); 260 print_speed(freq);
387 printf("\n");
388 } else 261 } else
389 printf("%lu\n", freq); 262 printf("%lu", freq);
263 printf(_(" (asserted by call to kernel)\n"));
390 return 0; 264 return 0;
391} 265}
392 266
@@ -396,13 +270,16 @@ static int get_freq_kernel(unsigned int cpu, unsigned int human)
396static int get_freq_hardware(unsigned int cpu, unsigned int human) 270static int get_freq_hardware(unsigned int cpu, unsigned int human)
397{ 271{
398 unsigned long freq = cpufreq_get_freq_hardware(cpu); 272 unsigned long freq = cpufreq_get_freq_hardware(cpu);
399 if (!freq) 273 printf(_(" current CPU frequency: "));
274 if (!freq) {
275 printf("Unable to call hardware\n");
400 return -EINVAL; 276 return -EINVAL;
277 }
401 if (human) { 278 if (human) {
402 print_speed(freq); 279 print_speed(freq);
403 printf("\n");
404 } else 280 } else
405 printf("%lu\n", freq); 281 printf("%lu", freq);
282 printf(_(" (asserted by call to hardware)\n"));
406 return 0; 283 return 0;
407} 284}
408 285
@@ -411,9 +288,17 @@ static int get_freq_hardware(unsigned int cpu, unsigned int human)
411static int get_hardware_limits(unsigned int cpu) 288static int get_hardware_limits(unsigned int cpu)
412{ 289{
413 unsigned long min, max; 290 unsigned long min, max;
414 if (cpufreq_get_hardware_limits(cpu, &min, &max)) 291
292 printf(_(" hardware limits: "));
293 if (cpufreq_get_hardware_limits(cpu, &min, &max)) {
294 printf(_("Not Available\n"));
415 return -EINVAL; 295 return -EINVAL;
416 printf("%lu %lu\n", min, max); 296 }
297
298 print_speed(min);
299 printf(" - ");
300 print_speed(max);
301 printf("\n");
417 return 0; 302 return 0;
418} 303}
419 304
@@ -422,9 +307,11 @@ static int get_hardware_limits(unsigned int cpu)
422static int get_driver(unsigned int cpu) 307static int get_driver(unsigned int cpu)
423{ 308{
424 char *driver = cpufreq_get_driver(cpu); 309 char *driver = cpufreq_get_driver(cpu);
425 if (!driver) 310 if (!driver) {
311 printf(_(" no or unknown cpufreq driver is active on this CPU\n"));
426 return -EINVAL; 312 return -EINVAL;
427 printf("%s\n", driver); 313 }
314 printf(" driver: %s\n", driver);
428 cpufreq_put_driver(driver); 315 cpufreq_put_driver(driver);
429 return 0; 316 return 0;
430} 317}
@@ -434,9 +321,19 @@ static int get_driver(unsigned int cpu)
434static int get_policy(unsigned int cpu) 321static int get_policy(unsigned int cpu)
435{ 322{
436 struct cpufreq_policy *policy = cpufreq_get_policy(cpu); 323 struct cpufreq_policy *policy = cpufreq_get_policy(cpu);
437 if (!policy) 324 if (!policy) {
325 printf(_(" Unable to determine current policy\n"));
438 return -EINVAL; 326 return -EINVAL;
439 printf("%lu %lu %s\n", policy->min, policy->max, policy->governor); 327 }
328 printf(_(" current policy: frequency should be within "));
329 print_speed(policy->min);
330 printf(_(" and "));
331 print_speed(policy->max);
332
333 printf(".\n ");
334 printf(_("The governor \"%s\" may decide which speed to use\n"
335 " within this range.\n"),
336 policy->governor);
440 cpufreq_put_policy(policy); 337 cpufreq_put_policy(policy);
441 return 0; 338 return 0;
442} 339}
@@ -447,8 +344,12 @@ static int get_available_governors(unsigned int cpu)
447{ 344{
448 struct cpufreq_available_governors *governors = 345 struct cpufreq_available_governors *governors =
449 cpufreq_get_available_governors(cpu); 346 cpufreq_get_available_governors(cpu);
450 if (!governors) 347
348 printf(_(" available cpufreq governors: "));
349 if (!governors) {
350 printf(_("Not Available\n"));
451 return -EINVAL; 351 return -EINVAL;
352 }
452 353
453 while (governors->next) { 354 while (governors->next) {
454 printf("%s ", governors->governor); 355 printf("%s ", governors->governor);
@@ -465,8 +366,12 @@ static int get_available_governors(unsigned int cpu)
465static int get_affected_cpus(unsigned int cpu) 366static int get_affected_cpus(unsigned int cpu)
466{ 367{
467 struct cpufreq_affected_cpus *cpus = cpufreq_get_affected_cpus(cpu); 368 struct cpufreq_affected_cpus *cpus = cpufreq_get_affected_cpus(cpu);
468 if (!cpus) 369
370 printf(_(" CPUs which need to have their frequency coordinated by software: "));
371 if (!cpus) {
372 printf(_("Not Available\n"));
469 return -EINVAL; 373 return -EINVAL;
374 }
470 375
471 while (cpus->next) { 376 while (cpus->next) {
472 printf("%d ", cpus->cpu); 377 printf("%d ", cpus->cpu);
@@ -482,8 +387,12 @@ static int get_affected_cpus(unsigned int cpu)
482static int get_related_cpus(unsigned int cpu) 387static int get_related_cpus(unsigned int cpu)
483{ 388{
484 struct cpufreq_affected_cpus *cpus = cpufreq_get_related_cpus(cpu); 389 struct cpufreq_affected_cpus *cpus = cpufreq_get_related_cpus(cpu);
485 if (!cpus) 390
391 printf(_(" CPUs which run at the same hardware frequency: "));
392 if (!cpus) {
393 printf(_("Not Available\n"));
486 return -EINVAL; 394 return -EINVAL;
395 }
487 396
488 while (cpus->next) { 397 while (cpus->next) {
489 printf("%d ", cpus->cpu); 398 printf("%d ", cpus->cpu);
@@ -524,8 +433,12 @@ static int get_freq_stats(unsigned int cpu, unsigned int human)
524static int get_latency(unsigned int cpu, unsigned int human) 433static int get_latency(unsigned int cpu, unsigned int human)
525{ 434{
526 unsigned long latency = cpufreq_get_transition_latency(cpu); 435 unsigned long latency = cpufreq_get_transition_latency(cpu);
527 if (!latency) 436
437 printf(_(" maximum transition latency: "));
438 if (!latency || latency == UINT_MAX) {
439 printf(_(" Cannot determine or is not supported.\n"));
528 return -EINVAL; 440 return -EINVAL;
441 }
529 442
530 if (human) { 443 if (human) {
531 print_duration(latency); 444 print_duration(latency);
@@ -535,6 +448,36 @@ static int get_latency(unsigned int cpu, unsigned int human)
535 return 0; 448 return 0;
536} 449}
537 450
451static void debug_output_one(unsigned int cpu)
452{
453 struct cpufreq_available_frequencies *freqs;
454
455 get_driver(cpu);
456 get_related_cpus(cpu);
457 get_affected_cpus(cpu);
458 get_latency(cpu, 1);
459 get_hardware_limits(cpu);
460
461 freqs = cpufreq_get_available_frequencies(cpu);
462 if (freqs) {
463 printf(_(" available frequency steps: "));
464 while (freqs->next) {
465 print_speed(freqs->frequency);
466 printf(", ");
467 freqs = freqs->next;
468 }
469 print_speed(freqs->frequency);
470 printf("\n");
471 cpufreq_put_available_frequencies(freqs);
472 }
473
474 get_available_governors(cpu);
475 get_policy(cpu);
476 if (get_freq_hardware(cpu, 1) < 0)
477 get_freq_kernel(cpu, 1);
478 get_boost_mode(cpu);
479}
480
538static struct option info_opts[] = { 481static struct option info_opts[] = {
539 {"debug", no_argument, NULL, 'e'}, 482 {"debug", no_argument, NULL, 'e'},
540 {"boost", no_argument, NULL, 'b'}, 483 {"boost", no_argument, NULL, 'b'},
@@ -647,11 +590,14 @@ int cmd_freq_info(int argc, char **argv)
647 590
648 if (!bitmask_isbitset(cpus_chosen, cpu)) 591 if (!bitmask_isbitset(cpus_chosen, cpu))
649 continue; 592 continue;
650 if (cpufreq_cpu_exists(cpu)) { 593
651 printf(_("couldn't analyze CPU %d as it doesn't seem to be present\n"), cpu); 594 printf(_("analyzing CPU %d:\n"), cpu);
595
596 if (sysfs_is_cpu_online(cpu) != 1) {
597 printf(_(" *is offline\n"));
598 printf("\n");
652 continue; 599 continue;
653 } 600 }
654 printf(_("analyzing CPU %d:\n"), cpu);
655 601
656 switch (output_param) { 602 switch (output_param) {
657 case 'b': 603 case 'b':
@@ -693,6 +639,7 @@ int cmd_freq_info(int argc, char **argv)
693 } 639 }
694 if (ret) 640 if (ret)
695 return ret; 641 return ret;
642 printf("\n");
696 } 643 }
697 return ret; 644 return ret;
698} 645}
diff --git a/tools/power/cpupower/utils/cpuidle-info.c b/tools/power/cpupower/utils/cpuidle-info.c
index 750c1d82c3f7..8bf8ab5ffa25 100644
--- a/tools/power/cpupower/utils/cpuidle-info.c
+++ b/tools/power/cpupower/utils/cpuidle-info.c
@@ -12,7 +12,6 @@
12#include <stdlib.h> 12#include <stdlib.h>
13#include <string.h> 13#include <string.h>
14#include <getopt.h> 14#include <getopt.h>
15#include <cpufreq.h>
16 15
17#include "helpers/helpers.h" 16#include "helpers/helpers.h"
18#include "helpers/sysfs.h" 17#include "helpers/sysfs.h"
@@ -25,8 +24,6 @@ static void cpuidle_cpu_output(unsigned int cpu, int verbose)
25 unsigned int idlestates, idlestate; 24 unsigned int idlestates, idlestate;
26 char *tmp; 25 char *tmp;
27 26
28 printf(_ ("Analyzing CPU %d:\n"), cpu);
29
30 idlestates = sysfs_get_idlestate_count(cpu); 27 idlestates = sysfs_get_idlestate_count(cpu);
31 if (idlestates == 0) { 28 if (idlestates == 0) {
32 printf(_("CPU %u: No idle states\n"), cpu); 29 printf(_("CPU %u: No idle states\n"), cpu);
@@ -71,7 +68,6 @@ static void cpuidle_cpu_output(unsigned int cpu, int verbose)
71 printf(_("Duration: %llu\n"), 68 printf(_("Duration: %llu\n"),
72 sysfs_get_idlestate_time(cpu, idlestate)); 69 sysfs_get_idlestate_time(cpu, idlestate));
73 } 70 }
74 printf("\n");
75} 71}
76 72
77static void cpuidle_general_output(void) 73static void cpuidle_general_output(void)
@@ -189,10 +185,17 @@ int cmd_idle_info(int argc, char **argv)
189 for (cpu = bitmask_first(cpus_chosen); 185 for (cpu = bitmask_first(cpus_chosen);
190 cpu <= bitmask_last(cpus_chosen); cpu++) { 186 cpu <= bitmask_last(cpus_chosen); cpu++) {
191 187
192 if (!bitmask_isbitset(cpus_chosen, cpu) || 188 if (!bitmask_isbitset(cpus_chosen, cpu))
193 cpufreq_cpu_exists(cpu))
194 continue; 189 continue;
195 190
191 printf(_("analyzing CPU %d:\n"), cpu);
192
193 if (sysfs_is_cpu_online(cpu) != 1) {
194 printf(_(" *is offline\n"));
195 printf("\n");
196 continue;
197 }
198
196 switch (output_param) { 199 switch (output_param) {
197 200
198 case 'o': 201 case 'o':
@@ -203,6 +206,7 @@ int cmd_idle_info(int argc, char **argv)
203 cpuidle_cpu_output(cpu, verbose); 206 cpuidle_cpu_output(cpu, verbose);
204 break; 207 break;
205 } 208 }
209 printf("\n");
206 } 210 }
207 return EXIT_SUCCESS; 211 return EXIT_SUCCESS;
208} 212}
diff --git a/tools/power/cpupower/utils/cpupower-info.c b/tools/power/cpupower/utils/cpupower-info.c
index 10299f2e9d2a..c7caa8eaa6d0 100644
--- a/tools/power/cpupower/utils/cpupower-info.c
+++ b/tools/power/cpupower/utils/cpupower-info.c
@@ -12,7 +12,6 @@
12#include <string.h> 12#include <string.h>
13#include <getopt.h> 13#include <getopt.h>
14 14
15#include <cpufreq.h>
16#include "helpers/helpers.h" 15#include "helpers/helpers.h"
17#include "helpers/sysfs.h" 16#include "helpers/sysfs.h"
18 17
@@ -83,12 +82,16 @@ int cmd_info(int argc, char **argv)
83 for (cpu = bitmask_first(cpus_chosen); 82 for (cpu = bitmask_first(cpus_chosen);
84 cpu <= bitmask_last(cpus_chosen); cpu++) { 83 cpu <= bitmask_last(cpus_chosen); cpu++) {
85 84
86 if (!bitmask_isbitset(cpus_chosen, cpu) || 85 if (!bitmask_isbitset(cpus_chosen, cpu))
87 cpufreq_cpu_exists(cpu))
88 continue; 86 continue;
89 87
90 printf(_("analyzing CPU %d:\n"), cpu); 88 printf(_("analyzing CPU %d:\n"), cpu);
91 89
90 if (sysfs_is_cpu_online(cpu) != 1){
91 printf(_(" *is offline\n"));
92 continue;
93 }
94
92 if (params.perf_bias) { 95 if (params.perf_bias) {
93 ret = msr_intel_get_perf_bias(cpu); 96 ret = msr_intel_get_perf_bias(cpu);
94 if (ret < 0) { 97 if (ret < 0) {
diff --git a/tools/power/cpupower/utils/cpupower-set.c b/tools/power/cpupower/utils/cpupower-set.c
index 3e6f374f8dd7..532f46b9a335 100644
--- a/tools/power/cpupower/utils/cpupower-set.c
+++ b/tools/power/cpupower/utils/cpupower-set.c
@@ -12,7 +12,6 @@
12#include <string.h> 12#include <string.h>
13#include <getopt.h> 13#include <getopt.h>
14 14
15#include <cpufreq.h>
16#include "helpers/helpers.h" 15#include "helpers/helpers.h"
17#include "helpers/sysfs.h" 16#include "helpers/sysfs.h"
18#include "helpers/bitmask.h" 17#include "helpers/bitmask.h"
@@ -78,10 +77,15 @@ int cmd_set(int argc, char **argv)
78 for (cpu = bitmask_first(cpus_chosen); 77 for (cpu = bitmask_first(cpus_chosen);
79 cpu <= bitmask_last(cpus_chosen); cpu++) { 78 cpu <= bitmask_last(cpus_chosen); cpu++) {
80 79
81 if (!bitmask_isbitset(cpus_chosen, cpu) || 80 if (!bitmask_isbitset(cpus_chosen, cpu))
82 cpufreq_cpu_exists(cpu))
83 continue; 81 continue;
84 82
83 if (sysfs_is_cpu_online(cpu) != 1){
84 fprintf(stderr, _("Cannot set values on CPU %d:"), cpu);
85 fprintf(stderr, _(" *is offline\n"));
86 continue;
87 }
88
85 if (params.perf_bias) { 89 if (params.perf_bias) {
86 ret = msr_intel_set_perf_bias(cpu, perf_bias); 90 ret = msr_intel_set_perf_bias(cpu, perf_bias);
87 if (ret) { 91 if (ret) {
diff --git a/tools/power/cpupower/utils/helpers/topology.c b/tools/power/cpupower/utils/helpers/topology.c
index 9cbb7fd75171..5f9c908f4557 100644
--- a/tools/power/cpupower/utils/helpers/topology.c
+++ b/tools/power/cpupower/utils/helpers/topology.c
@@ -106,7 +106,7 @@ int get_cpu_topology(struct cpupower_topology *cpu_top)
106 cpu_top->pkgs++; 106 cpu_top->pkgs++;
107 } 107 }
108 } 108 }
109 if (!cpu_top->core_info[0].pkg == -1) 109 if (!(cpu_top->core_info[0].pkg == -1))
110 cpu_top->pkgs++; 110 cpu_top->pkgs++;
111 111
112 /* Intel's cores count is not consecutively numbered, there may 112 /* Intel's cores count is not consecutively numbered, there may
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
index d8e4b20b6d54..0dac7e05a6ac 100644
--- a/tools/power/x86/turbostat/turbostat.c
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -1173,9 +1173,9 @@ dump_nhm_platform_info(void)
1173 unsigned long long msr; 1173 unsigned long long msr;
1174 unsigned int ratio; 1174 unsigned int ratio;
1175 1175
1176 get_msr(base_cpu, MSR_NHM_PLATFORM_INFO, &msr); 1176 get_msr(base_cpu, MSR_PLATFORM_INFO, &msr);
1177 1177
1178 fprintf(stderr, "cpu%d: MSR_NHM_PLATFORM_INFO: 0x%08llx\n", base_cpu, msr); 1178 fprintf(stderr, "cpu%d: MSR_PLATFORM_INFO: 0x%08llx\n", base_cpu, msr);
1179 1179
1180 ratio = (msr >> 40) & 0xFF; 1180 ratio = (msr >> 40) & 0xFF;
1181 fprintf(stderr, "%d * %.0f = %.0f MHz max efficiency frequency\n", 1181 fprintf(stderr, "%d * %.0f = %.0f MHz max efficiency frequency\n",
@@ -1807,7 +1807,7 @@ void check_permissions()
1807 * 1807 *
1808 * MSR_SMI_COUNT 0x00000034 1808 * MSR_SMI_COUNT 0x00000034
1809 * 1809 *
1810 * MSR_NHM_PLATFORM_INFO 0x000000ce 1810 * MSR_PLATFORM_INFO 0x000000ce
1811 * MSR_NHM_SNB_PKG_CST_CFG_CTL 0x000000e2 1811 * MSR_NHM_SNB_PKG_CST_CFG_CTL 0x000000e2
1812 * 1812 *
1813 * MSR_PKG_C3_RESIDENCY 0x000003f8 1813 * MSR_PKG_C3_RESIDENCY 0x000003f8
@@ -1876,7 +1876,7 @@ int probe_nhm_msrs(unsigned int family, unsigned int model)
1876 get_msr(base_cpu, MSR_NHM_SNB_PKG_CST_CFG_CTL, &msr); 1876 get_msr(base_cpu, MSR_NHM_SNB_PKG_CST_CFG_CTL, &msr);
1877 pkg_cstate_limit = pkg_cstate_limits[msr & 0xF]; 1877 pkg_cstate_limit = pkg_cstate_limits[msr & 0xF];
1878 1878
1879 get_msr(base_cpu, MSR_NHM_PLATFORM_INFO, &msr); 1879 get_msr(base_cpu, MSR_PLATFORM_INFO, &msr);
1880 base_ratio = (msr >> 8) & 0xFF; 1880 base_ratio = (msr >> 8) & 0xFF;
1881 1881
1882 base_hz = base_ratio * bclk * 1000000; 1882 base_hz = base_ratio * bclk * 1000000;
diff --git a/tools/perf/config/Makefile.arch b/tools/scripts/Makefile.arch
index e11fbd6fae78..e11fbd6fae78 100644
--- a/tools/perf/config/Makefile.arch
+++ b/tools/scripts/Makefile.arch
diff --git a/tools/spi/.gitignore b/tools/spi/.gitignore
new file mode 100644
index 000000000000..4280576397e8
--- /dev/null
+++ b/tools/spi/.gitignore
@@ -0,0 +1,2 @@
1spidev_fdx
2spidev_test
diff --git a/tools/spi/Makefile b/tools/spi/Makefile
new file mode 100644
index 000000000000..cd0db62e4d9d
--- /dev/null
+++ b/tools/spi/Makefile
@@ -0,0 +1,4 @@
1all: spidev_test spidev_fdx
2
3clean:
4 $(RM) spidev_test spidev_fdx
diff --git a/tools/spi/spidev_fdx.c b/tools/spi/spidev_fdx.c
new file mode 100644
index 000000000000..0ea3e51292fc
--- /dev/null
+++ b/tools/spi/spidev_fdx.c
@@ -0,0 +1,158 @@
1#include <stdio.h>
2#include <unistd.h>
3#include <stdlib.h>
4#include <fcntl.h>
5#include <string.h>
6
7#include <sys/ioctl.h>
8#include <sys/types.h>
9#include <sys/stat.h>
10
11#include <linux/types.h>
12#include <linux/spi/spidev.h>
13
14
15static int verbose;
16
17static void do_read(int fd, int len)
18{
19 unsigned char buf[32], *bp;
20 int status;
21
22 /* read at least 2 bytes, no more than 32 */
23 if (len < 2)
24 len = 2;
25 else if (len > sizeof(buf))
26 len = sizeof(buf);
27 memset(buf, 0, sizeof buf);
28
29 status = read(fd, buf, len);
30 if (status < 0) {
31 perror("read");
32 return;
33 }
34 if (status != len) {
35 fprintf(stderr, "short read\n");
36 return;
37 }
38
39 printf("read(%2d, %2d): %02x %02x,", len, status,
40 buf[0], buf[1]);
41 status -= 2;
42 bp = buf + 2;
43 while (status-- > 0)
44 printf(" %02x", *bp++);
45 printf("\n");
46}
47
48static void do_msg(int fd, int len)
49{
50 struct spi_ioc_transfer xfer[2];
51 unsigned char buf[32], *bp;
52 int status;
53
54 memset(xfer, 0, sizeof xfer);
55 memset(buf, 0, sizeof buf);
56
57 if (len > sizeof buf)
58 len = sizeof buf;
59
60 buf[0] = 0xaa;
61 xfer[0].tx_buf = (unsigned long)buf;
62 xfer[0].len = 1;
63
64 xfer[1].rx_buf = (unsigned long) buf;
65 xfer[1].len = len;
66
67 status = ioctl(fd, SPI_IOC_MESSAGE(2), xfer);
68 if (status < 0) {
69 perror("SPI_IOC_MESSAGE");
70 return;
71 }
72
73 printf("response(%2d, %2d): ", len, status);
74 for (bp = buf; len; len--)
75 printf(" %02x", *bp++);
76 printf("\n");
77}
78
79static void dumpstat(const char *name, int fd)
80{
81 __u8 lsb, bits;
82 __u32 mode, speed;
83
84 if (ioctl(fd, SPI_IOC_RD_MODE32, &mode) < 0) {
85 perror("SPI rd_mode");
86 return;
87 }
88 if (ioctl(fd, SPI_IOC_RD_LSB_FIRST, &lsb) < 0) {
89 perror("SPI rd_lsb_fist");
90 return;
91 }
92 if (ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits) < 0) {
93 perror("SPI bits_per_word");
94 return;
95 }
96 if (ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) < 0) {
97 perror("SPI max_speed_hz");
98 return;
99 }
100
101 printf("%s: spi mode 0x%x, %d bits %sper word, %d Hz max\n",
102 name, mode, bits, lsb ? "(lsb first) " : "", speed);
103}
104
105int main(int argc, char **argv)
106{
107 int c;
108 int readcount = 0;
109 int msglen = 0;
110 int fd;
111 const char *name;
112
113 while ((c = getopt(argc, argv, "hm:r:v")) != EOF) {
114 switch (c) {
115 case 'm':
116 msglen = atoi(optarg);
117 if (msglen < 0)
118 goto usage;
119 continue;
120 case 'r':
121 readcount = atoi(optarg);
122 if (readcount < 0)
123 goto usage;
124 continue;
125 case 'v':
126 verbose++;
127 continue;
128 case 'h':
129 case '?':
130usage:
131 fprintf(stderr,
132 "usage: %s [-h] [-m N] [-r N] /dev/spidevB.D\n",
133 argv[0]);
134 return 1;
135 }
136 }
137
138 if ((optind + 1) != argc)
139 goto usage;
140 name = argv[optind];
141
142 fd = open(name, O_RDWR);
143 if (fd < 0) {
144 perror("open");
145 return 1;
146 }
147
148 dumpstat(name, fd);
149
150 if (msglen)
151 do_msg(fd, msglen);
152
153 if (readcount)
154 do_read(fd, readcount);
155
156 close(fd);
157 return 0;
158}
diff --git a/tools/spi/spidev_test.c b/tools/spi/spidev_test.c
new file mode 100644
index 000000000000..8a73d8185316
--- /dev/null
+++ b/tools/spi/spidev_test.c
@@ -0,0 +1,399 @@
1/*
2 * SPI testing utility (using spidev driver)
3 *
4 * Copyright (c) 2007 MontaVista Software, Inc.
5 * Copyright (c) 2007 Anton Vorontsov <avorontsov@ru.mvista.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License.
10 *
11 * Cross-compile with cross-gcc -I/path/to/cross-kernel/include
12 */
13
14#include <stdint.h>
15#include <unistd.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <getopt.h>
20#include <fcntl.h>
21#include <sys/ioctl.h>
22#include <sys/stat.h>
23#include <linux/types.h>
24#include <linux/spi/spidev.h>
25
26#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
27
28static void pabort(const char *s)
29{
30 perror(s);
31 abort();
32}
33
34static const char *device = "/dev/spidev1.1";
35static uint32_t mode;
36static uint8_t bits = 8;
37static char *input_file;
38static char *output_file;
39static uint32_t speed = 500000;
40static uint16_t delay;
41static int verbose;
42
43uint8_t default_tx[] = {
44 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
45 0x40, 0x00, 0x00, 0x00, 0x00, 0x95,
46 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
47 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
48 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
49 0xF0, 0x0D,
50};
51
52uint8_t default_rx[ARRAY_SIZE(default_tx)] = {0, };
53char *input_tx;
54
55static void hex_dump(const void *src, size_t length, size_t line_size,
56 char *prefix)
57{
58 int i = 0;
59 const unsigned char *address = src;
60 const unsigned char *line = address;
61 unsigned char c;
62
63 printf("%s | ", prefix);
64 while (length-- > 0) {
65 printf("%02X ", *address++);
66 if (!(++i % line_size) || (length == 0 && i % line_size)) {
67 if (length == 0) {
68 while (i++ % line_size)
69 printf("__ ");
70 }
71 printf(" | "); /* right close */
72 while (line < address) {
73 c = *line++;
74 printf("%c", (c < 33 || c == 255) ? 0x2E : c);
75 }
76 printf("\n");
77 if (length > 0)
78 printf("%s | ", prefix);
79 }
80 }
81}
82
83/*
84 * Unescape - process hexadecimal escape character
85 * converts shell input "\x23" -> 0x23
86 */
87static int unescape(char *_dst, char *_src, size_t len)
88{
89 int ret = 0;
90 int match;
91 char *src = _src;
92 char *dst = _dst;
93 unsigned int ch;
94
95 while (*src) {
96 if (*src == '\\' && *(src+1) == 'x') {
97 match = sscanf(src + 2, "%2x", &ch);
98 if (!match)
99 pabort("malformed input string");
100
101 src += 4;
102 *dst++ = (unsigned char)ch;
103 } else {
104 *dst++ = *src++;
105 }
106 ret++;
107 }
108 return ret;
109}
110
111static void transfer(int fd, uint8_t const *tx, uint8_t const *rx, size_t len)
112{
113 int ret;
114 int out_fd;
115 struct spi_ioc_transfer tr = {
116 .tx_buf = (unsigned long)tx,
117 .rx_buf = (unsigned long)rx,
118 .len = len,
119 .delay_usecs = delay,
120 .speed_hz = speed,
121 .bits_per_word = bits,
122 };
123
124 if (mode & SPI_TX_QUAD)
125 tr.tx_nbits = 4;
126 else if (mode & SPI_TX_DUAL)
127 tr.tx_nbits = 2;
128 if (mode & SPI_RX_QUAD)
129 tr.rx_nbits = 4;
130 else if (mode & SPI_RX_DUAL)
131 tr.rx_nbits = 2;
132 if (!(mode & SPI_LOOP)) {
133 if (mode & (SPI_TX_QUAD | SPI_TX_DUAL))
134 tr.rx_buf = 0;
135 else if (mode & (SPI_RX_QUAD | SPI_RX_DUAL))
136 tr.tx_buf = 0;
137 }
138
139 ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
140 if (ret < 1)
141 pabort("can't send spi message");
142
143 if (verbose)
144 hex_dump(tx, len, 32, "TX");
145
146 if (output_file) {
147 out_fd = open(output_file, O_WRONLY | O_CREAT | O_TRUNC, 0666);
148 if (out_fd < 0)
149 pabort("could not open output file");
150
151 ret = write(out_fd, rx, len);
152 if (ret != len)
153 pabort("not all bytes written to output file");
154
155 close(out_fd);
156 }
157
158 if (verbose || !output_file)
159 hex_dump(rx, len, 32, "RX");
160}
161
162static void print_usage(const char *prog)
163{
164 printf("Usage: %s [-DsbdlHOLC3]\n", prog);
165 puts(" -D --device device to use (default /dev/spidev1.1)\n"
166 " -s --speed max speed (Hz)\n"
167 " -d --delay delay (usec)\n"
168 " -b --bpw bits per word\n"
169 " -i --input input data from a file (e.g. \"test.bin\")\n"
170 " -o --output output data to a file (e.g. \"results.bin\")\n"
171 " -l --loop loopback\n"
172 " -H --cpha clock phase\n"
173 " -O --cpol clock polarity\n"
174 " -L --lsb least significant bit first\n"
175 " -C --cs-high chip select active high\n"
176 " -3 --3wire SI/SO signals shared\n"
177 " -v --verbose Verbose (show tx buffer)\n"
178 " -p Send data (e.g. \"1234\\xde\\xad\")\n"
179 " -N --no-cs no chip select\n"
180 " -R --ready slave pulls low to pause\n"
181 " -2 --dual dual transfer\n"
182 " -4 --quad quad transfer\n");
183 exit(1);
184}
185
186static void parse_opts(int argc, char *argv[])
187{
188 while (1) {
189 static const struct option lopts[] = {
190 { "device", 1, 0, 'D' },
191 { "speed", 1, 0, 's' },
192 { "delay", 1, 0, 'd' },
193 { "bpw", 1, 0, 'b' },
194 { "input", 1, 0, 'i' },
195 { "output", 1, 0, 'o' },
196 { "loop", 0, 0, 'l' },
197 { "cpha", 0, 0, 'H' },
198 { "cpol", 0, 0, 'O' },
199 { "lsb", 0, 0, 'L' },
200 { "cs-high", 0, 0, 'C' },
201 { "3wire", 0, 0, '3' },
202 { "no-cs", 0, 0, 'N' },
203 { "ready", 0, 0, 'R' },
204 { "dual", 0, 0, '2' },
205 { "verbose", 0, 0, 'v' },
206 { "quad", 0, 0, '4' },
207 { NULL, 0, 0, 0 },
208 };
209 int c;
210
211 c = getopt_long(argc, argv, "D:s:d:b:i:o:lHOLC3NR24p:v",
212 lopts, NULL);
213
214 if (c == -1)
215 break;
216
217 switch (c) {
218 case 'D':
219 device = optarg;
220 break;
221 case 's':
222 speed = atoi(optarg);
223 break;
224 case 'd':
225 delay = atoi(optarg);
226 break;
227 case 'b':
228 bits = atoi(optarg);
229 break;
230 case 'i':
231 input_file = optarg;
232 break;
233 case 'o':
234 output_file = optarg;
235 break;
236 case 'l':
237 mode |= SPI_LOOP;
238 break;
239 case 'H':
240 mode |= SPI_CPHA;
241 break;
242 case 'O':
243 mode |= SPI_CPOL;
244 break;
245 case 'L':
246 mode |= SPI_LSB_FIRST;
247 break;
248 case 'C':
249 mode |= SPI_CS_HIGH;
250 break;
251 case '3':
252 mode |= SPI_3WIRE;
253 break;
254 case 'N':
255 mode |= SPI_NO_CS;
256 break;
257 case 'v':
258 verbose = 1;
259 break;
260 case 'R':
261 mode |= SPI_READY;
262 break;
263 case 'p':
264 input_tx = optarg;
265 break;
266 case '2':
267 mode |= SPI_TX_DUAL;
268 break;
269 case '4':
270 mode |= SPI_TX_QUAD;
271 break;
272 default:
273 print_usage(argv[0]);
274 break;
275 }
276 }
277 if (mode & SPI_LOOP) {
278 if (mode & SPI_TX_DUAL)
279 mode |= SPI_RX_DUAL;
280 if (mode & SPI_TX_QUAD)
281 mode |= SPI_RX_QUAD;
282 }
283}
284
285static void transfer_escaped_string(int fd, char *str)
286{
287 size_t size = strlen(str + 1);
288 uint8_t *tx;
289 uint8_t *rx;
290
291 tx = malloc(size);
292 if (!tx)
293 pabort("can't allocate tx buffer");
294
295 rx = malloc(size);
296 if (!rx)
297 pabort("can't allocate rx buffer");
298
299 size = unescape((char *)tx, str, size);
300 transfer(fd, tx, rx, size);
301 free(rx);
302 free(tx);
303}
304
305static void transfer_file(int fd, char *filename)
306{
307 ssize_t bytes;
308 struct stat sb;
309 int tx_fd;
310 uint8_t *tx;
311 uint8_t *rx;
312
313 if (stat(filename, &sb) == -1)
314 pabort("can't stat input file");
315
316 tx_fd = open(filename, O_RDONLY);
317 if (fd < 0)
318 pabort("can't open input file");
319
320 tx = malloc(sb.st_size);
321 if (!tx)
322 pabort("can't allocate tx buffer");
323
324 rx = malloc(sb.st_size);
325 if (!rx)
326 pabort("can't allocate rx buffer");
327
328 bytes = read(tx_fd, tx, sb.st_size);
329 if (bytes != sb.st_size)
330 pabort("failed to read input file");
331
332 transfer(fd, tx, rx, sb.st_size);
333 free(rx);
334 free(tx);
335 close(tx_fd);
336}
337
338int main(int argc, char *argv[])
339{
340 int ret = 0;
341 int fd;
342
343 parse_opts(argc, argv);
344
345 fd = open(device, O_RDWR);
346 if (fd < 0)
347 pabort("can't open device");
348
349 /*
350 * spi mode
351 */
352 ret = ioctl(fd, SPI_IOC_WR_MODE32, &mode);
353 if (ret == -1)
354 pabort("can't set spi mode");
355
356 ret = ioctl(fd, SPI_IOC_RD_MODE32, &mode);
357 if (ret == -1)
358 pabort("can't get spi mode");
359
360 /*
361 * bits per word
362 */
363 ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
364 if (ret == -1)
365 pabort("can't set bits per word");
366
367 ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
368 if (ret == -1)
369 pabort("can't get bits per word");
370
371 /*
372 * max speed hz
373 */
374 ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
375 if (ret == -1)
376 pabort("can't set max speed hz");
377
378 ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
379 if (ret == -1)
380 pabort("can't get max speed hz");
381
382 printf("spi mode: 0x%x\n", mode);
383 printf("bits per word: %d\n", bits);
384 printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);
385
386 if (input_tx && input_file)
387 pabort("only one of -p and --input may be selected");
388
389 if (input_tx)
390 transfer_escaped_string(fd, input_tx);
391 else if (input_file)
392 transfer_file(fd, input_file);
393 else
394 transfer(fd, default_tx, default_rx, sizeof(default_tx));
395
396 close(fd);
397
398 return ret;
399}
diff --git a/tools/testing/nvdimm/Kbuild b/tools/testing/nvdimm/Kbuild
index 38b00ecb2ed5..a34bfd0c8928 100644
--- a/tools/testing/nvdimm/Kbuild
+++ b/tools/testing/nvdimm/Kbuild
@@ -9,6 +9,8 @@ ldflags-y += --wrap=memunmap
9ldflags-y += --wrap=__devm_request_region 9ldflags-y += --wrap=__devm_request_region
10ldflags-y += --wrap=__request_region 10ldflags-y += --wrap=__request_region
11ldflags-y += --wrap=__release_region 11ldflags-y += --wrap=__release_region
12ldflags-y += --wrap=devm_memremap_pages
13ldflags-y += --wrap=phys_to_pfn_t
12 14
13DRIVERS := ../../../drivers 15DRIVERS := ../../../drivers
14NVDIMM_SRC := $(DRIVERS)/nvdimm 16NVDIMM_SRC := $(DRIVERS)/nvdimm
diff --git a/tools/testing/nvdimm/test/iomap.c b/tools/testing/nvdimm/test/iomap.c
index b7251314bbc0..0c1a7e65bb81 100644
--- a/tools/testing/nvdimm/test/iomap.c
+++ b/tools/testing/nvdimm/test/iomap.c
@@ -16,6 +16,7 @@
16#include <linux/module.h> 16#include <linux/module.h>
17#include <linux/types.h> 17#include <linux/types.h>
18#include <linux/io.h> 18#include <linux/io.h>
19#include <linux/mm.h>
19#include "nfit_test.h" 20#include "nfit_test.h"
20 21
21static LIST_HEAD(iomap_head); 22static LIST_HEAD(iomap_head);
@@ -41,7 +42,7 @@ void nfit_test_teardown(void)
41} 42}
42EXPORT_SYMBOL(nfit_test_teardown); 43EXPORT_SYMBOL(nfit_test_teardown);
43 44
44static struct nfit_test_resource *get_nfit_res(resource_size_t resource) 45static struct nfit_test_resource *__get_nfit_res(resource_size_t resource)
45{ 46{
46 struct iomap_ops *ops; 47 struct iomap_ops *ops;
47 48
@@ -51,14 +52,22 @@ static struct nfit_test_resource *get_nfit_res(resource_size_t resource)
51 return NULL; 52 return NULL;
52} 53}
53 54
54void __iomem *__nfit_test_ioremap(resource_size_t offset, unsigned long size, 55static struct nfit_test_resource *get_nfit_res(resource_size_t resource)
55 void __iomem *(*fallback_fn)(resource_size_t, unsigned long))
56{ 56{
57 struct nfit_test_resource *nfit_res; 57 struct nfit_test_resource *res;
58 58
59 rcu_read_lock(); 59 rcu_read_lock();
60 nfit_res = get_nfit_res(offset); 60 res = __get_nfit_res(resource);
61 rcu_read_unlock(); 61 rcu_read_unlock();
62
63 return res;
64}
65
66void __iomem *__nfit_test_ioremap(resource_size_t offset, unsigned long size,
67 void __iomem *(*fallback_fn)(resource_size_t, unsigned long))
68{
69 struct nfit_test_resource *nfit_res = get_nfit_res(offset);
70
62 if (nfit_res) 71 if (nfit_res)
63 return (void __iomem *) nfit_res->buf + offset 72 return (void __iomem *) nfit_res->buf + offset
64 - nfit_res->res->start; 73 - nfit_res->res->start;
@@ -68,11 +77,8 @@ void __iomem *__nfit_test_ioremap(resource_size_t offset, unsigned long size,
68void __iomem *__wrap_devm_ioremap_nocache(struct device *dev, 77void __iomem *__wrap_devm_ioremap_nocache(struct device *dev,
69 resource_size_t offset, unsigned long size) 78 resource_size_t offset, unsigned long size)
70{ 79{
71 struct nfit_test_resource *nfit_res; 80 struct nfit_test_resource *nfit_res = get_nfit_res(offset);
72 81
73 rcu_read_lock();
74 nfit_res = get_nfit_res(offset);
75 rcu_read_unlock();
76 if (nfit_res) 82 if (nfit_res)
77 return (void __iomem *) nfit_res->buf + offset 83 return (void __iomem *) nfit_res->buf + offset
78 - nfit_res->res->start; 84 - nfit_res->res->start;
@@ -83,25 +89,58 @@ EXPORT_SYMBOL(__wrap_devm_ioremap_nocache);
83void *__wrap_devm_memremap(struct device *dev, resource_size_t offset, 89void *__wrap_devm_memremap(struct device *dev, resource_size_t offset,
84 size_t size, unsigned long flags) 90 size_t size, unsigned long flags)
85{ 91{
86 struct nfit_test_resource *nfit_res; 92 struct nfit_test_resource *nfit_res = get_nfit_res(offset);
87 93
88 rcu_read_lock();
89 nfit_res = get_nfit_res(offset);
90 rcu_read_unlock();
91 if (nfit_res) 94 if (nfit_res)
92 return nfit_res->buf + offset - nfit_res->res->start; 95 return nfit_res->buf + offset - nfit_res->res->start;
93 return devm_memremap(dev, offset, size, flags); 96 return devm_memremap(dev, offset, size, flags);
94} 97}
95EXPORT_SYMBOL(__wrap_devm_memremap); 98EXPORT_SYMBOL(__wrap_devm_memremap);
96 99
100#ifdef __HAVE_ARCH_PTE_DEVMAP
101#include <linux/memremap.h>
102#include <linux/pfn_t.h>
103
104void *__wrap_devm_memremap_pages(struct device *dev, struct resource *res,
105 struct percpu_ref *ref, struct vmem_altmap *altmap)
106{
107 resource_size_t offset = res->start;
108 struct nfit_test_resource *nfit_res = get_nfit_res(offset);
109
110 if (nfit_res)
111 return nfit_res->buf + offset - nfit_res->res->start;
112 return devm_memremap_pages(dev, res, ref, altmap);
113}
114EXPORT_SYMBOL(__wrap_devm_memremap_pages);
115
116pfn_t __wrap_phys_to_pfn_t(phys_addr_t addr, unsigned long flags)
117{
118 struct nfit_test_resource *nfit_res = get_nfit_res(addr);
119
120 if (nfit_res)
121 flags &= ~PFN_MAP;
122 return phys_to_pfn_t(addr, flags);
123}
124EXPORT_SYMBOL(__wrap_phys_to_pfn_t);
125#else
126/* to be removed post 4.5-rc1 */
127void *__wrap_devm_memremap_pages(struct device *dev, struct resource *res)
128{
129 resource_size_t offset = res->start;
130 struct nfit_test_resource *nfit_res = get_nfit_res(offset);
131
132 if (nfit_res)
133 return nfit_res->buf + offset - nfit_res->res->start;
134 return devm_memremap_pages(dev, res);
135}
136EXPORT_SYMBOL(__wrap_devm_memremap_pages);
137#endif
138
97void *__wrap_memremap(resource_size_t offset, size_t size, 139void *__wrap_memremap(resource_size_t offset, size_t size,
98 unsigned long flags) 140 unsigned long flags)
99{ 141{
100 struct nfit_test_resource *nfit_res; 142 struct nfit_test_resource *nfit_res = get_nfit_res(offset);
101 143
102 rcu_read_lock();
103 nfit_res = get_nfit_res(offset);
104 rcu_read_unlock();
105 if (nfit_res) 144 if (nfit_res)
106 return nfit_res->buf + offset - nfit_res->res->start; 145 return nfit_res->buf + offset - nfit_res->res->start;
107 return memremap(offset, size, flags); 146 return memremap(offset, size, flags);
@@ -110,11 +149,8 @@ EXPORT_SYMBOL(__wrap_memremap);
110 149
111void __wrap_devm_memunmap(struct device *dev, void *addr) 150void __wrap_devm_memunmap(struct device *dev, void *addr)
112{ 151{
113 struct nfit_test_resource *nfit_res; 152 struct nfit_test_resource *nfit_res = get_nfit_res((long) addr);
114 153
115 rcu_read_lock();
116 nfit_res = get_nfit_res((unsigned long) addr);
117 rcu_read_unlock();
118 if (nfit_res) 154 if (nfit_res)
119 return; 155 return;
120 return devm_memunmap(dev, addr); 156 return devm_memunmap(dev, addr);
@@ -135,11 +171,7 @@ EXPORT_SYMBOL(__wrap_ioremap_wc);
135 171
136void __wrap_iounmap(volatile void __iomem *addr) 172void __wrap_iounmap(volatile void __iomem *addr)
137{ 173{
138 struct nfit_test_resource *nfit_res; 174 struct nfit_test_resource *nfit_res = get_nfit_res((long) addr);
139
140 rcu_read_lock();
141 nfit_res = get_nfit_res((unsigned long) addr);
142 rcu_read_unlock();
143 if (nfit_res) 175 if (nfit_res)
144 return; 176 return;
145 return iounmap(addr); 177 return iounmap(addr);
@@ -148,11 +180,8 @@ EXPORT_SYMBOL(__wrap_iounmap);
148 180
149void __wrap_memunmap(void *addr) 181void __wrap_memunmap(void *addr)
150{ 182{
151 struct nfit_test_resource *nfit_res; 183 struct nfit_test_resource *nfit_res = get_nfit_res((long) addr);
152 184
153 rcu_read_lock();
154 nfit_res = get_nfit_res((unsigned long) addr);
155 rcu_read_unlock();
156 if (nfit_res) 185 if (nfit_res)
157 return; 186 return;
158 return memunmap(addr); 187 return memunmap(addr);
@@ -166,9 +195,7 @@ static struct resource *nfit_test_request_region(struct device *dev,
166 struct nfit_test_resource *nfit_res; 195 struct nfit_test_resource *nfit_res;
167 196
168 if (parent == &iomem_resource) { 197 if (parent == &iomem_resource) {
169 rcu_read_lock();
170 nfit_res = get_nfit_res(start); 198 nfit_res = get_nfit_res(start);
171 rcu_read_unlock();
172 if (nfit_res) { 199 if (nfit_res) {
173 struct resource *res = nfit_res->res + 1; 200 struct resource *res = nfit_res->res + 1;
174 201
@@ -218,9 +245,7 @@ void __wrap___release_region(struct resource *parent, resource_size_t start,
218 struct nfit_test_resource *nfit_res; 245 struct nfit_test_resource *nfit_res;
219 246
220 if (parent == &iomem_resource) { 247 if (parent == &iomem_resource) {
221 rcu_read_lock();
222 nfit_res = get_nfit_res(start); 248 nfit_res = get_nfit_res(start);
223 rcu_read_unlock();
224 if (nfit_res) { 249 if (nfit_res) {
225 struct resource *res = nfit_res->res + 1; 250 struct resource *res = nfit_res->res + 1;
226 251
diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c
index 40ab4476c80a..90bd2ea41032 100644
--- a/tools/testing/nvdimm/test/nfit.c
+++ b/tools/testing/nvdimm/test/nfit.c
@@ -248,6 +248,8 @@ static int nfit_test_cmd_ars_status(struct nd_cmd_ars_status *nd_cmd,
248 248
249 nd_cmd->out_length = 256; 249 nd_cmd->out_length = 256;
250 nd_cmd->num_records = 0; 250 nd_cmd->num_records = 0;
251 nd_cmd->address = 0;
252 nd_cmd->length = -1ULL;
251 nd_cmd->status = 0; 253 nd_cmd->status = 0;
252 254
253 return 0; 255 return 0;
@@ -420,8 +422,7 @@ static struct nfit_test_resource *nfit_test_lookup(resource_size_t addr)
420 422
421static int nfit_test0_alloc(struct nfit_test *t) 423static int nfit_test0_alloc(struct nfit_test *t)
422{ 424{
423 size_t nfit_size = sizeof(struct acpi_table_nfit) 425 size_t nfit_size = sizeof(struct acpi_nfit_system_address) * NUM_SPA
424 + sizeof(struct acpi_nfit_system_address) * NUM_SPA
425 + sizeof(struct acpi_nfit_memory_map) * NUM_MEM 426 + sizeof(struct acpi_nfit_memory_map) * NUM_MEM
426 + sizeof(struct acpi_nfit_control_region) * NUM_DCR 427 + sizeof(struct acpi_nfit_control_region) * NUM_DCR
427 + sizeof(struct acpi_nfit_data_region) * NUM_BDW 428 + sizeof(struct acpi_nfit_data_region) * NUM_BDW
@@ -471,8 +472,7 @@ static int nfit_test0_alloc(struct nfit_test *t)
471 472
472static int nfit_test1_alloc(struct nfit_test *t) 473static int nfit_test1_alloc(struct nfit_test *t)
473{ 474{
474 size_t nfit_size = sizeof(struct acpi_table_nfit) 475 size_t nfit_size = sizeof(struct acpi_nfit_system_address)
475 + sizeof(struct acpi_nfit_system_address)
476 + sizeof(struct acpi_nfit_memory_map) 476 + sizeof(struct acpi_nfit_memory_map)
477 + sizeof(struct acpi_nfit_control_region); 477 + sizeof(struct acpi_nfit_control_region);
478 478
@@ -488,39 +488,24 @@ static int nfit_test1_alloc(struct nfit_test *t)
488 return 0; 488 return 0;
489} 489}
490 490
491static void nfit_test_init_header(struct acpi_table_nfit *nfit, size_t size)
492{
493 memcpy(nfit->header.signature, ACPI_SIG_NFIT, 4);
494 nfit->header.length = size;
495 nfit->header.revision = 1;
496 memcpy(nfit->header.oem_id, "LIBND", 6);
497 memcpy(nfit->header.oem_table_id, "TEST", 5);
498 nfit->header.oem_revision = 1;
499 memcpy(nfit->header.asl_compiler_id, "TST", 4);
500 nfit->header.asl_compiler_revision = 1;
501}
502
503static void nfit_test0_setup(struct nfit_test *t) 491static void nfit_test0_setup(struct nfit_test *t)
504{ 492{
505 struct nvdimm_bus_descriptor *nd_desc; 493 struct nvdimm_bus_descriptor *nd_desc;
506 struct acpi_nfit_desc *acpi_desc; 494 struct acpi_nfit_desc *acpi_desc;
507 struct acpi_nfit_memory_map *memdev; 495 struct acpi_nfit_memory_map *memdev;
508 void *nfit_buf = t->nfit_buf; 496 void *nfit_buf = t->nfit_buf;
509 size_t size = t->nfit_size;
510 struct acpi_nfit_system_address *spa; 497 struct acpi_nfit_system_address *spa;
511 struct acpi_nfit_control_region *dcr; 498 struct acpi_nfit_control_region *dcr;
512 struct acpi_nfit_data_region *bdw; 499 struct acpi_nfit_data_region *bdw;
513 struct acpi_nfit_flush_address *flush; 500 struct acpi_nfit_flush_address *flush;
514 unsigned int offset; 501 unsigned int offset;
515 502
516 nfit_test_init_header(nfit_buf, size);
517
518 /* 503 /*
519 * spa0 (interleave first half of dimm0 and dimm1, note storage 504 * spa0 (interleave first half of dimm0 and dimm1, note storage
520 * does not actually alias the related block-data-window 505 * does not actually alias the related block-data-window
521 * regions) 506 * regions)
522 */ 507 */
523 spa = nfit_buf + sizeof(struct acpi_table_nfit); 508 spa = nfit_buf;
524 spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; 509 spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
525 spa->header.length = sizeof(*spa); 510 spa->header.length = sizeof(*spa);
526 memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_PM), 16); 511 memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_PM), 16);
@@ -533,7 +518,7 @@ static void nfit_test0_setup(struct nfit_test *t)
533 * does not actually alias the related block-data-window 518 * does not actually alias the related block-data-window
534 * regions) 519 * regions)
535 */ 520 */
536 spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa); 521 spa = nfit_buf + sizeof(*spa);
537 spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; 522 spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
538 spa->header.length = sizeof(*spa); 523 spa->header.length = sizeof(*spa);
539 memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_PM), 16); 524 memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_PM), 16);
@@ -542,7 +527,7 @@ static void nfit_test0_setup(struct nfit_test *t)
542 spa->length = SPA1_SIZE; 527 spa->length = SPA1_SIZE;
543 528
544 /* spa2 (dcr0) dimm0 */ 529 /* spa2 (dcr0) dimm0 */
545 spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 2; 530 spa = nfit_buf + sizeof(*spa) * 2;
546 spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; 531 spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
547 spa->header.length = sizeof(*spa); 532 spa->header.length = sizeof(*spa);
548 memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16); 533 memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16);
@@ -551,7 +536,7 @@ static void nfit_test0_setup(struct nfit_test *t)
551 spa->length = DCR_SIZE; 536 spa->length = DCR_SIZE;
552 537
553 /* spa3 (dcr1) dimm1 */ 538 /* spa3 (dcr1) dimm1 */
554 spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 3; 539 spa = nfit_buf + sizeof(*spa) * 3;
555 spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; 540 spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
556 spa->header.length = sizeof(*spa); 541 spa->header.length = sizeof(*spa);
557 memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16); 542 memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16);
@@ -560,7 +545,7 @@ static void nfit_test0_setup(struct nfit_test *t)
560 spa->length = DCR_SIZE; 545 spa->length = DCR_SIZE;
561 546
562 /* spa4 (dcr2) dimm2 */ 547 /* spa4 (dcr2) dimm2 */
563 spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 4; 548 spa = nfit_buf + sizeof(*spa) * 4;
564 spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; 549 spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
565 spa->header.length = sizeof(*spa); 550 spa->header.length = sizeof(*spa);
566 memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16); 551 memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16);
@@ -569,7 +554,7 @@ static void nfit_test0_setup(struct nfit_test *t)
569 spa->length = DCR_SIZE; 554 spa->length = DCR_SIZE;
570 555
571 /* spa5 (dcr3) dimm3 */ 556 /* spa5 (dcr3) dimm3 */
572 spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 5; 557 spa = nfit_buf + sizeof(*spa) * 5;
573 spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; 558 spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
574 spa->header.length = sizeof(*spa); 559 spa->header.length = sizeof(*spa);
575 memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16); 560 memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16);
@@ -578,7 +563,7 @@ static void nfit_test0_setup(struct nfit_test *t)
578 spa->length = DCR_SIZE; 563 spa->length = DCR_SIZE;
579 564
580 /* spa6 (bdw for dcr0) dimm0 */ 565 /* spa6 (bdw for dcr0) dimm0 */
581 spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 6; 566 spa = nfit_buf + sizeof(*spa) * 6;
582 spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; 567 spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
583 spa->header.length = sizeof(*spa); 568 spa->header.length = sizeof(*spa);
584 memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); 569 memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16);
@@ -587,7 +572,7 @@ static void nfit_test0_setup(struct nfit_test *t)
587 spa->length = DIMM_SIZE; 572 spa->length = DIMM_SIZE;
588 573
589 /* spa7 (bdw for dcr1) dimm1 */ 574 /* spa7 (bdw for dcr1) dimm1 */
590 spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 7; 575 spa = nfit_buf + sizeof(*spa) * 7;
591 spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; 576 spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
592 spa->header.length = sizeof(*spa); 577 spa->header.length = sizeof(*spa);
593 memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); 578 memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16);
@@ -596,7 +581,7 @@ static void nfit_test0_setup(struct nfit_test *t)
596 spa->length = DIMM_SIZE; 581 spa->length = DIMM_SIZE;
597 582
598 /* spa8 (bdw for dcr2) dimm2 */ 583 /* spa8 (bdw for dcr2) dimm2 */
599 spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 8; 584 spa = nfit_buf + sizeof(*spa) * 8;
600 spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; 585 spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
601 spa->header.length = sizeof(*spa); 586 spa->header.length = sizeof(*spa);
602 memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); 587 memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16);
@@ -605,7 +590,7 @@ static void nfit_test0_setup(struct nfit_test *t)
605 spa->length = DIMM_SIZE; 590 spa->length = DIMM_SIZE;
606 591
607 /* spa9 (bdw for dcr3) dimm3 */ 592 /* spa9 (bdw for dcr3) dimm3 */
608 spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 9; 593 spa = nfit_buf + sizeof(*spa) * 9;
609 spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; 594 spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
610 spa->header.length = sizeof(*spa); 595 spa->header.length = sizeof(*spa);
611 memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); 596 memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16);
@@ -613,7 +598,7 @@ static void nfit_test0_setup(struct nfit_test *t)
613 spa->address = t->dimm_dma[3]; 598 spa->address = t->dimm_dma[3];
614 spa->length = DIMM_SIZE; 599 spa->length = DIMM_SIZE;
615 600
616 offset = sizeof(struct acpi_table_nfit) + sizeof(*spa) * 10; 601 offset = sizeof(*spa) * 10;
617 /* mem-region0 (spa0, dimm0) */ 602 /* mem-region0 (spa0, dimm0) */
618 memdev = nfit_buf + offset; 603 memdev = nfit_buf + offset;
619 memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; 604 memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP;
@@ -1100,15 +1085,15 @@ static void nfit_test0_setup(struct nfit_test *t)
1100 1085
1101static void nfit_test1_setup(struct nfit_test *t) 1086static void nfit_test1_setup(struct nfit_test *t)
1102{ 1087{
1103 size_t size = t->nfit_size, offset; 1088 size_t offset;
1104 void *nfit_buf = t->nfit_buf; 1089 void *nfit_buf = t->nfit_buf;
1105 struct acpi_nfit_memory_map *memdev; 1090 struct acpi_nfit_memory_map *memdev;
1106 struct acpi_nfit_control_region *dcr; 1091 struct acpi_nfit_control_region *dcr;
1107 struct acpi_nfit_system_address *spa; 1092 struct acpi_nfit_system_address *spa;
1093 struct nvdimm_bus_descriptor *nd_desc;
1094 struct acpi_nfit_desc *acpi_desc;
1108 1095
1109 nfit_test_init_header(nfit_buf, size); 1096 offset = 0;
1110
1111 offset = sizeof(struct acpi_table_nfit);
1112 /* spa0 (flat range with no bdw aliasing) */ 1097 /* spa0 (flat range with no bdw aliasing) */
1113 spa = nfit_buf + offset; 1098 spa = nfit_buf + offset;
1114 spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; 1099 spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
@@ -1154,6 +1139,13 @@ static void nfit_test1_setup(struct nfit_test *t)
1154 dcr->command_size = 0; 1139 dcr->command_size = 0;
1155 dcr->status_offset = 0; 1140 dcr->status_offset = 0;
1156 dcr->status_size = 0; 1141 dcr->status_size = 0;
1142
1143 acpi_desc = &t->acpi_desc;
1144 set_bit(ND_CMD_ARS_CAP, &acpi_desc->bus_dsm_force_en);
1145 set_bit(ND_CMD_ARS_START, &acpi_desc->bus_dsm_force_en);
1146 set_bit(ND_CMD_ARS_STATUS, &acpi_desc->bus_dsm_force_en);
1147 nd_desc = &acpi_desc->nd_desc;
1148 nd_desc->ndctl = nfit_test_ctl;
1157} 1149}
1158 1150
1159static int nfit_test_blk_do_io(struct nd_blk_region *ndbr, resource_size_t dpa, 1151static int nfit_test_blk_do_io(struct nd_blk_region *ndbr, resource_size_t dpa,
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index c8edff6803d1..b04afc3295df 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -1,10 +1,12 @@
1TARGETS = breakpoints 1TARGETS = breakpoints
2TARGETS += capabilities
2TARGETS += cpu-hotplug 3TARGETS += cpu-hotplug
3TARGETS += efivarfs 4TARGETS += efivarfs
4TARGETS += exec 5TARGETS += exec
5TARGETS += firmware 6TARGETS += firmware
6TARGETS += ftrace 7TARGETS += ftrace
7TARGETS += futex 8TARGETS += futex
9TARGETS += ipc
8TARGETS += kcmp 10TARGETS += kcmp
9TARGETS += lib 11TARGETS += lib
10TARGETS += membarrier 12TARGETS += membarrier
diff --git a/tools/testing/selftests/breakpoints/.gitignore b/tools/testing/selftests/breakpoints/.gitignore
new file mode 100644
index 000000000000..9b3193d06608
--- /dev/null
+++ b/tools/testing/selftests/breakpoints/.gitignore
@@ -0,0 +1 @@
breakpoint_test
diff --git a/tools/testing/selftests/capabilities/Makefile b/tools/testing/selftests/capabilities/Makefile
index 8c8f0c1f0889..008602aed920 100644
--- a/tools/testing/selftests/capabilities/Makefile
+++ b/tools/testing/selftests/capabilities/Makefile
@@ -1,18 +1,15 @@
1all: 1TEST_FILES := validate_cap
2
3include ../lib.mk
4
5.PHONY: all clean
6
7TARGETS := validate_cap test_execve
8TEST_PROGS := test_execve 2TEST_PROGS := test_execve
9 3
10CFLAGS := -O2 -g -std=gnu99 -Wall -lcap-ng 4BINARIES := $(TEST_FILES) $(TEST_PROGS)
11 5
12all: $(TARGETS) 6CFLAGS += -O2 -g -std=gnu99 -Wall
7LDLIBS += -lcap-ng -lrt -ldl
8
9all: $(BINARIES)
13 10
14clean: 11clean:
15 $(RM) $(TARGETS) 12 $(RM) $(BINARIES)
13
14include ../lib.mk
16 15
17$(TARGETS): %: %.c
18 $(CC) -o $@ $(CFLAGS) $(EXTRA_CFLAGS) $^ -lrt -ldl
diff --git a/tools/testing/selftests/firmware/fw_filesystem.sh b/tools/testing/selftests/firmware/fw_filesystem.sh
index c4366dc74e01..5c495ad7958a 100755
--- a/tools/testing/selftests/firmware/fw_filesystem.sh
+++ b/tools/testing/selftests/firmware/fw_filesystem.sh
@@ -48,8 +48,21 @@ echo "ABCD0123" >"$FW"
48 48
49NAME=$(basename "$FW") 49NAME=$(basename "$FW")
50 50
51if printf '\000' >"$DIR"/trigger_request; then
52 echo "$0: empty filename should not succeed" >&2
53 exit 1
54fi
55
56if printf '\000' >"$DIR"/trigger_async_request; then
57 echo "$0: empty filename should not succeed (async)" >&2
58 exit 1
59fi
60
51# Request a firmware that doesn't exist, it should fail. 61# Request a firmware that doesn't exist, it should fail.
52echo -n "nope-$NAME" >"$DIR"/trigger_request 62if echo -n "nope-$NAME" >"$DIR"/trigger_request; then
63 echo "$0: firmware shouldn't have loaded" >&2
64 exit 1
65fi
53if diff -q "$FW" /dev/test_firmware >/dev/null ; then 66if diff -q "$FW" /dev/test_firmware >/dev/null ; then
54 echo "$0: firmware was not expected to match" >&2 67 echo "$0: firmware was not expected to match" >&2
55 exit 1 68 exit 1
@@ -74,4 +87,18 @@ else
74 echo "$0: filesystem loading works" 87 echo "$0: filesystem loading works"
75fi 88fi
76 89
90# Try the asynchronous version too
91if ! echo -n "$NAME" >"$DIR"/trigger_async_request ; then
92 echo "$0: could not trigger async request" >&2
93 exit 1
94fi
95
96# Verify the contents are what we expect.
97if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then
98 echo "$0: firmware was not loaded (async)" >&2
99 exit 1
100else
101 echo "$0: async filesystem loading works"
102fi
103
77exit 0 104exit 0
diff --git a/tools/testing/selftests/ftrace/test.d/instances/instance.tc b/tools/testing/selftests/ftrace/test.d/instances/instance.tc
new file mode 100644
index 000000000000..773e276ff90b
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/instances/instance.tc
@@ -0,0 +1,90 @@
1#!/bin/sh
2# description: Test creation and deletion of trace instances
3
4if [ ! -d instances ] ; then
5 echo "no instance directory with this kernel"
6 exit_unsupported;
7fi
8
9fail() { # mesg
10 rmdir x y z 2>/dev/null
11 echo $1
12 set -e
13 exit $FAIL
14}
15
16cd instances
17
18# we don't want to fail on error
19set +e
20
21mkdir x
22rmdir x
23result=$?
24
25if [ $result -ne 0 ]; then
26 echo "instance rmdir not supported"
27 exit_unsupported
28fi
29
30instance_slam() {
31 while :; do
32 mkdir x
33 mkdir y
34 mkdir z
35 rmdir x
36 rmdir y
37 rmdir z
38 done 2>/dev/null
39}
40
41instance_slam &
42x=`jobs -l`
43p1=`echo $x | cut -d' ' -f2`
44echo $p1
45
46instance_slam &
47x=`jobs -l | tail -1`
48p2=`echo $x | cut -d' ' -f2`
49echo $p2
50
51instance_slam &
52x=`jobs -l | tail -1`
53p3=`echo $x | cut -d' ' -f2`
54echo $p3
55
56instance_slam &
57x=`jobs -l | tail -1`
58p4=`echo $x | cut -d' ' -f2`
59echo $p4
60
61instance_slam &
62x=`jobs -l | tail -1`
63p5=`echo $x | cut -d' ' -f2`
64echo $p5
65
66ls -lR >/dev/null
67sleep 1
68
69kill -1 $p1
70kill -1 $p2
71kill -1 $p3
72kill -1 $p4
73kill -1 $p5
74
75echo "Wait for processes to finish"
76wait $p1 $p2 $p3 $p4 $p5
77echo "all processes finished, wait for cleanup"
78
79mkdir x y z
80ls x y z
81rmdir x y z
82for d in x y z; do
83 if [ -d $d ]; then
84 fail "instance $d still exists"
85 fi
86done
87
88set -e
89
90exit 0
diff --git a/tools/testing/selftests/futex/README b/tools/testing/selftests/futex/README
index 3224a049b196..0558bb9ce0a6 100644
--- a/tools/testing/selftests/futex/README
+++ b/tools/testing/selftests/futex/README
@@ -27,7 +27,7 @@ o The build system shall remain as simple as possible, avoiding any archive or
27o Where possible, any helper functions or other package-wide code shall be 27o Where possible, any helper functions or other package-wide code shall be
28 implemented in header files, avoiding the need to compile intermediate object 28 implemented in header files, avoiding the need to compile intermediate object
29 files. 29 files.
30o External dependendencies shall remain as minimal as possible. Currently gcc 30o External dependencies shall remain as minimal as possible. Currently gcc
31 and glibc are the only dependencies. 31 and glibc are the only dependencies.
32o Tests return 0 for success and < 0 for failure. 32o Tests return 0 for success and < 0 for failure.
33 33
diff --git a/tools/testing/selftests/intel_pstate/Makefile b/tools/testing/selftests/intel_pstate/Makefile
new file mode 100644
index 000000000000..f5f1a28715ff
--- /dev/null
+++ b/tools/testing/selftests/intel_pstate/Makefile
@@ -0,0 +1,15 @@
1CC := $(CROSS_COMPILE)gcc
2CFLAGS := $(CFLAGS) -Wall -D_GNU_SOURCE
3LDFLAGS := $(LDFLAGS) -lm
4
5TARGETS := msr aperf
6
7TEST_PROGS := $(TARGETS) run.sh
8
9.PHONY: all clean
10all: $(TARGETS)
11
12$(TARGETS): $(HEADERS)
13
14clean:
15 rm -f $(TARGETS)
diff --git a/tools/testing/selftests/intel_pstate/aperf.c b/tools/testing/selftests/intel_pstate/aperf.c
new file mode 100644
index 000000000000..6046e183f4ad
--- /dev/null
+++ b/tools/testing/selftests/intel_pstate/aperf.c
@@ -0,0 +1,80 @@
1#include <math.h>
2#include <unistd.h>
3#include <stdio.h>
4#include <stdlib.h>
5#include <sys/types.h>
6#include <sys/stat.h>
7#include <fcntl.h>
8#include <sys/timeb.h>
9#include <sched.h>
10#include <errno.h>
11
12void usage(char *name) {
13 printf ("Usage: %s cpunum\n", name);
14}
15
16int main(int argc, char **argv) {
17 int i, cpu, fd;
18 char msr_file_name[64];
19 long long tsc, old_tsc, new_tsc;
20 long long aperf, old_aperf, new_aperf;
21 long long mperf, old_mperf, new_mperf;
22 struct timeb before, after;
23 long long int start, finish, total;
24 cpu_set_t cpuset;
25
26 if (argc != 2) {
27 usage(argv[0]);
28 return 1;
29 }
30
31 errno = 0;
32 cpu = strtol(argv[1], (char **) NULL, 10);
33
34 if (errno) {
35 usage(argv[0]);
36 return 1;
37 }
38
39 sprintf(msr_file_name, "/dev/cpu/%d/msr", cpu);
40 fd = open(msr_file_name, O_RDONLY);
41
42 if (fd == -1) {
43 perror("Failed to open");
44 return 1;
45 }
46
47 CPU_ZERO(&cpuset);
48 CPU_SET(cpu, &cpuset);
49
50 if (sched_setaffinity(0, sizeof(cpu_set_t), &cpuset)) {
51 perror("Failed to set cpu affinity");
52 return 1;
53 }
54
55 ftime(&before);
56 pread(fd, &old_tsc, sizeof(old_tsc), 0x10);
57 pread(fd, &old_aperf, sizeof(old_mperf), 0xe7);
58 pread(fd, &old_mperf, sizeof(old_aperf), 0xe8);
59
60 for (i=0; i<0x8fffffff; i++) {
61 sqrt(i);
62 }
63
64 ftime(&after);
65 pread(fd, &new_tsc, sizeof(new_tsc), 0x10);
66 pread(fd, &new_aperf, sizeof(new_mperf), 0xe7);
67 pread(fd, &new_mperf, sizeof(new_aperf), 0xe8);
68
69 tsc = new_tsc-old_tsc;
70 aperf = new_aperf-old_aperf;
71 mperf = new_mperf-old_mperf;
72
73 start = before.time*1000 + before.millitm;
74 finish = after.time*1000 + after.millitm;
75 total = finish - start;
76
77 printf("runTime: %4.2f\n", 1.0*total/1000);
78 printf("freq: %7.0f\n", tsc / (1.0*aperf / (1.0 * mperf)) / total);
79 return 0;
80}
diff --git a/tools/testing/selftests/intel_pstate/msr.c b/tools/testing/selftests/intel_pstate/msr.c
new file mode 100644
index 000000000000..abbbfc84d359
--- /dev/null
+++ b/tools/testing/selftests/intel_pstate/msr.c
@@ -0,0 +1,39 @@
1#include <math.h>
2#include <unistd.h>
3#include <stdio.h>
4#include <stdlib.h>
5#include <sys/types.h>
6#include <sys/stat.h>
7#include <fcntl.h>
8#include <sys/timeb.h>
9#include <sched.h>
10#include <errno.h>
11
12
13int main(int argc, char **argv) {
14 int cpu, fd;
15 long long msr;
16 char msr_file_name[64];
17
18 if (argc != 2)
19 return 1;
20
21 errno = 0;
22 cpu = strtol(argv[1], (char **) NULL, 10);
23
24 if (errno)
25 return 1;
26
27 sprintf(msr_file_name, "/dev/cpu/%d/msr", cpu);
28 fd = open(msr_file_name, O_RDONLY);
29
30 if (fd == -1) {
31 perror("Failed to open");
32 return 1;
33 }
34
35 pread(fd, &msr, sizeof(msr), 0x199);
36
37 printf("msr 0x199: 0x%llx\n", msr);
38 return 0;
39}
diff --git a/tools/testing/selftests/intel_pstate/run.sh b/tools/testing/selftests/intel_pstate/run.sh
new file mode 100755
index 000000000000..bdaf37e92684
--- /dev/null
+++ b/tools/testing/selftests/intel_pstate/run.sh
@@ -0,0 +1,113 @@
1#!/bin/bash
2#
3# This test runs on Intel x86 based hardware which support the intel_pstate
4# driver. The test checks the frequency settings from the maximum turbo
5# state to the minimum supported frequency, in decrements of 100MHz. The
6# test runs the aperf.c program to put load on each processor.
7#
8# The results are displayed in a table which indicate the "Target" state,
9# or the requested frequency in MHz, the Actual frequency, as read from
10# /proc/cpuinfo, the difference between the Target and Actual frequencies,
11# and the value of MSR 0x199 (MSR_IA32_PERF_CTL) which indicates what
12# pstate the cpu is in, and the value of
13# /sys/devices/system/cpu/intel_pstate/max_perf_pct X maximum turbo state
14#
15# Notes: In some cases several frequency values may be placed in the
16# /tmp/result.X files. This is done on purpose in order to catch cases
17# where the pstate driver may not be working at all. There is the case
18# where, for example, several "similar" frequencies are in the file:
19#
20#
21#/tmp/result.3100:1:cpu MHz : 2899.980
22#/tmp/result.3100:2:cpu MHz : 2900.000
23#/tmp/result.3100:3:msr 0x199: 0x1e00
24#/tmp/result.3100:4:max_perf_pct 94
25#
26# and the test will error out in those cases. The result.X file can be checked
27# for consistency and modified to remove the extra MHz values. The result.X
28# files can be re-evaluated by setting EVALUATE_ONLY to 1 below.
29
30EVALUATE_ONLY=0
31
32max_cpus=$(($(nproc)-1))
33
34# compile programs
35gcc -o aperf aperf.c -lm
36[ $? -ne 0 ] && echo "Problem compiling aperf.c." && exit 1
37gcc -o msr msr.c -lm
38[ $? -ne 0 ] && echo "Problem compiling msr.c." && exit 1
39
40function run_test () {
41
42 file_ext=$1
43 for cpu in `seq 0 $max_cpus`
44 do
45 echo "launching aperf load on $cpu"
46 ./aperf $cpu &
47 done
48
49 echo "sleeping for 5 seconds"
50 sleep 5
51 num_freqs=$(cat /proc/cpuinfo | grep MHz | sort -u | wc -l)
52 if [ $num_freqs -le 2 ]; then
53 cat /proc/cpuinfo | grep MHz | sort -u | tail -1 > /tmp/result.$1
54 else
55 cat /proc/cpuinfo | grep MHz | sort -u > /tmp/result.$1
56 fi
57 ./msr 0 >> /tmp/result.$1
58
59 max_perf_pct=$(cat /sys/devices/system/cpu/intel_pstate/max_perf_pct)
60 echo "max_perf_pct $max_perf_pct" >> /tmp/result.$1
61
62 for job in `jobs -p`
63 do
64 echo "waiting for job id $job"
65 wait $job
66 done
67}
68
69#
70# MAIN (ALL UNITS IN MHZ)
71#
72
73# Get the marketing frequency
74_mkt_freq=$(cat /proc/cpuinfo | grep -m 1 "model name" | awk '{print $NF}')
75_mkt_freq=$(echo $_mkt_freq | tr -d [:alpha:][:punct:])
76mkt_freq=${_mkt_freq}0
77
78# Get the ranges from cpupower
79_min_freq=$(cpupower frequency-info -l | tail -1 | awk ' { print $1 } ')
80min_freq=$(($_min_freq / 1000))
81_max_freq=$(cpupower frequency-info -l | tail -1 | awk ' { print $2 } ')
82max_freq=$(($_max_freq / 1000))
83
84
85for freq in `seq $max_freq -100 $min_freq`
86do
87 echo "Setting maximum frequency to $freq"
88 cpupower frequency-set -g powersave --max=${freq}MHz >& /dev/null
89 [ $EVALUATE_ONLY -eq 0 ] && run_test $freq
90done
91
92echo "=============================================================================="
93
94echo "The marketing frequency of the cpu is $mkt_freq MHz"
95echo "The maximum frequency of the cpu is $max_freq MHz"
96echo "The minimum frequency of the cpu is $min_freq MHz"
97
98cpupower frequency-set -g powersave --max=${max_freq}MHz >& /dev/null
99
100# make a pretty table
101echo "Target Actual Difference MSR(0x199) max_perf_pct"
102for freq in `seq $max_freq -100 $min_freq`
103do
104 result_freq=$(cat /tmp/result.${freq} | grep "cpu MHz" | awk ' { print $4 } ' | awk -F "." ' { print $1 } ')
105 msr=$(cat /tmp/result.${freq} | grep "msr" | awk ' { print $3 } ')
106 max_perf_pct=$(cat /tmp/result.${freq} | grep "max_perf_pct" | awk ' { print $2 } ' )
107 if [ $result_freq -eq $freq ]; then
108 echo " $freq $result_freq 0 $msr $(($max_perf_pct*3300))"
109 else
110 echo " $freq $result_freq $(($result_freq-$freq)) $msr $(($max_perf_pct*$max_freq))"
111 fi
112done
113exit 0
diff --git a/tools/testing/selftests/net/.gitignore b/tools/testing/selftests/net/.gitignore
index 00326629d4af..6fb23366b258 100644
--- a/tools/testing/selftests/net/.gitignore
+++ b/tools/testing/selftests/net/.gitignore
@@ -1,3 +1,4 @@
1socket 1socket
2psock_fanout 2psock_fanout
3psock_tpacket 3psock_tpacket
4reuseport_bpf
diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile
index fac4782c51d8..41449b5ad0a9 100644
--- a/tools/testing/selftests/net/Makefile
+++ b/tools/testing/selftests/net/Makefile
@@ -4,7 +4,7 @@ CFLAGS = -Wall -O2 -g
4 4
5CFLAGS += -I../../../../usr/include/ 5CFLAGS += -I../../../../usr/include/
6 6
7NET_PROGS = socket psock_fanout psock_tpacket 7NET_PROGS = socket psock_fanout psock_tpacket reuseport_bpf
8 8
9all: $(NET_PROGS) 9all: $(NET_PROGS)
10%: %.c 10%: %.c
diff --git a/tools/testing/selftests/net/reuseport_bpf.c b/tools/testing/selftests/net/reuseport_bpf.c
new file mode 100644
index 000000000000..bec1b5dd2530
--- /dev/null
+++ b/tools/testing/selftests/net/reuseport_bpf.c
@@ -0,0 +1,514 @@
1/*
2 * Test functionality of BPF filters for SO_REUSEPORT. The tests below will use
3 * a BPF program (both classic and extended) to read the first word from an
4 * incoming packet (expected to be in network byte-order), calculate a modulus
5 * of that number, and then dispatch the packet to the Nth socket using the
6 * result. These tests are run for each supported address family and protocol.
7 * Additionally, a few edge cases in the implementation are tested.
8 */
9
10#include <errno.h>
11#include <error.h>
12#include <linux/bpf.h>
13#include <linux/filter.h>
14#include <linux/unistd.h>
15#include <netinet/in.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <sys/epoll.h>
20#include <sys/types.h>
21#include <sys/socket.h>
22#include <unistd.h>
23
24#ifndef ARRAY_SIZE
25#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
26#endif
27
28struct test_params {
29 int recv_family;
30 int send_family;
31 int protocol;
32 size_t recv_socks;
33 uint16_t recv_port;
34 uint16_t send_port_min;
35};
36
37static size_t sockaddr_size(void)
38{
39 return sizeof(struct sockaddr_storage);
40}
41
42static struct sockaddr *new_any_sockaddr(int family, uint16_t port)
43{
44 struct sockaddr_storage *addr;
45 struct sockaddr_in *addr4;
46 struct sockaddr_in6 *addr6;
47
48 addr = malloc(sizeof(struct sockaddr_storage));
49 memset(addr, 0, sizeof(struct sockaddr_storage));
50
51 switch (family) {
52 case AF_INET:
53 addr4 = (struct sockaddr_in *)addr;
54 addr4->sin_family = AF_INET;
55 addr4->sin_addr.s_addr = htonl(INADDR_ANY);
56 addr4->sin_port = htons(port);
57 break;
58 case AF_INET6:
59 addr6 = (struct sockaddr_in6 *)addr;
60 addr6->sin6_family = AF_INET6;
61 addr6->sin6_addr = in6addr_any;
62 addr6->sin6_port = htons(port);
63 break;
64 default:
65 error(1, 0, "Unsupported family %d", family);
66 }
67 return (struct sockaddr *)addr;
68}
69
70static struct sockaddr *new_loopback_sockaddr(int family, uint16_t port)
71{
72 struct sockaddr *addr = new_any_sockaddr(family, port);
73 struct sockaddr_in *addr4;
74 struct sockaddr_in6 *addr6;
75
76 switch (family) {
77 case AF_INET:
78 addr4 = (struct sockaddr_in *)addr;
79 addr4->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
80 break;
81 case AF_INET6:
82 addr6 = (struct sockaddr_in6 *)addr;
83 addr6->sin6_addr = in6addr_loopback;
84 break;
85 default:
86 error(1, 0, "Unsupported family %d", family);
87 }
88 return addr;
89}
90
91static void attach_ebpf(int fd, uint16_t mod)
92{
93 static char bpf_log_buf[65536];
94 static const char bpf_license[] = "GPL";
95
96 int bpf_fd;
97 const struct bpf_insn prog[] = {
98 /* BPF_MOV64_REG(BPF_REG_6, BPF_REG_1) */
99 { BPF_ALU64 | BPF_MOV | BPF_X, BPF_REG_6, BPF_REG_1, 0, 0 },
100 /* BPF_LD_ABS(BPF_W, 0) R0 = (uint32_t)skb[0] */
101 { BPF_LD | BPF_ABS | BPF_W, 0, 0, 0, 0 },
102 /* BPF_ALU64_IMM(BPF_MOD, BPF_REG_0, mod) */
103 { BPF_ALU64 | BPF_MOD | BPF_K, BPF_REG_0, 0, 0, mod },
104 /* BPF_EXIT_INSN() */
105 { BPF_JMP | BPF_EXIT, 0, 0, 0, 0 }
106 };
107 union bpf_attr attr;
108
109 memset(&attr, 0, sizeof(attr));
110 attr.prog_type = BPF_PROG_TYPE_SOCKET_FILTER;
111 attr.insn_cnt = ARRAY_SIZE(prog);
112 attr.insns = (uint64_t)prog;
113 attr.license = (uint64_t)bpf_license;
114 attr.log_buf = (uint64_t)bpf_log_buf;
115 attr.log_size = sizeof(bpf_log_buf);
116 attr.log_level = 1;
117 attr.kern_version = 0;
118
119 bpf_fd = syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));
120 if (bpf_fd < 0)
121 error(1, errno, "ebpf error. log:\n%s\n", bpf_log_buf);
122
123 if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_REUSEPORT_EBPF, &bpf_fd,
124 sizeof(bpf_fd)))
125 error(1, errno, "failed to set SO_ATTACH_REUSEPORT_EBPF");
126
127 close(bpf_fd);
128}
129
130static void attach_cbpf(int fd, uint16_t mod)
131{
132 struct sock_filter code[] = {
133 /* A = (uint32_t)skb[0] */
134 { BPF_LD | BPF_W | BPF_ABS, 0, 0, 0 },
135 /* A = A % mod */
136 { BPF_ALU | BPF_MOD, 0, 0, mod },
137 /* return A */
138 { BPF_RET | BPF_A, 0, 0, 0 },
139 };
140 struct sock_fprog p = {
141 .len = ARRAY_SIZE(code),
142 .filter = code,
143 };
144
145 if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_REUSEPORT_CBPF, &p, sizeof(p)))
146 error(1, errno, "failed to set SO_ATTACH_REUSEPORT_CBPF");
147}
148
149static void build_recv_group(const struct test_params p, int fd[], uint16_t mod,
150 void (*attach_bpf)(int, uint16_t))
151{
152 struct sockaddr * const addr =
153 new_any_sockaddr(p.recv_family, p.recv_port);
154 int i, opt;
155
156 for (i = 0; i < p.recv_socks; ++i) {
157 fd[i] = socket(p.recv_family, p.protocol, 0);
158 if (fd[i] < 0)
159 error(1, errno, "failed to create recv %d", i);
160
161 opt = 1;
162 if (setsockopt(fd[i], SOL_SOCKET, SO_REUSEPORT, &opt,
163 sizeof(opt)))
164 error(1, errno, "failed to set SO_REUSEPORT on %d", i);
165
166 if (i == 0)
167 attach_bpf(fd[i], mod);
168
169 if (bind(fd[i], addr, sockaddr_size()))
170 error(1, errno, "failed to bind recv socket %d", i);
171
172 if (p.protocol == SOCK_STREAM)
173 if (listen(fd[i], p.recv_socks * 10))
174 error(1, errno, "failed to listen on socket");
175 }
176 free(addr);
177}
178
179static void send_from(struct test_params p, uint16_t sport, char *buf,
180 size_t len)
181{
182 struct sockaddr * const saddr = new_any_sockaddr(p.send_family, sport);
183 struct sockaddr * const daddr =
184 new_loopback_sockaddr(p.send_family, p.recv_port);
185 const int fd = socket(p.send_family, p.protocol, 0);
186
187 if (fd < 0)
188 error(1, errno, "failed to create send socket");
189
190 if (bind(fd, saddr, sockaddr_size()))
191 error(1, errno, "failed to bind send socket");
192 if (connect(fd, daddr, sockaddr_size()))
193 error(1, errno, "failed to connect");
194
195 if (send(fd, buf, len, 0) < 0)
196 error(1, errno, "failed to send message");
197
198 close(fd);
199 free(saddr);
200 free(daddr);
201}
202
203static void test_recv_order(const struct test_params p, int fd[], int mod)
204{
205 char recv_buf[8], send_buf[8];
206 struct msghdr msg;
207 struct iovec recv_io = { recv_buf, 8 };
208 struct epoll_event ev;
209 int epfd, conn, i, sport, expected;
210 uint32_t data, ndata;
211
212 epfd = epoll_create(1);
213 if (epfd < 0)
214 error(1, errno, "failed to create epoll");
215 for (i = 0; i < p.recv_socks; ++i) {
216 ev.events = EPOLLIN;
217 ev.data.fd = fd[i];
218 if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd[i], &ev))
219 error(1, errno, "failed to register sock %d epoll", i);
220 }
221
222 memset(&msg, 0, sizeof(msg));
223 msg.msg_iov = &recv_io;
224 msg.msg_iovlen = 1;
225
226 for (data = 0; data < p.recv_socks * 2; ++data) {
227 sport = p.send_port_min + data;
228 ndata = htonl(data);
229 memcpy(send_buf, &ndata, sizeof(ndata));
230 send_from(p, sport, send_buf, sizeof(ndata));
231
232 i = epoll_wait(epfd, &ev, 1, -1);
233 if (i < 0)
234 error(1, errno, "epoll wait failed");
235
236 if (p.protocol == SOCK_STREAM) {
237 conn = accept(ev.data.fd, NULL, NULL);
238 if (conn < 0)
239 error(1, errno, "error accepting");
240 i = recvmsg(conn, &msg, 0);
241 close(conn);
242 } else {
243 i = recvmsg(ev.data.fd, &msg, 0);
244 }
245 if (i < 0)
246 error(1, errno, "recvmsg error");
247 if (i != sizeof(ndata))
248 error(1, 0, "expected size %zd got %d",
249 sizeof(ndata), i);
250
251 for (i = 0; i < p.recv_socks; ++i)
252 if (ev.data.fd == fd[i])
253 break;
254 memcpy(&ndata, recv_buf, sizeof(ndata));
255 fprintf(stderr, "Socket %d: %d\n", i, ntohl(ndata));
256
257 expected = (sport % mod);
258 if (i != expected)
259 error(1, 0, "expected socket %d", expected);
260 }
261}
262
263static void test_reuseport_ebpf(const struct test_params p)
264{
265 int i, fd[p.recv_socks];
266
267 fprintf(stderr, "Testing EBPF mod %zd...\n", p.recv_socks);
268 build_recv_group(p, fd, p.recv_socks, attach_ebpf);
269 test_recv_order(p, fd, p.recv_socks);
270
271 fprintf(stderr, "Reprograming, testing mod %zd...\n", p.recv_socks / 2);
272 attach_ebpf(fd[0], p.recv_socks / 2);
273 test_recv_order(p, fd, p.recv_socks / 2);
274
275 for (i = 0; i < p.recv_socks; ++i)
276 close(fd[i]);
277}
278
279static void test_reuseport_cbpf(const struct test_params p)
280{
281 int i, fd[p.recv_socks];
282
283 fprintf(stderr, "Testing CBPF mod %zd...\n", p.recv_socks);
284 build_recv_group(p, fd, p.recv_socks, attach_cbpf);
285 test_recv_order(p, fd, p.recv_socks);
286
287 fprintf(stderr, "Reprograming, testing mod %zd...\n", p.recv_socks / 2);
288 attach_cbpf(fd[0], p.recv_socks / 2);
289 test_recv_order(p, fd, p.recv_socks / 2);
290
291 for (i = 0; i < p.recv_socks; ++i)
292 close(fd[i]);
293}
294
295static void test_extra_filter(const struct test_params p)
296{
297 struct sockaddr * const addr =
298 new_any_sockaddr(p.recv_family, p.recv_port);
299 int fd1, fd2, opt;
300
301 fprintf(stderr, "Testing too many filters...\n");
302 fd1 = socket(p.recv_family, p.protocol, 0);
303 if (fd1 < 0)
304 error(1, errno, "failed to create socket 1");
305 fd2 = socket(p.recv_family, p.protocol, 0);
306 if (fd2 < 0)
307 error(1, errno, "failed to create socket 2");
308
309 opt = 1;
310 if (setsockopt(fd1, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt)))
311 error(1, errno, "failed to set SO_REUSEPORT on socket 1");
312 if (setsockopt(fd2, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt)))
313 error(1, errno, "failed to set SO_REUSEPORT on socket 2");
314
315 attach_ebpf(fd1, 10);
316 attach_ebpf(fd2, 10);
317
318 if (bind(fd1, addr, sockaddr_size()))
319 error(1, errno, "failed to bind recv socket 1");
320
321 if (!bind(fd2, addr, sockaddr_size()) && errno != EADDRINUSE)
322 error(1, errno, "bind socket 2 should fail with EADDRINUSE");
323
324 free(addr);
325}
326
327static void test_filter_no_reuseport(const struct test_params p)
328{
329 struct sockaddr * const addr =
330 new_any_sockaddr(p.recv_family, p.recv_port);
331 const char bpf_license[] = "GPL";
332 struct bpf_insn ecode[] = {
333 { BPF_ALU64 | BPF_MOV | BPF_K, BPF_REG_0, 0, 0, 10 },
334 { BPF_JMP | BPF_EXIT, 0, 0, 0, 0 }
335 };
336 struct sock_filter ccode[] = {{ BPF_RET | BPF_A, 0, 0, 0 }};
337 union bpf_attr eprog;
338 struct sock_fprog cprog;
339 int fd, bpf_fd;
340
341 fprintf(stderr, "Testing filters on non-SO_REUSEPORT socket...\n");
342
343 memset(&eprog, 0, sizeof(eprog));
344 eprog.prog_type = BPF_PROG_TYPE_SOCKET_FILTER;
345 eprog.insn_cnt = ARRAY_SIZE(ecode);
346 eprog.insns = (uint64_t)ecode;
347 eprog.license = (uint64_t)bpf_license;
348 eprog.kern_version = 0;
349
350 memset(&cprog, 0, sizeof(cprog));
351 cprog.len = ARRAY_SIZE(ccode);
352 cprog.filter = ccode;
353
354
355 bpf_fd = syscall(__NR_bpf, BPF_PROG_LOAD, &eprog, sizeof(eprog));
356 if (bpf_fd < 0)
357 error(1, errno, "ebpf error");
358 fd = socket(p.recv_family, p.protocol, 0);
359 if (fd < 0)
360 error(1, errno, "failed to create socket 1");
361
362 if (bind(fd, addr, sockaddr_size()))
363 error(1, errno, "failed to bind recv socket 1");
364
365 errno = 0;
366 if (!setsockopt(fd, SOL_SOCKET, SO_ATTACH_REUSEPORT_EBPF, &bpf_fd,
367 sizeof(bpf_fd)) || errno != EINVAL)
368 error(1, errno, "setsockopt should have returned EINVAL");
369
370 errno = 0;
371 if (!setsockopt(fd, SOL_SOCKET, SO_ATTACH_REUSEPORT_CBPF, &cprog,
372 sizeof(cprog)) || errno != EINVAL)
373 error(1, errno, "setsockopt should have returned EINVAL");
374
375 free(addr);
376}
377
378static void test_filter_without_bind(void)
379{
380 int fd1, fd2;
381
382 fprintf(stderr, "Testing filter add without bind...\n");
383 fd1 = socket(AF_INET, SOCK_DGRAM, 0);
384 if (fd1 < 0)
385 error(1, errno, "failed to create socket 1");
386 fd2 = socket(AF_INET, SOCK_DGRAM, 0);
387 if (fd2 < 0)
388 error(1, errno, "failed to create socket 2");
389
390 attach_ebpf(fd1, 10);
391 attach_cbpf(fd2, 10);
392
393 close(fd1);
394 close(fd2);
395}
396
397
398int main(void)
399{
400 fprintf(stderr, "---- IPv4 UDP ----\n");
401 /* NOTE: UDP socket lookups traverse a different code path when there
402 * are > 10 sockets in a group. Run the bpf test through both paths.
403 */
404 test_reuseport_ebpf((struct test_params) {
405 .recv_family = AF_INET,
406 .send_family = AF_INET,
407 .protocol = SOCK_DGRAM,
408 .recv_socks = 10,
409 .recv_port = 8000,
410 .send_port_min = 9000});
411 test_reuseport_ebpf((struct test_params) {
412 .recv_family = AF_INET,
413 .send_family = AF_INET,
414 .protocol = SOCK_DGRAM,
415 .recv_socks = 20,
416 .recv_port = 8000,
417 .send_port_min = 9000});
418 test_reuseport_cbpf((struct test_params) {
419 .recv_family = AF_INET,
420 .send_family = AF_INET,
421 .protocol = SOCK_DGRAM,
422 .recv_socks = 10,
423 .recv_port = 8001,
424 .send_port_min = 9020});
425 test_reuseport_cbpf((struct test_params) {
426 .recv_family = AF_INET,
427 .send_family = AF_INET,
428 .protocol = SOCK_DGRAM,
429 .recv_socks = 20,
430 .recv_port = 8001,
431 .send_port_min = 9020});
432 test_extra_filter((struct test_params) {
433 .recv_family = AF_INET,
434 .protocol = SOCK_DGRAM,
435 .recv_port = 8002});
436 test_filter_no_reuseport((struct test_params) {
437 .recv_family = AF_INET,
438 .protocol = SOCK_DGRAM,
439 .recv_port = 8008});
440
441 fprintf(stderr, "---- IPv6 UDP ----\n");
442 test_reuseport_ebpf((struct test_params) {
443 .recv_family = AF_INET6,
444 .send_family = AF_INET6,
445 .protocol = SOCK_DGRAM,
446 .recv_socks = 10,
447 .recv_port = 8003,
448 .send_port_min = 9040});
449 test_reuseport_ebpf((struct test_params) {
450 .recv_family = AF_INET6,
451 .send_family = AF_INET6,
452 .protocol = SOCK_DGRAM,
453 .recv_socks = 20,
454 .recv_port = 8003,
455 .send_port_min = 9040});
456 test_reuseport_cbpf((struct test_params) {
457 .recv_family = AF_INET6,
458 .send_family = AF_INET6,
459 .protocol = SOCK_DGRAM,
460 .recv_socks = 10,
461 .recv_port = 8004,
462 .send_port_min = 9060});
463 test_reuseport_cbpf((struct test_params) {
464 .recv_family = AF_INET6,
465 .send_family = AF_INET6,
466 .protocol = SOCK_DGRAM,
467 .recv_socks = 20,
468 .recv_port = 8004,
469 .send_port_min = 9060});
470 test_extra_filter((struct test_params) {
471 .recv_family = AF_INET6,
472 .protocol = SOCK_DGRAM,
473 .recv_port = 8005});
474 test_filter_no_reuseport((struct test_params) {
475 .recv_family = AF_INET6,
476 .protocol = SOCK_DGRAM,
477 .recv_port = 8009});
478
479 fprintf(stderr, "---- IPv6 UDP w/ mapped IPv4 ----\n");
480 test_reuseport_ebpf((struct test_params) {
481 .recv_family = AF_INET6,
482 .send_family = AF_INET,
483 .protocol = SOCK_DGRAM,
484 .recv_socks = 20,
485 .recv_port = 8006,
486 .send_port_min = 9080});
487 test_reuseport_ebpf((struct test_params) {
488 .recv_family = AF_INET6,
489 .send_family = AF_INET,
490 .protocol = SOCK_DGRAM,
491 .recv_socks = 10,
492 .recv_port = 8006,
493 .send_port_min = 9080});
494 test_reuseport_cbpf((struct test_params) {
495 .recv_family = AF_INET6,
496 .send_family = AF_INET,
497 .protocol = SOCK_DGRAM,
498 .recv_socks = 10,
499 .recv_port = 8007,
500 .send_port_min = 9100});
501 test_reuseport_cbpf((struct test_params) {
502 .recv_family = AF_INET6,
503 .send_family = AF_INET,
504 .protocol = SOCK_DGRAM,
505 .recv_socks = 20,
506 .recv_port = 8007,
507 .send_port_min = 9100});
508
509
510 test_filter_without_bind();
511
512 fprintf(stderr, "SUCCESS\n");
513 return 0;
514}
diff --git a/tools/testing/selftests/powerpc/benchmarks/.gitignore b/tools/testing/selftests/powerpc/benchmarks/.gitignore
index b4709ea588c1..6fa673316ac2 100644
--- a/tools/testing/selftests/powerpc/benchmarks/.gitignore
+++ b/tools/testing/selftests/powerpc/benchmarks/.gitignore
@@ -1 +1,2 @@
1gettimeofday 1gettimeofday
2context_switch
diff --git a/tools/testing/selftests/powerpc/benchmarks/Makefile b/tools/testing/selftests/powerpc/benchmarks/Makefile
index 5fa48702070d..912445ff7ce7 100644
--- a/tools/testing/selftests/powerpc/benchmarks/Makefile
+++ b/tools/testing/selftests/powerpc/benchmarks/Makefile
@@ -1,4 +1,4 @@
1TEST_PROGS := gettimeofday 1TEST_PROGS := gettimeofday context_switch
2 2
3CFLAGS += -O2 3CFLAGS += -O2
4 4
@@ -6,6 +6,9 @@ all: $(TEST_PROGS)
6 6
7$(TEST_PROGS): ../harness.c 7$(TEST_PROGS): ../harness.c
8 8
9context_switch: ../utils.c
10context_switch: LDLIBS += -lpthread
11
9include ../../lib.mk 12include ../../lib.mk
10 13
11clean: 14clean:
diff --git a/tools/testing/selftests/powerpc/benchmarks/context_switch.c b/tools/testing/selftests/powerpc/benchmarks/context_switch.c
new file mode 100644
index 000000000000..7b785941adec
--- /dev/null
+++ b/tools/testing/selftests/powerpc/benchmarks/context_switch.c
@@ -0,0 +1,466 @@
1/*
2 * Context switch microbenchmark.
3 *
4 * Copyright (C) 2015 Anton Blanchard <anton@au.ibm.com>, IBM
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11
12#define _GNU_SOURCE
13#include <sched.h>
14#include <string.h>
15#include <stdio.h>
16#include <unistd.h>
17#include <stdlib.h>
18#include <getopt.h>
19#include <signal.h>
20#include <assert.h>
21#include <pthread.h>
22#include <limits.h>
23#include <sys/time.h>
24#include <sys/syscall.h>
25#include <sys/types.h>
26#include <sys/shm.h>
27#include <linux/futex.h>
28
29#include "../utils.h"
30
31static unsigned int timeout = 30;
32
33static int touch_vdso;
34struct timeval tv;
35
36static int touch_fp = 1;
37double fp;
38
39static int touch_vector = 1;
40typedef int v4si __attribute__ ((vector_size (16)));
41v4si a, b, c;
42
43#ifdef __powerpc__
44static int touch_altivec = 1;
45
46static void __attribute__((__target__("no-vsx"))) altivec_touch_fn(void)
47{
48 c = a + b;
49}
50#endif
51
52static void touch(void)
53{
54 if (touch_vdso)
55 gettimeofday(&tv, NULL);
56
57 if (touch_fp)
58 fp += 0.1;
59
60#ifdef __powerpc__
61 if (touch_altivec)
62 altivec_touch_fn();
63#endif
64
65 if (touch_vector)
66 c = a + b;
67
68 asm volatile("# %0 %1 %2": : "r"(&tv), "r"(&fp), "r"(&c));
69}
70
71static void start_thread_on(void *(*fn)(void *), void *arg, unsigned long cpu)
72{
73 pthread_t tid;
74 cpu_set_t cpuset;
75 pthread_attr_t attr;
76
77 CPU_ZERO(&cpuset);
78 CPU_SET(cpu, &cpuset);
79
80 pthread_attr_init(&attr);
81
82 if (pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset)) {
83 perror("pthread_attr_setaffinity_np");
84 exit(1);
85 }
86
87 if (pthread_create(&tid, &attr, fn, arg)) {
88 perror("pthread_create");
89 exit(1);
90 }
91}
92
93static void start_process_on(void *(*fn)(void *), void *arg, unsigned long cpu)
94{
95 int pid;
96 cpu_set_t cpuset;
97
98 pid = fork();
99 if (pid == -1) {
100 perror("fork");
101 exit(1);
102 }
103
104 if (pid)
105 return;
106
107 CPU_ZERO(&cpuset);
108 CPU_SET(cpu, &cpuset);
109
110 if (sched_setaffinity(0, sizeof(cpuset), &cpuset)) {
111 perror("sched_setaffinity");
112 exit(1);
113 }
114
115 fn(arg);
116
117 exit(0);
118}
119
120static unsigned long iterations;
121static unsigned long iterations_prev;
122
123static void sigalrm_handler(int junk)
124{
125 unsigned long i = iterations;
126
127 printf("%ld\n", i - iterations_prev);
128 iterations_prev = i;
129
130 if (--timeout == 0)
131 kill(0, SIGUSR1);
132
133 alarm(1);
134}
135
136static void sigusr1_handler(int junk)
137{
138 exit(0);
139}
140
141struct actions {
142 void (*setup)(int, int);
143 void *(*thread1)(void *);
144 void *(*thread2)(void *);
145};
146
147#define READ 0
148#define WRITE 1
149
150static int pipe_fd1[2];
151static int pipe_fd2[2];
152
153static void pipe_setup(int cpu1, int cpu2)
154{
155 if (pipe(pipe_fd1) || pipe(pipe_fd2))
156 exit(1);
157}
158
159static void *pipe_thread1(void *arg)
160{
161 signal(SIGALRM, sigalrm_handler);
162 alarm(1);
163
164 while (1) {
165 assert(read(pipe_fd1[READ], &c, 1) == 1);
166 touch();
167
168 assert(write(pipe_fd2[WRITE], &c, 1) == 1);
169 touch();
170
171 iterations += 2;
172 }
173
174 return NULL;
175}
176
177static void *pipe_thread2(void *arg)
178{
179 while (1) {
180 assert(write(pipe_fd1[WRITE], &c, 1) == 1);
181 touch();
182
183 assert(read(pipe_fd2[READ], &c, 1) == 1);
184 touch();
185 }
186
187 return NULL;
188}
189
190static struct actions pipe_actions = {
191 .setup = pipe_setup,
192 .thread1 = pipe_thread1,
193 .thread2 = pipe_thread2,
194};
195
196static void yield_setup(int cpu1, int cpu2)
197{
198 if (cpu1 != cpu2) {
199 fprintf(stderr, "Both threads must be on the same CPU for yield test\n");
200 exit(1);
201 }
202}
203
204static void *yield_thread1(void *arg)
205{
206 signal(SIGALRM, sigalrm_handler);
207 alarm(1);
208
209 while (1) {
210 sched_yield();
211 touch();
212
213 iterations += 2;
214 }
215
216 return NULL;
217}
218
219static void *yield_thread2(void *arg)
220{
221 while (1) {
222 sched_yield();
223 touch();
224 }
225
226 return NULL;
227}
228
229static struct actions yield_actions = {
230 .setup = yield_setup,
231 .thread1 = yield_thread1,
232 .thread2 = yield_thread2,
233};
234
235static long sys_futex(void *addr1, int op, int val1, struct timespec *timeout,
236 void *addr2, int val3)
237{
238 return syscall(SYS_futex, addr1, op, val1, timeout, addr2, val3);
239}
240
241static unsigned long cmpxchg(unsigned long *p, unsigned long expected,
242 unsigned long desired)
243{
244 unsigned long exp = expected;
245
246 __atomic_compare_exchange_n(p, &exp, desired, 0,
247 __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
248 return exp;
249}
250
251static unsigned long xchg(unsigned long *p, unsigned long val)
252{
253 return __atomic_exchange_n(p, val, __ATOMIC_SEQ_CST);
254}
255
256static int mutex_lock(unsigned long *m)
257{
258 int c;
259
260 c = cmpxchg(m, 0, 1);
261 if (!c)
262 return 0;
263
264 if (c == 1)
265 c = xchg(m, 2);
266
267 while (c) {
268 sys_futex(m, FUTEX_WAIT, 2, NULL, NULL, 0);
269 c = xchg(m, 2);
270 }
271
272 return 0;
273}
274
275static int mutex_unlock(unsigned long *m)
276{
277 if (*m == 2)
278 *m = 0;
279 else if (xchg(m, 0) == 1)
280 return 0;
281
282 sys_futex(m, FUTEX_WAKE, 1, NULL, NULL, 0);
283
284 return 0;
285}
286
287static unsigned long *m1, *m2;
288
289static void futex_setup(int cpu1, int cpu2)
290{
291 int shmid;
292 void *shmaddr;
293
294 shmid = shmget(IPC_PRIVATE, getpagesize(), SHM_R | SHM_W);
295 if (shmid < 0) {
296 perror("shmget");
297 exit(1);
298 }
299
300 shmaddr = shmat(shmid, NULL, 0);
301 if (shmaddr == (char *)-1) {
302 perror("shmat");
303 shmctl(shmid, IPC_RMID, NULL);
304 exit(1);
305 }
306
307 shmctl(shmid, IPC_RMID, NULL);
308
309 m1 = shmaddr;
310 m2 = shmaddr + sizeof(*m1);
311
312 *m1 = 0;
313 *m2 = 0;
314
315 mutex_lock(m1);
316 mutex_lock(m2);
317}
318
319static void *futex_thread1(void *arg)
320{
321 signal(SIGALRM, sigalrm_handler);
322 alarm(1);
323
324 while (1) {
325 mutex_lock(m2);
326 mutex_unlock(m1);
327
328 iterations += 2;
329 }
330
331 return NULL;
332}
333
334static void *futex_thread2(void *arg)
335{
336 while (1) {
337 mutex_unlock(m2);
338 mutex_lock(m1);
339 }
340
341 return NULL;
342}
343
344static struct actions futex_actions = {
345 .setup = futex_setup,
346 .thread1 = futex_thread1,
347 .thread2 = futex_thread2,
348};
349
350static int processes;
351
352static struct option options[] = {
353 { "test", required_argument, 0, 't' },
354 { "process", no_argument, &processes, 1 },
355 { "timeout", required_argument, 0, 's' },
356 { "vdso", no_argument, &touch_vdso, 1 },
357 { "no-fp", no_argument, &touch_fp, 0 },
358#ifdef __powerpc__
359 { "no-altivec", no_argument, &touch_altivec, 0 },
360#endif
361 { "no-vector", no_argument, &touch_vector, 0 },
362 { 0, },
363};
364
365static void usage(void)
366{
367 fprintf(stderr, "Usage: context_switch2 <options> CPU1 CPU2\n\n");
368 fprintf(stderr, "\t\t--test=X\tpipe, futex or yield (default)\n");
369 fprintf(stderr, "\t\t--process\tUse processes (default threads)\n");
370 fprintf(stderr, "\t\t--timeout=X\tDuration in seconds to run (default 30)\n");
371 fprintf(stderr, "\t\t--vdso\t\ttouch VDSO\n");
372 fprintf(stderr, "\t\t--fp\t\ttouch FP\n");
373#ifdef __powerpc__
374 fprintf(stderr, "\t\t--altivec\ttouch altivec\n");
375#endif
376 fprintf(stderr, "\t\t--vector\ttouch vector\n");
377}
378
379int main(int argc, char *argv[])
380{
381 signed char c;
382 struct actions *actions = &yield_actions;
383 int cpu1;
384 int cpu2;
385 static void (*start_fn)(void *(*fn)(void *), void *arg, unsigned long cpu);
386
387 while (1) {
388 int option_index = 0;
389
390 c = getopt_long(argc, argv, "", options, &option_index);
391
392 if (c == -1)
393 break;
394
395 switch (c) {
396 case 0:
397 if (options[option_index].flag != 0)
398 break;
399
400 usage();
401 exit(1);
402 break;
403
404 case 't':
405 if (!strcmp(optarg, "pipe")) {
406 actions = &pipe_actions;
407 } else if (!strcmp(optarg, "yield")) {
408 actions = &yield_actions;
409 } else if (!strcmp(optarg, "futex")) {
410 actions = &futex_actions;
411 } else {
412 usage();
413 exit(1);
414 }
415 break;
416
417 case 's':
418 timeout = atoi(optarg);
419 break;
420
421 default:
422 usage();
423 exit(1);
424 }
425 }
426
427 if (processes)
428 start_fn = start_process_on;
429 else
430 start_fn = start_thread_on;
431
432 if (((argc - optind) != 2)) {
433 cpu1 = cpu2 = pick_online_cpu();
434 } else {
435 cpu1 = atoi(argv[optind++]);
436 cpu2 = atoi(argv[optind++]);
437 }
438
439 printf("Using %s with ", processes ? "processes" : "threads");
440
441 if (actions == &pipe_actions)
442 printf("pipe");
443 else if (actions == &yield_actions)
444 printf("yield");
445 else
446 printf("futex");
447
448 printf(" on cpus %d/%d touching FP:%s altivec:%s vector:%s vdso:%s\n",
449 cpu1, cpu2, touch_fp ? "yes" : "no", touch_altivec ? "yes" : "no",
450 touch_vector ? "yes" : "no", touch_vdso ? "yes" : "no");
451
452 /* Create a new process group so we can signal everyone for exit */
453 setpgid(getpid(), getpid());
454
455 signal(SIGUSR1, sigusr1_handler);
456
457 actions->setup(cpu1, cpu2);
458
459 start_fn(actions->thread1, NULL, cpu1);
460 start_fn(actions->thread2, NULL, cpu2);
461
462 while (1)
463 sleep(3600);
464
465 return 0;
466}
diff --git a/tools/testing/selftests/powerpc/dscr/dscr_inherit_exec_test.c b/tools/testing/selftests/powerpc/dscr/dscr_inherit_exec_test.c
index 8265504de571..08a8b95e3bc1 100644
--- a/tools/testing/selftests/powerpc/dscr/dscr_inherit_exec_test.c
+++ b/tools/testing/selftests/powerpc/dscr/dscr_inherit_exec_test.c
@@ -60,14 +60,6 @@ int dscr_inherit_exec(void)
60 else 60 else
61 set_dscr(dscr); 61 set_dscr(dscr);
62 62
63 /*
64 * XXX: Force a context switch out so that DSCR
65 * current value is copied into the thread struct
66 * which is required for the child to inherit the
67 * changed value.
68 */
69 sleep(1);
70
71 pid = fork(); 63 pid = fork();
72 if (pid == -1) { 64 if (pid == -1) {
73 perror("fork() failed"); 65 perror("fork() failed");
diff --git a/tools/testing/selftests/powerpc/dscr/dscr_inherit_test.c b/tools/testing/selftests/powerpc/dscr/dscr_inherit_test.c
index 4e414caf7f40..3e5a6d195e9a 100644
--- a/tools/testing/selftests/powerpc/dscr/dscr_inherit_test.c
+++ b/tools/testing/selftests/powerpc/dscr/dscr_inherit_test.c
@@ -40,14 +40,6 @@ int dscr_inherit(void)
40 else 40 else
41 set_dscr(dscr); 41 set_dscr(dscr);
42 42
43 /*
44 * XXX: Force a context switch out so that DSCR
45 * current value is copied into the thread struct
46 * which is required for the child to inherit the
47 * changed value.
48 */
49 sleep(1);
50
51 pid = fork(); 43 pid = fork();
52 if (pid == -1) { 44 if (pid == -1) {
53 perror("fork() failed"); 45 perror("fork() failed");
diff --git a/tools/testing/selftests/powerpc/harness.c b/tools/testing/selftests/powerpc/harness.c
index f7997affd143..52f9be7f61f0 100644
--- a/tools/testing/selftests/powerpc/harness.c
+++ b/tools/testing/selftests/powerpc/harness.c
@@ -116,46 +116,3 @@ int test_harness(int (test_function)(void), char *name)
116 116
117 return rc; 117 return rc;
118} 118}
119
120static char auxv[4096];
121
122void *get_auxv_entry(int type)
123{
124 ElfW(auxv_t) *p;
125 void *result;
126 ssize_t num;
127 int fd;
128
129 fd = open("/proc/self/auxv", O_RDONLY);
130 if (fd == -1) {
131 perror("open");
132 return NULL;
133 }
134
135 result = NULL;
136
137 num = read(fd, auxv, sizeof(auxv));
138 if (num < 0) {
139 perror("read");
140 goto out;
141 }
142
143 if (num > sizeof(auxv)) {
144 printf("Overflowed auxv buffer\n");
145 goto out;
146 }
147
148 p = (ElfW(auxv_t) *)auxv;
149
150 while (p->a_type != AT_NULL) {
151 if (p->a_type == type) {
152 result = (void *)p->a_un.a_val;
153 break;
154 }
155
156 p++;
157 }
158out:
159 close(fd);
160 return result;
161}
diff --git a/tools/testing/selftests/powerpc/pmu/Makefile b/tools/testing/selftests/powerpc/pmu/Makefile
index a9099d9f8f39..ac41a7177f2e 100644
--- a/tools/testing/selftests/powerpc/pmu/Makefile
+++ b/tools/testing/selftests/powerpc/pmu/Makefile
@@ -2,7 +2,7 @@ noarg:
2 $(MAKE) -C ../ 2 $(MAKE) -C ../
3 3
4TEST_PROGS := count_instructions l3_bank_test per_event_excludes 4TEST_PROGS := count_instructions l3_bank_test per_event_excludes
5EXTRA_SOURCES := ../harness.c event.c lib.c 5EXTRA_SOURCES := ../harness.c event.c lib.c ../utils.c
6 6
7all: $(TEST_PROGS) ebb 7all: $(TEST_PROGS) ebb
8 8
@@ -12,6 +12,8 @@ $(TEST_PROGS): $(EXTRA_SOURCES)
12count_instructions: loop.S count_instructions.c $(EXTRA_SOURCES) 12count_instructions: loop.S count_instructions.c $(EXTRA_SOURCES)
13 $(CC) $(CFLAGS) -m64 -o $@ $^ 13 $(CC) $(CFLAGS) -m64 -o $@ $^
14 14
15per_event_excludes: ../utils.c
16
15include ../../lib.mk 17include ../../lib.mk
16 18
17DEFAULT_RUN_TESTS := $(RUN_TESTS) 19DEFAULT_RUN_TESTS := $(RUN_TESTS)
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/Makefile b/tools/testing/selftests/powerpc/pmu/ebb/Makefile
index 5cdc9dbf2b27..8d2279c4bb4b 100644
--- a/tools/testing/selftests/powerpc/pmu/ebb/Makefile
+++ b/tools/testing/selftests/powerpc/pmu/ebb/Makefile
@@ -18,7 +18,8 @@ TEST_PROGS := reg_access_test event_attributes_test cycles_test \
18 18
19all: $(TEST_PROGS) 19all: $(TEST_PROGS)
20 20
21$(TEST_PROGS): ../../harness.c ../event.c ../lib.c ebb.c ebb_handler.S trace.c busy_loop.S 21$(TEST_PROGS): ../../harness.c ../../utils.c ../event.c ../lib.c \
22 ebb.c ebb_handler.S trace.c busy_loop.S
22 23
23instruction_count_test: ../loop.S 24instruction_count_test: ../loop.S
24 25
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/ebb.c b/tools/testing/selftests/powerpc/pmu/ebb/ebb.c
index 9729d9f90218..e67452f1bcff 100644
--- a/tools/testing/selftests/powerpc/pmu/ebb/ebb.c
+++ b/tools/testing/selftests/powerpc/pmu/ebb/ebb.c
@@ -13,7 +13,6 @@
13#include <stdlib.h> 13#include <stdlib.h>
14#include <string.h> 14#include <string.h>
15#include <sys/ioctl.h> 15#include <sys/ioctl.h>
16#include <linux/auxvec.h>
17 16
18#include "trace.h" 17#include "trace.h"
19#include "reg.h" 18#include "reg.h"
@@ -324,7 +323,7 @@ bool ebb_is_supported(void)
324{ 323{
325#ifdef PPC_FEATURE2_EBB 324#ifdef PPC_FEATURE2_EBB
326 /* EBB requires at least POWER8 */ 325 /* EBB requires at least POWER8 */
327 return ((long)get_auxv_entry(AT_HWCAP2) & PPC_FEATURE2_EBB); 326 return have_hwcap2(PPC_FEATURE2_EBB);
328#else 327#else
329 return false; 328 return false;
330#endif 329#endif
diff --git a/tools/testing/selftests/powerpc/pmu/lib.c b/tools/testing/selftests/powerpc/pmu/lib.c
index a07104c2afe6..a361ad3334ce 100644
--- a/tools/testing/selftests/powerpc/pmu/lib.c
+++ b/tools/testing/selftests/powerpc/pmu/lib.c
@@ -15,32 +15,6 @@
15#include "lib.h" 15#include "lib.h"
16 16
17 17
18int pick_online_cpu(void)
19{
20 cpu_set_t mask;
21 int cpu;
22
23 CPU_ZERO(&mask);
24
25 if (sched_getaffinity(0, sizeof(mask), &mask)) {
26 perror("sched_getaffinity");
27 return -1;
28 }
29
30 /* We prefer a primary thread, but skip 0 */
31 for (cpu = 8; cpu < CPU_SETSIZE; cpu += 8)
32 if (CPU_ISSET(cpu, &mask))
33 return cpu;
34
35 /* Search for anything, but in reverse */
36 for (cpu = CPU_SETSIZE - 1; cpu >= 0; cpu--)
37 if (CPU_ISSET(cpu, &mask))
38 return cpu;
39
40 printf("No cpus in affinity mask?!\n");
41 return -1;
42}
43
44int bind_to_cpu(int cpu) 18int bind_to_cpu(int cpu)
45{ 19{
46 cpu_set_t mask; 20 cpu_set_t mask;
diff --git a/tools/testing/selftests/powerpc/pmu/lib.h b/tools/testing/selftests/powerpc/pmu/lib.h
index ca5d72ae3be6..0213af4ff332 100644
--- a/tools/testing/selftests/powerpc/pmu/lib.h
+++ b/tools/testing/selftests/powerpc/pmu/lib.h
@@ -19,7 +19,6 @@ union pipe {
19 int fds[2]; 19 int fds[2];
20}; 20};
21 21
22extern int pick_online_cpu(void);
23extern int bind_to_cpu(int cpu); 22extern int bind_to_cpu(int cpu);
24extern int kill_child_and_wait(pid_t child_pid); 23extern int kill_child_and_wait(pid_t child_pid);
25extern int wait_for_child(pid_t child_pid); 24extern int wait_for_child(pid_t child_pid);
diff --git a/tools/testing/selftests/powerpc/scripts/hmi.sh b/tools/testing/selftests/powerpc/scripts/hmi.sh
new file mode 100755
index 000000000000..83fb253ae3bd
--- /dev/null
+++ b/tools/testing/selftests/powerpc/scripts/hmi.sh
@@ -0,0 +1,89 @@
1#!/bin/sh
2#
3# Copyright 2015, Daniel Axtens, IBM Corporation
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; version 2 of the License.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13
14
15# do we have ./getscom, ./putscom?
16if [ -x ./getscom ] && [ -x ./putscom ]; then
17 GETSCOM=./getscom
18 PUTSCOM=./putscom
19elif which getscom > /dev/null; then
20 GETSCOM=$(which getscom)
21 PUTSCOM=$(which putscom)
22else
23 cat <<EOF
24Can't find getscom/putscom in . or \$PATH.
25See https://github.com/open-power/skiboot.
26The tool is in external/xscom-utils
27EOF
28 exit 1
29fi
30
31# We will get 8 HMI events per injection
32# todo: deal with things being offline
33expected_hmis=8
34COUNT_HMIS() {
35 dmesg | grep -c 'Harmless Hypervisor Maintenance interrupt'
36}
37
38# massively expand snooze delay, allowing injection on all cores
39ppc64_cpu --smt-snooze-delay=1000000000
40
41# when we exit, restore it
42trap "ppc64_cpu --smt-snooze-delay=100" 0 1
43
44# for each chip+core combination
45# todo - less fragile parsing
46egrep -o 'OCC: Chip [0-9a-f]+ Core [0-9a-f]' < /sys/firmware/opal/msglog |
47while read chipcore; do
48 chip=$(echo "$chipcore"|awk '{print $3}')
49 core=$(echo "$chipcore"|awk '{print $5}')
50 fir="0x1${core}013100"
51
52 # verify that Core FIR is zero as expected
53 if [ "$($GETSCOM -c 0x${chip} $fir)" != 0 ]; then
54 echo "FIR was not zero before injection for chip $chip, core $core. Aborting!"
55 echo "Result of $GETSCOM -c 0x${chip} $fir:"
56 $GETSCOM -c 0x${chip} $fir
57 echo "If you get a -5 error, the core may be in idle state. Try stress-ng."
58 echo "Otherwise, try $PUTSCOM -c 0x${chip} $fir 0"
59 exit 1
60 fi
61
62 # keep track of the number of HMIs handled
63 old_hmis=$(COUNT_HMIS)
64
65 # do injection, adding a marker to dmesg for clarity
66 echo "Injecting HMI on core $core, chip $chip" | tee /dev/kmsg
67 # inject a RegFile recoverable error
68 if ! $PUTSCOM -c 0x${chip} $fir 2000000000000000 > /dev/null; then
69 echo "Error injecting. Aborting!"
70 exit 1
71 fi
72
73 # now we want to wait for all the HMIs to be processed
74 # we expect one per thread on the core
75 i=0;
76 new_hmis=$(COUNT_HMIS)
77 while [ $new_hmis -lt $((old_hmis + expected_hmis)) ] && [ $i -lt 12 ]; do
78 echo "Seen $((new_hmis - old_hmis)) HMI(s) out of $expected_hmis expected, sleeping"
79 sleep 5;
80 i=$((i + 1))
81 new_hmis=$(COUNT_HMIS)
82 done
83 if [ $i = 12 ]; then
84 echo "Haven't seen expected $expected_hmis recoveries after 1 min. Aborting."
85 exit 1
86 fi
87 echo "Processed $expected_hmis events; presumed success. Check dmesg."
88 echo ""
89done
diff --git a/tools/testing/selftests/powerpc/tm/.gitignore b/tools/testing/selftests/powerpc/tm/.gitignore
index 2699635d2cd9..7d0f14b8cb2e 100644
--- a/tools/testing/selftests/powerpc/tm/.gitignore
+++ b/tools/testing/selftests/powerpc/tm/.gitignore
@@ -1,2 +1,5 @@
1tm-resched-dscr 1tm-resched-dscr
2tm-syscall 2tm-syscall
3tm-signal-msr-resv
4tm-signal-stack
5tm-vmxcopy
diff --git a/tools/testing/selftests/powerpc/tm/Makefile b/tools/testing/selftests/powerpc/tm/Makefile
index 4bea62a319dc..737f72c964e6 100644
--- a/tools/testing/selftests/powerpc/tm/Makefile
+++ b/tools/testing/selftests/powerpc/tm/Makefile
@@ -1,8 +1,8 @@
1TEST_PROGS := tm-resched-dscr tm-syscall 1TEST_PROGS := tm-resched-dscr tm-syscall tm-signal-msr-resv tm-signal-stack tm-vmxcopy
2 2
3all: $(TEST_PROGS) 3all: $(TEST_PROGS)
4 4
5$(TEST_PROGS): ../harness.c 5$(TEST_PROGS): ../harness.c ../utils.c
6 6
7tm-syscall: tm-syscall-asm.S 7tm-syscall: tm-syscall-asm.S
8tm-syscall: CFLAGS += -mhtm -I../../../../../usr/include 8tm-syscall: CFLAGS += -mhtm -I../../../../../usr/include
diff --git a/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c b/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c
index 42d4c8caad81..8fde93d6021f 100644
--- a/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c
+++ b/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c
@@ -29,6 +29,7 @@
29#include <asm/tm.h> 29#include <asm/tm.h>
30 30
31#include "utils.h" 31#include "utils.h"
32#include "tm.h"
32 33
33#define TBEGIN ".long 0x7C00051D ;" 34#define TBEGIN ".long 0x7C00051D ;"
34#define TEND ".long 0x7C00055D ;" 35#define TEND ".long 0x7C00055D ;"
@@ -42,6 +43,8 @@ int test_body(void)
42{ 43{
43 uint64_t rv, dscr1 = 1, dscr2, texasr; 44 uint64_t rv, dscr1 = 1, dscr2, texasr;
44 45
46 SKIP_IF(!have_htm());
47
45 printf("Check DSCR TM context switch: "); 48 printf("Check DSCR TM context switch: ");
46 fflush(stdout); 49 fflush(stdout);
47 for (;;) { 50 for (;;) {
diff --git a/tools/testing/selftests/powerpc/tm/tm-signal-msr-resv.c b/tools/testing/selftests/powerpc/tm/tm-signal-msr-resv.c
new file mode 100644
index 000000000000..d86653f282b1
--- /dev/null
+++ b/tools/testing/selftests/powerpc/tm/tm-signal-msr-resv.c
@@ -0,0 +1,74 @@
1/*
2 * Copyright 2015, Michael Neuling, IBM Corp.
3 * Licensed under GPLv2.
4 *
5 * Test the kernel's signal return code to ensure that it doesn't
6 * crash when both the transactional and suspend MSR bits are set in
7 * the signal context.
8 *
9 * For this test, we send ourselves a SIGUSR1. In the SIGUSR1 handler
10 * we modify the signal context to set both MSR TM S and T bits (which
11 * is "reserved" by the PowerISA). When we return from the signal
12 * handler (implicit sigreturn), the kernel should detect reserved MSR
13 * value and send us with a SIGSEGV.
14 */
15
16#include <stdlib.h>
17#include <stdio.h>
18#include <signal.h>
19#include <unistd.h>
20
21#include "utils.h"
22#include "tm.h"
23
24int segv_expected = 0;
25
26void signal_segv(int signum)
27{
28 if (segv_expected && (signum == SIGSEGV))
29 _exit(0);
30 _exit(1);
31}
32
33void signal_usr1(int signum, siginfo_t *info, void *uc)
34{
35 ucontext_t *ucp = uc;
36
37 /* Link tm checkpointed context to normal context */
38 ucp->uc_link = ucp;
39 /* Set all TM bits so that the context is now invalid */
40#ifdef __powerpc64__
41 ucp->uc_mcontext.gp_regs[PT_MSR] |= (7ULL << 32);
42#else
43 ucp->uc_mcontext.regs->gpr[PT_MSR] |= (7ULL);
44#endif
45 /* Should segv on return becuase of invalid context */
46 segv_expected = 1;
47}
48
49int tm_signal_msr_resv()
50{
51 struct sigaction act;
52
53 SKIP_IF(!have_htm());
54
55 act.sa_sigaction = signal_usr1;
56 sigemptyset(&act.sa_mask);
57 act.sa_flags = SA_SIGINFO;
58 if (sigaction(SIGUSR1, &act, NULL) < 0) {
59 perror("sigaction sigusr1");
60 exit(1);
61 }
62 if (signal(SIGSEGV, signal_segv) == SIG_ERR)
63 exit(1);
64
65 raise(SIGUSR1);
66
67 /* We shouldn't get here as we exit in the segv handler */
68 return 1;
69}
70
71int main(void)
72{
73 return test_harness(tm_signal_msr_resv, "tm_signal_msr_resv");
74}
diff --git a/tools/testing/selftests/powerpc/tm/tm-signal-stack.c b/tools/testing/selftests/powerpc/tm/tm-signal-stack.c
new file mode 100644
index 000000000000..e44a238c1d77
--- /dev/null
+++ b/tools/testing/selftests/powerpc/tm/tm-signal-stack.c
@@ -0,0 +1,76 @@
1/*
2 * Copyright 2015, Michael Neuling, IBM Corp.
3 * Licensed under GPLv2.
4 *
5 * Test the kernel's signal delievery code to ensure that we don't
6 * trelaim twice in the kernel signal delivery code. This can happen
7 * if we trigger a signal when in a transaction and the stack pointer
8 * is bogus.
9 *
10 * This test case registers a SEGV handler, sets the stack pointer
11 * (r1) to NULL, starts a transaction and then generates a SEGV. The
12 * SEGV should be handled but we exit here as the stack pointer is
13 * invalid and hance we can't sigreturn. We only need to check that
14 * this flow doesn't crash the kernel.
15 */
16
17#include <unistd.h>
18#include <sys/types.h>
19#include <sys/wait.h>
20#include <stdlib.h>
21#include <stdio.h>
22#include <signal.h>
23
24#include "utils.h"
25#include "tm.h"
26
27void signal_segv(int signum)
28{
29 /* This should never actually run since stack is foobar */
30 exit(1);
31}
32
33int tm_signal_stack()
34{
35 int pid;
36
37 SKIP_IF(!have_htm());
38
39 pid = fork();
40 if (pid < 0)
41 exit(1);
42
43 if (pid) { /* Parent */
44 /*
45 * It's likely the whole machine will crash here so if
46 * the child ever exits, we are good.
47 */
48 wait(NULL);
49 return 0;
50 }
51
52 /*
53 * The flow here is:
54 * 1) register a signal handler (so signal delievery occurs)
55 * 2) make stack pointer (r1) = NULL
56 * 3) start transaction
57 * 4) cause segv
58 */
59 if (signal(SIGSEGV, signal_segv) == SIG_ERR)
60 exit(1);
61 asm volatile("li 1, 0 ;" /* stack ptr == NULL */
62 "1:"
63 ".long 0x7C00051D ;" /* tbegin */
64 "beq 1b ;" /* retry forever */
65 ".long 0x7C0005DD ; ;" /* tsuspend */
66 "ld 2, 0(1) ;" /* trigger segv" */
67 : : : "memory");
68
69 /* This should never get here due to above segv */
70 return 1;
71}
72
73int main(void)
74{
75 return test_harness(tm_signal_stack, "tm_signal_stack");
76}
diff --git a/tools/testing/selftests/powerpc/tm/tm-syscall.c b/tools/testing/selftests/powerpc/tm/tm-syscall.c
index e835bf7ec7ae..60560cb20e38 100644
--- a/tools/testing/selftests/powerpc/tm/tm-syscall.c
+++ b/tools/testing/selftests/powerpc/tm/tm-syscall.c
@@ -13,12 +13,11 @@
13#include <unistd.h> 13#include <unistd.h>
14#include <sys/syscall.h> 14#include <sys/syscall.h>
15#include <asm/tm.h> 15#include <asm/tm.h>
16#include <asm/cputable.h>
17#include <linux/auxvec.h>
18#include <sys/time.h> 16#include <sys/time.h>
19#include <stdlib.h> 17#include <stdlib.h>
20 18
21#include "utils.h" 19#include "utils.h"
20#include "tm.h"
22 21
23extern int getppid_tm_active(void); 22extern int getppid_tm_active(void);
24extern int getppid_tm_suspended(void); 23extern int getppid_tm_suspended(void);
@@ -77,16 +76,6 @@ pid_t getppid_tm(bool suspend)
77 exit(-1); 76 exit(-1);
78} 77}
79 78
80static inline bool have_htm_nosc(void)
81{
82#ifdef PPC_FEATURE2_HTM_NOSC
83 return ((long)get_auxv_entry(AT_HWCAP2) & PPC_FEATURE2_HTM_NOSC);
84#else
85 printf("PPC_FEATURE2_HTM_NOSC not defined, can't check AT_HWCAP2\n");
86 return false;
87#endif
88}
89
90int tm_syscall(void) 79int tm_syscall(void)
91{ 80{
92 unsigned count = 0; 81 unsigned count = 0;
diff --git a/tools/testing/selftests/powerpc/tm/tm-vmxcopy.c b/tools/testing/selftests/powerpc/tm/tm-vmxcopy.c
new file mode 100644
index 000000000000..0274de7b11f3
--- /dev/null
+++ b/tools/testing/selftests/powerpc/tm/tm-vmxcopy.c
@@ -0,0 +1,103 @@
1/*
2 * Copyright 2015, Michael Neuling, IBM Corp.
3 * Licensed under GPLv2.
4 *
5 * Original: Michael Neuling 4/12/2013
6 * Edited: Rashmica Gupta 4/12/2015
7 *
8 * See if the altivec state is leaked out of an aborted transaction due to
9 * kernel vmx copy loops.
10 *
11 * When the transaction aborts, VSR values should rollback to the values
12 * they held before the transaction commenced. Using VSRs while transaction
13 * is suspended should not affect the checkpointed values.
14 *
15 * (1) write A to a VSR
16 * (2) start transaction
17 * (3) suspend transaction
18 * (4) change the VSR to B
19 * (5) trigger kernel vmx copy loop
20 * (6) abort transaction
21 * (7) check that the VSR value is A
22 */
23
24#include <inttypes.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <unistd.h>
28#include <sys/mman.h>
29#include <string.h>
30#include <assert.h>
31
32#include "tm.h"
33#include "utils.h"
34
35int test_vmxcopy()
36{
37 long double vecin = 1.3;
38 long double vecout;
39 unsigned long pgsize = getpagesize();
40 int i;
41 int fd;
42 int size = pgsize*16;
43 char tmpfile[] = "/tmp/page_faultXXXXXX";
44 char buf[pgsize];
45 char *a;
46 uint64_t aborted = 0;
47
48 SKIP_IF(!have_htm());
49
50 fd = mkstemp(tmpfile);
51 assert(fd >= 0);
52
53 memset(buf, 0, pgsize);
54 for (i = 0; i < size; i += pgsize)
55 assert(write(fd, buf, pgsize) == pgsize);
56
57 unlink(tmpfile);
58
59 a = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
60 assert(a != MAP_FAILED);
61
62 asm __volatile__(
63 "lxvd2x 40,0,%[vecinptr];" /* set 40 to initial value*/
64 "tbegin.;"
65 "beq 3f;"
66 "tsuspend.;"
67 "xxlxor 40,40,40;" /* set 40 to 0 */
68 "std 5, 0(%[map]);" /* cause kernel vmx copy page */
69 "tabort. 0;"
70 "tresume.;"
71 "tend.;"
72 "li %[res], 0;"
73 "b 5f;"
74
75 /* Abort handler */
76 "3:;"
77 "li %[res], 1;"
78
79 "5:;"
80 "stxvd2x 40,0,%[vecoutptr];"
81 : [res]"=r"(aborted)
82 : [vecinptr]"r"(&vecin),
83 [vecoutptr]"r"(&vecout),
84 [map]"r"(a)
85 : "memory", "r0", "r3", "r4", "r5", "r6", "r7");
86
87 if (aborted && (vecin != vecout)){
88 printf("FAILED: vector state leaked on abort %f != %f\n",
89 (double)vecin, (double)vecout);
90 return 1;
91 }
92
93 munmap(a, size);
94
95 close(fd);
96
97 return 0;
98}
99
100int main(void)
101{
102 return test_harness(test_vmxcopy, "tm_vmxcopy");
103}
diff --git a/tools/testing/selftests/powerpc/tm/tm.h b/tools/testing/selftests/powerpc/tm/tm.h
new file mode 100644
index 000000000000..24144b25772c
--- /dev/null
+++ b/tools/testing/selftests/powerpc/tm/tm.h
@@ -0,0 +1,34 @@
1/*
2 * Copyright 2015, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#ifndef _SELFTESTS_POWERPC_TM_TM_H
7#define _SELFTESTS_POWERPC_TM_TM_H
8
9#include <stdbool.h>
10#include <asm/cputable.h>
11
12#include "../utils.h"
13
14static inline bool have_htm(void)
15{
16#ifdef PPC_FEATURE2_HTM
17 return have_hwcap2(PPC_FEATURE2_HTM);
18#else
19 printf("PPC_FEATURE2_HTM not defined, can't check AT_HWCAP2\n");
20 return false;
21#endif
22}
23
24static inline bool have_htm_nosc(void)
25{
26#ifdef PPC_FEATURE2_HTM_NOSC
27 return have_hwcap2(PPC_FEATURE2_HTM_NOSC);
28#else
29 printf("PPC_FEATURE2_HTM_NOSC not defined, can't check AT_HWCAP2\n");
30 return false;
31#endif
32}
33
34#endif /* _SELFTESTS_POWERPC_TM_TM_H */
diff --git a/tools/testing/selftests/powerpc/utils.c b/tools/testing/selftests/powerpc/utils.c
new file mode 100644
index 000000000000..dcf74184bfd0
--- /dev/null
+++ b/tools/testing/selftests/powerpc/utils.c
@@ -0,0 +1,87 @@
1/*
2 * Copyright 2013-2015, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#define _GNU_SOURCE /* For CPU_ZERO etc. */
7
8#include <elf.h>
9#include <errno.h>
10#include <fcntl.h>
11#include <link.h>
12#include <sched.h>
13#include <stdio.h>
14#include <sys/stat.h>
15#include <sys/types.h>
16#include <unistd.h>
17
18#include "utils.h"
19
20static char auxv[4096];
21
22void *get_auxv_entry(int type)
23{
24 ElfW(auxv_t) *p;
25 void *result;
26 ssize_t num;
27 int fd;
28
29 fd = open("/proc/self/auxv", O_RDONLY);
30 if (fd == -1) {
31 perror("open");
32 return NULL;
33 }
34
35 result = NULL;
36
37 num = read(fd, auxv, sizeof(auxv));
38 if (num < 0) {
39 perror("read");
40 goto out;
41 }
42
43 if (num > sizeof(auxv)) {
44 printf("Overflowed auxv buffer\n");
45 goto out;
46 }
47
48 p = (ElfW(auxv_t) *)auxv;
49
50 while (p->a_type != AT_NULL) {
51 if (p->a_type == type) {
52 result = (void *)p->a_un.a_val;
53 break;
54 }
55
56 p++;
57 }
58out:
59 close(fd);
60 return result;
61}
62
63int pick_online_cpu(void)
64{
65 cpu_set_t mask;
66 int cpu;
67
68 CPU_ZERO(&mask);
69
70 if (sched_getaffinity(0, sizeof(mask), &mask)) {
71 perror("sched_getaffinity");
72 return -1;
73 }
74
75 /* We prefer a primary thread, but skip 0 */
76 for (cpu = 8; cpu < CPU_SETSIZE; cpu += 8)
77 if (CPU_ISSET(cpu, &mask))
78 return cpu;
79
80 /* Search for anything, but in reverse */
81 for (cpu = CPU_SETSIZE - 1; cpu >= 0; cpu--)
82 if (CPU_ISSET(cpu, &mask))
83 return cpu;
84
85 printf("No cpus in affinity mask?!\n");
86 return -1;
87}
diff --git a/tools/testing/selftests/powerpc/utils.h b/tools/testing/selftests/powerpc/utils.h
index b7d41086bb0a..175ac6ad10dd 100644
--- a/tools/testing/selftests/powerpc/utils.h
+++ b/tools/testing/selftests/powerpc/utils.h
@@ -8,6 +8,7 @@
8 8
9#include <stdint.h> 9#include <stdint.h>
10#include <stdbool.h> 10#include <stdbool.h>
11#include <linux/auxvec.h>
11 12
12/* Avoid headaches with PRI?64 - just use %ll? always */ 13/* Avoid headaches with PRI?64 - just use %ll? always */
13typedef unsigned long long u64; 14typedef unsigned long long u64;
@@ -21,6 +22,12 @@ typedef uint8_t u8;
21 22
22int test_harness(int (test_function)(void), char *name); 23int test_harness(int (test_function)(void), char *name);
23extern void *get_auxv_entry(int type); 24extern void *get_auxv_entry(int type);
25int pick_online_cpu(void);
26
27static inline bool have_hwcap2(unsigned long ftr2)
28{
29 return ((unsigned long)get_auxv_entry(AT_HWCAP2) & ftr2) == ftr2;
30}
24 31
25/* Yes, this is evil */ 32/* Yes, this is evil */
26#define FAIL_IF(x) \ 33#define FAIL_IF(x) \
diff --git a/tools/testing/selftests/ptrace/.gitignore b/tools/testing/selftests/ptrace/.gitignore
new file mode 100644
index 000000000000..b3e59d41fd82
--- /dev/null
+++ b/tools/testing/selftests/ptrace/.gitignore
@@ -0,0 +1 @@
peeksiginfo
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh
index 5236e073919d..0f80eefb0bfd 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh
@@ -38,8 +38,6 @@
38# 38#
39# Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com> 39# Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
40 40
41grace=120
42
43T=/tmp/kvm-test-1-run.sh.$$ 41T=/tmp/kvm-test-1-run.sh.$$
44trap 'rm -rf $T' 0 42trap 'rm -rf $T' 0
45touch $T 43touch $T
@@ -152,7 +150,7 @@ fi
152qemu_args="`specify_qemu_cpus "$QEMU" "$qemu_args" "$cpu_count"`" 150qemu_args="`specify_qemu_cpus "$QEMU" "$qemu_args" "$cpu_count"`"
153 151
154# Generate architecture-specific and interaction-specific qemu arguments 152# Generate architecture-specific and interaction-specific qemu arguments
155qemu_args="$qemu_args `identify_qemu_args "$QEMU" "$builddir/console.log"`" 153qemu_args="$qemu_args `identify_qemu_args "$QEMU" "$resdir/console.log"`"
156 154
157# Generate qemu -append arguments 155# Generate qemu -append arguments
158qemu_append="`identify_qemu_append "$QEMU"`" 156qemu_append="`identify_qemu_append "$QEMU"`"
@@ -168,7 +166,7 @@ then
168 touch $resdir/buildonly 166 touch $resdir/buildonly
169 exit 0 167 exit 0
170fi 168fi
171echo "NOTE: $QEMU either did not run or was interactive" > $builddir/console.log 169echo "NOTE: $QEMU either did not run or was interactive" > $resdir/console.log
172echo $QEMU $qemu_args -m 512 -kernel $resdir/bzImage -append \"$qemu_append $boot_args\" > $resdir/qemu-cmd 170echo $QEMU $qemu_args -m 512 -kernel $resdir/bzImage -append \"$qemu_append $boot_args\" > $resdir/qemu-cmd
173( $QEMU $qemu_args -m 512 -kernel $resdir/bzImage -append "$qemu_append $boot_args"; echo $? > $resdir/qemu-retval ) & 171( $QEMU $qemu_args -m 512 -kernel $resdir/bzImage -append "$qemu_append $boot_args"; echo $? > $resdir/qemu-retval ) &
174qemu_pid=$! 172qemu_pid=$!
@@ -214,7 +212,7 @@ then
214 else 212 else
215 break 213 break
216 fi 214 fi
217 if test $kruntime -ge $((seconds + grace)) 215 if test $kruntime -ge $((seconds + $TORTURE_SHUTDOWN_GRACE))
218 then 216 then
219 echo "!!! PID $qemu_pid hung at $kruntime vs. $seconds seconds" >> $resdir/Warnings 2>&1 217 echo "!!! PID $qemu_pid hung at $kruntime vs. $seconds seconds" >> $resdir/Warnings 2>&1
220 kill -KILL $qemu_pid 218 kill -KILL $qemu_pid
@@ -224,6 +222,5 @@ then
224 done 222 done
225fi 223fi
226 224
227cp $builddir/console.log $resdir
228parse-torture.sh $resdir/console.log $title 225parse-torture.sh $resdir/console.log $title
229parse-console.sh $resdir/console.log $title 226parse-console.sh $resdir/console.log $title
diff --git a/tools/testing/selftests/rcutorture/bin/kvm.sh b/tools/testing/selftests/rcutorture/bin/kvm.sh
index f6483609ebc2..4a431767f77a 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm.sh
@@ -42,6 +42,7 @@ TORTURE_DEFCONFIG=defconfig
42TORTURE_BOOT_IMAGE="" 42TORTURE_BOOT_IMAGE=""
43TORTURE_INITRD="$KVM/initrd"; export TORTURE_INITRD 43TORTURE_INITRD="$KVM/initrd"; export TORTURE_INITRD
44TORTURE_KMAKE_ARG="" 44TORTURE_KMAKE_ARG=""
45TORTURE_SHUTDOWN_GRACE=180
45TORTURE_SUITE=rcu 46TORTURE_SUITE=rcu
46resdir="" 47resdir=""
47configs="" 48configs=""
@@ -149,6 +150,11 @@ do
149 resdir=$2 150 resdir=$2
150 shift 151 shift
151 ;; 152 ;;
153 --shutdown-grace)
154 checkarg --shutdown-grace "(seconds)" "$#" "$2" '^[0-9]*$' '^error'
155 TORTURE_SHUTDOWN_GRACE=$2
156 shift
157 ;;
152 --torture) 158 --torture)
153 checkarg --torture "(suite name)" "$#" "$2" '^\(lock\|rcu\)$' '^--' 159 checkarg --torture "(suite name)" "$#" "$2" '^\(lock\|rcu\)$' '^--'
154 TORTURE_SUITE=$2 160 TORTURE_SUITE=$2
@@ -266,6 +272,7 @@ TORTURE_KMAKE_ARG="$TORTURE_KMAKE_ARG"; export TORTURE_KMAKE_ARG
266TORTURE_QEMU_CMD="$TORTURE_QEMU_CMD"; export TORTURE_QEMU_CMD 272TORTURE_QEMU_CMD="$TORTURE_QEMU_CMD"; export TORTURE_QEMU_CMD
267TORTURE_QEMU_INTERACTIVE="$TORTURE_QEMU_INTERACTIVE"; export TORTURE_QEMU_INTERACTIVE 273TORTURE_QEMU_INTERACTIVE="$TORTURE_QEMU_INTERACTIVE"; export TORTURE_QEMU_INTERACTIVE
268TORTURE_QEMU_MAC="$TORTURE_QEMU_MAC"; export TORTURE_QEMU_MAC 274TORTURE_QEMU_MAC="$TORTURE_QEMU_MAC"; export TORTURE_QEMU_MAC
275TORTURE_SHUTDOWN_GRACE="$TORTURE_SHUTDOWN_GRACE"; export TORTURE_SHUTDOWN_GRACE
269TORTURE_SUITE="$TORTURE_SUITE"; export TORTURE_SUITE 276TORTURE_SUITE="$TORTURE_SUITE"; export TORTURE_SUITE
270if ! test -e $resdir 277if ! test -e $resdir
271then 278then
@@ -307,10 +314,10 @@ awk < $T/cfgcpu.pack \
307} 314}
308 315
309# Dump out the scripting required to run one test batch. 316# Dump out the scripting required to run one test batch.
310function dump(first, pastlast) 317function dump(first, pastlast, batchnum)
311{ 318{
312 print "echo ----Start batch: `date`"; 319 print "echo ----Start batch " batchnum ": `date`";
313 print "echo ----Start batch: `date` >> " rd "/log"; 320 print "echo ----Start batch " batchnum ": `date` >> " rd "/log";
314 jn=1 321 jn=1
315 for (j = first; j < pastlast; j++) { 322 for (j = first; j < pastlast; j++) {
316 builddir=KVM "/b" jn 323 builddir=KVM "/b" jn
@@ -371,25 +378,28 @@ END {
371 njobs = i; 378 njobs = i;
372 nc = ncpus; 379 nc = ncpus;
373 first = 0; 380 first = 0;
381 batchnum = 1;
374 382
375 # Each pass through the following loop considers one test. 383 # Each pass through the following loop considers one test.
376 for (i = 0; i < njobs; i++) { 384 for (i = 0; i < njobs; i++) {
377 if (ncpus == 0) { 385 if (ncpus == 0) {
378 # Sequential test specified, each test its own batch. 386 # Sequential test specified, each test its own batch.
379 dump(i, i + 1); 387 dump(i, i + 1, batchnum);
380 first = i; 388 first = i;
389 batchnum++;
381 } else if (nc < cpus[i] && i != 0) { 390 } else if (nc < cpus[i] && i != 0) {
382 # Out of CPUs, dump out a batch. 391 # Out of CPUs, dump out a batch.
383 dump(first, i); 392 dump(first, i, batchnum);
384 first = i; 393 first = i;
385 nc = ncpus; 394 nc = ncpus;
395 batchnum++;
386 } 396 }
387 # Account for the CPUs needed by the current test. 397 # Account for the CPUs needed by the current test.
388 nc -= cpus[i]; 398 nc -= cpus[i];
389 } 399 }
390 # Dump the last batch. 400 # Dump the last batch.
391 if (ncpus != 0) 401 if (ncpus != 0)
392 dump(first, i); 402 dump(first, i, batchnum);
393}' >> $T/script 403}' >> $T/script
394 404
395cat << ___EOF___ >> $T/script 405cat << ___EOF___ >> $T/script
diff --git a/tools/testing/selftests/rcutorture/bin/parse-console.sh b/tools/testing/selftests/rcutorture/bin/parse-console.sh
index d8f35cf116be..844787a0d7be 100755
--- a/tools/testing/selftests/rcutorture/bin/parse-console.sh
+++ b/tools/testing/selftests/rcutorture/bin/parse-console.sh
@@ -24,9 +24,6 @@
24# 24#
25# Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com> 25# Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
26 26
27T=/tmp/abat-chk-badness.sh.$$
28trap 'rm -f $T' 0
29
30file="$1" 27file="$1"
31title="$2" 28title="$2"
32 29
@@ -36,9 +33,41 @@ if grep -Pq '\x00' < $file
36then 33then
37 print_warning Console output contains nul bytes, old qemu still running? 34 print_warning Console output contains nul bytes, old qemu still running?
38fi 35fi
39egrep 'Badness|WARNING:|Warn|BUG|===========|Call Trace:|Oops:|Stall ended before state dump start' < $file | grep -v 'ODEBUG: ' | grep -v 'Warning: unable to open an initial console' > $T 36egrep 'Badness|WARNING:|Warn|BUG|===========|Call Trace:|Oops:|detected stalls on CPUs/tasks:|Stall ended before state dump start' < $file | grep -v 'ODEBUG: ' | grep -v 'Warning: unable to open an initial console' > $1.diags
40if test -s $T 37if test -s $1.diags
41then 38then
42 print_warning Assertion failure in $file $title 39 print_warning Assertion failure in $file $title
43 cat $T 40 # cat $1.diags
41 summary=""
42 n_badness=`grep -c Badness $1`
43 if test "$n_badness" -ne 0
44 then
45 summary="$summary Badness: $n_badness"
46 fi
47 n_warn=`grep -v 'Warning: unable to open an initial console' $1 | egrep -c 'WARNING:|Warn'`
48 if test "$n_warn" -ne 0
49 then
50 summary="$summary Warnings: $n_warn"
51 fi
52 n_bugs=`egrep -c 'BUG|Oops:' $1`
53 if test "$n_bugs" -ne 0
54 then
55 summary="$summary Bugs: $n_bugs"
56 fi
57 n_calltrace=`grep -c 'Call Trace:' $1`
58 if test "$n_calltrace" -ne 0
59 then
60 summary="$summary Call Traces: $n_calltrace"
61 fi
62 n_lockdep=`grep -c =========== $1`
63 if test "$n_badness" -ne 0
64 then
65 summary="$summary lockdep: $n_badness"
66 fi
67 n_stalls=`egrep -c 'detected stalls on CPUs/tasks:|Stall ended before state dump start' $1`
68 if test "$n_stalls" -ne 0
69 then
70 summary="$summary Stalls: $n_stalls"
71 fi
72 print_warning Summary: $summary
44fi 73fi
diff --git a/tools/testing/selftests/rcutorture/doc/TINY_RCU.txt b/tools/testing/selftests/rcutorture/doc/TINY_RCU.txt
index 9ef33a743b73..24396ae8355b 100644
--- a/tools/testing/selftests/rcutorture/doc/TINY_RCU.txt
+++ b/tools/testing/selftests/rcutorture/doc/TINY_RCU.txt
@@ -20,7 +20,6 @@ CONFIG_PROVE_RCU
20 20
21CONFIG_NO_HZ_FULL_SYSIDLE 21CONFIG_NO_HZ_FULL_SYSIDLE
22CONFIG_RCU_NOCB_CPU 22CONFIG_RCU_NOCB_CPU
23CONFIG_RCU_USER_QS
24 23
25 Meaningless for TINY_RCU. 24 Meaningless for TINY_RCU.
26 25
diff --git a/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt b/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt
index 657f3a035488..4e2b1893d40d 100644
--- a/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt
+++ b/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt
@@ -72,10 +72,6 @@ CONFIG_RCU_TORTURE_TEST_RUNNABLE
72 72
73 Always used in KVM testing. 73 Always used in KVM testing.
74 74
75CONFIG_RCU_USER_QS
76
77 Redundant with CONFIG_NO_HZ_FULL.
78
79CONFIG_PREEMPT_RCU 75CONFIG_PREEMPT_RCU
80CONFIG_TREE_RCU 76CONFIG_TREE_RCU
81 77
diff --git a/tools/testing/selftests/seccomp/seccomp_bpf.c b/tools/testing/selftests/seccomp/seccomp_bpf.c
index e38cc54942db..b9453b838162 100644
--- a/tools/testing/selftests/seccomp/seccomp_bpf.c
+++ b/tools/testing/selftests/seccomp/seccomp_bpf.c
@@ -492,6 +492,9 @@ TEST_SIGNAL(KILL_one_arg_six, SIGSYS)
492 pid_t parent = getppid(); 492 pid_t parent = getppid();
493 int fd; 493 int fd;
494 void *map1, *map2; 494 void *map1, *map2;
495 int page_size = sysconf(_SC_PAGESIZE);
496
497 ASSERT_LT(0, page_size);
495 498
496 ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); 499 ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
497 ASSERT_EQ(0, ret); 500 ASSERT_EQ(0, ret);
@@ -504,16 +507,16 @@ TEST_SIGNAL(KILL_one_arg_six, SIGSYS)
504 507
505 EXPECT_EQ(parent, syscall(__NR_getppid)); 508 EXPECT_EQ(parent, syscall(__NR_getppid));
506 map1 = (void *)syscall(sysno, 509 map1 = (void *)syscall(sysno,
507 NULL, PAGE_SIZE, PROT_READ, MAP_PRIVATE, fd, PAGE_SIZE); 510 NULL, page_size, PROT_READ, MAP_PRIVATE, fd, page_size);
508 EXPECT_NE(MAP_FAILED, map1); 511 EXPECT_NE(MAP_FAILED, map1);
509 /* mmap2() should never return. */ 512 /* mmap2() should never return. */
510 map2 = (void *)syscall(sysno, 513 map2 = (void *)syscall(sysno,
511 NULL, PAGE_SIZE, PROT_READ, MAP_PRIVATE, fd, 0x0C0FFEE); 514 NULL, page_size, PROT_READ, MAP_PRIVATE, fd, 0x0C0FFEE);
512 EXPECT_EQ(MAP_FAILED, map2); 515 EXPECT_EQ(MAP_FAILED, map2);
513 516
514 /* The test failed, so clean up the resources. */ 517 /* The test failed, so clean up the resources. */
515 munmap(map1, PAGE_SIZE); 518 munmap(map1, page_size);
516 munmap(map2, PAGE_SIZE); 519 munmap(map2, page_size);
517 close(fd); 520 close(fd);
518} 521}
519 522
@@ -1243,11 +1246,24 @@ TEST_F(TRACE_poke, getpid_runs_normally)
1243# error "Do not know how to find your architecture's registers and syscalls" 1246# error "Do not know how to find your architecture's registers and syscalls"
1244#endif 1247#endif
1245 1248
1249/* Use PTRACE_GETREGS and PTRACE_SETREGS when available. This is useful for
1250 * architectures without HAVE_ARCH_TRACEHOOK (e.g. User-mode Linux).
1251 */
1252#if defined(__x86_64__) || defined(__i386__)
1253#define HAVE_GETREGS
1254#endif
1255
1246/* Architecture-specific syscall fetching routine. */ 1256/* Architecture-specific syscall fetching routine. */
1247int get_syscall(struct __test_metadata *_metadata, pid_t tracee) 1257int get_syscall(struct __test_metadata *_metadata, pid_t tracee)
1248{ 1258{
1249 struct iovec iov;
1250 ARCH_REGS regs; 1259 ARCH_REGS regs;
1260#ifdef HAVE_GETREGS
1261 EXPECT_EQ(0, ptrace(PTRACE_GETREGS, tracee, 0, &regs)) {
1262 TH_LOG("PTRACE_GETREGS failed");
1263 return -1;
1264 }
1265#else
1266 struct iovec iov;
1251 1267
1252 iov.iov_base = &regs; 1268 iov.iov_base = &regs;
1253 iov.iov_len = sizeof(regs); 1269 iov.iov_len = sizeof(regs);
@@ -1255,6 +1271,7 @@ int get_syscall(struct __test_metadata *_metadata, pid_t tracee)
1255 TH_LOG("PTRACE_GETREGSET failed"); 1271 TH_LOG("PTRACE_GETREGSET failed");
1256 return -1; 1272 return -1;
1257 } 1273 }
1274#endif
1258 1275
1259 return regs.SYSCALL_NUM; 1276 return regs.SYSCALL_NUM;
1260} 1277}
@@ -1263,13 +1280,16 @@ int get_syscall(struct __test_metadata *_metadata, pid_t tracee)
1263void change_syscall(struct __test_metadata *_metadata, 1280void change_syscall(struct __test_metadata *_metadata,
1264 pid_t tracee, int syscall) 1281 pid_t tracee, int syscall)
1265{ 1282{
1266 struct iovec iov;
1267 int ret; 1283 int ret;
1268 ARCH_REGS regs; 1284 ARCH_REGS regs;
1269 1285#ifdef HAVE_GETREGS
1286 ret = ptrace(PTRACE_GETREGS, tracee, 0, &regs);
1287#else
1288 struct iovec iov;
1270 iov.iov_base = &regs; 1289 iov.iov_base = &regs;
1271 iov.iov_len = sizeof(regs); 1290 iov.iov_len = sizeof(regs);
1272 ret = ptrace(PTRACE_GETREGSET, tracee, NT_PRSTATUS, &iov); 1291 ret = ptrace(PTRACE_GETREGSET, tracee, NT_PRSTATUS, &iov);
1292#endif
1273 EXPECT_EQ(0, ret); 1293 EXPECT_EQ(0, ret);
1274 1294
1275#if defined(__x86_64__) || defined(__i386__) || defined(__powerpc__) || \ 1295#if defined(__x86_64__) || defined(__i386__) || defined(__powerpc__) || \
@@ -1309,9 +1329,13 @@ void change_syscall(struct __test_metadata *_metadata,
1309 if (syscall == -1) 1329 if (syscall == -1)
1310 regs.SYSCALL_RET = 1; 1330 regs.SYSCALL_RET = 1;
1311 1331
1332#ifdef HAVE_GETREGS
1333 ret = ptrace(PTRACE_SETREGS, tracee, 0, &regs);
1334#else
1312 iov.iov_base = &regs; 1335 iov.iov_base = &regs;
1313 iov.iov_len = sizeof(regs); 1336 iov.iov_len = sizeof(regs);
1314 ret = ptrace(PTRACE_SETREGSET, tracee, NT_PRSTATUS, &iov); 1337 ret = ptrace(PTRACE_SETREGSET, tracee, NT_PRSTATUS, &iov);
1338#endif
1315 EXPECT_EQ(0, ret); 1339 EXPECT_EQ(0, ret);
1316} 1340}
1317 1341
diff --git a/tools/testing/selftests/seccomp/test_harness.h b/tools/testing/selftests/seccomp/test_harness.h
index fb2841601f2f..a786c69c7584 100644
--- a/tools/testing/selftests/seccomp/test_harness.h
+++ b/tools/testing/selftests/seccomp/test_harness.h
@@ -42,6 +42,7 @@
42#define TEST_HARNESS_H_ 42#define TEST_HARNESS_H_
43 43
44#define _GNU_SOURCE 44#define _GNU_SOURCE
45#include <stdint.h>
45#include <stdio.h> 46#include <stdio.h>
46#include <stdlib.h> 47#include <stdlib.h>
47#include <string.h> 48#include <string.h>
@@ -370,8 +371,8 @@
370 __typeof__(_expected) __exp = (_expected); \ 371 __typeof__(_expected) __exp = (_expected); \
371 __typeof__(_seen) __seen = (_seen); \ 372 __typeof__(_seen) __seen = (_seen); \
372 if (!(__exp _t __seen)) { \ 373 if (!(__exp _t __seen)) { \
373 unsigned long long __exp_print = (unsigned long long)__exp; \ 374 unsigned long long __exp_print = (uintptr_t)__exp; \
374 unsigned long long __seen_print = (unsigned long long)__seen; \ 375 unsigned long long __seen_print = (uintptr_t)__seen; \
375 __TH_LOG("Expected %s (%llu) %s %s (%llu)", \ 376 __TH_LOG("Expected %s (%llu) %s %s (%llu)", \
376 #_expected, __exp_print, #_t, \ 377 #_expected, __exp_print, #_t, \
377 #_seen, __seen_print); \ 378 #_seen, __seen_print); \
diff --git a/tools/testing/selftests/timers/.gitignore b/tools/testing/selftests/timers/.gitignore
index ced998151bc4..68f3fc71ac44 100644
--- a/tools/testing/selftests/timers/.gitignore
+++ b/tools/testing/selftests/timers/.gitignore
@@ -16,3 +16,4 @@ set-timer-lat
16skew_consistency 16skew_consistency
17threadtest 17threadtest
18valid-adjtimex 18valid-adjtimex
19adjtick
diff --git a/tools/testing/selftests/timers/clocksource-switch.c b/tools/testing/selftests/timers/clocksource-switch.c
index 627ec7425f78..fd88e3025bed 100644
--- a/tools/testing/selftests/timers/clocksource-switch.c
+++ b/tools/testing/selftests/timers/clocksource-switch.c
@@ -97,7 +97,7 @@ int get_cur_clocksource(char *buf, size_t size)
97int change_clocksource(char *clocksource) 97int change_clocksource(char *clocksource)
98{ 98{
99 int fd; 99 int fd;
100 size_t size; 100 ssize_t size;
101 101
102 fd = open("/sys/devices/system/clocksource/clocksource0/current_clocksource", O_WRONLY); 102 fd = open("/sys/devices/system/clocksource/clocksource0/current_clocksource", O_WRONLY);
103 103
diff --git a/tools/testing/selftests/timers/valid-adjtimex.c b/tools/testing/selftests/timers/valid-adjtimex.c
index e86d937cc22c..60fe3c569bd9 100644
--- a/tools/testing/selftests/timers/valid-adjtimex.c
+++ b/tools/testing/selftests/timers/valid-adjtimex.c
@@ -45,7 +45,17 @@ static inline int ksft_exit_fail(void)
45} 45}
46#endif 46#endif
47 47
48#define NSEC_PER_SEC 1000000000L 48#define NSEC_PER_SEC 1000000000LL
49#define USEC_PER_SEC 1000000LL
50
51#define ADJ_SETOFFSET 0x0100
52
53#include <sys/syscall.h>
54static int clock_adjtime(clockid_t id, struct timex *tx)
55{
56 return syscall(__NR_clock_adjtime, id, tx);
57}
58
49 59
50/* clear NTP time_status & time_state */ 60/* clear NTP time_status & time_state */
51int clear_time_state(void) 61int clear_time_state(void)
@@ -193,10 +203,137 @@ out:
193} 203}
194 204
195 205
206int set_offset(long long offset, int use_nano)
207{
208 struct timex tmx = {};
209 int ret;
210
211 tmx.modes = ADJ_SETOFFSET;
212 if (use_nano) {
213 tmx.modes |= ADJ_NANO;
214
215 tmx.time.tv_sec = offset / NSEC_PER_SEC;
216 tmx.time.tv_usec = offset % NSEC_PER_SEC;
217
218 if (offset < 0 && tmx.time.tv_usec) {
219 tmx.time.tv_sec -= 1;
220 tmx.time.tv_usec += NSEC_PER_SEC;
221 }
222 } else {
223 tmx.time.tv_sec = offset / USEC_PER_SEC;
224 tmx.time.tv_usec = offset % USEC_PER_SEC;
225
226 if (offset < 0 && tmx.time.tv_usec) {
227 tmx.time.tv_sec -= 1;
228 tmx.time.tv_usec += USEC_PER_SEC;
229 }
230 }
231
232 ret = clock_adjtime(CLOCK_REALTIME, &tmx);
233 if (ret < 0) {
234 printf("(sec: %ld usec: %ld) ", tmx.time.tv_sec, tmx.time.tv_usec);
235 printf("[FAIL]\n");
236 return -1;
237 }
238 return 0;
239}
240
241int set_bad_offset(long sec, long usec, int use_nano)
242{
243 struct timex tmx = {};
244 int ret;
245
246 tmx.modes = ADJ_SETOFFSET;
247 if (use_nano)
248 tmx.modes |= ADJ_NANO;
249
250 tmx.time.tv_sec = sec;
251 tmx.time.tv_usec = usec;
252 ret = clock_adjtime(CLOCK_REALTIME, &tmx);
253 if (ret >= 0) {
254 printf("Invalid (sec: %ld usec: %ld) did not fail! ", tmx.time.tv_sec, tmx.time.tv_usec);
255 printf("[FAIL]\n");
256 return -1;
257 }
258 return 0;
259}
260
261int validate_set_offset(void)
262{
263 printf("Testing ADJ_SETOFFSET... ");
264
265 /* Test valid values */
266 if (set_offset(NSEC_PER_SEC - 1, 1))
267 return -1;
268
269 if (set_offset(-NSEC_PER_SEC + 1, 1))
270 return -1;
271
272 if (set_offset(-NSEC_PER_SEC - 1, 1))
273 return -1;
274
275 if (set_offset(5 * NSEC_PER_SEC, 1))
276 return -1;
277
278 if (set_offset(-5 * NSEC_PER_SEC, 1))
279 return -1;
280
281 if (set_offset(5 * NSEC_PER_SEC + NSEC_PER_SEC / 2, 1))
282 return -1;
283
284 if (set_offset(-5 * NSEC_PER_SEC - NSEC_PER_SEC / 2, 1))
285 return -1;
286
287 if (set_offset(USEC_PER_SEC - 1, 0))
288 return -1;
289
290 if (set_offset(-USEC_PER_SEC + 1, 0))
291 return -1;
292
293 if (set_offset(-USEC_PER_SEC - 1, 0))
294 return -1;
295
296 if (set_offset(5 * USEC_PER_SEC, 0))
297 return -1;
298
299 if (set_offset(-5 * USEC_PER_SEC, 0))
300 return -1;
301
302 if (set_offset(5 * USEC_PER_SEC + USEC_PER_SEC / 2, 0))
303 return -1;
304
305 if (set_offset(-5 * USEC_PER_SEC - USEC_PER_SEC / 2, 0))
306 return -1;
307
308 /* Test invalid values */
309 if (set_bad_offset(0, -1, 1))
310 return -1;
311 if (set_bad_offset(0, -1, 0))
312 return -1;
313 if (set_bad_offset(0, 2 * NSEC_PER_SEC, 1))
314 return -1;
315 if (set_bad_offset(0, 2 * USEC_PER_SEC, 0))
316 return -1;
317 if (set_bad_offset(0, NSEC_PER_SEC, 1))
318 return -1;
319 if (set_bad_offset(0, USEC_PER_SEC, 0))
320 return -1;
321 if (set_bad_offset(0, -NSEC_PER_SEC, 1))
322 return -1;
323 if (set_bad_offset(0, -USEC_PER_SEC, 0))
324 return -1;
325
326 printf("[OK]\n");
327 return 0;
328}
329
196int main(int argc, char **argv) 330int main(int argc, char **argv)
197{ 331{
198 if (validate_freq()) 332 if (validate_freq())
199 return ksft_exit_fail(); 333 return ksft_exit_fail();
200 334
335 if (validate_set_offset())
336 return ksft_exit_fail();
337
201 return ksft_exit_pass(); 338 return ksft_exit_pass();
202} 339}
diff --git a/tools/testing/selftests/vm/.gitignore b/tools/testing/selftests/vm/.gitignore
index ff1bb16cec4f..a937a9d26b60 100644
--- a/tools/testing/selftests/vm/.gitignore
+++ b/tools/testing/selftests/vm/.gitignore
@@ -2,3 +2,8 @@ hugepage-mmap
2hugepage-shm 2hugepage-shm
3map_hugetlb 3map_hugetlb
4thuge-gen 4thuge-gen
5compaction_test
6mlock2-tests
7on-fault-limit
8transhuge-stress
9userfaultfd
diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile
index eabcff411984..d0c473f65850 100644
--- a/tools/testing/selftests/x86/Makefile
+++ b/tools/testing/selftests/x86/Makefile
@@ -4,9 +4,11 @@ include ../lib.mk
4 4
5.PHONY: all all_32 all_64 warn_32bit_failure clean 5.PHONY: all all_32 all_64 warn_32bit_failure clean
6 6
7TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs ldt_gdt syscall_nt ptrace_syscall 7TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt ptrace_syscall
8TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault sigreturn test_syscall_vdso unwind_vdso \ 8TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault sigreturn test_syscall_vdso unwind_vdso \
9 test_FCMOV test_FCOMI test_FISTTP 9 test_FCMOV test_FCOMI test_FISTTP \
10 ldt_gdt \
11 vdso_restorer
10 12
11TARGETS_C_32BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_32BIT_ONLY) 13TARGETS_C_32BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_32BIT_ONLY)
12BINARIES_32 := $(TARGETS_C_32BIT_ALL:%=%_32) 14BINARIES_32 := $(TARGETS_C_32BIT_ALL:%=%_32)
diff --git a/tools/testing/selftests/x86/vdso_restorer.c b/tools/testing/selftests/x86/vdso_restorer.c
new file mode 100644
index 000000000000..cb038424a403
--- /dev/null
+++ b/tools/testing/selftests/x86/vdso_restorer.c
@@ -0,0 +1,88 @@
1/*
2 * vdso_restorer.c - tests vDSO-based signal restore
3 * Copyright (c) 2015 Andrew Lutomirski
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it 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
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * This makes sure that sa_restorer == NULL keeps working on 32-bit
15 * configurations. Modern glibc doesn't use it under any circumstances,
16 * so it's easy to overlook breakage.
17 *
18 * 64-bit userspace has never supported sa_restorer == NULL, so this is
19 * 32-bit only.
20 */
21
22#define _GNU_SOURCE
23
24#include <err.h>
25#include <stdio.h>
26#include <string.h>
27#include <signal.h>
28#include <unistd.h>
29#include <syscall.h>
30#include <sys/syscall.h>
31
32/* Open-code this -- the headers are too messy to easily use them. */
33struct real_sigaction {
34 void *handler;
35 unsigned long flags;
36 void *restorer;
37 unsigned int mask[2];
38};
39
40static volatile sig_atomic_t handler_called;
41
42static void handler_with_siginfo(int sig, siginfo_t *info, void *ctx_void)
43{
44 handler_called = 1;
45}
46
47static void handler_without_siginfo(int sig)
48{
49 handler_called = 1;
50}
51
52int main()
53{
54 int nerrs = 0;
55 struct real_sigaction sa;
56
57 memset(&sa, 0, sizeof(sa));
58 sa.handler = handler_with_siginfo;
59 sa.flags = SA_SIGINFO;
60 sa.restorer = NULL; /* request kernel-provided restorer */
61
62 if (syscall(SYS_rt_sigaction, SIGUSR1, &sa, NULL, 8) != 0)
63 err(1, "raw rt_sigaction syscall");
64
65 raise(SIGUSR1);
66
67 if (handler_called) {
68 printf("[OK]\tSA_SIGINFO handler returned successfully\n");
69 } else {
70 printf("[FAIL]\tSA_SIGINFO handler was not called\n");
71 nerrs++;
72 }
73
74 sa.flags = 0;
75 sa.handler = handler_without_siginfo;
76 if (syscall(SYS_sigaction, SIGUSR1, &sa, 0) != 0)
77 err(1, "raw sigaction syscall");
78 handler_called = 0;
79
80 raise(SIGUSR1);
81
82 if (handler_called) {
83 printf("[OK]\t!SA_SIGINFO handler returned successfully\n");
84 } else {
85 printf("[FAIL]\t!SA_SIGINFO handler was not called\n");
86 nerrs++;
87 }
88}
diff --git a/tools/virtio/asm/barrier.h b/tools/virtio/asm/barrier.h
index 26b7926bda88..ba34f9e96efd 100644
--- a/tools/virtio/asm/barrier.h
+++ b/tools/virtio/asm/barrier.h
@@ -1,15 +1,19 @@
1#if defined(__i386__) || defined(__x86_64__) 1#if defined(__i386__) || defined(__x86_64__)
2#define barrier() asm volatile("" ::: "memory") 2#define barrier() asm volatile("" ::: "memory")
3#define mb() __sync_synchronize() 3#define virt_mb() __sync_synchronize()
4 4#define virt_rmb() barrier()
5#define smp_mb() mb() 5#define virt_wmb() barrier()
6# define dma_rmb() barrier() 6/* Atomic store should be enough, but gcc generates worse code in that case. */
7# define dma_wmb() barrier() 7#define virt_store_mb(var, value) do { \
8# define smp_rmb() barrier() 8 typeof(var) virt_store_mb_value = (value); \
9# define smp_wmb() barrier() 9 __atomic_exchange(&(var), &virt_store_mb_value, &virt_store_mb_value, \
10 __ATOMIC_SEQ_CST); \
11 barrier(); \
12} while (0);
10/* Weak barriers should be used. If not - it's a bug */ 13/* Weak barriers should be used. If not - it's a bug */
11# define rmb() abort() 14# define mb() abort()
12# define wmb() abort() 15# define rmb() abort()
16# define wmb() abort()
13#else 17#else
14#error Please fill in barrier macros 18#error Please fill in barrier macros
15#endif 19#endif
diff --git a/tools/virtio/linux/compiler.h b/tools/virtio/linux/compiler.h
new file mode 100644
index 000000000000..845960e1cbf2
--- /dev/null
+++ b/tools/virtio/linux/compiler.h
@@ -0,0 +1,9 @@
1#ifndef LINUX_COMPILER_H
2#define LINUX_COMPILER_H
3
4#define WRITE_ONCE(var, val) \
5 (*((volatile typeof(val) *)(&(var))) = (val))
6
7#define READ_ONCE(var) (*((volatile typeof(val) *)(&(var))))
8
9#endif
diff --git a/tools/virtio/linux/kernel.h b/tools/virtio/linux/kernel.h
index 0a3da64638ce..033849948215 100644
--- a/tools/virtio/linux/kernel.h
+++ b/tools/virtio/linux/kernel.h
@@ -8,6 +8,7 @@
8#include <assert.h> 8#include <assert.h>
9#include <stdarg.h> 9#include <stdarg.h>
10 10
11#include <linux/compiler.h>
11#include <linux/types.h> 12#include <linux/types.h>
12#include <linux/printk.h> 13#include <linux/printk.h>
13#include <linux/bug.h> 14#include <linux/bug.h>
@@ -110,4 +111,10 @@ static inline void free_page(unsigned long addr)
110 (void) (&_min1 == &_min2); \ 111 (void) (&_min1 == &_min2); \
111 _min1 < _min2 ? _min1 : _min2; }) 112 _min1 < _min2 ? _min1 : _min2; })
112 113
114/* TODO: empty stubs for now. Broken but enough for virtio_ring.c */
115#define list_add_tail(a, b) do {} while (0)
116#define list_del(a) do {} while (0)
117#define list_for_each_entry(a, b, c) while (0)
118/* end of stubs */
119
113#endif /* KERNEL_H */ 120#endif /* KERNEL_H */
diff --git a/tools/virtio/linux/virtio.h b/tools/virtio/linux/virtio.h
index a3e07016a440..ee125e714053 100644
--- a/tools/virtio/linux/virtio.h
+++ b/tools/virtio/linux/virtio.h
@@ -3,12 +3,6 @@
3#include <linux/scatterlist.h> 3#include <linux/scatterlist.h>
4#include <linux/kernel.h> 4#include <linux/kernel.h>
5 5
6/* TODO: empty stubs for now. Broken but enough for virtio_ring.c */
7#define list_add_tail(a, b) do {} while (0)
8#define list_del(a) do {} while (0)
9#define list_for_each_entry(a, b, c) while (0)
10/* end of stubs */
11
12struct virtio_device { 6struct virtio_device {
13 void *dev; 7 void *dev;
14 u64 features; 8 u64 features;
diff --git a/tools/virtio/linux/virtio_config.h b/tools/virtio/linux/virtio_config.h
index 806d683ab107..57a6964a1e35 100644
--- a/tools/virtio/linux/virtio_config.h
+++ b/tools/virtio/linux/virtio_config.h
@@ -40,33 +40,39 @@ static inline void __virtio_clear_bit(struct virtio_device *vdev,
40#define virtio_has_feature(dev, feature) \ 40#define virtio_has_feature(dev, feature) \
41 (__virtio_test_bit((dev), feature)) 41 (__virtio_test_bit((dev), feature))
42 42
43static inline bool virtio_is_little_endian(struct virtio_device *vdev)
44{
45 return virtio_has_feature(vdev, VIRTIO_F_VERSION_1) ||
46 virtio_legacy_is_little_endian();
47}
48
49/* Memory accessors */
43static inline u16 virtio16_to_cpu(struct virtio_device *vdev, __virtio16 val) 50static inline u16 virtio16_to_cpu(struct virtio_device *vdev, __virtio16 val)
44{ 51{
45 return __virtio16_to_cpu(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); 52 return __virtio16_to_cpu(virtio_is_little_endian(vdev), val);
46} 53}
47 54
48static inline __virtio16 cpu_to_virtio16(struct virtio_device *vdev, u16 val) 55static inline __virtio16 cpu_to_virtio16(struct virtio_device *vdev, u16 val)
49{ 56{
50 return __cpu_to_virtio16(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); 57 return __cpu_to_virtio16(virtio_is_little_endian(vdev), val);
51} 58}
52 59
53static inline u32 virtio32_to_cpu(struct virtio_device *vdev, __virtio32 val) 60static inline u32 virtio32_to_cpu(struct virtio_device *vdev, __virtio32 val)
54{ 61{
55 return __virtio32_to_cpu(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); 62 return __virtio32_to_cpu(virtio_is_little_endian(vdev), val);
56} 63}
57 64
58static inline __virtio32 cpu_to_virtio32(struct virtio_device *vdev, u32 val) 65static inline __virtio32 cpu_to_virtio32(struct virtio_device *vdev, u32 val)
59{ 66{
60 return __cpu_to_virtio32(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); 67 return __cpu_to_virtio32(virtio_is_little_endian(vdev), val);
61} 68}
62 69
63static inline u64 virtio64_to_cpu(struct virtio_device *vdev, __virtio64 val) 70static inline u64 virtio64_to_cpu(struct virtio_device *vdev, __virtio64 val)
64{ 71{
65 return __virtio64_to_cpu(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); 72 return __virtio64_to_cpu(virtio_is_little_endian(vdev), val);
66} 73}
67 74
68static inline __virtio64 cpu_to_virtio64(struct virtio_device *vdev, u64 val) 75static inline __virtio64 cpu_to_virtio64(struct virtio_device *vdev, u64 val)
69{ 76{
70 return __cpu_to_virtio64(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); 77 return __cpu_to_virtio64(virtio_is_little_endian(vdev), val);
71} 78}
72
diff --git a/tools/virtio/ringtest/Makefile b/tools/virtio/ringtest/Makefile
new file mode 100644
index 000000000000..feaa64ac4630
--- /dev/null
+++ b/tools/virtio/ringtest/Makefile
@@ -0,0 +1,22 @@
1all:
2
3all: ring virtio_ring_0_9 virtio_ring_poll
4
5CFLAGS += -Wall
6CFLAGS += -pthread -O2 -ggdb
7LDFLAGS += -pthread -O2 -ggdb
8
9main.o: main.c main.h
10ring.o: ring.c main.h
11virtio_ring_0_9.o: virtio_ring_0_9.c main.h
12virtio_ring_poll.o: virtio_ring_poll.c virtio_ring_0_9.c main.h
13ring: ring.o main.o
14virtio_ring_0_9: virtio_ring_0_9.o main.o
15virtio_ring_poll: virtio_ring_poll.o main.o
16clean:
17 -rm main.o
18 -rm ring.o ring
19 -rm virtio_ring_0_9.o virtio_ring_0_9
20 -rm virtio_ring_poll.o virtio_ring_poll
21
22.PHONY: all clean
diff --git a/tools/virtio/ringtest/README b/tools/virtio/ringtest/README
new file mode 100644
index 000000000000..34e94c46104f
--- /dev/null
+++ b/tools/virtio/ringtest/README
@@ -0,0 +1,2 @@
1Partial implementation of various ring layouts, useful to tune virtio design.
2Uses shared memory heavily.
diff --git a/tools/virtio/ringtest/main.c b/tools/virtio/ringtest/main.c
new file mode 100644
index 000000000000..3a5ff438bd62
--- /dev/null
+++ b/tools/virtio/ringtest/main.c
@@ -0,0 +1,366 @@
1/*
2 * Copyright (C) 2016 Red Hat, Inc.
3 * Author: Michael S. Tsirkin <mst@redhat.com>
4 * This work is licensed under the terms of the GNU GPL, version 2.
5 *
6 * Command line processing and common functions for ring benchmarking.
7 */
8#define _GNU_SOURCE
9#include <getopt.h>
10#include <pthread.h>
11#include <assert.h>
12#include <sched.h>
13#include "main.h"
14#include <sys/eventfd.h>
15#include <stdlib.h>
16#include <stdio.h>
17#include <unistd.h>
18#include <limits.h>
19
20int runcycles = 10000000;
21int max_outstanding = INT_MAX;
22int batch = 1;
23
24bool do_sleep = false;
25bool do_relax = false;
26bool do_exit = true;
27
28unsigned ring_size = 256;
29
30static int kickfd = -1;
31static int callfd = -1;
32
33void notify(int fd)
34{
35 unsigned long long v = 1;
36 int r;
37
38 vmexit();
39 r = write(fd, &v, sizeof v);
40 assert(r == sizeof v);
41 vmentry();
42}
43
44void wait_for_notify(int fd)
45{
46 unsigned long long v = 1;
47 int r;
48
49 vmexit();
50 r = read(fd, &v, sizeof v);
51 assert(r == sizeof v);
52 vmentry();
53}
54
55void kick(void)
56{
57 notify(kickfd);
58}
59
60void wait_for_kick(void)
61{
62 wait_for_notify(kickfd);
63}
64
65void call(void)
66{
67 notify(callfd);
68}
69
70void wait_for_call(void)
71{
72 wait_for_notify(callfd);
73}
74
75void set_affinity(const char *arg)
76{
77 cpu_set_t cpuset;
78 int ret;
79 pthread_t self;
80 long int cpu;
81 char *endptr;
82
83 if (!arg)
84 return;
85
86 cpu = strtol(arg, &endptr, 0);
87 assert(!*endptr);
88
89 assert(cpu >= 0 || cpu < CPU_SETSIZE);
90
91 self = pthread_self();
92 CPU_ZERO(&cpuset);
93 CPU_SET(cpu, &cpuset);
94
95 ret = pthread_setaffinity_np(self, sizeof(cpu_set_t), &cpuset);
96 assert(!ret);
97}
98
99static void run_guest(void)
100{
101 int completed_before;
102 int completed = 0;
103 int started = 0;
104 int bufs = runcycles;
105 int spurious = 0;
106 int r;
107 unsigned len;
108 void *buf;
109 int tokick = batch;
110
111 for (;;) {
112 if (do_sleep)
113 disable_call();
114 completed_before = completed;
115 do {
116 if (started < bufs &&
117 started - completed < max_outstanding) {
118 r = add_inbuf(0, NULL, "Hello, world!");
119 if (__builtin_expect(r == 0, true)) {
120 ++started;
121 if (!--tokick) {
122 tokick = batch;
123 if (do_sleep)
124 kick_available();
125 }
126
127 }
128 } else
129 r = -1;
130
131 /* Flush out completed bufs if any */
132 if (get_buf(&len, &buf)) {
133 ++completed;
134 if (__builtin_expect(completed == bufs, false))
135 return;
136 r = 0;
137 }
138 } while (r == 0);
139 if (completed == completed_before)
140 ++spurious;
141 assert(completed <= bufs);
142 assert(started <= bufs);
143 if (do_sleep) {
144 if (enable_call())
145 wait_for_call();
146 } else {
147 poll_used();
148 }
149 }
150}
151
152static void run_host(void)
153{
154 int completed_before;
155 int completed = 0;
156 int spurious = 0;
157 int bufs = runcycles;
158 unsigned len;
159 void *buf;
160
161 for (;;) {
162 if (do_sleep) {
163 if (enable_kick())
164 wait_for_kick();
165 } else {
166 poll_avail();
167 }
168 if (do_sleep)
169 disable_kick();
170 completed_before = completed;
171 while (__builtin_expect(use_buf(&len, &buf), true)) {
172 if (do_sleep)
173 call_used();
174 ++completed;
175 if (__builtin_expect(completed == bufs, false))
176 return;
177 }
178 if (completed == completed_before)
179 ++spurious;
180 assert(completed <= bufs);
181 if (completed == bufs)
182 break;
183 }
184}
185
186void *start_guest(void *arg)
187{
188 set_affinity(arg);
189 run_guest();
190 pthread_exit(NULL);
191}
192
193void *start_host(void *arg)
194{
195 set_affinity(arg);
196 run_host();
197 pthread_exit(NULL);
198}
199
200static const char optstring[] = "";
201static const struct option longopts[] = {
202 {
203 .name = "help",
204 .has_arg = no_argument,
205 .val = 'h',
206 },
207 {
208 .name = "host-affinity",
209 .has_arg = required_argument,
210 .val = 'H',
211 },
212 {
213 .name = "guest-affinity",
214 .has_arg = required_argument,
215 .val = 'G',
216 },
217 {
218 .name = "ring-size",
219 .has_arg = required_argument,
220 .val = 'R',
221 },
222 {
223 .name = "run-cycles",
224 .has_arg = required_argument,
225 .val = 'C',
226 },
227 {
228 .name = "outstanding",
229 .has_arg = required_argument,
230 .val = 'o',
231 },
232 {
233 .name = "batch",
234 .has_arg = required_argument,
235 .val = 'b',
236 },
237 {
238 .name = "sleep",
239 .has_arg = no_argument,
240 .val = 's',
241 },
242 {
243 .name = "relax",
244 .has_arg = no_argument,
245 .val = 'x',
246 },
247 {
248 .name = "exit",
249 .has_arg = no_argument,
250 .val = 'e',
251 },
252 {
253 }
254};
255
256static void help(void)
257{
258 fprintf(stderr, "Usage: <test> [--help]"
259 " [--host-affinity H]"
260 " [--guest-affinity G]"
261 " [--ring-size R (default: %d)]"
262 " [--run-cycles C (default: %d)]"
263 " [--batch b]"
264 " [--outstanding o]"
265 " [--sleep]"
266 " [--relax]"
267 " [--exit]"
268 "\n",
269 ring_size,
270 runcycles);
271}
272
273int main(int argc, char **argv)
274{
275 int ret;
276 pthread_t host, guest;
277 void *tret;
278 char *host_arg = NULL;
279 char *guest_arg = NULL;
280 char *endptr;
281 long int c;
282
283 kickfd = eventfd(0, 0);
284 assert(kickfd >= 0);
285 callfd = eventfd(0, 0);
286 assert(callfd >= 0);
287
288 for (;;) {
289 int o = getopt_long(argc, argv, optstring, longopts, NULL);
290 switch (o) {
291 case -1:
292 goto done;
293 case '?':
294 help();
295 exit(2);
296 case 'H':
297 host_arg = optarg;
298 break;
299 case 'G':
300 guest_arg = optarg;
301 break;
302 case 'R':
303 ring_size = strtol(optarg, &endptr, 0);
304 assert(ring_size && !(ring_size & (ring_size - 1)));
305 assert(!*endptr);
306 break;
307 case 'C':
308 c = strtol(optarg, &endptr, 0);
309 assert(!*endptr);
310 assert(c > 0 && c < INT_MAX);
311 runcycles = c;
312 break;
313 case 'o':
314 c = strtol(optarg, &endptr, 0);
315 assert(!*endptr);
316 assert(c > 0 && c < INT_MAX);
317 max_outstanding = c;
318 break;
319 case 'b':
320 c = strtol(optarg, &endptr, 0);
321 assert(!*endptr);
322 assert(c > 0 && c < INT_MAX);
323 batch = c;
324 break;
325 case 's':
326 do_sleep = true;
327 break;
328 case 'x':
329 do_relax = true;
330 break;
331 case 'e':
332 do_exit = true;
333 break;
334 default:
335 help();
336 exit(4);
337 break;
338 }
339 }
340
341 /* does nothing here, used to make sure all smp APIs compile */
342 smp_acquire();
343 smp_release();
344 smp_mb();
345done:
346
347 if (batch > max_outstanding)
348 batch = max_outstanding;
349
350 if (optind < argc) {
351 help();
352 exit(4);
353 }
354 alloc_ring();
355
356 ret = pthread_create(&host, NULL, start_host, host_arg);
357 assert(!ret);
358 ret = pthread_create(&guest, NULL, start_guest, guest_arg);
359 assert(!ret);
360
361 ret = pthread_join(guest, &tret);
362 assert(!ret);
363 ret = pthread_join(host, &tret);
364 assert(!ret);
365 return 0;
366}
diff --git a/tools/virtio/ringtest/main.h b/tools/virtio/ringtest/main.h
new file mode 100644
index 000000000000..16917acb0ade
--- /dev/null
+++ b/tools/virtio/ringtest/main.h
@@ -0,0 +1,119 @@
1/*
2 * Copyright (C) 2016 Red Hat, Inc.
3 * Author: Michael S. Tsirkin <mst@redhat.com>
4 * This work is licensed under the terms of the GNU GPL, version 2.
5 *
6 * Common macros and functions for ring benchmarking.
7 */
8#ifndef MAIN_H
9#define MAIN_H
10
11#include <stdbool.h>
12
13extern bool do_exit;
14
15#if defined(__x86_64__) || defined(__i386__)
16#include "x86intrin.h"
17
18static inline void wait_cycles(unsigned long long cycles)
19{
20 unsigned long long t;
21
22 t = __rdtsc();
23 while (__rdtsc() - t < cycles) {}
24}
25
26#define VMEXIT_CYCLES 500
27#define VMENTRY_CYCLES 500
28
29#else
30static inline void wait_cycles(unsigned long long cycles)
31{
32 _Exit(5);
33}
34#define VMEXIT_CYCLES 0
35#define VMENTRY_CYCLES 0
36#endif
37
38static inline void vmexit(void)
39{
40 if (!do_exit)
41 return;
42
43 wait_cycles(VMEXIT_CYCLES);
44}
45static inline void vmentry(void)
46{
47 if (!do_exit)
48 return;
49
50 wait_cycles(VMENTRY_CYCLES);
51}
52
53/* implemented by ring */
54void alloc_ring(void);
55/* guest side */
56int add_inbuf(unsigned, void *, void *);
57void *get_buf(unsigned *, void **);
58void disable_call();
59bool enable_call();
60void kick_available();
61void poll_used();
62/* host side */
63void disable_kick();
64bool enable_kick();
65bool use_buf(unsigned *, void **);
66void call_used();
67void poll_avail();
68
69/* implemented by main */
70extern bool do_sleep;
71void kick(void);
72void wait_for_kick(void);
73void call(void);
74void wait_for_call(void);
75
76extern unsigned ring_size;
77
78/* Compiler barrier - similar to what Linux uses */
79#define barrier() asm volatile("" ::: "memory")
80
81/* Is there a portable way to do this? */
82#if defined(__x86_64__) || defined(__i386__)
83#define cpu_relax() asm ("rep; nop" ::: "memory")
84#else
85#define cpu_relax() assert(0)
86#endif
87
88extern bool do_relax;
89
90static inline void busy_wait(void)
91{
92 if (do_relax)
93 cpu_relax();
94 else
95 /* prevent compiler from removing busy loops */
96 barrier();
97}
98
99/*
100 * Not using __ATOMIC_SEQ_CST since gcc docs say they are only synchronized
101 * with other __ATOMIC_SEQ_CST calls.
102 */
103#define smp_mb() __sync_synchronize()
104
105/*
106 * This abuses the atomic builtins for thread fences, and
107 * adds a compiler barrier.
108 */
109#define smp_release() do { \
110 barrier(); \
111 __atomic_thread_fence(__ATOMIC_RELEASE); \
112} while (0)
113
114#define smp_acquire() do { \
115 __atomic_thread_fence(__ATOMIC_ACQUIRE); \
116 barrier(); \
117} while (0)
118
119#endif
diff --git a/tools/virtio/ringtest/ring.c b/tools/virtio/ringtest/ring.c
new file mode 100644
index 000000000000..c25c8d248b6b
--- /dev/null
+++ b/tools/virtio/ringtest/ring.c
@@ -0,0 +1,272 @@
1/*
2 * Copyright (C) 2016 Red Hat, Inc.
3 * Author: Michael S. Tsirkin <mst@redhat.com>
4 * This work is licensed under the terms of the GNU GPL, version 2.
5 *
6 * Simple descriptor-based ring. virtio 0.9 compatible event index is used for
7 * signalling, unconditionally.
8 */
9#define _GNU_SOURCE
10#include "main.h"
11#include <stdlib.h>
12#include <stdio.h>
13#include <string.h>
14
15/* Next - Where next entry will be written.
16 * Prev - "Next" value when event triggered previously.
17 * Event - Peer requested event after writing this entry.
18 */
19static inline bool need_event(unsigned short event,
20 unsigned short next,
21 unsigned short prev)
22{
23 return (unsigned short)(next - event - 1) < (unsigned short)(next - prev);
24}
25
26/* Design:
27 * Guest adds descriptors with unique index values and DESC_HW in flags.
28 * Host overwrites used descriptors with correct len, index, and DESC_HW clear.
29 * Flags are always set last.
30 */
31#define DESC_HW 0x1
32
33struct desc {
34 unsigned short flags;
35 unsigned short index;
36 unsigned len;
37 unsigned long long addr;
38};
39
40/* how much padding is needed to avoid false cache sharing */
41#define HOST_GUEST_PADDING 0x80
42
43/* Mostly read */
44struct event {
45 unsigned short kick_index;
46 unsigned char reserved0[HOST_GUEST_PADDING - 2];
47 unsigned short call_index;
48 unsigned char reserved1[HOST_GUEST_PADDING - 2];
49};
50
51struct data {
52 void *buf; /* descriptor is writeable, we can't get buf from there */
53 void *data;
54} *data;
55
56struct desc *ring;
57struct event *event;
58
59struct guest {
60 unsigned avail_idx;
61 unsigned last_used_idx;
62 unsigned num_free;
63 unsigned kicked_avail_idx;
64 unsigned char reserved[HOST_GUEST_PADDING - 12];
65} guest;
66
67struct host {
68 /* we do not need to track last avail index
69 * unless we have more than one in flight.
70 */
71 unsigned used_idx;
72 unsigned called_used_idx;
73 unsigned char reserved[HOST_GUEST_PADDING - 4];
74} host;
75
76/* implemented by ring */
77void alloc_ring(void)
78{
79 int ret;
80 int i;
81
82 ret = posix_memalign((void **)&ring, 0x1000, ring_size * sizeof *ring);
83 if (ret) {
84 perror("Unable to allocate ring buffer.\n");
85 exit(3);
86 }
87 event = malloc(sizeof *event);
88 if (!event) {
89 perror("Unable to allocate event buffer.\n");
90 exit(3);
91 }
92 memset(event, 0, sizeof *event);
93 guest.avail_idx = 0;
94 guest.kicked_avail_idx = -1;
95 guest.last_used_idx = 0;
96 host.used_idx = 0;
97 host.called_used_idx = -1;
98 for (i = 0; i < ring_size; ++i) {
99 struct desc desc = {
100 .index = i,
101 };
102 ring[i] = desc;
103 }
104 guest.num_free = ring_size;
105 data = malloc(ring_size * sizeof *data);
106 if (!data) {
107 perror("Unable to allocate data buffer.\n");
108 exit(3);
109 }
110 memset(data, 0, ring_size * sizeof *data);
111}
112
113/* guest side */
114int add_inbuf(unsigned len, void *buf, void *datap)
115{
116 unsigned head, index;
117
118 if (!guest.num_free)
119 return -1;
120
121 guest.num_free--;
122 head = (ring_size - 1) & (guest.avail_idx++);
123
124 /* Start with a write. On MESI architectures this helps
125 * avoid a shared state with consumer that is polling this descriptor.
126 */
127 ring[head].addr = (unsigned long)(void*)buf;
128 ring[head].len = len;
129 /* read below might bypass write above. That is OK because it's just an
130 * optimization. If this happens, we will get the cache line in a
131 * shared state which is unfortunate, but probably not worth it to
132 * add an explicit full barrier to avoid this.
133 */
134 barrier();
135 index = ring[head].index;
136 data[index].buf = buf;
137 data[index].data = datap;
138 /* Barrier A (for pairing) */
139 smp_release();
140 ring[head].flags = DESC_HW;
141
142 return 0;
143}
144
145void *get_buf(unsigned *lenp, void **bufp)
146{
147 unsigned head = (ring_size - 1) & guest.last_used_idx;
148 unsigned index;
149 void *datap;
150
151 if (ring[head].flags & DESC_HW)
152 return NULL;
153 /* Barrier B (for pairing) */
154 smp_acquire();
155 *lenp = ring[head].len;
156 index = ring[head].index & (ring_size - 1);
157 datap = data[index].data;
158 *bufp = data[index].buf;
159 data[index].buf = NULL;
160 data[index].data = NULL;
161 guest.num_free++;
162 guest.last_used_idx++;
163 return datap;
164}
165
166void poll_used(void)
167{
168 unsigned head = (ring_size - 1) & guest.last_used_idx;
169
170 while (ring[head].flags & DESC_HW)
171 busy_wait();
172}
173
174void disable_call()
175{
176 /* Doing nothing to disable calls might cause
177 * extra interrupts, but reduces the number of cache misses.
178 */
179}
180
181bool enable_call()
182{
183 unsigned head = (ring_size - 1) & guest.last_used_idx;
184
185 event->call_index = guest.last_used_idx;
186 /* Flush call index write */
187 /* Barrier D (for pairing) */
188 smp_mb();
189 return ring[head].flags & DESC_HW;
190}
191
192void kick_available(void)
193{
194 /* Flush in previous flags write */
195 /* Barrier C (for pairing) */
196 smp_mb();
197 if (!need_event(event->kick_index,
198 guest.avail_idx,
199 guest.kicked_avail_idx))
200 return;
201
202 guest.kicked_avail_idx = guest.avail_idx;
203 kick();
204}
205
206/* host side */
207void disable_kick()
208{
209 /* Doing nothing to disable kicks might cause
210 * extra interrupts, but reduces the number of cache misses.
211 */
212}
213
214bool enable_kick()
215{
216 unsigned head = (ring_size - 1) & host.used_idx;
217
218 event->kick_index = host.used_idx;
219 /* Barrier C (for pairing) */
220 smp_mb();
221 return !(ring[head].flags & DESC_HW);
222}
223
224void poll_avail(void)
225{
226 unsigned head = (ring_size - 1) & host.used_idx;
227
228 while (!(ring[head].flags & DESC_HW))
229 busy_wait();
230}
231
232bool use_buf(unsigned *lenp, void **bufp)
233{
234 unsigned head = (ring_size - 1) & host.used_idx;
235
236 if (!(ring[head].flags & DESC_HW))
237 return false;
238
239 /* make sure length read below is not speculated */
240 /* Barrier A (for pairing) */
241 smp_acquire();
242
243 /* simple in-order completion: we don't need
244 * to touch index at all. This also means we
245 * can just modify the descriptor in-place.
246 */
247 ring[head].len--;
248 /* Make sure len is valid before flags.
249 * Note: alternative is to write len and flags in one access -
250 * possible on 64 bit architectures but wmb is free on Intel anyway
251 * so I have no way to test whether it's a gain.
252 */
253 /* Barrier B (for pairing) */
254 smp_release();
255 ring[head].flags = 0;
256 host.used_idx++;
257 return true;
258}
259
260void call_used(void)
261{
262 /* Flush in previous flags write */
263 /* Barrier D (for pairing) */
264 smp_mb();
265 if (!need_event(event->call_index,
266 host.used_idx,
267 host.called_used_idx))
268 return;
269
270 host.called_used_idx = host.used_idx;
271 call();
272}
diff --git a/tools/virtio/ringtest/run-on-all.sh b/tools/virtio/ringtest/run-on-all.sh
new file mode 100755
index 000000000000..52b0f71ffa8d
--- /dev/null
+++ b/tools/virtio/ringtest/run-on-all.sh
@@ -0,0 +1,24 @@
1#!/bin/sh
2
3#use last CPU for host. Why not the first?
4#many devices tend to use cpu0 by default so
5#it tends to be busier
6HOST_AFFINITY=$(cd /dev/cpu; ls|grep -v '[a-z]'|sort -n|tail -1)
7
8#run command on all cpus
9for cpu in $(cd /dev/cpu; ls|grep -v '[a-z]'|sort -n);
10do
11 #Don't run guest and host on same CPU
12 #It actually works ok if using signalling
13 if
14 (echo "$@" | grep -e "--sleep" > /dev/null) || \
15 test $HOST_AFFINITY '!=' $cpu
16 then
17 echo "GUEST AFFINITY $cpu"
18 "$@" --host-affinity $HOST_AFFINITY --guest-affinity $cpu
19 fi
20done
21echo "NO GUEST AFFINITY"
22"$@" --host-affinity $HOST_AFFINITY
23echo "NO AFFINITY"
24"$@"
diff --git a/tools/virtio/ringtest/virtio_ring_0_9.c b/tools/virtio/ringtest/virtio_ring_0_9.c
new file mode 100644
index 000000000000..47c9a1a18d36
--- /dev/null
+++ b/tools/virtio/ringtest/virtio_ring_0_9.c
@@ -0,0 +1,316 @@
1/*
2 * Copyright (C) 2016 Red Hat, Inc.
3 * Author: Michael S. Tsirkin <mst@redhat.com>
4 * This work is licensed under the terms of the GNU GPL, version 2.
5 *
6 * Partial implementation of virtio 0.9. event index is used for signalling,
7 * unconditionally. Design roughly follows linux kernel implementation in order
8 * to be able to judge its performance.
9 */
10#define _GNU_SOURCE
11#include "main.h"
12#include <stdlib.h>
13#include <stdio.h>
14#include <assert.h>
15#include <string.h>
16#include <linux/virtio_ring.h>
17
18struct data {
19 void *data;
20} *data;
21
22struct vring ring;
23
24/* enabling the below activates experimental ring polling code
25 * (which skips index reads on consumer in favor of looking at
26 * high bits of ring id ^ 0x8000).
27 */
28/* #ifdef RING_POLL */
29
30/* how much padding is needed to avoid false cache sharing */
31#define HOST_GUEST_PADDING 0x80
32
33struct guest {
34 unsigned short avail_idx;
35 unsigned short last_used_idx;
36 unsigned short num_free;
37 unsigned short kicked_avail_idx;
38 unsigned short free_head;
39 unsigned char reserved[HOST_GUEST_PADDING - 10];
40} guest;
41
42struct host {
43 /* we do not need to track last avail index
44 * unless we have more than one in flight.
45 */
46 unsigned short used_idx;
47 unsigned short called_used_idx;
48 unsigned char reserved[HOST_GUEST_PADDING - 4];
49} host;
50
51/* implemented by ring */
52void alloc_ring(void)
53{
54 int ret;
55 int i;
56 void *p;
57
58 ret = posix_memalign(&p, 0x1000, vring_size(ring_size, 0x1000));
59 if (ret) {
60 perror("Unable to allocate ring buffer.\n");
61 exit(3);
62 }
63 memset(p, 0, vring_size(ring_size, 0x1000));
64 vring_init(&ring, ring_size, p, 0x1000);
65
66 guest.avail_idx = 0;
67 guest.kicked_avail_idx = -1;
68 guest.last_used_idx = 0;
69 /* Put everything in free lists. */
70 guest.free_head = 0;
71 for (i = 0; i < ring_size - 1; i++)
72 ring.desc[i].next = i + 1;
73 host.used_idx = 0;
74 host.called_used_idx = -1;
75 guest.num_free = ring_size;
76 data = malloc(ring_size * sizeof *data);
77 if (!data) {
78 perror("Unable to allocate data buffer.\n");
79 exit(3);
80 }
81 memset(data, 0, ring_size * sizeof *data);
82}
83
84/* guest side */
85int add_inbuf(unsigned len, void *buf, void *datap)
86{
87 unsigned head, avail;
88 struct vring_desc *desc;
89
90 if (!guest.num_free)
91 return -1;
92
93 head = guest.free_head;
94 guest.num_free--;
95
96 desc = ring.desc;
97 desc[head].flags = VRING_DESC_F_NEXT;
98 desc[head].addr = (unsigned long)(void *)buf;
99 desc[head].len = len;
100 /* We do it like this to simulate the way
101 * we'd have to flip it if we had multiple
102 * descriptors.
103 */
104 desc[head].flags &= ~VRING_DESC_F_NEXT;
105 guest.free_head = desc[head].next;
106
107 data[head].data = datap;
108
109#ifdef RING_POLL
110 /* Barrier A (for pairing) */
111 smp_release();
112 avail = guest.avail_idx++;
113 ring.avail->ring[avail & (ring_size - 1)] =
114 (head | (avail & ~(ring_size - 1))) ^ 0x8000;
115#else
116 avail = (ring_size - 1) & (guest.avail_idx++);
117 ring.avail->ring[avail] = head;
118 /* Barrier A (for pairing) */
119 smp_release();
120#endif
121 ring.avail->idx = guest.avail_idx;
122 return 0;
123}
124
125void *get_buf(unsigned *lenp, void **bufp)
126{
127 unsigned head;
128 unsigned index;
129 void *datap;
130
131#ifdef RING_POLL
132 head = (ring_size - 1) & guest.last_used_idx;
133 index = ring.used->ring[head].id;
134 if ((index ^ guest.last_used_idx ^ 0x8000) & ~(ring_size - 1))
135 return NULL;
136 /* Barrier B (for pairing) */
137 smp_acquire();
138 index &= ring_size - 1;
139#else
140 if (ring.used->idx == guest.last_used_idx)
141 return NULL;
142 /* Barrier B (for pairing) */
143 smp_acquire();
144 head = (ring_size - 1) & guest.last_used_idx;
145 index = ring.used->ring[head].id;
146#endif
147 *lenp = ring.used->ring[head].len;
148 datap = data[index].data;
149 *bufp = (void*)(unsigned long)ring.desc[index].addr;
150 data[index].data = NULL;
151 ring.desc[index].next = guest.free_head;
152 guest.free_head = index;
153 guest.num_free++;
154 guest.last_used_idx++;
155 return datap;
156}
157
158void poll_used(void)
159{
160#ifdef RING_POLL
161 unsigned head = (ring_size - 1) & guest.last_used_idx;
162
163 for (;;) {
164 unsigned index = ring.used->ring[head].id;
165
166 if ((index ^ guest.last_used_idx ^ 0x8000) & ~(ring_size - 1))
167 busy_wait();
168 else
169 break;
170 }
171#else
172 unsigned head = guest.last_used_idx;
173
174 while (ring.used->idx == head)
175 busy_wait();
176#endif
177}
178
179void disable_call()
180{
181 /* Doing nothing to disable calls might cause
182 * extra interrupts, but reduces the number of cache misses.
183 */
184}
185
186bool enable_call()
187{
188 unsigned short last_used_idx;
189
190 vring_used_event(&ring) = (last_used_idx = guest.last_used_idx);
191 /* Flush call index write */
192 /* Barrier D (for pairing) */
193 smp_mb();
194#ifdef RING_POLL
195 {
196 unsigned short head = last_used_idx & (ring_size - 1);
197 unsigned index = ring.used->ring[head].id;
198
199 return (index ^ last_used_idx ^ 0x8000) & ~(ring_size - 1);
200 }
201#else
202 return ring.used->idx == last_used_idx;
203#endif
204}
205
206void kick_available(void)
207{
208 /* Flush in previous flags write */
209 /* Barrier C (for pairing) */
210 smp_mb();
211 if (!vring_need_event(vring_avail_event(&ring),
212 guest.avail_idx,
213 guest.kicked_avail_idx))
214 return;
215
216 guest.kicked_avail_idx = guest.avail_idx;
217 kick();
218}
219
220/* host side */
221void disable_kick()
222{
223 /* Doing nothing to disable kicks might cause
224 * extra interrupts, but reduces the number of cache misses.
225 */
226}
227
228bool enable_kick()
229{
230 unsigned head = host.used_idx;
231
232 vring_avail_event(&ring) = head;
233 /* Barrier C (for pairing) */
234 smp_mb();
235#ifdef RING_POLL
236 {
237 unsigned index = ring.avail->ring[head & (ring_size - 1)];
238
239 return (index ^ head ^ 0x8000) & ~(ring_size - 1);
240 }
241#else
242 return head == ring.avail->idx;
243#endif
244}
245
246void poll_avail(void)
247{
248 unsigned head = host.used_idx;
249#ifdef RING_POLL
250 for (;;) {
251 unsigned index = ring.avail->ring[head & (ring_size - 1)];
252 if ((index ^ head ^ 0x8000) & ~(ring_size - 1))
253 busy_wait();
254 else
255 break;
256 }
257#else
258 while (ring.avail->idx == head)
259 busy_wait();
260#endif
261}
262
263bool use_buf(unsigned *lenp, void **bufp)
264{
265 unsigned used_idx = host.used_idx;
266 struct vring_desc *desc;
267 unsigned head;
268
269#ifdef RING_POLL
270 head = ring.avail->ring[used_idx & (ring_size - 1)];
271 if ((used_idx ^ head ^ 0x8000) & ~(ring_size - 1))
272 return false;
273 /* Barrier A (for pairing) */
274 smp_acquire();
275
276 used_idx &= ring_size - 1;
277 desc = &ring.desc[head & (ring_size - 1)];
278#else
279 if (used_idx == ring.avail->idx)
280 return false;
281
282 /* Barrier A (for pairing) */
283 smp_acquire();
284
285 used_idx &= ring_size - 1;
286 head = ring.avail->ring[used_idx];
287 desc = &ring.desc[head];
288#endif
289
290 *lenp = desc->len;
291 *bufp = (void *)(unsigned long)desc->addr;
292
293 /* now update used ring */
294 ring.used->ring[used_idx].id = head;
295 ring.used->ring[used_idx].len = desc->len - 1;
296 /* Barrier B (for pairing) */
297 smp_release();
298 host.used_idx++;
299 ring.used->idx = host.used_idx;
300
301 return true;
302}
303
304void call_used(void)
305{
306 /* Flush in previous flags write */
307 /* Barrier D (for pairing) */
308 smp_mb();
309 if (!vring_need_event(vring_used_event(&ring),
310 host.used_idx,
311 host.called_used_idx))
312 return;
313
314 host.called_used_idx = host.used_idx;
315 call();
316}
diff --git a/tools/virtio/ringtest/virtio_ring_poll.c b/tools/virtio/ringtest/virtio_ring_poll.c
new file mode 100644
index 000000000000..84fc2c557aaa
--- /dev/null
+++ b/tools/virtio/ringtest/virtio_ring_poll.c
@@ -0,0 +1,2 @@
1#define RING_POLL 1
2#include "virtio_ring_0_9.c"
diff --git a/tools/vm/page-types.c b/tools/vm/page-types.c
index bcf5ec760eb9..5a6016224bb9 100644
--- a/tools/vm/page-types.c
+++ b/tools/vm/page-types.c
@@ -128,6 +128,7 @@ static const char * const page_flag_names[] = {
128 [KPF_THP] = "t:thp", 128 [KPF_THP] = "t:thp",
129 [KPF_BALLOON] = "o:balloon", 129 [KPF_BALLOON] = "o:balloon",
130 [KPF_ZERO_PAGE] = "z:zero_page", 130 [KPF_ZERO_PAGE] = "z:zero_page",
131 [KPF_IDLE] = "i:idle_page",
131 132
132 [KPF_RESERVED] = "r:reserved", 133 [KPF_RESERVED] = "r:reserved",
133 [KPF_MLOCKED] = "m:mlocked", 134 [KPF_MLOCKED] = "m:mlocked",