aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/Makefile6
-rw-r--r--tools/include/linux/compiler.h2
-rw-r--r--tools/include/linux/export.h (renamed from tools/virtio/linux/export.h)5
-rw-r--r--tools/include/linux/types.h (renamed from tools/lib/lockdep/uinclude/linux/types.h)29
-rw-r--r--tools/lib/api/fs/fs.c43
-rw-r--r--tools/lib/lockdep/Makefile7
-rw-r--r--tools/lib/lockdep/uinclude/linux/export.h7
-rw-r--r--tools/lib/traceevent/event-parse.c113
-rw-r--r--tools/lib/traceevent/event-parse.h25
-rw-r--r--tools/lib/traceevent/event-plugin.c203
-rw-r--r--tools/lib/traceevent/plugin_function.c43
-rw-r--r--tools/net/bpf_exp.l1
-rw-r--r--tools/net/bpf_exp.y11
-rw-r--r--tools/net/bpf_jit_disasm.c20
-rw-r--r--tools/perf/Documentation/perf-diff.txt26
-rw-r--r--tools/perf/Documentation/perf-record.txt3
-rw-r--r--tools/perf/Documentation/perf-report.txt71
-rw-r--r--tools/perf/Documentation/perf-timechart.txt41
-rw-r--r--tools/perf/Documentation/perf-top.txt38
-rw-r--r--tools/perf/MANIFEST2
-rw-r--r--tools/perf/Makefile.perf32
-rw-r--r--tools/perf/arch/arm/Makefile7
-rw-r--r--tools/perf/arch/arm/include/perf_regs.h7
-rw-r--r--tools/perf/arch/arm/tests/dwarf-unwind.c60
-rw-r--r--tools/perf/arch/arm/tests/regs_load.S58
-rw-r--r--tools/perf/arch/arm/util/unwind-libdw.c36
-rw-r--r--tools/perf/arch/arm64/Makefile7
-rw-r--r--tools/perf/arch/arm64/include/perf_regs.h88
-rw-r--r--tools/perf/arch/arm64/util/dwarf-regs.c80
-rw-r--r--tools/perf/arch/arm64/util/unwind-libunwind.c82
-rw-r--r--tools/perf/arch/x86/include/perf_regs.h2
-rw-r--r--tools/perf/arch/x86/tests/dwarf-unwind.c2
-rw-r--r--tools/perf/arch/x86/util/tsc.c2
-rw-r--r--tools/perf/arch/x86/util/tsc.h2
-rw-r--r--tools/perf/builtin-annotate.c8
-rw-r--r--tools/perf/builtin-diff.c52
-rw-r--r--tools/perf/builtin-inject.c4
-rw-r--r--tools/perf/builtin-kmem.c88
-rw-r--r--tools/perf/builtin-lock.c10
-rw-r--r--tools/perf/builtin-mem.c15
-rw-r--r--tools/perf/builtin-probe.c23
-rw-r--r--tools/perf/builtin-record.c163
-rw-r--r--tools/perf/builtin-report.c372
-rw-r--r--tools/perf/builtin-sched.c82
-rw-r--r--tools/perf/builtin-top.c112
-rw-r--r--tools/perf/config/Makefile29
-rw-r--r--tools/perf/config/feature-checks/Makefile4
-rw-r--r--tools/perf/config/feature-checks/test-all.c5
-rw-r--r--tools/perf/config/feature-checks/test-on-exit.c16
-rw-r--r--tools/perf/perf-completion.sh4
-rw-r--r--tools/perf/perf-sys.h190
-rw-r--r--tools/perf/perf.c9
-rw-r--r--tools/perf/perf.h248
-rw-r--r--tools/perf/tests/attr.c7
-rw-r--r--tools/perf/tests/builtin-test.c64
-rw-r--r--tools/perf/tests/code-reading.c5
-rw-r--r--tools/perf/tests/dso-data.c216
-rw-r--r--tools/perf/tests/dwarf-unwind.c4
-rw-r--r--tools/perf/tests/evsel-tp-sched.c3
-rw-r--r--tools/perf/tests/hists_common.c209
-rw-r--r--tools/perf/tests/hists_common.h75
-rw-r--r--tools/perf/tests/hists_cumulate.c726
-rw-r--r--tools/perf/tests/hists_filter.c289
-rw-r--r--tools/perf/tests/hists_link.c209
-rw-r--r--tools/perf/tests/hists_output.c621
-rw-r--r--tools/perf/tests/keep-tracking.c2
-rw-r--r--tools/perf/tests/make7
-rw-r--r--tools/perf/tests/mmap-thread-lookup.c233
-rw-r--r--tools/perf/tests/parse-events.c142
-rw-r--r--tools/perf/tests/parse-no-sample-id-all.c2
-rw-r--r--tools/perf/tests/perf-time-to-tsc.c3
-rw-r--r--tools/perf/tests/rdpmc.c2
-rw-r--r--tools/perf/tests/sample-parsing.c2
-rw-r--r--tools/perf/tests/tests.h9
-rw-r--r--tools/perf/tests/thread-mg-share.c90
-rw-r--r--tools/perf/ui/browser.c2
-rw-r--r--tools/perf/ui/browser.h4
-rw-r--r--tools/perf/ui/browsers/hists.c270
-rw-r--r--tools/perf/ui/gtk/hists.c77
-rw-r--r--tools/perf/ui/hist.c371
-rw-r--r--tools/perf/ui/progress.h2
-rw-r--r--tools/perf/ui/setup.c2
-rw-r--r--tools/perf/ui/stdio/hist.c89
-rw-r--r--tools/perf/util/annotate.h2
-rw-r--r--tools/perf/util/build-id.c2
-rw-r--r--tools/perf/util/build-id.h2
-rw-r--r--tools/perf/util/callchain.c123
-rw-r--r--tools/perf/util/callchain.h19
-rw-r--r--tools/perf/util/config.c4
-rw-r--r--tools/perf/util/cpumap.c160
-rw-r--r--tools/perf/util/cpumap.h35
-rw-r--r--tools/perf/util/dso.c279
-rw-r--r--tools/perf/util/dso.h52
-rw-r--r--tools/perf/util/dwarf-aux.c7
-rw-r--r--tools/perf/util/event.c61
-rw-r--r--tools/perf/util/event.h31
-rw-r--r--tools/perf/util/evsel.c5
-rw-r--r--tools/perf/util/evsel.h9
-rw-r--r--tools/perf/util/header.h4
-rw-r--r--tools/perf/util/hist.c677
-rw-r--r--tools/perf/util/hist.h102
-rw-r--r--tools/perf/util/include/linux/bitmap.h3
-rw-r--r--tools/perf/util/include/linux/export.h6
-rw-r--r--tools/perf/util/include/linux/list.h1
-rw-r--r--tools/perf/util/include/linux/types.h29
-rw-r--r--tools/perf/util/machine.c15
-rw-r--r--tools/perf/util/map.c122
-rw-r--r--tools/perf/util/map.h18
-rw-r--r--tools/perf/util/pager.c12
-rw-r--r--tools/perf/util/parse-events.h3
-rw-r--r--tools/perf/util/parse-events.y14
-rw-r--r--tools/perf/util/perf_regs.c10
-rw-r--r--tools/perf/util/perf_regs.h6
-rw-r--r--tools/perf/util/pmu.c6
-rw-r--r--tools/perf/util/pmu.h2
-rw-r--r--tools/perf/util/probe-event.c13
-rw-r--r--tools/perf/util/probe-finder.c15
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c1
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c2
-rw-r--r--tools/perf/util/session.c5
-rw-r--r--tools/perf/util/sort.c630
-rw-r--r--tools/perf/util/sort.h28
-rw-r--r--tools/perf/util/stat.h2
-rw-r--r--tools/perf/util/svghelper.c2
-rw-r--r--tools/perf/util/svghelper.h2
-rw-r--r--tools/perf/util/symbol.c11
-rw-r--r--tools/perf/util/symbol.h5
-rw-r--r--tools/perf/util/thread.c52
-rw-r--r--tools/perf/util/thread.h3
-rw-r--r--tools/perf/util/top.h2
-rw-r--r--tools/perf/util/types.h24
-rw-r--r--tools/perf/util/unwind-libdw.c2
-rw-r--r--tools/perf/util/unwind-libunwind.c2
-rw-r--r--tools/perf/util/unwind.h2
-rw-r--r--tools/perf/util/util.c3
-rw-r--r--tools/perf/util/util.h3
-rw-r--r--tools/perf/util/values.h2
-rw-r--r--tools/power/acpi/Makefile28
-rw-r--r--tools/power/acpi/common/cmfsize.c101
-rw-r--r--tools/power/acpi/common/getopt.c239
-rw-r--r--tools/power/acpi/man/acpidump.885
-rw-r--r--tools/power/acpi/os_specific/service_layers/oslinuxtbl.c1329
-rw-r--r--tools/power/acpi/os_specific/service_layers/osunixdir.c204
-rw-r--r--tools/power/acpi/os_specific/service_layers/osunixmap.c151
-rw-r--r--tools/power/acpi/tools/acpidump/acpidump.c559
-rw-r--r--tools/power/acpi/tools/acpidump/acpidump.h130
-rw-r--r--tools/power/acpi/tools/acpidump/apdump.c451
-rw-r--r--tools/power/acpi/tools/acpidump/apfiles.c228
-rw-r--r--tools/power/acpi/tools/acpidump/apmain.c351
-rw-r--r--tools/power/acpi/tools/ec/Makefile22
-rw-r--r--tools/power/acpi/tools/ec/ec_access.c238
-rw-r--r--tools/power/cpupower/Makefile12
-rw-r--r--tools/power/cpupower/README24
-rw-r--r--tools/power/cpupower/ToDo1
-rw-r--r--tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c2
-rw-r--r--tools/power/cpupower/man/cpupower-frequency-info.13
-rw-r--r--tools/power/cpupower/man/cpupower-idle-set.110
-rw-r--r--tools/power/cpupower/man/cpupower-info.12
-rw-r--r--tools/power/cpupower/man/cpupower-set.131
-rw-r--r--tools/power/cpupower/utils/cpufreq-info.c110
-rw-r--r--tools/power/cpupower/utils/cpuidle-set.c75
-rw-r--r--tools/power/cpupower/utils/cpupower-info.c42
-rw-r--r--tools/power/cpupower/utils/cpupower-set.c43
-rw-r--r--tools/power/cpupower/utils/cpupower.c14
-rw-r--r--tools/power/x86/turbostat/turbostat.c4
-rw-r--r--tools/testing/selftests/Makefile1
-rw-r--r--tools/testing/selftests/cpu-hotplug/Makefile2
-rw-r--r--tools/testing/selftests/ipc/msgque.c5
-rw-r--r--tools/testing/selftests/memory-hotplug/Makefile2
-rw-r--r--tools/testing/selftests/net/Makefile8
-rw-r--r--tools/testing/selftests/powerpc/Makefile2
-rw-r--r--tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h5
-rw-r--r--tools/testing/selftests/powerpc/harness.c15
-rw-r--r--tools/testing/selftests/powerpc/mm/Makefile18
-rw-r--r--tools/testing/selftests/powerpc/mm/hugetlb_vs_thp_test.c72
-rw-r--r--tools/testing/selftests/powerpc/pmu/Makefile26
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/Makefile32
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/back_to_back_ebbs_test.c106
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/close_clears_pmcc_test.c59
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/cpu_event_pinned_vs_ebb_test.c93
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/cpu_event_vs_ebb_test.c89
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/cycles_test.c58
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/cycles_with_freeze_test.c117
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/ebb.c727
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/ebb.h78
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/ebb_handler.S365
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/ebb_on_child_test.c86
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/ebb_on_willing_child_test.c92
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/ebb_vs_cpu_event_test.c86
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/event_attributes_test.c131
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/fixed_instruction_loop.S43
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/fork_cleanup_test.c79
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/instruction_count_test.c164
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/lost_exception_test.c100
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/multi_counter_test.c91
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/multi_ebb_procs_test.c109
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/no_handler_test.c61
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/pmae_handling_test.c106
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/pmc56_overflow_test.c93
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/reg.h49
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/reg_access_test.c39
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/task_event_pinned_vs_ebb_test.c91
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/task_event_vs_ebb_test.c83
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/trace.c300
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/trace.h41
-rw-r--r--tools/testing/selftests/powerpc/pmu/event.c26
-rw-r--r--tools/testing/selftests/powerpc/pmu/event.h4
-rw-r--r--tools/testing/selftests/powerpc/pmu/lib.c252
-rw-r--r--tools/testing/selftests/powerpc/pmu/lib.h41
-rw-r--r--tools/testing/selftests/powerpc/pmu/loop.S73
-rw-r--r--tools/testing/selftests/powerpc/subunit.h5
-rw-r--r--tools/testing/selftests/powerpc/tm/Makefile15
-rw-r--r--tools/testing/selftests/powerpc/tm/tm-resched-dscr.c98
-rw-r--r--tools/testing/selftests/powerpc/utils.h12
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/configinit.sh2
-rw-r--r--tools/testing/selftests/rcutorture/bin/functions.sh48
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-build.sh6
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-recheck-lock.sh2
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-recheck-rcu.sh2
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-recheck.sh24
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh47
-rw-r--r--tools/testing/selftests/rcutorture/bin/kvm.sh142
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/parse-torture.sh (renamed from tools/testing/selftests/rcutorture/bin/parse-rcutorture.sh)22
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE02-T25
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE08.boot1
-rw-r--r--tools/testing/selftests/sysctl/Makefile19
-rw-r--r--tools/testing/selftests/sysctl/common_tests109
-rw-r--r--tools/testing/selftests/sysctl/run_numerictests10
-rw-r--r--tools/testing/selftests/sysctl/run_stringtests77
-rw-r--r--tools/thermal/tmon/Makefile2
-rw-r--r--tools/thermal/tmon/tmon.c26
-rw-r--r--tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c349
-rw-r--r--tools/usb/ffs-aio-example/multibuff/host_app/Makefile13
-rw-r--r--tools/usb/ffs-aio-example/multibuff/host_app/test.c146
-rw-r--r--tools/usb/ffs-aio-example/simple/device_app/aio_simple.c335
-rw-r--r--tools/usb/ffs-aio-example/simple/host_app/Makefile13
-rw-r--r--tools/usb/ffs-aio-example/simple/host_app/test.c148
-rw-r--r--tools/usb/ffs-test.c4
-rw-r--r--tools/virtio/Makefile2
-rw-r--r--tools/virtio/linux/kernel.h7
-rw-r--r--tools/virtio/linux/types.h28
-rw-r--r--tools/vm/page-types.c35
242 files changed, 16570 insertions, 2777 deletions
diff --git a/tools/Makefile b/tools/Makefile
index bcae806b0c39..9a617adc6675 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -44,6 +44,9 @@ cpupower: FORCE
44cgroup firewire hv guest usb virtio vm net: FORCE 44cgroup firewire hv guest usb virtio vm net: FORCE
45 $(call descend,$@) 45 $(call descend,$@)
46 46
47liblockdep: FORCE
48 $(call descend,lib/lockdep)
49
47libapikfs: FORCE 50libapikfs: FORCE
48 $(call descend,lib/api) 51 $(call descend,lib/api)
49 52
@@ -91,6 +94,9 @@ cpupower_clean:
91cgroup_clean hv_clean firewire_clean lguest_clean usb_clean virtio_clean vm_clean net_clean: 94cgroup_clean hv_clean firewire_clean lguest_clean usb_clean virtio_clean vm_clean net_clean:
92 $(call descend,$(@:_clean=),clean) 95 $(call descend,$(@:_clean=),clean)
93 96
97liblockdep_clean:
98 $(call descend,lib/lockdep,clean)
99
94libapikfs_clean: 100libapikfs_clean:
95 $(call descend,lib/api,clean) 101 $(call descend,lib/api,clean)
96 102
diff --git a/tools/include/linux/compiler.h b/tools/include/linux/compiler.h
index fbc6665c6d53..88461f09cc86 100644
--- a/tools/include/linux/compiler.h
+++ b/tools/include/linux/compiler.h
@@ -35,4 +35,6 @@
35# define unlikely(x) __builtin_expect(!!(x), 0) 35# define unlikely(x) __builtin_expect(!!(x), 0)
36#endif 36#endif
37 37
38#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
39
38#endif /* _TOOLS_LINUX_COMPILER_H */ 40#endif /* _TOOLS_LINUX_COMPILER_H */
diff --git a/tools/virtio/linux/export.h b/tools/include/linux/export.h
index 7311d326894a..d07e586b9ba0 100644
--- a/tools/virtio/linux/export.h
+++ b/tools/include/linux/export.h
@@ -1,5 +1,10 @@
1#ifndef _TOOLS_LINUX_EXPORT_H_
2#define _TOOLS_LINUX_EXPORT_H_
3
1#define EXPORT_SYMBOL(sym) 4#define EXPORT_SYMBOL(sym)
2#define EXPORT_SYMBOL_GPL(sym) 5#define EXPORT_SYMBOL_GPL(sym)
3#define EXPORT_SYMBOL_GPL_FUTURE(sym) 6#define EXPORT_SYMBOL_GPL_FUTURE(sym)
4#define EXPORT_UNUSED_SYMBOL(sym) 7#define EXPORT_UNUSED_SYMBOL(sym)
5#define EXPORT_UNUSED_SYMBOL_GPL(sym) 8#define EXPORT_UNUSED_SYMBOL_GPL(sym)
9
10#endif
diff --git a/tools/lib/lockdep/uinclude/linux/types.h b/tools/include/linux/types.h
index 929938f426de..b5cf25e05df2 100644
--- a/tools/lib/lockdep/uinclude/linux/types.h
+++ b/tools/include/linux/types.h
@@ -1,8 +1,9 @@
1#ifndef _LIBLOCKDEP_LINUX_TYPES_H_ 1#ifndef _TOOLS_LINUX_TYPES_H_
2#define _LIBLOCKDEP_LINUX_TYPES_H_ 2#define _TOOLS_LINUX_TYPES_H_
3 3
4#include <stdbool.h> 4#include <stdbool.h>
5#include <stddef.h> 5#include <stddef.h>
6#include <stdint.h>
6 7
7#define __SANE_USERSPACE_TYPES__ /* For PPC64, to get LL64 types */ 8#define __SANE_USERSPACE_TYPES__ /* For PPC64, to get LL64 types */
8#include <asm/types.h> 9#include <asm/types.h>
@@ -10,10 +11,22 @@
10struct page; 11struct page;
11struct kmem_cache; 12struct kmem_cache;
12 13
13typedef unsigned gfp_t; 14typedef enum {
15 GFP_KERNEL,
16 GFP_ATOMIC,
17 __GFP_HIGHMEM,
18 __GFP_HIGH
19} gfp_t;
14 20
15typedef __u64 u64; 21/*
16typedef __s64 s64; 22 * We define u64 as uint64_t for every architecture
23 * so that we can print it with "%"PRIx64 without getting warnings.
24 *
25 * typedef __u64 u64;
26 * typedef __s64 s64;
27 */
28typedef uint64_t u64;
29typedef int64_t s64;
17 30
18typedef __u32 u32; 31typedef __u32 u32;
19typedef __s32 s32; 32typedef __s32 s32;
@@ -35,6 +48,10 @@ typedef __s8 s8;
35#define __bitwise 48#define __bitwise
36#endif 49#endif
37 50
51#define __force
52#define __user
53#define __must_check
54#define __cold
38 55
39typedef __u16 __bitwise __le16; 56typedef __u16 __bitwise __le16;
40typedef __u16 __bitwise __be16; 57typedef __u16 __bitwise __be16;
@@ -55,4 +72,4 @@ struct hlist_node {
55 struct hlist_node *next, **pprev; 72 struct hlist_node *next, **pprev;
56}; 73};
57 74
58#endif 75#endif /* _TOOLS_LINUX_TYPES_H_ */
diff --git a/tools/lib/api/fs/fs.c b/tools/lib/api/fs/fs.c
index 5b5eb788996e..c1b49c36a951 100644
--- a/tools/lib/api/fs/fs.c
+++ b/tools/lib/api/fs/fs.c
@@ -1,8 +1,10 @@
1/* TODO merge/factor in debugfs.c here */ 1/* TODO merge/factor in debugfs.c here */
2 2
3#include <ctype.h>
3#include <errno.h> 4#include <errno.h>
4#include <stdbool.h> 5#include <stdbool.h>
5#include <stdio.h> 6#include <stdio.h>
7#include <stdlib.h>
6#include <string.h> 8#include <string.h>
7#include <sys/vfs.h> 9#include <sys/vfs.h>
8 10
@@ -96,12 +98,51 @@ static bool fs__check_mounts(struct fs *fs)
96 return false; 98 return false;
97} 99}
98 100
101static void mem_toupper(char *f, size_t len)
102{
103 while (len) {
104 *f = toupper(*f);
105 f++;
106 len--;
107 }
108}
109
110/*
111 * Check for "NAME_PATH" environment variable to override fs location (for
112 * testing). This matches the recommendation in Documentation/sysfs-rules.txt
113 * for SYSFS_PATH.
114 */
115static bool fs__env_override(struct fs *fs)
116{
117 char *override_path;
118 size_t name_len = strlen(fs->name);
119 /* name + "_PATH" + '\0' */
120 char upper_name[name_len + 5 + 1];
121 memcpy(upper_name, fs->name, name_len);
122 mem_toupper(upper_name, name_len);
123 strcpy(&upper_name[name_len], "_PATH");
124
125 override_path = getenv(upper_name);
126 if (!override_path)
127 return false;
128
129 fs->found = true;
130 strncpy(fs->path, override_path, sizeof(fs->path));
131 return true;
132}
133
99static const char *fs__get_mountpoint(struct fs *fs) 134static const char *fs__get_mountpoint(struct fs *fs)
100{ 135{
136 if (fs__env_override(fs))
137 return fs->path;
138
101 if (fs__check_mounts(fs)) 139 if (fs__check_mounts(fs))
102 return fs->path; 140 return fs->path;
103 141
104 return fs__read_mounts(fs) ? fs->path : NULL; 142 if (fs__read_mounts(fs))
143 return fs->path;
144
145 return NULL;
105} 146}
106 147
107static const char *fs__mountpoint(int idx) 148static const char *fs__mountpoint(int idx)
diff --git a/tools/lib/lockdep/Makefile b/tools/lib/lockdep/Makefile
index cb09d3ff8f58..52f9279c6c13 100644
--- a/tools/lib/lockdep/Makefile
+++ b/tools/lib/lockdep/Makefile
@@ -1,8 +1,7 @@
1# file format version 1# file format version
2FILE_VERSION = 1 2FILE_VERSION = 1
3 3
4MAKEFLAGS += --no-print-directory 4LIBLOCKDEP_VERSION=$(shell make --no-print-directory -sC ../../.. kernelversion)
5LIBLOCKDEP_VERSION=$(shell make -sC ../../.. kernelversion)
6 5
7# Makefiles suck: This macro sets a default value of $(2) for the 6# Makefiles suck: This macro sets a default value of $(2) for the
8# variable named by $(1), unless the variable has been set by 7# variable named by $(1), unless the variable has been set by
@@ -105,7 +104,7 @@ N =
105 104
106export Q VERBOSE 105export Q VERBOSE
107 106
108INCLUDES = -I. -I/usr/local/include -I./uinclude -I./include $(CONFIG_INCLUDES) 107INCLUDES = -I. -I/usr/local/include -I./uinclude -I./include -I../../include $(CONFIG_INCLUDES)
109 108
110# Set compile option CFLAGS if not set elsewhere 109# Set compile option CFLAGS if not set elsewhere
111CFLAGS ?= -g -DCONFIG_LOCKDEP -DCONFIG_STACKTRACE -DCONFIG_PROVE_LOCKING -DBITS_PER_LONG=__WORDSIZE -DLIBLOCKDEP_VERSION='"$(LIBLOCKDEP_VERSION)"' -rdynamic -O0 -g 110CFLAGS ?= -g -DCONFIG_LOCKDEP -DCONFIG_STACKTRACE -DCONFIG_PROVE_LOCKING -DBITS_PER_LONG=__WORDSIZE -DLIBLOCKDEP_VERSION='"$(LIBLOCKDEP_VERSION)"' -rdynamic -O0 -g
@@ -231,7 +230,7 @@ install_lib: all_cmd
231install: install_lib 230install: install_lib
232 231
233clean: 232clean:
234 $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d 233 $(RM) *.o *~ $(TARGETS) *.a *liblockdep*.so* $(VERSION_FILES) .*.d
235 $(RM) tags TAGS 234 $(RM) tags TAGS
236 235
237endif # skip-makefile 236endif # skip-makefile
diff --git a/tools/lib/lockdep/uinclude/linux/export.h b/tools/lib/lockdep/uinclude/linux/export.h
deleted file mode 100644
index 6bdf3492c535..000000000000
--- a/tools/lib/lockdep/uinclude/linux/export.h
+++ /dev/null
@@ -1,7 +0,0 @@
1#ifndef _LIBLOCKDEP_LINUX_EXPORT_H_
2#define _LIBLOCKDEP_LINUX_EXPORT_H_
3
4#define EXPORT_SYMBOL(sym)
5#define EXPORT_SYMBOL_GPL(sym)
6
7#endif
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c
index b83184f2d484..93825a17dcce 100644
--- a/tools/lib/traceevent/event-parse.c
+++ b/tools/lib/traceevent/event-parse.c
@@ -765,6 +765,9 @@ static void free_arg(struct print_arg *arg)
765 case PRINT_BSTRING: 765 case PRINT_BSTRING:
766 free(arg->string.string); 766 free(arg->string.string);
767 break; 767 break;
768 case PRINT_BITMASK:
769 free(arg->bitmask.bitmask);
770 break;
768 case PRINT_DYNAMIC_ARRAY: 771 case PRINT_DYNAMIC_ARRAY:
769 free(arg->dynarray.index); 772 free(arg->dynarray.index);
770 break; 773 break;
@@ -2268,6 +2271,7 @@ static int arg_num_eval(struct print_arg *arg, long long *val)
2268 case PRINT_FIELD ... PRINT_SYMBOL: 2271 case PRINT_FIELD ... PRINT_SYMBOL:
2269 case PRINT_STRING: 2272 case PRINT_STRING:
2270 case PRINT_BSTRING: 2273 case PRINT_BSTRING:
2274 case PRINT_BITMASK:
2271 default: 2275 default:
2272 do_warning("invalid eval type %d", arg->type); 2276 do_warning("invalid eval type %d", arg->type);
2273 ret = 0; 2277 ret = 0;
@@ -2296,6 +2300,7 @@ static char *arg_eval (struct print_arg *arg)
2296 case PRINT_FIELD ... PRINT_SYMBOL: 2300 case PRINT_FIELD ... PRINT_SYMBOL:
2297 case PRINT_STRING: 2301 case PRINT_STRING:
2298 case PRINT_BSTRING: 2302 case PRINT_BSTRING:
2303 case PRINT_BITMASK:
2299 default: 2304 default:
2300 do_warning("invalid eval type %d", arg->type); 2305 do_warning("invalid eval type %d", arg->type);
2301 break; 2306 break;
@@ -2683,6 +2688,35 @@ process_str(struct event_format *event __maybe_unused, struct print_arg *arg,
2683 return EVENT_ERROR; 2688 return EVENT_ERROR;
2684} 2689}
2685 2690
2691static enum event_type
2692process_bitmask(struct event_format *event __maybe_unused, struct print_arg *arg,
2693 char **tok)
2694{
2695 enum event_type type;
2696 char *token;
2697
2698 if (read_expect_type(EVENT_ITEM, &token) < 0)
2699 goto out_free;
2700
2701 arg->type = PRINT_BITMASK;
2702 arg->bitmask.bitmask = token;
2703 arg->bitmask.offset = -1;
2704
2705 if (read_expected(EVENT_DELIM, ")") < 0)
2706 goto out_err;
2707
2708 type = read_token(&token);
2709 *tok = token;
2710
2711 return type;
2712
2713 out_free:
2714 free_token(token);
2715 out_err:
2716 *tok = NULL;
2717 return EVENT_ERROR;
2718}
2719
2686static struct pevent_function_handler * 2720static struct pevent_function_handler *
2687find_func_handler(struct pevent *pevent, char *func_name) 2721find_func_handler(struct pevent *pevent, char *func_name)
2688{ 2722{
@@ -2797,6 +2831,10 @@ process_function(struct event_format *event, struct print_arg *arg,
2797 free_token(token); 2831 free_token(token);
2798 return process_str(event, arg, tok); 2832 return process_str(event, arg, tok);
2799 } 2833 }
2834 if (strcmp(token, "__get_bitmask") == 0) {
2835 free_token(token);
2836 return process_bitmask(event, arg, tok);
2837 }
2800 if (strcmp(token, "__get_dynamic_array") == 0) { 2838 if (strcmp(token, "__get_dynamic_array") == 0) {
2801 free_token(token); 2839 free_token(token);
2802 return process_dynamic_array(event, arg, tok); 2840 return process_dynamic_array(event, arg, tok);
@@ -3324,6 +3362,7 @@ eval_num_arg(void *data, int size, struct event_format *event, struct print_arg
3324 return eval_type(val, arg, 0); 3362 return eval_type(val, arg, 0);
3325 case PRINT_STRING: 3363 case PRINT_STRING:
3326 case PRINT_BSTRING: 3364 case PRINT_BSTRING:
3365 case PRINT_BITMASK:
3327 return 0; 3366 return 0;
3328 case PRINT_FUNC: { 3367 case PRINT_FUNC: {
3329 struct trace_seq s; 3368 struct trace_seq s;
@@ -3556,6 +3595,60 @@ static void print_str_to_seq(struct trace_seq *s, const char *format,
3556 trace_seq_printf(s, format, str); 3595 trace_seq_printf(s, format, str);
3557} 3596}
3558 3597
3598static void print_bitmask_to_seq(struct pevent *pevent,
3599 struct trace_seq *s, const char *format,
3600 int len_arg, const void *data, int size)
3601{
3602 int nr_bits = size * 8;
3603 int str_size = (nr_bits + 3) / 4;
3604 int len = 0;
3605 char buf[3];
3606 char *str;
3607 int index;
3608 int i;
3609
3610 /*
3611 * The kernel likes to put in commas every 32 bits, we
3612 * can do the same.
3613 */
3614 str_size += (nr_bits - 1) / 32;
3615
3616 str = malloc(str_size + 1);
3617 if (!str) {
3618 do_warning("%s: not enough memory!", __func__);
3619 return;
3620 }
3621 str[str_size] = 0;
3622
3623 /* Start out with -2 for the two chars per byte */
3624 for (i = str_size - 2; i >= 0; i -= 2) {
3625 /*
3626 * data points to a bit mask of size bytes.
3627 * In the kernel, this is an array of long words, thus
3628 * endianess is very important.
3629 */
3630 if (pevent->file_bigendian)
3631 index = size - (len + 1);
3632 else
3633 index = len;
3634
3635 snprintf(buf, 3, "%02x", *((unsigned char *)data + index));
3636 memcpy(str + i, buf, 2);
3637 len++;
3638 if (!(len & 3) && i > 0) {
3639 i--;
3640 str[i] = ',';
3641 }
3642 }
3643
3644 if (len_arg >= 0)
3645 trace_seq_printf(s, format, len_arg, str);
3646 else
3647 trace_seq_printf(s, format, str);
3648
3649 free(str);
3650}
3651
3559static void print_str_arg(struct trace_seq *s, void *data, int size, 3652static void print_str_arg(struct trace_seq *s, void *data, int size,
3560 struct event_format *event, const char *format, 3653 struct event_format *event, const char *format,
3561 int len_arg, struct print_arg *arg) 3654 int len_arg, struct print_arg *arg)
@@ -3691,6 +3784,23 @@ static void print_str_arg(struct trace_seq *s, void *data, int size,
3691 case PRINT_BSTRING: 3784 case PRINT_BSTRING:
3692 print_str_to_seq(s, format, len_arg, arg->string.string); 3785 print_str_to_seq(s, format, len_arg, arg->string.string);
3693 break; 3786 break;
3787 case PRINT_BITMASK: {
3788 int bitmask_offset;
3789 int bitmask_size;
3790
3791 if (arg->bitmask.offset == -1) {
3792 struct format_field *f;
3793
3794 f = pevent_find_any_field(event, arg->bitmask.bitmask);
3795 arg->bitmask.offset = f->offset;
3796 }
3797 bitmask_offset = data2host4(pevent, data + arg->bitmask.offset);
3798 bitmask_size = bitmask_offset >> 16;
3799 bitmask_offset &= 0xffff;
3800 print_bitmask_to_seq(pevent, s, format, len_arg,
3801 data + bitmask_offset, bitmask_size);
3802 break;
3803 }
3694 case PRINT_OP: 3804 case PRINT_OP:
3695 /* 3805 /*
3696 * The only op for string should be ? : 3806 * The only op for string should be ? :
@@ -4822,6 +4932,9 @@ static void print_args(struct print_arg *args)
4822 case PRINT_BSTRING: 4932 case PRINT_BSTRING:
4823 printf("__get_str(%s)", args->string.string); 4933 printf("__get_str(%s)", args->string.string);
4824 break; 4934 break;
4935 case PRINT_BITMASK:
4936 printf("__get_bitmask(%s)", args->bitmask.bitmask);
4937 break;
4825 case PRINT_TYPE: 4938 case PRINT_TYPE:
4826 printf("(%s)", args->typecast.type); 4939 printf("(%s)", args->typecast.type);
4827 print_args(args->typecast.item); 4940 print_args(args->typecast.item);
diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h
index feab94281634..7a3873ff9a4f 100644
--- a/tools/lib/traceevent/event-parse.h
+++ b/tools/lib/traceevent/event-parse.h
@@ -107,8 +107,8 @@ typedef int (*pevent_event_handler_func)(struct trace_seq *s,
107typedef int (*pevent_plugin_load_func)(struct pevent *pevent); 107typedef int (*pevent_plugin_load_func)(struct pevent *pevent);
108typedef int (*pevent_plugin_unload_func)(struct pevent *pevent); 108typedef int (*pevent_plugin_unload_func)(struct pevent *pevent);
109 109
110struct plugin_option { 110struct pevent_plugin_option {
111 struct plugin_option *next; 111 struct pevent_plugin_option *next;
112 void *handle; 112 void *handle;
113 char *file; 113 char *file;
114 char *name; 114 char *name;
@@ -135,7 +135,7 @@ struct plugin_option {
135 * PEVENT_PLUGIN_OPTIONS: (optional) 135 * PEVENT_PLUGIN_OPTIONS: (optional)
136 * Plugin options that can be set before loading 136 * Plugin options that can be set before loading
137 * 137 *
138 * struct plugin_option PEVENT_PLUGIN_OPTIONS[] = { 138 * struct pevent_plugin_option PEVENT_PLUGIN_OPTIONS[] = {
139 * { 139 * {
140 * .name = "option-name", 140 * .name = "option-name",
141 * .plugin_alias = "overide-file-name", (optional) 141 * .plugin_alias = "overide-file-name", (optional)
@@ -208,6 +208,11 @@ struct print_arg_string {
208 int offset; 208 int offset;
209}; 209};
210 210
211struct print_arg_bitmask {
212 char *bitmask;
213 int offset;
214};
215
211struct print_arg_field { 216struct print_arg_field {
212 char *name; 217 char *name;
213 struct format_field *field; 218 struct format_field *field;
@@ -274,6 +279,7 @@ enum print_arg_type {
274 PRINT_DYNAMIC_ARRAY, 279 PRINT_DYNAMIC_ARRAY,
275 PRINT_OP, 280 PRINT_OP,
276 PRINT_FUNC, 281 PRINT_FUNC,
282 PRINT_BITMASK,
277}; 283};
278 284
279struct print_arg { 285struct print_arg {
@@ -288,6 +294,7 @@ struct print_arg {
288 struct print_arg_hex hex; 294 struct print_arg_hex hex;
289 struct print_arg_func func; 295 struct print_arg_func func;
290 struct print_arg_string string; 296 struct print_arg_string string;
297 struct print_arg_bitmask bitmask;
291 struct print_arg_op op; 298 struct print_arg_op op;
292 struct print_arg_dynarray dynarray; 299 struct print_arg_dynarray dynarray;
293 }; 300 };
@@ -354,6 +361,8 @@ enum pevent_func_arg_type {
354 361
355enum pevent_flag { 362enum pevent_flag {
356 PEVENT_NSEC_OUTPUT = 1, /* output in NSECS */ 363 PEVENT_NSEC_OUTPUT = 1, /* output in NSECS */
364 PEVENT_DISABLE_SYS_PLUGINS = 1 << 1,
365 PEVENT_DISABLE_PLUGINS = 1 << 2,
357}; 366};
358 367
359#define PEVENT_ERRORS \ 368#define PEVENT_ERRORS \
@@ -410,9 +419,19 @@ enum pevent_errno {
410 419
411struct plugin_list; 420struct plugin_list;
412 421
422#define INVALID_PLUGIN_LIST_OPTION ((char **)((unsigned long)-1))
423
413struct plugin_list *traceevent_load_plugins(struct pevent *pevent); 424struct plugin_list *traceevent_load_plugins(struct pevent *pevent);
414void traceevent_unload_plugins(struct plugin_list *plugin_list, 425void traceevent_unload_plugins(struct plugin_list *plugin_list,
415 struct pevent *pevent); 426 struct pevent *pevent);
427char **traceevent_plugin_list_options(void);
428void traceevent_plugin_free_options_list(char **list);
429int traceevent_plugin_add_options(const char *name,
430 struct pevent_plugin_option *options);
431void traceevent_plugin_remove_options(struct pevent_plugin_option *options);
432void traceevent_print_plugins(struct trace_seq *s,
433 const char *prefix, const char *suffix,
434 const struct plugin_list *list);
416 435
417struct cmdline; 436struct cmdline;
418struct cmdline_list; 437struct cmdline_list;
diff --git a/tools/lib/traceevent/event-plugin.c b/tools/lib/traceevent/event-plugin.c
index 0c8bf6780e4d..136162c03af1 100644
--- a/tools/lib/traceevent/event-plugin.c
+++ b/tools/lib/traceevent/event-plugin.c
@@ -18,6 +18,7 @@
18 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 18 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
19 */ 19 */
20 20
21#include <stdio.h>
21#include <string.h> 22#include <string.h>
22#include <dlfcn.h> 23#include <dlfcn.h>
23#include <stdlib.h> 24#include <stdlib.h>
@@ -30,12 +31,207 @@
30 31
31#define LOCAL_PLUGIN_DIR ".traceevent/plugins" 32#define LOCAL_PLUGIN_DIR ".traceevent/plugins"
32 33
34static struct registered_plugin_options {
35 struct registered_plugin_options *next;
36 struct pevent_plugin_option *options;
37} *registered_options;
38
39static struct trace_plugin_options {
40 struct trace_plugin_options *next;
41 char *plugin;
42 char *option;
43 char *value;
44} *trace_plugin_options;
45
33struct plugin_list { 46struct plugin_list {
34 struct plugin_list *next; 47 struct plugin_list *next;
35 char *name; 48 char *name;
36 void *handle; 49 void *handle;
37}; 50};
38 51
52/**
53 * traceevent_plugin_list_options - get list of plugin options
54 *
55 * Returns an array of char strings that list the currently registered
56 * plugin options in the format of <plugin>:<option>. This list can be
57 * used by toggling the option.
58 *
59 * Returns NULL if there's no options registered. On error it returns
60 * INVALID_PLUGIN_LIST_OPTION
61 *
62 * Must be freed with traceevent_plugin_free_options_list().
63 */
64char **traceevent_plugin_list_options(void)
65{
66 struct registered_plugin_options *reg;
67 struct pevent_plugin_option *op;
68 char **list = NULL;
69 char *name;
70 int count = 0;
71
72 for (reg = registered_options; reg; reg = reg->next) {
73 for (op = reg->options; op->name; op++) {
74 char *alias = op->plugin_alias ? op->plugin_alias : op->file;
75 char **temp = list;
76
77 name = malloc(strlen(op->name) + strlen(alias) + 2);
78 if (!name)
79 goto err;
80
81 sprintf(name, "%s:%s", alias, op->name);
82 list = realloc(list, count + 2);
83 if (!list) {
84 list = temp;
85 free(name);
86 goto err;
87 }
88 list[count++] = name;
89 list[count] = NULL;
90 }
91 }
92 return list;
93
94 err:
95 while (--count >= 0)
96 free(list[count]);
97 free(list);
98
99 return INVALID_PLUGIN_LIST_OPTION;
100}
101
102void traceevent_plugin_free_options_list(char **list)
103{
104 int i;
105
106 if (!list)
107 return;
108
109 if (list == INVALID_PLUGIN_LIST_OPTION)
110 return;
111
112 for (i = 0; list[i]; i++)
113 free(list[i]);
114
115 free(list);
116}
117
118static int
119update_option(const char *file, struct pevent_plugin_option *option)
120{
121 struct trace_plugin_options *op;
122 char *plugin;
123
124 if (option->plugin_alias) {
125 plugin = strdup(option->plugin_alias);
126 if (!plugin)
127 return -1;
128 } else {
129 char *p;
130 plugin = strdup(file);
131 if (!plugin)
132 return -1;
133 p = strstr(plugin, ".");
134 if (p)
135 *p = '\0';
136 }
137
138 /* first look for named options */
139 for (op = trace_plugin_options; op; op = op->next) {
140 if (!op->plugin)
141 continue;
142 if (strcmp(op->plugin, plugin) != 0)
143 continue;
144 if (strcmp(op->option, option->name) != 0)
145 continue;
146
147 option->value = op->value;
148 option->set ^= 1;
149 goto out;
150 }
151
152 /* first look for unnamed options */
153 for (op = trace_plugin_options; op; op = op->next) {
154 if (op->plugin)
155 continue;
156 if (strcmp(op->option, option->name) != 0)
157 continue;
158
159 option->value = op->value;
160 option->set ^= 1;
161 break;
162 }
163
164 out:
165 free(plugin);
166 return 0;
167}
168
169/**
170 * traceevent_plugin_add_options - Add a set of options by a plugin
171 * @name: The name of the plugin adding the options
172 * @options: The set of options being loaded
173 *
174 * Sets the options with the values that have been added by user.
175 */
176int traceevent_plugin_add_options(const char *name,
177 struct pevent_plugin_option *options)
178{
179 struct registered_plugin_options *reg;
180
181 reg = malloc(sizeof(*reg));
182 if (!reg)
183 return -1;
184 reg->next = registered_options;
185 reg->options = options;
186 registered_options = reg;
187
188 while (options->name) {
189 update_option(name, options);
190 options++;
191 }
192 return 0;
193}
194
195/**
196 * traceevent_plugin_remove_options - remove plugin options that were registered
197 * @options: Options to removed that were registered with traceevent_plugin_add_options
198 */
199void traceevent_plugin_remove_options(struct pevent_plugin_option *options)
200{
201 struct registered_plugin_options **last;
202 struct registered_plugin_options *reg;
203
204 for (last = &registered_options; *last; last = &(*last)->next) {
205 if ((*last)->options == options) {
206 reg = *last;
207 *last = reg->next;
208 free(reg);
209 return;
210 }
211 }
212}
213
214/**
215 * traceevent_print_plugins - print out the list of plugins loaded
216 * @s: the trace_seq descripter to write to
217 * @prefix: The prefix string to add before listing the option name
218 * @suffix: The suffix string ot append after the option name
219 * @list: The list of plugins (usually returned by traceevent_load_plugins()
220 *
221 * Writes to the trace_seq @s the list of plugins (files) that is
222 * returned by traceevent_load_plugins(). Use @prefix and @suffix for formating:
223 * @prefix = " ", @suffix = "\n".
224 */
225void traceevent_print_plugins(struct trace_seq *s,
226 const char *prefix, const char *suffix,
227 const struct plugin_list *list)
228{
229 while (list) {
230 trace_seq_printf(s, "%s%s%s", prefix, list->name, suffix);
231 list = list->next;
232 }
233}
234
39static void 235static void
40load_plugin(struct pevent *pevent, const char *path, 236load_plugin(struct pevent *pevent, const char *path,
41 const char *file, void *data) 237 const char *file, void *data)
@@ -148,12 +344,17 @@ load_plugins(struct pevent *pevent, const char *suffix,
148 char *path; 344 char *path;
149 char *envdir; 345 char *envdir;
150 346
347 if (pevent->flags & PEVENT_DISABLE_PLUGINS)
348 return;
349
151 /* 350 /*
152 * If a system plugin directory was defined, 351 * If a system plugin directory was defined,
153 * check that first. 352 * check that first.
154 */ 353 */
155#ifdef PLUGIN_DIR 354#ifdef PLUGIN_DIR
156 load_plugins_dir(pevent, suffix, PLUGIN_DIR, load_plugin, data); 355 if (!(pevent->flags & PEVENT_DISABLE_SYS_PLUGINS))
356 load_plugins_dir(pevent, suffix, PLUGIN_DIR,
357 load_plugin, data);
157#endif 358#endif
158 359
159 /* 360 /*
diff --git a/tools/lib/traceevent/plugin_function.c b/tools/lib/traceevent/plugin_function.c
index 80ba4ff1fe84..a00ec190821a 100644
--- a/tools/lib/traceevent/plugin_function.c
+++ b/tools/lib/traceevent/plugin_function.c
@@ -33,6 +33,29 @@ static int cpus = -1;
33 33
34#define STK_BLK 10 34#define STK_BLK 10
35 35
36struct pevent_plugin_option plugin_options[] =
37{
38 {
39 .name = "parent",
40 .plugin_alias = "ftrace",
41 .description =
42 "Print parent of functions for function events",
43 },
44 {
45 .name = "indent",
46 .plugin_alias = "ftrace",
47 .description =
48 "Try to show function call indents, based on parents",
49 .set = 1,
50 },
51 {
52 .name = NULL,
53 }
54};
55
56static struct pevent_plugin_option *ftrace_parent = &plugin_options[0];
57static struct pevent_plugin_option *ftrace_indent = &plugin_options[1];
58
36static void add_child(struct func_stack *stack, const char *child, int pos) 59static void add_child(struct func_stack *stack, const char *child, int pos)
37{ 60{
38 int i; 61 int i;
@@ -119,7 +142,8 @@ static int function_handler(struct trace_seq *s, struct pevent_record *record,
119 142
120 parent = pevent_find_function(pevent, pfunction); 143 parent = pevent_find_function(pevent, pfunction);
121 144
122 index = add_and_get_index(parent, func, record->cpu); 145 if (parent && ftrace_indent->set)
146 index = add_and_get_index(parent, func, record->cpu);
123 147
124 trace_seq_printf(s, "%*s", index*3, ""); 148 trace_seq_printf(s, "%*s", index*3, "");
125 149
@@ -128,11 +152,13 @@ static int function_handler(struct trace_seq *s, struct pevent_record *record,
128 else 152 else
129 trace_seq_printf(s, "0x%llx", function); 153 trace_seq_printf(s, "0x%llx", function);
130 154
131 trace_seq_printf(s, " <-- "); 155 if (ftrace_parent->set) {
132 if (parent) 156 trace_seq_printf(s, " <-- ");
133 trace_seq_printf(s, "%s", parent); 157 if (parent)
134 else 158 trace_seq_printf(s, "%s", parent);
135 trace_seq_printf(s, "0x%llx", pfunction); 159 else
160 trace_seq_printf(s, "0x%llx", pfunction);
161 }
136 162
137 return 0; 163 return 0;
138} 164}
@@ -141,6 +167,9 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
141{ 167{
142 pevent_register_event_handler(pevent, -1, "ftrace", "function", 168 pevent_register_event_handler(pevent, -1, "ftrace", "function",
143 function_handler, NULL); 169 function_handler, NULL);
170
171 traceevent_plugin_add_options("ftrace", plugin_options);
172
144 return 0; 173 return 0;
145} 174}
146 175
@@ -157,6 +186,8 @@ void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
157 free(fstack[i].stack); 186 free(fstack[i].stack);
158 } 187 }
159 188
189 traceevent_plugin_remove_options(plugin_options);
190
160 free(fstack); 191 free(fstack);
161 fstack = NULL; 192 fstack = NULL;
162 cpus = -1; 193 cpus = -1;
diff --git a/tools/net/bpf_exp.l b/tools/net/bpf_exp.l
index bf7be77ddd62..833a96611da6 100644
--- a/tools/net/bpf_exp.l
+++ b/tools/net/bpf_exp.l
@@ -92,6 +92,7 @@ extern void yyerror(const char *str);
92"#"?("cpu") { return K_CPU; } 92"#"?("cpu") { return K_CPU; }
93"#"?("vlan_tci") { return K_VLANT; } 93"#"?("vlan_tci") { return K_VLANT; }
94"#"?("vlan_pr") { return K_VLANP; } 94"#"?("vlan_pr") { return K_VLANP; }
95"#"?("rand") { return K_RAND; }
95 96
96":" { return ':'; } 97":" { return ':'; }
97"," { return ','; } 98"," { return ','; }
diff --git a/tools/net/bpf_exp.y b/tools/net/bpf_exp.y
index d15efc989ef5..e6306c51c26f 100644
--- a/tools/net/bpf_exp.y
+++ b/tools/net/bpf_exp.y
@@ -56,7 +56,7 @@ static void bpf_set_jmp_label(char *label, enum jmp_type type);
56%token OP_LDXI 56%token OP_LDXI
57 57
58%token K_PKT_LEN K_PROTO K_TYPE K_NLATTR K_NLATTR_NEST K_MARK K_QUEUE K_HATYPE 58%token K_PKT_LEN K_PROTO K_TYPE K_NLATTR K_NLATTR_NEST K_MARK K_QUEUE K_HATYPE
59%token K_RXHASH K_CPU K_IFIDX K_VLANT K_VLANP K_POFF 59%token K_RXHASH K_CPU K_IFIDX K_VLANT K_VLANP K_POFF K_RAND
60 60
61%token ':' ',' '[' ']' '(' ')' 'x' 'a' '+' 'M' '*' '&' '#' '%' 61%token ':' ',' '[' ']' '(' ')' 'x' 'a' '+' 'M' '*' '&' '#' '%'
62 62
@@ -164,6 +164,9 @@ ldb
164 | OP_LDB K_POFF { 164 | OP_LDB K_POFF {
165 bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, 165 bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
166 SKF_AD_OFF + SKF_AD_PAY_OFFSET); } 166 SKF_AD_OFF + SKF_AD_PAY_OFFSET); }
167 | OP_LDB K_RAND {
168 bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
169 SKF_AD_OFF + SKF_AD_RANDOM); }
167 ; 170 ;
168 171
169ldh 172ldh
@@ -212,6 +215,9 @@ ldh
212 | OP_LDH K_POFF { 215 | OP_LDH K_POFF {
213 bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, 216 bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
214 SKF_AD_OFF + SKF_AD_PAY_OFFSET); } 217 SKF_AD_OFF + SKF_AD_PAY_OFFSET); }
218 | OP_LDH K_RAND {
219 bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
220 SKF_AD_OFF + SKF_AD_RANDOM); }
215 ; 221 ;
216 222
217ldi 223ldi
@@ -265,6 +271,9 @@ ld
265 | OP_LD K_POFF { 271 | OP_LD K_POFF {
266 bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, 272 bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
267 SKF_AD_OFF + SKF_AD_PAY_OFFSET); } 273 SKF_AD_OFF + SKF_AD_PAY_OFFSET); }
274 | OP_LD K_RAND {
275 bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
276 SKF_AD_OFF + SKF_AD_RANDOM); }
268 | OP_LD 'M' '[' number ']' { 277 | OP_LD 'M' '[' number ']' {
269 bpf_set_curr_instr(BPF_LD | BPF_MEM, 0, 0, $4); } 278 bpf_set_curr_instr(BPF_LD | BPF_MEM, 0, 0, $4); }
270 | OP_LD '[' 'x' '+' number ']' { 279 | OP_LD '[' 'x' '+' number ']' {
diff --git a/tools/net/bpf_jit_disasm.c b/tools/net/bpf_jit_disasm.c
index cfe0cdcda3de..c5baf9c591b7 100644
--- a/tools/net/bpf_jit_disasm.c
+++ b/tools/net/bpf_jit_disasm.c
@@ -43,8 +43,7 @@ static void get_exec_path(char *tpath, size_t size)
43 free(path); 43 free(path);
44} 44}
45 45
46static void get_asm_insns(uint8_t *image, size_t len, unsigned long base, 46static void get_asm_insns(uint8_t *image, size_t len, int opcodes)
47 int opcodes)
48{ 47{
49 int count, i, pc = 0; 48 int count, i, pc = 0;
50 char tpath[256]; 49 char tpath[256];
@@ -107,13 +106,13 @@ static void put_klog_buff(char *buff)
107} 106}
108 107
109static int get_last_jit_image(char *haystack, size_t hlen, 108static int get_last_jit_image(char *haystack, size_t hlen,
110 uint8_t *image, size_t ilen, 109 uint8_t *image, size_t ilen)
111 unsigned long *base)
112{ 110{
113 char *ptr, *pptr, *tmp; 111 char *ptr, *pptr, *tmp;
114 off_t off = 0; 112 off_t off = 0;
115 int ret, flen, proglen, pass, ulen = 0; 113 int ret, flen, proglen, pass, ulen = 0;
116 regmatch_t pmatch[1]; 114 regmatch_t pmatch[1];
115 unsigned long base;
117 regex_t regex; 116 regex_t regex;
118 117
119 if (hlen == 0) 118 if (hlen == 0)
@@ -136,7 +135,7 @@ static int get_last_jit_image(char *haystack, size_t hlen,
136 135
137 ptr = haystack + off - (pmatch[0].rm_eo - pmatch[0].rm_so); 136 ptr = haystack + off - (pmatch[0].rm_eo - pmatch[0].rm_so);
138 ret = sscanf(ptr, "flen=%d proglen=%d pass=%d image=%lx", 137 ret = sscanf(ptr, "flen=%d proglen=%d pass=%d image=%lx",
139 &flen, &proglen, &pass, base); 138 &flen, &proglen, &pass, &base);
140 if (ret != 4) 139 if (ret != 4)
141 return 0; 140 return 0;
142 141
@@ -162,7 +161,7 @@ static int get_last_jit_image(char *haystack, size_t hlen,
162 assert(ulen == proglen); 161 assert(ulen == proglen);
163 printf("%d bytes emitted from JIT compiler (pass:%d, flen:%d)\n", 162 printf("%d bytes emitted from JIT compiler (pass:%d, flen:%d)\n",
164 proglen, pass, flen); 163 proglen, pass, flen);
165 printf("%lx + <x>:\n", *base); 164 printf("%lx + <x>:\n", base);
166 165
167 regfree(&regex); 166 regfree(&regex);
168 return ulen; 167 return ulen;
@@ -172,8 +171,7 @@ int main(int argc, char **argv)
172{ 171{
173 int len, klen, opcodes = 0; 172 int len, klen, opcodes = 0;
174 char *kbuff; 173 char *kbuff;
175 unsigned long base; 174 static uint8_t image[32768];
176 uint8_t image[4096];
177 175
178 if (argc > 1) { 176 if (argc > 1) {
179 if (!strncmp("-o", argv[argc - 1], 2)) { 177 if (!strncmp("-o", argv[argc - 1], 2)) {
@@ -189,9 +187,9 @@ int main(int argc, char **argv)
189 187
190 kbuff = get_klog_buff(&klen); 188 kbuff = get_klog_buff(&klen);
191 189
192 len = get_last_jit_image(kbuff, klen, image, sizeof(image), &base); 190 len = get_last_jit_image(kbuff, klen, image, sizeof(image));
193 if (len > 0 && base > 0) 191 if (len > 0)
194 get_asm_insns(image, len, base, opcodes); 192 get_asm_insns(image, len, opcodes);
195 193
196 put_klog_buff(kbuff); 194 put_klog_buff(kbuff);
197 195
diff --git a/tools/perf/Documentation/perf-diff.txt b/tools/perf/Documentation/perf-diff.txt
index fdfceee0ffd0..b3b8abae62b8 100644
--- a/tools/perf/Documentation/perf-diff.txt
+++ b/tools/perf/Documentation/perf-diff.txt
@@ -33,21 +33,25 @@ OPTIONS
33-d:: 33-d::
34--dsos=:: 34--dsos=::
35 Only consider symbols in these dsos. CSV that understands 35 Only consider symbols in these dsos. CSV that understands
36 file://filename entries. 36 file://filename entries. This option will affect the percentage
37 of the Baseline/Delta column. See --percentage for more info.
37 38
38-C:: 39-C::
39--comms=:: 40--comms=::
40 Only consider symbols in these comms. CSV that understands 41 Only consider symbols in these comms. CSV that understands
41 file://filename entries. 42 file://filename entries. This option will affect the percentage
43 of the Baseline/Delta column. See --percentage for more info.
42 44
43-S:: 45-S::
44--symbols=:: 46--symbols=::
45 Only consider these symbols. CSV that understands 47 Only consider these symbols. CSV that understands
46 file://filename entries. 48 file://filename entries. This option will affect the percentage
49 of the Baseline/Delta column. See --percentage for more info.
47 50
48-s:: 51-s::
49--sort=:: 52--sort=::
50 Sort by key(s): pid, comm, dso, symbol. 53 Sort by key(s): pid, comm, dso, symbol, cpu, parent, srcline.
54 Please see description of --sort in the perf-report man page.
51 55
52-t:: 56-t::
53--field-separator=:: 57--field-separator=::
@@ -89,6 +93,14 @@ OPTIONS
89--order:: 93--order::
90 Specify compute sorting column number. 94 Specify compute sorting column number.
91 95
96--percentage::
97 Determine how to display the overhead percentage of filtered entries.
98 Filters can be applied by --comms, --dsos and/or --symbols options.
99
100 "relative" means it's relative to filtered entries only so that the
101 sum of shown entries will be always 100%. "absolute" means it retains
102 the original value before and after the filter is applied.
103
92COMPARISON 104COMPARISON
93---------- 105----------
94The comparison is governed by the baseline file. The baseline perf.data 106The comparison is governed by the baseline file. The baseline perf.data
@@ -157,6 +169,10 @@ with:
157 - period_percent being the % of the hist entry period value within 169 - period_percent being the % of the hist entry period value within
158 single data file 170 single data file
159 171
172 - with filtering by -C, -d and/or -S, period_percent might be changed
173 relative to how entries are filtered. Use --percentage=absolute to
174 prevent such fluctuation.
175
160ratio 176ratio
161~~~~~ 177~~~~~
162If specified the 'Ratio' column is displayed with value 'r' computed as: 178If specified the 'Ratio' column is displayed with value 'r' computed as:
@@ -187,4 +203,4 @@ If specified the 'Weighted diff' column is displayed with value 'd' computed as:
187 203
188SEE ALSO 204SEE ALSO
189-------- 205--------
190linkperf:perf-record[1] 206linkperf:perf-record[1], linkperf:perf-report[1]
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index c71b0f36d9e8..d460049cae8e 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -184,9 +184,10 @@ following filters are defined:
184 - in_tx: only when the target is in a hardware transaction 184 - in_tx: only when the target is in a hardware transaction
185 - no_tx: only when the target is not in a hardware transaction 185 - no_tx: only when the target is not in a hardware transaction
186 - abort_tx: only when the target is a hardware transaction abort 186 - abort_tx: only when the target is a hardware transaction abort
187 - cond: conditional branches
187 188
188+ 189+
189The option requires at least one branch type among any, any_call, any_ret, ind_call. 190The option requires at least one branch type among any, any_call, any_ret, ind_call, cond.
190The privilege levels may be omitted, in which case, the privilege levels of the associated 191The privilege levels may be omitted, in which case, the privilege levels of the associated
191event are applied to the branch filter. Both kernel (k) and hypervisor (hv) privilege 192event are applied to the branch filter. Both kernel (k) and hypervisor (hv) privilege
192levels are subject to permissions. When sampling on multiple events, branch stack sampling 193levels are subject to permissions. When sampling on multiple events, branch stack sampling
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 8eab8a4bdeb8..d2b59af62bc0 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -25,10 +25,6 @@ OPTIONS
25--verbose:: 25--verbose::
26 Be more verbose. (show symbol address, etc) 26 Be more verbose. (show symbol address, etc)
27 27
28-d::
29--dsos=::
30 Only consider symbols in these dsos. CSV that understands
31 file://filename entries.
32-n:: 28-n::
33--show-nr-samples:: 29--show-nr-samples::
34 Show the number of samples for each symbol 30 Show the number of samples for each symbol
@@ -42,11 +38,18 @@ OPTIONS
42-c:: 38-c::
43--comms=:: 39--comms=::
44 Only consider symbols in these comms. CSV that understands 40 Only consider symbols in these comms. CSV that understands
45 file://filename entries. 41 file://filename entries. This option will affect the percentage of
42 the overhead column. See --percentage for more info.
43-d::
44--dsos=::
45 Only consider symbols in these dsos. CSV that understands
46 file://filename entries. This option will affect the percentage of
47 the overhead column. See --percentage for more info.
46-S:: 48-S::
47--symbols=:: 49--symbols=::
48 Only consider these symbols. CSV that understands 50 Only consider these symbols. CSV that understands
49 file://filename entries. 51 file://filename entries. This option will affect the percentage of
52 the overhead column. See --percentage for more info.
50 53
51--symbol-filter=:: 54--symbol-filter=::
52 Only show symbols that match (partially) with this filter. 55 Only show symbols that match (partially) with this filter.
@@ -76,6 +79,15 @@ OPTIONS
76 abort cost. This is the global weight. 79 abort cost. This is the global weight.
77 - local_weight: Local weight version of the weight above. 80 - local_weight: Local weight version of the weight above.
78 - transaction: Transaction abort flags. 81 - transaction: Transaction abort flags.
82 - overhead: Overhead percentage of sample
83 - overhead_sys: Overhead percentage of sample running in system mode
84 - overhead_us: Overhead percentage of sample running in user mode
85 - overhead_guest_sys: Overhead percentage of sample running in system mode
86 on guest machine
87 - overhead_guest_us: Overhead percentage of sample running in user mode on
88 guest machine
89 - sample: Number of sample
90 - period: Raw number of event count of sample
79 91
80 By default, comm, dso and symbol keys are used. 92 By default, comm, dso and symbol keys are used.
81 (i.e. --sort comm,dso,symbol) 93 (i.e. --sort comm,dso,symbol)
@@ -95,6 +107,32 @@ OPTIONS
95 And default sort keys are changed to comm, dso_from, symbol_from, dso_to 107 And default sort keys are changed to comm, dso_from, symbol_from, dso_to
96 and symbol_to, see '--branch-stack'. 108 and symbol_to, see '--branch-stack'.
97 109
110-F::
111--fields=::
112 Specify output field - multiple keys can be specified in CSV format.
113 Following fields are available:
114 overhead, overhead_sys, overhead_us, overhead_children, sample and period.
115 Also it can contain any sort key(s).
116
117 By default, every sort keys not specified in -F will be appended
118 automatically.
119
120 If --mem-mode option is used, following sort keys are also available
121 (incompatible with --branch-stack):
122 symbol_daddr, dso_daddr, locked, tlb, mem, snoop, dcacheline.
123
124 - symbol_daddr: name of data symbol being executed on at the time of sample
125 - dso_daddr: name of library or module containing the data being executed
126 on at the time of sample
127 - locked: whether the bus was locked at the time of sample
128 - tlb: type of tlb access for the data at the time of sample
129 - mem: type of memory access for the data at the time of sample
130 - snoop: type of snoop (if any) for the data at the time of sample
131 - dcacheline: the cacheline the data address is on at the time of sample
132
133 And default sort keys are changed to local_weight, mem, sym, dso,
134 symbol_daddr, dso_daddr, snoop, tlb, locked, see '--mem-mode'.
135
98-p:: 136-p::
99--parent=<regex>:: 137--parent=<regex>::
100 A regex filter to identify parent. The parent is a caller of this 138 A regex filter to identify parent. The parent is a caller of this
@@ -141,6 +179,11 @@ OPTIONS
141 179
142 Default: fractal,0.5,callee,function. 180 Default: fractal,0.5,callee,function.
143 181
182--children::
183 Accumulate callchain of children to parent entry so that then can
184 show up in the output. The output will have a new "Children" column
185 and will be sorted on the data. It requires callchains are recorded.
186
144--max-stack:: 187--max-stack::
145 Set the stack depth limit when parsing the callchain, anything 188 Set the stack depth limit when parsing the callchain, anything
146 beyond the specified depth will be ignored. This is a trade-off 189 beyond the specified depth will be ignored. This is a trade-off
@@ -233,10 +276,26 @@ OPTIONS
233 Demangle symbol names to human readable form. It's enabled by default, 276 Demangle symbol names to human readable form. It's enabled by default,
234 disable with --no-demangle. 277 disable with --no-demangle.
235 278
279--mem-mode::
280 Use the data addresses of samples in addition to instruction addresses
281 to build the histograms. To generate meaningful output, the perf.data
282 file must have been obtained using perf record -d -W and using a
283 special event -e cpu/mem-loads/ or -e cpu/mem-stores/. See
284 'perf mem' for simpler access.
285
236--percent-limit:: 286--percent-limit::
237 Do not show entries which have an overhead under that percent. 287 Do not show entries which have an overhead under that percent.
238 (Default: 0). 288 (Default: 0).
239 289
290--percentage::
291 Determine how to display the overhead percentage of filtered entries.
292 Filters can be applied by --comms, --dsos and/or --symbols options and
293 Zoom operations on the TUI (thread, dso, etc).
294
295 "relative" means it's relative to filtered entries only so that the
296 sum of shown entries will be always 100%. "absolute" means it retains
297 the original value before and after the filter is applied.
298
240--header:: 299--header::
241 Show header information in the perf.data file. This includes 300 Show header information in the perf.data file. This includes
242 various information like hostname, OS and perf version, cpu/mem 301 various information like hostname, OS and perf version, cpu/mem
diff --git a/tools/perf/Documentation/perf-timechart.txt b/tools/perf/Documentation/perf-timechart.txt
index bc5990c33dc0..5e0f986dff38 100644
--- a/tools/perf/Documentation/perf-timechart.txt
+++ b/tools/perf/Documentation/perf-timechart.txt
@@ -43,27 +43,6 @@ TIMECHART OPTIONS
43 43
44--symfs=<directory>:: 44--symfs=<directory>::
45 Look for files with symbols relative to this directory. 45 Look for files with symbols relative to this directory.
46
47EXAMPLES
48--------
49
50$ perf timechart record git pull
51
52 [ perf record: Woken up 13 times to write data ]
53 [ perf record: Captured and wrote 4.253 MB perf.data (~185801 samples) ]
54
55$ perf timechart
56
57 Written 10.2 seconds of trace to output.svg.
58
59Record system-wide timechart:
60
61 $ perf timechart record
62
63 then generate timechart and highlight 'gcc' tasks:
64
65 $ perf timechart --highlight gcc
66
67-n:: 46-n::
68--proc-num:: 47--proc-num::
69 Print task info for at least given number of tasks. 48 Print task info for at least given number of tasks.
@@ -88,6 +67,26 @@ RECORD OPTIONS
88--callchain:: 67--callchain::
89 Do call-graph (stack chain/backtrace) recording 68 Do call-graph (stack chain/backtrace) recording
90 69
70EXAMPLES
71--------
72
73$ perf timechart record git pull
74
75 [ perf record: Woken up 13 times to write data ]
76 [ perf record: Captured and wrote 4.253 MB perf.data (~185801 samples) ]
77
78$ perf timechart
79
80 Written 10.2 seconds of trace to output.svg.
81
82Record system-wide timechart:
83
84 $ perf timechart record
85
86 then generate timechart and highlight 'gcc' tasks:
87
88 $ perf timechart --highlight gcc
89
91SEE ALSO 90SEE ALSO
92-------- 91--------
93linkperf:perf-record[1] 92linkperf:perf-record[1]
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index 976b00c6cdb1..180ae02137a5 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -113,7 +113,17 @@ Default is to monitor all CPUS.
113-s:: 113-s::
114--sort:: 114--sort::
115 Sort by key(s): pid, comm, dso, symbol, parent, srcline, weight, 115 Sort by key(s): pid, comm, dso, symbol, parent, srcline, weight,
116 local_weight, abort, in_tx, transaction 116 local_weight, abort, in_tx, transaction, overhead, sample, period.
117 Please see description of --sort in the perf-report man page.
118
119--fields=::
120 Specify output field - multiple keys can be specified in CSV format.
121 Following fields are available:
122 overhead, overhead_sys, overhead_us, overhead_children, sample and period.
123 Also it can contain any sort key(s).
124
125 By default, every sort keys not specified in --field will be appended
126 automatically.
117 127
118-n:: 128-n::
119--show-nr-samples:: 129--show-nr-samples::
@@ -123,13 +133,16 @@ Default is to monitor all CPUS.
123 Show a column with the sum of periods. 133 Show a column with the sum of periods.
124 134
125--dsos:: 135--dsos::
126 Only consider symbols in these dsos. 136 Only consider symbols in these dsos. This option will affect the
137 percentage of the overhead column. See --percentage for more info.
127 138
128--comms:: 139--comms::
129 Only consider symbols in these comms. 140 Only consider symbols in these comms. This option will affect the
141 percentage of the overhead column. See --percentage for more info.
130 142
131--symbols:: 143--symbols::
132 Only consider these symbols. 144 Only consider these symbols. This option will affect the
145 percentage of the overhead column. See --percentage for more info.
133 146
134-M:: 147-M::
135--disassembler-style=:: Set disassembler style for objdump. 148--disassembler-style=:: Set disassembler style for objdump.
@@ -148,6 +161,12 @@ Default is to monitor all CPUS.
148 Setup and enable call-graph (stack chain/backtrace) recording, 161 Setup and enable call-graph (stack chain/backtrace) recording,
149 implies -g. 162 implies -g.
150 163
164--children::
165 Accumulate callchain of children to parent entry so that then can
166 show up in the output. The output will have a new "Children" column
167 and will be sorted on the data. It requires -g/--call-graph option
168 enabled.
169
151--max-stack:: 170--max-stack::
152 Set the stack depth limit when parsing the callchain, anything 171 Set the stack depth limit when parsing the callchain, anything
153 beyond the specified depth will be ignored. This is a trade-off 172 beyond the specified depth will be ignored. This is a trade-off
@@ -165,6 +184,15 @@ Default is to monitor all CPUS.
165 Do not show entries which have an overhead under that percent. 184 Do not show entries which have an overhead under that percent.
166 (Default: 0). 185 (Default: 0).
167 186
187--percentage::
188 Determine how to display the overhead percentage of filtered entries.
189 Filters can be applied by --comms, --dsos and/or --symbols options and
190 Zoom operations on the TUI (thread, dso, etc).
191
192 "relative" means it's relative to filtered entries only so that the
193 sum of shown entries will be always 100%. "absolute" means it retains
194 the original value before and after the filter is applied.
195
168INTERACTIVE PROMPTING KEYS 196INTERACTIVE PROMPTING KEYS
169-------------------------- 197--------------------------
170 198
@@ -200,4 +228,4 @@ Pressing any unmapped key displays a menu, and prompts for input.
200 228
201SEE ALSO 229SEE ALSO
202-------- 230--------
203linkperf:perf-stat[1], linkperf:perf-list[1] 231linkperf:perf-stat[1], linkperf:perf-list[1], linkperf:perf-report[1]
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST
index c0c87c87b60f..45da209b6ed3 100644
--- a/tools/perf/MANIFEST
+++ b/tools/perf/MANIFEST
@@ -7,6 +7,8 @@ tools/lib/symbol/kallsyms.h
7tools/include/asm/bug.h 7tools/include/asm/bug.h
8tools/include/linux/compiler.h 8tools/include/linux/compiler.h
9tools/include/linux/hash.h 9tools/include/linux/hash.h
10tools/include/linux/export.h
11tools/include/linux/types.h
10include/linux/const.h 12include/linux/const.h
11include/linux/perf_event.h 13include/linux/perf_event.h
12include/linux/rbtree.h 14include/linux/rbtree.h
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 895edd32930c..9670a16fa577 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -222,12 +222,12 @@ LIB_H += util/include/linux/const.h
222LIB_H += util/include/linux/ctype.h 222LIB_H += util/include/linux/ctype.h
223LIB_H += util/include/linux/kernel.h 223LIB_H += util/include/linux/kernel.h
224LIB_H += util/include/linux/list.h 224LIB_H += util/include/linux/list.h
225LIB_H += util/include/linux/export.h 225LIB_H += ../include/linux/export.h
226LIB_H += util/include/linux/poison.h 226LIB_H += util/include/linux/poison.h
227LIB_H += util/include/linux/rbtree.h 227LIB_H += util/include/linux/rbtree.h
228LIB_H += util/include/linux/rbtree_augmented.h 228LIB_H += util/include/linux/rbtree_augmented.h
229LIB_H += util/include/linux/string.h 229LIB_H += util/include/linux/string.h
230LIB_H += util/include/linux/types.h 230LIB_H += ../include/linux/types.h
231LIB_H += util/include/linux/linkage.h 231LIB_H += util/include/linux/linkage.h
232LIB_H += util/include/asm/asm-offsets.h 232LIB_H += util/include/asm/asm-offsets.h
233LIB_H += ../include/asm/bug.h 233LIB_H += ../include/asm/bug.h
@@ -252,7 +252,6 @@ LIB_H += util/event.h
252LIB_H += util/evsel.h 252LIB_H += util/evsel.h
253LIB_H += util/evlist.h 253LIB_H += util/evlist.h
254LIB_H += util/exec_cmd.h 254LIB_H += util/exec_cmd.h
255LIB_H += util/types.h
256LIB_H += util/levenshtein.h 255LIB_H += util/levenshtein.h
257LIB_H += util/machine.h 256LIB_H += util/machine.h
258LIB_H += util/map.h 257LIB_H += util/map.h
@@ -397,7 +396,11 @@ LIB_OBJS += $(OUTPUT)tests/rdpmc.o
397LIB_OBJS += $(OUTPUT)tests/evsel-roundtrip-name.o 396LIB_OBJS += $(OUTPUT)tests/evsel-roundtrip-name.o
398LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o 397LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o
399LIB_OBJS += $(OUTPUT)tests/pmu.o 398LIB_OBJS += $(OUTPUT)tests/pmu.o
399LIB_OBJS += $(OUTPUT)tests/hists_common.o
400LIB_OBJS += $(OUTPUT)tests/hists_link.o 400LIB_OBJS += $(OUTPUT)tests/hists_link.o
401LIB_OBJS += $(OUTPUT)tests/hists_filter.o
402LIB_OBJS += $(OUTPUT)tests/hists_output.o
403LIB_OBJS += $(OUTPUT)tests/hists_cumulate.o
401LIB_OBJS += $(OUTPUT)tests/python-use.o 404LIB_OBJS += $(OUTPUT)tests/python-use.o
402LIB_OBJS += $(OUTPUT)tests/bp_signal.o 405LIB_OBJS += $(OUTPUT)tests/bp_signal.o
403LIB_OBJS += $(OUTPUT)tests/bp_signal_overflow.o 406LIB_OBJS += $(OUTPUT)tests/bp_signal_overflow.o
@@ -410,10 +413,12 @@ LIB_OBJS += $(OUTPUT)tests/code-reading.o
410LIB_OBJS += $(OUTPUT)tests/sample-parsing.o 413LIB_OBJS += $(OUTPUT)tests/sample-parsing.o
411LIB_OBJS += $(OUTPUT)tests/parse-no-sample-id-all.o 414LIB_OBJS += $(OUTPUT)tests/parse-no-sample-id-all.o
412ifndef NO_DWARF_UNWIND 415ifndef NO_DWARF_UNWIND
413ifeq ($(ARCH),x86) 416ifeq ($(ARCH),$(filter $(ARCH),x86 arm))
414LIB_OBJS += $(OUTPUT)tests/dwarf-unwind.o 417LIB_OBJS += $(OUTPUT)tests/dwarf-unwind.o
415endif 418endif
416endif 419endif
420LIB_OBJS += $(OUTPUT)tests/mmap-thread-lookup.o
421LIB_OBJS += $(OUTPUT)tests/thread-mg-share.o
417 422
418BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o 423BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
419BUILTIN_OBJS += $(OUTPUT)builtin-bench.o 424BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
@@ -784,8 +789,8 @@ help:
784 @echo '' 789 @echo ''
785 @echo 'Perf install targets:' 790 @echo 'Perf install targets:'
786 @echo ' NOTE: documentation build requires asciidoc, xmlto packages to be installed' 791 @echo ' NOTE: documentation build requires asciidoc, xmlto packages to be installed'
787 @echo ' HINT: use "make prefix=<path> <install target>" to install to a particular' 792 @echo ' HINT: use "prefix" or "DESTDIR" to install to a particular'
788 @echo ' path like make prefix=/usr/local install install-doc' 793 @echo ' path like "make prefix=/usr/local install install-doc"'
789 @echo ' install - install compiled binaries' 794 @echo ' install - install compiled binaries'
790 @echo ' install-doc - install *all* documentation' 795 @echo ' install-doc - install *all* documentation'
791 @echo ' install-man - install manpage documentation' 796 @echo ' install-man - install manpage documentation'
@@ -810,17 +815,20 @@ INSTALL_DOC_TARGETS += quick-install-doc quick-install-man quick-install-html
810$(DOC_TARGETS): 815$(DOC_TARGETS):
811 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:doc=all) 816 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:doc=all)
812 817
818TAG_FOLDERS= . ../lib/traceevent ../lib/api ../lib/symbol
819TAG_FILES= ../../include/uapi/linux/perf_event.h
820
813TAGS: 821TAGS:
814 $(RM) TAGS 822 $(QUIET_GEN)$(RM) TAGS; \
815 $(FIND) . -name '*.[hcS]' -print | xargs etags -a 823 $(FIND) $(TAG_FOLDERS) -name '*.[hcS]' -print | xargs etags -a $(TAG_FILES)
816 824
817tags: 825tags:
818 $(RM) tags 826 $(QUIET_GEN)$(RM) tags; \
819 $(FIND) . -name '*.[hcS]' -print | xargs ctags -a 827 $(FIND) $(TAG_FOLDERS) -name '*.[hcS]' -print | xargs ctags -a $(TAG_FILES)
820 828
821cscope: 829cscope:
822 $(RM) cscope* 830 $(QUIET_GEN)$(RM) cscope*; \
823 $(FIND) . -name '*.[hcS]' -print | xargs cscope -b 831 $(FIND) $(TAG_FOLDERS) -name '*.[hcS]' -print | xargs cscope -b $(TAG_FILES)
824 832
825### Detect prefix changes 833### Detect prefix changes
826TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):\ 834TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):\
diff --git a/tools/perf/arch/arm/Makefile b/tools/perf/arch/arm/Makefile
index 67e9b3d38e89..09d62153d384 100644
--- a/tools/perf/arch/arm/Makefile
+++ b/tools/perf/arch/arm/Makefile
@@ -5,3 +5,10 @@ endif
5ifndef NO_LIBUNWIND 5ifndef NO_LIBUNWIND
6LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind-libunwind.o 6LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind-libunwind.o
7endif 7endif
8ifndef NO_LIBDW_DWARF_UNWIND
9LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind-libdw.o
10endif
11ifndef NO_DWARF_UNWIND
12LIB_OBJS += $(OUTPUT)arch/$(ARCH)/tests/regs_load.o
13LIB_OBJS += $(OUTPUT)arch/$(ARCH)/tests/dwarf-unwind.o
14endif
diff --git a/tools/perf/arch/arm/include/perf_regs.h b/tools/perf/arch/arm/include/perf_regs.h
index 2a1cfde66b69..f619c9c5a4bf 100644
--- a/tools/perf/arch/arm/include/perf_regs.h
+++ b/tools/perf/arch/arm/include/perf_regs.h
@@ -2,10 +2,15 @@
2#define ARCH_PERF_REGS_H 2#define ARCH_PERF_REGS_H
3 3
4#include <stdlib.h> 4#include <stdlib.h>
5#include "../../util/types.h" 5#include <linux/types.h>
6#include <asm/perf_regs.h> 6#include <asm/perf_regs.h>
7 7
8void perf_regs_load(u64 *regs);
9
8#define PERF_REGS_MASK ((1ULL << PERF_REG_ARM_MAX) - 1) 10#define PERF_REGS_MASK ((1ULL << PERF_REG_ARM_MAX) - 1)
11#define PERF_REGS_MAX PERF_REG_ARM_MAX
12#define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_32
13
9#define PERF_REG_IP PERF_REG_ARM_PC 14#define PERF_REG_IP PERF_REG_ARM_PC
10#define PERF_REG_SP PERF_REG_ARM_SP 15#define PERF_REG_SP PERF_REG_ARM_SP
11 16
diff --git a/tools/perf/arch/arm/tests/dwarf-unwind.c b/tools/perf/arch/arm/tests/dwarf-unwind.c
new file mode 100644
index 000000000000..9f870d27cb39
--- /dev/null
+++ b/tools/perf/arch/arm/tests/dwarf-unwind.c
@@ -0,0 +1,60 @@
1#include <string.h>
2#include "perf_regs.h"
3#include "thread.h"
4#include "map.h"
5#include "event.h"
6#include "tests/tests.h"
7
8#define STACK_SIZE 8192
9
10static int sample_ustack(struct perf_sample *sample,
11 struct thread *thread, u64 *regs)
12{
13 struct stack_dump *stack = &sample->user_stack;
14 struct map *map;
15 unsigned long sp;
16 u64 stack_size, *buf;
17
18 buf = malloc(STACK_SIZE);
19 if (!buf) {
20 pr_debug("failed to allocate sample uregs data\n");
21 return -1;
22 }
23
24 sp = (unsigned long) regs[PERF_REG_ARM_SP];
25
26 map = map_groups__find(thread->mg, MAP__VARIABLE, (u64) sp);
27 if (!map) {
28 pr_debug("failed to get stack map\n");
29 free(buf);
30 return -1;
31 }
32
33 stack_size = map->end - sp;
34 stack_size = stack_size > STACK_SIZE ? STACK_SIZE : stack_size;
35
36 memcpy(buf, (void *) sp, stack_size);
37 stack->data = (char *) buf;
38 stack->size = stack_size;
39 return 0;
40}
41
42int test__arch_unwind_sample(struct perf_sample *sample,
43 struct thread *thread)
44{
45 struct regs_dump *regs = &sample->user_regs;
46 u64 *buf;
47
48 buf = calloc(1, sizeof(u64) * PERF_REGS_MAX);
49 if (!buf) {
50 pr_debug("failed to allocate sample uregs data\n");
51 return -1;
52 }
53
54 perf_regs_load(buf);
55 regs->abi = PERF_SAMPLE_REGS_ABI;
56 regs->regs = buf;
57 regs->mask = PERF_REGS_MASK;
58
59 return sample_ustack(sample, thread, buf);
60}
diff --git a/tools/perf/arch/arm/tests/regs_load.S b/tools/perf/arch/arm/tests/regs_load.S
new file mode 100644
index 000000000000..e09e983946fe
--- /dev/null
+++ b/tools/perf/arch/arm/tests/regs_load.S
@@ -0,0 +1,58 @@
1#include <linux/linkage.h>
2
3#define R0 0x00
4#define R1 0x08
5#define R2 0x10
6#define R3 0x18
7#define R4 0x20
8#define R5 0x28
9#define R6 0x30
10#define R7 0x38
11#define R8 0x40
12#define R9 0x48
13#define SL 0x50
14#define FP 0x58
15#define IP 0x60
16#define SP 0x68
17#define LR 0x70
18#define PC 0x78
19
20/*
21 * Implementation of void perf_regs_load(u64 *regs);
22 *
23 * This functions fills in the 'regs' buffer from the actual registers values,
24 * in the way the perf built-in unwinding test expects them:
25 * - the PC at the time at the call to this function. Since this function
26 * is called using a bl instruction, the PC value is taken from LR.
27 * The built-in unwinding test then unwinds the call stack from the dwarf
28 * information in unwind__get_entries.
29 *
30 * Notes:
31 * - the 8 bytes stride in the registers offsets comes from the fact
32 * that the registers are stored in an u64 array (u64 *regs),
33 * - the regs buffer needs to be zeroed before the call to this function,
34 * in this case using a calloc in dwarf-unwind.c.
35 */
36
37.text
38.type perf_regs_load,%function
39ENTRY(perf_regs_load)
40 str r0, [r0, #R0]
41 str r1, [r0, #R1]
42 str r2, [r0, #R2]
43 str r3, [r0, #R3]
44 str r4, [r0, #R4]
45 str r5, [r0, #R5]
46 str r6, [r0, #R6]
47 str r7, [r0, #R7]
48 str r8, [r0, #R8]
49 str r9, [r0, #R9]
50 str sl, [r0, #SL]
51 str fp, [r0, #FP]
52 str ip, [r0, #IP]
53 str sp, [r0, #SP]
54 str lr, [r0, #LR]
55 str lr, [r0, #PC] // store pc as lr in order to skip the call
56 // to this function
57 mov pc, lr
58ENDPROC(perf_regs_load)
diff --git a/tools/perf/arch/arm/util/unwind-libdw.c b/tools/perf/arch/arm/util/unwind-libdw.c
new file mode 100644
index 000000000000..b4176c60117a
--- /dev/null
+++ b/tools/perf/arch/arm/util/unwind-libdw.c
@@ -0,0 +1,36 @@
1#include <elfutils/libdwfl.h>
2#include "../../util/unwind-libdw.h"
3#include "../../util/perf_regs.h"
4
5bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
6{
7 struct unwind_info *ui = arg;
8 struct regs_dump *user_regs = &ui->sample->user_regs;
9 Dwarf_Word dwarf_regs[PERF_REG_ARM_MAX];
10
11#define REG(r) ({ \
12 Dwarf_Word val = 0; \
13 perf_reg_value(&val, user_regs, PERF_REG_ARM_##r); \
14 val; \
15})
16
17 dwarf_regs[0] = REG(R0);
18 dwarf_regs[1] = REG(R1);
19 dwarf_regs[2] = REG(R2);
20 dwarf_regs[3] = REG(R3);
21 dwarf_regs[4] = REG(R4);
22 dwarf_regs[5] = REG(R5);
23 dwarf_regs[6] = REG(R6);
24 dwarf_regs[7] = REG(R7);
25 dwarf_regs[8] = REG(R8);
26 dwarf_regs[9] = REG(R9);
27 dwarf_regs[10] = REG(R10);
28 dwarf_regs[11] = REG(FP);
29 dwarf_regs[12] = REG(IP);
30 dwarf_regs[13] = REG(SP);
31 dwarf_regs[14] = REG(LR);
32 dwarf_regs[15] = REG(PC);
33
34 return dwfl_thread_state_registers(thread, 0, PERF_REG_ARM_MAX,
35 dwarf_regs);
36}
diff --git a/tools/perf/arch/arm64/Makefile b/tools/perf/arch/arm64/Makefile
new file mode 100644
index 000000000000..67e9b3d38e89
--- /dev/null
+++ b/tools/perf/arch/arm64/Makefile
@@ -0,0 +1,7 @@
1ifndef NO_DWARF
2PERF_HAVE_DWARF_REGS := 1
3LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
4endif
5ifndef NO_LIBUNWIND
6LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind-libunwind.o
7endif
diff --git a/tools/perf/arch/arm64/include/perf_regs.h b/tools/perf/arch/arm64/include/perf_regs.h
new file mode 100644
index 000000000000..e9441b9e2a30
--- /dev/null
+++ b/tools/perf/arch/arm64/include/perf_regs.h
@@ -0,0 +1,88 @@
1#ifndef ARCH_PERF_REGS_H
2#define ARCH_PERF_REGS_H
3
4#include <stdlib.h>
5#include <linux/types.h>
6#include <asm/perf_regs.h>
7
8#define PERF_REGS_MASK ((1ULL << PERF_REG_ARM64_MAX) - 1)
9#define PERF_REG_IP PERF_REG_ARM64_PC
10#define PERF_REG_SP PERF_REG_ARM64_SP
11
12static inline const char *perf_reg_name(int id)
13{
14 switch (id) {
15 case PERF_REG_ARM64_X0:
16 return "x0";
17 case PERF_REG_ARM64_X1:
18 return "x1";
19 case PERF_REG_ARM64_X2:
20 return "x2";
21 case PERF_REG_ARM64_X3:
22 return "x3";
23 case PERF_REG_ARM64_X4:
24 return "x4";
25 case PERF_REG_ARM64_X5:
26 return "x5";
27 case PERF_REG_ARM64_X6:
28 return "x6";
29 case PERF_REG_ARM64_X7:
30 return "x7";
31 case PERF_REG_ARM64_X8:
32 return "x8";
33 case PERF_REG_ARM64_X9:
34 return "x9";
35 case PERF_REG_ARM64_X10:
36 return "x10";
37 case PERF_REG_ARM64_X11:
38 return "x11";
39 case PERF_REG_ARM64_X12:
40 return "x12";
41 case PERF_REG_ARM64_X13:
42 return "x13";
43 case PERF_REG_ARM64_X14:
44 return "x14";
45 case PERF_REG_ARM64_X15:
46 return "x15";
47 case PERF_REG_ARM64_X16:
48 return "x16";
49 case PERF_REG_ARM64_X17:
50 return "x17";
51 case PERF_REG_ARM64_X18:
52 return "x18";
53 case PERF_REG_ARM64_X19:
54 return "x19";
55 case PERF_REG_ARM64_X20:
56 return "x20";
57 case PERF_REG_ARM64_X21:
58 return "x21";
59 case PERF_REG_ARM64_X22:
60 return "x22";
61 case PERF_REG_ARM64_X23:
62 return "x23";
63 case PERF_REG_ARM64_X24:
64 return "x24";
65 case PERF_REG_ARM64_X25:
66 return "x25";
67 case PERF_REG_ARM64_X26:
68 return "x26";
69 case PERF_REG_ARM64_X27:
70 return "x27";
71 case PERF_REG_ARM64_X28:
72 return "x28";
73 case PERF_REG_ARM64_X29:
74 return "x29";
75 case PERF_REG_ARM64_SP:
76 return "sp";
77 case PERF_REG_ARM64_LR:
78 return "lr";
79 case PERF_REG_ARM64_PC:
80 return "pc";
81 default:
82 return NULL;
83 }
84
85 return NULL;
86}
87
88#endif /* ARCH_PERF_REGS_H */
diff --git a/tools/perf/arch/arm64/util/dwarf-regs.c b/tools/perf/arch/arm64/util/dwarf-regs.c
new file mode 100644
index 000000000000..d49efeb8172e
--- /dev/null
+++ b/tools/perf/arch/arm64/util/dwarf-regs.c
@@ -0,0 +1,80 @@
1/*
2 * Mapping of DWARF debug register numbers into register names.
3 *
4 * Copyright (C) 2010 Will Deacon, ARM Ltd.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <stddef.h>
12#include <dwarf-regs.h>
13
14struct pt_regs_dwarfnum {
15 const char *name;
16 unsigned int dwarfnum;
17};
18
19#define STR(s) #s
20#define REG_DWARFNUM_NAME(r, num) {.name = r, .dwarfnum = num}
21#define GPR_DWARFNUM_NAME(num) \
22 {.name = STR(%x##num), .dwarfnum = num}
23#define REG_DWARFNUM_END {.name = NULL, .dwarfnum = 0}
24
25/*
26 * Reference:
27 * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0057b/IHI0057B_aadwarf64.pdf
28 */
29static const struct pt_regs_dwarfnum regdwarfnum_table[] = {
30 GPR_DWARFNUM_NAME(0),
31 GPR_DWARFNUM_NAME(1),
32 GPR_DWARFNUM_NAME(2),
33 GPR_DWARFNUM_NAME(3),
34 GPR_DWARFNUM_NAME(4),
35 GPR_DWARFNUM_NAME(5),
36 GPR_DWARFNUM_NAME(6),
37 GPR_DWARFNUM_NAME(7),
38 GPR_DWARFNUM_NAME(8),
39 GPR_DWARFNUM_NAME(9),
40 GPR_DWARFNUM_NAME(10),
41 GPR_DWARFNUM_NAME(11),
42 GPR_DWARFNUM_NAME(12),
43 GPR_DWARFNUM_NAME(13),
44 GPR_DWARFNUM_NAME(14),
45 GPR_DWARFNUM_NAME(15),
46 GPR_DWARFNUM_NAME(16),
47 GPR_DWARFNUM_NAME(17),
48 GPR_DWARFNUM_NAME(18),
49 GPR_DWARFNUM_NAME(19),
50 GPR_DWARFNUM_NAME(20),
51 GPR_DWARFNUM_NAME(21),
52 GPR_DWARFNUM_NAME(22),
53 GPR_DWARFNUM_NAME(23),
54 GPR_DWARFNUM_NAME(24),
55 GPR_DWARFNUM_NAME(25),
56 GPR_DWARFNUM_NAME(26),
57 GPR_DWARFNUM_NAME(27),
58 GPR_DWARFNUM_NAME(28),
59 GPR_DWARFNUM_NAME(29),
60 REG_DWARFNUM_NAME("%lr", 30),
61 REG_DWARFNUM_NAME("%sp", 31),
62 REG_DWARFNUM_END,
63};
64
65/**
66 * get_arch_regstr() - lookup register name from it's DWARF register number
67 * @n: the DWARF register number
68 *
69 * get_arch_regstr() returns the name of the register in struct
70 * regdwarfnum_table from it's DWARF register number. If the register is not
71 * found in the table, this returns NULL;
72 */
73const char *get_arch_regstr(unsigned int n)
74{
75 const struct pt_regs_dwarfnum *roff;
76 for (roff = regdwarfnum_table; roff->name != NULL; roff++)
77 if (roff->dwarfnum == n)
78 return roff->name;
79 return NULL;
80}
diff --git a/tools/perf/arch/arm64/util/unwind-libunwind.c b/tools/perf/arch/arm64/util/unwind-libunwind.c
new file mode 100644
index 000000000000..436ee43859dc
--- /dev/null
+++ b/tools/perf/arch/arm64/util/unwind-libunwind.c
@@ -0,0 +1,82 @@
1
2#include <errno.h>
3#include <libunwind.h>
4#include "perf_regs.h"
5#include "../../util/unwind.h"
6
7int libunwind__arch_reg_id(int regnum)
8{
9 switch (regnum) {
10 case UNW_AARCH64_X0:
11 return PERF_REG_ARM64_X0;
12 case UNW_AARCH64_X1:
13 return PERF_REG_ARM64_X1;
14 case UNW_AARCH64_X2:
15 return PERF_REG_ARM64_X2;
16 case UNW_AARCH64_X3:
17 return PERF_REG_ARM64_X3;
18 case UNW_AARCH64_X4:
19 return PERF_REG_ARM64_X4;
20 case UNW_AARCH64_X5:
21 return PERF_REG_ARM64_X5;
22 case UNW_AARCH64_X6:
23 return PERF_REG_ARM64_X6;
24 case UNW_AARCH64_X7:
25 return PERF_REG_ARM64_X7;
26 case UNW_AARCH64_X8:
27 return PERF_REG_ARM64_X8;
28 case UNW_AARCH64_X9:
29 return PERF_REG_ARM64_X9;
30 case UNW_AARCH64_X10:
31 return PERF_REG_ARM64_X10;
32 case UNW_AARCH64_X11:
33 return PERF_REG_ARM64_X11;
34 case UNW_AARCH64_X12:
35 return PERF_REG_ARM64_X12;
36 case UNW_AARCH64_X13:
37 return PERF_REG_ARM64_X13;
38 case UNW_AARCH64_X14:
39 return PERF_REG_ARM64_X14;
40 case UNW_AARCH64_X15:
41 return PERF_REG_ARM64_X15;
42 case UNW_AARCH64_X16:
43 return PERF_REG_ARM64_X16;
44 case UNW_AARCH64_X17:
45 return PERF_REG_ARM64_X17;
46 case UNW_AARCH64_X18:
47 return PERF_REG_ARM64_X18;
48 case UNW_AARCH64_X19:
49 return PERF_REG_ARM64_X19;
50 case UNW_AARCH64_X20:
51 return PERF_REG_ARM64_X20;
52 case UNW_AARCH64_X21:
53 return PERF_REG_ARM64_X21;
54 case UNW_AARCH64_X22:
55 return PERF_REG_ARM64_X22;
56 case UNW_AARCH64_X23:
57 return PERF_REG_ARM64_X23;
58 case UNW_AARCH64_X24:
59 return PERF_REG_ARM64_X24;
60 case UNW_AARCH64_X25:
61 return PERF_REG_ARM64_X25;
62 case UNW_AARCH64_X26:
63 return PERF_REG_ARM64_X26;
64 case UNW_AARCH64_X27:
65 return PERF_REG_ARM64_X27;
66 case UNW_AARCH64_X28:
67 return PERF_REG_ARM64_X28;
68 case UNW_AARCH64_X29:
69 return PERF_REG_ARM64_X29;
70 case UNW_AARCH64_X30:
71 return PERF_REG_ARM64_LR;
72 case UNW_AARCH64_SP:
73 return PERF_REG_ARM64_SP;
74 case UNW_AARCH64_PC:
75 return PERF_REG_ARM64_PC;
76 default:
77 pr_err("unwind: invalid reg id %d\n", regnum);
78 return -EINVAL;
79 }
80
81 return -EINVAL;
82}
diff --git a/tools/perf/arch/x86/include/perf_regs.h b/tools/perf/arch/x86/include/perf_regs.h
index fc819ca34a7e..7df517acfef8 100644
--- a/tools/perf/arch/x86/include/perf_regs.h
+++ b/tools/perf/arch/x86/include/perf_regs.h
@@ -2,7 +2,7 @@
2#define ARCH_PERF_REGS_H 2#define ARCH_PERF_REGS_H
3 3
4#include <stdlib.h> 4#include <stdlib.h>
5#include "../../util/types.h" 5#include <linux/types.h>
6#include <asm/perf_regs.h> 6#include <asm/perf_regs.h>
7 7
8void perf_regs_load(u64 *regs); 8void perf_regs_load(u64 *regs);
diff --git a/tools/perf/arch/x86/tests/dwarf-unwind.c b/tools/perf/arch/x86/tests/dwarf-unwind.c
index 83bc2385e6d3..9f89f899ccc7 100644
--- a/tools/perf/arch/x86/tests/dwarf-unwind.c
+++ b/tools/perf/arch/x86/tests/dwarf-unwind.c
@@ -23,7 +23,7 @@ static int sample_ustack(struct perf_sample *sample,
23 23
24 sp = (unsigned long) regs[PERF_REG_X86_SP]; 24 sp = (unsigned long) regs[PERF_REG_X86_SP];
25 25
26 map = map_groups__find(&thread->mg, MAP__VARIABLE, (u64) sp); 26 map = map_groups__find(thread->mg, MAP__VARIABLE, (u64) sp);
27 if (!map) { 27 if (!map) {
28 pr_debug("failed to get stack map\n"); 28 pr_debug("failed to get stack map\n");
29 free(buf); 29 free(buf);
diff --git a/tools/perf/arch/x86/util/tsc.c b/tools/perf/arch/x86/util/tsc.c
index b2519e49424f..40021fa3129b 100644
--- a/tools/perf/arch/x86/util/tsc.c
+++ b/tools/perf/arch/x86/util/tsc.c
@@ -4,7 +4,7 @@
4#include <linux/perf_event.h> 4#include <linux/perf_event.h>
5 5
6#include "../../perf.h" 6#include "../../perf.h"
7#include "../../util/types.h" 7#include <linux/types.h>
8#include "../../util/debug.h" 8#include "../../util/debug.h"
9#include "tsc.h" 9#include "tsc.h"
10 10
diff --git a/tools/perf/arch/x86/util/tsc.h b/tools/perf/arch/x86/util/tsc.h
index a24dec81c795..2affe0366b59 100644
--- a/tools/perf/arch/x86/util/tsc.h
+++ b/tools/perf/arch/x86/util/tsc.h
@@ -1,7 +1,7 @@
1#ifndef TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ 1#ifndef TOOLS_PERF_ARCH_X86_UTIL_TSC_H__
2#define TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ 2#define TOOLS_PERF_ARCH_X86_UTIL_TSC_H__
3 3
4#include "../../util/types.h" 4#include <linux/types.h>
5 5
6struct perf_tsc_conversion { 6struct perf_tsc_conversion {
7 u16 time_shift; 7 u16 time_shift;
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 0da603b79b61..1ec429fef2be 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -46,7 +46,7 @@ struct perf_annotate {
46}; 46};
47 47
48static int perf_evsel__add_sample(struct perf_evsel *evsel, 48static int perf_evsel__add_sample(struct perf_evsel *evsel,
49 struct perf_sample *sample, 49 struct perf_sample *sample __maybe_unused,
50 struct addr_location *al, 50 struct addr_location *al,
51 struct perf_annotate *ann) 51 struct perf_annotate *ann)
52{ 52{
@@ -65,13 +65,13 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel,
65 return 0; 65 return 0;
66 } 66 }
67 67
68 he = __hists__add_entry(&evsel->hists, al, NULL, NULL, NULL, 1, 1, 0); 68 he = __hists__add_entry(&evsel->hists, al, NULL, NULL, NULL, 1, 1, 0,
69 true);
69 if (he == NULL) 70 if (he == NULL)
70 return -ENOMEM; 71 return -ENOMEM;
71 72
72 ret = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); 73 ret = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
73 evsel->hists.stats.total_period += sample->period; 74 hists__inc_nr_samples(&evsel->hists, true);
74 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
75 return ret; 75 return ret;
76} 76}
77 77
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 204fffe22532..9a5a035cb426 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -60,7 +60,6 @@ static int data__files_cnt;
60#define data__for_each_file(i, d) data__for_each_file_start(i, d, 0) 60#define data__for_each_file(i, d) data__for_each_file_start(i, d, 0)
61#define data__for_each_file_new(i, d) data__for_each_file_start(i, d, 1) 61#define data__for_each_file_new(i, d) data__for_each_file_start(i, d, 1)
62 62
63static char diff__default_sort_order[] = "dso,symbol";
64static bool force; 63static bool force;
65static bool show_period; 64static bool show_period;
66static bool show_formula; 65static bool show_formula;
@@ -220,7 +219,8 @@ static int setup_compute(const struct option *opt, const char *str,
220 219
221static double period_percent(struct hist_entry *he, u64 period) 220static double period_percent(struct hist_entry *he, u64 period)
222{ 221{
223 u64 total = he->hists->stats.total_period; 222 u64 total = hists__total_period(he->hists);
223
224 return (period * 100.0) / total; 224 return (period * 100.0) / total;
225} 225}
226 226
@@ -259,11 +259,18 @@ static s64 compute_wdiff(struct hist_entry *he, struct hist_entry *pair)
259static int formula_delta(struct hist_entry *he, struct hist_entry *pair, 259static int formula_delta(struct hist_entry *he, struct hist_entry *pair,
260 char *buf, size_t size) 260 char *buf, size_t size)
261{ 261{
262 u64 he_total = he->hists->stats.total_period;
263 u64 pair_total = pair->hists->stats.total_period;
264
265 if (symbol_conf.filter_relative) {
266 he_total = he->hists->stats.total_non_filtered_period;
267 pair_total = pair->hists->stats.total_non_filtered_period;
268 }
262 return scnprintf(buf, size, 269 return scnprintf(buf, size,
263 "(%" PRIu64 " * 100 / %" PRIu64 ") - " 270 "(%" PRIu64 " * 100 / %" PRIu64 ") - "
264 "(%" PRIu64 " * 100 / %" PRIu64 ")", 271 "(%" PRIu64 " * 100 / %" PRIu64 ")",
265 pair->stat.period, pair->hists->stats.total_period, 272 pair->stat.period, pair_total,
266 he->stat.period, he->hists->stats.total_period); 273 he->stat.period, he_total);
267} 274}
268 275
269static int formula_ratio(struct hist_entry *he, struct hist_entry *pair, 276static int formula_ratio(struct hist_entry *he, struct hist_entry *pair,
@@ -308,7 +315,7 @@ static int hists__add_entry(struct hists *hists,
308 u64 weight, u64 transaction) 315 u64 weight, u64 transaction)
309{ 316{
310 if (__hists__add_entry(hists, al, NULL, NULL, NULL, period, weight, 317 if (__hists__add_entry(hists, al, NULL, NULL, NULL, period, weight,
311 transaction) != NULL) 318 transaction, true) != NULL)
312 return 0; 319 return 0;
313 return -ENOMEM; 320 return -ENOMEM;
314} 321}
@@ -327,16 +334,22 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused,
327 return -1; 334 return -1;
328 } 335 }
329 336
330 if (al.filtered)
331 return 0;
332
333 if (hists__add_entry(&evsel->hists, &al, sample->period, 337 if (hists__add_entry(&evsel->hists, &al, sample->period,
334 sample->weight, sample->transaction)) { 338 sample->weight, sample->transaction)) {
335 pr_warning("problem incrementing symbol period, skipping event\n"); 339 pr_warning("problem incrementing symbol period, skipping event\n");
336 return -1; 340 return -1;
337 } 341 }
338 342
343 /*
344 * The total_period is updated here before going to the output
345 * tree since normally only the baseline hists will call
346 * hists__output_resort() and precompute needs the total
347 * period in order to sort entries by percentage delta.
348 */
339 evsel->hists.stats.total_period += sample->period; 349 evsel->hists.stats.total_period += sample->period;
350 if (!al.filtered)
351 evsel->hists.stats.total_non_filtered_period += sample->period;
352
340 return 0; 353 return 0;
341} 354}
342 355
@@ -564,8 +577,7 @@ static void hists__compute_resort(struct hists *hists)
564 hists->entries = RB_ROOT; 577 hists->entries = RB_ROOT;
565 next = rb_first(root); 578 next = rb_first(root);
566 579
567 hists->nr_entries = 0; 580 hists__reset_stats(hists);
568 hists->stats.total_period = 0;
569 hists__reset_col_len(hists); 581 hists__reset_col_len(hists);
570 582
571 while (next != NULL) { 583 while (next != NULL) {
@@ -575,7 +587,10 @@ static void hists__compute_resort(struct hists *hists)
575 next = rb_next(&he->rb_node_in); 587 next = rb_next(&he->rb_node_in);
576 588
577 insert_hist_entry_by_compute(&hists->entries, he, compute); 589 insert_hist_entry_by_compute(&hists->entries, he, compute);
578 hists__inc_nr_entries(hists, he); 590 hists__inc_stats(hists, he);
591
592 if (!he->filtered)
593 hists__calc_col_len(hists, he);
579 } 594 }
580} 595}
581 596
@@ -725,20 +740,24 @@ static const struct option options[] = {
725 OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", 740 OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
726 "only consider these symbols"), 741 "only consider these symbols"),
727 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 742 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
728 "sort by key(s): pid, comm, dso, symbol, parent"), 743 "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline, ..."
744 " Please refer the man page for the complete list."),
729 OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator", 745 OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator",
730 "separator for columns, no spaces will be added between " 746 "separator for columns, no spaces will be added between "
731 "columns '.' is reserved."), 747 "columns '.' is reserved."),
732 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", 748 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
733 "Look for files with symbols relative to this directory"), 749 "Look for files with symbols relative to this directory"),
734 OPT_UINTEGER('o', "order", &sort_compute, "Specify compute sorting."), 750 OPT_UINTEGER('o', "order", &sort_compute, "Specify compute sorting."),
751 OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
752 "How to display percentage of filtered entries", parse_filter_percentage),
735 OPT_END() 753 OPT_END()
736}; 754};
737 755
738static double baseline_percent(struct hist_entry *he) 756static double baseline_percent(struct hist_entry *he)
739{ 757{
740 struct hists *hists = he->hists; 758 u64 total = hists__total_period(he->hists);
741 return 100.0 * he->stat.period / hists->stats.total_period; 759
760 return 100.0 * he->stat.period / total;
742} 761}
743 762
744static int hpp__color_baseline(struct perf_hpp_fmt *fmt, 763static int hpp__color_baseline(struct perf_hpp_fmt *fmt,
@@ -1120,7 +1139,8 @@ static int data_init(int argc, const char **argv)
1120 1139
1121int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused) 1140int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
1122{ 1141{
1123 sort_order = diff__default_sort_order; 1142 perf_config(perf_default_config, NULL);
1143
1124 argc = parse_options(argc, argv, options, diff_usage, 0); 1144 argc = parse_options(argc, argv, options, diff_usage, 0);
1125 1145
1126 if (symbol__init() < 0) 1146 if (symbol__init() < 0)
@@ -1131,6 +1151,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
1131 1151
1132 ui_init(); 1152 ui_init();
1133 1153
1154 sort__mode = SORT_MODE__DIFF;
1155
1134 if (setup_sorting() < 0) 1156 if (setup_sorting() < 0)
1135 usage_with_options(diff_usage, options); 1157 usage_with_options(diff_usage, options);
1136 1158
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 3a7387551369..16c7c11ad06e 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -72,7 +72,7 @@ static int perf_event__repipe_attr(struct perf_tool *tool,
72 if (ret) 72 if (ret)
73 return ret; 73 return ret;
74 74
75 if (&inject->output.is_pipe) 75 if (!inject->output.is_pipe)
76 return 0; 76 return 0;
77 77
78 return perf_event__repipe_synth(tool, event); 78 return perf_event__repipe_synth(tool, event);
@@ -209,7 +209,7 @@ static int perf_event__inject_buildid(struct perf_tool *tool,
209 209
210 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 210 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
211 211
212 thread = machine__findnew_thread(machine, sample->pid, sample->pid); 212 thread = machine__findnew_thread(machine, sample->pid, sample->tid);
213 if (thread == NULL) { 213 if (thread == NULL) {
214 pr_err("problem processing %d event, skipping it.\n", 214 pr_err("problem processing %d event, skipping it.\n",
215 event->header.type); 215 event->header.type);
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 929462aa4943..bef3376bfaf3 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -14,6 +14,7 @@
14#include "util/parse-options.h" 14#include "util/parse-options.h"
15#include "util/trace-event.h" 15#include "util/trace-event.h"
16#include "util/data.h" 16#include "util/data.h"
17#include "util/cpumap.h"
17 18
18#include "util/debug.h" 19#include "util/debug.h"
19 20
@@ -31,9 +32,6 @@ static int caller_lines = -1;
31 32
32static bool raw_ip; 33static bool raw_ip;
33 34
34static int *cpunode_map;
35static int max_cpu_num;
36
37struct alloc_stat { 35struct alloc_stat {
38 u64 call_site; 36 u64 call_site;
39 u64 ptr; 37 u64 ptr;
@@ -55,76 +53,6 @@ static struct rb_root root_caller_sorted;
55static unsigned long total_requested, total_allocated; 53static unsigned long total_requested, total_allocated;
56static unsigned long nr_allocs, nr_cross_allocs; 54static unsigned long nr_allocs, nr_cross_allocs;
57 55
58#define PATH_SYS_NODE "/sys/devices/system/node"
59
60static int init_cpunode_map(void)
61{
62 FILE *fp;
63 int i, err = -1;
64
65 fp = fopen("/sys/devices/system/cpu/kernel_max", "r");
66 if (!fp) {
67 max_cpu_num = 4096;
68 return 0;
69 }
70
71 if (fscanf(fp, "%d", &max_cpu_num) < 1) {
72 pr_err("Failed to read 'kernel_max' from sysfs");
73 goto out_close;
74 }
75
76 max_cpu_num++;
77
78 cpunode_map = calloc(max_cpu_num, sizeof(int));
79 if (!cpunode_map) {
80 pr_err("%s: calloc failed\n", __func__);
81 goto out_close;
82 }
83
84 for (i = 0; i < max_cpu_num; i++)
85 cpunode_map[i] = -1;
86
87 err = 0;
88out_close:
89 fclose(fp);
90 return err;
91}
92
93static int setup_cpunode_map(void)
94{
95 struct dirent *dent1, *dent2;
96 DIR *dir1, *dir2;
97 unsigned int cpu, mem;
98 char buf[PATH_MAX];
99
100 if (init_cpunode_map())
101 return -1;
102
103 dir1 = opendir(PATH_SYS_NODE);
104 if (!dir1)
105 return 0;
106
107 while ((dent1 = readdir(dir1)) != NULL) {
108 if (dent1->d_type != DT_DIR ||
109 sscanf(dent1->d_name, "node%u", &mem) < 1)
110 continue;
111
112 snprintf(buf, PATH_MAX, "%s/%s", PATH_SYS_NODE, dent1->d_name);
113 dir2 = opendir(buf);
114 if (!dir2)
115 continue;
116 while ((dent2 = readdir(dir2)) != NULL) {
117 if (dent2->d_type != DT_LNK ||
118 sscanf(dent2->d_name, "cpu%u", &cpu) < 1)
119 continue;
120 cpunode_map[cpu] = mem;
121 }
122 closedir(dir2);
123 }
124 closedir(dir1);
125 return 0;
126}
127
128static int insert_alloc_stat(unsigned long call_site, unsigned long ptr, 56static int insert_alloc_stat(unsigned long call_site, unsigned long ptr,
129 int bytes_req, int bytes_alloc, int cpu) 57 int bytes_req, int bytes_alloc, int cpu)
130{ 58{
@@ -235,7 +163,7 @@ static int perf_evsel__process_alloc_node_event(struct perf_evsel *evsel,
235 int ret = perf_evsel__process_alloc_event(evsel, sample); 163 int ret = perf_evsel__process_alloc_event(evsel, sample);
236 164
237 if (!ret) { 165 if (!ret) {
238 int node1 = cpunode_map[sample->cpu], 166 int node1 = cpu__get_node(sample->cpu),
239 node2 = perf_evsel__intval(evsel, sample, "node"); 167 node2 = perf_evsel__intval(evsel, sample, "node");
240 168
241 if (node1 != node2) 169 if (node1 != node2)
@@ -307,7 +235,7 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
307 struct machine *machine) 235 struct machine *machine)
308{ 236{
309 struct thread *thread = machine__findnew_thread(machine, sample->pid, 237 struct thread *thread = machine__findnew_thread(machine, sample->pid,
310 sample->pid); 238 sample->tid);
311 239
312 if (thread == NULL) { 240 if (thread == NULL) {
313 pr_debug("problem processing %d event, skipping it.\n", 241 pr_debug("problem processing %d event, skipping it.\n",
@@ -756,11 +684,13 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
756 OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"), 684 OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"),
757 OPT_END() 685 OPT_END()
758 }; 686 };
759 const char * const kmem_usage[] = { 687 const char *const kmem_subcommands[] = { "record", "stat", NULL };
760 "perf kmem [<options>] {record|stat}", 688 const char *kmem_usage[] = {
689 NULL,
761 NULL 690 NULL
762 }; 691 };
763 argc = parse_options(argc, argv, kmem_options, kmem_usage, 0); 692 argc = parse_options_subcommand(argc, argv, kmem_options,
693 kmem_subcommands, kmem_usage, 0);
764 694
765 if (!argc) 695 if (!argc)
766 usage_with_options(kmem_usage, kmem_options); 696 usage_with_options(kmem_usage, kmem_options);
@@ -770,7 +700,7 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
770 if (!strncmp(argv[0], "rec", 3)) { 700 if (!strncmp(argv[0], "rec", 3)) {
771 return __cmd_record(argc, argv); 701 return __cmd_record(argc, argv);
772 } else if (!strcmp(argv[0], "stat")) { 702 } else if (!strcmp(argv[0], "stat")) {
773 if (setup_cpunode_map()) 703 if (cpu__setup_cpunode_map())
774 return -1; 704 return -1;
775 705
776 if (list_empty(&caller_sort)) 706 if (list_empty(&caller_sort))
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index c852c7a85d32..6148afc995c6 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -961,8 +961,10 @@ int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused)
961 "perf lock info [<options>]", 961 "perf lock info [<options>]",
962 NULL 962 NULL
963 }; 963 };
964 const char * const lock_usage[] = { 964 const char *const lock_subcommands[] = { "record", "report", "script",
965 "perf lock [<options>] {record|report|script|info}", 965 "info", NULL };
966 const char *lock_usage[] = {
967 NULL,
966 NULL 968 NULL
967 }; 969 };
968 const char * const report_usage[] = { 970 const char * const report_usage[] = {
@@ -976,8 +978,8 @@ int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused)
976 for (i = 0; i < LOCKHASH_SIZE; i++) 978 for (i = 0; i < LOCKHASH_SIZE; i++)
977 INIT_LIST_HEAD(lockhash_table + i); 979 INIT_LIST_HEAD(lockhash_table + i);
978 980
979 argc = parse_options(argc, argv, lock_options, lock_usage, 981 argc = parse_options_subcommand(argc, argv, lock_options, lock_subcommands,
980 PARSE_OPT_STOP_AT_NON_OPTION); 982 lock_usage, PARSE_OPT_STOP_AT_NON_OPTION);
981 if (!argc) 983 if (!argc)
982 usage_with_options(lock_usage, lock_options); 984 usage_with_options(lock_usage, lock_options);
983 985
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c
index 2e3ade69a58e..4a1a6c94a5eb 100644
--- a/tools/perf/builtin-mem.c
+++ b/tools/perf/builtin-mem.c
@@ -21,11 +21,6 @@ struct perf_mem {
21 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 21 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
22}; 22};
23 23
24static const char * const mem_usage[] = {
25 "perf mem [<options>] {record <command> |report}",
26 NULL
27};
28
29static int __cmd_record(int argc, const char **argv) 24static int __cmd_record(int argc, const char **argv)
30{ 25{
31 int rec_argc, i = 0, j; 26 int rec_argc, i = 0, j;
@@ -220,9 +215,15 @@ int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused)
220 " between columns '.' is reserved."), 215 " between columns '.' is reserved."),
221 OPT_END() 216 OPT_END()
222 }; 217 };
218 const char *const mem_subcommands[] = { "record", "report", NULL };
219 const char *mem_usage[] = {
220 NULL,
221 NULL
222 };
223
223 224
224 argc = parse_options(argc, argv, mem_options, mem_usage, 225 argc = parse_options_subcommand(argc, argv, mem_options, mem_subcommands,
225 PARSE_OPT_STOP_AT_NON_OPTION); 226 mem_usage, PARSE_OPT_STOP_AT_NON_OPTION);
226 227
227 if (!argc || !(strncmp(argv[0], "rec", 3) || mem_operation)) 228 if (!argc || !(strncmp(argv[0], "rec", 3) || mem_operation))
228 usage_with_options(mem_usage, mem_options); 229 usage_with_options(mem_usage, mem_options);
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index cdcd4eb3a57d..c63fa2925075 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -288,6 +288,13 @@ static void cleanup_params(void)
288 memset(&params, 0, sizeof(params)); 288 memset(&params, 0, sizeof(params));
289} 289}
290 290
291static void pr_err_with_code(const char *msg, int err)
292{
293 pr_err("%s", msg);
294 pr_debug(" Reason: %s (Code: %d)", strerror(-err), err);
295 pr_err("\n");
296}
297
291static int 298static int
292__cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) 299__cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
293{ 300{
@@ -379,7 +386,7 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
379 } 386 }
380 ret = parse_probe_event_argv(argc, argv); 387 ret = parse_probe_event_argv(argc, argv);
381 if (ret < 0) { 388 if (ret < 0) {
382 pr_err(" Error: Parse Error. (%d)\n", ret); 389 pr_err_with_code(" Error: Command Parse Error.", ret);
383 return ret; 390 return ret;
384 } 391 }
385 } 392 }
@@ -419,8 +426,7 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
419 } 426 }
420 ret = show_perf_probe_events(); 427 ret = show_perf_probe_events();
421 if (ret < 0) 428 if (ret < 0)
422 pr_err(" Error: Failed to show event list. (%d)\n", 429 pr_err_with_code(" Error: Failed to show event list.", ret);
423 ret);
424 return ret; 430 return ret;
425 } 431 }
426 if (params.show_funcs) { 432 if (params.show_funcs) {
@@ -445,8 +451,7 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
445 strfilter__delete(params.filter); 451 strfilter__delete(params.filter);
446 params.filter = NULL; 452 params.filter = NULL;
447 if (ret < 0) 453 if (ret < 0)
448 pr_err(" Error: Failed to show functions." 454 pr_err_with_code(" Error: Failed to show functions.", ret);
449 " (%d)\n", ret);
450 return ret; 455 return ret;
451 } 456 }
452 457
@@ -464,7 +469,7 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
464 469
465 ret = show_line_range(&params.line_range, params.target); 470 ret = show_line_range(&params.line_range, params.target);
466 if (ret < 0) 471 if (ret < 0)
467 pr_err(" Error: Failed to show lines. (%d)\n", ret); 472 pr_err_with_code(" Error: Failed to show lines.", ret);
468 return ret; 473 return ret;
469 } 474 }
470 if (params.show_vars) { 475 if (params.show_vars) {
@@ -485,7 +490,7 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
485 strfilter__delete(params.filter); 490 strfilter__delete(params.filter);
486 params.filter = NULL; 491 params.filter = NULL;
487 if (ret < 0) 492 if (ret < 0)
488 pr_err(" Error: Failed to show vars. (%d)\n", ret); 493 pr_err_with_code(" Error: Failed to show vars.", ret);
489 return ret; 494 return ret;
490 } 495 }
491#endif 496#endif
@@ -493,7 +498,7 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
493 if (params.dellist) { 498 if (params.dellist) {
494 ret = del_perf_probe_events(params.dellist); 499 ret = del_perf_probe_events(params.dellist);
495 if (ret < 0) { 500 if (ret < 0) {
496 pr_err(" Error: Failed to delete events. (%d)\n", ret); 501 pr_err_with_code(" Error: Failed to delete events.", ret);
497 return ret; 502 return ret;
498 } 503 }
499 } 504 }
@@ -504,7 +509,7 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
504 params.target, 509 params.target,
505 params.force_add); 510 params.force_add);
506 if (ret < 0) { 511 if (ret < 0) {
507 pr_err(" Error: Failed to add events. (%d)\n", ret); 512 pr_err_with_code(" Error: Failed to add events.", ret);
508 return ret; 513 return ret;
509 } 514 }
510 } 515 }
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 8ce62ef7f6c3..378b85b731a7 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -30,37 +30,6 @@
30#include <sched.h> 30#include <sched.h>
31#include <sys/mman.h> 31#include <sys/mman.h>
32 32
33#ifndef HAVE_ON_EXIT_SUPPORT
34#ifndef ATEXIT_MAX
35#define ATEXIT_MAX 32
36#endif
37static int __on_exit_count = 0;
38typedef void (*on_exit_func_t) (int, void *);
39static on_exit_func_t __on_exit_funcs[ATEXIT_MAX];
40static void *__on_exit_args[ATEXIT_MAX];
41static int __exitcode = 0;
42static void __handle_on_exit_funcs(void);
43static int on_exit(on_exit_func_t function, void *arg);
44#define exit(x) (exit)(__exitcode = (x))
45
46static int on_exit(on_exit_func_t function, void *arg)
47{
48 if (__on_exit_count == ATEXIT_MAX)
49 return -ENOMEM;
50 else if (__on_exit_count == 0)
51 atexit(__handle_on_exit_funcs);
52 __on_exit_funcs[__on_exit_count] = function;
53 __on_exit_args[__on_exit_count++] = arg;
54 return 0;
55}
56
57static void __handle_on_exit_funcs(void)
58{
59 int i;
60 for (i = 0; i < __on_exit_count; i++)
61 __on_exit_funcs[i] (__exitcode, __on_exit_args[i]);
62}
63#endif
64 33
65struct record { 34struct record {
66 struct perf_tool tool; 35 struct perf_tool tool;
@@ -147,29 +116,19 @@ static void sig_handler(int sig)
147{ 116{
148 if (sig == SIGCHLD) 117 if (sig == SIGCHLD)
149 child_finished = 1; 118 child_finished = 1;
119 else
120 signr = sig;
150 121
151 done = 1; 122 done = 1;
152 signr = sig;
153} 123}
154 124
155static void record__sig_exit(int exit_status __maybe_unused, void *arg) 125static void record__sig_exit(void)
156{ 126{
157 struct record *rec = arg; 127 if (signr == -1)
158 int status;
159
160 if (rec->evlist->workload.pid > 0) {
161 if (!child_finished)
162 kill(rec->evlist->workload.pid, SIGTERM);
163
164 wait(&status);
165 if (WIFSIGNALED(status))
166 psignal(WTERMSIG(status), rec->progname);
167 }
168
169 if (signr == -1 || signr == SIGUSR1)
170 return; 128 return;
171 129
172 signal(signr, SIG_DFL); 130 signal(signr, SIG_DFL);
131 raise(signr);
173} 132}
174 133
175static int record__open(struct record *rec) 134static int record__open(struct record *rec)
@@ -243,27 +202,6 @@ static int process_buildids(struct record *rec)
243 size, &build_id__mark_dso_hit_ops); 202 size, &build_id__mark_dso_hit_ops);
244} 203}
245 204
246static void record__exit(int status, void *arg)
247{
248 struct record *rec = arg;
249 struct perf_data_file *file = &rec->file;
250
251 if (status != 0)
252 return;
253
254 if (!file->is_pipe) {
255 rec->session->header.data_size += rec->bytes_written;
256
257 if (!rec->no_buildid)
258 process_buildids(rec);
259 perf_session__write_header(rec->session, rec->evlist,
260 file->fd, true);
261 perf_session__delete(rec->session);
262 perf_evlist__delete(rec->evlist);
263 symbol__exit();
264 }
265}
266
267static void perf_event__synthesize_guest_os(struct machine *machine, void *data) 205static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
268{ 206{
269 int err; 207 int err;
@@ -344,18 +282,19 @@ static volatile int workload_exec_errno;
344 * if the fork fails, since we asked by setting its 282 * if the fork fails, since we asked by setting its
345 * want_signal to true. 283 * want_signal to true.
346 */ 284 */
347static void workload_exec_failed_signal(int signo, siginfo_t *info, 285static void workload_exec_failed_signal(int signo __maybe_unused,
286 siginfo_t *info,
348 void *ucontext __maybe_unused) 287 void *ucontext __maybe_unused)
349{ 288{
350 workload_exec_errno = info->si_value.sival_int; 289 workload_exec_errno = info->si_value.sival_int;
351 done = 1; 290 done = 1;
352 signr = signo;
353 child_finished = 1; 291 child_finished = 1;
354} 292}
355 293
356static int __cmd_record(struct record *rec, int argc, const char **argv) 294static int __cmd_record(struct record *rec, int argc, const char **argv)
357{ 295{
358 int err; 296 int err;
297 int status = 0;
359 unsigned long waking = 0; 298 unsigned long waking = 0;
360 const bool forks = argc > 0; 299 const bool forks = argc > 0;
361 struct machine *machine; 300 struct machine *machine;
@@ -367,7 +306,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
367 306
368 rec->progname = argv[0]; 307 rec->progname = argv[0];
369 308
370 on_exit(record__sig_exit, rec); 309 atexit(record__sig_exit);
371 signal(SIGCHLD, sig_handler); 310 signal(SIGCHLD, sig_handler);
372 signal(SIGINT, sig_handler); 311 signal(SIGINT, sig_handler);
373 signal(SIGTERM, sig_handler); 312 signal(SIGTERM, sig_handler);
@@ -388,32 +327,28 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
388 workload_exec_failed_signal); 327 workload_exec_failed_signal);
389 if (err < 0) { 328 if (err < 0) {
390 pr_err("Couldn't run the workload!\n"); 329 pr_err("Couldn't run the workload!\n");
330 status = err;
391 goto out_delete_session; 331 goto out_delete_session;
392 } 332 }
393 } 333 }
394 334
395 if (record__open(rec) != 0) { 335 if (record__open(rec) != 0) {
396 err = -1; 336 err = -1;
397 goto out_delete_session; 337 goto out_child;
398 } 338 }
399 339
400 if (!rec->evlist->nr_groups) 340 if (!rec->evlist->nr_groups)
401 perf_header__clear_feat(&session->header, HEADER_GROUP_DESC); 341 perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
402 342
403 /*
404 * perf_session__delete(session) will be called at record__exit()
405 */
406 on_exit(record__exit, rec);
407
408 if (file->is_pipe) { 343 if (file->is_pipe) {
409 err = perf_header__write_pipe(file->fd); 344 err = perf_header__write_pipe(file->fd);
410 if (err < 0) 345 if (err < 0)
411 goto out_delete_session; 346 goto out_child;
412 } else { 347 } else {
413 err = perf_session__write_header(session, rec->evlist, 348 err = perf_session__write_header(session, rec->evlist,
414 file->fd, false); 349 file->fd, false);
415 if (err < 0) 350 if (err < 0)
416 goto out_delete_session; 351 goto out_child;
417 } 352 }
418 353
419 if (!rec->no_buildid 354 if (!rec->no_buildid
@@ -421,7 +356,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
421 pr_err("Couldn't generate buildids. " 356 pr_err("Couldn't generate buildids. "
422 "Use --no-buildid to profile anyway.\n"); 357 "Use --no-buildid to profile anyway.\n");
423 err = -1; 358 err = -1;
424 goto out_delete_session; 359 goto out_child;
425 } 360 }
426 361
427 machine = &session->machines.host; 362 machine = &session->machines.host;
@@ -431,7 +366,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
431 process_synthesized_event); 366 process_synthesized_event);
432 if (err < 0) { 367 if (err < 0) {
433 pr_err("Couldn't synthesize attrs.\n"); 368 pr_err("Couldn't synthesize attrs.\n");
434 goto out_delete_session; 369 goto out_child;
435 } 370 }
436 371
437 if (have_tracepoints(&rec->evlist->entries)) { 372 if (have_tracepoints(&rec->evlist->entries)) {
@@ -447,7 +382,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
447 process_synthesized_event); 382 process_synthesized_event);
448 if (err <= 0) { 383 if (err <= 0) {
449 pr_err("Couldn't record tracing data.\n"); 384 pr_err("Couldn't record tracing data.\n");
450 goto out_delete_session; 385 goto out_child;
451 } 386 }
452 rec->bytes_written += err; 387 rec->bytes_written += err;
453 } 388 }
@@ -475,7 +410,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
475 err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads, 410 err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads,
476 process_synthesized_event, opts->sample_address); 411 process_synthesized_event, opts->sample_address);
477 if (err != 0) 412 if (err != 0)
478 goto out_delete_session; 413 goto out_child;
479 414
480 if (rec->realtime_prio) { 415 if (rec->realtime_prio) {
481 struct sched_param param; 416 struct sched_param param;
@@ -484,7 +419,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
484 if (sched_setscheduler(0, SCHED_FIFO, &param)) { 419 if (sched_setscheduler(0, SCHED_FIFO, &param)) {
485 pr_err("Could not set realtime priority.\n"); 420 pr_err("Could not set realtime priority.\n");
486 err = -1; 421 err = -1;
487 goto out_delete_session; 422 goto out_child;
488 } 423 }
489 } 424 }
490 425
@@ -512,13 +447,19 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
512 447
513 if (record__mmap_read_all(rec) < 0) { 448 if (record__mmap_read_all(rec) < 0) {
514 err = -1; 449 err = -1;
515 goto out_delete_session; 450 goto out_child;
516 } 451 }
517 452
518 if (hits == rec->samples) { 453 if (hits == rec->samples) {
519 if (done) 454 if (done)
520 break; 455 break;
521 err = poll(rec->evlist->pollfd, rec->evlist->nr_fds, -1); 456 err = poll(rec->evlist->pollfd, rec->evlist->nr_fds, -1);
457 /*
458 * Propagate error, only if there's any. Ignore positive
459 * number of returned events and interrupt error.
460 */
461 if (err > 0 || (err < 0 && errno == EINTR))
462 err = 0;
522 waking++; 463 waking++;
523 } 464 }
524 465
@@ -538,28 +479,52 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
538 const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg)); 479 const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg));
539 pr_err("Workload failed: %s\n", emsg); 480 pr_err("Workload failed: %s\n", emsg);
540 err = -1; 481 err = -1;
541 goto out_delete_session; 482 goto out_child;
542 } 483 }
543 484
544 if (quiet || signr == SIGUSR1) 485 if (!quiet) {
545 return 0; 486 fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
546 487
547 fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking); 488 /*
489 * Approximate RIP event size: 24 bytes.
490 */
491 fprintf(stderr,
492 "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
493 (double)rec->bytes_written / 1024.0 / 1024.0,
494 file->path,
495 rec->bytes_written / 24);
496 }
548 497
549 /* 498out_child:
550 * Approximate RIP event size: 24 bytes. 499 if (forks) {
551 */ 500 int exit_status;
552 fprintf(stderr,
553 "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
554 (double)rec->bytes_written / 1024.0 / 1024.0,
555 file->path,
556 rec->bytes_written / 24);
557 501
558 return 0; 502 if (!child_finished)
503 kill(rec->evlist->workload.pid, SIGTERM);
504
505 wait(&exit_status);
506
507 if (err < 0)
508 status = err;
509 else if (WIFEXITED(exit_status))
510 status = WEXITSTATUS(exit_status);
511 else if (WIFSIGNALED(exit_status))
512 signr = WTERMSIG(exit_status);
513 } else
514 status = err;
515
516 if (!err && !file->is_pipe) {
517 rec->session->header.data_size += rec->bytes_written;
518
519 if (!rec->no_buildid)
520 process_buildids(rec);
521 perf_session__write_header(rec->session, rec->evlist,
522 file->fd, true);
523 }
559 524
560out_delete_session: 525out_delete_session:
561 perf_session__delete(session); 526 perf_session__delete(session);
562 return err; 527 return status;
563} 528}
564 529
565#define BRANCH_OPT(n, m) \ 530#define BRANCH_OPT(n, m) \
@@ -583,6 +548,7 @@ static const struct branch_mode branch_modes[] = {
583 BRANCH_OPT("abort_tx", PERF_SAMPLE_BRANCH_ABORT_TX), 548 BRANCH_OPT("abort_tx", PERF_SAMPLE_BRANCH_ABORT_TX),
584 BRANCH_OPT("in_tx", PERF_SAMPLE_BRANCH_IN_TX), 549 BRANCH_OPT("in_tx", PERF_SAMPLE_BRANCH_IN_TX),
585 BRANCH_OPT("no_tx", PERF_SAMPLE_BRANCH_NO_TX), 550 BRANCH_OPT("no_tx", PERF_SAMPLE_BRANCH_NO_TX),
551 BRANCH_OPT("cond", PERF_SAMPLE_BRANCH_COND),
586 BRANCH_END 552 BRANCH_END
587}; 553};
588 554
@@ -988,6 +954,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
988 954
989 err = __cmd_record(&record, argc, argv); 955 err = __cmd_record(&record, argc, argv);
990out_symbol_exit: 956out_symbol_exit:
957 perf_evlist__delete(rec->evlist);
991 symbol__exit(); 958 symbol__exit();
992 return err; 959 return err;
993} 960}
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index c8f21137dfd8..21d830bafff3 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -57,6 +57,7 @@ struct report {
57 const char *cpu_list; 57 const char *cpu_list;
58 const char *symbol_filter_str; 58 const char *symbol_filter_str;
59 float min_percent; 59 float min_percent;
60 u64 nr_entries;
60 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 61 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
61}; 62};
62 63
@@ -71,150 +72,69 @@ static int report__config(const char *var, const char *value, void *cb)
71 rep->min_percent = strtof(value, NULL); 72 rep->min_percent = strtof(value, NULL);
72 return 0; 73 return 0;
73 } 74 }
75 if (!strcmp(var, "report.children")) {
76 symbol_conf.cumulate_callchain = perf_config_bool(var, value);
77 return 0;
78 }
74 79
75 return perf_default_config(var, value, cb); 80 return perf_default_config(var, value, cb);
76} 81}
77 82
78static int report__add_mem_hist_entry(struct report *rep, struct addr_location *al, 83static void report__inc_stats(struct report *rep, struct hist_entry *he)
79 struct perf_sample *sample, struct perf_evsel *evsel)
80{ 84{
81 struct symbol *parent = NULL;
82 struct hist_entry *he;
83 struct mem_info *mi, *mx;
84 uint64_t cost;
85 int err = sample__resolve_callchain(sample, &parent, evsel, al, rep->max_stack);
86
87 if (err)
88 return err;
89
90 mi = sample__resolve_mem(sample, al);
91 if (!mi)
92 return -ENOMEM;
93
94 if (rep->hide_unresolved && !al->sym)
95 return 0;
96
97 cost = sample->weight;
98 if (!cost)
99 cost = 1;
100
101 /* 85 /*
102 * must pass period=weight in order to get the correct 86 * The @he is either of a newly created one or an existing one
103 * sorting from hists__collapse_resort() which is solely 87 * merging current sample. We only want to count a new one so
104 * based on periods. We want sorting be done on nr_events * weight 88 * checking ->nr_events being 1.
105 * and this is indirectly achieved by passing period=weight here
106 * and the he_stat__add_period() function.
107 */ 89 */
108 he = __hists__add_entry(&evsel->hists, al, parent, NULL, mi, 90 if (he->stat.nr_events == 1)
109 cost, cost, 0); 91 rep->nr_entries++;
110 if (!he)
111 return -ENOMEM;
112
113 if (ui__has_annotation()) {
114 err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
115 if (err)
116 goto out;
117
118 mx = he->mem_info;
119 err = addr_map_symbol__inc_samples(&mx->daddr, evsel->idx);
120 if (err)
121 goto out;
122 }
123
124 evsel->hists.stats.total_period += cost;
125 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
126 err = hist_entry__append_callchain(he, sample);
127out:
128 return err;
129} 92}
130 93
131static int report__add_branch_hist_entry(struct report *rep, struct addr_location *al, 94static int hist_iter__report_callback(struct hist_entry_iter *iter,
132 struct perf_sample *sample, struct perf_evsel *evsel) 95 struct addr_location *al, bool single,
96 void *arg)
133{ 97{
134 struct symbol *parent = NULL; 98 int err = 0;
135 unsigned i; 99 struct report *rep = arg;
136 struct hist_entry *he; 100 struct hist_entry *he = iter->he;
137 struct branch_info *bi, *bx; 101 struct perf_evsel *evsel = iter->evsel;
138 int err = sample__resolve_callchain(sample, &parent, evsel, al, rep->max_stack); 102 struct mem_info *mi;
139 103 struct branch_info *bi;
140 if (err)
141 return err;
142
143 bi = sample__resolve_bstack(sample, al);
144 if (!bi)
145 return -ENOMEM;
146
147 for (i = 0; i < sample->branch_stack->nr; i++) {
148 if (rep->hide_unresolved && !(bi[i].from.sym && bi[i].to.sym))
149 continue;
150 104
151 err = -ENOMEM; 105 report__inc_stats(rep, he);
152 106
153 /* overwrite the 'al' to branch-to info */ 107 if (!ui__has_annotation())
154 al->map = bi[i].to.map; 108 return 0;
155 al->sym = bi[i].to.sym;
156 al->addr = bi[i].to.addr;
157 /*
158 * The report shows the percentage of total branches captured
159 * and not events sampled. Thus we use a pseudo period of 1.
160 */
161 he = __hists__add_entry(&evsel->hists, al, parent, &bi[i], NULL,
162 1, 1, 0);
163 if (he) {
164 if (ui__has_annotation()) {
165 bx = he->branch_info;
166 err = addr_map_symbol__inc_samples(&bx->from,
167 evsel->idx);
168 if (err)
169 goto out;
170
171 err = addr_map_symbol__inc_samples(&bx->to,
172 evsel->idx);
173 if (err)
174 goto out;
175 }
176 109
177 evsel->hists.stats.total_period += 1; 110 if (sort__mode == SORT_MODE__BRANCH) {
178 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); 111 bi = he->branch_info;
179 } else 112 err = addr_map_symbol__inc_samples(&bi->from, evsel->idx);
113 if (err)
180 goto out; 114 goto out;
181 }
182 err = 0;
183out:
184 free(bi);
185 return err;
186}
187 115
188static int report__add_hist_entry(struct report *rep, struct perf_evsel *evsel, 116 err = addr_map_symbol__inc_samples(&bi->to, evsel->idx);
189 struct addr_location *al, struct perf_sample *sample)
190{
191 struct symbol *parent = NULL;
192 struct hist_entry *he;
193 int err = sample__resolve_callchain(sample, &parent, evsel, al, rep->max_stack);
194
195 if (err)
196 return err;
197 117
198 he = __hists__add_entry(&evsel->hists, al, parent, NULL, NULL, 118 } else if (rep->mem_mode) {
199 sample->period, sample->weight, 119 mi = he->mem_info;
200 sample->transaction); 120 err = addr_map_symbol__inc_samples(&mi->daddr, evsel->idx);
201 if (he == NULL) 121 if (err)
202 return -ENOMEM; 122 goto out;
203 123
204 err = hist_entry__append_callchain(he, sample); 124 err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
205 if (err)
206 goto out;
207 125
208 if (ui__has_annotation()) 126 } else if (symbol_conf.cumulate_callchain) {
127 if (single)
128 err = hist_entry__inc_addr_samples(he, evsel->idx,
129 al->addr);
130 } else {
209 err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); 131 err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
132 }
210 133
211 evsel->hists.stats.total_period += sample->period;
212 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
213out: 134out:
214 return err; 135 return err;
215} 136}
216 137
217
218static int process_sample_event(struct perf_tool *tool, 138static int process_sample_event(struct perf_tool *tool,
219 union perf_event *event, 139 union perf_event *event,
220 struct perf_sample *sample, 140 struct perf_sample *sample,
@@ -223,6 +143,10 @@ static int process_sample_event(struct perf_tool *tool,
223{ 143{
224 struct report *rep = container_of(tool, struct report, tool); 144 struct report *rep = container_of(tool, struct report, tool);
225 struct addr_location al; 145 struct addr_location al;
146 struct hist_entry_iter iter = {
147 .hide_unresolved = rep->hide_unresolved,
148 .add_entry_cb = hist_iter__report_callback,
149 };
226 int ret; 150 int ret;
227 151
228 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) { 152 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
@@ -237,22 +161,23 @@ static int process_sample_event(struct perf_tool *tool,
237 if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap)) 161 if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
238 return 0; 162 return 0;
239 163
240 if (sort__mode == SORT_MODE__BRANCH) { 164 if (sort__mode == SORT_MODE__BRANCH)
241 ret = report__add_branch_hist_entry(rep, &al, sample, evsel); 165 iter.ops = &hist_iter_branch;
242 if (ret < 0) 166 else if (rep->mem_mode)
243 pr_debug("problem adding lbr entry, skipping event\n"); 167 iter.ops = &hist_iter_mem;
244 } else if (rep->mem_mode == 1) { 168 else if (symbol_conf.cumulate_callchain)
245 ret = report__add_mem_hist_entry(rep, &al, sample, evsel); 169 iter.ops = &hist_iter_cumulative;
246 if (ret < 0) 170 else
247 pr_debug("problem adding mem entry, skipping event\n"); 171 iter.ops = &hist_iter_normal;
248 } else { 172
249 if (al.map != NULL) 173 if (al.map != NULL)
250 al.map->dso->hit = 1; 174 al.map->dso->hit = 1;
175
176 ret = hist_entry_iter__add(&iter, &al, evsel, sample, rep->max_stack,
177 rep);
178 if (ret < 0)
179 pr_debug("problem adding hist entry, skipping event\n");
251 180
252 ret = report__add_hist_entry(rep, evsel, &al, sample);
253 if (ret < 0)
254 pr_debug("problem incrementing symbol period, skipping event\n");
255 }
256 return ret; 181 return ret;
257} 182}
258 183
@@ -309,6 +234,14 @@ static int report__setup_sample_type(struct report *rep)
309 } 234 }
310 } 235 }
311 236
237 if (symbol_conf.cumulate_callchain) {
238 /* Silently ignore if callchain is missing */
239 if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) {
240 symbol_conf.cumulate_callchain = false;
241 perf_hpp__cancel_cumulate();
242 }
243 }
244
312 if (sort__mode == SORT_MODE__BRANCH) { 245 if (sort__mode == SORT_MODE__BRANCH) {
313 if (!is_pipe && 246 if (!is_pipe &&
314 !(sample_type & PERF_SAMPLE_BRANCH_STACK)) { 247 !(sample_type & PERF_SAMPLE_BRANCH_STACK)) {
@@ -337,6 +270,11 @@ static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report
337 char buf[512]; 270 char buf[512];
338 size_t size = sizeof(buf); 271 size_t size = sizeof(buf);
339 272
273 if (symbol_conf.filter_relative) {
274 nr_samples = hists->stats.nr_non_filtered_samples;
275 nr_events = hists->stats.total_non_filtered_period;
276 }
277
340 if (perf_evsel__is_group_event(evsel)) { 278 if (perf_evsel__is_group_event(evsel)) {
341 struct perf_evsel *pos; 279 struct perf_evsel *pos;
342 280
@@ -344,8 +282,13 @@ static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report
344 evname = buf; 282 evname = buf;
345 283
346 for_each_group_member(pos, evsel) { 284 for_each_group_member(pos, evsel) {
347 nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE]; 285 if (symbol_conf.filter_relative) {
348 nr_events += pos->hists.stats.total_period; 286 nr_samples += pos->hists.stats.nr_non_filtered_samples;
287 nr_events += pos->hists.stats.total_non_filtered_period;
288 } else {
289 nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
290 nr_events += pos->hists.stats.total_period;
291 }
349 } 292 }
350 } 293 }
351 294
@@ -470,24 +413,12 @@ static int report__browse_hists(struct report *rep)
470 return ret; 413 return ret;
471} 414}
472 415
473static u64 report__collapse_hists(struct report *rep) 416static void report__collapse_hists(struct report *rep)
474{ 417{
475 struct ui_progress prog; 418 struct ui_progress prog;
476 struct perf_evsel *pos; 419 struct perf_evsel *pos;
477 u64 nr_samples = 0;
478 /*
479 * Count number of histogram entries to use when showing progress,
480 * reusing nr_samples variable.
481 */
482 evlist__for_each(rep->session->evlist, pos)
483 nr_samples += pos->hists.nr_entries;
484 420
485 ui_progress__init(&prog, nr_samples, "Merging related events..."); 421 ui_progress__init(&prog, rep->nr_entries, "Merging related events...");
486 /*
487 * Count total number of samples, will be used to check if this
488 * session had any.
489 */
490 nr_samples = 0;
491 422
492 evlist__for_each(rep->session->evlist, pos) { 423 evlist__for_each(rep->session->evlist, pos) {
493 struct hists *hists = &pos->hists; 424 struct hists *hists = &pos->hists;
@@ -496,7 +427,6 @@ static u64 report__collapse_hists(struct report *rep)
496 hists->symbol_filter_str = rep->symbol_filter_str; 427 hists->symbol_filter_str = rep->symbol_filter_str;
497 428
498 hists__collapse_resort(hists, &prog); 429 hists__collapse_resort(hists, &prog);
499 nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE];
500 430
501 /* Non-group events are considered as leader */ 431 /* Non-group events are considered as leader */
502 if (symbol_conf.event_group && 432 if (symbol_conf.event_group &&
@@ -509,14 +439,11 @@ static u64 report__collapse_hists(struct report *rep)
509 } 439 }
510 440
511 ui_progress__finish(); 441 ui_progress__finish();
512
513 return nr_samples;
514} 442}
515 443
516static int __cmd_report(struct report *rep) 444static int __cmd_report(struct report *rep)
517{ 445{
518 int ret; 446 int ret;
519 u64 nr_samples;
520 struct perf_session *session = rep->session; 447 struct perf_session *session = rep->session;
521 struct perf_evsel *pos; 448 struct perf_evsel *pos;
522 struct perf_data_file *file = session->file; 449 struct perf_data_file *file = session->file;
@@ -556,12 +483,12 @@ static int __cmd_report(struct report *rep)
556 } 483 }
557 } 484 }
558 485
559 nr_samples = report__collapse_hists(rep); 486 report__collapse_hists(rep);
560 487
561 if (session_done()) 488 if (session_done())
562 return 0; 489 return 0;
563 490
564 if (nr_samples == 0) { 491 if (rep->nr_entries == 0) {
565 ui__error("The %s file has no samples!\n", file->path); 492 ui__error("The %s file has no samples!\n", file->path);
566 return 0; 493 return 0;
567 } 494 }
@@ -573,11 +500,9 @@ static int __cmd_report(struct report *rep)
573} 500}
574 501
575static int 502static int
576parse_callchain_opt(const struct option *opt, const char *arg, int unset) 503report_parse_callchain_opt(const struct option *opt, const char *arg, int unset)
577{ 504{
578 struct report *rep = (struct report *)opt->value; 505 struct report *rep = (struct report *)opt->value;
579 char *tok, *tok2;
580 char *endptr;
581 506
582 /* 507 /*
583 * --no-call-graph 508 * --no-call-graph
@@ -587,80 +512,7 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset)
587 return 0; 512 return 0;
588 } 513 }
589 514
590 symbol_conf.use_callchain = true; 515 return parse_callchain_report_opt(arg);
591
592 if (!arg)
593 return 0;
594
595 tok = strtok((char *)arg, ",");
596 if (!tok)
597 return -1;
598
599 /* get the output mode */
600 if (!strncmp(tok, "graph", strlen(arg)))
601 callchain_param.mode = CHAIN_GRAPH_ABS;
602
603 else if (!strncmp(tok, "flat", strlen(arg)))
604 callchain_param.mode = CHAIN_FLAT;
605
606 else if (!strncmp(tok, "fractal", strlen(arg)))
607 callchain_param.mode = CHAIN_GRAPH_REL;
608
609 else if (!strncmp(tok, "none", strlen(arg))) {
610 callchain_param.mode = CHAIN_NONE;
611 symbol_conf.use_callchain = false;
612
613 return 0;
614 }
615
616 else
617 return -1;
618
619 /* get the min percentage */
620 tok = strtok(NULL, ",");
621 if (!tok)
622 goto setup;
623
624 callchain_param.min_percent = strtod(tok, &endptr);
625 if (tok == endptr)
626 return -1;
627
628 /* get the print limit */
629 tok2 = strtok(NULL, ",");
630 if (!tok2)
631 goto setup;
632
633 if (tok2[0] != 'c') {
634 callchain_param.print_limit = strtoul(tok2, &endptr, 0);
635 tok2 = strtok(NULL, ",");
636 if (!tok2)
637 goto setup;
638 }
639
640 /* get the call chain order */
641 if (!strncmp(tok2, "caller", strlen("caller")))
642 callchain_param.order = ORDER_CALLER;
643 else if (!strncmp(tok2, "callee", strlen("callee")))
644 callchain_param.order = ORDER_CALLEE;
645 else
646 return -1;
647
648 /* Get the sort key */
649 tok2 = strtok(NULL, ",");
650 if (!tok2)
651 goto setup;
652 if (!strncmp(tok2, "function", strlen("function")))
653 callchain_param.key = CCKEY_FUNCTION;
654 else if (!strncmp(tok2, "address", strlen("address")))
655 callchain_param.key = CCKEY_ADDRESS;
656 else
657 return -1;
658setup:
659 if (callchain_register_param(&callchain_param) < 0) {
660 pr_err("Can't register callchain params\n");
661 return -1;
662 }
663 return 0;
664} 516}
665 517
666int 518int
@@ -760,10 +612,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
760 OPT_BOOLEAN(0, "header-only", &report.header_only, 612 OPT_BOOLEAN(0, "header-only", &report.header_only,
761 "Show only data header."), 613 "Show only data header."),
762 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 614 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
763 "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline," 615 "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline, ..."
764 " dso_to, dso_from, symbol_to, symbol_from, mispredict," 616 " Please refer the man page for the complete list."),
765 " weight, local_weight, mem, symbol_daddr, dso_daddr, tlb, " 617 OPT_STRING('F', "fields", &field_order, "key[,keys...]",
766 "snoop, locked, abort, in_tx, transaction"), 618 "output field(s): overhead, period, sample plus all of sort keys"),
767 OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization, 619 OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
768 "Show sample percentage for different cpu modes"), 620 "Show sample percentage for different cpu modes"),
769 OPT_STRING('p', "parent", &parent_pattern, "regex", 621 OPT_STRING('p', "parent", &parent_pattern, "regex",
@@ -772,7 +624,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
772 "Only display entries with parent-match"), 624 "Only display entries with parent-match"),
773 OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order", 625 OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order",
774 "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit, callchain order, key (function or address). " 626 "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit, callchain order, key (function or address). "
775 "Default: fractal,0.5,callee,function", &parse_callchain_opt, callchain_default_opt), 627 "Default: fractal,0.5,callee,function", &report_parse_callchain_opt, callchain_default_opt),
628 OPT_BOOLEAN(0, "children", &symbol_conf.cumulate_callchain,
629 "Accumulate callchains of children and show total overhead as well"),
776 OPT_INTEGER(0, "max-stack", &report.max_stack, 630 OPT_INTEGER(0, "max-stack", &report.max_stack,
777 "Set the maximum stack depth when parsing the callchain, " 631 "Set the maximum stack depth when parsing the callchain, "
778 "anything beyond the specified depth will be ignored. " 632 "anything beyond the specified depth will be ignored. "
@@ -823,6 +677,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
823 OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"), 677 OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"),
824 OPT_CALLBACK(0, "percent-limit", &report, "percent", 678 OPT_CALLBACK(0, "percent-limit", &report, "percent",
825 "Don't show entries under that percent", parse_percent_limit), 679 "Don't show entries under that percent", parse_percent_limit),
680 OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
681 "how to display percentage of filtered entries", parse_filter_percentage),
826 OPT_END() 682 OPT_END()
827 }; 683 };
828 struct perf_data_file file = { 684 struct perf_data_file file = {
@@ -863,55 +719,37 @@ repeat:
863 has_br_stack = perf_header__has_feat(&session->header, 719 has_br_stack = perf_header__has_feat(&session->header,
864 HEADER_BRANCH_STACK); 720 HEADER_BRANCH_STACK);
865 721
866 if (branch_mode == -1 && has_br_stack) 722 if (branch_mode == -1 && has_br_stack) {
867 sort__mode = SORT_MODE__BRANCH; 723 sort__mode = SORT_MODE__BRANCH;
868 724 symbol_conf.cumulate_callchain = false;
869 /* sort__mode could be NORMAL if --no-branch-stack */
870 if (sort__mode == SORT_MODE__BRANCH) {
871 /*
872 * if no sort_order is provided, then specify
873 * branch-mode specific order
874 */
875 if (sort_order == default_sort_order)
876 sort_order = "comm,dso_from,symbol_from,"
877 "dso_to,symbol_to";
878
879 } 725 }
726
880 if (report.mem_mode) { 727 if (report.mem_mode) {
881 if (sort__mode == SORT_MODE__BRANCH) { 728 if (sort__mode == SORT_MODE__BRANCH) {
882 pr_err("branch and mem mode incompatible\n"); 729 pr_err("branch and mem mode incompatible\n");
883 goto error; 730 goto error;
884 } 731 }
885 sort__mode = SORT_MODE__MEMORY; 732 sort__mode = SORT_MODE__MEMORY;
886 733 symbol_conf.cumulate_callchain = false;
887 /*
888 * if no sort_order is provided, then specify
889 * branch-mode specific order
890 */
891 if (sort_order == default_sort_order)
892 sort_order = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked";
893 } 734 }
894 735
895 if (setup_sorting() < 0) { 736 if (setup_sorting() < 0) {
896 parse_options_usage(report_usage, options, "s", 1); 737 if (sort_order)
738 parse_options_usage(report_usage, options, "s", 1);
739 if (field_order)
740 parse_options_usage(sort_order ? NULL : report_usage,
741 options, "F", 1);
897 goto error; 742 goto error;
898 } 743 }
899 744
900 if (parent_pattern != default_parent_pattern) {
901 if (sort_dimension__add("parent") < 0)
902 goto error;
903 }
904
905 /* Force tty output for header output. */ 745 /* Force tty output for header output. */
906 if (report.header || report.header_only) 746 if (report.header || report.header_only)
907 use_browser = 0; 747 use_browser = 0;
908 748
909 if (strcmp(input_name, "-") != 0) 749 if (strcmp(input_name, "-") != 0)
910 setup_browser(true); 750 setup_browser(true);
911 else { 751 else
912 use_browser = 0; 752 use_browser = 0;
913 perf_hpp__init();
914 }
915 753
916 if (report.header || report.header_only) { 754 if (report.header || report.header_only) {
917 perf_session__fprintf_info(session, stdout, 755 perf_session__fprintf_info(session, stdout,
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 9ac0a495c954..c38d06c04775 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -66,7 +66,7 @@ struct sched_atom {
66 struct task_desc *wakee; 66 struct task_desc *wakee;
67}; 67};
68 68
69#define TASK_STATE_TO_CHAR_STR "RSDTtZX" 69#define TASK_STATE_TO_CHAR_STR "RSDTtZXxKWP"
70 70
71enum thread_state { 71enum thread_state {
72 THREAD_SLEEPING = 0, 72 THREAD_SLEEPING = 0,
@@ -149,7 +149,6 @@ struct perf_sched {
149 unsigned long nr_runs; 149 unsigned long nr_runs;
150 unsigned long nr_timestamps; 150 unsigned long nr_timestamps;
151 unsigned long nr_unordered_timestamps; 151 unsigned long nr_unordered_timestamps;
152 unsigned long nr_state_machine_bugs;
153 unsigned long nr_context_switch_bugs; 152 unsigned long nr_context_switch_bugs;
154 unsigned long nr_events; 153 unsigned long nr_events;
155 unsigned long nr_lost_chunks; 154 unsigned long nr_lost_chunks;
@@ -1007,17 +1006,12 @@ static int latency_wakeup_event(struct perf_sched *sched,
1007 struct perf_sample *sample, 1006 struct perf_sample *sample,
1008 struct machine *machine) 1007 struct machine *machine)
1009{ 1008{
1010 const u32 pid = perf_evsel__intval(evsel, sample, "pid"), 1009 const u32 pid = perf_evsel__intval(evsel, sample, "pid");
1011 success = perf_evsel__intval(evsel, sample, "success");
1012 struct work_atoms *atoms; 1010 struct work_atoms *atoms;
1013 struct work_atom *atom; 1011 struct work_atom *atom;
1014 struct thread *wakee; 1012 struct thread *wakee;
1015 u64 timestamp = sample->time; 1013 u64 timestamp = sample->time;
1016 1014
1017 /* Note for later, it may be interesting to observe the failing cases */
1018 if (!success)
1019 return 0;
1020
1021 wakee = machine__findnew_thread(machine, 0, pid); 1015 wakee = machine__findnew_thread(machine, 0, pid);
1022 atoms = thread_atoms_search(&sched->atom_root, wakee, &sched->cmp_pid); 1016 atoms = thread_atoms_search(&sched->atom_root, wakee, &sched->cmp_pid);
1023 if (!atoms) { 1017 if (!atoms) {
@@ -1037,12 +1031,18 @@ static int latency_wakeup_event(struct perf_sched *sched,
1037 atom = list_entry(atoms->work_list.prev, struct work_atom, list); 1031 atom = list_entry(atoms->work_list.prev, struct work_atom, list);
1038 1032
1039 /* 1033 /*
1034 * As we do not guarantee the wakeup event happens when
1035 * task is out of run queue, also may happen when task is
1036 * on run queue and wakeup only change ->state to TASK_RUNNING,
1037 * then we should not set the ->wake_up_time when wake up a
1038 * task which is on run queue.
1039 *
1040 * You WILL be missing events if you've recorded only 1040 * You WILL be missing events if you've recorded only
1041 * one CPU, or are only looking at only one, so don't 1041 * one CPU, or are only looking at only one, so don't
1042 * make useless noise. 1042 * skip in this case.
1043 */ 1043 */
1044 if (sched->profile_cpu == -1 && atom->state != THREAD_SLEEPING) 1044 if (sched->profile_cpu == -1 && atom->state != THREAD_SLEEPING)
1045 sched->nr_state_machine_bugs++; 1045 return 0;
1046 1046
1047 sched->nr_timestamps++; 1047 sched->nr_timestamps++;
1048 if (atom->sched_out_time > timestamp) { 1048 if (atom->sched_out_time > timestamp) {
@@ -1266,9 +1266,8 @@ static int process_sched_wakeup_event(struct perf_tool *tool,
1266static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel, 1266static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,
1267 struct perf_sample *sample, struct machine *machine) 1267 struct perf_sample *sample, struct machine *machine)
1268{ 1268{
1269 const u32 prev_pid = perf_evsel__intval(evsel, sample, "prev_pid"), 1269 const u32 next_pid = perf_evsel__intval(evsel, sample, "next_pid");
1270 next_pid = perf_evsel__intval(evsel, sample, "next_pid"); 1270 struct thread *sched_in;
1271 struct thread *sched_out __maybe_unused, *sched_in;
1272 int new_shortname; 1271 int new_shortname;
1273 u64 timestamp0, timestamp = sample->time; 1272 u64 timestamp0, timestamp = sample->time;
1274 s64 delta; 1273 s64 delta;
@@ -1291,7 +1290,6 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,
1291 return -1; 1290 return -1;
1292 } 1291 }
1293 1292
1294 sched_out = machine__findnew_thread(machine, 0, prev_pid);
1295 sched_in = machine__findnew_thread(machine, 0, next_pid); 1293 sched_in = machine__findnew_thread(machine, 0, next_pid);
1296 1294
1297 sched->curr_thread[this_cpu] = sched_in; 1295 sched->curr_thread[this_cpu] = sched_in;
@@ -1300,17 +1298,25 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,
1300 1298
1301 new_shortname = 0; 1299 new_shortname = 0;
1302 if (!sched_in->shortname[0]) { 1300 if (!sched_in->shortname[0]) {
1303 sched_in->shortname[0] = sched->next_shortname1; 1301 if (!strcmp(thread__comm_str(sched_in), "swapper")) {
1304 sched_in->shortname[1] = sched->next_shortname2; 1302 /*
1305 1303 * Don't allocate a letter-number for swapper:0
1306 if (sched->next_shortname1 < 'Z') { 1304 * as a shortname. Instead, we use '.' for it.
1307 sched->next_shortname1++; 1305 */
1306 sched_in->shortname[0] = '.';
1307 sched_in->shortname[1] = ' ';
1308 } else { 1308 } else {
1309 sched->next_shortname1='A'; 1309 sched_in->shortname[0] = sched->next_shortname1;
1310 if (sched->next_shortname2 < '9') { 1310 sched_in->shortname[1] = sched->next_shortname2;
1311 sched->next_shortname2++; 1311
1312 if (sched->next_shortname1 < 'Z') {
1313 sched->next_shortname1++;
1312 } else { 1314 } else {
1313 sched->next_shortname2='0'; 1315 sched->next_shortname1 = 'A';
1316 if (sched->next_shortname2 < '9')
1317 sched->next_shortname2++;
1318 else
1319 sched->next_shortname2 = '0';
1314 } 1320 }
1315 } 1321 }
1316 new_shortname = 1; 1322 new_shortname = 1;
@@ -1322,12 +1328,9 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,
1322 else 1328 else
1323 printf("*"); 1329 printf("*");
1324 1330
1325 if (sched->curr_thread[cpu]) { 1331 if (sched->curr_thread[cpu])
1326 if (sched->curr_thread[cpu]->tid) 1332 printf("%2s ", sched->curr_thread[cpu]->shortname);
1327 printf("%2s ", sched->curr_thread[cpu]->shortname); 1333 else
1328 else
1329 printf(". ");
1330 } else
1331 printf(" "); 1334 printf(" ");
1332 } 1335 }
1333 1336
@@ -1425,7 +1428,7 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool __maybe_
1425 int err = 0; 1428 int err = 0;
1426 1429
1427 evsel->hists.stats.total_period += sample->period; 1430 evsel->hists.stats.total_period += sample->period;
1428 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); 1431 hists__inc_nr_samples(&evsel->hists, true);
1429 1432
1430 if (evsel->handler != NULL) { 1433 if (evsel->handler != NULL) {
1431 tracepoint_handler f = evsel->handler; 1434 tracepoint_handler f = evsel->handler;
@@ -1496,14 +1499,6 @@ static void print_bad_events(struct perf_sched *sched)
1496 (double)sched->nr_lost_events/(double)sched->nr_events * 100.0, 1499 (double)sched->nr_lost_events/(double)sched->nr_events * 100.0,
1497 sched->nr_lost_events, sched->nr_events, sched->nr_lost_chunks); 1500 sched->nr_lost_events, sched->nr_events, sched->nr_lost_chunks);
1498 } 1501 }
1499 if (sched->nr_state_machine_bugs && sched->nr_timestamps) {
1500 printf(" INFO: %.3f%% state machine bugs (%ld out of %ld)",
1501 (double)sched->nr_state_machine_bugs/(double)sched->nr_timestamps*100.0,
1502 sched->nr_state_machine_bugs, sched->nr_timestamps);
1503 if (sched->nr_lost_events)
1504 printf(" (due to lost events?)");
1505 printf("\n");
1506 }
1507 if (sched->nr_context_switch_bugs && sched->nr_timestamps) { 1502 if (sched->nr_context_switch_bugs && sched->nr_timestamps) {
1508 printf(" INFO: %.3f%% context switch bugs (%ld out of %ld)", 1503 printf(" INFO: %.3f%% context switch bugs (%ld out of %ld)",
1509 (double)sched->nr_context_switch_bugs/(double)sched->nr_timestamps*100.0, 1504 (double)sched->nr_context_switch_bugs/(double)sched->nr_timestamps*100.0,
@@ -1635,6 +1630,7 @@ static int __cmd_record(int argc, const char **argv)
1635 "-e", "sched:sched_stat_runtime", 1630 "-e", "sched:sched_stat_runtime",
1636 "-e", "sched:sched_process_fork", 1631 "-e", "sched:sched_process_fork",
1637 "-e", "sched:sched_wakeup", 1632 "-e", "sched:sched_wakeup",
1633 "-e", "sched:sched_wakeup_new",
1638 "-e", "sched:sched_migrate_task", 1634 "-e", "sched:sched_migrate_task",
1639 }; 1635 };
1640 1636
@@ -1713,8 +1709,10 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
1713 "perf sched replay [<options>]", 1709 "perf sched replay [<options>]",
1714 NULL 1710 NULL
1715 }; 1711 };
1716 const char * const sched_usage[] = { 1712 const char *const sched_subcommands[] = { "record", "latency", "map",
1717 "perf sched [<options>] {record|latency|map|replay|script}", 1713 "replay", "script", NULL };
1714 const char *sched_usage[] = {
1715 NULL,
1718 NULL 1716 NULL
1719 }; 1717 };
1720 struct trace_sched_handler lat_ops = { 1718 struct trace_sched_handler lat_ops = {
@@ -1736,8 +1734,8 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
1736 for (i = 0; i < ARRAY_SIZE(sched.curr_pid); i++) 1734 for (i = 0; i < ARRAY_SIZE(sched.curr_pid); i++)
1737 sched.curr_pid[i] = -1; 1735 sched.curr_pid[i] = -1;
1738 1736
1739 argc = parse_options(argc, argv, sched_options, sched_usage, 1737 argc = parse_options_subcommand(argc, argv, sched_options, sched_subcommands,
1740 PARSE_OPT_STOP_AT_NON_OPTION); 1738 sched_usage, PARSE_OPT_STOP_AT_NON_OPTION);
1741 if (!argc) 1739 if (!argc)
1742 usage_with_options(sched_usage, sched_options); 1740 usage_with_options(sched_usage, sched_options);
1743 1741
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 65aaa5bbf7ec..377971dc89a3 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -196,6 +196,12 @@ static void perf_top__record_precise_ip(struct perf_top *top,
196 196
197 pthread_mutex_unlock(&notes->lock); 197 pthread_mutex_unlock(&notes->lock);
198 198
199 /*
200 * This function is now called with he->hists->lock held.
201 * Release it before going to sleep.
202 */
203 pthread_mutex_unlock(&he->hists->lock);
204
199 if (err == -ERANGE && !he->ms.map->erange_warned) 205 if (err == -ERANGE && !he->ms.map->erange_warned)
200 ui__warn_map_erange(he->ms.map, sym, ip); 206 ui__warn_map_erange(he->ms.map, sym, ip);
201 else if (err == -ENOMEM) { 207 else if (err == -ENOMEM) {
@@ -203,6 +209,8 @@ static void perf_top__record_precise_ip(struct perf_top *top,
203 sym->name); 209 sym->name);
204 sleep(1); 210 sleep(1);
205 } 211 }
212
213 pthread_mutex_lock(&he->hists->lock);
206} 214}
207 215
208static void perf_top__show_details(struct perf_top *top) 216static void perf_top__show_details(struct perf_top *top)
@@ -238,24 +246,6 @@ out_unlock:
238 pthread_mutex_unlock(&notes->lock); 246 pthread_mutex_unlock(&notes->lock);
239} 247}
240 248
241static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel,
242 struct addr_location *al,
243 struct perf_sample *sample)
244{
245 struct hist_entry *he;
246
247 pthread_mutex_lock(&evsel->hists.lock);
248 he = __hists__add_entry(&evsel->hists, al, NULL, NULL, NULL,
249 sample->period, sample->weight,
250 sample->transaction);
251 pthread_mutex_unlock(&evsel->hists.lock);
252 if (he == NULL)
253 return NULL;
254
255 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
256 return he;
257}
258
259static void perf_top__print_sym_table(struct perf_top *top) 249static void perf_top__print_sym_table(struct perf_top *top)
260{ 250{
261 char bf[160]; 251 char bf[160];
@@ -659,6 +649,26 @@ static int symbol_filter(struct map *map __maybe_unused, struct symbol *sym)
659 return 0; 649 return 0;
660} 650}
661 651
652static int hist_iter__top_callback(struct hist_entry_iter *iter,
653 struct addr_location *al, bool single,
654 void *arg)
655{
656 struct perf_top *top = arg;
657 struct hist_entry *he = iter->he;
658 struct perf_evsel *evsel = iter->evsel;
659
660 if (sort__has_sym && single) {
661 u64 ip = al->addr;
662
663 if (al->map)
664 ip = al->map->unmap_ip(al->map, ip);
665
666 perf_top__record_precise_ip(top, he, evsel->idx, ip);
667 }
668
669 return 0;
670}
671
662static void perf_event__process_sample(struct perf_tool *tool, 672static void perf_event__process_sample(struct perf_tool *tool,
663 const union perf_event *event, 673 const union perf_event *event,
664 struct perf_evsel *evsel, 674 struct perf_evsel *evsel,
@@ -666,8 +676,6 @@ static void perf_event__process_sample(struct perf_tool *tool,
666 struct machine *machine) 676 struct machine *machine)
667{ 677{
668 struct perf_top *top = container_of(tool, struct perf_top, tool); 678 struct perf_top *top = container_of(tool, struct perf_top, tool);
669 struct symbol *parent = NULL;
670 u64 ip = sample->ip;
671 struct addr_location al; 679 struct addr_location al;
672 int err; 680 int err;
673 681
@@ -694,8 +702,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
694 if (event->header.misc & PERF_RECORD_MISC_EXACT_IP) 702 if (event->header.misc & PERF_RECORD_MISC_EXACT_IP)
695 top->exact_samples++; 703 top->exact_samples++;
696 704
697 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0 || 705 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0)
698 al.filtered)
699 return; 706 return;
700 707
701 if (!top->kptr_restrict_warned && 708 if (!top->kptr_restrict_warned &&
@@ -743,25 +750,23 @@ static void perf_event__process_sample(struct perf_tool *tool,
743 } 750 }
744 751
745 if (al.sym == NULL || !al.sym->ignore) { 752 if (al.sym == NULL || !al.sym->ignore) {
746 struct hist_entry *he; 753 struct hist_entry_iter iter = {
754 .add_entry_cb = hist_iter__top_callback,
755 };
747 756
748 err = sample__resolve_callchain(sample, &parent, evsel, &al, 757 if (symbol_conf.cumulate_callchain)
749 top->max_stack); 758 iter.ops = &hist_iter_cumulative;
750 if (err) 759 else
751 return; 760 iter.ops = &hist_iter_normal;
752 761
753 he = perf_evsel__add_hist_entry(evsel, &al, sample); 762 pthread_mutex_lock(&evsel->hists.lock);
754 if (he == NULL) {
755 pr_err("Problem incrementing symbol period, skipping event\n");
756 return;
757 }
758 763
759 err = hist_entry__append_callchain(he, sample); 764 err = hist_entry_iter__add(&iter, &al, evsel, sample,
760 if (err) 765 top->max_stack, top);
761 return; 766 if (err < 0)
767 pr_err("Problem incrementing symbol period, skipping event\n");
762 768
763 if (sort__has_sym) 769 pthread_mutex_unlock(&evsel->hists.lock);
764 perf_top__record_precise_ip(top, he, evsel->idx, ip);
765 } 770 }
766 771
767 return; 772 return;
@@ -999,6 +1004,10 @@ static int perf_top_config(const char *var, const char *value, void *cb)
999 1004
1000 if (!strcmp(var, "top.call-graph")) 1005 if (!strcmp(var, "top.call-graph"))
1001 return record_parse_callchain(value, &top->record_opts); 1006 return record_parse_callchain(value, &top->record_opts);
1007 if (!strcmp(var, "top.children")) {
1008 symbol_conf.cumulate_callchain = perf_config_bool(var, value);
1009 return 0;
1010 }
1002 1011
1003 return perf_default_config(var, value, cb); 1012 return perf_default_config(var, value, cb);
1004} 1013}
@@ -1081,8 +1090,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1081 OPT_INCR('v', "verbose", &verbose, 1090 OPT_INCR('v', "verbose", &verbose,
1082 "be more verbose (show counter open errors, etc)"), 1091 "be more verbose (show counter open errors, etc)"),
1083 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 1092 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1084 "sort by key(s): pid, comm, dso, symbol, parent, weight, local_weight," 1093 "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline, ..."
1085 " abort, in_tx, transaction"), 1094 " Please refer the man page for the complete list."),
1095 OPT_STRING(0, "fields", &field_order, "key[,keys...]",
1096 "output field(s): overhead, period, sample plus all of sort keys"),
1086 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, 1097 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
1087 "Show a column with the number of samples"), 1098 "Show a column with the number of samples"),
1088 OPT_CALLBACK_NOOPT('g', NULL, &top.record_opts, 1099 OPT_CALLBACK_NOOPT('g', NULL, &top.record_opts,
@@ -1091,6 +1102,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1091 OPT_CALLBACK(0, "call-graph", &top.record_opts, 1102 OPT_CALLBACK(0, "call-graph", &top.record_opts,
1092 "mode[,dump_size]", record_callchain_help, 1103 "mode[,dump_size]", record_callchain_help,
1093 &parse_callchain_opt), 1104 &parse_callchain_opt),
1105 OPT_BOOLEAN(0, "children", &symbol_conf.cumulate_callchain,
1106 "Accumulate callchains of children and show total overhead as well"),
1094 OPT_INTEGER(0, "max-stack", &top.max_stack, 1107 OPT_INTEGER(0, "max-stack", &top.max_stack,
1095 "Set the maximum stack depth when parsing the callchain. " 1108 "Set the maximum stack depth when parsing the callchain. "
1096 "Default: " __stringify(PERF_MAX_STACK_DEPTH)), 1109 "Default: " __stringify(PERF_MAX_STACK_DEPTH)),
@@ -1116,6 +1129,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1116 OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"), 1129 OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"),
1117 OPT_CALLBACK(0, "percent-limit", &top, "percent", 1130 OPT_CALLBACK(0, "percent-limit", &top, "percent",
1118 "Don't show entries under that percent", parse_percent_limit), 1131 "Don't show entries under that percent", parse_percent_limit),
1132 OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
1133 "How to display percentage of filtered entries", parse_filter_percentage),
1119 OPT_END() 1134 OPT_END()
1120 }; 1135 };
1121 const char * const top_usage[] = { 1136 const char * const top_usage[] = {
@@ -1133,17 +1148,19 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1133 if (argc) 1148 if (argc)
1134 usage_with_options(top_usage, options); 1149 usage_with_options(top_usage, options);
1135 1150
1136 if (sort_order == default_sort_order) 1151 sort__mode = SORT_MODE__TOP;
1137 sort_order = "dso,symbol"; 1152 /* display thread wants entries to be collapsed in a different tree */
1153 sort__need_collapse = 1;
1138 1154
1139 if (setup_sorting() < 0) { 1155 if (setup_sorting() < 0) {
1140 parse_options_usage(top_usage, options, "s", 1); 1156 if (sort_order)
1157 parse_options_usage(top_usage, options, "s", 1);
1158 if (field_order)
1159 parse_options_usage(sort_order ? NULL : top_usage,
1160 options, "fields", 0);
1141 goto out_delete_evlist; 1161 goto out_delete_evlist;
1142 } 1162 }
1143 1163
1144 /* display thread wants entries to be collapsed in a different tree */
1145 sort__need_collapse = 1;
1146
1147 if (top.use_stdio) 1164 if (top.use_stdio)
1148 use_browser = 0; 1165 use_browser = 0;
1149 else if (top.use_tui) 1166 else if (top.use_tui)
@@ -1192,6 +1209,11 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1192 1209
1193 top.sym_evsel = perf_evlist__first(top.evlist); 1210 top.sym_evsel = perf_evlist__first(top.evlist);
1194 1211
1212 if (!symbol_conf.use_callchain) {
1213 symbol_conf.cumulate_callchain = false;
1214 perf_hpp__cancel_cumulate();
1215 }
1216
1195 symbol_conf.priv_size = sizeof(struct annotation); 1217 symbol_conf.priv_size = sizeof(struct annotation);
1196 1218
1197 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); 1219 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index 802cf544202b..f30ac5e5d271 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -29,16 +29,22 @@ ifeq ($(ARCH),x86)
29 endif 29 endif
30 NO_PERF_REGS := 0 30 NO_PERF_REGS := 0
31endif 31endif
32
32ifeq ($(ARCH),arm) 33ifeq ($(ARCH),arm)
33 NO_PERF_REGS := 0 34 NO_PERF_REGS := 0
34 LIBUNWIND_LIBS = -lunwind -lunwind-arm 35 LIBUNWIND_LIBS = -lunwind -lunwind-arm
35endif 36endif
36 37
37# So far there's only x86 libdw unwind support merged in perf. 38ifeq ($(ARCH),arm64)
39 NO_PERF_REGS := 0
40 LIBUNWIND_LIBS = -lunwind -lunwind-aarch64
41endif
42
43# So far there's only x86 and arm libdw unwind support merged in perf.
38# Disable it on all other architectures in case libdw unwind 44# Disable it on all other architectures in case libdw unwind
39# support is detected in system. Add supported architectures 45# support is detected in system. Add supported architectures
40# to the check. 46# to the check.
41ifneq ($(ARCH),x86) 47ifneq ($(ARCH),$(filter $(ARCH),x86 arm))
42 NO_LIBDW_DWARF_UNWIND := 1 48 NO_LIBDW_DWARF_UNWIND := 1
43endif 49endif
44 50
@@ -168,7 +174,6 @@ CORE_FEATURE_TESTS = \
168 libpython-version \ 174 libpython-version \
169 libslang \ 175 libslang \
170 libunwind \ 176 libunwind \
171 on-exit \
172 stackprotector-all \ 177 stackprotector-all \
173 timerfd \ 178 timerfd \
174 libdw-dwarf-unwind 179 libdw-dwarf-unwind
@@ -194,7 +199,6 @@ VF_FEATURE_TESTS = \
194 libelf-getphdrnum \ 199 libelf-getphdrnum \
195 libelf-mmap \ 200 libelf-mmap \
196 libpython-version \ 201 libpython-version \
197 on-exit \
198 stackprotector-all \ 202 stackprotector-all \
199 timerfd \ 203 timerfd \
200 libunwind-debug-frame \ 204 libunwind-debug-frame \
@@ -295,7 +299,11 @@ else
295 NO_LIBUNWIND := 1 299 NO_LIBUNWIND := 1
296 NO_LIBDW_DWARF_UNWIND := 1 300 NO_LIBDW_DWARF_UNWIND := 1
297 else 301 else
298 msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static); 302 ifneq ($(filter s% -static%,$(LDFLAGS),),)
303 msg := $(error No static glibc found, please install glibc-static);
304 else
305 msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]);
306 endif
299 endif 307 endif
300 else 308 else
301 ifndef NO_LIBDW_DWARF_UNWIND 309 ifndef NO_LIBDW_DWARF_UNWIND
@@ -370,7 +378,7 @@ else
370endif 378endif
371 379
372ifndef NO_LIBUNWIND 380ifndef NO_LIBUNWIND
373 ifeq ($(ARCH),arm) 381 ifeq ($(ARCH),$(filter $(ARCH),arm arm64))
374 $(call feature_check,libunwind-debug-frame) 382 $(call feature_check,libunwind-debug-frame)
375 ifneq ($(feature-libunwind-debug-frame), 1) 383 ifneq ($(feature-libunwind-debug-frame), 1)
376 msg := $(warning No debug_frame support found in libunwind); 384 msg := $(warning No debug_frame support found in libunwind);
@@ -443,6 +451,7 @@ else
443 ifneq ($(feature-libperl), 1) 451 ifneq ($(feature-libperl), 1)
444 CFLAGS += -DNO_LIBPERL 452 CFLAGS += -DNO_LIBPERL
445 NO_LIBPERL := 1 453 NO_LIBPERL := 1
454 msg := $(warning Missing perl devel files. Disabling perl scripting support, consider installing perl-ExtUtils-Embed);
446 else 455 else
447 LDFLAGS += $(PERL_EMBED_LDFLAGS) 456 LDFLAGS += $(PERL_EMBED_LDFLAGS)
448 EXTLIBS += $(PERL_EMBED_LIBADD) 457 EXTLIBS += $(PERL_EMBED_LIBADD)
@@ -565,12 +574,6 @@ ifneq ($(filter -lbfd,$(EXTLIBS)),)
565 CFLAGS += -DHAVE_LIBBFD_SUPPORT 574 CFLAGS += -DHAVE_LIBBFD_SUPPORT
566endif 575endif
567 576
568ifndef NO_ON_EXIT
569 ifeq ($(feature-on-exit), 1)
570 CFLAGS += -DHAVE_ON_EXIT_SUPPORT
571 endif
572endif
573
574ifndef NO_BACKTRACE 577ifndef NO_BACKTRACE
575 ifeq ($(feature-backtrace), 1) 578 ifeq ($(feature-backtrace), 1)
576 CFLAGS += -DHAVE_BACKTRACE_SUPPORT 579 CFLAGS += -DHAVE_BACKTRACE_SUPPORT
@@ -601,7 +604,7 @@ endif
601 604
602# Make the path relative to DESTDIR, not to prefix 605# Make the path relative to DESTDIR, not to prefix
603ifndef DESTDIR 606ifndef DESTDIR
604prefix = $(HOME) 607prefix ?= $(HOME)
605endif 608endif
606bindir_relative = bin 609bindir_relative = bin
607bindir = $(prefix)/$(bindir_relative) 610bindir = $(prefix)/$(bindir_relative)
diff --git a/tools/perf/config/feature-checks/Makefile b/tools/perf/config/feature-checks/Makefile
index 2da103c53f89..64c84e5f0514 100644
--- a/tools/perf/config/feature-checks/Makefile
+++ b/tools/perf/config/feature-checks/Makefile
@@ -24,7 +24,6 @@ FILES= \
24 test-libslang.bin \ 24 test-libslang.bin \
25 test-libunwind.bin \ 25 test-libunwind.bin \
26 test-libunwind-debug-frame.bin \ 26 test-libunwind-debug-frame.bin \
27 test-on-exit.bin \
28 test-stackprotector-all.bin \ 27 test-stackprotector-all.bin \
29 test-timerfd.bin \ 28 test-timerfd.bin \
30 test-libdw-dwarf-unwind.bin 29 test-libdw-dwarf-unwind.bin
@@ -133,9 +132,6 @@ test-liberty-z.bin:
133test-cplus-demangle.bin: 132test-cplus-demangle.bin:
134 $(BUILD) -liberty 133 $(BUILD) -liberty
135 134
136test-on-exit.bin:
137 $(BUILD)
138
139test-backtrace.bin: 135test-backtrace.bin:
140 $(BUILD) 136 $(BUILD)
141 137
diff --git a/tools/perf/config/feature-checks/test-all.c b/tools/perf/config/feature-checks/test-all.c
index fc37eb3ca17b..fe5c1e5c952f 100644
--- a/tools/perf/config/feature-checks/test-all.c
+++ b/tools/perf/config/feature-checks/test-all.c
@@ -69,10 +69,6 @@
69# include "test-libbfd.c" 69# include "test-libbfd.c"
70#undef main 70#undef main
71 71
72#define main main_test_on_exit
73# include "test-on-exit.c"
74#undef main
75
76#define main main_test_backtrace 72#define main main_test_backtrace
77# include "test-backtrace.c" 73# include "test-backtrace.c"
78#undef main 74#undef main
@@ -110,7 +106,6 @@ int main(int argc, char *argv[])
110 main_test_gtk2(argc, argv); 106 main_test_gtk2(argc, argv);
111 main_test_gtk2_infobar(argc, argv); 107 main_test_gtk2_infobar(argc, argv);
112 main_test_libbfd(); 108 main_test_libbfd();
113 main_test_on_exit();
114 main_test_backtrace(); 109 main_test_backtrace();
115 main_test_libnuma(); 110 main_test_libnuma();
116 main_test_timerfd(); 111 main_test_timerfd();
diff --git a/tools/perf/config/feature-checks/test-on-exit.c b/tools/perf/config/feature-checks/test-on-exit.c
deleted file mode 100644
index 8e88b16e6ded..000000000000
--- a/tools/perf/config/feature-checks/test-on-exit.c
+++ /dev/null
@@ -1,16 +0,0 @@
1#include <stdio.h>
2#include <stdlib.h>
3
4static void exit_fn(int status, void *__data)
5{
6 printf("exit status: %d, data: %d\n", status, *(int *)__data);
7}
8
9static int data = 123;
10
11int main(void)
12{
13 on_exit(exit_fn, &data);
14
15 return 321;
16}
diff --git a/tools/perf/perf-completion.sh b/tools/perf/perf-completion.sh
index ae3a57694b6b..33569847fdcc 100644
--- a/tools/perf/perf-completion.sh
+++ b/tools/perf/perf-completion.sh
@@ -121,8 +121,8 @@ __perf_main ()
121 elif [[ $prev == "-e" && "${words[1]}" == @(record|stat|top) ]]; then 121 elif [[ $prev == "-e" && "${words[1]}" == @(record|stat|top) ]]; then
122 evts=$($cmd list --raw-dump) 122 evts=$($cmd list --raw-dump)
123 __perfcomp_colon "$evts" "$cur" 123 __perfcomp_colon "$evts" "$cur"
124 # List subcommands for 'perf kvm' 124 # List subcommands for perf commands
125 elif [[ $prev == "kvm" ]]; then 125 elif [[ $prev == @(kvm|kmem|mem|lock|sched) ]]; then
126 subcmds=$($cmd $prev --list-cmds) 126 subcmds=$($cmd $prev --list-cmds)
127 __perfcomp_colon "$subcmds" "$cur" 127 __perfcomp_colon "$subcmds" "$cur"
128 # List long option names 128 # List long option names
diff --git a/tools/perf/perf-sys.h b/tools/perf/perf-sys.h
new file mode 100644
index 000000000000..5268a1481d23
--- /dev/null
+++ b/tools/perf/perf-sys.h
@@ -0,0 +1,190 @@
1#ifndef _PERF_SYS_H
2#define _PERF_SYS_H
3
4#include <unistd.h>
5#include <sys/types.h>
6#include <sys/syscall.h>
7#include <linux/types.h>
8#include <linux/perf_event.h>
9#include <asm/unistd.h>
10
11#if defined(__i386__)
12#define mb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
13#define wmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
14#define rmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
15#define cpu_relax() asm volatile("rep; nop" ::: "memory");
16#define CPUINFO_PROC "model name"
17#ifndef __NR_perf_event_open
18# define __NR_perf_event_open 336
19#endif
20#ifndef __NR_futex
21# define __NR_futex 240
22#endif
23#ifndef __NR_gettid
24# define __NR_gettid 224
25#endif
26#endif
27
28#if defined(__x86_64__)
29#define mb() asm volatile("mfence" ::: "memory")
30#define wmb() asm volatile("sfence" ::: "memory")
31#define rmb() asm volatile("lfence" ::: "memory")
32#define cpu_relax() asm volatile("rep; nop" ::: "memory");
33#define CPUINFO_PROC "model name"
34#ifndef __NR_perf_event_open
35# define __NR_perf_event_open 298
36#endif
37#ifndef __NR_futex
38# define __NR_futex 202
39#endif
40#ifndef __NR_gettid
41# define __NR_gettid 186
42#endif
43#endif
44
45#ifdef __powerpc__
46#include "../../arch/powerpc/include/uapi/asm/unistd.h"
47#define mb() asm volatile ("sync" ::: "memory")
48#define wmb() asm volatile ("sync" ::: "memory")
49#define rmb() asm volatile ("sync" ::: "memory")
50#define CPUINFO_PROC "cpu"
51#endif
52
53#ifdef __s390__
54#define mb() asm volatile("bcr 15,0" ::: "memory")
55#define wmb() asm volatile("bcr 15,0" ::: "memory")
56#define rmb() asm volatile("bcr 15,0" ::: "memory")
57#endif
58
59#ifdef __sh__
60#if defined(__SH4A__) || defined(__SH5__)
61# define mb() asm volatile("synco" ::: "memory")
62# define wmb() asm volatile("synco" ::: "memory")
63# define rmb() asm volatile("synco" ::: "memory")
64#else
65# define mb() asm volatile("" ::: "memory")
66# define wmb() asm volatile("" ::: "memory")
67# define rmb() asm volatile("" ::: "memory")
68#endif
69#define CPUINFO_PROC "cpu type"
70#endif
71
72#ifdef __hppa__
73#define mb() asm volatile("" ::: "memory")
74#define wmb() asm volatile("" ::: "memory")
75#define rmb() asm volatile("" ::: "memory")
76#define CPUINFO_PROC "cpu"
77#endif
78
79#ifdef __sparc__
80#ifdef __LP64__
81#define mb() asm volatile("ba,pt %%xcc, 1f\n" \
82 "membar #StoreLoad\n" \
83 "1:\n":::"memory")
84#else
85#define mb() asm volatile("":::"memory")
86#endif
87#define wmb() asm volatile("":::"memory")
88#define rmb() asm volatile("":::"memory")
89#define CPUINFO_PROC "cpu"
90#endif
91
92#ifdef __alpha__
93#define mb() asm volatile("mb" ::: "memory")
94#define wmb() asm volatile("wmb" ::: "memory")
95#define rmb() asm volatile("mb" ::: "memory")
96#define CPUINFO_PROC "cpu model"
97#endif
98
99#ifdef __ia64__
100#define mb() asm volatile ("mf" ::: "memory")
101#define wmb() asm volatile ("mf" ::: "memory")
102#define rmb() asm volatile ("mf" ::: "memory")
103#define cpu_relax() asm volatile ("hint @pause" ::: "memory")
104#define CPUINFO_PROC "model name"
105#endif
106
107#ifdef __arm__
108/*
109 * Use the __kuser_memory_barrier helper in the CPU helper page. See
110 * arch/arm/kernel/entry-armv.S in the kernel source for details.
111 */
112#define mb() ((void(*)(void))0xffff0fa0)()
113#define wmb() ((void(*)(void))0xffff0fa0)()
114#define rmb() ((void(*)(void))0xffff0fa0)()
115#define CPUINFO_PROC "Processor"
116#endif
117
118#ifdef __aarch64__
119#define mb() asm volatile("dmb ish" ::: "memory")
120#define wmb() asm volatile("dmb ishst" ::: "memory")
121#define rmb() asm volatile("dmb ishld" ::: "memory")
122#define cpu_relax() asm volatile("yield" ::: "memory")
123#endif
124
125#ifdef __mips__
126#define mb() asm volatile( \
127 ".set mips2\n\t" \
128 "sync\n\t" \
129 ".set mips0" \
130 : /* no output */ \
131 : /* no input */ \
132 : "memory")
133#define wmb() mb()
134#define rmb() mb()
135#define CPUINFO_PROC "cpu model"
136#endif
137
138#ifdef __arc__
139#define mb() asm volatile("" ::: "memory")
140#define wmb() asm volatile("" ::: "memory")
141#define rmb() asm volatile("" ::: "memory")
142#define CPUINFO_PROC "Processor"
143#endif
144
145#ifdef __metag__
146#define mb() asm volatile("" ::: "memory")
147#define wmb() asm volatile("" ::: "memory")
148#define rmb() asm volatile("" ::: "memory")
149#define CPUINFO_PROC "CPU"
150#endif
151
152#ifdef __xtensa__
153#define mb() asm volatile("memw" ::: "memory")
154#define wmb() asm volatile("memw" ::: "memory")
155#define rmb() asm volatile("" ::: "memory")
156#define CPUINFO_PROC "core ID"
157#endif
158
159#ifdef __tile__
160#define mb() asm volatile ("mf" ::: "memory")
161#define wmb() asm volatile ("mf" ::: "memory")
162#define rmb() asm volatile ("mf" ::: "memory")
163#define cpu_relax() asm volatile ("mfspr zero, PASS" ::: "memory")
164#define CPUINFO_PROC "model name"
165#endif
166
167#define barrier() asm volatile ("" ::: "memory")
168
169#ifndef cpu_relax
170#define cpu_relax() barrier()
171#endif
172
173static inline int
174sys_perf_event_open(struct perf_event_attr *attr,
175 pid_t pid, int cpu, int group_fd,
176 unsigned long flags)
177{
178 int fd;
179
180 fd = syscall(__NR_perf_event_open, attr, pid, cpu,
181 group_fd, flags);
182
183#ifdef HAVE_ATTR_TEST
184 if (unlikely(test_attr__enabled))
185 test_attr__open(attr, pid, cpu, fd, group_fd, flags);
186#endif
187 return fd;
188}
189
190#endif /* _PERF_SYS_H */
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 431798a4110d..95c58fc15284 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -458,6 +458,7 @@ int main(int argc, const char **argv)
458 458
459 /* The page_size is placed in util object. */ 459 /* The page_size is placed in util object. */
460 page_size = sysconf(_SC_PAGE_SIZE); 460 page_size = sysconf(_SC_PAGE_SIZE);
461 cacheline_size = sysconf(_SC_LEVEL1_DCACHE_LINESIZE);
461 462
462 cmd = perf_extract_argv0_path(argv[0]); 463 cmd = perf_extract_argv0_path(argv[0]);
463 if (!cmd) 464 if (!cmd)
@@ -481,14 +482,18 @@ int main(int argc, const char **argv)
481 fprintf(stderr, "cannot handle %s internally", cmd); 482 fprintf(stderr, "cannot handle %s internally", cmd);
482 goto out; 483 goto out;
483 } 484 }
484#ifdef HAVE_LIBAUDIT_SUPPORT
485 if (!prefixcmp(cmd, "trace")) { 485 if (!prefixcmp(cmd, "trace")) {
486#ifdef HAVE_LIBAUDIT_SUPPORT
486 set_buildid_dir(); 487 set_buildid_dir();
487 setup_path(); 488 setup_path();
488 argv[0] = "trace"; 489 argv[0] = "trace";
489 return cmd_trace(argc, argv, NULL); 490 return cmd_trace(argc, argv, NULL);
490 } 491#else
492 fprintf(stderr,
493 "trace command not available: missing audit-libs devel package at build time.\n");
494 goto out;
491#endif 495#endif
496 }
492 /* Look for flags.. */ 497 /* Look for flags.. */
493 argv++; 498 argv++;
494 argc--; 499 argc--;
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 5c11ecad02a9..510c65f72858 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -1,182 +1,18 @@
1#ifndef _PERF_PERF_H 1#ifndef _PERF_PERF_H
2#define _PERF_PERF_H 2#define _PERF_PERF_H
3 3
4#include <asm/unistd.h>
5
6#if defined(__i386__)
7#define mb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
8#define wmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
9#define rmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
10#define cpu_relax() asm volatile("rep; nop" ::: "memory");
11#define CPUINFO_PROC "model name"
12#ifndef __NR_perf_event_open
13# define __NR_perf_event_open 336
14#endif
15#ifndef __NR_futex
16# define __NR_futex 240
17#endif
18#endif
19
20#if defined(__x86_64__)
21#define mb() asm volatile("mfence" ::: "memory")
22#define wmb() asm volatile("sfence" ::: "memory")
23#define rmb() asm volatile("lfence" ::: "memory")
24#define cpu_relax() asm volatile("rep; nop" ::: "memory");
25#define CPUINFO_PROC "model name"
26#ifndef __NR_perf_event_open
27# define __NR_perf_event_open 298
28#endif
29#ifndef __NR_futex
30# define __NR_futex 202
31#endif
32#endif
33
34#ifdef __powerpc__
35#include "../../arch/powerpc/include/uapi/asm/unistd.h"
36#define mb() asm volatile ("sync" ::: "memory")
37#define wmb() asm volatile ("sync" ::: "memory")
38#define rmb() asm volatile ("sync" ::: "memory")
39#define CPUINFO_PROC "cpu"
40#endif
41
42#ifdef __s390__
43#define mb() asm volatile("bcr 15,0" ::: "memory")
44#define wmb() asm volatile("bcr 15,0" ::: "memory")
45#define rmb() asm volatile("bcr 15,0" ::: "memory")
46#endif
47
48#ifdef __sh__
49#if defined(__SH4A__) || defined(__SH5__)
50# define mb() asm volatile("synco" ::: "memory")
51# define wmb() asm volatile("synco" ::: "memory")
52# define rmb() asm volatile("synco" ::: "memory")
53#else
54# define mb() asm volatile("" ::: "memory")
55# define wmb() asm volatile("" ::: "memory")
56# define rmb() asm volatile("" ::: "memory")
57#endif
58#define CPUINFO_PROC "cpu type"
59#endif
60
61#ifdef __hppa__
62#define mb() asm volatile("" ::: "memory")
63#define wmb() asm volatile("" ::: "memory")
64#define rmb() asm volatile("" ::: "memory")
65#define CPUINFO_PROC "cpu"
66#endif
67
68#ifdef __sparc__
69#ifdef __LP64__
70#define mb() asm volatile("ba,pt %%xcc, 1f\n" \
71 "membar #StoreLoad\n" \
72 "1:\n":::"memory")
73#else
74#define mb() asm volatile("":::"memory")
75#endif
76#define wmb() asm volatile("":::"memory")
77#define rmb() asm volatile("":::"memory")
78#define CPUINFO_PROC "cpu"
79#endif
80
81#ifdef __alpha__
82#define mb() asm volatile("mb" ::: "memory")
83#define wmb() asm volatile("wmb" ::: "memory")
84#define rmb() asm volatile("mb" ::: "memory")
85#define CPUINFO_PROC "cpu model"
86#endif
87
88#ifdef __ia64__
89#define mb() asm volatile ("mf" ::: "memory")
90#define wmb() asm volatile ("mf" ::: "memory")
91#define rmb() asm volatile ("mf" ::: "memory")
92#define cpu_relax() asm volatile ("hint @pause" ::: "memory")
93#define CPUINFO_PROC "model name"
94#endif
95
96#ifdef __arm__
97/*
98 * Use the __kuser_memory_barrier helper in the CPU helper page. See
99 * arch/arm/kernel/entry-armv.S in the kernel source for details.
100 */
101#define mb() ((void(*)(void))0xffff0fa0)()
102#define wmb() ((void(*)(void))0xffff0fa0)()
103#define rmb() ((void(*)(void))0xffff0fa0)()
104#define CPUINFO_PROC "Processor"
105#endif
106
107#ifdef __aarch64__
108#define mb() asm volatile("dmb ish" ::: "memory")
109#define wmb() asm volatile("dmb ishst" ::: "memory")
110#define rmb() asm volatile("dmb ishld" ::: "memory")
111#define cpu_relax() asm volatile("yield" ::: "memory")
112#endif
113
114#ifdef __mips__
115#define mb() asm volatile( \
116 ".set mips2\n\t" \
117 "sync\n\t" \
118 ".set mips0" \
119 : /* no output */ \
120 : /* no input */ \
121 : "memory")
122#define wmb() mb()
123#define rmb() mb()
124#define CPUINFO_PROC "cpu model"
125#endif
126
127#ifdef __arc__
128#define mb() asm volatile("" ::: "memory")
129#define wmb() asm volatile("" ::: "memory")
130#define rmb() asm volatile("" ::: "memory")
131#define CPUINFO_PROC "Processor"
132#endif
133
134#ifdef __metag__
135#define mb() asm volatile("" ::: "memory")
136#define wmb() asm volatile("" ::: "memory")
137#define rmb() asm volatile("" ::: "memory")
138#define CPUINFO_PROC "CPU"
139#endif
140
141#ifdef __xtensa__
142#define mb() asm volatile("memw" ::: "memory")
143#define wmb() asm volatile("memw" ::: "memory")
144#define rmb() asm volatile("" ::: "memory")
145#define CPUINFO_PROC "core ID"
146#endif
147
148#ifdef __tile__
149#define mb() asm volatile ("mf" ::: "memory")
150#define wmb() asm volatile ("mf" ::: "memory")
151#define rmb() asm volatile ("mf" ::: "memory")
152#define cpu_relax() asm volatile ("mfspr zero, PASS" ::: "memory")
153#define CPUINFO_PROC "model name"
154#endif
155
156#define barrier() asm volatile ("" ::: "memory")
157
158#ifndef cpu_relax
159#define cpu_relax() barrier()
160#endif
161
162#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
163
164
165#include <time.h> 4#include <time.h>
166#include <unistd.h>
167#include <sys/types.h>
168#include <sys/syscall.h>
169
170#include <linux/perf_event.h>
171#include "util/types.h"
172#include <stdbool.h> 5#include <stdbool.h>
6#include <linux/types.h>
7#include <linux/perf_event.h>
173 8
174/* 9extern bool test_attr__enabled;
175 * prctl(PR_TASK_PERF_EVENTS_DISABLE) will (cheaply) disable all 10void test_attr__init(void);
176 * counters in the current task. 11void test_attr__open(struct perf_event_attr *attr, pid_t pid, int cpu,
177 */ 12 int fd, int group_fd, unsigned long flags);
178#define PR_TASK_PERF_EVENTS_DISABLE 31 13
179#define PR_TASK_PERF_EVENTS_ENABLE 32 14#define HAVE_ATTR_TEST
15#include "perf-sys.h"
180 16
181#ifndef NSEC_PER_SEC 17#ifndef NSEC_PER_SEC
182# define NSEC_PER_SEC 1000000000ULL 18# define NSEC_PER_SEC 1000000000ULL
@@ -193,67 +29,8 @@ static inline unsigned long long rdclock(void)
193 return ts.tv_sec * 1000000000ULL + ts.tv_nsec; 29 return ts.tv_sec * 1000000000ULL + ts.tv_nsec;
194} 30}
195 31
196/*
197 * Pick up some kernel type conventions:
198 */
199#define __user
200#define asmlinkage
201
202#define unlikely(x) __builtin_expect(!!(x), 0)
203#define min(x, y) ({ \
204 typeof(x) _min1 = (x); \
205 typeof(y) _min2 = (y); \
206 (void) (&_min1 == &_min2); \
207 _min1 < _min2 ? _min1 : _min2; })
208
209extern bool test_attr__enabled;
210void test_attr__init(void);
211void test_attr__open(struct perf_event_attr *attr, pid_t pid, int cpu,
212 int fd, int group_fd, unsigned long flags);
213
214static inline int
215sys_perf_event_open(struct perf_event_attr *attr,
216 pid_t pid, int cpu, int group_fd,
217 unsigned long flags)
218{
219 int fd;
220
221 fd = syscall(__NR_perf_event_open, attr, pid, cpu,
222 group_fd, flags);
223
224 if (unlikely(test_attr__enabled))
225 test_attr__open(attr, pid, cpu, fd, group_fd, flags);
226
227 return fd;
228}
229
230#define MAX_COUNTERS 256
231#define MAX_NR_CPUS 256 32#define MAX_NR_CPUS 256
232 33
233struct ip_callchain {
234 u64 nr;
235 u64 ips[0];
236};
237
238struct branch_flags {
239 u64 mispred:1;
240 u64 predicted:1;
241 u64 in_tx:1;
242 u64 abort:1;
243 u64 reserved:60;
244};
245
246struct branch_entry {
247 u64 from;
248 u64 to;
249 struct branch_flags flags;
250};
251
252struct branch_stack {
253 u64 nr;
254 struct branch_entry entries[0];
255};
256
257extern const char *input_name; 34extern const char *input_name;
258extern bool perf_host, perf_guest; 35extern bool perf_host, perf_guest;
259extern const char perf_version_string[]; 36extern const char perf_version_string[];
@@ -262,13 +39,6 @@ void pthread__unblock_sigwinch(void);
262 39
263#include "util/target.h" 40#include "util/target.h"
264 41
265enum perf_call_graph_mode {
266 CALLCHAIN_NONE,
267 CALLCHAIN_FP,
268 CALLCHAIN_DWARF,
269 CALLCHAIN_MAX
270};
271
272struct record_opts { 42struct record_opts {
273 struct target target; 43 struct target target;
274 int call_graph; 44 int call_graph;
diff --git a/tools/perf/tests/attr.c b/tools/perf/tests/attr.c
index 00218f503b2e..2dfc9ad0e6f2 100644
--- a/tools/perf/tests/attr.c
+++ b/tools/perf/tests/attr.c
@@ -1,4 +1,3 @@
1
2/* 1/*
3 * The struct perf_event_attr test support. 2 * The struct perf_event_attr test support.
4 * 3 *
@@ -19,14 +18,8 @@
19 * permissions. All the event text files are stored there. 18 * permissions. All the event text files are stored there.
20 */ 19 */
21 20
22/*
23 * Powerpc needs __SANE_USERSPACE_TYPES__ before <linux/types.h> to select
24 * 'int-ll64.h' and avoid compile warnings when printing __u64 with %llu.
25 */
26#define __SANE_USERSPACE_TYPES__
27#include <stdlib.h> 21#include <stdlib.h>
28#include <stdio.h> 22#include <stdio.h>
29#include <inttypes.h>
30#include <linux/types.h> 23#include <linux/types.h>
31#include <linux/kernel.h> 24#include <linux/kernel.h>
32#include "../perf.h" 25#include "../perf.h"
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index b11bf8a08430..6f8b01bc6033 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -3,6 +3,8 @@
3 * 3 *
4 * Builtin regression testing command: ever growing number of sanity tests 4 * Builtin regression testing command: ever growing number of sanity tests
5 */ 5 */
6#include <unistd.h>
7#include <string.h>
6#include "builtin.h" 8#include "builtin.h"
7#include "intlist.h" 9#include "intlist.h"
8#include "tests.h" 10#include "tests.h"
@@ -50,10 +52,18 @@ static struct test {
50 .func = test__pmu, 52 .func = test__pmu,
51 }, 53 },
52 { 54 {
53 .desc = "Test dso data interface", 55 .desc = "Test dso data read",
54 .func = test__dso_data, 56 .func = test__dso_data,
55 }, 57 },
56 { 58 {
59 .desc = "Test dso data cache",
60 .func = test__dso_data_cache,
61 },
62 {
63 .desc = "Test dso data reopen",
64 .func = test__dso_data_reopen,
65 },
66 {
57 .desc = "roundtrip evsel->name check", 67 .desc = "roundtrip evsel->name check",
58 .func = test__perf_evsel__roundtrip_name_test, 68 .func = test__perf_evsel__roundtrip_name_test,
59 }, 69 },
@@ -115,7 +125,7 @@ static struct test {
115 .desc = "Test parsing with no sample_id_all bit set", 125 .desc = "Test parsing with no sample_id_all bit set",
116 .func = test__parse_no_sample_id_all, 126 .func = test__parse_no_sample_id_all,
117 }, 127 },
118#if defined(__x86_64__) || defined(__i386__) 128#if defined(__x86_64__) || defined(__i386__) || defined(__arm__)
119#ifdef HAVE_DWARF_UNWIND_SUPPORT 129#ifdef HAVE_DWARF_UNWIND_SUPPORT
120 { 130 {
121 .desc = "Test dwarf unwind", 131 .desc = "Test dwarf unwind",
@@ -124,6 +134,26 @@ static struct test {
124#endif 134#endif
125#endif 135#endif
126 { 136 {
137 .desc = "Test filtering hist entries",
138 .func = test__hists_filter,
139 },
140 {
141 .desc = "Test mmap thread lookup",
142 .func = test__mmap_thread_lookup,
143 },
144 {
145 .desc = "Test thread mg sharing",
146 .func = test__thread_mg_share,
147 },
148 {
149 .desc = "Test output sorting of hist entries",
150 .func = test__hists_output,
151 },
152 {
153 .desc = "Test cumulation of child hist entries",
154 .func = test__hists_cumulate,
155 },
156 {
127 .func = NULL, 157 .func = NULL,
128 }, 158 },
129}; 159};
@@ -152,6 +182,34 @@ static bool perf_test__matches(int curr, int argc, const char *argv[])
152 return false; 182 return false;
153} 183}
154 184
185static int run_test(struct test *test)
186{
187 int status, err = -1, child = fork();
188
189 if (child < 0) {
190 pr_err("failed to fork test: %s\n", strerror(errno));
191 return -1;
192 }
193
194 if (!child) {
195 pr_debug("test child forked, pid %d\n", getpid());
196 err = test->func();
197 exit(err);
198 }
199
200 wait(&status);
201
202 if (WIFEXITED(status)) {
203 err = WEXITSTATUS(status);
204 pr_debug("test child finished with %d\n", err);
205 } else if (WIFSIGNALED(status)) {
206 err = -1;
207 pr_debug("test child interrupted\n");
208 }
209
210 return err;
211}
212
155static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist) 213static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist)
156{ 214{
157 int i = 0; 215 int i = 0;
@@ -180,7 +238,7 @@ static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist)
180 } 238 }
181 239
182 pr_debug("\n--- start ---\n"); 240 pr_debug("\n--- start ---\n");
183 err = tests[curr].func(); 241 err = run_test(&tests[curr]);
184 pr_debug("---- end ----\n%s:", tests[curr].desc); 242 pr_debug("---- end ----\n%s:", tests[curr].desc);
185 243
186 switch (err) { 244 switch (err) {
diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c
index bfb186900ac0..67f2d6323558 100644
--- a/tools/perf/tests/code-reading.c
+++ b/tools/perf/tests/code-reading.c
@@ -1,8 +1,7 @@
1#include <sys/types.h> 1#include <linux/types.h>
2#include <stdlib.h> 2#include <stdlib.h>
3#include <unistd.h> 3#include <unistd.h>
4#include <stdio.h> 4#include <stdio.h>
5#include <inttypes.h>
6#include <ctype.h> 5#include <ctype.h>
7#include <string.h> 6#include <string.h>
8 7
@@ -257,7 +256,7 @@ static int process_sample_event(struct machine *machine,
257 return -1; 256 return -1;
258 } 257 }
259 258
260 thread = machine__findnew_thread(machine, sample.pid, sample.pid); 259 thread = machine__findnew_thread(machine, sample.pid, sample.tid);
261 if (!thread) { 260 if (!thread) {
262 pr_debug("machine__findnew_thread failed\n"); 261 pr_debug("machine__findnew_thread failed\n");
263 return -1; 262 return -1;
diff --git a/tools/perf/tests/dso-data.c b/tools/perf/tests/dso-data.c
index 9cc81a3eb9b4..630808cd7cc2 100644
--- a/tools/perf/tests/dso-data.c
+++ b/tools/perf/tests/dso-data.c
@@ -1,22 +1,27 @@
1#include "util.h"
2
3#include <stdlib.h> 1#include <stdlib.h>
4#include <sys/types.h> 2#include <linux/types.h>
5#include <sys/stat.h> 3#include <sys/stat.h>
6#include <fcntl.h> 4#include <fcntl.h>
7#include <string.h> 5#include <string.h>
8 6#include <sys/time.h>
7#include <sys/resource.h>
8#include <api/fs/fs.h>
9#include "util.h"
9#include "machine.h" 10#include "machine.h"
10#include "symbol.h" 11#include "symbol.h"
11#include "tests.h" 12#include "tests.h"
12 13
13static char *test_file(int size) 14static char *test_file(int size)
14{ 15{
15 static char buf_templ[] = "/tmp/test-XXXXXX"; 16#define TEMPL "/tmp/perf-test-XXXXXX"
17 static char buf_templ[sizeof(TEMPL)];
16 char *templ = buf_templ; 18 char *templ = buf_templ;
17 int fd, i; 19 int fd, i;
18 unsigned char *buf; 20 unsigned char *buf;
19 21
22 strcpy(buf_templ, TEMPL);
23#undef TEMPL
24
20 fd = mkstemp(templ); 25 fd = mkstemp(templ);
21 if (fd < 0) { 26 if (fd < 0) {
22 perror("mkstemp failed"); 27 perror("mkstemp failed");
@@ -150,3 +155,204 @@ int test__dso_data(void)
150 unlink(file); 155 unlink(file);
151 return 0; 156 return 0;
152} 157}
158
159static long open_files_cnt(void)
160{
161 char path[PATH_MAX];
162 struct dirent *dent;
163 DIR *dir;
164 long nr = 0;
165
166 scnprintf(path, PATH_MAX, "%s/self/fd", procfs__mountpoint());
167 pr_debug("fd path: %s\n", path);
168
169 dir = opendir(path);
170 TEST_ASSERT_VAL("failed to open fd directory", dir);
171
172 while ((dent = readdir(dir)) != NULL) {
173 if (!strcmp(dent->d_name, ".") ||
174 !strcmp(dent->d_name, ".."))
175 continue;
176
177 nr++;
178 }
179
180 closedir(dir);
181 return nr - 1;
182}
183
184static struct dso **dsos;
185
186static int dsos__create(int cnt, int size)
187{
188 int i;
189
190 dsos = malloc(sizeof(dsos) * cnt);
191 TEST_ASSERT_VAL("failed to alloc dsos array", dsos);
192
193 for (i = 0; i < cnt; i++) {
194 char *file;
195
196 file = test_file(size);
197 TEST_ASSERT_VAL("failed to get dso file", file);
198
199 dsos[i] = dso__new(file);
200 TEST_ASSERT_VAL("failed to get dso", dsos[i]);
201 }
202
203 return 0;
204}
205
206static void dsos__delete(int cnt)
207{
208 int i;
209
210 for (i = 0; i < cnt; i++) {
211 struct dso *dso = dsos[i];
212
213 unlink(dso->name);
214 dso__delete(dso);
215 }
216
217 free(dsos);
218}
219
220static int set_fd_limit(int n)
221{
222 struct rlimit rlim;
223
224 if (getrlimit(RLIMIT_NOFILE, &rlim))
225 return -1;
226
227 pr_debug("file limit %ld, new %d\n", (long) rlim.rlim_cur, n);
228
229 rlim.rlim_cur = n;
230 return setrlimit(RLIMIT_NOFILE, &rlim);
231}
232
233int test__dso_data_cache(void)
234{
235 struct machine machine;
236 long nr_end, nr = open_files_cnt();
237 int dso_cnt, limit, i, fd;
238
239 memset(&machine, 0, sizeof(machine));
240
241 /* set as system limit */
242 limit = nr * 4;
243 TEST_ASSERT_VAL("failed to set file limit", !set_fd_limit(limit));
244
245 /* and this is now our dso open FDs limit + 1 extra */
246 dso_cnt = limit / 2 + 1;
247 TEST_ASSERT_VAL("failed to create dsos\n",
248 !dsos__create(dso_cnt, TEST_FILE_SIZE));
249
250 for (i = 0; i < (dso_cnt - 1); i++) {
251 struct dso *dso = dsos[i];
252
253 /*
254 * Open dsos via dso__data_fd or dso__data_read_offset.
255 * Both opens the data file and keep it open.
256 */
257 if (i % 2) {
258 fd = dso__data_fd(dso, &machine);
259 TEST_ASSERT_VAL("failed to get fd", fd > 0);
260 } else {
261 #define BUFSIZE 10
262 u8 buf[BUFSIZE];
263 ssize_t n;
264
265 n = dso__data_read_offset(dso, &machine, 0, buf, BUFSIZE);
266 TEST_ASSERT_VAL("failed to read dso", n == BUFSIZE);
267 }
268 }
269
270 /* open +1 dso over the allowed limit */
271 fd = dso__data_fd(dsos[i], &machine);
272 TEST_ASSERT_VAL("failed to get fd", fd > 0);
273
274 /* should force the first one to be closed */
275 TEST_ASSERT_VAL("failed to close dsos[0]", dsos[0]->data.fd == -1);
276
277 /* cleanup everything */
278 dsos__delete(dso_cnt);
279
280 /* Make sure we did not leak any file descriptor. */
281 nr_end = open_files_cnt();
282 pr_debug("nr start %ld, nr stop %ld\n", nr, nr_end);
283 TEST_ASSERT_VAL("failed leadking files", nr == nr_end);
284 return 0;
285}
286
287int test__dso_data_reopen(void)
288{
289 struct machine machine;
290 long nr_end, nr = open_files_cnt();
291 int fd, fd_extra;
292
293#define dso_0 (dsos[0])
294#define dso_1 (dsos[1])
295#define dso_2 (dsos[2])
296
297 memset(&machine, 0, sizeof(machine));
298
299 /*
300 * Test scenario:
301 * - create 3 dso objects
302 * - set process file descriptor limit to current
303 * files count + 3
304 * - test that the first dso gets closed when we
305 * reach the files count limit
306 */
307
308 /* Make sure we are able to open 3 fds anyway */
309 TEST_ASSERT_VAL("failed to set file limit",
310 !set_fd_limit((nr + 3)));
311
312 TEST_ASSERT_VAL("failed to create dsos\n", !dsos__create(3, TEST_FILE_SIZE));
313
314 /* open dso_0 */
315 fd = dso__data_fd(dso_0, &machine);
316 TEST_ASSERT_VAL("failed to get fd", fd > 0);
317
318 /* open dso_1 */
319 fd = dso__data_fd(dso_1, &machine);
320 TEST_ASSERT_VAL("failed to get fd", fd > 0);
321
322 /*
323 * open extra file descriptor and we just
324 * reached the files count limit
325 */
326 fd_extra = open("/dev/null", O_RDONLY);
327 TEST_ASSERT_VAL("failed to open extra fd", fd_extra > 0);
328
329 /* open dso_2 */
330 fd = dso__data_fd(dso_2, &machine);
331 TEST_ASSERT_VAL("failed to get fd", fd > 0);
332
333 /*
334 * dso_0 should get closed, because we reached
335 * the file descriptor limit
336 */
337 TEST_ASSERT_VAL("failed to close dso_0", dso_0->data.fd == -1);
338
339 /* open dso_0 */
340 fd = dso__data_fd(dso_0, &machine);
341 TEST_ASSERT_VAL("failed to get fd", fd > 0);
342
343 /*
344 * dso_1 should get closed, because we reached
345 * the file descriptor limit
346 */
347 TEST_ASSERT_VAL("failed to close dso_1", dso_1->data.fd == -1);
348
349 /* cleanup everything */
350 close(fd_extra);
351 dsos__delete(3);
352
353 /* Make sure we did not leak any file descriptor. */
354 nr_end = open_files_cnt();
355 pr_debug("nr start %ld, nr stop %ld\n", nr, nr_end);
356 TEST_ASSERT_VAL("failed leadking files", nr == nr_end);
357 return 0;
358}
diff --git a/tools/perf/tests/dwarf-unwind.c b/tools/perf/tests/dwarf-unwind.c
index c059ee81c038..96adb730b744 100644
--- a/tools/perf/tests/dwarf-unwind.c
+++ b/tools/perf/tests/dwarf-unwind.c
@@ -1,5 +1,5 @@
1#include <linux/compiler.h> 1#include <linux/compiler.h>
2#include <sys/types.h> 2#include <linux/types.h>
3#include <unistd.h> 3#include <unistd.h>
4#include "tests.h" 4#include "tests.h"
5#include "debug.h" 5#include "debug.h"
@@ -15,7 +15,7 @@ static int mmap_handler(struct perf_tool *tool __maybe_unused,
15 struct perf_sample *sample __maybe_unused, 15 struct perf_sample *sample __maybe_unused,
16 struct machine *machine) 16 struct machine *machine)
17{ 17{
18 return machine__process_mmap_event(machine, event, NULL); 18 return machine__process_mmap2_event(machine, event, NULL);
19} 19}
20 20
21static int init_live_machine(struct machine *machine) 21static int init_live_machine(struct machine *machine)
diff --git a/tools/perf/tests/evsel-tp-sched.c b/tools/perf/tests/evsel-tp-sched.c
index 4774f7fbb758..35d7fdb2328d 100644
--- a/tools/perf/tests/evsel-tp-sched.c
+++ b/tools/perf/tests/evsel-tp-sched.c
@@ -74,9 +74,6 @@ int test__perf_evsel__tp_sched_test(void)
74 if (perf_evsel__test_field(evsel, "prio", 4, true)) 74 if (perf_evsel__test_field(evsel, "prio", 4, true))
75 ret = -1; 75 ret = -1;
76 76
77 if (perf_evsel__test_field(evsel, "success", 4, true))
78 ret = -1;
79
80 if (perf_evsel__test_field(evsel, "target_cpu", 4, true)) 77 if (perf_evsel__test_field(evsel, "target_cpu", 4, true))
81 ret = -1; 78 ret = -1;
82 79
diff --git a/tools/perf/tests/hists_common.c b/tools/perf/tests/hists_common.c
new file mode 100644
index 000000000000..a62c09134516
--- /dev/null
+++ b/tools/perf/tests/hists_common.c
@@ -0,0 +1,209 @@
1#include "perf.h"
2#include "util/debug.h"
3#include "util/symbol.h"
4#include "util/sort.h"
5#include "util/evsel.h"
6#include "util/evlist.h"
7#include "util/machine.h"
8#include "util/thread.h"
9#include "tests/hists_common.h"
10
11static struct {
12 u32 pid;
13 const char *comm;
14} fake_threads[] = {
15 { FAKE_PID_PERF1, "perf" },
16 { FAKE_PID_PERF2, "perf" },
17 { FAKE_PID_BASH, "bash" },
18};
19
20static struct {
21 u32 pid;
22 u64 start;
23 const char *filename;
24} fake_mmap_info[] = {
25 { FAKE_PID_PERF1, FAKE_MAP_PERF, "perf" },
26 { FAKE_PID_PERF1, FAKE_MAP_LIBC, "libc" },
27 { FAKE_PID_PERF1, FAKE_MAP_KERNEL, "[kernel]" },
28 { FAKE_PID_PERF2, FAKE_MAP_PERF, "perf" },
29 { FAKE_PID_PERF2, FAKE_MAP_LIBC, "libc" },
30 { FAKE_PID_PERF2, FAKE_MAP_KERNEL, "[kernel]" },
31 { FAKE_PID_BASH, FAKE_MAP_BASH, "bash" },
32 { FAKE_PID_BASH, FAKE_MAP_LIBC, "libc" },
33 { FAKE_PID_BASH, FAKE_MAP_KERNEL, "[kernel]" },
34};
35
36struct fake_sym {
37 u64 start;
38 u64 length;
39 const char *name;
40};
41
42static struct fake_sym perf_syms[] = {
43 { FAKE_SYM_OFFSET1, FAKE_SYM_LENGTH, "main" },
44 { FAKE_SYM_OFFSET2, FAKE_SYM_LENGTH, "run_command" },
45 { FAKE_SYM_OFFSET3, FAKE_SYM_LENGTH, "cmd_record" },
46};
47
48static struct fake_sym bash_syms[] = {
49 { FAKE_SYM_OFFSET1, FAKE_SYM_LENGTH, "main" },
50 { FAKE_SYM_OFFSET2, FAKE_SYM_LENGTH, "xmalloc" },
51 { FAKE_SYM_OFFSET3, FAKE_SYM_LENGTH, "xfree" },
52};
53
54static struct fake_sym libc_syms[] = {
55 { 700, 100, "malloc" },
56 { 800, 100, "free" },
57 { 900, 100, "realloc" },
58 { FAKE_SYM_OFFSET1, FAKE_SYM_LENGTH, "malloc" },
59 { FAKE_SYM_OFFSET2, FAKE_SYM_LENGTH, "free" },
60 { FAKE_SYM_OFFSET3, FAKE_SYM_LENGTH, "realloc" },
61};
62
63static struct fake_sym kernel_syms[] = {
64 { FAKE_SYM_OFFSET1, FAKE_SYM_LENGTH, "schedule" },
65 { FAKE_SYM_OFFSET2, FAKE_SYM_LENGTH, "page_fault" },
66 { FAKE_SYM_OFFSET3, FAKE_SYM_LENGTH, "sys_perf_event_open" },
67};
68
69static struct {
70 const char *dso_name;
71 struct fake_sym *syms;
72 size_t nr_syms;
73} fake_symbols[] = {
74 { "perf", perf_syms, ARRAY_SIZE(perf_syms) },
75 { "bash", bash_syms, ARRAY_SIZE(bash_syms) },
76 { "libc", libc_syms, ARRAY_SIZE(libc_syms) },
77 { "[kernel]", kernel_syms, ARRAY_SIZE(kernel_syms) },
78};
79
80struct machine *setup_fake_machine(struct machines *machines)
81{
82 struct machine *machine = machines__find(machines, HOST_KERNEL_ID);
83 size_t i;
84
85 if (machine == NULL) {
86 pr_debug("Not enough memory for machine setup\n");
87 return NULL;
88 }
89
90 for (i = 0; i < ARRAY_SIZE(fake_threads); i++) {
91 struct thread *thread;
92
93 thread = machine__findnew_thread(machine, fake_threads[i].pid,
94 fake_threads[i].pid);
95 if (thread == NULL)
96 goto out;
97
98 thread__set_comm(thread, fake_threads[i].comm, 0);
99 }
100
101 for (i = 0; i < ARRAY_SIZE(fake_mmap_info); i++) {
102 union perf_event fake_mmap_event = {
103 .mmap = {
104 .header = { .misc = PERF_RECORD_MISC_USER, },
105 .pid = fake_mmap_info[i].pid,
106 .tid = fake_mmap_info[i].pid,
107 .start = fake_mmap_info[i].start,
108 .len = FAKE_MAP_LENGTH,
109 .pgoff = 0ULL,
110 },
111 };
112
113 strcpy(fake_mmap_event.mmap.filename,
114 fake_mmap_info[i].filename);
115
116 machine__process_mmap_event(machine, &fake_mmap_event, NULL);
117 }
118
119 for (i = 0; i < ARRAY_SIZE(fake_symbols); i++) {
120 size_t k;
121 struct dso *dso;
122
123 dso = __dsos__findnew(&machine->user_dsos,
124 fake_symbols[i].dso_name);
125 if (dso == NULL)
126 goto out;
127
128 /* emulate dso__load() */
129 dso__set_loaded(dso, MAP__FUNCTION);
130
131 for (k = 0; k < fake_symbols[i].nr_syms; k++) {
132 struct symbol *sym;
133 struct fake_sym *fsym = &fake_symbols[i].syms[k];
134
135 sym = symbol__new(fsym->start, fsym->length,
136 STB_GLOBAL, fsym->name);
137 if (sym == NULL)
138 goto out;
139
140 symbols__insert(&dso->symbols[MAP__FUNCTION], sym);
141 }
142 }
143
144 return machine;
145
146out:
147 pr_debug("Not enough memory for machine setup\n");
148 machine__delete_threads(machine);
149 machine__delete(machine);
150 return NULL;
151}
152
153void print_hists_in(struct hists *hists)
154{
155 int i = 0;
156 struct rb_root *root;
157 struct rb_node *node;
158
159 if (sort__need_collapse)
160 root = &hists->entries_collapsed;
161 else
162 root = hists->entries_in;
163
164 pr_info("----- %s --------\n", __func__);
165 node = rb_first(root);
166 while (node) {
167 struct hist_entry *he;
168
169 he = rb_entry(node, struct hist_entry, rb_node_in);
170
171 if (!he->filtered) {
172 pr_info("%2d: entry: %-8s [%-8s] %20s: period = %"PRIu64"\n",
173 i, thread__comm_str(he->thread),
174 he->ms.map->dso->short_name,
175 he->ms.sym->name, he->stat.period);
176 }
177
178 i++;
179 node = rb_next(node);
180 }
181}
182
183void print_hists_out(struct hists *hists)
184{
185 int i = 0;
186 struct rb_root *root;
187 struct rb_node *node;
188
189 root = &hists->entries;
190
191 pr_info("----- %s --------\n", __func__);
192 node = rb_first(root);
193 while (node) {
194 struct hist_entry *he;
195
196 he = rb_entry(node, struct hist_entry, rb_node);
197
198 if (!he->filtered) {
199 pr_info("%2d: entry: %8s:%5d [%-8s] %20s: period = %"PRIu64"/%"PRIu64"\n",
200 i, thread__comm_str(he->thread), he->thread->tid,
201 he->ms.map->dso->short_name,
202 he->ms.sym->name, he->stat.period,
203 he->stat_acc ? he->stat_acc->period : 0);
204 }
205
206 i++;
207 node = rb_next(node);
208 }
209}
diff --git a/tools/perf/tests/hists_common.h b/tools/perf/tests/hists_common.h
new file mode 100644
index 000000000000..888254e8665c
--- /dev/null
+++ b/tools/perf/tests/hists_common.h
@@ -0,0 +1,75 @@
1#ifndef __PERF_TESTS__HISTS_COMMON_H__
2#define __PERF_TESTS__HISTS_COMMON_H__
3
4struct machine;
5struct machines;
6
7#define FAKE_PID_PERF1 100
8#define FAKE_PID_PERF2 200
9#define FAKE_PID_BASH 300
10
11#define FAKE_MAP_PERF 0x400000
12#define FAKE_MAP_BASH 0x400000
13#define FAKE_MAP_LIBC 0x500000
14#define FAKE_MAP_KERNEL 0xf00000
15#define FAKE_MAP_LENGTH 0x100000
16
17#define FAKE_SYM_OFFSET1 700
18#define FAKE_SYM_OFFSET2 800
19#define FAKE_SYM_OFFSET3 900
20#define FAKE_SYM_LENGTH 100
21
22#define FAKE_IP_PERF_MAIN FAKE_MAP_PERF + FAKE_SYM_OFFSET1
23#define FAKE_IP_PERF_RUN_COMMAND FAKE_MAP_PERF + FAKE_SYM_OFFSET2
24#define FAKE_IP_PERF_CMD_RECORD FAKE_MAP_PERF + FAKE_SYM_OFFSET3
25#define FAKE_IP_BASH_MAIN FAKE_MAP_BASH + FAKE_SYM_OFFSET1
26#define FAKE_IP_BASH_XMALLOC FAKE_MAP_BASH + FAKE_SYM_OFFSET2
27#define FAKE_IP_BASH_XFREE FAKE_MAP_BASH + FAKE_SYM_OFFSET3
28#define FAKE_IP_LIBC_MALLOC FAKE_MAP_LIBC + FAKE_SYM_OFFSET1
29#define FAKE_IP_LIBC_FREE FAKE_MAP_LIBC + FAKE_SYM_OFFSET2
30#define FAKE_IP_LIBC_REALLOC FAKE_MAP_LIBC + FAKE_SYM_OFFSET3
31#define FAKE_IP_KERNEL_SCHEDULE FAKE_MAP_KERNEL + FAKE_SYM_OFFSET1
32#define FAKE_IP_KERNEL_PAGE_FAULT FAKE_MAP_KERNEL + FAKE_SYM_OFFSET2
33#define FAKE_IP_KERNEL_SYS_PERF_EVENT_OPEN FAKE_MAP_KERNEL + FAKE_SYM_OFFSET3
34
35/*
36 * The setup_fake_machine() provides a test environment which consists
37 * of 3 processes that have 3 mappings and in turn, have 3 symbols
38 * respectively. See below table:
39 *
40 * Command: Pid Shared Object Symbol
41 * ............. ............. ...................
42 * perf: 100 perf main
43 * perf: 100 perf run_command
44 * perf: 100 perf cmd_record
45 * perf: 100 libc malloc
46 * perf: 100 libc free
47 * perf: 100 libc realloc
48 * perf: 100 [kernel] schedule
49 * perf: 100 [kernel] page_fault
50 * perf: 100 [kernel] sys_perf_event_open
51 * perf: 200 perf main
52 * perf: 200 perf run_command
53 * perf: 200 perf cmd_record
54 * perf: 200 libc malloc
55 * perf: 200 libc free
56 * perf: 200 libc realloc
57 * perf: 200 [kernel] schedule
58 * perf: 200 [kernel] page_fault
59 * perf: 200 [kernel] sys_perf_event_open
60 * bash: 300 bash main
61 * bash: 300 bash xmalloc
62 * bash: 300 bash xfree
63 * bash: 300 libc malloc
64 * bash: 300 libc free
65 * bash: 300 libc realloc
66 * bash: 300 [kernel] schedule
67 * bash: 300 [kernel] page_fault
68 * bash: 300 [kernel] sys_perf_event_open
69 */
70struct machine *setup_fake_machine(struct machines *machines);
71
72void print_hists_in(struct hists *hists);
73void print_hists_out(struct hists *hists);
74
75#endif /* __PERF_TESTS__HISTS_COMMON_H__ */
diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c
new file mode 100644
index 000000000000..0ac240db2e24
--- /dev/null
+++ b/tools/perf/tests/hists_cumulate.c
@@ -0,0 +1,726 @@
1#include "perf.h"
2#include "util/debug.h"
3#include "util/symbol.h"
4#include "util/sort.h"
5#include "util/evsel.h"
6#include "util/evlist.h"
7#include "util/machine.h"
8#include "util/thread.h"
9#include "util/parse-events.h"
10#include "tests/tests.h"
11#include "tests/hists_common.h"
12
13struct sample {
14 u32 pid;
15 u64 ip;
16 struct thread *thread;
17 struct map *map;
18 struct symbol *sym;
19};
20
21/* For the numbers, see hists_common.c */
22static struct sample fake_samples[] = {
23 /* perf [kernel] schedule() */
24 { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_KERNEL_SCHEDULE, },
25 /* perf [perf] main() */
26 { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_PERF_MAIN, },
27 /* perf [perf] cmd_record() */
28 { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_PERF_CMD_RECORD, },
29 /* perf [libc] malloc() */
30 { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_LIBC_MALLOC, },
31 /* perf [libc] free() */
32 { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_LIBC_FREE, },
33 /* perf [perf] main() */
34 { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_MAIN, },
35 /* perf [kernel] page_fault() */
36 { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_KERNEL_PAGE_FAULT, },
37 /* bash [bash] main() */
38 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_MAIN, },
39 /* bash [bash] xmalloc() */
40 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_XMALLOC, },
41 /* bash [kernel] page_fault() */
42 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_KERNEL_PAGE_FAULT, },
43};
44
45/*
46 * Will be casted to struct ip_callchain which has all 64 bit entries
47 * of nr and ips[].
48 */
49static u64 fake_callchains[][10] = {
50 /* schedule => run_command => main */
51 { 3, FAKE_IP_KERNEL_SCHEDULE, FAKE_IP_PERF_RUN_COMMAND, FAKE_IP_PERF_MAIN, },
52 /* main */
53 { 1, FAKE_IP_PERF_MAIN, },
54 /* cmd_record => run_command => main */
55 { 3, FAKE_IP_PERF_CMD_RECORD, FAKE_IP_PERF_RUN_COMMAND, FAKE_IP_PERF_MAIN, },
56 /* malloc => cmd_record => run_command => main */
57 { 4, FAKE_IP_LIBC_MALLOC, FAKE_IP_PERF_CMD_RECORD, FAKE_IP_PERF_RUN_COMMAND,
58 FAKE_IP_PERF_MAIN, },
59 /* free => cmd_record => run_command => main */
60 { 4, FAKE_IP_LIBC_FREE, FAKE_IP_PERF_CMD_RECORD, FAKE_IP_PERF_RUN_COMMAND,
61 FAKE_IP_PERF_MAIN, },
62 /* main */
63 { 1, FAKE_IP_PERF_MAIN, },
64 /* page_fault => sys_perf_event_open => run_command => main */
65 { 4, FAKE_IP_KERNEL_PAGE_FAULT, FAKE_IP_KERNEL_SYS_PERF_EVENT_OPEN,
66 FAKE_IP_PERF_RUN_COMMAND, FAKE_IP_PERF_MAIN, },
67 /* main */
68 { 1, FAKE_IP_BASH_MAIN, },
69 /* xmalloc => malloc => xmalloc => malloc => xmalloc => main */
70 { 6, FAKE_IP_BASH_XMALLOC, FAKE_IP_LIBC_MALLOC, FAKE_IP_BASH_XMALLOC,
71 FAKE_IP_LIBC_MALLOC, FAKE_IP_BASH_XMALLOC, FAKE_IP_BASH_MAIN, },
72 /* page_fault => malloc => main */
73 { 3, FAKE_IP_KERNEL_PAGE_FAULT, FAKE_IP_LIBC_MALLOC, FAKE_IP_BASH_MAIN, },
74};
75
76static int add_hist_entries(struct hists *hists, struct machine *machine)
77{
78 struct addr_location al;
79 struct perf_evsel *evsel = hists_to_evsel(hists);
80 struct perf_sample sample = { .period = 1000, };
81 size_t i;
82
83 for (i = 0; i < ARRAY_SIZE(fake_samples); i++) {
84 const union perf_event event = {
85 .header = {
86 .misc = PERF_RECORD_MISC_USER,
87 },
88 };
89 struct hist_entry_iter iter = {
90 .hide_unresolved = false,
91 };
92
93 if (symbol_conf.cumulate_callchain)
94 iter.ops = &hist_iter_cumulative;
95 else
96 iter.ops = &hist_iter_normal;
97
98 sample.pid = fake_samples[i].pid;
99 sample.tid = fake_samples[i].pid;
100 sample.ip = fake_samples[i].ip;
101 sample.callchain = (struct ip_callchain *)fake_callchains[i];
102
103 if (perf_event__preprocess_sample(&event, machine, &al,
104 &sample) < 0)
105 goto out;
106
107 if (hist_entry_iter__add(&iter, &al, evsel, &sample,
108 PERF_MAX_STACK_DEPTH, NULL) < 0)
109 goto out;
110
111 fake_samples[i].thread = al.thread;
112 fake_samples[i].map = al.map;
113 fake_samples[i].sym = al.sym;
114 }
115
116 return TEST_OK;
117
118out:
119 pr_debug("Not enough memory for adding a hist entry\n");
120 return TEST_FAIL;
121}
122
123static void del_hist_entries(struct hists *hists)
124{
125 struct hist_entry *he;
126 struct rb_root *root_in;
127 struct rb_root *root_out;
128 struct rb_node *node;
129
130 if (sort__need_collapse)
131 root_in = &hists->entries_collapsed;
132 else
133 root_in = hists->entries_in;
134
135 root_out = &hists->entries;
136
137 while (!RB_EMPTY_ROOT(root_out)) {
138 node = rb_first(root_out);
139
140 he = rb_entry(node, struct hist_entry, rb_node);
141 rb_erase(node, root_out);
142 rb_erase(&he->rb_node_in, root_in);
143 hist_entry__free(he);
144 }
145}
146
147typedef int (*test_fn_t)(struct perf_evsel *, struct machine *);
148
149#define COMM(he) (thread__comm_str(he->thread))
150#define DSO(he) (he->ms.map->dso->short_name)
151#define SYM(he) (he->ms.sym->name)
152#define CPU(he) (he->cpu)
153#define PID(he) (he->thread->tid)
154#define DEPTH(he) (he->callchain->max_depth)
155#define CDSO(cl) (cl->ms.map->dso->short_name)
156#define CSYM(cl) (cl->ms.sym->name)
157
158struct result {
159 u64 children;
160 u64 self;
161 const char *comm;
162 const char *dso;
163 const char *sym;
164};
165
166struct callchain_result {
167 u64 nr;
168 struct {
169 const char *dso;
170 const char *sym;
171 } node[10];
172};
173
174static int do_test(struct hists *hists, struct result *expected, size_t nr_expected,
175 struct callchain_result *expected_callchain, size_t nr_callchain)
176{
177 char buf[32];
178 size_t i, c;
179 struct hist_entry *he;
180 struct rb_root *root;
181 struct rb_node *node;
182 struct callchain_node *cnode;
183 struct callchain_list *clist;
184
185 /*
186 * adding and deleting hist entries must be done outside of this
187 * function since TEST_ASSERT_VAL() returns in case of failure.
188 */
189 hists__collapse_resort(hists, NULL);
190 hists__output_resort(hists);
191
192 if (verbose > 2) {
193 pr_info("use callchain: %d, cumulate callchain: %d\n",
194 symbol_conf.use_callchain,
195 symbol_conf.cumulate_callchain);
196 print_hists_out(hists);
197 }
198
199 root = &hists->entries;
200 for (node = rb_first(root), i = 0;
201 node && (he = rb_entry(node, struct hist_entry, rb_node));
202 node = rb_next(node), i++) {
203 scnprintf(buf, sizeof(buf), "Invalid hist entry #%zd", i);
204
205 TEST_ASSERT_VAL("Incorrect number of hist entry",
206 i < nr_expected);
207 TEST_ASSERT_VAL(buf, he->stat.period == expected[i].self &&
208 !strcmp(COMM(he), expected[i].comm) &&
209 !strcmp(DSO(he), expected[i].dso) &&
210 !strcmp(SYM(he), expected[i].sym));
211
212 if (symbol_conf.cumulate_callchain)
213 TEST_ASSERT_VAL(buf, he->stat_acc->period == expected[i].children);
214
215 if (!symbol_conf.use_callchain)
216 continue;
217
218 /* check callchain entries */
219 root = &he->callchain->node.rb_root;
220 cnode = rb_entry(rb_first(root), struct callchain_node, rb_node);
221
222 c = 0;
223 list_for_each_entry(clist, &cnode->val, list) {
224 scnprintf(buf, sizeof(buf), "Invalid callchain entry #%zd/%zd", i, c);
225
226 TEST_ASSERT_VAL("Incorrect number of callchain entry",
227 c < expected_callchain[i].nr);
228 TEST_ASSERT_VAL(buf,
229 !strcmp(CDSO(clist), expected_callchain[i].node[c].dso) &&
230 !strcmp(CSYM(clist), expected_callchain[i].node[c].sym));
231 c++;
232 }
233 /* TODO: handle multiple child nodes properly */
234 TEST_ASSERT_VAL("Incorrect number of callchain entry",
235 c <= expected_callchain[i].nr);
236 }
237 TEST_ASSERT_VAL("Incorrect number of hist entry",
238 i == nr_expected);
239 TEST_ASSERT_VAL("Incorrect number of callchain entry",
240 !symbol_conf.use_callchain || nr_expected == nr_callchain);
241 return 0;
242}
243
244/* NO callchain + NO children */
245static int test1(struct perf_evsel *evsel, struct machine *machine)
246{
247 int err;
248 struct hists *hists = &evsel->hists;
249 /*
250 * expected output:
251 *
252 * Overhead Command Shared Object Symbol
253 * ======== ======= ============= ==============
254 * 20.00% perf perf [.] main
255 * 10.00% bash [kernel] [k] page_fault
256 * 10.00% bash bash [.] main
257 * 10.00% bash bash [.] xmalloc
258 * 10.00% perf [kernel] [k] page_fault
259 * 10.00% perf [kernel] [k] schedule
260 * 10.00% perf libc [.] free
261 * 10.00% perf libc [.] malloc
262 * 10.00% perf perf [.] cmd_record
263 */
264 struct result expected[] = {
265 { 0, 2000, "perf", "perf", "main" },
266 { 0, 1000, "bash", "[kernel]", "page_fault" },
267 { 0, 1000, "bash", "bash", "main" },
268 { 0, 1000, "bash", "bash", "xmalloc" },
269 { 0, 1000, "perf", "[kernel]", "page_fault" },
270 { 0, 1000, "perf", "[kernel]", "schedule" },
271 { 0, 1000, "perf", "libc", "free" },
272 { 0, 1000, "perf", "libc", "malloc" },
273 { 0, 1000, "perf", "perf", "cmd_record" },
274 };
275
276 symbol_conf.use_callchain = false;
277 symbol_conf.cumulate_callchain = false;
278
279 setup_sorting();
280 callchain_register_param(&callchain_param);
281
282 err = add_hist_entries(hists, machine);
283 if (err < 0)
284 goto out;
285
286 err = do_test(hists, expected, ARRAY_SIZE(expected), NULL, 0);
287
288out:
289 del_hist_entries(hists);
290 reset_output_field();
291 return err;
292}
293
294/* callcain + NO children */
295static int test2(struct perf_evsel *evsel, struct machine *machine)
296{
297 int err;
298 struct hists *hists = &evsel->hists;
299 /*
300 * expected output:
301 *
302 * Overhead Command Shared Object Symbol
303 * ======== ======= ============= ==============
304 * 20.00% perf perf [.] main
305 * |
306 * --- main
307 *
308 * 10.00% bash [kernel] [k] page_fault
309 * |
310 * --- page_fault
311 * malloc
312 * main
313 *
314 * 10.00% bash bash [.] main
315 * |
316 * --- main
317 *
318 * 10.00% bash bash [.] xmalloc
319 * |
320 * --- xmalloc
321 * malloc
322 * xmalloc <--- NOTE: there's a cycle
323 * malloc
324 * xmalloc
325 * main
326 *
327 * 10.00% perf [kernel] [k] page_fault
328 * |
329 * --- page_fault
330 * sys_perf_event_open
331 * run_command
332 * main
333 *
334 * 10.00% perf [kernel] [k] schedule
335 * |
336 * --- schedule
337 * run_command
338 * main
339 *
340 * 10.00% perf libc [.] free
341 * |
342 * --- free
343 * cmd_record
344 * run_command
345 * main
346 *
347 * 10.00% perf libc [.] malloc
348 * |
349 * --- malloc
350 * cmd_record
351 * run_command
352 * main
353 *
354 * 10.00% perf perf [.] cmd_record
355 * |
356 * --- cmd_record
357 * run_command
358 * main
359 *
360 */
361 struct result expected[] = {
362 { 0, 2000, "perf", "perf", "main" },
363 { 0, 1000, "bash", "[kernel]", "page_fault" },
364 { 0, 1000, "bash", "bash", "main" },
365 { 0, 1000, "bash", "bash", "xmalloc" },
366 { 0, 1000, "perf", "[kernel]", "page_fault" },
367 { 0, 1000, "perf", "[kernel]", "schedule" },
368 { 0, 1000, "perf", "libc", "free" },
369 { 0, 1000, "perf", "libc", "malloc" },
370 { 0, 1000, "perf", "perf", "cmd_record" },
371 };
372 struct callchain_result expected_callchain[] = {
373 {
374 1, { { "perf", "main" }, },
375 },
376 {
377 3, { { "[kernel]", "page_fault" },
378 { "libc", "malloc" },
379 { "bash", "main" }, },
380 },
381 {
382 1, { { "bash", "main" }, },
383 },
384 {
385 6, { { "bash", "xmalloc" },
386 { "libc", "malloc" },
387 { "bash", "xmalloc" },
388 { "libc", "malloc" },
389 { "bash", "xmalloc" },
390 { "bash", "main" }, },
391 },
392 {
393 4, { { "[kernel]", "page_fault" },
394 { "[kernel]", "sys_perf_event_open" },
395 { "perf", "run_command" },
396 { "perf", "main" }, },
397 },
398 {
399 3, { { "[kernel]", "schedule" },
400 { "perf", "run_command" },
401 { "perf", "main" }, },
402 },
403 {
404 4, { { "libc", "free" },
405 { "perf", "cmd_record" },
406 { "perf", "run_command" },
407 { "perf", "main" }, },
408 },
409 {
410 4, { { "libc", "malloc" },
411 { "perf", "cmd_record" },
412 { "perf", "run_command" },
413 { "perf", "main" }, },
414 },
415 {
416 3, { { "perf", "cmd_record" },
417 { "perf", "run_command" },
418 { "perf", "main" }, },
419 },
420 };
421
422 symbol_conf.use_callchain = true;
423 symbol_conf.cumulate_callchain = false;
424
425 setup_sorting();
426 callchain_register_param(&callchain_param);
427
428 err = add_hist_entries(hists, machine);
429 if (err < 0)
430 goto out;
431
432 err = do_test(hists, expected, ARRAY_SIZE(expected),
433 expected_callchain, ARRAY_SIZE(expected_callchain));
434
435out:
436 del_hist_entries(hists);
437 reset_output_field();
438 return err;
439}
440
441/* NO callchain + children */
442static int test3(struct perf_evsel *evsel, struct machine *machine)
443{
444 int err;
445 struct hists *hists = &evsel->hists;
446 /*
447 * expected output:
448 *
449 * Children Self Command Shared Object Symbol
450 * ======== ======== ======= ============= =======================
451 * 70.00% 20.00% perf perf [.] main
452 * 50.00% 0.00% perf perf [.] run_command
453 * 30.00% 10.00% bash bash [.] main
454 * 30.00% 10.00% perf perf [.] cmd_record
455 * 20.00% 0.00% bash libc [.] malloc
456 * 10.00% 10.00% bash [kernel] [k] page_fault
457 * 10.00% 10.00% perf [kernel] [k] schedule
458 * 10.00% 0.00% perf [kernel] [k] sys_perf_event_open
459 * 10.00% 10.00% perf [kernel] [k] page_fault
460 * 10.00% 10.00% perf libc [.] free
461 * 10.00% 10.00% perf libc [.] malloc
462 * 10.00% 10.00% bash bash [.] xmalloc
463 */
464 struct result expected[] = {
465 { 7000, 2000, "perf", "perf", "main" },
466 { 5000, 0, "perf", "perf", "run_command" },
467 { 3000, 1000, "bash", "bash", "main" },
468 { 3000, 1000, "perf", "perf", "cmd_record" },
469 { 2000, 0, "bash", "libc", "malloc" },
470 { 1000, 1000, "bash", "[kernel]", "page_fault" },
471 { 1000, 1000, "perf", "[kernel]", "schedule" },
472 { 1000, 0, "perf", "[kernel]", "sys_perf_event_open" },
473 { 1000, 1000, "perf", "[kernel]", "page_fault" },
474 { 1000, 1000, "perf", "libc", "free" },
475 { 1000, 1000, "perf", "libc", "malloc" },
476 { 1000, 1000, "bash", "bash", "xmalloc" },
477 };
478
479 symbol_conf.use_callchain = false;
480 symbol_conf.cumulate_callchain = true;
481
482 setup_sorting();
483 callchain_register_param(&callchain_param);
484
485 err = add_hist_entries(hists, machine);
486 if (err < 0)
487 goto out;
488
489 err = do_test(hists, expected, ARRAY_SIZE(expected), NULL, 0);
490
491out:
492 del_hist_entries(hists);
493 reset_output_field();
494 return err;
495}
496
497/* callchain + children */
498static int test4(struct perf_evsel *evsel, struct machine *machine)
499{
500 int err;
501 struct hists *hists = &evsel->hists;
502 /*
503 * expected output:
504 *
505 * Children Self Command Shared Object Symbol
506 * ======== ======== ======= ============= =======================
507 * 70.00% 20.00% perf perf [.] main
508 * |
509 * --- main
510 *
511 * 50.00% 0.00% perf perf [.] run_command
512 * |
513 * --- run_command
514 * main
515 *
516 * 30.00% 10.00% bash bash [.] main
517 * |
518 * --- main
519 *
520 * 30.00% 10.00% perf perf [.] cmd_record
521 * |
522 * --- cmd_record
523 * run_command
524 * main
525 *
526 * 20.00% 0.00% bash libc [.] malloc
527 * |
528 * --- malloc
529 * |
530 * |--50.00%-- xmalloc
531 * | main
532 * --50.00%-- main
533 *
534 * 10.00% 10.00% bash [kernel] [k] page_fault
535 * |
536 * --- page_fault
537 * malloc
538 * main
539 *
540 * 10.00% 10.00% perf [kernel] [k] schedule
541 * |
542 * --- schedule
543 * run_command
544 * main
545 *
546 * 10.00% 0.00% perf [kernel] [k] sys_perf_event_open
547 * |
548 * --- sys_perf_event_open
549 * run_command
550 * main
551 *
552 * 10.00% 10.00% perf [kernel] [k] page_fault
553 * |
554 * --- page_fault
555 * sys_perf_event_open
556 * run_command
557 * main
558 *
559 * 10.00% 10.00% perf libc [.] free
560 * |
561 * --- free
562 * cmd_record
563 * run_command
564 * main
565 *
566 * 10.00% 10.00% perf libc [.] malloc
567 * |
568 * --- malloc
569 * cmd_record
570 * run_command
571 * main
572 *
573 * 10.00% 10.00% bash bash [.] xmalloc
574 * |
575 * --- xmalloc
576 * malloc
577 * xmalloc <--- NOTE: there's a cycle
578 * malloc
579 * xmalloc
580 * main
581 *
582 */
583 struct result expected[] = {
584 { 7000, 2000, "perf", "perf", "main" },
585 { 5000, 0, "perf", "perf", "run_command" },
586 { 3000, 1000, "bash", "bash", "main" },
587 { 3000, 1000, "perf", "perf", "cmd_record" },
588 { 2000, 0, "bash", "libc", "malloc" },
589 { 1000, 1000, "bash", "[kernel]", "page_fault" },
590 { 1000, 1000, "perf", "[kernel]", "schedule" },
591 { 1000, 0, "perf", "[kernel]", "sys_perf_event_open" },
592 { 1000, 1000, "perf", "[kernel]", "page_fault" },
593 { 1000, 1000, "perf", "libc", "free" },
594 { 1000, 1000, "perf", "libc", "malloc" },
595 { 1000, 1000, "bash", "bash", "xmalloc" },
596 };
597 struct callchain_result expected_callchain[] = {
598 {
599 1, { { "perf", "main" }, },
600 },
601 {
602 2, { { "perf", "run_command" },
603 { "perf", "main" }, },
604 },
605 {
606 1, { { "bash", "main" }, },
607 },
608 {
609 3, { { "perf", "cmd_record" },
610 { "perf", "run_command" },
611 { "perf", "main" }, },
612 },
613 {
614 4, { { "libc", "malloc" },
615 { "bash", "xmalloc" },
616 { "bash", "main" },
617 { "bash", "main" }, },
618 },
619 {
620 3, { { "[kernel]", "page_fault" },
621 { "libc", "malloc" },
622 { "bash", "main" }, },
623 },
624 {
625 3, { { "[kernel]", "schedule" },
626 { "perf", "run_command" },
627 { "perf", "main" }, },
628 },
629 {
630 3, { { "[kernel]", "sys_perf_event_open" },
631 { "perf", "run_command" },
632 { "perf", "main" }, },
633 },
634 {
635 4, { { "[kernel]", "page_fault" },
636 { "[kernel]", "sys_perf_event_open" },
637 { "perf", "run_command" },
638 { "perf", "main" }, },
639 },
640 {
641 4, { { "libc", "free" },
642 { "perf", "cmd_record" },
643 { "perf", "run_command" },
644 { "perf", "main" }, },
645 },
646 {
647 4, { { "libc", "malloc" },
648 { "perf", "cmd_record" },
649 { "perf", "run_command" },
650 { "perf", "main" }, },
651 },
652 {
653 6, { { "bash", "xmalloc" },
654 { "libc", "malloc" },
655 { "bash", "xmalloc" },
656 { "libc", "malloc" },
657 { "bash", "xmalloc" },
658 { "bash", "main" }, },
659 },
660 };
661
662 symbol_conf.use_callchain = true;
663 symbol_conf.cumulate_callchain = true;
664
665 setup_sorting();
666 callchain_register_param(&callchain_param);
667
668 err = add_hist_entries(hists, machine);
669 if (err < 0)
670 goto out;
671
672 err = do_test(hists, expected, ARRAY_SIZE(expected),
673 expected_callchain, ARRAY_SIZE(expected_callchain));
674
675out:
676 del_hist_entries(hists);
677 reset_output_field();
678 return err;
679}
680
681int test__hists_cumulate(void)
682{
683 int err = TEST_FAIL;
684 struct machines machines;
685 struct machine *machine;
686 struct perf_evsel *evsel;
687 struct perf_evlist *evlist = perf_evlist__new();
688 size_t i;
689 test_fn_t testcases[] = {
690 test1,
691 test2,
692 test3,
693 test4,
694 };
695
696 TEST_ASSERT_VAL("No memory", evlist);
697
698 err = parse_events(evlist, "cpu-clock");
699 if (err)
700 goto out;
701
702 machines__init(&machines);
703
704 /* setup threads/dso/map/symbols also */
705 machine = setup_fake_machine(&machines);
706 if (!machine)
707 goto out;
708
709 if (verbose > 1)
710 machine__fprintf(machine, stderr);
711
712 evsel = perf_evlist__first(evlist);
713
714 for (i = 0; i < ARRAY_SIZE(testcases); i++) {
715 err = testcases[i](evsel, machine);
716 if (err < 0)
717 break;
718 }
719
720out:
721 /* tear down everything */
722 perf_evlist__delete(evlist);
723 machines__exit(&machines);
724
725 return err;
726}
diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c
new file mode 100644
index 000000000000..821f581fd930
--- /dev/null
+++ b/tools/perf/tests/hists_filter.c
@@ -0,0 +1,289 @@
1#include "perf.h"
2#include "util/debug.h"
3#include "util/symbol.h"
4#include "util/sort.h"
5#include "util/evsel.h"
6#include "util/evlist.h"
7#include "util/machine.h"
8#include "util/thread.h"
9#include "util/parse-events.h"
10#include "tests/tests.h"
11#include "tests/hists_common.h"
12
13struct sample {
14 u32 pid;
15 u64 ip;
16 struct thread *thread;
17 struct map *map;
18 struct symbol *sym;
19};
20
21/* For the numbers, see hists_common.c */
22static struct sample fake_samples[] = {
23 /* perf [kernel] schedule() */
24 { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_KERNEL_SCHEDULE, },
25 /* perf [perf] main() */
26 { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_PERF_MAIN, },
27 /* perf [libc] malloc() */
28 { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_LIBC_MALLOC, },
29 /* perf [perf] main() */
30 { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_MAIN, }, /* will be merged */
31 /* perf [perf] cmd_record() */
32 { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_CMD_RECORD, },
33 /* perf [kernel] page_fault() */
34 { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_KERNEL_PAGE_FAULT, },
35 /* bash [bash] main() */
36 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_MAIN, },
37 /* bash [bash] xmalloc() */
38 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_XMALLOC, },
39 /* bash [libc] malloc() */
40 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_LIBC_MALLOC, },
41 /* bash [kernel] page_fault() */
42 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_KERNEL_PAGE_FAULT, },
43};
44
45static int add_hist_entries(struct perf_evlist *evlist,
46 struct machine *machine __maybe_unused)
47{
48 struct perf_evsel *evsel;
49 struct addr_location al;
50 struct perf_sample sample = { .period = 100, };
51 size_t i;
52
53 /*
54 * each evsel will have 10 samples but the 4th sample
55 * (perf [perf] main) will be collapsed to an existing entry
56 * so total 9 entries will be in the tree.
57 */
58 evlist__for_each(evlist, evsel) {
59 for (i = 0; i < ARRAY_SIZE(fake_samples); i++) {
60 const union perf_event event = {
61 .header = {
62 .misc = PERF_RECORD_MISC_USER,
63 },
64 };
65 struct hist_entry_iter iter = {
66 .ops = &hist_iter_normal,
67 .hide_unresolved = false,
68 };
69
70 /* make sure it has no filter at first */
71 evsel->hists.thread_filter = NULL;
72 evsel->hists.dso_filter = NULL;
73 evsel->hists.symbol_filter_str = NULL;
74
75 sample.pid = fake_samples[i].pid;
76 sample.tid = fake_samples[i].pid;
77 sample.ip = fake_samples[i].ip;
78
79 if (perf_event__preprocess_sample(&event, machine, &al,
80 &sample) < 0)
81 goto out;
82
83 if (hist_entry_iter__add(&iter, &al, evsel, &sample,
84 PERF_MAX_STACK_DEPTH, NULL) < 0)
85 goto out;
86
87 fake_samples[i].thread = al.thread;
88 fake_samples[i].map = al.map;
89 fake_samples[i].sym = al.sym;
90 }
91 }
92
93 return 0;
94
95out:
96 pr_debug("Not enough memory for adding a hist entry\n");
97 return TEST_FAIL;
98}
99
100int test__hists_filter(void)
101{
102 int err = TEST_FAIL;
103 struct machines machines;
104 struct machine *machine;
105 struct perf_evsel *evsel;
106 struct perf_evlist *evlist = perf_evlist__new();
107
108 TEST_ASSERT_VAL("No memory", evlist);
109
110 err = parse_events(evlist, "cpu-clock");
111 if (err)
112 goto out;
113 err = parse_events(evlist, "task-clock");
114 if (err)
115 goto out;
116
117 /* default sort order (comm,dso,sym) will be used */
118 if (setup_sorting() < 0)
119 goto out;
120
121 machines__init(&machines);
122
123 /* setup threads/dso/map/symbols also */
124 machine = setup_fake_machine(&machines);
125 if (!machine)
126 goto out;
127
128 if (verbose > 1)
129 machine__fprintf(machine, stderr);
130
131 /* process sample events */
132 err = add_hist_entries(evlist, machine);
133 if (err < 0)
134 goto out;
135
136 evlist__for_each(evlist, evsel) {
137 struct hists *hists = &evsel->hists;
138
139 hists__collapse_resort(hists, NULL);
140 hists__output_resort(hists);
141
142 if (verbose > 2) {
143 pr_info("Normal histogram\n");
144 print_hists_out(hists);
145 }
146
147 TEST_ASSERT_VAL("Invalid nr samples",
148 hists->stats.nr_events[PERF_RECORD_SAMPLE] == 10);
149 TEST_ASSERT_VAL("Invalid nr hist entries",
150 hists->nr_entries == 9);
151 TEST_ASSERT_VAL("Invalid total period",
152 hists->stats.total_period == 1000);
153 TEST_ASSERT_VAL("Unmatched nr samples",
154 hists->stats.nr_events[PERF_RECORD_SAMPLE] ==
155 hists->stats.nr_non_filtered_samples);
156 TEST_ASSERT_VAL("Unmatched nr hist entries",
157 hists->nr_entries == hists->nr_non_filtered_entries);
158 TEST_ASSERT_VAL("Unmatched total period",
159 hists->stats.total_period ==
160 hists->stats.total_non_filtered_period);
161
162 /* now applying thread filter for 'bash' */
163 evsel->hists.thread_filter = fake_samples[9].thread;
164 hists__filter_by_thread(hists);
165
166 if (verbose > 2) {
167 pr_info("Histogram for thread filter\n");
168 print_hists_out(hists);
169 }
170
171 /* normal stats should be invariant */
172 TEST_ASSERT_VAL("Invalid nr samples",
173 hists->stats.nr_events[PERF_RECORD_SAMPLE] == 10);
174 TEST_ASSERT_VAL("Invalid nr hist entries",
175 hists->nr_entries == 9);
176 TEST_ASSERT_VAL("Invalid total period",
177 hists->stats.total_period == 1000);
178
179 /* but filter stats are changed */
180 TEST_ASSERT_VAL("Unmatched nr samples for thread filter",
181 hists->stats.nr_non_filtered_samples == 4);
182 TEST_ASSERT_VAL("Unmatched nr hist entries for thread filter",
183 hists->nr_non_filtered_entries == 4);
184 TEST_ASSERT_VAL("Unmatched total period for thread filter",
185 hists->stats.total_non_filtered_period == 400);
186
187 /* remove thread filter first */
188 evsel->hists.thread_filter = NULL;
189 hists__filter_by_thread(hists);
190
191 /* now applying dso filter for 'kernel' */
192 evsel->hists.dso_filter = fake_samples[0].map->dso;
193 hists__filter_by_dso(hists);
194
195 if (verbose > 2) {
196 pr_info("Histogram for dso filter\n");
197 print_hists_out(hists);
198 }
199
200 /* normal stats should be invariant */
201 TEST_ASSERT_VAL("Invalid nr samples",
202 hists->stats.nr_events[PERF_RECORD_SAMPLE] == 10);
203 TEST_ASSERT_VAL("Invalid nr hist entries",
204 hists->nr_entries == 9);
205 TEST_ASSERT_VAL("Invalid total period",
206 hists->stats.total_period == 1000);
207
208 /* but filter stats are changed */
209 TEST_ASSERT_VAL("Unmatched nr samples for dso filter",
210 hists->stats.nr_non_filtered_samples == 3);
211 TEST_ASSERT_VAL("Unmatched nr hist entries for dso filter",
212 hists->nr_non_filtered_entries == 3);
213 TEST_ASSERT_VAL("Unmatched total period for dso filter",
214 hists->stats.total_non_filtered_period == 300);
215
216 /* remove dso filter first */
217 evsel->hists.dso_filter = NULL;
218 hists__filter_by_dso(hists);
219
220 /*
221 * now applying symbol filter for 'main'. Also note that
222 * there's 3 samples that have 'main' symbol but the 4th
223 * entry of fake_samples was collapsed already so it won't
224 * be counted as a separate entry but the sample count and
225 * total period will be remained.
226 */
227 evsel->hists.symbol_filter_str = "main";
228 hists__filter_by_symbol(hists);
229
230 if (verbose > 2) {
231 pr_info("Histogram for symbol filter\n");
232 print_hists_out(hists);
233 }
234
235 /* normal stats should be invariant */
236 TEST_ASSERT_VAL("Invalid nr samples",
237 hists->stats.nr_events[PERF_RECORD_SAMPLE] == 10);
238 TEST_ASSERT_VAL("Invalid nr hist entries",
239 hists->nr_entries == 9);
240 TEST_ASSERT_VAL("Invalid total period",
241 hists->stats.total_period == 1000);
242
243 /* but filter stats are changed */
244 TEST_ASSERT_VAL("Unmatched nr samples for symbol filter",
245 hists->stats.nr_non_filtered_samples == 3);
246 TEST_ASSERT_VAL("Unmatched nr hist entries for symbol filter",
247 hists->nr_non_filtered_entries == 2);
248 TEST_ASSERT_VAL("Unmatched total period for symbol filter",
249 hists->stats.total_non_filtered_period == 300);
250
251 /* now applying all filters at once. */
252 evsel->hists.thread_filter = fake_samples[1].thread;
253 evsel->hists.dso_filter = fake_samples[1].map->dso;
254 hists__filter_by_thread(hists);
255 hists__filter_by_dso(hists);
256
257 if (verbose > 2) {
258 pr_info("Histogram for all filters\n");
259 print_hists_out(hists);
260 }
261
262 /* normal stats should be invariant */
263 TEST_ASSERT_VAL("Invalid nr samples",
264 hists->stats.nr_events[PERF_RECORD_SAMPLE] == 10);
265 TEST_ASSERT_VAL("Invalid nr hist entries",
266 hists->nr_entries == 9);
267 TEST_ASSERT_VAL("Invalid total period",
268 hists->stats.total_period == 1000);
269
270 /* but filter stats are changed */
271 TEST_ASSERT_VAL("Unmatched nr samples for all filter",
272 hists->stats.nr_non_filtered_samples == 2);
273 TEST_ASSERT_VAL("Unmatched nr hist entries for all filter",
274 hists->nr_non_filtered_entries == 1);
275 TEST_ASSERT_VAL("Unmatched total period for all filter",
276 hists->stats.total_non_filtered_period == 200);
277 }
278
279
280 err = TEST_OK;
281
282out:
283 /* tear down everything */
284 perf_evlist__delete(evlist);
285 reset_output_field();
286 machines__exit(&machines);
287
288 return err;
289}
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c
index 7ccbc7b6ae77..d4b34b0f50a2 100644
--- a/tools/perf/tests/hists_link.c
+++ b/tools/perf/tests/hists_link.c
@@ -8,145 +8,7 @@
8#include "machine.h" 8#include "machine.h"
9#include "thread.h" 9#include "thread.h"
10#include "parse-events.h" 10#include "parse-events.h"
11 11#include "hists_common.h"
12static struct {
13 u32 pid;
14 const char *comm;
15} fake_threads[] = {
16 { 100, "perf" },
17 { 200, "perf" },
18 { 300, "bash" },
19};
20
21static struct {
22 u32 pid;
23 u64 start;
24 const char *filename;
25} fake_mmap_info[] = {
26 { 100, 0x40000, "perf" },
27 { 100, 0x50000, "libc" },
28 { 100, 0xf0000, "[kernel]" },
29 { 200, 0x40000, "perf" },
30 { 200, 0x50000, "libc" },
31 { 200, 0xf0000, "[kernel]" },
32 { 300, 0x40000, "bash" },
33 { 300, 0x50000, "libc" },
34 { 300, 0xf0000, "[kernel]" },
35};
36
37struct fake_sym {
38 u64 start;
39 u64 length;
40 const char *name;
41};
42
43static struct fake_sym perf_syms[] = {
44 { 700, 100, "main" },
45 { 800, 100, "run_command" },
46 { 900, 100, "cmd_record" },
47};
48
49static struct fake_sym bash_syms[] = {
50 { 700, 100, "main" },
51 { 800, 100, "xmalloc" },
52 { 900, 100, "xfree" },
53};
54
55static struct fake_sym libc_syms[] = {
56 { 700, 100, "malloc" },
57 { 800, 100, "free" },
58 { 900, 100, "realloc" },
59};
60
61static struct fake_sym kernel_syms[] = {
62 { 700, 100, "schedule" },
63 { 800, 100, "page_fault" },
64 { 900, 100, "sys_perf_event_open" },
65};
66
67static struct {
68 const char *dso_name;
69 struct fake_sym *syms;
70 size_t nr_syms;
71} fake_symbols[] = {
72 { "perf", perf_syms, ARRAY_SIZE(perf_syms) },
73 { "bash", bash_syms, ARRAY_SIZE(bash_syms) },
74 { "libc", libc_syms, ARRAY_SIZE(libc_syms) },
75 { "[kernel]", kernel_syms, ARRAY_SIZE(kernel_syms) },
76};
77
78static struct machine *setup_fake_machine(struct machines *machines)
79{
80 struct machine *machine = machines__find(machines, HOST_KERNEL_ID);
81 size_t i;
82
83 if (machine == NULL) {
84 pr_debug("Not enough memory for machine setup\n");
85 return NULL;
86 }
87
88 for (i = 0; i < ARRAY_SIZE(fake_threads); i++) {
89 struct thread *thread;
90
91 thread = machine__findnew_thread(machine, fake_threads[i].pid,
92 fake_threads[i].pid);
93 if (thread == NULL)
94 goto out;
95
96 thread__set_comm(thread, fake_threads[i].comm, 0);
97 }
98
99 for (i = 0; i < ARRAY_SIZE(fake_mmap_info); i++) {
100 union perf_event fake_mmap_event = {
101 .mmap = {
102 .header = { .misc = PERF_RECORD_MISC_USER, },
103 .pid = fake_mmap_info[i].pid,
104 .tid = fake_mmap_info[i].pid,
105 .start = fake_mmap_info[i].start,
106 .len = 0x1000ULL,
107 .pgoff = 0ULL,
108 },
109 };
110
111 strcpy(fake_mmap_event.mmap.filename,
112 fake_mmap_info[i].filename);
113
114 machine__process_mmap_event(machine, &fake_mmap_event, NULL);
115 }
116
117 for (i = 0; i < ARRAY_SIZE(fake_symbols); i++) {
118 size_t k;
119 struct dso *dso;
120
121 dso = __dsos__findnew(&machine->user_dsos,
122 fake_symbols[i].dso_name);
123 if (dso == NULL)
124 goto out;
125
126 /* emulate dso__load() */
127 dso__set_loaded(dso, MAP__FUNCTION);
128
129 for (k = 0; k < fake_symbols[i].nr_syms; k++) {
130 struct symbol *sym;
131 struct fake_sym *fsym = &fake_symbols[i].syms[k];
132
133 sym = symbol__new(fsym->start, fsym->length,
134 STB_GLOBAL, fsym->name);
135 if (sym == NULL)
136 goto out;
137
138 symbols__insert(&dso->symbols[MAP__FUNCTION], sym);
139 }
140 }
141
142 return machine;
143
144out:
145 pr_debug("Not enough memory for machine setup\n");
146 machine__delete_threads(machine);
147 machine__delete(machine);
148 return NULL;
149}
150 12
151struct sample { 13struct sample {
152 u32 pid; 14 u32 pid;
@@ -156,43 +18,44 @@ struct sample {
156 struct symbol *sym; 18 struct symbol *sym;
157}; 19};
158 20
21/* For the numbers, see hists_common.c */
159static struct sample fake_common_samples[] = { 22static struct sample fake_common_samples[] = {
160 /* perf [kernel] schedule() */ 23 /* perf [kernel] schedule() */
161 { .pid = 100, .ip = 0xf0000 + 700, }, 24 { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_KERNEL_SCHEDULE, },
162 /* perf [perf] main() */ 25 /* perf [perf] main() */
163 { .pid = 200, .ip = 0x40000 + 700, }, 26 { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_MAIN, },
164 /* perf [perf] cmd_record() */ 27 /* perf [perf] cmd_record() */
165 { .pid = 200, .ip = 0x40000 + 900, }, 28 { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_CMD_RECORD, },
166 /* bash [bash] xmalloc() */ 29 /* bash [bash] xmalloc() */
167 { .pid = 300, .ip = 0x40000 + 800, }, 30 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_XMALLOC, },
168 /* bash [libc] malloc() */ 31 /* bash [libc] malloc() */
169 { .pid = 300, .ip = 0x50000 + 700, }, 32 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_LIBC_MALLOC, },
170}; 33};
171 34
172static struct sample fake_samples[][5] = { 35static struct sample fake_samples[][5] = {
173 { 36 {
174 /* perf [perf] run_command() */ 37 /* perf [perf] run_command() */
175 { .pid = 100, .ip = 0x40000 + 800, }, 38 { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_PERF_RUN_COMMAND, },
176 /* perf [libc] malloc() */ 39 /* perf [libc] malloc() */
177 { .pid = 100, .ip = 0x50000 + 700, }, 40 { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_LIBC_MALLOC, },
178 /* perf [kernel] page_fault() */ 41 /* perf [kernel] page_fault() */
179 { .pid = 100, .ip = 0xf0000 + 800, }, 42 { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_KERNEL_PAGE_FAULT, },
180 /* perf [kernel] sys_perf_event_open() */ 43 /* perf [kernel] sys_perf_event_open() */
181 { .pid = 200, .ip = 0xf0000 + 900, }, 44 { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_KERNEL_SYS_PERF_EVENT_OPEN, },
182 /* bash [libc] free() */ 45 /* bash [libc] free() */
183 { .pid = 300, .ip = 0x50000 + 800, }, 46 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_LIBC_FREE, },
184 }, 47 },
185 { 48 {
186 /* perf [libc] free() */ 49 /* perf [libc] free() */
187 { .pid = 200, .ip = 0x50000 + 800, }, 50 { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_LIBC_FREE, },
188 /* bash [libc] malloc() */ 51 /* bash [libc] malloc() */
189 { .pid = 300, .ip = 0x50000 + 700, }, /* will be merged */ 52 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_LIBC_MALLOC, }, /* will be merged */
190 /* bash [bash] xfee() */ 53 /* bash [bash] xfee() */
191 { .pid = 300, .ip = 0x40000 + 900, }, 54 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_XFREE, },
192 /* bash [libc] realloc() */ 55 /* bash [libc] realloc() */
193 { .pid = 300, .ip = 0x50000 + 900, }, 56 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_LIBC_REALLOC, },
194 /* bash [kernel] page_fault() */ 57 /* bash [kernel] page_fault() */
195 { .pid = 300, .ip = 0xf0000 + 800, }, 58 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_KERNEL_PAGE_FAULT, },
196 }, 59 },
197}; 60};
198 61
@@ -201,7 +64,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
201 struct perf_evsel *evsel; 64 struct perf_evsel *evsel;
202 struct addr_location al; 65 struct addr_location al;
203 struct hist_entry *he; 66 struct hist_entry *he;
204 struct perf_sample sample = { .cpu = 0, }; 67 struct perf_sample sample = { .period = 1, };
205 size_t i = 0, k; 68 size_t i = 0, k;
206 69
207 /* 70 /*
@@ -218,13 +81,14 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
218 }; 81 };
219 82
220 sample.pid = fake_common_samples[k].pid; 83 sample.pid = fake_common_samples[k].pid;
84 sample.tid = fake_common_samples[k].pid;
221 sample.ip = fake_common_samples[k].ip; 85 sample.ip = fake_common_samples[k].ip;
222 if (perf_event__preprocess_sample(&event, machine, &al, 86 if (perf_event__preprocess_sample(&event, machine, &al,
223 &sample) < 0) 87 &sample) < 0)
224 goto out; 88 goto out;
225 89
226 he = __hists__add_entry(&evsel->hists, &al, NULL, 90 he = __hists__add_entry(&evsel->hists, &al, NULL,
227 NULL, NULL, 1, 1, 0); 91 NULL, NULL, 1, 1, 0, true);
228 if (he == NULL) 92 if (he == NULL)
229 goto out; 93 goto out;
230 94
@@ -241,13 +105,14 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
241 }; 105 };
242 106
243 sample.pid = fake_samples[i][k].pid; 107 sample.pid = fake_samples[i][k].pid;
108 sample.tid = fake_samples[i][k].pid;
244 sample.ip = fake_samples[i][k].ip; 109 sample.ip = fake_samples[i][k].ip;
245 if (perf_event__preprocess_sample(&event, machine, &al, 110 if (perf_event__preprocess_sample(&event, machine, &al,
246 &sample) < 0) 111 &sample) < 0)
247 goto out; 112 goto out;
248 113
249 he = __hists__add_entry(&evsel->hists, &al, NULL, 114 he = __hists__add_entry(&evsel->hists, &al, NULL,
250 NULL, NULL, 1, 1, 0); 115 NULL, NULL, 1, 1, 0, true);
251 if (he == NULL) 116 if (he == NULL)
252 goto out; 117 goto out;
253 118
@@ -403,33 +268,6 @@ static int validate_link(struct hists *leader, struct hists *other)
403 return __validate_link(leader, 0) || __validate_link(other, 1); 268 return __validate_link(leader, 0) || __validate_link(other, 1);
404} 269}
405 270
406static void print_hists(struct hists *hists)
407{
408 int i = 0;
409 struct rb_root *root;
410 struct rb_node *node;
411
412 if (sort__need_collapse)
413 root = &hists->entries_collapsed;
414 else
415 root = hists->entries_in;
416
417 pr_info("----- %s --------\n", __func__);
418 node = rb_first(root);
419 while (node) {
420 struct hist_entry *he;
421
422 he = rb_entry(node, struct hist_entry, rb_node_in);
423
424 pr_info("%2d: entry: %-8s [%-8s] %20s: period = %"PRIu64"\n",
425 i, thread__comm_str(he->thread), he->ms.map->dso->short_name,
426 he->ms.sym->name, he->stat.period);
427
428 i++;
429 node = rb_next(node);
430 }
431}
432
433int test__hists_link(void) 271int test__hists_link(void)
434{ 272{
435 int err = -1; 273 int err = -1;
@@ -471,7 +309,7 @@ int test__hists_link(void)
471 hists__collapse_resort(&evsel->hists, NULL); 309 hists__collapse_resort(&evsel->hists, NULL);
472 310
473 if (verbose > 2) 311 if (verbose > 2)
474 print_hists(&evsel->hists); 312 print_hists_in(&evsel->hists);
475 } 313 }
476 314
477 first = perf_evlist__first(evlist); 315 first = perf_evlist__first(evlist);
@@ -494,6 +332,7 @@ int test__hists_link(void)
494out: 332out:
495 /* tear down everything */ 333 /* tear down everything */
496 perf_evlist__delete(evlist); 334 perf_evlist__delete(evlist);
335 reset_output_field();
497 machines__exit(&machines); 336 machines__exit(&machines);
498 337
499 return err; 338 return err;
diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c
new file mode 100644
index 000000000000..e3bbd6c54c1b
--- /dev/null
+++ b/tools/perf/tests/hists_output.c
@@ -0,0 +1,621 @@
1#include "perf.h"
2#include "util/debug.h"
3#include "util/symbol.h"
4#include "util/sort.h"
5#include "util/evsel.h"
6#include "util/evlist.h"
7#include "util/machine.h"
8#include "util/thread.h"
9#include "util/parse-events.h"
10#include "tests/tests.h"
11#include "tests/hists_common.h"
12
13struct sample {
14 u32 cpu;
15 u32 pid;
16 u64 ip;
17 struct thread *thread;
18 struct map *map;
19 struct symbol *sym;
20};
21
22/* For the numbers, see hists_common.c */
23static struct sample fake_samples[] = {
24 /* perf [kernel] schedule() */
25 { .cpu = 0, .pid = FAKE_PID_PERF1, .ip = FAKE_IP_KERNEL_SCHEDULE, },
26 /* perf [perf] main() */
27 { .cpu = 1, .pid = FAKE_PID_PERF1, .ip = FAKE_IP_PERF_MAIN, },
28 /* perf [perf] cmd_record() */
29 { .cpu = 1, .pid = FAKE_PID_PERF1, .ip = FAKE_IP_PERF_CMD_RECORD, },
30 /* perf [libc] malloc() */
31 { .cpu = 1, .pid = FAKE_PID_PERF1, .ip = FAKE_IP_LIBC_MALLOC, },
32 /* perf [libc] free() */
33 { .cpu = 2, .pid = FAKE_PID_PERF1, .ip = FAKE_IP_LIBC_FREE, },
34 /* perf [perf] main() */
35 { .cpu = 2, .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_MAIN, },
36 /* perf [kernel] page_fault() */
37 { .cpu = 2, .pid = FAKE_PID_PERF2, .ip = FAKE_IP_KERNEL_PAGE_FAULT, },
38 /* bash [bash] main() */
39 { .cpu = 3, .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_MAIN, },
40 /* bash [bash] xmalloc() */
41 { .cpu = 0, .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_XMALLOC, },
42 /* bash [kernel] page_fault() */
43 { .cpu = 1, .pid = FAKE_PID_BASH, .ip = FAKE_IP_KERNEL_PAGE_FAULT, },
44};
45
46static int add_hist_entries(struct hists *hists, struct machine *machine)
47{
48 struct addr_location al;
49 struct perf_evsel *evsel = hists_to_evsel(hists);
50 struct perf_sample sample = { .period = 100, };
51 size_t i;
52
53 for (i = 0; i < ARRAY_SIZE(fake_samples); i++) {
54 const union perf_event event = {
55 .header = {
56 .misc = PERF_RECORD_MISC_USER,
57 },
58 };
59 struct hist_entry_iter iter = {
60 .ops = &hist_iter_normal,
61 .hide_unresolved = false,
62 };
63
64 sample.cpu = fake_samples[i].cpu;
65 sample.pid = fake_samples[i].pid;
66 sample.tid = fake_samples[i].pid;
67 sample.ip = fake_samples[i].ip;
68
69 if (perf_event__preprocess_sample(&event, machine, &al,
70 &sample) < 0)
71 goto out;
72
73 if (hist_entry_iter__add(&iter, &al, evsel, &sample,
74 PERF_MAX_STACK_DEPTH, NULL) < 0)
75 goto out;
76
77 fake_samples[i].thread = al.thread;
78 fake_samples[i].map = al.map;
79 fake_samples[i].sym = al.sym;
80 }
81
82 return TEST_OK;
83
84out:
85 pr_debug("Not enough memory for adding a hist entry\n");
86 return TEST_FAIL;
87}
88
89static void del_hist_entries(struct hists *hists)
90{
91 struct hist_entry *he;
92 struct rb_root *root_in;
93 struct rb_root *root_out;
94 struct rb_node *node;
95
96 if (sort__need_collapse)
97 root_in = &hists->entries_collapsed;
98 else
99 root_in = hists->entries_in;
100
101 root_out = &hists->entries;
102
103 while (!RB_EMPTY_ROOT(root_out)) {
104 node = rb_first(root_out);
105
106 he = rb_entry(node, struct hist_entry, rb_node);
107 rb_erase(node, root_out);
108 rb_erase(&he->rb_node_in, root_in);
109 hist_entry__free(he);
110 }
111}
112
113typedef int (*test_fn_t)(struct perf_evsel *, struct machine *);
114
115#define COMM(he) (thread__comm_str(he->thread))
116#define DSO(he) (he->ms.map->dso->short_name)
117#define SYM(he) (he->ms.sym->name)
118#define CPU(he) (he->cpu)
119#define PID(he) (he->thread->tid)
120
121/* default sort keys (no field) */
122static int test1(struct perf_evsel *evsel, struct machine *machine)
123{
124 int err;
125 struct hists *hists = &evsel->hists;
126 struct hist_entry *he;
127 struct rb_root *root;
128 struct rb_node *node;
129
130 field_order = NULL;
131 sort_order = NULL; /* equivalent to sort_order = "comm,dso,sym" */
132
133 setup_sorting();
134
135 /*
136 * expected output:
137 *
138 * Overhead Command Shared Object Symbol
139 * ======== ======= ============= ==============
140 * 20.00% perf perf [.] main
141 * 10.00% bash [kernel] [k] page_fault
142 * 10.00% bash bash [.] main
143 * 10.00% bash bash [.] xmalloc
144 * 10.00% perf [kernel] [k] page_fault
145 * 10.00% perf [kernel] [k] schedule
146 * 10.00% perf libc [.] free
147 * 10.00% perf libc [.] malloc
148 * 10.00% perf perf [.] cmd_record
149 */
150 err = add_hist_entries(hists, machine);
151 if (err < 0)
152 goto out;
153
154 hists__collapse_resort(hists, NULL);
155 hists__output_resort(hists);
156
157 if (verbose > 2) {
158 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
159 print_hists_out(hists);
160 }
161
162 root = &evsel->hists.entries;
163 node = rb_first(root);
164 he = rb_entry(node, struct hist_entry, rb_node);
165 TEST_ASSERT_VAL("Invalid hist entry",
166 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&
167 !strcmp(SYM(he), "main") && he->stat.period == 200);
168
169 node = rb_next(node);
170 he = rb_entry(node, struct hist_entry, rb_node);
171 TEST_ASSERT_VAL("Invalid hist entry",
172 !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "[kernel]") &&
173 !strcmp(SYM(he), "page_fault") && he->stat.period == 100);
174
175 node = rb_next(node);
176 he = rb_entry(node, struct hist_entry, rb_node);
177 TEST_ASSERT_VAL("Invalid hist entry",
178 !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "bash") &&
179 !strcmp(SYM(he), "main") && he->stat.period == 100);
180
181 node = rb_next(node);
182 he = rb_entry(node, struct hist_entry, rb_node);
183 TEST_ASSERT_VAL("Invalid hist entry",
184 !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "bash") &&
185 !strcmp(SYM(he), "xmalloc") && he->stat.period == 100);
186
187 node = rb_next(node);
188 he = rb_entry(node, struct hist_entry, rb_node);
189 TEST_ASSERT_VAL("Invalid hist entry",
190 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "[kernel]") &&
191 !strcmp(SYM(he), "page_fault") && he->stat.period == 100);
192
193 node = rb_next(node);
194 he = rb_entry(node, struct hist_entry, rb_node);
195 TEST_ASSERT_VAL("Invalid hist entry",
196 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "[kernel]") &&
197 !strcmp(SYM(he), "schedule") && he->stat.period == 100);
198
199 node = rb_next(node);
200 he = rb_entry(node, struct hist_entry, rb_node);
201 TEST_ASSERT_VAL("Invalid hist entry",
202 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "libc") &&
203 !strcmp(SYM(he), "free") && he->stat.period == 100);
204
205 node = rb_next(node);
206 he = rb_entry(node, struct hist_entry, rb_node);
207 TEST_ASSERT_VAL("Invalid hist entry",
208 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "libc") &&
209 !strcmp(SYM(he), "malloc") && he->stat.period == 100);
210
211 node = rb_next(node);
212 he = rb_entry(node, struct hist_entry, rb_node);
213 TEST_ASSERT_VAL("Invalid hist entry",
214 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&
215 !strcmp(SYM(he), "cmd_record") && he->stat.period == 100);
216
217out:
218 del_hist_entries(hists);
219 reset_output_field();
220 return err;
221}
222
223/* mixed fields and sort keys */
224static int test2(struct perf_evsel *evsel, struct machine *machine)
225{
226 int err;
227 struct hists *hists = &evsel->hists;
228 struct hist_entry *he;
229 struct rb_root *root;
230 struct rb_node *node;
231
232 field_order = "overhead,cpu";
233 sort_order = "pid";
234
235 setup_sorting();
236
237 /*
238 * expected output:
239 *
240 * Overhead CPU Command: Pid
241 * ======== === =============
242 * 30.00% 1 perf : 100
243 * 10.00% 0 perf : 100
244 * 10.00% 2 perf : 100
245 * 20.00% 2 perf : 200
246 * 10.00% 0 bash : 300
247 * 10.00% 1 bash : 300
248 * 10.00% 3 bash : 300
249 */
250 err = add_hist_entries(hists, machine);
251 if (err < 0)
252 goto out;
253
254 hists__collapse_resort(hists, NULL);
255 hists__output_resort(hists);
256
257 if (verbose > 2) {
258 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
259 print_hists_out(hists);
260 }
261
262 root = &evsel->hists.entries;
263 node = rb_first(root);
264 he = rb_entry(node, struct hist_entry, rb_node);
265 TEST_ASSERT_VAL("Invalid hist entry",
266 CPU(he) == 1 && PID(he) == 100 && he->stat.period == 300);
267
268 node = rb_next(node);
269 he = rb_entry(node, struct hist_entry, rb_node);
270 TEST_ASSERT_VAL("Invalid hist entry",
271 CPU(he) == 0 && PID(he) == 100 && he->stat.period == 100);
272
273out:
274 del_hist_entries(hists);
275 reset_output_field();
276 return err;
277}
278
279/* fields only (no sort key) */
280static int test3(struct perf_evsel *evsel, struct machine *machine)
281{
282 int err;
283 struct hists *hists = &evsel->hists;
284 struct hist_entry *he;
285 struct rb_root *root;
286 struct rb_node *node;
287
288 field_order = "comm,overhead,dso";
289 sort_order = NULL;
290
291 setup_sorting();
292
293 /*
294 * expected output:
295 *
296 * Command Overhead Shared Object
297 * ======= ======== =============
298 * bash 20.00% bash
299 * bash 10.00% [kernel]
300 * perf 30.00% perf
301 * perf 20.00% [kernel]
302 * perf 20.00% libc
303 */
304 err = add_hist_entries(hists, machine);
305 if (err < 0)
306 goto out;
307
308 hists__collapse_resort(hists, NULL);
309 hists__output_resort(hists);
310
311 if (verbose > 2) {
312 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
313 print_hists_out(hists);
314 }
315
316 root = &evsel->hists.entries;
317 node = rb_first(root);
318 he = rb_entry(node, struct hist_entry, rb_node);
319 TEST_ASSERT_VAL("Invalid hist entry",
320 !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "bash") &&
321 he->stat.period == 200);
322
323 node = rb_next(node);
324 he = rb_entry(node, struct hist_entry, rb_node);
325 TEST_ASSERT_VAL("Invalid hist entry",
326 !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "[kernel]") &&
327 he->stat.period == 100);
328
329 node = rb_next(node);
330 he = rb_entry(node, struct hist_entry, rb_node);
331 TEST_ASSERT_VAL("Invalid hist entry",
332 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&
333 he->stat.period == 300);
334
335 node = rb_next(node);
336 he = rb_entry(node, struct hist_entry, rb_node);
337 TEST_ASSERT_VAL("Invalid hist entry",
338 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "[kernel]") &&
339 he->stat.period == 200);
340
341 node = rb_next(node);
342 he = rb_entry(node, struct hist_entry, rb_node);
343 TEST_ASSERT_VAL("Invalid hist entry",
344 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "libc") &&
345 he->stat.period == 200);
346
347out:
348 del_hist_entries(hists);
349 reset_output_field();
350 return err;
351}
352
353/* handle duplicate 'dso' field */
354static int test4(struct perf_evsel *evsel, struct machine *machine)
355{
356 int err;
357 struct hists *hists = &evsel->hists;
358 struct hist_entry *he;
359 struct rb_root *root;
360 struct rb_node *node;
361
362 field_order = "dso,sym,comm,overhead,dso";
363 sort_order = "sym";
364
365 setup_sorting();
366
367 /*
368 * expected output:
369 *
370 * Shared Object Symbol Command Overhead
371 * ============= ============== ======= ========
372 * perf [.] cmd_record perf 10.00%
373 * libc [.] free perf 10.00%
374 * bash [.] main bash 10.00%
375 * perf [.] main perf 20.00%
376 * libc [.] malloc perf 10.00%
377 * [kernel] [k] page_fault bash 10.00%
378 * [kernel] [k] page_fault perf 10.00%
379 * [kernel] [k] schedule perf 10.00%
380 * bash [.] xmalloc bash 10.00%
381 */
382 err = add_hist_entries(hists, machine);
383 if (err < 0)
384 goto out;
385
386 hists__collapse_resort(hists, NULL);
387 hists__output_resort(hists);
388
389 if (verbose > 2) {
390 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
391 print_hists_out(hists);
392 }
393
394 root = &evsel->hists.entries;
395 node = rb_first(root);
396 he = rb_entry(node, struct hist_entry, rb_node);
397 TEST_ASSERT_VAL("Invalid hist entry",
398 !strcmp(DSO(he), "perf") && !strcmp(SYM(he), "cmd_record") &&
399 !strcmp(COMM(he), "perf") && he->stat.period == 100);
400
401 node = rb_next(node);
402 he = rb_entry(node, struct hist_entry, rb_node);
403 TEST_ASSERT_VAL("Invalid hist entry",
404 !strcmp(DSO(he), "libc") && !strcmp(SYM(he), "free") &&
405 !strcmp(COMM(he), "perf") && he->stat.period == 100);
406
407 node = rb_next(node);
408 he = rb_entry(node, struct hist_entry, rb_node);
409 TEST_ASSERT_VAL("Invalid hist entry",
410 !strcmp(DSO(he), "bash") && !strcmp(SYM(he), "main") &&
411 !strcmp(COMM(he), "bash") && he->stat.period == 100);
412
413 node = rb_next(node);
414 he = rb_entry(node, struct hist_entry, rb_node);
415 TEST_ASSERT_VAL("Invalid hist entry",
416 !strcmp(DSO(he), "perf") && !strcmp(SYM(he), "main") &&
417 !strcmp(COMM(he), "perf") && he->stat.period == 200);
418
419 node = rb_next(node);
420 he = rb_entry(node, struct hist_entry, rb_node);
421 TEST_ASSERT_VAL("Invalid hist entry",
422 !strcmp(DSO(he), "libc") && !strcmp(SYM(he), "malloc") &&
423 !strcmp(COMM(he), "perf") && he->stat.period == 100);
424
425 node = rb_next(node);
426 he = rb_entry(node, struct hist_entry, rb_node);
427 TEST_ASSERT_VAL("Invalid hist entry",
428 !strcmp(DSO(he), "[kernel]") && !strcmp(SYM(he), "page_fault") &&
429 !strcmp(COMM(he), "bash") && he->stat.period == 100);
430
431 node = rb_next(node);
432 he = rb_entry(node, struct hist_entry, rb_node);
433 TEST_ASSERT_VAL("Invalid hist entry",
434 !strcmp(DSO(he), "[kernel]") && !strcmp(SYM(he), "page_fault") &&
435 !strcmp(COMM(he), "perf") && he->stat.period == 100);
436
437 node = rb_next(node);
438 he = rb_entry(node, struct hist_entry, rb_node);
439 TEST_ASSERT_VAL("Invalid hist entry",
440 !strcmp(DSO(he), "[kernel]") && !strcmp(SYM(he), "schedule") &&
441 !strcmp(COMM(he), "perf") && he->stat.period == 100);
442
443 node = rb_next(node);
444 he = rb_entry(node, struct hist_entry, rb_node);
445 TEST_ASSERT_VAL("Invalid hist entry",
446 !strcmp(DSO(he), "bash") && !strcmp(SYM(he), "xmalloc") &&
447 !strcmp(COMM(he), "bash") && he->stat.period == 100);
448
449out:
450 del_hist_entries(hists);
451 reset_output_field();
452 return err;
453}
454
455/* full sort keys w/o overhead field */
456static int test5(struct perf_evsel *evsel, struct machine *machine)
457{
458 int err;
459 struct hists *hists = &evsel->hists;
460 struct hist_entry *he;
461 struct rb_root *root;
462 struct rb_node *node;
463
464 field_order = "cpu,pid,comm,dso,sym";
465 sort_order = "dso,pid";
466
467 setup_sorting();
468
469 /*
470 * expected output:
471 *
472 * CPU Command: Pid Command Shared Object Symbol
473 * === ============= ======= ============= ==============
474 * 0 perf: 100 perf [kernel] [k] schedule
475 * 2 perf: 200 perf [kernel] [k] page_fault
476 * 1 bash: 300 bash [kernel] [k] page_fault
477 * 0 bash: 300 bash bash [.] xmalloc
478 * 3 bash: 300 bash bash [.] main
479 * 1 perf: 100 perf libc [.] malloc
480 * 2 perf: 100 perf libc [.] free
481 * 1 perf: 100 perf perf [.] cmd_record
482 * 1 perf: 100 perf perf [.] main
483 * 2 perf: 200 perf perf [.] main
484 */
485 err = add_hist_entries(hists, machine);
486 if (err < 0)
487 goto out;
488
489 hists__collapse_resort(hists, NULL);
490 hists__output_resort(hists);
491
492 if (verbose > 2) {
493 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
494 print_hists_out(hists);
495 }
496
497 root = &evsel->hists.entries;
498 node = rb_first(root);
499 he = rb_entry(node, struct hist_entry, rb_node);
500
501 TEST_ASSERT_VAL("Invalid hist entry",
502 CPU(he) == 0 && PID(he) == 100 &&
503 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "[kernel]") &&
504 !strcmp(SYM(he), "schedule") && he->stat.period == 100);
505
506 node = rb_next(node);
507 he = rb_entry(node, struct hist_entry, rb_node);
508 TEST_ASSERT_VAL("Invalid hist entry",
509 CPU(he) == 2 && PID(he) == 200 &&
510 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "[kernel]") &&
511 !strcmp(SYM(he), "page_fault") && he->stat.period == 100);
512
513 node = rb_next(node);
514 he = rb_entry(node, struct hist_entry, rb_node);
515 TEST_ASSERT_VAL("Invalid hist entry",
516 CPU(he) == 1 && PID(he) == 300 &&
517 !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "[kernel]") &&
518 !strcmp(SYM(he), "page_fault") && he->stat.period == 100);
519
520 node = rb_next(node);
521 he = rb_entry(node, struct hist_entry, rb_node);
522 TEST_ASSERT_VAL("Invalid hist entry",
523 CPU(he) == 0 && PID(he) == 300 &&
524 !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "bash") &&
525 !strcmp(SYM(he), "xmalloc") && he->stat.period == 100);
526
527 node = rb_next(node);
528 he = rb_entry(node, struct hist_entry, rb_node);
529 TEST_ASSERT_VAL("Invalid hist entry",
530 CPU(he) == 3 && PID(he) == 300 &&
531 !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "bash") &&
532 !strcmp(SYM(he), "main") && he->stat.period == 100);
533
534 node = rb_next(node);
535 he = rb_entry(node, struct hist_entry, rb_node);
536 TEST_ASSERT_VAL("Invalid hist entry",
537 CPU(he) == 1 && PID(he) == 100 &&
538 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "libc") &&
539 !strcmp(SYM(he), "malloc") && he->stat.period == 100);
540
541 node = rb_next(node);
542 he = rb_entry(node, struct hist_entry, rb_node);
543 TEST_ASSERT_VAL("Invalid hist entry",
544 CPU(he) == 2 && PID(he) == 100 &&
545 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "libc") &&
546 !strcmp(SYM(he), "free") && he->stat.period == 100);
547
548 node = rb_next(node);
549 he = rb_entry(node, struct hist_entry, rb_node);
550 TEST_ASSERT_VAL("Invalid hist entry",
551 CPU(he) == 1 && PID(he) == 100 &&
552 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&
553 !strcmp(SYM(he), "cmd_record") && he->stat.period == 100);
554
555 node = rb_next(node);
556 he = rb_entry(node, struct hist_entry, rb_node);
557 TEST_ASSERT_VAL("Invalid hist entry",
558 CPU(he) == 1 && PID(he) == 100 &&
559 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&
560 !strcmp(SYM(he), "main") && he->stat.period == 100);
561
562 node = rb_next(node);
563 he = rb_entry(node, struct hist_entry, rb_node);
564 TEST_ASSERT_VAL("Invalid hist entry",
565 CPU(he) == 2 && PID(he) == 200 &&
566 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&
567 !strcmp(SYM(he), "main") && he->stat.period == 100);
568
569out:
570 del_hist_entries(hists);
571 reset_output_field();
572 return err;
573}
574
575int test__hists_output(void)
576{
577 int err = TEST_FAIL;
578 struct machines machines;
579 struct machine *machine;
580 struct perf_evsel *evsel;
581 struct perf_evlist *evlist = perf_evlist__new();
582 size_t i;
583 test_fn_t testcases[] = {
584 test1,
585 test2,
586 test3,
587 test4,
588 test5,
589 };
590
591 TEST_ASSERT_VAL("No memory", evlist);
592
593 err = parse_events(evlist, "cpu-clock");
594 if (err)
595 goto out;
596
597 machines__init(&machines);
598
599 /* setup threads/dso/map/symbols also */
600 machine = setup_fake_machine(&machines);
601 if (!machine)
602 goto out;
603
604 if (verbose > 1)
605 machine__fprintf(machine, stderr);
606
607 evsel = perf_evlist__first(evlist);
608
609 for (i = 0; i < ARRAY_SIZE(testcases); i++) {
610 err = testcases[i](evsel, machine);
611 if (err < 0)
612 break;
613 }
614
615out:
616 /* tear down everything */
617 perf_evlist__delete(evlist);
618 machines__exit(&machines);
619
620 return err;
621}
diff --git a/tools/perf/tests/keep-tracking.c b/tools/perf/tests/keep-tracking.c
index 497957f269d8..7a5ab7b0b8f6 100644
--- a/tools/perf/tests/keep-tracking.c
+++ b/tools/perf/tests/keep-tracking.c
@@ -1,4 +1,4 @@
1#include <sys/types.h> 1#include <linux/types.h>
2#include <unistd.h> 2#include <unistd.h>
3#include <sys/prctl.h> 3#include <sys/prctl.h>
4 4
diff --git a/tools/perf/tests/make b/tools/perf/tests/make
index 2f92d6e7ee00..69a71ff84e01 100644
--- a/tools/perf/tests/make
+++ b/tools/perf/tests/make
@@ -205,8 +205,7 @@ $(run):
205 ( eval $$cmd ) >> $@ 2>&1; \ 205 ( eval $$cmd ) >> $@ 2>&1; \
206 echo " test: $(call test,$@)" >> $@ 2>&1; \ 206 echo " test: $(call test,$@)" >> $@ 2>&1; \
207 $(call test,$@) && \ 207 $(call test,$@) && \
208 rm -f $@ \ 208 rm -rf $@ $$TMP_DEST || (cat $@ ; false)
209 rm -rf $$TMP_DEST
210 209
211$(run_O): 210$(run_O):
212 $(call clean) 211 $(call clean)
@@ -217,9 +216,7 @@ $(run_O):
217 ( eval $$cmd ) >> $@ 2>&1 && \ 216 ( eval $$cmd ) >> $@ 2>&1 && \
218 echo " test: $(call test_O,$@)" >> $@ 2>&1; \ 217 echo " test: $(call test_O,$@)" >> $@ 2>&1; \
219 $(call test_O,$@) && \ 218 $(call test_O,$@) && \
220 rm -f $@ && \ 219 rm -rf $@ $$TMP_O $$TMP_DEST || (cat $@ ; false)
221 rm -rf $$TMP_O \
222 rm -rf $$TMP_DEST
223 220
224tarpkg: 221tarpkg:
225 @cmd="$(PERF)/tests/perf-targz-src-pkg $(PERF)"; \ 222 @cmd="$(PERF)/tests/perf-targz-src-pkg $(PERF)"; \
diff --git a/tools/perf/tests/mmap-thread-lookup.c b/tools/perf/tests/mmap-thread-lookup.c
new file mode 100644
index 000000000000..4a456fef66ca
--- /dev/null
+++ b/tools/perf/tests/mmap-thread-lookup.c
@@ -0,0 +1,233 @@
1#include <unistd.h>
2#include <sys/syscall.h>
3#include <sys/types.h>
4#include <sys/mman.h>
5#include <pthread.h>
6#include <stdlib.h>
7#include <stdio.h>
8#include "debug.h"
9#include "tests.h"
10#include "machine.h"
11#include "thread_map.h"
12#include "symbol.h"
13#include "thread.h"
14
15#define THREADS 4
16
17static int go_away;
18
19struct thread_data {
20 pthread_t pt;
21 pid_t tid;
22 void *map;
23 int ready[2];
24};
25
26static struct thread_data threads[THREADS];
27
28static int thread_init(struct thread_data *td)
29{
30 void *map;
31
32 map = mmap(NULL, page_size,
33 PROT_READ|PROT_WRITE|PROT_EXEC,
34 MAP_SHARED|MAP_ANONYMOUS, -1, 0);
35
36 if (map == MAP_FAILED) {
37 perror("mmap failed");
38 return -1;
39 }
40
41 td->map = map;
42 td->tid = syscall(SYS_gettid);
43
44 pr_debug("tid = %d, map = %p\n", td->tid, map);
45 return 0;
46}
47
48static void *thread_fn(void *arg)
49{
50 struct thread_data *td = arg;
51 ssize_t ret;
52 int go;
53
54 if (thread_init(td))
55 return NULL;
56
57 /* Signal thread_create thread is initialized. */
58 ret = write(td->ready[1], &go, sizeof(int));
59 if (ret != sizeof(int)) {
60 pr_err("failed to notify\n");
61 return NULL;
62 }
63
64 while (!go_away) {
65 /* Waiting for main thread to kill us. */
66 usleep(100);
67 }
68
69 munmap(td->map, page_size);
70 return NULL;
71}
72
73static int thread_create(int i)
74{
75 struct thread_data *td = &threads[i];
76 int err, go;
77
78 if (pipe(td->ready))
79 return -1;
80
81 err = pthread_create(&td->pt, NULL, thread_fn, td);
82 if (!err) {
83 /* Wait for thread initialization. */
84 ssize_t ret = read(td->ready[0], &go, sizeof(int));
85 err = ret != sizeof(int);
86 }
87
88 close(td->ready[0]);
89 close(td->ready[1]);
90 return err;
91}
92
93static int threads_create(void)
94{
95 struct thread_data *td0 = &threads[0];
96 int i, err = 0;
97
98 go_away = 0;
99
100 /* 0 is main thread */
101 if (thread_init(td0))
102 return -1;
103
104 for (i = 1; !err && i < THREADS; i++)
105 err = thread_create(i);
106
107 return err;
108}
109
110static int threads_destroy(void)
111{
112 struct thread_data *td0 = &threads[0];
113 int i, err = 0;
114
115 /* cleanup the main thread */
116 munmap(td0->map, page_size);
117
118 go_away = 1;
119
120 for (i = 1; !err && i < THREADS; i++)
121 err = pthread_join(threads[i].pt, NULL);
122
123 return err;
124}
125
126typedef int (*synth_cb)(struct machine *machine);
127
128static int synth_all(struct machine *machine)
129{
130 return perf_event__synthesize_threads(NULL,
131 perf_event__process,
132 machine, 0);
133}
134
135static int synth_process(struct machine *machine)
136{
137 struct thread_map *map;
138 int err;
139
140 map = thread_map__new_by_pid(getpid());
141
142 err = perf_event__synthesize_thread_map(NULL, map,
143 perf_event__process,
144 machine, 0);
145
146 thread_map__delete(map);
147 return err;
148}
149
150static int mmap_events(synth_cb synth)
151{
152 struct machines machines;
153 struct machine *machine;
154 int err, i;
155
156 /*
157 * The threads_create will not return before all threads
158 * are spawned and all created memory map.
159 *
160 * They will loop until threads_destroy is called, so we
161 * can safely run synthesizing function.
162 */
163 TEST_ASSERT_VAL("failed to create threads", !threads_create());
164
165 machines__init(&machines);
166 machine = &machines.host;
167
168 dump_trace = verbose > 1 ? 1 : 0;
169
170 err = synth(machine);
171
172 dump_trace = 0;
173
174 TEST_ASSERT_VAL("failed to destroy threads", !threads_destroy());
175 TEST_ASSERT_VAL("failed to synthesize maps", !err);
176
177 /*
178 * All data is synthesized, try to find map for each
179 * thread object.
180 */
181 for (i = 0; i < THREADS; i++) {
182 struct thread_data *td = &threads[i];
183 struct addr_location al;
184 struct thread *thread;
185
186 thread = machine__findnew_thread(machine, getpid(), td->tid);
187
188 pr_debug("looking for map %p\n", td->map);
189
190 thread__find_addr_map(thread, machine,
191 PERF_RECORD_MISC_USER, MAP__FUNCTION,
192 (unsigned long) (td->map + 1), &al);
193
194 if (!al.map) {
195 pr_debug("failed, couldn't find map\n");
196 err = -1;
197 break;
198 }
199
200 pr_debug("map %p, addr %" PRIx64 "\n", al.map, al.map->start);
201 }
202
203 machine__delete_threads(machine);
204 machines__exit(&machines);
205 return err;
206}
207
208/*
209 * This test creates 'THREADS' number of threads (including
210 * main thread) and each thread creates memory map.
211 *
212 * When threads are created, we synthesize them with both
213 * (separate tests):
214 * perf_event__synthesize_thread_map (process based)
215 * perf_event__synthesize_threads (global)
216 *
217 * We test we can find all memory maps via:
218 * thread__find_addr_map
219 *
220 * by using all thread objects.
221 */
222int test__mmap_thread_lookup(void)
223{
224 /* perf_event__synthesize_threads synthesize */
225 TEST_ASSERT_VAL("failed with sythesizing all",
226 !mmap_events(synth_all));
227
228 /* perf_event__synthesize_thread_map synthesize */
229 TEST_ASSERT_VAL("failed with sythesizing process",
230 !mmap_events(synth_process));
231
232 return 0;
233}
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
index 8605ff5572ae..deba66955f8c 100644
--- a/tools/perf/tests/parse-events.c
+++ b/tools/perf/tests/parse-events.c
@@ -1174,188 +1174,240 @@ static int test__all_tracepoints(struct perf_evlist *evlist)
1174struct evlist_test { 1174struct evlist_test {
1175 const char *name; 1175 const char *name;
1176 __u32 type; 1176 __u32 type;
1177 const int id;
1177 int (*check)(struct perf_evlist *evlist); 1178 int (*check)(struct perf_evlist *evlist);
1178}; 1179};
1179 1180
1180static struct evlist_test test__events[] = { 1181static struct evlist_test test__events[] = {
1181 [0] = { 1182 {
1182 .name = "syscalls:sys_enter_open", 1183 .name = "syscalls:sys_enter_open",
1183 .check = test__checkevent_tracepoint, 1184 .check = test__checkevent_tracepoint,
1185 .id = 0,
1184 }, 1186 },
1185 [1] = { 1187 {
1186 .name = "syscalls:*", 1188 .name = "syscalls:*",
1187 .check = test__checkevent_tracepoint_multi, 1189 .check = test__checkevent_tracepoint_multi,
1190 .id = 1,
1188 }, 1191 },
1189 [2] = { 1192 {
1190 .name = "r1a", 1193 .name = "r1a",
1191 .check = test__checkevent_raw, 1194 .check = test__checkevent_raw,
1195 .id = 2,
1192 }, 1196 },
1193 [3] = { 1197 {
1194 .name = "1:1", 1198 .name = "1:1",
1195 .check = test__checkevent_numeric, 1199 .check = test__checkevent_numeric,
1200 .id = 3,
1196 }, 1201 },
1197 [4] = { 1202 {
1198 .name = "instructions", 1203 .name = "instructions",
1199 .check = test__checkevent_symbolic_name, 1204 .check = test__checkevent_symbolic_name,
1205 .id = 4,
1200 }, 1206 },
1201 [5] = { 1207 {
1202 .name = "cycles/period=100000,config2/", 1208 .name = "cycles/period=100000,config2/",
1203 .check = test__checkevent_symbolic_name_config, 1209 .check = test__checkevent_symbolic_name_config,
1210 .id = 5,
1204 }, 1211 },
1205 [6] = { 1212 {
1206 .name = "faults", 1213 .name = "faults",
1207 .check = test__checkevent_symbolic_alias, 1214 .check = test__checkevent_symbolic_alias,
1215 .id = 6,
1208 }, 1216 },
1209 [7] = { 1217 {
1210 .name = "L1-dcache-load-miss", 1218 .name = "L1-dcache-load-miss",
1211 .check = test__checkevent_genhw, 1219 .check = test__checkevent_genhw,
1220 .id = 7,
1212 }, 1221 },
1213 [8] = { 1222 {
1214 .name = "mem:0", 1223 .name = "mem:0",
1215 .check = test__checkevent_breakpoint, 1224 .check = test__checkevent_breakpoint,
1225 .id = 8,
1216 }, 1226 },
1217 [9] = { 1227 {
1218 .name = "mem:0:x", 1228 .name = "mem:0:x",
1219 .check = test__checkevent_breakpoint_x, 1229 .check = test__checkevent_breakpoint_x,
1230 .id = 9,
1220 }, 1231 },
1221 [10] = { 1232 {
1222 .name = "mem:0:r", 1233 .name = "mem:0:r",
1223 .check = test__checkevent_breakpoint_r, 1234 .check = test__checkevent_breakpoint_r,
1235 .id = 10,
1224 }, 1236 },
1225 [11] = { 1237 {
1226 .name = "mem:0:w", 1238 .name = "mem:0:w",
1227 .check = test__checkevent_breakpoint_w, 1239 .check = test__checkevent_breakpoint_w,
1240 .id = 11,
1228 }, 1241 },
1229 [12] = { 1242 {
1230 .name = "syscalls:sys_enter_open:k", 1243 .name = "syscalls:sys_enter_open:k",
1231 .check = test__checkevent_tracepoint_modifier, 1244 .check = test__checkevent_tracepoint_modifier,
1245 .id = 12,
1232 }, 1246 },
1233 [13] = { 1247 {
1234 .name = "syscalls:*:u", 1248 .name = "syscalls:*:u",
1235 .check = test__checkevent_tracepoint_multi_modifier, 1249 .check = test__checkevent_tracepoint_multi_modifier,
1250 .id = 13,
1236 }, 1251 },
1237 [14] = { 1252 {
1238 .name = "r1a:kp", 1253 .name = "r1a:kp",
1239 .check = test__checkevent_raw_modifier, 1254 .check = test__checkevent_raw_modifier,
1255 .id = 14,
1240 }, 1256 },
1241 [15] = { 1257 {
1242 .name = "1:1:hp", 1258 .name = "1:1:hp",
1243 .check = test__checkevent_numeric_modifier, 1259 .check = test__checkevent_numeric_modifier,
1260 .id = 15,
1244 }, 1261 },
1245 [16] = { 1262 {
1246 .name = "instructions:h", 1263 .name = "instructions:h",
1247 .check = test__checkevent_symbolic_name_modifier, 1264 .check = test__checkevent_symbolic_name_modifier,
1265 .id = 16,
1248 }, 1266 },
1249 [17] = { 1267 {
1250 .name = "faults:u", 1268 .name = "faults:u",
1251 .check = test__checkevent_symbolic_alias_modifier, 1269 .check = test__checkevent_symbolic_alias_modifier,
1270 .id = 17,
1252 }, 1271 },
1253 [18] = { 1272 {
1254 .name = "L1-dcache-load-miss:kp", 1273 .name = "L1-dcache-load-miss:kp",
1255 .check = test__checkevent_genhw_modifier, 1274 .check = test__checkevent_genhw_modifier,
1275 .id = 18,
1256 }, 1276 },
1257 [19] = { 1277 {
1258 .name = "mem:0:u", 1278 .name = "mem:0:u",
1259 .check = test__checkevent_breakpoint_modifier, 1279 .check = test__checkevent_breakpoint_modifier,
1280 .id = 19,
1260 }, 1281 },
1261 [20] = { 1282 {
1262 .name = "mem:0:x:k", 1283 .name = "mem:0:x:k",
1263 .check = test__checkevent_breakpoint_x_modifier, 1284 .check = test__checkevent_breakpoint_x_modifier,
1285 .id = 20,
1264 }, 1286 },
1265 [21] = { 1287 {
1266 .name = "mem:0:r:hp", 1288 .name = "mem:0:r:hp",
1267 .check = test__checkevent_breakpoint_r_modifier, 1289 .check = test__checkevent_breakpoint_r_modifier,
1290 .id = 21,
1268 }, 1291 },
1269 [22] = { 1292 {
1270 .name = "mem:0:w:up", 1293 .name = "mem:0:w:up",
1271 .check = test__checkevent_breakpoint_w_modifier, 1294 .check = test__checkevent_breakpoint_w_modifier,
1295 .id = 22,
1272 }, 1296 },
1273 [23] = { 1297 {
1274 .name = "r1,syscalls:sys_enter_open:k,1:1:hp", 1298 .name = "r1,syscalls:sys_enter_open:k,1:1:hp",
1275 .check = test__checkevent_list, 1299 .check = test__checkevent_list,
1300 .id = 23,
1276 }, 1301 },
1277 [24] = { 1302 {
1278 .name = "instructions:G", 1303 .name = "instructions:G",
1279 .check = test__checkevent_exclude_host_modifier, 1304 .check = test__checkevent_exclude_host_modifier,
1305 .id = 24,
1280 }, 1306 },
1281 [25] = { 1307 {
1282 .name = "instructions:H", 1308 .name = "instructions:H",
1283 .check = test__checkevent_exclude_guest_modifier, 1309 .check = test__checkevent_exclude_guest_modifier,
1310 .id = 25,
1284 }, 1311 },
1285 [26] = { 1312 {
1286 .name = "mem:0:rw", 1313 .name = "mem:0:rw",
1287 .check = test__checkevent_breakpoint_rw, 1314 .check = test__checkevent_breakpoint_rw,
1315 .id = 26,
1288 }, 1316 },
1289 [27] = { 1317 {
1290 .name = "mem:0:rw:kp", 1318 .name = "mem:0:rw:kp",
1291 .check = test__checkevent_breakpoint_rw_modifier, 1319 .check = test__checkevent_breakpoint_rw_modifier,
1320 .id = 27,
1292 }, 1321 },
1293 [28] = { 1322 {
1294 .name = "{instructions:k,cycles:upp}", 1323 .name = "{instructions:k,cycles:upp}",
1295 .check = test__group1, 1324 .check = test__group1,
1325 .id = 28,
1296 }, 1326 },
1297 [29] = { 1327 {
1298 .name = "{faults:k,cache-references}:u,cycles:k", 1328 .name = "{faults:k,cache-references}:u,cycles:k",
1299 .check = test__group2, 1329 .check = test__group2,
1330 .id = 29,
1300 }, 1331 },
1301 [30] = { 1332 {
1302 .name = "group1{syscalls:sys_enter_open:H,cycles:kppp},group2{cycles,1:3}:G,instructions:u", 1333 .name = "group1{syscalls:sys_enter_open:H,cycles:kppp},group2{cycles,1:3}:G,instructions:u",
1303 .check = test__group3, 1334 .check = test__group3,
1335 .id = 30,
1304 }, 1336 },
1305 [31] = { 1337 {
1306 .name = "{cycles:u,instructions:kp}:p", 1338 .name = "{cycles:u,instructions:kp}:p",
1307 .check = test__group4, 1339 .check = test__group4,
1340 .id = 31,
1308 }, 1341 },
1309 [32] = { 1342 {
1310 .name = "{cycles,instructions}:G,{cycles:G,instructions:G},cycles", 1343 .name = "{cycles,instructions}:G,{cycles:G,instructions:G},cycles",
1311 .check = test__group5, 1344 .check = test__group5,
1345 .id = 32,
1312 }, 1346 },
1313 [33] = { 1347 {
1314 .name = "*:*", 1348 .name = "*:*",
1315 .check = test__all_tracepoints, 1349 .check = test__all_tracepoints,
1350 .id = 33,
1316 }, 1351 },
1317 [34] = { 1352 {
1318 .name = "{cycles,cache-misses:G}:H", 1353 .name = "{cycles,cache-misses:G}:H",
1319 .check = test__group_gh1, 1354 .check = test__group_gh1,
1355 .id = 34,
1320 }, 1356 },
1321 [35] = { 1357 {
1322 .name = "{cycles,cache-misses:H}:G", 1358 .name = "{cycles,cache-misses:H}:G",
1323 .check = test__group_gh2, 1359 .check = test__group_gh2,
1360 .id = 35,
1324 }, 1361 },
1325 [36] = { 1362 {
1326 .name = "{cycles:G,cache-misses:H}:u", 1363 .name = "{cycles:G,cache-misses:H}:u",
1327 .check = test__group_gh3, 1364 .check = test__group_gh3,
1365 .id = 36,
1328 }, 1366 },
1329 [37] = { 1367 {
1330 .name = "{cycles:G,cache-misses:H}:uG", 1368 .name = "{cycles:G,cache-misses:H}:uG",
1331 .check = test__group_gh4, 1369 .check = test__group_gh4,
1370 .id = 37,
1332 }, 1371 },
1333 [38] = { 1372 {
1334 .name = "{cycles,cache-misses,branch-misses}:S", 1373 .name = "{cycles,cache-misses,branch-misses}:S",
1335 .check = test__leader_sample1, 1374 .check = test__leader_sample1,
1375 .id = 38,
1336 }, 1376 },
1337 [39] = { 1377 {
1338 .name = "{instructions,branch-misses}:Su", 1378 .name = "{instructions,branch-misses}:Su",
1339 .check = test__leader_sample2, 1379 .check = test__leader_sample2,
1380 .id = 39,
1340 }, 1381 },
1341 [40] = { 1382 {
1342 .name = "instructions:uDp", 1383 .name = "instructions:uDp",
1343 .check = test__checkevent_pinned_modifier, 1384 .check = test__checkevent_pinned_modifier,
1385 .id = 40,
1344 }, 1386 },
1345 [41] = { 1387 {
1346 .name = "{cycles,cache-misses,branch-misses}:D", 1388 .name = "{cycles,cache-misses,branch-misses}:D",
1347 .check = test__pinned_group, 1389 .check = test__pinned_group,
1390 .id = 41,
1391 },
1392#if defined(__s390x__)
1393 {
1394 .name = "kvm-s390:kvm_s390_create_vm",
1395 .check = test__checkevent_tracepoint,
1396 .id = 100,
1348 }, 1397 },
1398#endif
1349}; 1399};
1350 1400
1351static struct evlist_test test__events_pmu[] = { 1401static struct evlist_test test__events_pmu[] = {
1352 [0] = { 1402 {
1353 .name = "cpu/config=10,config1,config2=3,period=1000/u", 1403 .name = "cpu/config=10,config1,config2=3,period=1000/u",
1354 .check = test__checkevent_pmu, 1404 .check = test__checkevent_pmu,
1405 .id = 0,
1355 }, 1406 },
1356 [1] = { 1407 {
1357 .name = "cpu/config=1,name=krava/u,cpu/config=2/u", 1408 .name = "cpu/config=1,name=krava/u,cpu/config=2/u",
1358 .check = test__checkevent_pmu_name, 1409 .check = test__checkevent_pmu_name,
1410 .id = 1,
1359 }, 1411 },
1360}; 1412};
1361 1413
@@ -1402,7 +1454,7 @@ static int test_events(struct evlist_test *events, unsigned cnt)
1402 for (i = 0; i < cnt; i++) { 1454 for (i = 0; i < cnt; i++) {
1403 struct evlist_test *e = &events[i]; 1455 struct evlist_test *e = &events[i];
1404 1456
1405 pr_debug("running test %d '%s'\n", i, e->name); 1457 pr_debug("running test %d '%s'\n", e->id, e->name);
1406 ret1 = test_event(e); 1458 ret1 = test_event(e);
1407 if (ret1) 1459 if (ret1)
1408 ret2 = ret1; 1460 ret2 = ret1;
diff --git a/tools/perf/tests/parse-no-sample-id-all.c b/tools/perf/tests/parse-no-sample-id-all.c
index e117b6c6a248..905019f9b740 100644
--- a/tools/perf/tests/parse-no-sample-id-all.c
+++ b/tools/perf/tests/parse-no-sample-id-all.c
@@ -1,4 +1,4 @@
1#include <sys/types.h> 1#include <linux/types.h>
2#include <stddef.h> 2#include <stddef.h>
3 3
4#include "tests.h" 4#include "tests.h"
diff --git a/tools/perf/tests/perf-time-to-tsc.c b/tools/perf/tests/perf-time-to-tsc.c
index 47146d388dbf..3b7cd4d32dcb 100644
--- a/tools/perf/tests/perf-time-to-tsc.c
+++ b/tools/perf/tests/perf-time-to-tsc.c
@@ -1,7 +1,6 @@
1#include <stdio.h> 1#include <stdio.h>
2#include <sys/types.h>
3#include <unistd.h> 2#include <unistd.h>
4#include <inttypes.h> 3#include <linux/types.h>
5#include <sys/prctl.h> 4#include <sys/prctl.h>
6 5
7#include "parse-events.h" 6#include "parse-events.h"
diff --git a/tools/perf/tests/rdpmc.c b/tools/perf/tests/rdpmc.c
index 46649c25fa5e..e59143fd9e71 100644
--- a/tools/perf/tests/rdpmc.c
+++ b/tools/perf/tests/rdpmc.c
@@ -2,7 +2,7 @@
2#include <stdlib.h> 2#include <stdlib.h>
3#include <signal.h> 3#include <signal.h>
4#include <sys/mman.h> 4#include <sys/mman.h>
5#include "types.h" 5#include <linux/types.h>
6#include "perf.h" 6#include "perf.h"
7#include "debug.h" 7#include "debug.h"
8#include "tests.h" 8#include "tests.h"
diff --git a/tools/perf/tests/sample-parsing.c b/tools/perf/tests/sample-parsing.c
index 0014d3c8c21c..7ae8d17db3d9 100644
--- a/tools/perf/tests/sample-parsing.c
+++ b/tools/perf/tests/sample-parsing.c
@@ -1,5 +1,5 @@
1#include <stdbool.h> 1#include <stdbool.h>
2#include <inttypes.h> 2#include <linux/types.h>
3 3
4#include "util.h" 4#include "util.h"
5#include "event.h" 5#include "event.h"
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index a24795ca002d..ed64790a395f 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -28,6 +28,8 @@ int test__syscall_open_tp_fields(void);
28int test__pmu(void); 28int test__pmu(void);
29int test__attr(void); 29int test__attr(void);
30int test__dso_data(void); 30int test__dso_data(void);
31int test__dso_data_cache(void);
32int test__dso_data_reopen(void);
31int test__parse_events(void); 33int test__parse_events(void);
32int test__hists_link(void); 34int test__hists_link(void);
33int test__python_use(void); 35int test__python_use(void);
@@ -41,8 +43,13 @@ int test__sample_parsing(void);
41int test__keep_tracking(void); 43int test__keep_tracking(void);
42int test__parse_no_sample_id_all(void); 44int test__parse_no_sample_id_all(void);
43int test__dwarf_unwind(void); 45int test__dwarf_unwind(void);
46int test__hists_filter(void);
47int test__mmap_thread_lookup(void);
48int test__thread_mg_share(void);
49int test__hists_output(void);
50int test__hists_cumulate(void);
44 51
45#if defined(__x86_64__) || defined(__i386__) 52#if defined(__x86_64__) || defined(__i386__) || defined(__arm__)
46#ifdef HAVE_DWARF_UNWIND_SUPPORT 53#ifdef HAVE_DWARF_UNWIND_SUPPORT
47struct thread; 54struct thread;
48struct perf_sample; 55struct perf_sample;
diff --git a/tools/perf/tests/thread-mg-share.c b/tools/perf/tests/thread-mg-share.c
new file mode 100644
index 000000000000..2b2e0dbe114f
--- /dev/null
+++ b/tools/perf/tests/thread-mg-share.c
@@ -0,0 +1,90 @@
1#include "tests.h"
2#include "machine.h"
3#include "thread.h"
4#include "map.h"
5
6int test__thread_mg_share(void)
7{
8 struct machines machines;
9 struct machine *machine;
10
11 /* thread group */
12 struct thread *leader;
13 struct thread *t1, *t2, *t3;
14 struct map_groups *mg;
15
16 /* other process */
17 struct thread *other, *other_leader;
18 struct map_groups *other_mg;
19
20 /*
21 * This test create 2 processes abstractions (struct thread)
22 * with several threads and checks they properly share and
23 * maintain map groups info (struct map_groups).
24 *
25 * thread group (pid: 0, tids: 0, 1, 2, 3)
26 * other group (pid: 4, tids: 4, 5)
27 */
28
29 machines__init(&machines);
30 machine = &machines.host;
31
32 /* create process with 4 threads */
33 leader = machine__findnew_thread(machine, 0, 0);
34 t1 = machine__findnew_thread(machine, 0, 1);
35 t2 = machine__findnew_thread(machine, 0, 2);
36 t3 = machine__findnew_thread(machine, 0, 3);
37
38 /* and create 1 separated process, without thread leader */
39 other = machine__findnew_thread(machine, 4, 5);
40
41 TEST_ASSERT_VAL("failed to create threads",
42 leader && t1 && t2 && t3 && other);
43
44 mg = leader->mg;
45 TEST_ASSERT_VAL("wrong refcnt", mg->refcnt == 4);
46
47 /* test the map groups pointer is shared */
48 TEST_ASSERT_VAL("map groups don't match", mg == t1->mg);
49 TEST_ASSERT_VAL("map groups don't match", mg == t2->mg);
50 TEST_ASSERT_VAL("map groups don't match", mg == t3->mg);
51
52 /*
53 * Verify the other leader was created by previous call.
54 * It should have shared map groups with no change in
55 * refcnt.
56 */
57 other_leader = machine__find_thread(machine, 4, 4);
58 TEST_ASSERT_VAL("failed to find other leader", other_leader);
59
60 other_mg = other->mg;
61 TEST_ASSERT_VAL("wrong refcnt", other_mg->refcnt == 2);
62
63 TEST_ASSERT_VAL("map groups don't match", other_mg == other_leader->mg);
64
65 /* release thread group */
66 thread__delete(leader);
67 TEST_ASSERT_VAL("wrong refcnt", mg->refcnt == 3);
68
69 thread__delete(t1);
70 TEST_ASSERT_VAL("wrong refcnt", mg->refcnt == 2);
71
72 thread__delete(t2);
73 TEST_ASSERT_VAL("wrong refcnt", mg->refcnt == 1);
74
75 thread__delete(t3);
76
77 /* release other group */
78 thread__delete(other_leader);
79 TEST_ASSERT_VAL("wrong refcnt", other_mg->refcnt == 1);
80
81 thread__delete(other);
82
83 /*
84 * Cannot call machine__delete_threads(machine) now,
85 * because we've already released all the threads.
86 */
87
88 machines__exit(&machines);
89 return 0;
90}
diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c
index d11541d4d7d7..3ccf6e14f89b 100644
--- a/tools/perf/ui/browser.c
+++ b/tools/perf/ui/browser.c
@@ -194,7 +194,7 @@ int ui_browser__warning(struct ui_browser *browser, int timeout,
194 ui_helpline__vpush(format, args); 194 ui_helpline__vpush(format, args);
195 va_end(args); 195 va_end(args);
196 } else { 196 } else {
197 while ((key == ui__question_window("Warning!", text, 197 while ((key = ui__question_window("Warning!", text,
198 "Press any key...", 198 "Press any key...",
199 timeout)) == K_RESIZE) 199 timeout)) == K_RESIZE)
200 ui_browser__handle_resize(browser); 200 ui_browser__handle_resize(browser);
diff --git a/tools/perf/ui/browser.h b/tools/perf/ui/browser.h
index 118cca29dd26..03d4d6295f10 100644
--- a/tools/perf/ui/browser.h
+++ b/tools/perf/ui/browser.h
@@ -1,9 +1,7 @@
1#ifndef _PERF_UI_BROWSER_H_ 1#ifndef _PERF_UI_BROWSER_H_
2#define _PERF_UI_BROWSER_H_ 1 2#define _PERF_UI_BROWSER_H_ 1
3 3
4#include <stdbool.h> 4#include <linux/types.h>
5#include <sys/types.h>
6#include "../types.h"
7 5
8#define HE_COLORSET_TOP 50 6#define HE_COLORSET_TOP 50
9#define HE_COLORSET_MEDIUM 51 7#define HE_COLORSET_MEDIUM 51
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index 7ec871af3f6f..52c03fbbba17 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -26,13 +26,35 @@ struct hist_browser {
26 int print_seq; 26 int print_seq;
27 bool show_dso; 27 bool show_dso;
28 float min_pcnt; 28 float min_pcnt;
29 u64 nr_pcnt_entries; 29 u64 nr_non_filtered_entries;
30 u64 nr_callchain_rows;
30}; 31};
31 32
32extern void hist_browser__init_hpp(void); 33extern void hist_browser__init_hpp(void);
33 34
34static int hists__browser_title(struct hists *hists, char *bf, size_t size, 35static int hists__browser_title(struct hists *hists, char *bf, size_t size,
35 const char *ev_name); 36 const char *ev_name);
37static void hist_browser__update_nr_entries(struct hist_browser *hb);
38
39static struct rb_node *hists__filter_entries(struct rb_node *nd,
40 float min_pcnt);
41
42static bool hist_browser__has_filter(struct hist_browser *hb)
43{
44 return hists__has_filter(hb->hists) || hb->min_pcnt;
45}
46
47static u32 hist_browser__nr_entries(struct hist_browser *hb)
48{
49 u32 nr_entries;
50
51 if (hist_browser__has_filter(hb))
52 nr_entries = hb->nr_non_filtered_entries;
53 else
54 nr_entries = hb->hists->nr_entries;
55
56 return nr_entries + hb->nr_callchain_rows;
57}
36 58
37static void hist_browser__refresh_dimensions(struct hist_browser *browser) 59static void hist_browser__refresh_dimensions(struct hist_browser *browser)
38{ 60{
@@ -43,7 +65,14 @@ static void hist_browser__refresh_dimensions(struct hist_browser *browser)
43 65
44static void hist_browser__reset(struct hist_browser *browser) 66static void hist_browser__reset(struct hist_browser *browser)
45{ 67{
46 browser->b.nr_entries = browser->hists->nr_entries; 68 /*
69 * The hists__remove_entry_filter() already folds non-filtered
70 * entries so we can assume it has 0 callchain rows.
71 */
72 browser->nr_callchain_rows = 0;
73
74 hist_browser__update_nr_entries(browser);
75 browser->b.nr_entries = hist_browser__nr_entries(browser);
47 hist_browser__refresh_dimensions(browser); 76 hist_browser__refresh_dimensions(browser);
48 ui_browser__reset_index(&browser->b); 77 ui_browser__reset_index(&browser->b);
49} 78}
@@ -198,14 +227,16 @@ static bool hist_browser__toggle_fold(struct hist_browser *browser)
198 struct hist_entry *he = browser->he_selection; 227 struct hist_entry *he = browser->he_selection;
199 228
200 hist_entry__init_have_children(he); 229 hist_entry__init_have_children(he);
201 browser->hists->nr_entries -= he->nr_rows; 230 browser->b.nr_entries -= he->nr_rows;
231 browser->nr_callchain_rows -= he->nr_rows;
202 232
203 if (he->ms.unfolded) 233 if (he->ms.unfolded)
204 he->nr_rows = callchain__count_rows(&he->sorted_chain); 234 he->nr_rows = callchain__count_rows(&he->sorted_chain);
205 else 235 else
206 he->nr_rows = 0; 236 he->nr_rows = 0;
207 browser->hists->nr_entries += he->nr_rows; 237
208 browser->b.nr_entries = browser->hists->nr_entries; 238 browser->b.nr_entries += he->nr_rows;
239 browser->nr_callchain_rows += he->nr_rows;
209 240
210 return true; 241 return true;
211 } 242 }
@@ -280,23 +311,27 @@ static void hist_entry__set_folding(struct hist_entry *he, bool unfold)
280 he->nr_rows = 0; 311 he->nr_rows = 0;
281} 312}
282 313
283static void hists__set_folding(struct hists *hists, bool unfold) 314static void
315__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
284{ 316{
285 struct rb_node *nd; 317 struct rb_node *nd;
318 struct hists *hists = browser->hists;
286 319
287 hists->nr_entries = 0; 320 for (nd = rb_first(&hists->entries);
288 321 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
289 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 322 nd = rb_next(nd)) {
290 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); 323 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
291 hist_entry__set_folding(he, unfold); 324 hist_entry__set_folding(he, unfold);
292 hists->nr_entries += 1 + he->nr_rows; 325 browser->nr_callchain_rows += he->nr_rows;
293 } 326 }
294} 327}
295 328
296static void hist_browser__set_folding(struct hist_browser *browser, bool unfold) 329static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
297{ 330{
298 hists__set_folding(browser->hists, unfold); 331 browser->nr_callchain_rows = 0;
299 browser->b.nr_entries = browser->hists->nr_entries; 332 __hist_browser__set_folding(browser, unfold);
333
334 browser->b.nr_entries = hist_browser__nr_entries(browser);
300 /* Go to the start, we may be way after valid entries after a collapse */ 335 /* Go to the start, we may be way after valid entries after a collapse */
301 ui_browser__reset_index(&browser->b); 336 ui_browser__reset_index(&browser->b);
302} 337}
@@ -310,8 +345,6 @@ static void ui_browser__warn_lost_events(struct ui_browser *browser)
310 "Or reduce the sampling frequency."); 345 "Or reduce the sampling frequency.");
311} 346}
312 347
313static void hist_browser__update_pcnt_entries(struct hist_browser *hb);
314
315static int hist_browser__run(struct hist_browser *browser, const char *ev_name, 348static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
316 struct hist_browser_timer *hbt) 349 struct hist_browser_timer *hbt)
317{ 350{
@@ -320,9 +353,7 @@ static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
320 int delay_secs = hbt ? hbt->refresh : 0; 353 int delay_secs = hbt ? hbt->refresh : 0;
321 354
322 browser->b.entries = &browser->hists->entries; 355 browser->b.entries = &browser->hists->entries;
323 browser->b.nr_entries = browser->hists->nr_entries; 356 browser->b.nr_entries = hist_browser__nr_entries(browser);
324 if (browser->min_pcnt)
325 browser->b.nr_entries = browser->nr_pcnt_entries;
326 357
327 hist_browser__refresh_dimensions(browser); 358 hist_browser__refresh_dimensions(browser);
328 hists__browser_title(browser->hists, title, sizeof(title), ev_name); 359 hists__browser_title(browser->hists, title, sizeof(title), ev_name);
@@ -339,13 +370,10 @@ static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
339 u64 nr_entries; 370 u64 nr_entries;
340 hbt->timer(hbt->arg); 371 hbt->timer(hbt->arg);
341 372
342 if (browser->min_pcnt) { 373 if (hist_browser__has_filter(browser))
343 hist_browser__update_pcnt_entries(browser); 374 hist_browser__update_nr_entries(browser);
344 nr_entries = browser->nr_pcnt_entries;
345 } else {
346 nr_entries = browser->hists->nr_entries;
347 }
348 375
376 nr_entries = hist_browser__nr_entries(browser);
349 ui_browser__update_nr_entries(&browser->b, nr_entries); 377 ui_browser__update_nr_entries(&browser->b, nr_entries);
350 378
351 if (browser->hists->stats.nr_lost_warned != 379 if (browser->hists->stats.nr_lost_warned !=
@@ -587,35 +615,6 @@ struct hpp_arg {
587 bool current_entry; 615 bool current_entry;
588}; 616};
589 617
590static int __hpp__overhead_callback(struct perf_hpp *hpp, bool front)
591{
592 struct hpp_arg *arg = hpp->ptr;
593
594 if (arg->current_entry && arg->b->navkeypressed)
595 ui_browser__set_color(arg->b, HE_COLORSET_SELECTED);
596 else
597 ui_browser__set_color(arg->b, HE_COLORSET_NORMAL);
598
599 if (front) {
600 if (!symbol_conf.use_callchain)
601 return 0;
602
603 slsmg_printf("%c ", arg->folded_sign);
604 return 2;
605 }
606
607 return 0;
608}
609
610static int __hpp__color_callback(struct perf_hpp *hpp, bool front __maybe_unused)
611{
612 struct hpp_arg *arg = hpp->ptr;
613
614 if (!arg->current_entry || !arg->b->navkeypressed)
615 ui_browser__set_color(arg->b, HE_COLORSET_NORMAL);
616 return 0;
617}
618
619static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...) 618static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
620{ 619{
621 struct hpp_arg *arg = hpp->ptr; 620 struct hpp_arg *arg = hpp->ptr;
@@ -636,7 +635,7 @@ static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
636 return ret; 635 return ret;
637} 636}
638 637
639#define __HPP_COLOR_PERCENT_FN(_type, _field, _cb) \ 638#define __HPP_COLOR_PERCENT_FN(_type, _field) \
640static u64 __hpp_get_##_field(struct hist_entry *he) \ 639static u64 __hpp_get_##_field(struct hist_entry *he) \
641{ \ 640{ \
642 return he->stat._field; \ 641 return he->stat._field; \
@@ -647,22 +646,43 @@ hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\
647 struct perf_hpp *hpp, \ 646 struct perf_hpp *hpp, \
648 struct hist_entry *he) \ 647 struct hist_entry *he) \
649{ \ 648{ \
650 return __hpp__fmt(hpp, he, __hpp_get_##_field, _cb, " %6.2f%%", \ 649 return __hpp__fmt(hpp, he, __hpp_get_##_field, " %6.2f%%", \
651 __hpp__slsmg_color_printf, true); \ 650 __hpp__slsmg_color_printf, true); \
652} 651}
653 652
654__HPP_COLOR_PERCENT_FN(overhead, period, __hpp__overhead_callback) 653#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
655__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys, __hpp__color_callback) 654static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
656__HPP_COLOR_PERCENT_FN(overhead_us, period_us, __hpp__color_callback) 655{ \
657__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys, __hpp__color_callback) 656 return he->stat_acc->_field; \
658__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us, __hpp__color_callback) 657} \
658 \
659static int \
660hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\
661 struct perf_hpp *hpp, \
662 struct hist_entry *he) \
663{ \
664 if (!symbol_conf.cumulate_callchain) { \
665 int ret = scnprintf(hpp->buf, hpp->size, "%8s", "N/A"); \
666 slsmg_printf("%s", hpp->buf); \
667 \
668 return ret; \
669 } \
670 return __hpp__fmt(hpp, he, __hpp_get_acc_##_field, " %6.2f%%", \
671 __hpp__slsmg_color_printf, true); \
672}
673
674__HPP_COLOR_PERCENT_FN(overhead, period)
675__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
676__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
677__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
678__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
679__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
659 680
660#undef __HPP_COLOR_PERCENT_FN 681#undef __HPP_COLOR_PERCENT_FN
682#undef __HPP_COLOR_ACC_PERCENT_FN
661 683
662void hist_browser__init_hpp(void) 684void hist_browser__init_hpp(void)
663{ 685{
664 perf_hpp__init();
665
666 perf_hpp__format[PERF_HPP__OVERHEAD].color = 686 perf_hpp__format[PERF_HPP__OVERHEAD].color =
667 hist_browser__hpp_color_overhead; 687 hist_browser__hpp_color_overhead;
668 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color = 688 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
@@ -673,6 +693,8 @@ void hist_browser__init_hpp(void)
673 hist_browser__hpp_color_overhead_guest_sys; 693 hist_browser__hpp_color_overhead_guest_sys;
674 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color = 694 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
675 hist_browser__hpp_color_overhead_guest_us; 695 hist_browser__hpp_color_overhead_guest_us;
696 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
697 hist_browser__hpp_color_overhead_acc;
676} 698}
677 699
678static int hist_browser__show_entry(struct hist_browser *browser, 700static int hist_browser__show_entry(struct hist_browser *browser,
@@ -700,7 +722,7 @@ static int hist_browser__show_entry(struct hist_browser *browser,
700 722
701 if (row_offset == 0) { 723 if (row_offset == 0) {
702 struct hpp_arg arg = { 724 struct hpp_arg arg = {
703 .b = &browser->b, 725 .b = &browser->b,
704 .folded_sign = folded_sign, 726 .folded_sign = folded_sign,
705 .current_entry = current_entry, 727 .current_entry = current_entry,
706 }; 728 };
@@ -713,11 +735,27 @@ static int hist_browser__show_entry(struct hist_browser *browser,
713 ui_browser__gotorc(&browser->b, row, 0); 735 ui_browser__gotorc(&browser->b, row, 0);
714 736
715 perf_hpp__for_each_format(fmt) { 737 perf_hpp__for_each_format(fmt) {
716 if (!first) { 738 if (perf_hpp__should_skip(fmt))
739 continue;
740
741 if (current_entry && browser->b.navkeypressed) {
742 ui_browser__set_color(&browser->b,
743 HE_COLORSET_SELECTED);
744 } else {
745 ui_browser__set_color(&browser->b,
746 HE_COLORSET_NORMAL);
747 }
748
749 if (first) {
750 if (symbol_conf.use_callchain) {
751 slsmg_printf("%c ", folded_sign);
752 width -= 2;
753 }
754 first = false;
755 } else {
717 slsmg_printf(" "); 756 slsmg_printf(" ");
718 width -= 2; 757 width -= 2;
719 } 758 }
720 first = false;
721 759
722 if (fmt->color) { 760 if (fmt->color) {
723 width -= fmt->color(fmt, &hpp, entry); 761 width -= fmt->color(fmt, &hpp, entry);
@@ -731,8 +769,8 @@ static int hist_browser__show_entry(struct hist_browser *browser,
731 if (!browser->b.navkeypressed) 769 if (!browser->b.navkeypressed)
732 width += 1; 770 width += 1;
733 771
734 hist_entry__sort_snprintf(entry, s, sizeof(s), browser->hists); 772 slsmg_write_nstring("", width);
735 slsmg_write_nstring(s, width); 773
736 ++row; 774 ++row;
737 ++printed; 775 ++printed;
738 } else 776 } else
@@ -769,12 +807,12 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)
769 807
770 for (nd = browser->top; nd; nd = rb_next(nd)) { 808 for (nd = browser->top; nd; nd = rb_next(nd)) {
771 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 809 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
772 float percent = h->stat.period * 100.0 / 810 float percent;
773 hb->hists->stats.total_period;
774 811
775 if (h->filtered) 812 if (h->filtered)
776 continue; 813 continue;
777 814
815 percent = hist_entry__get_percent_limit(h);
778 if (percent < hb->min_pcnt) 816 if (percent < hb->min_pcnt)
779 continue; 817 continue;
780 818
@@ -787,18 +825,13 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)
787} 825}
788 826
789static struct rb_node *hists__filter_entries(struct rb_node *nd, 827static struct rb_node *hists__filter_entries(struct rb_node *nd,
790 struct hists *hists,
791 float min_pcnt) 828 float min_pcnt)
792{ 829{
793 while (nd != NULL) { 830 while (nd != NULL) {
794 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 831 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
795 float percent = h->stat.period * 100.0 / 832 float percent = hist_entry__get_percent_limit(h);
796 hists->stats.total_period;
797
798 if (percent < min_pcnt)
799 return NULL;
800 833
801 if (!h->filtered) 834 if (!h->filtered && percent >= min_pcnt)
802 return nd; 835 return nd;
803 836
804 nd = rb_next(nd); 837 nd = rb_next(nd);
@@ -808,13 +841,11 @@ static struct rb_node *hists__filter_entries(struct rb_node *nd,
808} 841}
809 842
810static struct rb_node *hists__filter_prev_entries(struct rb_node *nd, 843static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
811 struct hists *hists,
812 float min_pcnt) 844 float min_pcnt)
813{ 845{
814 while (nd != NULL) { 846 while (nd != NULL) {
815 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 847 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
816 float percent = h->stat.period * 100.0 / 848 float percent = hist_entry__get_percent_limit(h);
817 hists->stats.total_period;
818 849
819 if (!h->filtered && percent >= min_pcnt) 850 if (!h->filtered && percent >= min_pcnt)
820 return nd; 851 return nd;
@@ -843,14 +874,14 @@ static void ui_browser__hists_seek(struct ui_browser *browser,
843 switch (whence) { 874 switch (whence) {
844 case SEEK_SET: 875 case SEEK_SET:
845 nd = hists__filter_entries(rb_first(browser->entries), 876 nd = hists__filter_entries(rb_first(browser->entries),
846 hb->hists, hb->min_pcnt); 877 hb->min_pcnt);
847 break; 878 break;
848 case SEEK_CUR: 879 case SEEK_CUR:
849 nd = browser->top; 880 nd = browser->top;
850 goto do_offset; 881 goto do_offset;
851 case SEEK_END: 882 case SEEK_END:
852 nd = hists__filter_prev_entries(rb_last(browser->entries), 883 nd = hists__filter_prev_entries(rb_last(browser->entries),
853 hb->hists, hb->min_pcnt); 884 hb->min_pcnt);
854 first = false; 885 first = false;
855 break; 886 break;
856 default: 887 default:
@@ -893,8 +924,7 @@ do_offset:
893 break; 924 break;
894 } 925 }
895 } 926 }
896 nd = hists__filter_entries(rb_next(nd), hb->hists, 927 nd = hists__filter_entries(rb_next(nd), hb->min_pcnt);
897 hb->min_pcnt);
898 if (nd == NULL) 928 if (nd == NULL)
899 break; 929 break;
900 --offset; 930 --offset;
@@ -927,7 +957,7 @@ do_offset:
927 } 957 }
928 } 958 }
929 959
930 nd = hists__filter_prev_entries(rb_prev(nd), hb->hists, 960 nd = hists__filter_prev_entries(rb_prev(nd),
931 hb->min_pcnt); 961 hb->min_pcnt);
932 if (nd == NULL) 962 if (nd == NULL)
933 break; 963 break;
@@ -1066,27 +1096,35 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser,
1066 struct hist_entry *he, FILE *fp) 1096 struct hist_entry *he, FILE *fp)
1067{ 1097{
1068 char s[8192]; 1098 char s[8192];
1069 double percent;
1070 int printed = 0; 1099 int printed = 0;
1071 char folded_sign = ' '; 1100 char folded_sign = ' ';
1101 struct perf_hpp hpp = {
1102 .buf = s,
1103 .size = sizeof(s),
1104 };
1105 struct perf_hpp_fmt *fmt;
1106 bool first = true;
1107 int ret;
1072 1108
1073 if (symbol_conf.use_callchain) 1109 if (symbol_conf.use_callchain)
1074 folded_sign = hist_entry__folded(he); 1110 folded_sign = hist_entry__folded(he);
1075 1111
1076 hist_entry__sort_snprintf(he, s, sizeof(s), browser->hists);
1077 percent = (he->stat.period * 100.0) / browser->hists->stats.total_period;
1078
1079 if (symbol_conf.use_callchain) 1112 if (symbol_conf.use_callchain)
1080 printed += fprintf(fp, "%c ", folded_sign); 1113 printed += fprintf(fp, "%c ", folded_sign);
1081 1114
1082 printed += fprintf(fp, " %5.2f%%", percent); 1115 perf_hpp__for_each_format(fmt) {
1083 1116 if (perf_hpp__should_skip(fmt))
1084 if (symbol_conf.show_nr_samples) 1117 continue;
1085 printed += fprintf(fp, " %11u", he->stat.nr_events);
1086 1118
1087 if (symbol_conf.show_total_period) 1119 if (!first) {
1088 printed += fprintf(fp, " %12" PRIu64, he->stat.period); 1120 ret = scnprintf(hpp.buf, hpp.size, " ");
1121 advance_hpp(&hpp, ret);
1122 } else
1123 first = false;
1089 1124
1125 ret = fmt->entry(fmt, &hpp, he);
1126 advance_hpp(&hpp, ret);
1127 }
1090 printed += fprintf(fp, "%s\n", rtrim(s)); 1128 printed += fprintf(fp, "%s\n", rtrim(s));
1091 1129
1092 if (folded_sign == '-') 1130 if (folded_sign == '-')
@@ -1098,7 +1136,6 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser,
1098static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp) 1136static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1099{ 1137{
1100 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries), 1138 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
1101 browser->hists,
1102 browser->min_pcnt); 1139 browser->min_pcnt);
1103 int printed = 0; 1140 int printed = 0;
1104 1141
@@ -1106,8 +1143,7 @@ static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1106 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1143 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1107 1144
1108 printed += hist_browser__fprintf_entry(browser, h, fp); 1145 printed += hist_browser__fprintf_entry(browser, h, fp);
1109 nd = hists__filter_entries(rb_next(nd), browser->hists, 1146 nd = hists__filter_entries(rb_next(nd), browser->min_pcnt);
1110 browser->min_pcnt);
1111 } 1147 }
1112 1148
1113 return printed; 1149 return printed;
@@ -1189,6 +1225,11 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size,
1189 char buf[512]; 1225 char buf[512];
1190 size_t buflen = sizeof(buf); 1226 size_t buflen = sizeof(buf);
1191 1227
1228 if (symbol_conf.filter_relative) {
1229 nr_samples = hists->stats.nr_non_filtered_samples;
1230 nr_events = hists->stats.total_non_filtered_period;
1231 }
1232
1192 if (perf_evsel__is_group_event(evsel)) { 1233 if (perf_evsel__is_group_event(evsel)) {
1193 struct perf_evsel *pos; 1234 struct perf_evsel *pos;
1194 1235
@@ -1196,8 +1237,13 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size,
1196 ev_name = buf; 1237 ev_name = buf;
1197 1238
1198 for_each_group_member(pos, evsel) { 1239 for_each_group_member(pos, evsel) {
1199 nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE]; 1240 if (symbol_conf.filter_relative) {
1200 nr_events += pos->hists.stats.total_period; 1241 nr_samples += pos->hists.stats.nr_non_filtered_samples;
1242 nr_events += pos->hists.stats.total_non_filtered_period;
1243 } else {
1244 nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1245 nr_events += pos->hists.stats.total_period;
1246 }
1201 } 1247 }
1202 } 1248 }
1203 1249
@@ -1324,18 +1370,22 @@ close_file_and_continue:
1324 return ret; 1370 return ret;
1325} 1371}
1326 1372
1327static void hist_browser__update_pcnt_entries(struct hist_browser *hb) 1373static void hist_browser__update_nr_entries(struct hist_browser *hb)
1328{ 1374{
1329 u64 nr_entries = 0; 1375 u64 nr_entries = 0;
1330 struct rb_node *nd = rb_first(&hb->hists->entries); 1376 struct rb_node *nd = rb_first(&hb->hists->entries);
1331 1377
1332 while (nd) { 1378 if (hb->min_pcnt == 0) {
1379 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
1380 return;
1381 }
1382
1383 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
1333 nr_entries++; 1384 nr_entries++;
1334 nd = hists__filter_entries(rb_next(nd), hb->hists, 1385 nd = rb_next(nd);
1335 hb->min_pcnt);
1336 } 1386 }
1337 1387
1338 hb->nr_pcnt_entries = nr_entries; 1388 hb->nr_non_filtered_entries = nr_entries;
1339} 1389}
1340 1390
1341static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, 1391static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
@@ -1370,6 +1420,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1370 "C Collapse all callchains\n" \ 1420 "C Collapse all callchains\n" \
1371 "d Zoom into current DSO\n" \ 1421 "d Zoom into current DSO\n" \
1372 "E Expand all callchains\n" \ 1422 "E Expand all callchains\n" \
1423 "F Toggle percentage of filtered entries\n" \
1373 1424
1374 /* help messages are sorted by lexical order of the hotkey */ 1425 /* help messages are sorted by lexical order of the hotkey */
1375 const char report_help[] = HIST_BROWSER_HELP_COMMON 1426 const char report_help[] = HIST_BROWSER_HELP_COMMON
@@ -1391,7 +1442,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1391 1442
1392 if (min_pcnt) { 1443 if (min_pcnt) {
1393 browser->min_pcnt = min_pcnt; 1444 browser->min_pcnt = min_pcnt;
1394 hist_browser__update_pcnt_entries(browser); 1445 hist_browser__update_nr_entries(browser);
1395 } 1446 }
1396 1447
1397 fstack = pstack__new(2); 1448 fstack = pstack__new(2);
@@ -1475,6 +1526,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1475 if (env->arch) 1526 if (env->arch)
1476 tui__header_window(env); 1527 tui__header_window(env);
1477 continue; 1528 continue;
1529 case 'F':
1530 symbol_conf.filter_relative ^= 1;
1531 continue;
1478 case K_F1: 1532 case K_F1:
1479 case 'h': 1533 case 'h':
1480 case '?': 1534 case '?':
@@ -1652,14 +1706,14 @@ zoom_dso:
1652zoom_out_dso: 1706zoom_out_dso:
1653 ui_helpline__pop(); 1707 ui_helpline__pop();
1654 browser->hists->dso_filter = NULL; 1708 browser->hists->dso_filter = NULL;
1655 sort_dso.elide = false; 1709 perf_hpp__set_elide(HISTC_DSO, false);
1656 } else { 1710 } else {
1657 if (dso == NULL) 1711 if (dso == NULL)
1658 continue; 1712 continue;
1659 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"", 1713 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
1660 dso->kernel ? "the Kernel" : dso->short_name); 1714 dso->kernel ? "the Kernel" : dso->short_name);
1661 browser->hists->dso_filter = dso; 1715 browser->hists->dso_filter = dso;
1662 sort_dso.elide = true; 1716 perf_hpp__set_elide(HISTC_DSO, true);
1663 pstack__push(fstack, &browser->hists->dso_filter); 1717 pstack__push(fstack, &browser->hists->dso_filter);
1664 } 1718 }
1665 hists__filter_by_dso(hists); 1719 hists__filter_by_dso(hists);
@@ -1671,13 +1725,13 @@ zoom_thread:
1671zoom_out_thread: 1725zoom_out_thread:
1672 ui_helpline__pop(); 1726 ui_helpline__pop();
1673 browser->hists->thread_filter = NULL; 1727 browser->hists->thread_filter = NULL;
1674 sort_thread.elide = false; 1728 perf_hpp__set_elide(HISTC_THREAD, false);
1675 } else { 1729 } else {
1676 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"", 1730 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
1677 thread->comm_set ? thread__comm_str(thread) : "", 1731 thread->comm_set ? thread__comm_str(thread) : "",
1678 thread->tid); 1732 thread->tid);
1679 browser->hists->thread_filter = thread; 1733 browser->hists->thread_filter = thread;
1680 sort_thread.elide = true; 1734 perf_hpp__set_elide(HISTC_THREAD, false);
1681 pstack__push(fstack, &browser->hists->thread_filter); 1735 pstack__push(fstack, &browser->hists->thread_filter);
1682 } 1736 }
1683 hists__filter_by_thread(hists); 1737 hists__filter_by_thread(hists);
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c
index e395ef9b0ae0..6ca60e482cdc 100644
--- a/tools/perf/ui/gtk/hists.c
+++ b/tools/perf/ui/gtk/hists.c
@@ -43,23 +43,36 @@ static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,
43 struct perf_hpp *hpp, \ 43 struct perf_hpp *hpp, \
44 struct hist_entry *he) \ 44 struct hist_entry *he) \
45{ \ 45{ \
46 return __hpp__fmt(hpp, he, he_get_##_field, NULL, " %6.2f%%", \ 46 return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%", \
47 __percent_color_snprintf, true); \ 47 __percent_color_snprintf, true); \
48} 48}
49 49
50#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
51static u64 he_get_acc_##_field(struct hist_entry *he) \
52{ \
53 return he->stat_acc->_field; \
54} \
55 \
56static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
57 struct perf_hpp *hpp, \
58 struct hist_entry *he) \
59{ \
60 return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, " %6.2f%%", \
61 __percent_color_snprintf, true); \
62}
63
50__HPP_COLOR_PERCENT_FN(overhead, period) 64__HPP_COLOR_PERCENT_FN(overhead, period)
51__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys) 65__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
52__HPP_COLOR_PERCENT_FN(overhead_us, period_us) 66__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
53__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys) 67__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
54__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us) 68__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
69__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
55 70
56#undef __HPP_COLOR_PERCENT_FN 71#undef __HPP_COLOR_PERCENT_FN
57 72
58 73
59void perf_gtk__init_hpp(void) 74void perf_gtk__init_hpp(void)
60{ 75{
61 perf_hpp__init();
62
63 perf_hpp__format[PERF_HPP__OVERHEAD].color = 76 perf_hpp__format[PERF_HPP__OVERHEAD].color =
64 perf_gtk__hpp_color_overhead; 77 perf_gtk__hpp_color_overhead;
65 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color = 78 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
@@ -70,6 +83,8 @@ void perf_gtk__init_hpp(void)
70 perf_gtk__hpp_color_overhead_guest_sys; 83 perf_gtk__hpp_color_overhead_guest_sys;
71 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color = 84 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
72 perf_gtk__hpp_color_overhead_guest_us; 85 perf_gtk__hpp_color_overhead_guest_us;
86 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
87 perf_gtk__hpp_color_overhead_acc;
73} 88}
74 89
75static void callchain_list__sym_name(struct callchain_list *cl, 90static void callchain_list__sym_name(struct callchain_list *cl,
@@ -153,7 +168,6 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
153 struct perf_hpp_fmt *fmt; 168 struct perf_hpp_fmt *fmt;
154 GType col_types[MAX_COLUMNS]; 169 GType col_types[MAX_COLUMNS];
155 GtkCellRenderer *renderer; 170 GtkCellRenderer *renderer;
156 struct sort_entry *se;
157 GtkTreeStore *store; 171 GtkTreeStore *store;
158 struct rb_node *nd; 172 struct rb_node *nd;
159 GtkWidget *view; 173 GtkWidget *view;
@@ -172,16 +186,6 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
172 perf_hpp__for_each_format(fmt) 186 perf_hpp__for_each_format(fmt)
173 col_types[nr_cols++] = G_TYPE_STRING; 187 col_types[nr_cols++] = G_TYPE_STRING;
174 188
175 list_for_each_entry(se, &hist_entry__sort_list, list) {
176 if (se->elide)
177 continue;
178
179 if (se == &sort_sym)
180 sym_col = nr_cols;
181
182 col_types[nr_cols++] = G_TYPE_STRING;
183 }
184
185 store = gtk_tree_store_newv(nr_cols, col_types); 189 store = gtk_tree_store_newv(nr_cols, col_types);
186 190
187 view = gtk_tree_view_new(); 191 view = gtk_tree_view_new();
@@ -191,6 +195,16 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
191 col_idx = 0; 195 col_idx = 0;
192 196
193 perf_hpp__for_each_format(fmt) { 197 perf_hpp__for_each_format(fmt) {
198 if (perf_hpp__should_skip(fmt))
199 continue;
200
201 /*
202 * XXX no way to determine where symcol column is..
203 * Just use last column for now.
204 */
205 if (perf_hpp__is_sort_entry(fmt))
206 sym_col = col_idx;
207
194 fmt->header(fmt, &hpp, hists_to_evsel(hists)); 208 fmt->header(fmt, &hpp, hists_to_evsel(hists));
195 209
196 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), 210 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
@@ -199,16 +213,6 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
199 col_idx++, NULL); 213 col_idx++, NULL);
200 } 214 }
201 215
202 list_for_each_entry(se, &hist_entry__sort_list, list) {
203 if (se->elide)
204 continue;
205
206 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
207 -1, se->se_header,
208 renderer, "text",
209 col_idx++, NULL);
210 }
211
212 for (col_idx = 0; col_idx < nr_cols; col_idx++) { 216 for (col_idx = 0; col_idx < nr_cols; col_idx++) {
213 GtkTreeViewColumn *column; 217 GtkTreeViewColumn *column;
214 218
@@ -228,12 +232,13 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
228 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 232 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
229 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 233 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
230 GtkTreeIter iter; 234 GtkTreeIter iter;
231 float percent = h->stat.period * 100.0 / 235 u64 total = hists__total_period(h->hists);
232 hists->stats.total_period; 236 float percent;
233 237
234 if (h->filtered) 238 if (h->filtered)
235 continue; 239 continue;
236 240
241 percent = hist_entry__get_percent_limit(h);
237 if (percent < min_pcnt) 242 if (percent < min_pcnt)
238 continue; 243 continue;
239 244
@@ -242,6 +247,9 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
242 col_idx = 0; 247 col_idx = 0;
243 248
244 perf_hpp__for_each_format(fmt) { 249 perf_hpp__for_each_format(fmt) {
250 if (perf_hpp__should_skip(fmt))
251 continue;
252
245 if (fmt->color) 253 if (fmt->color)
246 fmt->color(fmt, &hpp, h); 254 fmt->color(fmt, &hpp, h);
247 else 255 else
@@ -250,23 +258,10 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
250 gtk_tree_store_set(store, &iter, col_idx++, s, -1); 258 gtk_tree_store_set(store, &iter, col_idx++, s, -1);
251 } 259 }
252 260
253 list_for_each_entry(se, &hist_entry__sort_list, list) {
254 if (se->elide)
255 continue;
256
257 se->se_snprintf(h, s, ARRAY_SIZE(s),
258 hists__col_len(hists, se->se_width_idx));
259
260 gtk_tree_store_set(store, &iter, col_idx++, s, -1);
261 }
262
263 if (symbol_conf.use_callchain && sort__has_sym) { 261 if (symbol_conf.use_callchain && sort__has_sym) {
264 u64 total;
265
266 if (callchain_param.mode == CHAIN_GRAPH_REL) 262 if (callchain_param.mode == CHAIN_GRAPH_REL)
267 total = h->stat.period; 263 total = symbol_conf.cumulate_callchain ?
268 else 264 h->stat_acc->period : h->stat.period;
269 total = hists->stats.total_period;
270 265
271 perf_gtk__add_callchain(&h->sorted_chain, store, &iter, 266 perf_gtk__add_callchain(&h->sorted_chain, store, &iter,
272 sym_col, total); 267 sym_col, total);
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index 0f403b83e9d1..498adb23c02e 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -16,30 +16,25 @@
16}) 16})
17 17
18int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, 18int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
19 hpp_field_fn get_field, hpp_callback_fn callback, 19 hpp_field_fn get_field, const char *fmt,
20 const char *fmt, hpp_snprint_fn print_fn, bool fmt_percent) 20 hpp_snprint_fn print_fn, bool fmt_percent)
21{ 21{
22 int ret = 0; 22 int ret;
23 struct hists *hists = he->hists; 23 struct hists *hists = he->hists;
24 struct perf_evsel *evsel = hists_to_evsel(hists); 24 struct perf_evsel *evsel = hists_to_evsel(hists);
25 char *buf = hpp->buf; 25 char *buf = hpp->buf;
26 size_t size = hpp->size; 26 size_t size = hpp->size;
27 27
28 if (callback) {
29 ret = callback(hpp, true);
30 advance_hpp(hpp, ret);
31 }
32
33 if (fmt_percent) { 28 if (fmt_percent) {
34 double percent = 0.0; 29 double percent = 0.0;
30 u64 total = hists__total_period(hists);
35 31
36 if (hists->stats.total_period) 32 if (total)
37 percent = 100.0 * get_field(he) / 33 percent = 100.0 * get_field(he) / total;
38 hists->stats.total_period;
39 34
40 ret += hpp__call_print_fn(hpp, print_fn, fmt, percent); 35 ret = hpp__call_print_fn(hpp, print_fn, fmt, percent);
41 } else 36 } else
42 ret += hpp__call_print_fn(hpp, print_fn, fmt, get_field(he)); 37 ret = hpp__call_print_fn(hpp, print_fn, fmt, get_field(he));
43 38
44 if (perf_evsel__is_group_event(evsel)) { 39 if (perf_evsel__is_group_event(evsel)) {
45 int prev_idx, idx_delta; 40 int prev_idx, idx_delta;
@@ -50,7 +45,7 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
50 45
51 list_for_each_entry(pair, &he->pairs.head, pairs.node) { 46 list_for_each_entry(pair, &he->pairs.head, pairs.node) {
52 u64 period = get_field(pair); 47 u64 period = get_field(pair);
53 u64 total = pair->hists->stats.total_period; 48 u64 total = hists__total_period(pair->hists);
54 49
55 if (!total) 50 if (!total)
56 continue; 51 continue;
@@ -99,13 +94,6 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
99 } 94 }
100 } 95 }
101 96
102 if (callback) {
103 int __ret = callback(hpp, false);
104
105 advance_hpp(hpp, __ret);
106 ret += __ret;
107 }
108
109 /* 97 /*
110 * Restore original buf and size as it's where caller expects 98 * Restore original buf and size as it's where caller expects
111 * the result will be saved. 99 * the result will be saved.
@@ -116,6 +104,92 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
116 return ret; 104 return ret;
117} 105}
118 106
107int __hpp__fmt_acc(struct perf_hpp *hpp, struct hist_entry *he,
108 hpp_field_fn get_field, const char *fmt,
109 hpp_snprint_fn print_fn, bool fmt_percent)
110{
111 if (!symbol_conf.cumulate_callchain) {
112 return snprintf(hpp->buf, hpp->size, "%*s",
113 fmt_percent ? 8 : 12, "N/A");
114 }
115
116 return __hpp__fmt(hpp, he, get_field, fmt, print_fn, fmt_percent);
117}
118
119static int field_cmp(u64 field_a, u64 field_b)
120{
121 if (field_a > field_b)
122 return 1;
123 if (field_a < field_b)
124 return -1;
125 return 0;
126}
127
128static int __hpp__sort(struct hist_entry *a, struct hist_entry *b,
129 hpp_field_fn get_field)
130{
131 s64 ret;
132 int i, nr_members;
133 struct perf_evsel *evsel;
134 struct hist_entry *pair;
135 u64 *fields_a, *fields_b;
136
137 ret = field_cmp(get_field(a), get_field(b));
138 if (ret || !symbol_conf.event_group)
139 return ret;
140
141 evsel = hists_to_evsel(a->hists);
142 if (!perf_evsel__is_group_event(evsel))
143 return ret;
144
145 nr_members = evsel->nr_members;
146 fields_a = calloc(sizeof(*fields_a), nr_members);
147 fields_b = calloc(sizeof(*fields_b), nr_members);
148
149 if (!fields_a || !fields_b)
150 goto out;
151
152 list_for_each_entry(pair, &a->pairs.head, pairs.node) {
153 evsel = hists_to_evsel(pair->hists);
154 fields_a[perf_evsel__group_idx(evsel)] = get_field(pair);
155 }
156
157 list_for_each_entry(pair, &b->pairs.head, pairs.node) {
158 evsel = hists_to_evsel(pair->hists);
159 fields_b[perf_evsel__group_idx(evsel)] = get_field(pair);
160 }
161
162 for (i = 1; i < nr_members; i++) {
163 ret = field_cmp(fields_a[i], fields_b[i]);
164 if (ret)
165 break;
166 }
167
168out:
169 free(fields_a);
170 free(fields_b);
171
172 return ret;
173}
174
175static int __hpp__sort_acc(struct hist_entry *a, struct hist_entry *b,
176 hpp_field_fn get_field)
177{
178 s64 ret = 0;
179
180 if (symbol_conf.cumulate_callchain) {
181 /*
182 * Put caller above callee when they have equal period.
183 */
184 ret = field_cmp(get_field(a), get_field(b));
185 if (ret)
186 return ret;
187
188 ret = b->callchain->max_depth - a->callchain->max_depth;
189 }
190 return ret;
191}
192
119#define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ 193#define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \
120static int hpp__header_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ 194static int hpp__header_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
121 struct perf_hpp *hpp, \ 195 struct perf_hpp *hpp, \
@@ -179,7 +253,7 @@ static u64 he_get_##_field(struct hist_entry *he) \
179static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ 253static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
180 struct perf_hpp *hpp, struct hist_entry *he) \ 254 struct perf_hpp *hpp, struct hist_entry *he) \
181{ \ 255{ \
182 return __hpp__fmt(hpp, he, he_get_##_field, NULL, " %6.2f%%", \ 256 return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%", \
183 hpp_color_scnprintf, true); \ 257 hpp_color_scnprintf, true); \
184} 258}
185 259
@@ -188,10 +262,44 @@ static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \
188 struct perf_hpp *hpp, struct hist_entry *he) \ 262 struct perf_hpp *hpp, struct hist_entry *he) \
189{ \ 263{ \
190 const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \ 264 const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \
191 return __hpp__fmt(hpp, he, he_get_##_field, NULL, fmt, \ 265 return __hpp__fmt(hpp, he, he_get_##_field, fmt, \
192 hpp_entry_scnprintf, true); \ 266 hpp_entry_scnprintf, true); \
193} 267}
194 268
269#define __HPP_SORT_FN(_type, _field) \
270static int64_t hpp__sort_##_type(struct hist_entry *a, struct hist_entry *b) \
271{ \
272 return __hpp__sort(a, b, he_get_##_field); \
273}
274
275#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
276static u64 he_get_acc_##_field(struct hist_entry *he) \
277{ \
278 return he->stat_acc->_field; \
279} \
280 \
281static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
282 struct perf_hpp *hpp, struct hist_entry *he) \
283{ \
284 return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, " %6.2f%%", \
285 hpp_color_scnprintf, true); \
286}
287
288#define __HPP_ENTRY_ACC_PERCENT_FN(_type, _field) \
289static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \
290 struct perf_hpp *hpp, struct hist_entry *he) \
291{ \
292 const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \
293 return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, fmt, \
294 hpp_entry_scnprintf, true); \
295}
296
297#define __HPP_SORT_ACC_FN(_type, _field) \
298static int64_t hpp__sort_##_type(struct hist_entry *a, struct hist_entry *b) \
299{ \
300 return __hpp__sort_acc(a, b, he_get_acc_##_field); \
301}
302
195#define __HPP_ENTRY_RAW_FN(_type, _field) \ 303#define __HPP_ENTRY_RAW_FN(_type, _field) \
196static u64 he_get_raw_##_field(struct hist_entry *he) \ 304static u64 he_get_raw_##_field(struct hist_entry *he) \
197{ \ 305{ \
@@ -202,44 +310,85 @@ static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \
202 struct perf_hpp *hpp, struct hist_entry *he) \ 310 struct perf_hpp *hpp, struct hist_entry *he) \
203{ \ 311{ \
204 const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64; \ 312 const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64; \
205 return __hpp__fmt(hpp, he, he_get_raw_##_field, NULL, fmt, \ 313 return __hpp__fmt(hpp, he, he_get_raw_##_field, fmt, \
206 hpp_entry_scnprintf, false); \ 314 hpp_entry_scnprintf, false); \
207} 315}
208 316
317#define __HPP_SORT_RAW_FN(_type, _field) \
318static int64_t hpp__sort_##_type(struct hist_entry *a, struct hist_entry *b) \
319{ \
320 return __hpp__sort(a, b, he_get_raw_##_field); \
321}
322
323
209#define HPP_PERCENT_FNS(_type, _str, _field, _min_width, _unit_width) \ 324#define HPP_PERCENT_FNS(_type, _str, _field, _min_width, _unit_width) \
210__HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ 325__HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \
211__HPP_WIDTH_FN(_type, _min_width, _unit_width) \ 326__HPP_WIDTH_FN(_type, _min_width, _unit_width) \
212__HPP_COLOR_PERCENT_FN(_type, _field) \ 327__HPP_COLOR_PERCENT_FN(_type, _field) \
213__HPP_ENTRY_PERCENT_FN(_type, _field) 328__HPP_ENTRY_PERCENT_FN(_type, _field) \
329__HPP_SORT_FN(_type, _field)
330
331#define HPP_PERCENT_ACC_FNS(_type, _str, _field, _min_width, _unit_width)\
332__HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \
333__HPP_WIDTH_FN(_type, _min_width, _unit_width) \
334__HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
335__HPP_ENTRY_ACC_PERCENT_FN(_type, _field) \
336__HPP_SORT_ACC_FN(_type, _field)
214 337
215#define HPP_RAW_FNS(_type, _str, _field, _min_width, _unit_width) \ 338#define HPP_RAW_FNS(_type, _str, _field, _min_width, _unit_width) \
216__HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ 339__HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \
217__HPP_WIDTH_FN(_type, _min_width, _unit_width) \ 340__HPP_WIDTH_FN(_type, _min_width, _unit_width) \
218__HPP_ENTRY_RAW_FN(_type, _field) 341__HPP_ENTRY_RAW_FN(_type, _field) \
342__HPP_SORT_RAW_FN(_type, _field)
219 343
344__HPP_HEADER_FN(overhead_self, "Self", 8, 8)
220 345
221HPP_PERCENT_FNS(overhead, "Overhead", period, 8, 8) 346HPP_PERCENT_FNS(overhead, "Overhead", period, 8, 8)
222HPP_PERCENT_FNS(overhead_sys, "sys", period_sys, 8, 8) 347HPP_PERCENT_FNS(overhead_sys, "sys", period_sys, 8, 8)
223HPP_PERCENT_FNS(overhead_us, "usr", period_us, 8, 8) 348HPP_PERCENT_FNS(overhead_us, "usr", period_us, 8, 8)
224HPP_PERCENT_FNS(overhead_guest_sys, "guest sys", period_guest_sys, 9, 8) 349HPP_PERCENT_FNS(overhead_guest_sys, "guest sys", period_guest_sys, 9, 8)
225HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us, 9, 8) 350HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us, 9, 8)
351HPP_PERCENT_ACC_FNS(overhead_acc, "Children", period, 8, 8)
226 352
227HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12) 353HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12)
228HPP_RAW_FNS(period, "Period", period, 12, 12) 354HPP_RAW_FNS(period, "Period", period, 12, 12)
229 355
356static int64_t hpp__nop_cmp(struct hist_entry *a __maybe_unused,
357 struct hist_entry *b __maybe_unused)
358{
359 return 0;
360}
361
230#define HPP__COLOR_PRINT_FNS(_name) \ 362#define HPP__COLOR_PRINT_FNS(_name) \
231 { \ 363 { \
232 .header = hpp__header_ ## _name, \ 364 .header = hpp__header_ ## _name, \
233 .width = hpp__width_ ## _name, \ 365 .width = hpp__width_ ## _name, \
234 .color = hpp__color_ ## _name, \ 366 .color = hpp__color_ ## _name, \
235 .entry = hpp__entry_ ## _name \ 367 .entry = hpp__entry_ ## _name, \
368 .cmp = hpp__nop_cmp, \
369 .collapse = hpp__nop_cmp, \
370 .sort = hpp__sort_ ## _name, \
371 }
372
373#define HPP__COLOR_ACC_PRINT_FNS(_name) \
374 { \
375 .header = hpp__header_ ## _name, \
376 .width = hpp__width_ ## _name, \
377 .color = hpp__color_ ## _name, \
378 .entry = hpp__entry_ ## _name, \
379 .cmp = hpp__nop_cmp, \
380 .collapse = hpp__nop_cmp, \
381 .sort = hpp__sort_ ## _name, \
236 } 382 }
237 383
238#define HPP__PRINT_FNS(_name) \ 384#define HPP__PRINT_FNS(_name) \
239 { \ 385 { \
240 .header = hpp__header_ ## _name, \ 386 .header = hpp__header_ ## _name, \
241 .width = hpp__width_ ## _name, \ 387 .width = hpp__width_ ## _name, \
242 .entry = hpp__entry_ ## _name \ 388 .entry = hpp__entry_ ## _name, \
389 .cmp = hpp__nop_cmp, \
390 .collapse = hpp__nop_cmp, \
391 .sort = hpp__sort_ ## _name, \
243 } 392 }
244 393
245struct perf_hpp_fmt perf_hpp__format[] = { 394struct perf_hpp_fmt perf_hpp__format[] = {
@@ -248,28 +397,63 @@ struct perf_hpp_fmt perf_hpp__format[] = {
248 HPP__COLOR_PRINT_FNS(overhead_us), 397 HPP__COLOR_PRINT_FNS(overhead_us),
249 HPP__COLOR_PRINT_FNS(overhead_guest_sys), 398 HPP__COLOR_PRINT_FNS(overhead_guest_sys),
250 HPP__COLOR_PRINT_FNS(overhead_guest_us), 399 HPP__COLOR_PRINT_FNS(overhead_guest_us),
400 HPP__COLOR_ACC_PRINT_FNS(overhead_acc),
251 HPP__PRINT_FNS(samples), 401 HPP__PRINT_FNS(samples),
252 HPP__PRINT_FNS(period) 402 HPP__PRINT_FNS(period)
253}; 403};
254 404
255LIST_HEAD(perf_hpp__list); 405LIST_HEAD(perf_hpp__list);
406LIST_HEAD(perf_hpp__sort_list);
256 407
257 408
258#undef HPP__COLOR_PRINT_FNS 409#undef HPP__COLOR_PRINT_FNS
410#undef HPP__COLOR_ACC_PRINT_FNS
259#undef HPP__PRINT_FNS 411#undef HPP__PRINT_FNS
260 412
261#undef HPP_PERCENT_FNS 413#undef HPP_PERCENT_FNS
414#undef HPP_PERCENT_ACC_FNS
262#undef HPP_RAW_FNS 415#undef HPP_RAW_FNS
263 416
264#undef __HPP_HEADER_FN 417#undef __HPP_HEADER_FN
265#undef __HPP_WIDTH_FN 418#undef __HPP_WIDTH_FN
266#undef __HPP_COLOR_PERCENT_FN 419#undef __HPP_COLOR_PERCENT_FN
267#undef __HPP_ENTRY_PERCENT_FN 420#undef __HPP_ENTRY_PERCENT_FN
421#undef __HPP_COLOR_ACC_PERCENT_FN
422#undef __HPP_ENTRY_ACC_PERCENT_FN
268#undef __HPP_ENTRY_RAW_FN 423#undef __HPP_ENTRY_RAW_FN
424#undef __HPP_SORT_FN
425#undef __HPP_SORT_ACC_FN
426#undef __HPP_SORT_RAW_FN
269 427
270 428
271void perf_hpp__init(void) 429void perf_hpp__init(void)
272{ 430{
431 struct list_head *list;
432 int i;
433
434 for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
435 struct perf_hpp_fmt *fmt = &perf_hpp__format[i];
436
437 INIT_LIST_HEAD(&fmt->list);
438
439 /* sort_list may be linked by setup_sorting() */
440 if (fmt->sort_list.next == NULL)
441 INIT_LIST_HEAD(&fmt->sort_list);
442 }
443
444 /*
445 * If user specified field order, no need to setup default fields.
446 */
447 if (field_order)
448 return;
449
450 if (symbol_conf.cumulate_callchain) {
451 perf_hpp__column_enable(PERF_HPP__OVERHEAD_ACC);
452
453 perf_hpp__format[PERF_HPP__OVERHEAD].header =
454 hpp__header_overhead_self;
455 }
456
273 perf_hpp__column_enable(PERF_HPP__OVERHEAD); 457 perf_hpp__column_enable(PERF_HPP__OVERHEAD);
274 458
275 if (symbol_conf.show_cpu_utilization) { 459 if (symbol_conf.show_cpu_utilization) {
@@ -287,6 +471,17 @@ void perf_hpp__init(void)
287 471
288 if (symbol_conf.show_total_period) 472 if (symbol_conf.show_total_period)
289 perf_hpp__column_enable(PERF_HPP__PERIOD); 473 perf_hpp__column_enable(PERF_HPP__PERIOD);
474
475 /* prepend overhead field for backward compatiblity. */
476 list = &perf_hpp__format[PERF_HPP__OVERHEAD].sort_list;
477 if (list_empty(list))
478 list_add(list, &perf_hpp__sort_list);
479
480 if (symbol_conf.cumulate_callchain) {
481 list = &perf_hpp__format[PERF_HPP__OVERHEAD_ACC].sort_list;
482 if (list_empty(list))
483 list_add(list, &perf_hpp__sort_list);
484 }
290} 485}
291 486
292void perf_hpp__column_register(struct perf_hpp_fmt *format) 487void perf_hpp__column_register(struct perf_hpp_fmt *format)
@@ -294,29 +489,110 @@ void perf_hpp__column_register(struct perf_hpp_fmt *format)
294 list_add_tail(&format->list, &perf_hpp__list); 489 list_add_tail(&format->list, &perf_hpp__list);
295} 490}
296 491
492void perf_hpp__column_unregister(struct perf_hpp_fmt *format)
493{
494 list_del(&format->list);
495}
496
497void perf_hpp__register_sort_field(struct perf_hpp_fmt *format)
498{
499 list_add_tail(&format->sort_list, &perf_hpp__sort_list);
500}
501
297void perf_hpp__column_enable(unsigned col) 502void perf_hpp__column_enable(unsigned col)
298{ 503{
299 BUG_ON(col >= PERF_HPP__MAX_INDEX); 504 BUG_ON(col >= PERF_HPP__MAX_INDEX);
300 perf_hpp__column_register(&perf_hpp__format[col]); 505 perf_hpp__column_register(&perf_hpp__format[col]);
301} 506}
302 507
303int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size, 508void perf_hpp__column_disable(unsigned col)
304 struct hists *hists)
305{ 509{
306 const char *sep = symbol_conf.field_sep; 510 BUG_ON(col >= PERF_HPP__MAX_INDEX);
307 struct sort_entry *se; 511 perf_hpp__column_unregister(&perf_hpp__format[col]);
308 int ret = 0; 512}
513
514void perf_hpp__cancel_cumulate(void)
515{
516 if (field_order)
517 return;
309 518
310 list_for_each_entry(se, &hist_entry__sort_list, list) { 519 perf_hpp__column_disable(PERF_HPP__OVERHEAD_ACC);
311 if (se->elide) 520 perf_hpp__format[PERF_HPP__OVERHEAD].header = hpp__header_overhead;
521}
522
523void perf_hpp__setup_output_field(void)
524{
525 struct perf_hpp_fmt *fmt;
526
527 /* append sort keys to output field */
528 perf_hpp__for_each_sort_list(fmt) {
529 if (!list_empty(&fmt->list))
312 continue; 530 continue;
313 531
314 ret += scnprintf(s + ret, size - ret, "%s", sep ?: " "); 532 /*
315 ret += se->se_snprintf(he, s + ret, size - ret, 533 * sort entry fields are dynamically created,
316 hists__col_len(hists, se->se_width_idx)); 534 * so they can share a same sort key even though
535 * the list is empty.
536 */
537 if (perf_hpp__is_sort_entry(fmt)) {
538 struct perf_hpp_fmt *pos;
539
540 perf_hpp__for_each_format(pos) {
541 if (perf_hpp__same_sort_entry(pos, fmt))
542 goto next;
543 }
544 }
545
546 perf_hpp__column_register(fmt);
547next:
548 continue;
317 } 549 }
550}
318 551
319 return ret; 552void perf_hpp__append_sort_keys(void)
553{
554 struct perf_hpp_fmt *fmt;
555
556 /* append output fields to sort keys */
557 perf_hpp__for_each_format(fmt) {
558 if (!list_empty(&fmt->sort_list))
559 continue;
560
561 /*
562 * sort entry fields are dynamically created,
563 * so they can share a same sort key even though
564 * the list is empty.
565 */
566 if (perf_hpp__is_sort_entry(fmt)) {
567 struct perf_hpp_fmt *pos;
568
569 perf_hpp__for_each_sort_list(pos) {
570 if (perf_hpp__same_sort_entry(pos, fmt))
571 goto next;
572 }
573 }
574
575 perf_hpp__register_sort_field(fmt);
576next:
577 continue;
578 }
579}
580
581void perf_hpp__reset_output_field(void)
582{
583 struct perf_hpp_fmt *fmt, *tmp;
584
585 /* reset output fields */
586 perf_hpp__for_each_format_safe(fmt, tmp) {
587 list_del_init(&fmt->list);
588 list_del_init(&fmt->sort_list);
589 }
590
591 /* reset sort keys */
592 perf_hpp__for_each_sort_list_safe(fmt, tmp) {
593 list_del_init(&fmt->list);
594 list_del_init(&fmt->sort_list);
595 }
320} 596}
321 597
322/* 598/*
@@ -325,22 +601,23 @@ int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size,
325unsigned int hists__sort_list_width(struct hists *hists) 601unsigned int hists__sort_list_width(struct hists *hists)
326{ 602{
327 struct perf_hpp_fmt *fmt; 603 struct perf_hpp_fmt *fmt;
328 struct sort_entry *se; 604 int ret = 0;
329 int i = 0, ret = 0; 605 bool first = true;
330 struct perf_hpp dummy_hpp; 606 struct perf_hpp dummy_hpp;
331 607
332 perf_hpp__for_each_format(fmt) { 608 perf_hpp__for_each_format(fmt) {
333 if (i) 609 if (perf_hpp__should_skip(fmt))
610 continue;
611
612 if (first)
613 first = false;
614 else
334 ret += 2; 615 ret += 2;
335 616
336 ret += fmt->width(fmt, &dummy_hpp, hists_to_evsel(hists)); 617 ret += fmt->width(fmt, &dummy_hpp, hists_to_evsel(hists));
337 } 618 }
338 619
339 list_for_each_entry(se, &hist_entry__sort_list, list) 620 if (verbose && sort__has_sym) /* Addr + origin */
340 if (!se->elide)
341 ret += 2 + hists__col_len(hists, se->se_width_idx);
342
343 if (verbose) /* Addr + origin */
344 ret += 3 + BITS_PER_LONG / 4; 621 ret += 3 + BITS_PER_LONG / 4;
345 622
346 return ret; 623 return ret;
diff --git a/tools/perf/ui/progress.h b/tools/perf/ui/progress.h
index 29ec8efffefb..f34f89eb607c 100644
--- a/tools/perf/ui/progress.h
+++ b/tools/perf/ui/progress.h
@@ -1,7 +1,7 @@
1#ifndef _PERF_UI_PROGRESS_H_ 1#ifndef _PERF_UI_PROGRESS_H_
2#define _PERF_UI_PROGRESS_H_ 1 2#define _PERF_UI_PROGRESS_H_ 1
3 3
4#include <../types.h> 4#include <linux/types.h>
5 5
6void ui_progress__finish(void); 6void ui_progress__finish(void);
7 7
diff --git a/tools/perf/ui/setup.c b/tools/perf/ui/setup.c
index 5df5140a9f29..ba51fa8a1176 100644
--- a/tools/perf/ui/setup.c
+++ b/tools/perf/ui/setup.c
@@ -86,8 +86,6 @@ void setup_browser(bool fallback_to_pager)
86 use_browser = 0; 86 use_browser = 0;
87 if (fallback_to_pager) 87 if (fallback_to_pager)
88 setup_pager(); 88 setup_pager();
89
90 perf_hpp__init();
91 break; 89 break;
92 } 90 }
93} 91}
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index d59893edf031..90122abd3721 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -183,7 +183,8 @@ static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
183 * the symbol. No need to print it otherwise it appears as 183 * the symbol. No need to print it otherwise it appears as
184 * displayed twice. 184 * displayed twice.
185 */ 185 */
186 if (!i++ && sort__first_dimension == SORT_SYM) 186 if (!i++ && field_order == NULL &&
187 sort_order && !prefixcmp(sort_order, "sym"))
187 continue; 188 continue;
188 if (!printed) { 189 if (!printed) {
189 ret += callchain__fprintf_left_margin(fp, left_margin); 190 ret += callchain__fprintf_left_margin(fp, left_margin);
@@ -270,7 +271,9 @@ static size_t hist_entry_callchain__fprintf(struct hist_entry *he,
270{ 271{
271 switch (callchain_param.mode) { 272 switch (callchain_param.mode) {
272 case CHAIN_GRAPH_REL: 273 case CHAIN_GRAPH_REL:
273 return callchain__fprintf_graph(fp, &he->sorted_chain, he->stat.period, 274 return callchain__fprintf_graph(fp, &he->sorted_chain,
275 symbol_conf.cumulate_callchain ?
276 he->stat_acc->period : he->stat.period,
274 left_margin); 277 left_margin);
275 break; 278 break;
276 case CHAIN_GRAPH_ABS: 279 case CHAIN_GRAPH_ABS:
@@ -296,18 +299,24 @@ static size_t hist_entry__callchain_fprintf(struct hist_entry *he,
296 int left_margin = 0; 299 int left_margin = 0;
297 u64 total_period = hists->stats.total_period; 300 u64 total_period = hists->stats.total_period;
298 301
299 if (sort__first_dimension == SORT_COMM) { 302 if (field_order == NULL && (sort_order == NULL ||
300 struct sort_entry *se = list_first_entry(&hist_entry__sort_list, 303 !prefixcmp(sort_order, "comm"))) {
301 typeof(*se), list); 304 struct perf_hpp_fmt *fmt;
302 left_margin = hists__col_len(hists, se->se_width_idx); 305
303 left_margin -= thread__comm_len(he->thread); 306 perf_hpp__for_each_format(fmt) {
304 } 307 if (!perf_hpp__is_sort_entry(fmt))
308 continue;
305 309
310 /* must be 'comm' sort entry */
311 left_margin = fmt->width(fmt, NULL, hists_to_evsel(hists));
312 left_margin -= thread__comm_len(he->thread);
313 break;
314 }
315 }
306 return hist_entry_callchain__fprintf(he, total_period, left_margin, fp); 316 return hist_entry_callchain__fprintf(he, total_period, left_margin, fp);
307} 317}
308 318
309static int hist_entry__period_snprintf(struct perf_hpp *hpp, 319static int hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp)
310 struct hist_entry *he)
311{ 320{
312 const char *sep = symbol_conf.field_sep; 321 const char *sep = symbol_conf.field_sep;
313 struct perf_hpp_fmt *fmt; 322 struct perf_hpp_fmt *fmt;
@@ -319,6 +328,9 @@ static int hist_entry__period_snprintf(struct perf_hpp *hpp,
319 return 0; 328 return 0;
320 329
321 perf_hpp__for_each_format(fmt) { 330 perf_hpp__for_each_format(fmt) {
331 if (perf_hpp__should_skip(fmt))
332 continue;
333
322 /* 334 /*
323 * If there's no field_sep, we still need 335 * If there's no field_sep, we still need
324 * to display initial ' '. 336 * to display initial ' '.
@@ -353,8 +365,7 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
353 if (size == 0 || size > bfsz) 365 if (size == 0 || size > bfsz)
354 size = hpp.size = bfsz; 366 size = hpp.size = bfsz;
355 367
356 ret = hist_entry__period_snprintf(&hpp, he); 368 hist_entry__snprintf(he, &hpp);
357 hist_entry__sort_snprintf(he, bf + ret, size - ret, hists);
358 369
359 ret = fprintf(fp, "%s\n", bf); 370 ret = fprintf(fp, "%s\n", bf);
360 371
@@ -368,12 +379,10 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
368 int max_cols, float min_pcnt, FILE *fp) 379 int max_cols, float min_pcnt, FILE *fp)
369{ 380{
370 struct perf_hpp_fmt *fmt; 381 struct perf_hpp_fmt *fmt;
371 struct sort_entry *se;
372 struct rb_node *nd; 382 struct rb_node *nd;
373 size_t ret = 0; 383 size_t ret = 0;
374 unsigned int width; 384 unsigned int width;
375 const char *sep = symbol_conf.field_sep; 385 const char *sep = symbol_conf.field_sep;
376 const char *col_width = symbol_conf.col_width_list_str;
377 int nr_rows = 0; 386 int nr_rows = 0;
378 char bf[96]; 387 char bf[96];
379 struct perf_hpp dummy_hpp = { 388 struct perf_hpp dummy_hpp = {
@@ -386,12 +395,19 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
386 395
387 init_rem_hits(); 396 init_rem_hits();
388 397
398
399 perf_hpp__for_each_format(fmt)
400 perf_hpp__reset_width(fmt, hists);
401
389 if (!show_header) 402 if (!show_header)
390 goto print_entries; 403 goto print_entries;
391 404
392 fprintf(fp, "# "); 405 fprintf(fp, "# ");
393 406
394 perf_hpp__for_each_format(fmt) { 407 perf_hpp__for_each_format(fmt) {
408 if (perf_hpp__should_skip(fmt))
409 continue;
410
395 if (!first) 411 if (!first)
396 fprintf(fp, "%s", sep ?: " "); 412 fprintf(fp, "%s", sep ?: " ");
397 else 413 else
@@ -401,28 +417,6 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
401 fprintf(fp, "%s", bf); 417 fprintf(fp, "%s", bf);
402 } 418 }
403 419
404 list_for_each_entry(se, &hist_entry__sort_list, list) {
405 if (se->elide)
406 continue;
407 if (sep) {
408 fprintf(fp, "%c%s", *sep, se->se_header);
409 continue;
410 }
411 width = strlen(se->se_header);
412 if (symbol_conf.col_width_list_str) {
413 if (col_width) {
414 hists__set_col_len(hists, se->se_width_idx,
415 atoi(col_width));
416 col_width = strchr(col_width, ',');
417 if (col_width)
418 ++col_width;
419 }
420 }
421 if (!hists__new_col_len(hists, se->se_width_idx, width))
422 width = hists__col_len(hists, se->se_width_idx);
423 fprintf(fp, " %*s", width, se->se_header);
424 }
425
426 fprintf(fp, "\n"); 420 fprintf(fp, "\n");
427 if (max_rows && ++nr_rows >= max_rows) 421 if (max_rows && ++nr_rows >= max_rows)
428 goto out; 422 goto out;
@@ -437,6 +431,9 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
437 perf_hpp__for_each_format(fmt) { 431 perf_hpp__for_each_format(fmt) {
438 unsigned int i; 432 unsigned int i;
439 433
434 if (perf_hpp__should_skip(fmt))
435 continue;
436
440 if (!first) 437 if (!first)
441 fprintf(fp, "%s", sep ?: " "); 438 fprintf(fp, "%s", sep ?: " ");
442 else 439 else
@@ -447,20 +444,6 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
447 fprintf(fp, "."); 444 fprintf(fp, ".");
448 } 445 }
449 446
450 list_for_each_entry(se, &hist_entry__sort_list, list) {
451 unsigned int i;
452
453 if (se->elide)
454 continue;
455
456 fprintf(fp, " ");
457 width = hists__col_len(hists, se->se_width_idx);
458 if (width == 0)
459 width = strlen(se->se_header);
460 for (i = 0; i < width; i++)
461 fprintf(fp, ".");
462 }
463
464 fprintf(fp, "\n"); 447 fprintf(fp, "\n");
465 if (max_rows && ++nr_rows >= max_rows) 448 if (max_rows && ++nr_rows >= max_rows)
466 goto out; 449 goto out;
@@ -480,12 +463,12 @@ print_entries:
480 463
481 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 464 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
482 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 465 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
483 float percent = h->stat.period * 100.0 / 466 float percent;
484 hists->stats.total_period;
485 467
486 if (h->filtered) 468 if (h->filtered)
487 continue; 469 continue;
488 470
471 percent = hist_entry__get_percent_limit(h);
489 if (percent < min_pcnt) 472 if (percent < min_pcnt)
490 continue; 473 continue;
491 474
@@ -495,7 +478,7 @@ print_entries:
495 break; 478 break;
496 479
497 if (h->ms.map == NULL && verbose > 1) { 480 if (h->ms.map == NULL && verbose > 1) {
498 __map_groups__fprintf_maps(&h->thread->mg, 481 __map_groups__fprintf_maps(h->thread->mg,
499 MAP__FUNCTION, verbose, fp); 482 MAP__FUNCTION, verbose, fp);
500 fprintf(fp, "%.10s end\n", graph_dotted_line); 483 fprintf(fp, "%.10s end\n", graph_dotted_line);
501 } 484 }
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index 56ad4f5287de..112d6e268150 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -3,7 +3,7 @@
3 3
4#include <stdbool.h> 4#include <stdbool.h>
5#include <stdint.h> 5#include <stdint.h>
6#include "types.h" 6#include <linux/types.h>
7#include "symbol.h" 7#include "symbol.h"
8#include "hist.h" 8#include "hist.h"
9#include "sort.h" 9#include "sort.h"
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 6baabe63182b..a904a4cfe7d3 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -25,7 +25,7 @@ int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused,
25 struct addr_location al; 25 struct addr_location al;
26 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 26 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
27 struct thread *thread = machine__findnew_thread(machine, sample->pid, 27 struct thread *thread = machine__findnew_thread(machine, sample->pid,
28 sample->pid); 28 sample->tid);
29 29
30 if (thread == NULL) { 30 if (thread == NULL) {
31 pr_err("problem processing %d event, skipping it.\n", 31 pr_err("problem processing %d event, skipping it.\n",
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
index 845ef865eced..ae392561470b 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -4,7 +4,7 @@
4#define BUILD_ID_SIZE 20 4#define BUILD_ID_SIZE 20
5 5
6#include "tool.h" 6#include "tool.h"
7#include "types.h" 7#include <linux/types.h>
8 8
9extern struct perf_tool build_id__mark_dso_hit_ops; 9extern struct perf_tool build_id__mark_dso_hit_ops;
10struct dso; 10struct dso;
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 8d9db454f1a9..48b6d3f50012 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -25,6 +25,84 @@
25 25
26__thread struct callchain_cursor callchain_cursor; 26__thread struct callchain_cursor callchain_cursor;
27 27
28int
29parse_callchain_report_opt(const char *arg)
30{
31 char *tok, *tok2;
32 char *endptr;
33
34 symbol_conf.use_callchain = true;
35
36 if (!arg)
37 return 0;
38
39 tok = strtok((char *)arg, ",");
40 if (!tok)
41 return -1;
42
43 /* get the output mode */
44 if (!strncmp(tok, "graph", strlen(arg))) {
45 callchain_param.mode = CHAIN_GRAPH_ABS;
46
47 } else if (!strncmp(tok, "flat", strlen(arg))) {
48 callchain_param.mode = CHAIN_FLAT;
49 } else if (!strncmp(tok, "fractal", strlen(arg))) {
50 callchain_param.mode = CHAIN_GRAPH_REL;
51 } else if (!strncmp(tok, "none", strlen(arg))) {
52 callchain_param.mode = CHAIN_NONE;
53 symbol_conf.use_callchain = false;
54 return 0;
55 } else {
56 return -1;
57 }
58
59 /* get the min percentage */
60 tok = strtok(NULL, ",");
61 if (!tok)
62 goto setup;
63
64 callchain_param.min_percent = strtod(tok, &endptr);
65 if (tok == endptr)
66 return -1;
67
68 /* get the print limit */
69 tok2 = strtok(NULL, ",");
70 if (!tok2)
71 goto setup;
72
73 if (tok2[0] != 'c') {
74 callchain_param.print_limit = strtoul(tok2, &endptr, 0);
75 tok2 = strtok(NULL, ",");
76 if (!tok2)
77 goto setup;
78 }
79
80 /* get the call chain order */
81 if (!strncmp(tok2, "caller", strlen("caller")))
82 callchain_param.order = ORDER_CALLER;
83 else if (!strncmp(tok2, "callee", strlen("callee")))
84 callchain_param.order = ORDER_CALLEE;
85 else
86 return -1;
87
88 /* Get the sort key */
89 tok2 = strtok(NULL, ",");
90 if (!tok2)
91 goto setup;
92 if (!strncmp(tok2, "function", strlen("function")))
93 callchain_param.key = CCKEY_FUNCTION;
94 else if (!strncmp(tok2, "address", strlen("address")))
95 callchain_param.key = CCKEY_ADDRESS;
96 else
97 return -1;
98setup:
99 if (callchain_register_param(&callchain_param) < 0) {
100 pr_err("Can't register callchain params\n");
101 return -1;
102 }
103 return 0;
104}
105
28static void 106static void
29rb_insert_callchain(struct rb_root *root, struct callchain_node *chain, 107rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
30 enum chain_mode mode) 108 enum chain_mode mode)
@@ -538,7 +616,8 @@ int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent
538 if (sample->callchain == NULL) 616 if (sample->callchain == NULL)
539 return 0; 617 return 0;
540 618
541 if (symbol_conf.use_callchain || sort__has_parent) { 619 if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain ||
620 sort__has_parent) {
542 return machine__resolve_callchain(al->machine, evsel, al->thread, 621 return machine__resolve_callchain(al->machine, evsel, al->thread,
543 sample, parent, al, max_stack); 622 sample, parent, al, max_stack);
544 } 623 }
@@ -551,3 +630,45 @@ int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *samp
551 return 0; 630 return 0;
552 return callchain_append(he->callchain, &callchain_cursor, sample->period); 631 return callchain_append(he->callchain, &callchain_cursor, sample->period);
553} 632}
633
634int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *node,
635 bool hide_unresolved)
636{
637 al->map = node->map;
638 al->sym = node->sym;
639 if (node->map)
640 al->addr = node->map->map_ip(node->map, node->ip);
641 else
642 al->addr = node->ip;
643
644 if (al->sym == NULL) {
645 if (hide_unresolved)
646 return 0;
647 if (al->map == NULL)
648 goto out;
649 }
650
651 if (al->map->groups == &al->machine->kmaps) {
652 if (machine__is_host(al->machine)) {
653 al->cpumode = PERF_RECORD_MISC_KERNEL;
654 al->level = 'k';
655 } else {
656 al->cpumode = PERF_RECORD_MISC_GUEST_KERNEL;
657 al->level = 'g';
658 }
659 } else {
660 if (machine__is_host(al->machine)) {
661 al->cpumode = PERF_RECORD_MISC_USER;
662 al->level = '.';
663 } else if (perf_guest) {
664 al->cpumode = PERF_RECORD_MISC_GUEST_USER;
665 al->level = 'u';
666 } else {
667 al->cpumode = PERF_RECORD_MISC_HYPERVISOR;
668 al->level = 'H';
669 }
670 }
671
672out:
673 return 1;
674}
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 8ad97e9b119f..8f84423a75da 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -7,6 +7,13 @@
7#include "event.h" 7#include "event.h"
8#include "symbol.h" 8#include "symbol.h"
9 9
10enum perf_call_graph_mode {
11 CALLCHAIN_NONE,
12 CALLCHAIN_FP,
13 CALLCHAIN_DWARF,
14 CALLCHAIN_MAX
15};
16
10enum chain_mode { 17enum chain_mode {
11 CHAIN_NONE, 18 CHAIN_NONE,
12 CHAIN_FLAT, 19 CHAIN_FLAT,
@@ -155,6 +162,18 @@ int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent
155 struct perf_evsel *evsel, struct addr_location *al, 162 struct perf_evsel *evsel, struct addr_location *al,
156 int max_stack); 163 int max_stack);
157int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample); 164int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample);
165int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *node,
166 bool hide_unresolved);
158 167
159extern const char record_callchain_help[]; 168extern const char record_callchain_help[];
169int parse_callchain_report_opt(const char *arg);
170
171static inline void callchain_cursor_snapshot(struct callchain_cursor *dest,
172 struct callchain_cursor *src)
173{
174 *dest = *src;
175
176 dest->first = src->curr;
177 dest->nr -= src->pos;
178}
160#endif /* __PERF_CALLCHAIN_H */ 179#endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index 3e0fdd369ccb..24519e14ac56 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -11,6 +11,7 @@
11#include "util.h" 11#include "util.h"
12#include "cache.h" 12#include "cache.h"
13#include "exec_cmd.h" 13#include "exec_cmd.h"
14#include "util/hist.h" /* perf_hist_config */
14 15
15#define MAXNAME (256) 16#define MAXNAME (256)
16 17
@@ -355,6 +356,9 @@ int perf_default_config(const char *var, const char *value,
355 if (!prefixcmp(var, "core.")) 356 if (!prefixcmp(var, "core."))
356 return perf_default_core_config(var, value); 357 return perf_default_core_config(var, value);
357 358
359 if (!prefixcmp(var, "hist."))
360 return perf_hist_config(var, value);
361
358 /* Add other config variables here. */ 362 /* Add other config variables here. */
359 return 0; 363 return 0;
360} 364}
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
index 7fe4994eeb63..c4e55b71010c 100644
--- a/tools/perf/util/cpumap.c
+++ b/tools/perf/util/cpumap.c
@@ -317,3 +317,163 @@ int cpu_map__build_core_map(struct cpu_map *cpus, struct cpu_map **corep)
317{ 317{
318 return cpu_map__build_map(cpus, corep, cpu_map__get_core); 318 return cpu_map__build_map(cpus, corep, cpu_map__get_core);
319} 319}
320
321/* setup simple routines to easily access node numbers given a cpu number */
322static int get_max_num(char *path, int *max)
323{
324 size_t num;
325 char *buf;
326 int err = 0;
327
328 if (filename__read_str(path, &buf, &num))
329 return -1;
330
331 buf[num] = '\0';
332
333 /* start on the right, to find highest node num */
334 while (--num) {
335 if ((buf[num] == ',') || (buf[num] == '-')) {
336 num++;
337 break;
338 }
339 }
340 if (sscanf(&buf[num], "%d", max) < 1) {
341 err = -1;
342 goto out;
343 }
344
345 /* convert from 0-based to 1-based */
346 (*max)++;
347
348out:
349 free(buf);
350 return err;
351}
352
353/* Determine highest possible cpu in the system for sparse allocation */
354static void set_max_cpu_num(void)
355{
356 const char *mnt;
357 char path[PATH_MAX];
358 int ret = -1;
359
360 /* set up default */
361 max_cpu_num = 4096;
362
363 mnt = sysfs__mountpoint();
364 if (!mnt)
365 goto out;
366
367 /* get the highest possible cpu number for a sparse allocation */
368 ret = snprintf(path, PATH_MAX, "%s/devices/system/cpu/possible", mnt);
369 if (ret == PATH_MAX) {
370 pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX);
371 goto out;
372 }
373
374 ret = get_max_num(path, &max_cpu_num);
375
376out:
377 if (ret)
378 pr_err("Failed to read max cpus, using default of %d\n", max_cpu_num);
379}
380
381/* Determine highest possible node in the system for sparse allocation */
382static void set_max_node_num(void)
383{
384 const char *mnt;
385 char path[PATH_MAX];
386 int ret = -1;
387
388 /* set up default */
389 max_node_num = 8;
390
391 mnt = sysfs__mountpoint();
392 if (!mnt)
393 goto out;
394
395 /* get the highest possible cpu number for a sparse allocation */
396 ret = snprintf(path, PATH_MAX, "%s/devices/system/node/possible", mnt);
397 if (ret == PATH_MAX) {
398 pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX);
399 goto out;
400 }
401
402 ret = get_max_num(path, &max_node_num);
403
404out:
405 if (ret)
406 pr_err("Failed to read max nodes, using default of %d\n", max_node_num);
407}
408
409static int init_cpunode_map(void)
410{
411 int i;
412
413 set_max_cpu_num();
414 set_max_node_num();
415
416 cpunode_map = calloc(max_cpu_num, sizeof(int));
417 if (!cpunode_map) {
418 pr_err("%s: calloc failed\n", __func__);
419 return -1;
420 }
421
422 for (i = 0; i < max_cpu_num; i++)
423 cpunode_map[i] = -1;
424
425 return 0;
426}
427
428int cpu__setup_cpunode_map(void)
429{
430 struct dirent *dent1, *dent2;
431 DIR *dir1, *dir2;
432 unsigned int cpu, mem;
433 char buf[PATH_MAX];
434 char path[PATH_MAX];
435 const char *mnt;
436 int n;
437
438 /* initialize globals */
439 if (init_cpunode_map())
440 return -1;
441
442 mnt = sysfs__mountpoint();
443 if (!mnt)
444 return 0;
445
446 n = snprintf(path, PATH_MAX, "%s/devices/system/node", mnt);
447 if (n == PATH_MAX) {
448 pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX);
449 return -1;
450 }
451
452 dir1 = opendir(path);
453 if (!dir1)
454 return 0;
455
456 /* walk tree and setup map */
457 while ((dent1 = readdir(dir1)) != NULL) {
458 if (dent1->d_type != DT_DIR || sscanf(dent1->d_name, "node%u", &mem) < 1)
459 continue;
460
461 n = snprintf(buf, PATH_MAX, "%s/%s", path, dent1->d_name);
462 if (n == PATH_MAX) {
463 pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX);
464 continue;
465 }
466
467 dir2 = opendir(buf);
468 if (!dir2)
469 continue;
470 while ((dent2 = readdir(dir2)) != NULL) {
471 if (dent2->d_type != DT_LNK || sscanf(dent2->d_name, "cpu%u", &cpu) < 1)
472 continue;
473 cpunode_map[cpu] = mem;
474 }
475 closedir(dir2);
476 }
477 closedir(dir1);
478 return 0;
479}
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
index b123bb9d6f55..61a654849002 100644
--- a/tools/perf/util/cpumap.h
+++ b/tools/perf/util/cpumap.h
@@ -4,6 +4,9 @@
4#include <stdio.h> 4#include <stdio.h>
5#include <stdbool.h> 5#include <stdbool.h>
6 6
7#include "perf.h"
8#include "util/debug.h"
9
7struct cpu_map { 10struct cpu_map {
8 int nr; 11 int nr;
9 int map[]; 12 int map[];
@@ -46,4 +49,36 @@ static inline bool cpu_map__empty(const struct cpu_map *map)
46 return map ? map->map[0] == -1 : true; 49 return map ? map->map[0] == -1 : true;
47} 50}
48 51
52int max_cpu_num;
53int max_node_num;
54int *cpunode_map;
55
56int cpu__setup_cpunode_map(void);
57
58static inline int cpu__max_node(void)
59{
60 if (unlikely(!max_node_num))
61 pr_debug("cpu_map not initialized\n");
62
63 return max_node_num;
64}
65
66static inline int cpu__max_cpu(void)
67{
68 if (unlikely(!max_cpu_num))
69 pr_debug("cpu_map not initialized\n");
70
71 return max_cpu_num;
72}
73
74static inline int cpu__get_node(int cpu)
75{
76 if (unlikely(cpunode_map == NULL)) {
77 pr_debug("cpu_map not initialized\n");
78 return -1;
79 }
80
81 return cpunode_map[cpu];
82}
83
49#endif /* __PERF_CPUMAP_H */ 84#endif /* __PERF_CPUMAP_H */
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index 64453d63b971..819f10414f08 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -1,3 +1,6 @@
1#include <asm/bug.h>
2#include <sys/time.h>
3#include <sys/resource.h>
1#include "symbol.h" 4#include "symbol.h"
2#include "dso.h" 5#include "dso.h"
3#include "machine.h" 6#include "machine.h"
@@ -136,7 +139,48 @@ int dso__read_binary_type_filename(const struct dso *dso,
136 return ret; 139 return ret;
137} 140}
138 141
139static int open_dso(struct dso *dso, struct machine *machine) 142/*
143 * Global list of open DSOs and the counter.
144 */
145static LIST_HEAD(dso__data_open);
146static long dso__data_open_cnt;
147
148static void dso__list_add(struct dso *dso)
149{
150 list_add_tail(&dso->data.open_entry, &dso__data_open);
151 dso__data_open_cnt++;
152}
153
154static void dso__list_del(struct dso *dso)
155{
156 list_del(&dso->data.open_entry);
157 WARN_ONCE(dso__data_open_cnt <= 0,
158 "DSO data fd counter out of bounds.");
159 dso__data_open_cnt--;
160}
161
162static void close_first_dso(void);
163
164static int do_open(char *name)
165{
166 int fd;
167
168 do {
169 fd = open(name, O_RDONLY);
170 if (fd >= 0)
171 return fd;
172
173 pr_debug("dso open failed, mmap: %s\n", strerror(errno));
174 if (!dso__data_open_cnt || errno != EMFILE)
175 break;
176
177 close_first_dso();
178 } while (1);
179
180 return -1;
181}
182
183static int __open_dso(struct dso *dso, struct machine *machine)
140{ 184{
141 int fd; 185 int fd;
142 char *root_dir = (char *)""; 186 char *root_dir = (char *)"";
@@ -154,11 +198,130 @@ static int open_dso(struct dso *dso, struct machine *machine)
154 return -EINVAL; 198 return -EINVAL;
155 } 199 }
156 200
157 fd = open(name, O_RDONLY); 201 fd = do_open(name);
158 free(name); 202 free(name);
159 return fd; 203 return fd;
160} 204}
161 205
206static void check_data_close(void);
207
208/**
209 * dso_close - Open DSO data file
210 * @dso: dso object
211 *
212 * Open @dso's data file descriptor and updates
213 * list/count of open DSO objects.
214 */
215static int open_dso(struct dso *dso, struct machine *machine)
216{
217 int fd = __open_dso(dso, machine);
218
219 if (fd > 0) {
220 dso__list_add(dso);
221 /*
222 * Check if we crossed the allowed number
223 * of opened DSOs and close one if needed.
224 */
225 check_data_close();
226 }
227
228 return fd;
229}
230
231static void close_data_fd(struct dso *dso)
232{
233 if (dso->data.fd >= 0) {
234 close(dso->data.fd);
235 dso->data.fd = -1;
236 dso->data.file_size = 0;
237 dso__list_del(dso);
238 }
239}
240
241/**
242 * dso_close - Close DSO data file
243 * @dso: dso object
244 *
245 * Close @dso's data file descriptor and updates
246 * list/count of open DSO objects.
247 */
248static void close_dso(struct dso *dso)
249{
250 close_data_fd(dso);
251}
252
253static void close_first_dso(void)
254{
255 struct dso *dso;
256
257 dso = list_first_entry(&dso__data_open, struct dso, data.open_entry);
258 close_dso(dso);
259}
260
261static rlim_t get_fd_limit(void)
262{
263 struct rlimit l;
264 rlim_t limit = 0;
265
266 /* Allow half of the current open fd limit. */
267 if (getrlimit(RLIMIT_NOFILE, &l) == 0) {
268 if (l.rlim_cur == RLIM_INFINITY)
269 limit = l.rlim_cur;
270 else
271 limit = l.rlim_cur / 2;
272 } else {
273 pr_err("failed to get fd limit\n");
274 limit = 1;
275 }
276
277 return limit;
278}
279
280static bool may_cache_fd(void)
281{
282 static rlim_t limit;
283
284 if (!limit)
285 limit = get_fd_limit();
286
287 if (limit == RLIM_INFINITY)
288 return true;
289
290 return limit > (rlim_t) dso__data_open_cnt;
291}
292
293/*
294 * Check and close LRU dso if we crossed allowed limit
295 * for opened dso file descriptors. The limit is half
296 * of the RLIMIT_NOFILE files opened.
297*/
298static void check_data_close(void)
299{
300 bool cache_fd = may_cache_fd();
301
302 if (!cache_fd)
303 close_first_dso();
304}
305
306/**
307 * dso__data_close - Close DSO data file
308 * @dso: dso object
309 *
310 * External interface to close @dso's data file descriptor.
311 */
312void dso__data_close(struct dso *dso)
313{
314 close_dso(dso);
315}
316
317/**
318 * dso__data_fd - Get dso's data file descriptor
319 * @dso: dso object
320 * @machine: machine object
321 *
322 * External interface to find dso's file, open it and
323 * returns file descriptor.
324 */
162int dso__data_fd(struct dso *dso, struct machine *machine) 325int dso__data_fd(struct dso *dso, struct machine *machine)
163{ 326{
164 enum dso_binary_type binary_type_data[] = { 327 enum dso_binary_type binary_type_data[] = {
@@ -168,8 +331,13 @@ int dso__data_fd(struct dso *dso, struct machine *machine)
168 }; 331 };
169 int i = 0; 332 int i = 0;
170 333
171 if (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND) 334 if (dso->data.fd >= 0)
172 return open_dso(dso, machine); 335 return dso->data.fd;
336
337 if (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND) {
338 dso->data.fd = open_dso(dso, machine);
339 return dso->data.fd;
340 }
173 341
174 do { 342 do {
175 int fd; 343 int fd;
@@ -178,7 +346,7 @@ int dso__data_fd(struct dso *dso, struct machine *machine)
178 346
179 fd = open_dso(dso, machine); 347 fd = open_dso(dso, machine);
180 if (fd >= 0) 348 if (fd >= 0)
181 return fd; 349 return dso->data.fd = fd;
182 350
183 } while (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND); 351 } while (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND);
184 352
@@ -260,16 +428,10 @@ dso_cache__memcpy(struct dso_cache *cache, u64 offset,
260} 428}
261 429
262static ssize_t 430static ssize_t
263dso_cache__read(struct dso *dso, struct machine *machine, 431dso_cache__read(struct dso *dso, u64 offset, u8 *data, ssize_t size)
264 u64 offset, u8 *data, ssize_t size)
265{ 432{
266 struct dso_cache *cache; 433 struct dso_cache *cache;
267 ssize_t ret; 434 ssize_t ret;
268 int fd;
269
270 fd = dso__data_fd(dso, machine);
271 if (fd < 0)
272 return -1;
273 435
274 do { 436 do {
275 u64 cache_offset; 437 u64 cache_offset;
@@ -283,16 +445,16 @@ dso_cache__read(struct dso *dso, struct machine *machine,
283 cache_offset = offset & DSO__DATA_CACHE_MASK; 445 cache_offset = offset & DSO__DATA_CACHE_MASK;
284 ret = -EINVAL; 446 ret = -EINVAL;
285 447
286 if (-1 == lseek(fd, cache_offset, SEEK_SET)) 448 if (-1 == lseek(dso->data.fd, cache_offset, SEEK_SET))
287 break; 449 break;
288 450
289 ret = read(fd, cache->data, DSO__DATA_CACHE_SIZE); 451 ret = read(dso->data.fd, cache->data, DSO__DATA_CACHE_SIZE);
290 if (ret <= 0) 452 if (ret <= 0)
291 break; 453 break;
292 454
293 cache->offset = cache_offset; 455 cache->offset = cache_offset;
294 cache->size = ret; 456 cache->size = ret;
295 dso_cache__insert(&dso->cache, cache); 457 dso_cache__insert(&dso->data.cache, cache);
296 458
297 ret = dso_cache__memcpy(cache, offset, data, size); 459 ret = dso_cache__memcpy(cache, offset, data, size);
298 460
@@ -301,24 +463,27 @@ dso_cache__read(struct dso *dso, struct machine *machine,
301 if (ret <= 0) 463 if (ret <= 0)
302 free(cache); 464 free(cache);
303 465
304 close(fd);
305 return ret; 466 return ret;
306} 467}
307 468
308static ssize_t dso_cache_read(struct dso *dso, struct machine *machine, 469static ssize_t dso_cache_read(struct dso *dso, u64 offset,
309 u64 offset, u8 *data, ssize_t size) 470 u8 *data, ssize_t size)
310{ 471{
311 struct dso_cache *cache; 472 struct dso_cache *cache;
312 473
313 cache = dso_cache__find(&dso->cache, offset); 474 cache = dso_cache__find(&dso->data.cache, offset);
314 if (cache) 475 if (cache)
315 return dso_cache__memcpy(cache, offset, data, size); 476 return dso_cache__memcpy(cache, offset, data, size);
316 else 477 else
317 return dso_cache__read(dso, machine, offset, data, size); 478 return dso_cache__read(dso, offset, data, size);
318} 479}
319 480
320ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, 481/*
321 u64 offset, u8 *data, ssize_t size) 482 * Reads and caches dso data DSO__DATA_CACHE_SIZE size chunks
483 * in the rb_tree. Any read to already cached data is served
484 * by cached data.
485 */
486static ssize_t cached_read(struct dso *dso, u64 offset, u8 *data, ssize_t size)
322{ 487{
323 ssize_t r = 0; 488 ssize_t r = 0;
324 u8 *p = data; 489 u8 *p = data;
@@ -326,7 +491,7 @@ ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
326 do { 491 do {
327 ssize_t ret; 492 ssize_t ret;
328 493
329 ret = dso_cache_read(dso, machine, offset, p, size); 494 ret = dso_cache_read(dso, offset, p, size);
330 if (ret < 0) 495 if (ret < 0)
331 return ret; 496 return ret;
332 497
@@ -346,6 +511,67 @@ ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
346 return r; 511 return r;
347} 512}
348 513
514static int data_file_size(struct dso *dso)
515{
516 struct stat st;
517
518 if (!dso->data.file_size) {
519 if (fstat(dso->data.fd, &st)) {
520 pr_err("dso mmap failed, fstat: %s\n", strerror(errno));
521 return -1;
522 }
523 dso->data.file_size = st.st_size;
524 }
525
526 return 0;
527}
528
529static ssize_t data_read_offset(struct dso *dso, u64 offset,
530 u8 *data, ssize_t size)
531{
532 if (data_file_size(dso))
533 return -1;
534
535 /* Check the offset sanity. */
536 if (offset > dso->data.file_size)
537 return -1;
538
539 if (offset + size < offset)
540 return -1;
541
542 return cached_read(dso, offset, data, size);
543}
544
545/**
546 * dso__data_read_offset - Read data from dso file offset
547 * @dso: dso object
548 * @machine: machine object
549 * @offset: file offset
550 * @data: buffer to store data
551 * @size: size of the @data buffer
552 *
553 * External interface to read data from dso file offset. Open
554 * dso data file and use cached_read to get the data.
555 */
556ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
557 u64 offset, u8 *data, ssize_t size)
558{
559 if (dso__data_fd(dso, machine) < 0)
560 return -1;
561
562 return data_read_offset(dso, offset, data, size);
563}
564
565/**
566 * dso__data_read_addr - Read data from dso address
567 * @dso: dso object
568 * @machine: machine object
569 * @add: virtual memory address
570 * @data: buffer to store data
571 * @size: size of the @data buffer
572 *
573 * External interface to read data from dso address.
574 */
349ssize_t dso__data_read_addr(struct dso *dso, struct map *map, 575ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
350 struct machine *machine, u64 addr, 576 struct machine *machine, u64 addr,
351 u8 *data, ssize_t size) 577 u8 *data, ssize_t size)
@@ -473,7 +699,8 @@ struct dso *dso__new(const char *name)
473 dso__set_short_name(dso, dso->name, false); 699 dso__set_short_name(dso, dso->name, false);
474 for (i = 0; i < MAP__NR_TYPES; ++i) 700 for (i = 0; i < MAP__NR_TYPES; ++i)
475 dso->symbols[i] = dso->symbol_names[i] = RB_ROOT; 701 dso->symbols[i] = dso->symbol_names[i] = RB_ROOT;
476 dso->cache = RB_ROOT; 702 dso->data.cache = RB_ROOT;
703 dso->data.fd = -1;
477 dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND; 704 dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND;
478 dso->binary_type = DSO_BINARY_TYPE__NOT_FOUND; 705 dso->binary_type = DSO_BINARY_TYPE__NOT_FOUND;
479 dso->loaded = 0; 706 dso->loaded = 0;
@@ -485,6 +712,7 @@ struct dso *dso__new(const char *name)
485 dso->kernel = DSO_TYPE_USER; 712 dso->kernel = DSO_TYPE_USER;
486 dso->needs_swap = DSO_SWAP__UNSET; 713 dso->needs_swap = DSO_SWAP__UNSET;
487 INIT_LIST_HEAD(&dso->node); 714 INIT_LIST_HEAD(&dso->node);
715 INIT_LIST_HEAD(&dso->data.open_entry);
488 } 716 }
489 717
490 return dso; 718 return dso;
@@ -506,7 +734,8 @@ void dso__delete(struct dso *dso)
506 dso->long_name_allocated = false; 734 dso->long_name_allocated = false;
507 } 735 }
508 736
509 dso_cache__free(&dso->cache); 737 dso__data_close(dso);
738 dso_cache__free(&dso->data.cache);
510 dso__free_a2l(dso); 739 dso__free_a2l(dso);
511 zfree(&dso->symsrc_filename); 740 zfree(&dso->symsrc_filename);
512 free(dso); 741 free(dso);
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index ab06f1c03655..ad553ba257bf 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -4,7 +4,7 @@
4#include <linux/types.h> 4#include <linux/types.h>
5#include <linux/rbtree.h> 5#include <linux/rbtree.h>
6#include <stdbool.h> 6#include <stdbool.h>
7#include "types.h" 7#include <linux/types.h>
8#include "map.h" 8#include "map.h"
9#include "build-id.h" 9#include "build-id.h"
10 10
@@ -76,7 +76,6 @@ struct dso {
76 struct list_head node; 76 struct list_head node;
77 struct rb_root symbols[MAP__NR_TYPES]; 77 struct rb_root symbols[MAP__NR_TYPES];
78 struct rb_root symbol_names[MAP__NR_TYPES]; 78 struct rb_root symbol_names[MAP__NR_TYPES];
79 struct rb_root cache;
80 void *a2l; 79 void *a2l;
81 char *symsrc_filename; 80 char *symsrc_filename;
82 unsigned int a2l_fails; 81 unsigned int a2l_fails;
@@ -99,6 +98,15 @@ struct dso {
99 const char *long_name; 98 const char *long_name;
100 u16 long_name_len; 99 u16 long_name_len;
101 u16 short_name_len; 100 u16 short_name_len;
101
102 /* dso data file */
103 struct {
104 struct rb_root cache;
105 int fd;
106 size_t file_size;
107 struct list_head open_entry;
108 } data;
109
102 char name[0]; 110 char name[0];
103}; 111};
104 112
@@ -141,7 +149,47 @@ char dso__symtab_origin(const struct dso *dso);
141int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type type, 149int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type type,
142 char *root_dir, char *filename, size_t size); 150 char *root_dir, char *filename, size_t size);
143 151
152/*
153 * The dso__data_* external interface provides following functions:
154 * dso__data_fd
155 * dso__data_close
156 * dso__data_read_offset
157 * dso__data_read_addr
158 *
159 * Please refer to the dso.c object code for each function and
160 * arguments documentation. Following text tries to explain the
161 * dso file descriptor caching.
162 *
163 * The dso__data* interface allows caching of opened file descriptors
164 * to speed up the dso data accesses. The idea is to leave the file
165 * descriptor opened ideally for the whole life of the dso object.
166 *
167 * The current usage of the dso__data_* interface is as follows:
168 *
169 * Get DSO's fd:
170 * int fd = dso__data_fd(dso, machine);
171 * USE 'fd' SOMEHOW
172 *
173 * Read DSO's data:
174 * n = dso__data_read_offset(dso_0, &machine, 0, buf, BUFSIZE);
175 * n = dso__data_read_addr(dso_0, &machine, 0, buf, BUFSIZE);
176 *
177 * Eventually close DSO's fd:
178 * dso__data_close(dso);
179 *
180 * It is not necessary to close the DSO object data file. Each time new
181 * DSO data file is opened, the limit (RLIMIT_NOFILE/2) is checked. Once
182 * it is crossed, the oldest opened DSO object is closed.
183 *
184 * The dso__delete function calls close_dso function to ensure the
185 * data file descriptor gets closed/unmapped before the dso object
186 * is freed.
187 *
188 * TODO
189*/
144int dso__data_fd(struct dso *dso, struct machine *machine); 190int dso__data_fd(struct dso *dso, struct machine *machine);
191void dso__data_close(struct dso *dso);
192
145ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, 193ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
146 u64 offset, u8 *data, ssize_t size); 194 u64 offset, u8 *data, ssize_t size);
147ssize_t dso__data_read_addr(struct dso *dso, struct map *map, 195ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c
index 7defd77105d0..cc66c4049e09 100644
--- a/tools/perf/util/dwarf-aux.c
+++ b/tools/perf/util/dwarf-aux.c
@@ -747,14 +747,17 @@ struct __find_variable_param {
747static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data) 747static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data)
748{ 748{
749 struct __find_variable_param *fvp = data; 749 struct __find_variable_param *fvp = data;
750 Dwarf_Attribute attr;
750 int tag; 751 int tag;
751 752
752 tag = dwarf_tag(die_mem); 753 tag = dwarf_tag(die_mem);
753 if ((tag == DW_TAG_formal_parameter || 754 if ((tag == DW_TAG_formal_parameter ||
754 tag == DW_TAG_variable) && 755 tag == DW_TAG_variable) &&
755 die_compare_name(die_mem, fvp->name)) 756 die_compare_name(die_mem, fvp->name) &&
757 /* Does the DIE have location information or external instance? */
758 (dwarf_attr(die_mem, DW_AT_external, &attr) ||
759 dwarf_attr(die_mem, DW_AT_location, &attr)))
756 return DIE_FIND_CB_END; 760 return DIE_FIND_CB_END;
757
758 if (dwarf_haspc(die_mem, fvp->addr)) 761 if (dwarf_haspc(die_mem, fvp->addr))
759 return DIE_FIND_CB_CONTINUE; 762 return DIE_FIND_CB_CONTINUE;
760 else 763 else
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 9d12aa6dd485..d0281bdfa582 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -1,4 +1,5 @@
1#include <linux/types.h> 1#include <linux/types.h>
2#include <sys/mman.h>
2#include "event.h" 3#include "event.h"
3#include "debug.h" 4#include "debug.h"
4#include "hist.h" 5#include "hist.h"
@@ -178,13 +179,14 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool,
178 return -1; 179 return -1;
179 } 180 }
180 181
181 event->header.type = PERF_RECORD_MMAP; 182 event->header.type = PERF_RECORD_MMAP2;
182 183
183 while (1) { 184 while (1) {
184 char bf[BUFSIZ]; 185 char bf[BUFSIZ];
185 char prot[5]; 186 char prot[5];
186 char execname[PATH_MAX]; 187 char execname[PATH_MAX];
187 char anonstr[] = "//anon"; 188 char anonstr[] = "//anon";
189 unsigned int ino;
188 size_t size; 190 size_t size;
189 ssize_t n; 191 ssize_t n;
190 192
@@ -195,15 +197,20 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool,
195 strcpy(execname, ""); 197 strcpy(execname, "");
196 198
197 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ 199 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
198 n = sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %*x:%*x %*u %s\n", 200 n = sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %x:%x %u %s\n",
199 &event->mmap.start, &event->mmap.len, prot, 201 &event->mmap2.start, &event->mmap2.len, prot,
200 &event->mmap.pgoff, 202 &event->mmap2.pgoff, &event->mmap2.maj,
201 execname); 203 &event->mmap2.min,
204 &ino, execname);
205
202 /* 206 /*
203 * Anon maps don't have the execname. 207 * Anon maps don't have the execname.
204 */ 208 */
205 if (n < 4) 209 if (n < 7)
206 continue; 210 continue;
211
212 event->mmap2.ino = (u64)ino;
213
207 /* 214 /*
208 * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c 215 * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c
209 */ 216 */
@@ -212,6 +219,21 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool,
212 else 219 else
213 event->header.misc = PERF_RECORD_MISC_GUEST_USER; 220 event->header.misc = PERF_RECORD_MISC_GUEST_USER;
214 221
222 /* map protection and flags bits */
223 event->mmap2.prot = 0;
224 event->mmap2.flags = 0;
225 if (prot[0] == 'r')
226 event->mmap2.prot |= PROT_READ;
227 if (prot[1] == 'w')
228 event->mmap2.prot |= PROT_WRITE;
229 if (prot[2] == 'x')
230 event->mmap2.prot |= PROT_EXEC;
231
232 if (prot[3] == 's')
233 event->mmap2.flags |= MAP_SHARED;
234 else
235 event->mmap2.flags |= MAP_PRIVATE;
236
215 if (prot[2] != 'x') { 237 if (prot[2] != 'x') {
216 if (!mmap_data || prot[0] != 'r') 238 if (!mmap_data || prot[0] != 'r')
217 continue; 239 continue;
@@ -223,15 +245,15 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool,
223 strcpy(execname, anonstr); 245 strcpy(execname, anonstr);
224 246
225 size = strlen(execname) + 1; 247 size = strlen(execname) + 1;
226 memcpy(event->mmap.filename, execname, size); 248 memcpy(event->mmap2.filename, execname, size);
227 size = PERF_ALIGN(size, sizeof(u64)); 249 size = PERF_ALIGN(size, sizeof(u64));
228 event->mmap.len -= event->mmap.start; 250 event->mmap2.len -= event->mmap.start;
229 event->mmap.header.size = (sizeof(event->mmap) - 251 event->mmap2.header.size = (sizeof(event->mmap2) -
230 (sizeof(event->mmap.filename) - size)); 252 (sizeof(event->mmap2.filename) - size));
231 memset(event->mmap.filename + size, 0, machine->id_hdr_size); 253 memset(event->mmap2.filename + size, 0, machine->id_hdr_size);
232 event->mmap.header.size += machine->id_hdr_size; 254 event->mmap2.header.size += machine->id_hdr_size;
233 event->mmap.pid = tgid; 255 event->mmap2.pid = tgid;
234 event->mmap.tid = pid; 256 event->mmap2.tid = pid;
235 257
236 if (process(tool, event, &synth_sample, machine) != 0) { 258 if (process(tool, event, &synth_sample, machine) != 0) {
237 rc = -1; 259 rc = -1;
@@ -612,12 +634,15 @@ size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp)
612size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp) 634size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp)
613{ 635{
614 return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 636 return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64
615 " %02x:%02x %"PRIu64" %"PRIu64"]: %c %s\n", 637 " %02x:%02x %"PRIu64" %"PRIu64"]: %c%c%c%c %s\n",
616 event->mmap2.pid, event->mmap2.tid, event->mmap2.start, 638 event->mmap2.pid, event->mmap2.tid, event->mmap2.start,
617 event->mmap2.len, event->mmap2.pgoff, event->mmap2.maj, 639 event->mmap2.len, event->mmap2.pgoff, event->mmap2.maj,
618 event->mmap2.min, event->mmap2.ino, 640 event->mmap2.min, event->mmap2.ino,
619 event->mmap2.ino_generation, 641 event->mmap2.ino_generation,
620 (event->header.misc & PERF_RECORD_MISC_MMAP_DATA) ? 'r' : 'x', 642 (event->mmap2.prot & PROT_READ) ? 'r' : '-',
643 (event->mmap2.prot & PROT_WRITE) ? 'w' : '-',
644 (event->mmap2.prot & PROT_EXEC) ? 'x' : '-',
645 (event->mmap2.flags & MAP_SHARED) ? 's' : 'p',
621 event->mmap2.filename); 646 event->mmap2.filename);
622} 647}
623 648
@@ -699,7 +724,7 @@ void thread__find_addr_map(struct thread *thread,
699 enum map_type type, u64 addr, 724 enum map_type type, u64 addr,
700 struct addr_location *al) 725 struct addr_location *al)
701{ 726{
702 struct map_groups *mg = &thread->mg; 727 struct map_groups *mg = thread->mg;
703 bool load_map = false; 728 bool load_map = false;
704 729
705 al->machine = machine; 730 al->machine = machine;
@@ -788,7 +813,7 @@ int perf_event__preprocess_sample(const union perf_event *event,
788{ 813{
789 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 814 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
790 struct thread *thread = machine__findnew_thread(machine, sample->pid, 815 struct thread *thread = machine__findnew_thread(machine, sample->pid,
791 sample->pid); 816 sample->tid);
792 817
793 if (thread == NULL) 818 if (thread == NULL)
794 return -1; 819 return -1;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 38457d447a13..e5dd40addb30 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -7,6 +7,7 @@
7#include "../perf.h" 7#include "../perf.h"
8#include "map.h" 8#include "map.h"
9#include "build-id.h" 9#include "build-id.h"
10#include "perf_regs.h"
10 11
11struct mmap_event { 12struct mmap_event {
12 struct perf_event_header header; 13 struct perf_event_header header;
@@ -27,6 +28,8 @@ struct mmap2_event {
27 u32 min; 28 u32 min;
28 u64 ino; 29 u64 ino;
29 u64 ino_generation; 30 u64 ino_generation;
31 u32 prot;
32 u32 flags;
30 char filename[PATH_MAX]; 33 char filename[PATH_MAX];
31}; 34};
32 35
@@ -87,6 +90,10 @@ struct regs_dump {
87 u64 abi; 90 u64 abi;
88 u64 mask; 91 u64 mask;
89 u64 *regs; 92 u64 *regs;
93
94 /* Cached values/mask filled by first register access. */
95 u64 cache_regs[PERF_REGS_MAX];
96 u64 cache_mask;
90}; 97};
91 98
92struct stack_dump { 99struct stack_dump {
@@ -112,6 +119,30 @@ struct sample_read {
112 }; 119 };
113}; 120};
114 121
122struct ip_callchain {
123 u64 nr;
124 u64 ips[0];
125};
126
127struct branch_flags {
128 u64 mispred:1;
129 u64 predicted:1;
130 u64 in_tx:1;
131 u64 abort:1;
132 u64 reserved:60;
133};
134
135struct branch_entry {
136 u64 from;
137 u64 to;
138 struct branch_flags flags;
139};
140
141struct branch_stack {
142 u64 nr;
143 struct branch_entry entries[0];
144};
145
115struct perf_sample { 146struct perf_sample {
116 u64 ip; 147 u64 ip;
117 u32 pid, tid; 148 u32 pid, tid;
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 5c28d82b76c4..8606175fe1e8 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -589,10 +589,10 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
589 } 589 }
590 590
591 /* 591 /*
592 * We default some events to a 1 default interval. But keep 592 * We default some events to have a default interval. But keep
593 * it a weak assumption overridable by the user. 593 * it a weak assumption overridable by the user.
594 */ 594 */
595 if (!attr->sample_period || (opts->user_freq != UINT_MAX && 595 if (!attr->sample_period || (opts->user_freq != UINT_MAX ||
596 opts->user_interval != ULLONG_MAX)) { 596 opts->user_interval != ULLONG_MAX)) {
597 if (opts->freq) { 597 if (opts->freq) {
598 perf_evsel__set_sample_bit(evsel, PERIOD); 598 perf_evsel__set_sample_bit(evsel, PERIOD);
@@ -659,6 +659,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
659 perf_evsel__set_sample_bit(evsel, WEIGHT); 659 perf_evsel__set_sample_bit(evsel, WEIGHT);
660 660
661 attr->mmap = track; 661 attr->mmap = track;
662 attr->mmap2 = track && !perf_missing_features.mmap2;
662 attr->comm = track; 663 attr->comm = track;
663 664
664 if (opts->sample_transaction) 665 if (opts->sample_transaction)
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 0c9926cfb292..a52e9a5bb2d0 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -5,12 +5,12 @@
5#include <stdbool.h> 5#include <stdbool.h>
6#include <stddef.h> 6#include <stddef.h>
7#include <linux/perf_event.h> 7#include <linux/perf_event.h>
8#include "types.h" 8#include <linux/types.h>
9#include "xyarray.h" 9#include "xyarray.h"
10#include "cgroup.h" 10#include "cgroup.h"
11#include "hist.h" 11#include "hist.h"
12#include "symbol.h" 12#include "symbol.h"
13 13
14struct perf_counts_values { 14struct perf_counts_values {
15 union { 15 union {
16 struct { 16 struct {
@@ -91,6 +91,11 @@ struct perf_evsel {
91 char *group_name; 91 char *group_name;
92}; 92};
93 93
94union u64_swap {
95 u64 val64;
96 u32 val32[2];
97};
98
94#define hists_to_evsel(h) container_of(h, struct perf_evsel, hists) 99#define hists_to_evsel(h) container_of(h, struct perf_evsel, hists)
95 100
96struct cpu_map; 101struct cpu_map;
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index a2d047bdf4ef..d08cfe499404 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -4,10 +4,10 @@
4#include <linux/perf_event.h> 4#include <linux/perf_event.h>
5#include <sys/types.h> 5#include <sys/types.h>
6#include <stdbool.h> 6#include <stdbool.h>
7#include "types.h" 7#include <linux/bitmap.h>
8#include <linux/types.h>
8#include "event.h" 9#include "event.h"
9 10
10#include <linux/bitmap.h>
11 11
12enum { 12enum {
13 HEADER_RESERVED = 0, /* always cleared */ 13 HEADER_RESERVED = 0, /* always cleared */
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index f38590d7561b..30df6187ee02 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -4,6 +4,7 @@
4#include "session.h" 4#include "session.h"
5#include "sort.h" 5#include "sort.h"
6#include "evsel.h" 6#include "evsel.h"
7#include "annotate.h"
7#include <math.h> 8#include <math.h>
8 9
9static bool hists__filter_entry_by_dso(struct hists *hists, 10static bool hists__filter_entry_by_dso(struct hists *hists,
@@ -127,6 +128,8 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
127 + unresolved_col_width + 2; 128 + unresolved_col_width + 2;
128 hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL, 129 hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL,
129 symlen); 130 symlen);
131 hists__new_col_len(hists, HISTC_MEM_DCACHELINE,
132 symlen + 1);
130 } else { 133 } else {
131 symlen = unresolved_col_width + 4 + 2; 134 symlen = unresolved_col_width + 4 + 2;
132 hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL, 135 hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL,
@@ -225,14 +228,20 @@ static void he_stat__decay(struct he_stat *he_stat)
225static bool hists__decay_entry(struct hists *hists, struct hist_entry *he) 228static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
226{ 229{
227 u64 prev_period = he->stat.period; 230 u64 prev_period = he->stat.period;
231 u64 diff;
228 232
229 if (prev_period == 0) 233 if (prev_period == 0)
230 return true; 234 return true;
231 235
232 he_stat__decay(&he->stat); 236 he_stat__decay(&he->stat);
237 if (symbol_conf.cumulate_callchain)
238 he_stat__decay(he->stat_acc);
233 239
240 diff = prev_period - he->stat.period;
241
242 hists->stats.total_period -= diff;
234 if (!he->filtered) 243 if (!he->filtered)
235 hists->stats.total_period -= prev_period - he->stat.period; 244 hists->stats.total_non_filtered_period -= diff;
236 245
237 return he->stat.period == 0; 246 return he->stat.period == 0;
238} 247}
@@ -259,8 +268,11 @@ void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
259 if (sort__need_collapse) 268 if (sort__need_collapse)
260 rb_erase(&n->rb_node_in, &hists->entries_collapsed); 269 rb_erase(&n->rb_node_in, &hists->entries_collapsed);
261 270
262 hist_entry__free(n);
263 --hists->nr_entries; 271 --hists->nr_entries;
272 if (!n->filtered)
273 --hists->nr_non_filtered_entries;
274
275 hist_entry__free(n);
264 } 276 }
265 } 277 }
266} 278}
@@ -269,14 +281,31 @@ void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
269 * histogram, sorted on item, collects periods 281 * histogram, sorted on item, collects periods
270 */ 282 */
271 283
272static struct hist_entry *hist_entry__new(struct hist_entry *template) 284static struct hist_entry *hist_entry__new(struct hist_entry *template,
285 bool sample_self)
273{ 286{
274 size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_root) : 0; 287 size_t callchain_size = 0;
275 struct hist_entry *he = zalloc(sizeof(*he) + callchain_size); 288 struct hist_entry *he;
289
290 if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain)
291 callchain_size = sizeof(struct callchain_root);
292
293 he = zalloc(sizeof(*he) + callchain_size);
276 294
277 if (he != NULL) { 295 if (he != NULL) {
278 *he = *template; 296 *he = *template;
279 297
298 if (symbol_conf.cumulate_callchain) {
299 he->stat_acc = malloc(sizeof(he->stat));
300 if (he->stat_acc == NULL) {
301 free(he);
302 return NULL;
303 }
304 memcpy(he->stat_acc, &he->stat, sizeof(he->stat));
305 if (!sample_self)
306 memset(&he->stat, 0, sizeof(he->stat));
307 }
308
280 if (he->ms.map) 309 if (he->ms.map)
281 he->ms.map->referenced = true; 310 he->ms.map->referenced = true;
282 311
@@ -288,6 +317,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
288 */ 317 */
289 he->branch_info = malloc(sizeof(*he->branch_info)); 318 he->branch_info = malloc(sizeof(*he->branch_info));
290 if (he->branch_info == NULL) { 319 if (he->branch_info == NULL) {
320 free(he->stat_acc);
291 free(he); 321 free(he);
292 return NULL; 322 return NULL;
293 } 323 }
@@ -317,15 +347,6 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
317 return he; 347 return he;
318} 348}
319 349
320void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h)
321{
322 if (!h->filtered) {
323 hists__calc_col_len(hists, h);
324 ++hists->nr_entries;
325 hists->stats.total_period += h->stat.period;
326 }
327}
328
329static u8 symbol__parent_filter(const struct symbol *parent) 350static u8 symbol__parent_filter(const struct symbol *parent)
330{ 351{
331 if (symbol_conf.exclude_other && parent == NULL) 352 if (symbol_conf.exclude_other && parent == NULL)
@@ -335,7 +356,8 @@ static u8 symbol__parent_filter(const struct symbol *parent)
335 356
336static struct hist_entry *add_hist_entry(struct hists *hists, 357static struct hist_entry *add_hist_entry(struct hists *hists,
337 struct hist_entry *entry, 358 struct hist_entry *entry,
338 struct addr_location *al) 359 struct addr_location *al,
360 bool sample_self)
339{ 361{
340 struct rb_node **p; 362 struct rb_node **p;
341 struct rb_node *parent = NULL; 363 struct rb_node *parent = NULL;
@@ -359,7 +381,10 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
359 cmp = hist_entry__cmp(he, entry); 381 cmp = hist_entry__cmp(he, entry);
360 382
361 if (!cmp) { 383 if (!cmp) {
362 he_stat__add_period(&he->stat, period, weight); 384 if (sample_self)
385 he_stat__add_period(&he->stat, period, weight);
386 if (symbol_conf.cumulate_callchain)
387 he_stat__add_period(he->stat_acc, period, weight);
363 388
364 /* 389 /*
365 * This mem info was allocated from sample__resolve_mem 390 * This mem info was allocated from sample__resolve_mem
@@ -387,15 +412,17 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
387 p = &(*p)->rb_right; 412 p = &(*p)->rb_right;
388 } 413 }
389 414
390 he = hist_entry__new(entry); 415 he = hist_entry__new(entry, sample_self);
391 if (!he) 416 if (!he)
392 return NULL; 417 return NULL;
393 418
394 hists->nr_entries++;
395 rb_link_node(&he->rb_node_in, parent, p); 419 rb_link_node(&he->rb_node_in, parent, p);
396 rb_insert_color(&he->rb_node_in, hists->entries_in); 420 rb_insert_color(&he->rb_node_in, hists->entries_in);
397out: 421out:
398 he_stat__add_cpumode_period(&he->stat, al->cpumode, period); 422 if (sample_self)
423 he_stat__add_cpumode_period(&he->stat, al->cpumode, period);
424 if (symbol_conf.cumulate_callchain)
425 he_stat__add_cpumode_period(he->stat_acc, al->cpumode, period);
399 return he; 426 return he;
400} 427}
401 428
@@ -404,7 +431,8 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
404 struct symbol *sym_parent, 431 struct symbol *sym_parent,
405 struct branch_info *bi, 432 struct branch_info *bi,
406 struct mem_info *mi, 433 struct mem_info *mi,
407 u64 period, u64 weight, u64 transaction) 434 u64 period, u64 weight, u64 transaction,
435 bool sample_self)
408{ 436{
409 struct hist_entry entry = { 437 struct hist_entry entry = {
410 .thread = al->thread, 438 .thread = al->thread,
@@ -413,9 +441,10 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
413 .map = al->map, 441 .map = al->map,
414 .sym = al->sym, 442 .sym = al->sym,
415 }, 443 },
416 .cpu = al->cpu, 444 .cpu = al->cpu,
417 .ip = al->addr, 445 .cpumode = al->cpumode,
418 .level = al->level, 446 .ip = al->addr,
447 .level = al->level,
419 .stat = { 448 .stat = {
420 .nr_events = 1, 449 .nr_events = 1,
421 .period = period, 450 .period = period,
@@ -429,17 +458,442 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
429 .transaction = transaction, 458 .transaction = transaction,
430 }; 459 };
431 460
432 return add_hist_entry(hists, &entry, al); 461 return add_hist_entry(hists, &entry, al, sample_self);
462}
463
464static int
465iter_next_nop_entry(struct hist_entry_iter *iter __maybe_unused,
466 struct addr_location *al __maybe_unused)
467{
468 return 0;
469}
470
471static int
472iter_add_next_nop_entry(struct hist_entry_iter *iter __maybe_unused,
473 struct addr_location *al __maybe_unused)
474{
475 return 0;
476}
477
478static int
479iter_prepare_mem_entry(struct hist_entry_iter *iter, struct addr_location *al)
480{
481 struct perf_sample *sample = iter->sample;
482 struct mem_info *mi;
483
484 mi = sample__resolve_mem(sample, al);
485 if (mi == NULL)
486 return -ENOMEM;
487
488 iter->priv = mi;
489 return 0;
490}
491
492static int
493iter_add_single_mem_entry(struct hist_entry_iter *iter, struct addr_location *al)
494{
495 u64 cost;
496 struct mem_info *mi = iter->priv;
497 struct hist_entry *he;
498
499 if (mi == NULL)
500 return -EINVAL;
501
502 cost = iter->sample->weight;
503 if (!cost)
504 cost = 1;
505
506 /*
507 * must pass period=weight in order to get the correct
508 * sorting from hists__collapse_resort() which is solely
509 * based on periods. We want sorting be done on nr_events * weight
510 * and this is indirectly achieved by passing period=weight here
511 * and the he_stat__add_period() function.
512 */
513 he = __hists__add_entry(&iter->evsel->hists, al, iter->parent, NULL, mi,
514 cost, cost, 0, true);
515 if (!he)
516 return -ENOMEM;
517
518 iter->he = he;
519 return 0;
520}
521
522static int
523iter_finish_mem_entry(struct hist_entry_iter *iter,
524 struct addr_location *al __maybe_unused)
525{
526 struct perf_evsel *evsel = iter->evsel;
527 struct hist_entry *he = iter->he;
528 int err = -EINVAL;
529
530 if (he == NULL)
531 goto out;
532
533 hists__inc_nr_samples(&evsel->hists, he->filtered);
534
535 err = hist_entry__append_callchain(he, iter->sample);
536
537out:
538 /*
539 * We don't need to free iter->priv (mem_info) here since
540 * the mem info was either already freed in add_hist_entry() or
541 * passed to a new hist entry by hist_entry__new().
542 */
543 iter->priv = NULL;
544
545 iter->he = NULL;
546 return err;
547}
548
549static int
550iter_prepare_branch_entry(struct hist_entry_iter *iter, struct addr_location *al)
551{
552 struct branch_info *bi;
553 struct perf_sample *sample = iter->sample;
554
555 bi = sample__resolve_bstack(sample, al);
556 if (!bi)
557 return -ENOMEM;
558
559 iter->curr = 0;
560 iter->total = sample->branch_stack->nr;
561
562 iter->priv = bi;
563 return 0;
564}
565
566static int
567iter_add_single_branch_entry(struct hist_entry_iter *iter __maybe_unused,
568 struct addr_location *al __maybe_unused)
569{
570 /* to avoid calling callback function */
571 iter->he = NULL;
572
573 return 0;
574}
575
576static int
577iter_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *al)
578{
579 struct branch_info *bi = iter->priv;
580 int i = iter->curr;
581
582 if (bi == NULL)
583 return 0;
584
585 if (iter->curr >= iter->total)
586 return 0;
587
588 al->map = bi[i].to.map;
589 al->sym = bi[i].to.sym;
590 al->addr = bi[i].to.addr;
591 return 1;
592}
593
594static int
595iter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *al)
596{
597 struct branch_info *bi;
598 struct perf_evsel *evsel = iter->evsel;
599 struct hist_entry *he = NULL;
600 int i = iter->curr;
601 int err = 0;
602
603 bi = iter->priv;
604
605 if (iter->hide_unresolved && !(bi[i].from.sym && bi[i].to.sym))
606 goto out;
607
608 /*
609 * The report shows the percentage of total branches captured
610 * and not events sampled. Thus we use a pseudo period of 1.
611 */
612 he = __hists__add_entry(&evsel->hists, al, iter->parent, &bi[i], NULL,
613 1, 1, 0, true);
614 if (he == NULL)
615 return -ENOMEM;
616
617 hists__inc_nr_samples(&evsel->hists, he->filtered);
618
619out:
620 iter->he = he;
621 iter->curr++;
622 return err;
623}
624
625static int
626iter_finish_branch_entry(struct hist_entry_iter *iter,
627 struct addr_location *al __maybe_unused)
628{
629 zfree(&iter->priv);
630 iter->he = NULL;
631
632 return iter->curr >= iter->total ? 0 : -1;
633}
634
635static int
636iter_prepare_normal_entry(struct hist_entry_iter *iter __maybe_unused,
637 struct addr_location *al __maybe_unused)
638{
639 return 0;
640}
641
642static int
643iter_add_single_normal_entry(struct hist_entry_iter *iter, struct addr_location *al)
644{
645 struct perf_evsel *evsel = iter->evsel;
646 struct perf_sample *sample = iter->sample;
647 struct hist_entry *he;
648
649 he = __hists__add_entry(&evsel->hists, al, iter->parent, NULL, NULL,
650 sample->period, sample->weight,
651 sample->transaction, true);
652 if (he == NULL)
653 return -ENOMEM;
654
655 iter->he = he;
656 return 0;
657}
658
659static int
660iter_finish_normal_entry(struct hist_entry_iter *iter,
661 struct addr_location *al __maybe_unused)
662{
663 struct hist_entry *he = iter->he;
664 struct perf_evsel *evsel = iter->evsel;
665 struct perf_sample *sample = iter->sample;
666
667 if (he == NULL)
668 return 0;
669
670 iter->he = NULL;
671
672 hists__inc_nr_samples(&evsel->hists, he->filtered);
673
674 return hist_entry__append_callchain(he, sample);
675}
676
677static int
678iter_prepare_cumulative_entry(struct hist_entry_iter *iter __maybe_unused,
679 struct addr_location *al __maybe_unused)
680{
681 struct hist_entry **he_cache;
682
683 callchain_cursor_commit(&callchain_cursor);
684
685 /*
686 * This is for detecting cycles or recursions so that they're
687 * cumulated only one time to prevent entries more than 100%
688 * overhead.
689 */
690 he_cache = malloc(sizeof(*he_cache) * (PERF_MAX_STACK_DEPTH + 1));
691 if (he_cache == NULL)
692 return -ENOMEM;
693
694 iter->priv = he_cache;
695 iter->curr = 0;
696
697 return 0;
698}
699
700static int
701iter_add_single_cumulative_entry(struct hist_entry_iter *iter,
702 struct addr_location *al)
703{
704 struct perf_evsel *evsel = iter->evsel;
705 struct perf_sample *sample = iter->sample;
706 struct hist_entry **he_cache = iter->priv;
707 struct hist_entry *he;
708 int err = 0;
709
710 he = __hists__add_entry(&evsel->hists, al, iter->parent, NULL, NULL,
711 sample->period, sample->weight,
712 sample->transaction, true);
713 if (he == NULL)
714 return -ENOMEM;
715
716 iter->he = he;
717 he_cache[iter->curr++] = he;
718
719 callchain_append(he->callchain, &callchain_cursor, sample->period);
720
721 /*
722 * We need to re-initialize the cursor since callchain_append()
723 * advanced the cursor to the end.
724 */
725 callchain_cursor_commit(&callchain_cursor);
726
727 hists__inc_nr_samples(&evsel->hists, he->filtered);
728
729 return err;
730}
731
732static int
733iter_next_cumulative_entry(struct hist_entry_iter *iter,
734 struct addr_location *al)
735{
736 struct callchain_cursor_node *node;
737
738 node = callchain_cursor_current(&callchain_cursor);
739 if (node == NULL)
740 return 0;
741
742 return fill_callchain_info(al, node, iter->hide_unresolved);
743}
744
745static int
746iter_add_next_cumulative_entry(struct hist_entry_iter *iter,
747 struct addr_location *al)
748{
749 struct perf_evsel *evsel = iter->evsel;
750 struct perf_sample *sample = iter->sample;
751 struct hist_entry **he_cache = iter->priv;
752 struct hist_entry *he;
753 struct hist_entry he_tmp = {
754 .cpu = al->cpu,
755 .thread = al->thread,
756 .comm = thread__comm(al->thread),
757 .ip = al->addr,
758 .ms = {
759 .map = al->map,
760 .sym = al->sym,
761 },
762 .parent = iter->parent,
763 };
764 int i;
765 struct callchain_cursor cursor;
766
767 callchain_cursor_snapshot(&cursor, &callchain_cursor);
768
769 callchain_cursor_advance(&callchain_cursor);
770
771 /*
772 * Check if there's duplicate entries in the callchain.
773 * It's possible that it has cycles or recursive calls.
774 */
775 for (i = 0; i < iter->curr; i++) {
776 if (hist_entry__cmp(he_cache[i], &he_tmp) == 0) {
777 /* to avoid calling callback function */
778 iter->he = NULL;
779 return 0;
780 }
781 }
782
783 he = __hists__add_entry(&evsel->hists, al, iter->parent, NULL, NULL,
784 sample->period, sample->weight,
785 sample->transaction, false);
786 if (he == NULL)
787 return -ENOMEM;
788
789 iter->he = he;
790 he_cache[iter->curr++] = he;
791
792 callchain_append(he->callchain, &cursor, sample->period);
793 return 0;
794}
795
796static int
797iter_finish_cumulative_entry(struct hist_entry_iter *iter,
798 struct addr_location *al __maybe_unused)
799{
800 zfree(&iter->priv);
801 iter->he = NULL;
802
803 return 0;
804}
805
806const struct hist_iter_ops hist_iter_mem = {
807 .prepare_entry = iter_prepare_mem_entry,
808 .add_single_entry = iter_add_single_mem_entry,
809 .next_entry = iter_next_nop_entry,
810 .add_next_entry = iter_add_next_nop_entry,
811 .finish_entry = iter_finish_mem_entry,
812};
813
814const struct hist_iter_ops hist_iter_branch = {
815 .prepare_entry = iter_prepare_branch_entry,
816 .add_single_entry = iter_add_single_branch_entry,
817 .next_entry = iter_next_branch_entry,
818 .add_next_entry = iter_add_next_branch_entry,
819 .finish_entry = iter_finish_branch_entry,
820};
821
822const struct hist_iter_ops hist_iter_normal = {
823 .prepare_entry = iter_prepare_normal_entry,
824 .add_single_entry = iter_add_single_normal_entry,
825 .next_entry = iter_next_nop_entry,
826 .add_next_entry = iter_add_next_nop_entry,
827 .finish_entry = iter_finish_normal_entry,
828};
829
830const struct hist_iter_ops hist_iter_cumulative = {
831 .prepare_entry = iter_prepare_cumulative_entry,
832 .add_single_entry = iter_add_single_cumulative_entry,
833 .next_entry = iter_next_cumulative_entry,
834 .add_next_entry = iter_add_next_cumulative_entry,
835 .finish_entry = iter_finish_cumulative_entry,
836};
837
838int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al,
839 struct perf_evsel *evsel, struct perf_sample *sample,
840 int max_stack_depth, void *arg)
841{
842 int err, err2;
843
844 err = sample__resolve_callchain(sample, &iter->parent, evsel, al,
845 max_stack_depth);
846 if (err)
847 return err;
848
849 iter->evsel = evsel;
850 iter->sample = sample;
851
852 err = iter->ops->prepare_entry(iter, al);
853 if (err)
854 goto out;
855
856 err = iter->ops->add_single_entry(iter, al);
857 if (err)
858 goto out;
859
860 if (iter->he && iter->add_entry_cb) {
861 err = iter->add_entry_cb(iter, al, true, arg);
862 if (err)
863 goto out;
864 }
865
866 while (iter->ops->next_entry(iter, al)) {
867 err = iter->ops->add_next_entry(iter, al);
868 if (err)
869 break;
870
871 if (iter->he && iter->add_entry_cb) {
872 err = iter->add_entry_cb(iter, al, false, arg);
873 if (err)
874 goto out;
875 }
876 }
877
878out:
879 err2 = iter->ops->finish_entry(iter, al);
880 if (!err)
881 err = err2;
882
883 return err;
433} 884}
434 885
435int64_t 886int64_t
436hist_entry__cmp(struct hist_entry *left, struct hist_entry *right) 887hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
437{ 888{
438 struct sort_entry *se; 889 struct perf_hpp_fmt *fmt;
439 int64_t cmp = 0; 890 int64_t cmp = 0;
440 891
441 list_for_each_entry(se, &hist_entry__sort_list, list) { 892 perf_hpp__for_each_sort_list(fmt) {
442 cmp = se->se_cmp(left, right); 893 if (perf_hpp__should_skip(fmt))
894 continue;
895
896 cmp = fmt->cmp(left, right);
443 if (cmp) 897 if (cmp)
444 break; 898 break;
445 } 899 }
@@ -450,15 +904,14 @@ hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
450int64_t 904int64_t
451hist_entry__collapse(struct hist_entry *left, struct hist_entry *right) 905hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
452{ 906{
453 struct sort_entry *se; 907 struct perf_hpp_fmt *fmt;
454 int64_t cmp = 0; 908 int64_t cmp = 0;
455 909
456 list_for_each_entry(se, &hist_entry__sort_list, list) { 910 perf_hpp__for_each_sort_list(fmt) {
457 int64_t (*f)(struct hist_entry *, struct hist_entry *); 911 if (perf_hpp__should_skip(fmt))
458 912 continue;
459 f = se->se_collapse ?: se->se_cmp;
460 913
461 cmp = f(left, right); 914 cmp = fmt->collapse(left, right);
462 if (cmp) 915 if (cmp)
463 break; 916 break;
464 } 917 }
@@ -470,6 +923,7 @@ void hist_entry__free(struct hist_entry *he)
470{ 923{
471 zfree(&he->branch_info); 924 zfree(&he->branch_info);
472 zfree(&he->mem_info); 925 zfree(&he->mem_info);
926 zfree(&he->stat_acc);
473 free_srcline(he->srcline); 927 free_srcline(he->srcline);
474 free(he); 928 free(he);
475} 929}
@@ -495,6 +949,8 @@ static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,
495 949
496 if (!cmp) { 950 if (!cmp) {
497 he_stat__add_stat(&iter->stat, &he->stat); 951 he_stat__add_stat(&iter->stat, &he->stat);
952 if (symbol_conf.cumulate_callchain)
953 he_stat__add_stat(iter->stat_acc, he->stat_acc);
498 954
499 if (symbol_conf.use_callchain) { 955 if (symbol_conf.use_callchain) {
500 callchain_cursor_reset(&callchain_cursor); 956 callchain_cursor_reset(&callchain_cursor);
@@ -571,64 +1027,50 @@ void hists__collapse_resort(struct hists *hists, struct ui_progress *prog)
571 } 1027 }
572} 1028}
573 1029
574/* 1030static int hist_entry__sort(struct hist_entry *a, struct hist_entry *b)
575 * reverse the map, sort on period.
576 */
577
578static int period_cmp(u64 period_a, u64 period_b)
579{
580 if (period_a > period_b)
581 return 1;
582 if (period_a < period_b)
583 return -1;
584 return 0;
585}
586
587static int hist_entry__sort_on_period(struct hist_entry *a,
588 struct hist_entry *b)
589{ 1031{
590 int ret; 1032 struct perf_hpp_fmt *fmt;
591 int i, nr_members; 1033 int64_t cmp = 0;
592 struct perf_evsel *evsel;
593 struct hist_entry *pair;
594 u64 *periods_a, *periods_b;
595 1034
596 ret = period_cmp(a->stat.period, b->stat.period); 1035 perf_hpp__for_each_sort_list(fmt) {
597 if (ret || !symbol_conf.event_group) 1036 if (perf_hpp__should_skip(fmt))
598 return ret; 1037 continue;
599 1038
600 evsel = hists_to_evsel(a->hists); 1039 cmp = fmt->sort(a, b);
601 nr_members = evsel->nr_members; 1040 if (cmp)
602 if (nr_members <= 1) 1041 break;
603 return ret; 1042 }
604 1043
605 periods_a = zalloc(sizeof(periods_a) * nr_members); 1044 return cmp;
606 periods_b = zalloc(sizeof(periods_b) * nr_members); 1045}
607 1046
608 if (!periods_a || !periods_b) 1047static void hists__reset_filter_stats(struct hists *hists)
609 goto out; 1048{
1049 hists->nr_non_filtered_entries = 0;
1050 hists->stats.total_non_filtered_period = 0;
1051}
610 1052
611 list_for_each_entry(pair, &a->pairs.head, pairs.node) { 1053void hists__reset_stats(struct hists *hists)
612 evsel = hists_to_evsel(pair->hists); 1054{
613 periods_a[perf_evsel__group_idx(evsel)] = pair->stat.period; 1055 hists->nr_entries = 0;
614 } 1056 hists->stats.total_period = 0;
615 1057
616 list_for_each_entry(pair, &b->pairs.head, pairs.node) { 1058 hists__reset_filter_stats(hists);
617 evsel = hists_to_evsel(pair->hists); 1059}
618 periods_b[perf_evsel__group_idx(evsel)] = pair->stat.period;
619 }
620 1060
621 for (i = 1; i < nr_members; i++) { 1061static void hists__inc_filter_stats(struct hists *hists, struct hist_entry *h)
622 ret = period_cmp(periods_a[i], periods_b[i]); 1062{
623 if (ret) 1063 hists->nr_non_filtered_entries++;
624 break; 1064 hists->stats.total_non_filtered_period += h->stat.period;
625 } 1065}
626 1066
627out: 1067void hists__inc_stats(struct hists *hists, struct hist_entry *h)
628 free(periods_a); 1068{
629 free(periods_b); 1069 if (!h->filtered)
1070 hists__inc_filter_stats(hists, h);
630 1071
631 return ret; 1072 hists->nr_entries++;
1073 hists->stats.total_period += h->stat.period;
632} 1074}
633 1075
634static void __hists__insert_output_entry(struct rb_root *entries, 1076static void __hists__insert_output_entry(struct rb_root *entries,
@@ -647,7 +1089,7 @@ static void __hists__insert_output_entry(struct rb_root *entries,
647 parent = *p; 1089 parent = *p;
648 iter = rb_entry(parent, struct hist_entry, rb_node); 1090 iter = rb_entry(parent, struct hist_entry, rb_node);
649 1091
650 if (hist_entry__sort_on_period(he, iter) > 0) 1092 if (hist_entry__sort(he, iter) > 0)
651 p = &(*p)->rb_left; 1093 p = &(*p)->rb_left;
652 else 1094 else
653 p = &(*p)->rb_right; 1095 p = &(*p)->rb_right;
@@ -674,8 +1116,7 @@ void hists__output_resort(struct hists *hists)
674 next = rb_first(root); 1116 next = rb_first(root);
675 hists->entries = RB_ROOT; 1117 hists->entries = RB_ROOT;
676 1118
677 hists->nr_entries = 0; 1119 hists__reset_stats(hists);
678 hists->stats.total_period = 0;
679 hists__reset_col_len(hists); 1120 hists__reset_col_len(hists);
680 1121
681 while (next) { 1122 while (next) {
@@ -683,7 +1124,10 @@ void hists__output_resort(struct hists *hists)
683 next = rb_next(&n->rb_node_in); 1124 next = rb_next(&n->rb_node_in);
684 1125
685 __hists__insert_output_entry(&hists->entries, n, min_callchain_hits); 1126 __hists__insert_output_entry(&hists->entries, n, min_callchain_hits);
686 hists__inc_nr_entries(hists, n); 1127 hists__inc_stats(hists, n);
1128
1129 if (!n->filtered)
1130 hists__calc_col_len(hists, n);
687 } 1131 }
688} 1132}
689 1133
@@ -694,13 +1138,13 @@ static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h
694 if (h->filtered) 1138 if (h->filtered)
695 return; 1139 return;
696 1140
697 ++hists->nr_entries; 1141 /* force fold unfiltered entry for simplicity */
698 if (h->ms.unfolded) 1142 h->ms.unfolded = false;
699 hists->nr_entries += h->nr_rows;
700 h->row_offset = 0; 1143 h->row_offset = 0;
701 hists->stats.total_period += h->stat.period;
702 hists->stats.nr_events[PERF_RECORD_SAMPLE] += h->stat.nr_events;
703 1144
1145 hists->stats.nr_non_filtered_samples += h->stat.nr_events;
1146
1147 hists__inc_filter_stats(hists, h);
704 hists__calc_col_len(hists, h); 1148 hists__calc_col_len(hists, h);
705} 1149}
706 1150
@@ -721,8 +1165,9 @@ void hists__filter_by_dso(struct hists *hists)
721{ 1165{
722 struct rb_node *nd; 1166 struct rb_node *nd;
723 1167
724 hists->nr_entries = hists->stats.total_period = 0; 1168 hists->stats.nr_non_filtered_samples = 0;
725 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0; 1169
1170 hists__reset_filter_stats(hists);
726 hists__reset_col_len(hists); 1171 hists__reset_col_len(hists);
727 1172
728 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 1173 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
@@ -754,8 +1199,9 @@ void hists__filter_by_thread(struct hists *hists)
754{ 1199{
755 struct rb_node *nd; 1200 struct rb_node *nd;
756 1201
757 hists->nr_entries = hists->stats.total_period = 0; 1202 hists->stats.nr_non_filtered_samples = 0;
758 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0; 1203
1204 hists__reset_filter_stats(hists);
759 hists__reset_col_len(hists); 1205 hists__reset_col_len(hists);
760 1206
761 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 1207 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
@@ -785,8 +1231,9 @@ void hists__filter_by_symbol(struct hists *hists)
785{ 1231{
786 struct rb_node *nd; 1232 struct rb_node *nd;
787 1233
788 hists->nr_entries = hists->stats.total_period = 0; 1234 hists->stats.nr_non_filtered_samples = 0;
789 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0; 1235
1236 hists__reset_filter_stats(hists);
790 hists__reset_col_len(hists); 1237 hists__reset_col_len(hists);
791 1238
792 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 1239 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
@@ -810,6 +1257,13 @@ void hists__inc_nr_events(struct hists *hists, u32 type)
810 events_stats__inc(&hists->stats, type); 1257 events_stats__inc(&hists->stats, type);
811} 1258}
812 1259
1260void hists__inc_nr_samples(struct hists *hists, bool filtered)
1261{
1262 events_stats__inc(&hists->stats, PERF_RECORD_SAMPLE);
1263 if (!filtered)
1264 hists->stats.nr_non_filtered_samples++;
1265}
1266
813static struct hist_entry *hists__add_dummy_entry(struct hists *hists, 1267static struct hist_entry *hists__add_dummy_entry(struct hists *hists,
814 struct hist_entry *pair) 1268 struct hist_entry *pair)
815{ 1269{
@@ -841,13 +1295,13 @@ static struct hist_entry *hists__add_dummy_entry(struct hists *hists,
841 p = &(*p)->rb_right; 1295 p = &(*p)->rb_right;
842 } 1296 }
843 1297
844 he = hist_entry__new(pair); 1298 he = hist_entry__new(pair, true);
845 if (he) { 1299 if (he) {
846 memset(&he->stat, 0, sizeof(he->stat)); 1300 memset(&he->stat, 0, sizeof(he->stat));
847 he->hists = hists; 1301 he->hists = hists;
848 rb_link_node(&he->rb_node_in, parent, p); 1302 rb_link_node(&he->rb_node_in, parent, p);
849 rb_insert_color(&he->rb_node_in, root); 1303 rb_insert_color(&he->rb_node_in, root);
850 hists__inc_nr_entries(hists, he); 1304 hists__inc_stats(hists, he);
851 he->dummy = true; 1305 he->dummy = true;
852 } 1306 }
853out: 1307out:
@@ -931,3 +1385,30 @@ int hists__link(struct hists *leader, struct hists *other)
931 1385
932 return 0; 1386 return 0;
933} 1387}
1388
1389u64 hists__total_period(struct hists *hists)
1390{
1391 return symbol_conf.filter_relative ? hists->stats.total_non_filtered_period :
1392 hists->stats.total_period;
1393}
1394
1395int parse_filter_percentage(const struct option *opt __maybe_unused,
1396 const char *arg, int unset __maybe_unused)
1397{
1398 if (!strcmp(arg, "relative"))
1399 symbol_conf.filter_relative = true;
1400 else if (!strcmp(arg, "absolute"))
1401 symbol_conf.filter_relative = false;
1402 else
1403 return -1;
1404
1405 return 0;
1406}
1407
1408int perf_hist_config(const char *var, const char *value)
1409{
1410 if (!strcmp(var, "hist.percentage"))
1411 return parse_filter_percentage(NULL, value, 0);
1412
1413 return 0;
1414}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 1f1f513dfe7f..742f49a85725 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -37,9 +37,11 @@ enum hist_filter {
37 */ 37 */
38struct events_stats { 38struct events_stats {
39 u64 total_period; 39 u64 total_period;
40 u64 total_non_filtered_period;
40 u64 total_lost; 41 u64 total_lost;
41 u64 total_invalid_chains; 42 u64 total_invalid_chains;
42 u32 nr_events[PERF_RECORD_HEADER_MAX]; 43 u32 nr_events[PERF_RECORD_HEADER_MAX];
44 u32 nr_non_filtered_samples;
43 u32 nr_lost_warned; 45 u32 nr_lost_warned;
44 u32 nr_unknown_events; 46 u32 nr_unknown_events;
45 u32 nr_invalid_chains; 47 u32 nr_invalid_chains;
@@ -70,6 +72,7 @@ enum hist_column {
70 HISTC_MEM_TLB, 72 HISTC_MEM_TLB,
71 HISTC_MEM_LVL, 73 HISTC_MEM_LVL,
72 HISTC_MEM_SNOOP, 74 HISTC_MEM_SNOOP,
75 HISTC_MEM_DCACHELINE,
73 HISTC_TRANSACTION, 76 HISTC_TRANSACTION,
74 HISTC_NR_COLS, /* Last entry */ 77 HISTC_NR_COLS, /* Last entry */
75}; 78};
@@ -83,6 +86,7 @@ struct hists {
83 struct rb_root entries; 86 struct rb_root entries;
84 struct rb_root entries_collapsed; 87 struct rb_root entries_collapsed;
85 u64 nr_entries; 88 u64 nr_entries;
89 u64 nr_non_filtered_entries;
86 const struct thread *thread_filter; 90 const struct thread *thread_filter;
87 const struct dso *dso_filter; 91 const struct dso *dso_filter;
88 const char *uid_filter_str; 92 const char *uid_filter_str;
@@ -93,12 +97,50 @@ struct hists {
93 u16 col_len[HISTC_NR_COLS]; 97 u16 col_len[HISTC_NR_COLS];
94}; 98};
95 99
100struct hist_entry_iter;
101
102struct hist_iter_ops {
103 int (*prepare_entry)(struct hist_entry_iter *, struct addr_location *);
104 int (*add_single_entry)(struct hist_entry_iter *, struct addr_location *);
105 int (*next_entry)(struct hist_entry_iter *, struct addr_location *);
106 int (*add_next_entry)(struct hist_entry_iter *, struct addr_location *);
107 int (*finish_entry)(struct hist_entry_iter *, struct addr_location *);
108};
109
110struct hist_entry_iter {
111 int total;
112 int curr;
113
114 bool hide_unresolved;
115
116 struct perf_evsel *evsel;
117 struct perf_sample *sample;
118 struct hist_entry *he;
119 struct symbol *parent;
120 void *priv;
121
122 const struct hist_iter_ops *ops;
123 /* user-defined callback function (optional) */
124 int (*add_entry_cb)(struct hist_entry_iter *iter,
125 struct addr_location *al, bool single, void *arg);
126};
127
128extern const struct hist_iter_ops hist_iter_normal;
129extern const struct hist_iter_ops hist_iter_branch;
130extern const struct hist_iter_ops hist_iter_mem;
131extern const struct hist_iter_ops hist_iter_cumulative;
132
96struct hist_entry *__hists__add_entry(struct hists *hists, 133struct hist_entry *__hists__add_entry(struct hists *hists,
97 struct addr_location *al, 134 struct addr_location *al,
98 struct symbol *parent, 135 struct symbol *parent,
99 struct branch_info *bi, 136 struct branch_info *bi,
100 struct mem_info *mi, u64 period, 137 struct mem_info *mi, u64 period,
101 u64 weight, u64 transaction); 138 u64 weight, u64 transaction,
139 bool sample_self);
140int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al,
141 struct perf_evsel *evsel, struct perf_sample *sample,
142 int max_stack_depth, void *arg);
143
102int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right); 144int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right);
103int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right); 145int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right);
104int hist_entry__transaction_len(void); 146int hist_entry__transaction_len(void);
@@ -112,8 +154,11 @@ void hists__collapse_resort(struct hists *hists, struct ui_progress *prog);
112void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel); 154void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel);
113void hists__output_recalc_col_len(struct hists *hists, int max_rows); 155void hists__output_recalc_col_len(struct hists *hists, int max_rows);
114 156
115void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h); 157u64 hists__total_period(struct hists *hists);
158void hists__reset_stats(struct hists *hists);
159void hists__inc_stats(struct hists *hists, struct hist_entry *h);
116void hists__inc_nr_events(struct hists *hists, u32 type); 160void hists__inc_nr_events(struct hists *hists, u32 type);
161void hists__inc_nr_samples(struct hists *hists, bool filtered);
117void events_stats__inc(struct events_stats *stats, u32 type); 162void events_stats__inc(struct events_stats *stats, u32 type);
118size_t events_stats__fprintf(struct events_stats *stats, FILE *fp); 163size_t events_stats__fprintf(struct events_stats *stats, FILE *fp);
119 164
@@ -124,6 +169,12 @@ void hists__filter_by_dso(struct hists *hists);
124void hists__filter_by_thread(struct hists *hists); 169void hists__filter_by_thread(struct hists *hists);
125void hists__filter_by_symbol(struct hists *hists); 170void hists__filter_by_symbol(struct hists *hists);
126 171
172static inline bool hists__has_filter(struct hists *hists)
173{
174 return hists->thread_filter || hists->dso_filter ||
175 hists->symbol_filter_str;
176}
177
127u16 hists__col_len(struct hists *hists, enum hist_column col); 178u16 hists__col_len(struct hists *hists, enum hist_column col);
128void hists__set_col_len(struct hists *hists, enum hist_column col, u16 len); 179void hists__set_col_len(struct hists *hists, enum hist_column col, u16 len);
129bool hists__new_col_len(struct hists *hists, enum hist_column col, u16 len); 180bool hists__new_col_len(struct hists *hists, enum hist_column col, u16 len);
@@ -149,15 +200,30 @@ struct perf_hpp_fmt {
149 struct hist_entry *he); 200 struct hist_entry *he);
150 int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, 201 int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
151 struct hist_entry *he); 202 struct hist_entry *he);
203 int64_t (*cmp)(struct hist_entry *a, struct hist_entry *b);
204 int64_t (*collapse)(struct hist_entry *a, struct hist_entry *b);
205 int64_t (*sort)(struct hist_entry *a, struct hist_entry *b);
152 206
153 struct list_head list; 207 struct list_head list;
208 struct list_head sort_list;
209 bool elide;
154}; 210};
155 211
156extern struct list_head perf_hpp__list; 212extern struct list_head perf_hpp__list;
213extern struct list_head perf_hpp__sort_list;
157 214
158#define perf_hpp__for_each_format(format) \ 215#define perf_hpp__for_each_format(format) \
159 list_for_each_entry(format, &perf_hpp__list, list) 216 list_for_each_entry(format, &perf_hpp__list, list)
160 217
218#define perf_hpp__for_each_format_safe(format, tmp) \
219 list_for_each_entry_safe(format, tmp, &perf_hpp__list, list)
220
221#define perf_hpp__for_each_sort_list(format) \
222 list_for_each_entry(format, &perf_hpp__sort_list, sort_list)
223
224#define perf_hpp__for_each_sort_list_safe(format, tmp) \
225 list_for_each_entry_safe(format, tmp, &perf_hpp__sort_list, sort_list)
226
161extern struct perf_hpp_fmt perf_hpp__format[]; 227extern struct perf_hpp_fmt perf_hpp__format[];
162 228
163enum { 229enum {
@@ -167,6 +233,7 @@ enum {
167 PERF_HPP__OVERHEAD_US, 233 PERF_HPP__OVERHEAD_US,
168 PERF_HPP__OVERHEAD_GUEST_SYS, 234 PERF_HPP__OVERHEAD_GUEST_SYS,
169 PERF_HPP__OVERHEAD_GUEST_US, 235 PERF_HPP__OVERHEAD_GUEST_US,
236 PERF_HPP__OVERHEAD_ACC,
170 PERF_HPP__SAMPLES, 237 PERF_HPP__SAMPLES,
171 PERF_HPP__PERIOD, 238 PERF_HPP__PERIOD,
172 239
@@ -175,15 +242,36 @@ enum {
175 242
176void perf_hpp__init(void); 243void perf_hpp__init(void);
177void perf_hpp__column_register(struct perf_hpp_fmt *format); 244void perf_hpp__column_register(struct perf_hpp_fmt *format);
245void perf_hpp__column_unregister(struct perf_hpp_fmt *format);
178void perf_hpp__column_enable(unsigned col); 246void perf_hpp__column_enable(unsigned col);
247void perf_hpp__column_disable(unsigned col);
248void perf_hpp__cancel_cumulate(void);
249
250void perf_hpp__register_sort_field(struct perf_hpp_fmt *format);
251void perf_hpp__setup_output_field(void);
252void perf_hpp__reset_output_field(void);
253void perf_hpp__append_sort_keys(void);
254
255bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format);
256bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b);
257
258static inline bool perf_hpp__should_skip(struct perf_hpp_fmt *format)
259{
260 return format->elide;
261}
262
263void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists);
179 264
180typedef u64 (*hpp_field_fn)(struct hist_entry *he); 265typedef u64 (*hpp_field_fn)(struct hist_entry *he);
181typedef int (*hpp_callback_fn)(struct perf_hpp *hpp, bool front); 266typedef int (*hpp_callback_fn)(struct perf_hpp *hpp, bool front);
182typedef int (*hpp_snprint_fn)(struct perf_hpp *hpp, const char *fmt, ...); 267typedef int (*hpp_snprint_fn)(struct perf_hpp *hpp, const char *fmt, ...);
183 268
184int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, 269int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
185 hpp_field_fn get_field, hpp_callback_fn callback, 270 hpp_field_fn get_field, const char *fmt,
186 const char *fmt, hpp_snprint_fn print_fn, bool fmt_percent); 271 hpp_snprint_fn print_fn, bool fmt_percent);
272int __hpp__fmt_acc(struct perf_hpp *hpp, struct hist_entry *he,
273 hpp_field_fn get_field, const char *fmt,
274 hpp_snprint_fn print_fn, bool fmt_percent);
187 275
188static inline void advance_hpp(struct perf_hpp *hpp, int inc) 276static inline void advance_hpp(struct perf_hpp *hpp, int inc)
189{ 277{
@@ -250,4 +338,10 @@ static inline int script_browse(const char *script_opt __maybe_unused)
250#endif 338#endif
251 339
252unsigned int hists__sort_list_width(struct hists *hists); 340unsigned int hists__sort_list_width(struct hists *hists);
341
342struct option;
343int parse_filter_percentage(const struct option *opt __maybe_unused,
344 const char *arg, int unset __maybe_unused);
345int perf_hist_config(const char *var, const char *value);
346
253#endif /* __PERF_HIST_H */ 347#endif /* __PERF_HIST_H */
diff --git a/tools/perf/util/include/linux/bitmap.h b/tools/perf/util/include/linux/bitmap.h
index bb162e40c76c..01ffd12dc791 100644
--- a/tools/perf/util/include/linux/bitmap.h
+++ b/tools/perf/util/include/linux/bitmap.h
@@ -4,6 +4,9 @@
4#include <string.h> 4#include <string.h>
5#include <linux/bitops.h> 5#include <linux/bitops.h>
6 6
7#define DECLARE_BITMAP(name,bits) \
8 unsigned long name[BITS_TO_LONGS(bits)]
9
7int __bitmap_weight(const unsigned long *bitmap, int bits); 10int __bitmap_weight(const unsigned long *bitmap, int bits);
8void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1, 11void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
9 const unsigned long *bitmap2, int bits); 12 const unsigned long *bitmap2, int bits);
diff --git a/tools/perf/util/include/linux/export.h b/tools/perf/util/include/linux/export.h
deleted file mode 100644
index b43e2dc21e04..000000000000
--- a/tools/perf/util/include/linux/export.h
+++ /dev/null
@@ -1,6 +0,0 @@
1#ifndef PERF_LINUX_MODULE_H
2#define PERF_LINUX_MODULE_H
3
4#define EXPORT_SYMBOL(name)
5
6#endif
diff --git a/tools/perf/util/include/linux/list.h b/tools/perf/util/include/linux/list.h
index bfe0a2afd0d2..76ddbc726343 100644
--- a/tools/perf/util/include/linux/list.h
+++ b/tools/perf/util/include/linux/list.h
@@ -1,4 +1,5 @@
1#include <linux/kernel.h> 1#include <linux/kernel.h>
2#include <linux/types.h>
2 3
3#include "../../../../include/linux/list.h" 4#include "../../../../include/linux/list.h"
4 5
diff --git a/tools/perf/util/include/linux/types.h b/tools/perf/util/include/linux/types.h
deleted file mode 100644
index eb464786c084..000000000000
--- a/tools/perf/util/include/linux/types.h
+++ /dev/null
@@ -1,29 +0,0 @@
1#ifndef _PERF_LINUX_TYPES_H_
2#define _PERF_LINUX_TYPES_H_
3
4#include <asm/types.h>
5
6#ifndef __bitwise
7#define __bitwise
8#endif
9
10#ifndef __le32
11typedef __u32 __bitwise __le32;
12#endif
13
14#define DECLARE_BITMAP(name,bits) \
15 unsigned long name[BITS_TO_LONGS(bits)]
16
17struct list_head {
18 struct list_head *next, *prev;
19};
20
21struct hlist_head {
22 struct hlist_node *first;
23};
24
25struct hlist_node {
26 struct hlist_node *next, **pprev;
27};
28
29#endif
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 27c2a5efe450..0e5fea95d596 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -316,6 +316,17 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
316 rb_link_node(&th->rb_node, parent, p); 316 rb_link_node(&th->rb_node, parent, p);
317 rb_insert_color(&th->rb_node, &machine->threads); 317 rb_insert_color(&th->rb_node, &machine->threads);
318 machine->last_match = th; 318 machine->last_match = th;
319
320 /*
321 * We have to initialize map_groups separately
322 * after rb tree is updated.
323 *
324 * The reason is that we call machine__findnew_thread
325 * within thread__init_map_groups to find the thread
326 * leader and that would screwed the rb tree.
327 */
328 if (thread__init_map_groups(th, machine))
329 return NULL;
319 } 330 }
320 331
321 return th; 332 return th;
@@ -1049,6 +1060,8 @@ int machine__process_mmap2_event(struct machine *machine,
1049 event->mmap2.pid, event->mmap2.maj, 1060 event->mmap2.pid, event->mmap2.maj,
1050 event->mmap2.min, event->mmap2.ino, 1061 event->mmap2.min, event->mmap2.ino,
1051 event->mmap2.ino_generation, 1062 event->mmap2.ino_generation,
1063 event->mmap2.prot,
1064 event->mmap2.flags,
1052 event->mmap2.filename, type); 1065 event->mmap2.filename, type);
1053 1066
1054 if (map == NULL) 1067 if (map == NULL)
@@ -1094,7 +1107,7 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
1094 1107
1095 map = map__new(&machine->user_dsos, event->mmap.start, 1108 map = map__new(&machine->user_dsos, event->mmap.start,
1096 event->mmap.len, event->mmap.pgoff, 1109 event->mmap.len, event->mmap.pgoff,
1097 event->mmap.pid, 0, 0, 0, 0, 1110 event->mmap.pid, 0, 0, 0, 0, 0, 0,
1098 event->mmap.filename, 1111 event->mmap.filename,
1099 type); 1112 type);
1100 1113
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 39cd2d0faff6..25c571f4cba6 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -32,6 +32,93 @@ static inline int is_no_dso_memory(const char *filename)
32 !strcmp(filename, "[heap]"); 32 !strcmp(filename, "[heap]");
33} 33}
34 34
35static inline int is_android_lib(const char *filename)
36{
37 return !strncmp(filename, "/data/app-lib", 13) ||
38 !strncmp(filename, "/system/lib", 11);
39}
40
41static inline bool replace_android_lib(const char *filename, char *newfilename)
42{
43 const char *libname;
44 char *app_abi;
45 size_t app_abi_length, new_length;
46 size_t lib_length = 0;
47
48 libname = strrchr(filename, '/');
49 if (libname)
50 lib_length = strlen(libname);
51
52 app_abi = getenv("APP_ABI");
53 if (!app_abi)
54 return false;
55
56 app_abi_length = strlen(app_abi);
57
58 if (!strncmp(filename, "/data/app-lib", 13)) {
59 char *apk_path;
60
61 if (!app_abi_length)
62 return false;
63
64 new_length = 7 + app_abi_length + lib_length;
65
66 apk_path = getenv("APK_PATH");
67 if (apk_path) {
68 new_length += strlen(apk_path) + 1;
69 if (new_length > PATH_MAX)
70 return false;
71 snprintf(newfilename, new_length,
72 "%s/libs/%s/%s", apk_path, app_abi, libname);
73 } else {
74 if (new_length > PATH_MAX)
75 return false;
76 snprintf(newfilename, new_length,
77 "libs/%s/%s", app_abi, libname);
78 }
79 return true;
80 }
81
82 if (!strncmp(filename, "/system/lib/", 11)) {
83 char *ndk, *app;
84 const char *arch;
85 size_t ndk_length;
86 size_t app_length;
87
88 ndk = getenv("NDK_ROOT");
89 app = getenv("APP_PLATFORM");
90
91 if (!(ndk && app))
92 return false;
93
94 ndk_length = strlen(ndk);
95 app_length = strlen(app);
96
97 if (!(ndk_length && app_length && app_abi_length))
98 return false;
99
100 arch = !strncmp(app_abi, "arm", 3) ? "arm" :
101 !strncmp(app_abi, "mips", 4) ? "mips" :
102 !strncmp(app_abi, "x86", 3) ? "x86" : NULL;
103
104 if (!arch)
105 return false;
106
107 new_length = 27 + ndk_length +
108 app_length + lib_length
109 + strlen(arch);
110
111 if (new_length > PATH_MAX)
112 return false;
113 snprintf(newfilename, new_length,
114 "%s/platforms/%s/arch-%s/usr/lib/%s",
115 ndk, app, arch, libname);
116
117 return true;
118 }
119 return false;
120}
121
35void map__init(struct map *map, enum map_type type, 122void map__init(struct map *map, enum map_type type,
36 u64 start, u64 end, u64 pgoff, struct dso *dso) 123 u64 start, u64 end, u64 pgoff, struct dso *dso)
37{ 124{
@@ -51,7 +138,7 @@ void map__init(struct map *map, enum map_type type,
51 138
52struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, 139struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
53 u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino, 140 u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
54 u64 ino_gen, char *filename, 141 u64 ino_gen, u32 prot, u32 flags, char *filename,
55 enum map_type type) 142 enum map_type type)
56{ 143{
57 struct map *map = malloc(sizeof(*map)); 144 struct map *map = malloc(sizeof(*map));
@@ -59,8 +146,9 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
59 if (map != NULL) { 146 if (map != NULL) {
60 char newfilename[PATH_MAX]; 147 char newfilename[PATH_MAX];
61 struct dso *dso; 148 struct dso *dso;
62 int anon, no_dso, vdso; 149 int anon, no_dso, vdso, android;
63 150
151 android = is_android_lib(filename);
64 anon = is_anon_memory(filename); 152 anon = is_anon_memory(filename);
65 vdso = is_vdso_map(filename); 153 vdso = is_vdso_map(filename);
66 no_dso = is_no_dso_memory(filename); 154 no_dso = is_no_dso_memory(filename);
@@ -69,12 +157,19 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
69 map->min = d_min; 157 map->min = d_min;
70 map->ino = ino; 158 map->ino = ino;
71 map->ino_generation = ino_gen; 159 map->ino_generation = ino_gen;
160 map->prot = prot;
161 map->flags = flags;
72 162
73 if ((anon || no_dso) && type == MAP__FUNCTION) { 163 if ((anon || no_dso) && type == MAP__FUNCTION) {
74 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid); 164 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid);
75 filename = newfilename; 165 filename = newfilename;
76 } 166 }
77 167
168 if (android) {
169 if (replace_android_lib(filename, newfilename))
170 filename = newfilename;
171 }
172
78 if (vdso) { 173 if (vdso) {
79 pgoff = 0; 174 pgoff = 0;
80 dso = vdso__dso_findnew(dsos__list); 175 dso = vdso__dso_findnew(dsos__list);
@@ -323,6 +418,7 @@ void map_groups__init(struct map_groups *mg)
323 INIT_LIST_HEAD(&mg->removed_maps[i]); 418 INIT_LIST_HEAD(&mg->removed_maps[i]);
324 } 419 }
325 mg->machine = NULL; 420 mg->machine = NULL;
421 mg->refcnt = 1;
326} 422}
327 423
328static void maps__delete(struct rb_root *maps) 424static void maps__delete(struct rb_root *maps)
@@ -358,6 +454,28 @@ void map_groups__exit(struct map_groups *mg)
358 } 454 }
359} 455}
360 456
457struct map_groups *map_groups__new(void)
458{
459 struct map_groups *mg = malloc(sizeof(*mg));
460
461 if (mg != NULL)
462 map_groups__init(mg);
463
464 return mg;
465}
466
467void map_groups__delete(struct map_groups *mg)
468{
469 map_groups__exit(mg);
470 free(mg);
471}
472
473void map_groups__put(struct map_groups *mg)
474{
475 if (--mg->refcnt == 0)
476 map_groups__delete(mg);
477}
478
361void map_groups__flush(struct map_groups *mg) 479void map_groups__flush(struct map_groups *mg)
362{ 480{
363 int type; 481 int type;
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index f00f058afb3b..7758c72522ef 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -6,7 +6,7 @@
6#include <linux/rbtree.h> 6#include <linux/rbtree.h>
7#include <stdio.h> 7#include <stdio.h>
8#include <stdbool.h> 8#include <stdbool.h>
9#include "types.h" 9#include <linux/types.h>
10 10
11enum map_type { 11enum map_type {
12 MAP__FUNCTION = 0, 12 MAP__FUNCTION = 0,
@@ -35,6 +35,8 @@ struct map {
35 bool referenced; 35 bool referenced;
36 bool erange_warned; 36 bool erange_warned;
37 u32 priv; 37 u32 priv;
38 u32 prot;
39 u32 flags;
38 u64 pgoff; 40 u64 pgoff;
39 u64 reloc; 41 u64 reloc;
40 u32 maj, min; /* only valid for MMAP2 record */ 42 u32 maj, min; /* only valid for MMAP2 record */
@@ -59,8 +61,20 @@ struct map_groups {
59 struct rb_root maps[MAP__NR_TYPES]; 61 struct rb_root maps[MAP__NR_TYPES];
60 struct list_head removed_maps[MAP__NR_TYPES]; 62 struct list_head removed_maps[MAP__NR_TYPES];
61 struct machine *machine; 63 struct machine *machine;
64 int refcnt;
62}; 65};
63 66
67struct map_groups *map_groups__new(void);
68void map_groups__delete(struct map_groups *mg);
69
70static inline struct map_groups *map_groups__get(struct map_groups *mg)
71{
72 ++mg->refcnt;
73 return mg;
74}
75
76void map_groups__put(struct map_groups *mg);
77
64static inline struct kmap *map__kmap(struct map *map) 78static inline struct kmap *map__kmap(struct map *map)
65{ 79{
66 return (struct kmap *)(map + 1); 80 return (struct kmap *)(map + 1);
@@ -106,7 +120,7 @@ void map__init(struct map *map, enum map_type type,
106 u64 start, u64 end, u64 pgoff, struct dso *dso); 120 u64 start, u64 end, u64 pgoff, struct dso *dso);
107struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, 121struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
108 u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino, 122 u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
109 u64 ino_gen, 123 u64 ino_gen, u32 prot, u32 flags,
110 char *filename, enum map_type type); 124 char *filename, enum map_type type);
111struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 125struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
112void map__delete(struct map *map); 126void map__delete(struct map *map);
diff --git a/tools/perf/util/pager.c b/tools/perf/util/pager.c
index 3322b8446e89..31ee02d4e988 100644
--- a/tools/perf/util/pager.c
+++ b/tools/perf/util/pager.c
@@ -57,13 +57,13 @@ void setup_pager(void)
57 } 57 }
58 if (!pager) 58 if (!pager)
59 pager = getenv("PAGER"); 59 pager = getenv("PAGER");
60 if (!pager) { 60 if (!(pager || access("/usr/bin/pager", X_OK)))
61 if (!access("/usr/bin/pager", X_OK)) 61 pager = "/usr/bin/pager";
62 pager = "/usr/bin/pager"; 62 if (!(pager || access("/usr/bin/less", X_OK)))
63 } 63 pager = "/usr/bin/less";
64 if (!pager) 64 if (!pager)
65 pager = "less"; 65 pager = "cat";
66 else if (!*pager || !strcmp(pager, "cat")) 66 if (!*pager || !strcmp(pager, "cat"))
67 return; 67 return;
68 68
69 spawned_pager = 1; /* means we are emitting to terminal */ 69 spawned_pager = 1; /* means we are emitting to terminal */
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index f1cb4c4b3c70..df094b4ed5ed 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -6,9 +6,8 @@
6 6
7#include <linux/list.h> 7#include <linux/list.h>
8#include <stdbool.h> 8#include <stdbool.h>
9#include "types.h" 9#include <linux/types.h>
10#include <linux/perf_event.h> 10#include <linux/perf_event.h>
11#include "types.h"
12 11
13struct list_head; 12struct list_head;
14struct perf_evsel; 13struct perf_evsel;
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index 4eb67ec333f1..0bc87ba46bf3 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -9,7 +9,7 @@
9 9
10#include <linux/compiler.h> 10#include <linux/compiler.h>
11#include <linux/list.h> 11#include <linux/list.h>
12#include "types.h" 12#include <linux/types.h>
13#include "util.h" 13#include "util.h"
14#include "parse-events.h" 14#include "parse-events.h"
15#include "parse-events-bison.h" 15#include "parse-events-bison.h"
@@ -299,6 +299,18 @@ PE_PREFIX_MEM PE_VALUE sep_dc
299} 299}
300 300
301event_legacy_tracepoint: 301event_legacy_tracepoint:
302PE_NAME '-' PE_NAME ':' PE_NAME
303{
304 struct parse_events_evlist *data = _data;
305 struct list_head *list;
306 char sys_name[128];
307 snprintf(&sys_name, 128, "%s-%s", $1, $3);
308
309 ALLOC_LIST(list);
310 ABORT_ON(parse_events_add_tracepoint(list, &data->idx, &sys_name, $5));
311 $$ = list;
312}
313|
302PE_NAME ':' PE_NAME 314PE_NAME ':' PE_NAME
303{ 315{
304 struct parse_events_evlist *data = _data; 316 struct parse_events_evlist *data = _data;
diff --git a/tools/perf/util/perf_regs.c b/tools/perf/util/perf_regs.c
index a3539ef30b15..43168fb0d9a2 100644
--- a/tools/perf/util/perf_regs.c
+++ b/tools/perf/util/perf_regs.c
@@ -1,11 +1,15 @@
1#include <errno.h> 1#include <errno.h>
2#include "perf_regs.h" 2#include "perf_regs.h"
3#include "event.h"
3 4
4int perf_reg_value(u64 *valp, struct regs_dump *regs, int id) 5int perf_reg_value(u64 *valp, struct regs_dump *regs, int id)
5{ 6{
6 int i, idx = 0; 7 int i, idx = 0;
7 u64 mask = regs->mask; 8 u64 mask = regs->mask;
8 9
10 if (regs->cache_mask & (1 << id))
11 goto out;
12
9 if (!(mask & (1 << id))) 13 if (!(mask & (1 << id)))
10 return -EINVAL; 14 return -EINVAL;
11 15
@@ -14,6 +18,10 @@ int perf_reg_value(u64 *valp, struct regs_dump *regs, int id)
14 idx++; 18 idx++;
15 } 19 }
16 20
17 *valp = regs->regs[idx]; 21 regs->cache_mask |= (1 << id);
22 regs->cache_regs[id] = regs->regs[idx];
23
24out:
25 *valp = regs->cache_regs[id];
18 return 0; 26 return 0;
19} 27}
diff --git a/tools/perf/util/perf_regs.h b/tools/perf/util/perf_regs.h
index d6e8b6a8d7f3..980dbf76bc98 100644
--- a/tools/perf/util/perf_regs.h
+++ b/tools/perf/util/perf_regs.h
@@ -1,8 +1,9 @@
1#ifndef __PERF_REGS_H 1#ifndef __PERF_REGS_H
2#define __PERF_REGS_H 2#define __PERF_REGS_H
3 3
4#include "types.h" 4#include <linux/types.h>
5#include "event.h" 5
6struct regs_dump;
6 7
7#ifdef HAVE_PERF_REGS_SUPPORT 8#ifdef HAVE_PERF_REGS_SUPPORT
8#include <perf_regs.h> 9#include <perf_regs.h>
@@ -11,6 +12,7 @@ int perf_reg_value(u64 *valp, struct regs_dump *regs, int id);
11 12
12#else 13#else
13#define PERF_REGS_MASK 0 14#define PERF_REGS_MASK 0
15#define PERF_REGS_MAX 0
14 16
15static inline const char *perf_reg_name(int id __maybe_unused) 17static inline const char *perf_reg_name(int id __maybe_unused)
16{ 18{
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 00a7dcb2f55c..7a811eb61f75 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -284,17 +284,17 @@ static int pmu_aliases(const char *name, struct list_head *head)
284static int pmu_alias_terms(struct perf_pmu_alias *alias, 284static int pmu_alias_terms(struct perf_pmu_alias *alias,
285 struct list_head *terms) 285 struct list_head *terms)
286{ 286{
287 struct parse_events_term *term, *clone; 287 struct parse_events_term *term, *cloned;
288 LIST_HEAD(list); 288 LIST_HEAD(list);
289 int ret; 289 int ret;
290 290
291 list_for_each_entry(term, &alias->terms, list) { 291 list_for_each_entry(term, &alias->terms, list) {
292 ret = parse_events_term__clone(&clone, term); 292 ret = parse_events_term__clone(&cloned, term);
293 if (ret) { 293 if (ret) {
294 parse_events__free_terms(&list); 294 parse_events__free_terms(&list);
295 return ret; 295 return ret;
296 } 296 }
297 list_add_tail(&clone->list, &list); 297 list_add_tail(&cloned->list, &list);
298 } 298 }
299 list_splice(&list, terms); 299 list_splice(&list, terms);
300 return 0; 300 return 0;
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 8b64125a9281..c14a543ce1f3 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -1,7 +1,7 @@
1#ifndef __PMU_H 1#ifndef __PMU_H
2#define __PMU_H 2#define __PMU_H
3 3
4#include <linux/bitops.h> 4#include <linux/bitmap.h>
5#include <linux/perf_event.h> 5#include <linux/perf_event.h>
6#include <stdbool.h> 6#include <stdbool.h>
7 7
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 0d1542f33d87..9a0a1839a377 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -628,11 +628,11 @@ static int __show_line_range(struct line_range *lr, const char *module)
628 628
629 ret = debuginfo__find_line_range(dinfo, lr); 629 ret = debuginfo__find_line_range(dinfo, lr);
630 debuginfo__delete(dinfo); 630 debuginfo__delete(dinfo);
631 if (ret == 0) { 631 if (ret == 0 || ret == -ENOENT) {
632 pr_warning("Specified source line is not found.\n"); 632 pr_warning("Specified source line is not found.\n");
633 return -ENOENT; 633 return -ENOENT;
634 } else if (ret < 0) { 634 } else if (ret < 0) {
635 pr_warning("Debuginfo analysis failed. (%d)\n", ret); 635 pr_warning("Debuginfo analysis failed.\n");
636 return ret; 636 return ret;
637 } 637 }
638 638
@@ -641,7 +641,7 @@ static int __show_line_range(struct line_range *lr, const char *module)
641 ret = get_real_path(tmp, lr->comp_dir, &lr->path); 641 ret = get_real_path(tmp, lr->comp_dir, &lr->path);
642 free(tmp); /* Free old path */ 642 free(tmp); /* Free old path */
643 if (ret < 0) { 643 if (ret < 0) {
644 pr_warning("Failed to find source file. (%d)\n", ret); 644 pr_warning("Failed to find source file path.\n");
645 return ret; 645 return ret;
646 } 646 }
647 647
@@ -721,9 +721,14 @@ static int show_available_vars_at(struct debuginfo *dinfo,
721 ret = debuginfo__find_available_vars_at(dinfo, pev, &vls, 721 ret = debuginfo__find_available_vars_at(dinfo, pev, &vls,
722 max_vls, externs); 722 max_vls, externs);
723 if (ret <= 0) { 723 if (ret <= 0) {
724 pr_err("Failed to find variables at %s (%d)\n", buf, ret); 724 if (ret == 0 || ret == -ENOENT) {
725 pr_err("Failed to find the address of %s\n", buf);
726 ret = -ENOENT;
727 } else
728 pr_warning("Debuginfo analysis failed.\n");
725 goto end; 729 goto end;
726 } 730 }
731
727 /* Some variables are found */ 732 /* Some variables are found */
728 fprintf(stdout, "Available variables at %s\n", buf); 733 fprintf(stdout, "Available variables at %s\n", buf);
729 for (i = 0; i < ret; i++) { 734 for (i = 0; i < ret; i++) {
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 562762117639..98e304766416 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -511,12 +511,12 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
511 511
512 ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops, 512 ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops,
513 &pf->sp_die, pf->tvar); 513 &pf->sp_die, pf->tvar);
514 if (ret == -ENOENT) 514 if (ret == -ENOENT || ret == -EINVAL)
515 pr_err("Failed to find the location of %s at this address.\n" 515 pr_err("Failed to find the location of %s at this address.\n"
516 " Perhaps, it has been optimized out.\n", pf->pvar->var); 516 " Perhaps, it has been optimized out.\n", pf->pvar->var);
517 else if (ret == -ENOTSUP) 517 else if (ret == -ENOTSUP)
518 pr_err("Sorry, we don't support this variable location yet.\n"); 518 pr_err("Sorry, we don't support this variable location yet.\n");
519 else if (pf->pvar->field) { 519 else if (ret == 0 && pf->pvar->field) {
520 ret = convert_variable_fields(vr_die, pf->pvar->var, 520 ret = convert_variable_fields(vr_die, pf->pvar->var,
521 pf->pvar->field, &pf->tvar->ref, 521 pf->pvar->field, &pf->tvar->ref,
522 &die_mem); 522 &die_mem);
@@ -573,14 +573,13 @@ static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf)
573 if (!die_find_variable_at(sc_die, pf->pvar->var, pf->addr, &vr_die)) { 573 if (!die_find_variable_at(sc_die, pf->pvar->var, pf->addr, &vr_die)) {
574 /* Search again in global variables */ 574 /* Search again in global variables */
575 if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die)) 575 if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die))
576 pr_warning("Failed to find '%s' in this function.\n",
577 pf->pvar->var);
576 ret = -ENOENT; 578 ret = -ENOENT;
577 } 579 }
578 if (ret >= 0) 580 if (ret >= 0)
579 ret = convert_variable(&vr_die, pf); 581 ret = convert_variable(&vr_die, pf);
580 582
581 if (ret < 0)
582 pr_warning("Failed to find '%s' in this function.\n",
583 pf->pvar->var);
584 return ret; 583 return ret;
585} 584}
586 585
@@ -1281,7 +1280,11 @@ out:
1281 return ret; 1280 return ret;
1282} 1281}
1283 1282
1284/* Find available variables at given probe point */ 1283/*
1284 * Find available variables at given probe point
1285 * Return the number of found probe points. Return 0 if there is no
1286 * matched probe point. Return <0 if an error occurs.
1287 */
1285int debuginfo__find_available_vars_at(struct debuginfo *dbg, 1288int debuginfo__find_available_vars_at(struct debuginfo *dbg,
1286 struct perf_probe_event *pev, 1289 struct perf_probe_event *pev,
1287 struct variable_list **vls, 1290 struct variable_list **vls,
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index e108207c5de0..af7da565a750 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -215,6 +215,7 @@ static void define_event_symbols(struct event_format *event,
215 case PRINT_BSTRING: 215 case PRINT_BSTRING:
216 case PRINT_DYNAMIC_ARRAY: 216 case PRINT_DYNAMIC_ARRAY:
217 case PRINT_STRING: 217 case PRINT_STRING:
218 case PRINT_BITMASK:
218 break; 219 break;
219 case PRINT_TYPE: 220 case PRINT_TYPE:
220 define_event_symbols(event, ev_name, args->typecast.item); 221 define_event_symbols(event, ev_name, args->typecast.item);
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index cd9774df3750..1c419321f707 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -197,6 +197,7 @@ static void define_event_symbols(struct event_format *event,
197 case PRINT_BSTRING: 197 case PRINT_BSTRING:
198 case PRINT_DYNAMIC_ARRAY: 198 case PRINT_DYNAMIC_ARRAY:
199 case PRINT_FUNC: 199 case PRINT_FUNC:
200 case PRINT_BITMASK:
200 /* we should warn... */ 201 /* we should warn... */
201 return; 202 return;
202 } 203 }
@@ -622,6 +623,7 @@ static int python_generate_script(struct pevent *pevent, const char *outfile)
622 fprintf(ofp, "%s=", f->name); 623 fprintf(ofp, "%s=", f->name);
623 if (f->flags & FIELD_IS_STRING || 624 if (f->flags & FIELD_IS_STRING ||
624 f->flags & FIELD_IS_FLAG || 625 f->flags & FIELD_IS_FLAG ||
626 f->flags & FIELD_IS_ARRAY ||
625 f->flags & FIELD_IS_SYMBOLIC) 627 f->flags & FIELD_IS_SYMBOLIC)
626 fprintf(ofp, "%%s"); 628 fprintf(ofp, "%%s");
627 else if (f->flags & FIELD_IS_SIGNED) 629 else if (f->flags & FIELD_IS_SIGNED)
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 55960f22233c..64a186edc7be 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1625,13 +1625,14 @@ out_delete_map:
1625void perf_session__fprintf_info(struct perf_session *session, FILE *fp, 1625void perf_session__fprintf_info(struct perf_session *session, FILE *fp,
1626 bool full) 1626 bool full)
1627{ 1627{
1628 int fd = perf_data_file__fd(session->file);
1629 struct stat st; 1628 struct stat st;
1630 int ret; 1629 int fd, ret;
1631 1630
1632 if (session == NULL || fp == NULL) 1631 if (session == NULL || fp == NULL)
1633 return; 1632 return;
1634 1633
1634 fd = perf_data_file__fd(session->file);
1635
1635 ret = fstat(fd, &st); 1636 ret = fstat(fd, &st);
1636 if (ret == -1) 1637 if (ret == -1)
1637 return; 1638 return;
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 635cd8f8b22e..1ec57dd82284 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -1,13 +1,20 @@
1#include <sys/mman.h>
1#include "sort.h" 2#include "sort.h"
2#include "hist.h" 3#include "hist.h"
3#include "comm.h" 4#include "comm.h"
4#include "symbol.h" 5#include "symbol.h"
6#include "evsel.h"
5 7
6regex_t parent_regex; 8regex_t parent_regex;
7const char default_parent_pattern[] = "^sys_|^do_page_fault"; 9const char default_parent_pattern[] = "^sys_|^do_page_fault";
8const char *parent_pattern = default_parent_pattern; 10const char *parent_pattern = default_parent_pattern;
9const char default_sort_order[] = "comm,dso,symbol"; 11const char default_sort_order[] = "comm,dso,symbol";
10const char *sort_order = default_sort_order; 12const char default_branch_sort_order[] = "comm,dso_from,symbol_from,dso_to,symbol_to";
13const 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";
15const char default_diff_sort_order[] = "dso,symbol";
16const char *sort_order;
17const char *field_order;
11regex_t ignore_callees_regex; 18regex_t ignore_callees_regex;
12int have_ignore_callees = 0; 19int have_ignore_callees = 0;
13int sort__need_collapse = 0; 20int sort__need_collapse = 0;
@@ -16,9 +23,6 @@ int sort__has_sym = 0;
16int sort__has_dso = 0; 23int sort__has_dso = 0;
17enum sort_mode sort__mode = SORT_MODE__NORMAL; 24enum sort_mode sort__mode = SORT_MODE__NORMAL;
18 25
19enum sort_type sort__first_dimension;
20
21LIST_HEAD(hist_entry__sort_list);
22 26
23static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...) 27static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
24{ 28{
@@ -93,6 +97,12 @@ sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
93 return comm__str(right->comm) - comm__str(left->comm); 97 return comm__str(right->comm) - comm__str(left->comm);
94} 98}
95 99
100static int64_t
101sort__comm_sort(struct hist_entry *left, struct hist_entry *right)
102{
103 return strcmp(comm__str(right->comm), comm__str(left->comm));
104}
105
96static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf, 106static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf,
97 size_t size, unsigned int width) 107 size_t size, unsigned int width)
98{ 108{
@@ -103,6 +113,7 @@ struct sort_entry sort_comm = {
103 .se_header = "Command", 113 .se_header = "Command",
104 .se_cmp = sort__comm_cmp, 114 .se_cmp = sort__comm_cmp,
105 .se_collapse = sort__comm_collapse, 115 .se_collapse = sort__comm_collapse,
116 .se_sort = sort__comm_sort,
106 .se_snprintf = hist_entry__comm_snprintf, 117 .se_snprintf = hist_entry__comm_snprintf,
107 .se_width_idx = HISTC_COMM, 118 .se_width_idx = HISTC_COMM,
108}; 119};
@@ -116,7 +127,7 @@ static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
116 const char *dso_name_l, *dso_name_r; 127 const char *dso_name_l, *dso_name_r;
117 128
118 if (!dso_l || !dso_r) 129 if (!dso_l || !dso_r)
119 return cmp_null(dso_l, dso_r); 130 return cmp_null(dso_r, dso_l);
120 131
121 if (verbose) { 132 if (verbose) {
122 dso_name_l = dso_l->long_name; 133 dso_name_l = dso_l->long_name;
@@ -132,7 +143,7 @@ static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
132static int64_t 143static int64_t
133sort__dso_cmp(struct hist_entry *left, struct hist_entry *right) 144sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
134{ 145{
135 return _sort__dso_cmp(left->ms.map, right->ms.map); 146 return _sort__dso_cmp(right->ms.map, left->ms.map);
136} 147}
137 148
138static int _hist_entry__dso_snprintf(struct map *map, char *bf, 149static int _hist_entry__dso_snprintf(struct map *map, char *bf,
@@ -204,6 +215,15 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
204 return _sort__sym_cmp(left->ms.sym, right->ms.sym); 215 return _sort__sym_cmp(left->ms.sym, right->ms.sym);
205} 216}
206 217
218static int64_t
219sort__sym_sort(struct hist_entry *left, struct hist_entry *right)
220{
221 if (!left->ms.sym || !right->ms.sym)
222 return cmp_null(left->ms.sym, right->ms.sym);
223
224 return strcmp(right->ms.sym->name, left->ms.sym->name);
225}
226
207static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym, 227static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
208 u64 ip, char level, char *bf, size_t size, 228 u64 ip, char level, char *bf, size_t size,
209 unsigned int width) 229 unsigned int width)
@@ -250,6 +270,7 @@ static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
250struct sort_entry sort_sym = { 270struct sort_entry sort_sym = {
251 .se_header = "Symbol", 271 .se_header = "Symbol",
252 .se_cmp = sort__sym_cmp, 272 .se_cmp = sort__sym_cmp,
273 .se_sort = sort__sym_sort,
253 .se_snprintf = hist_entry__sym_snprintf, 274 .se_snprintf = hist_entry__sym_snprintf,
254 .se_width_idx = HISTC_SYMBOL, 275 .se_width_idx = HISTC_SYMBOL,
255}; 276};
@@ -277,7 +298,7 @@ sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
277 map__rip_2objdump(map, right->ip)); 298 map__rip_2objdump(map, right->ip));
278 } 299 }
279 } 300 }
280 return strcmp(left->srcline, right->srcline); 301 return strcmp(right->srcline, left->srcline);
281} 302}
282 303
283static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf, 304static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
@@ -305,7 +326,7 @@ sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
305 if (!sym_l || !sym_r) 326 if (!sym_l || !sym_r)
306 return cmp_null(sym_l, sym_r); 327 return cmp_null(sym_l, sym_r);
307 328
308 return strcmp(sym_l->name, sym_r->name); 329 return strcmp(sym_r->name, sym_l->name);
309} 330}
310 331
311static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf, 332static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
@@ -764,6 +785,104 @@ static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
764 return repsep_snprintf(bf, size, "%-*s", width, out); 785 return repsep_snprintf(bf, size, "%-*s", width, out);
765} 786}
766 787
788static inline u64 cl_address(u64 address)
789{
790 /* return the cacheline of the address */
791 return (address & ~(cacheline_size - 1));
792}
793
794static int64_t
795sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right)
796{
797 u64 l, r;
798 struct map *l_map, *r_map;
799
800 if (!left->mem_info) return -1;
801 if (!right->mem_info) return 1;
802
803 /* group event types together */
804 if (left->cpumode > right->cpumode) return -1;
805 if (left->cpumode < right->cpumode) return 1;
806
807 l_map = left->mem_info->daddr.map;
808 r_map = right->mem_info->daddr.map;
809
810 /* if both are NULL, jump to sort on al_addr instead */
811 if (!l_map && !r_map)
812 goto addr;
813
814 if (!l_map) return -1;
815 if (!r_map) return 1;
816
817 if (l_map->maj > r_map->maj) return -1;
818 if (l_map->maj < r_map->maj) return 1;
819
820 if (l_map->min > r_map->min) return -1;
821 if (l_map->min < r_map->min) return 1;
822
823 if (l_map->ino > r_map->ino) return -1;
824 if (l_map->ino < r_map->ino) return 1;
825
826 if (l_map->ino_generation > r_map->ino_generation) return -1;
827 if (l_map->ino_generation < r_map->ino_generation) return 1;
828
829 /*
830 * Addresses with no major/minor numbers are assumed to be
831 * anonymous in userspace. Sort those on pid then address.
832 *
833 * The kernel and non-zero major/minor mapped areas are
834 * assumed to be unity mapped. Sort those on address.
835 */
836
837 if ((left->cpumode != PERF_RECORD_MISC_KERNEL) &&
838 (!(l_map->flags & MAP_SHARED)) &&
839 !l_map->maj && !l_map->min && !l_map->ino &&
840 !l_map->ino_generation) {
841 /* userspace anonymous */
842
843 if (left->thread->pid_ > right->thread->pid_) return -1;
844 if (left->thread->pid_ < right->thread->pid_) return 1;
845 }
846
847addr:
848 /* al_addr does all the right addr - start + offset calculations */
849 l = cl_address(left->mem_info->daddr.al_addr);
850 r = cl_address(right->mem_info->daddr.al_addr);
851
852 if (l > r) return -1;
853 if (l < r) return 1;
854
855 return 0;
856}
857
858static int hist_entry__dcacheline_snprintf(struct hist_entry *he, char *bf,
859 size_t size, unsigned int width)
860{
861
862 uint64_t addr = 0;
863 struct map *map = NULL;
864 struct symbol *sym = NULL;
865 char level = he->level;
866
867 if (he->mem_info) {
868 addr = cl_address(he->mem_info->daddr.al_addr);
869 map = he->mem_info->daddr.map;
870 sym = he->mem_info->daddr.sym;
871
872 /* print [s] for shared data mmaps */
873 if ((he->cpumode != PERF_RECORD_MISC_KERNEL) &&
874 map && (map->type == MAP__VARIABLE) &&
875 (map->flags & MAP_SHARED) &&
876 (map->maj || map->min || map->ino ||
877 map->ino_generation))
878 level = 's';
879 else if (!map)
880 level = 'X';
881 }
882 return _hist_entry__sym_snprintf(map, sym, addr, level, bf, size,
883 width);
884}
885
767struct sort_entry sort_mispredict = { 886struct sort_entry sort_mispredict = {
768 .se_header = "Branch Mispredicted", 887 .se_header = "Branch Mispredicted",
769 .se_cmp = sort__mispredict_cmp, 888 .se_cmp = sort__mispredict_cmp,
@@ -856,6 +975,13 @@ struct sort_entry sort_mem_snoop = {
856 .se_width_idx = HISTC_MEM_SNOOP, 975 .se_width_idx = HISTC_MEM_SNOOP,
857}; 976};
858 977
978struct sort_entry sort_mem_dcacheline = {
979 .se_header = "Data Cacheline",
980 .se_cmp = sort__dcacheline_cmp,
981 .se_snprintf = hist_entry__dcacheline_snprintf,
982 .se_width_idx = HISTC_MEM_DCACHELINE,
983};
984
859static int64_t 985static int64_t
860sort__abort_cmp(struct hist_entry *left, struct hist_entry *right) 986sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
861{ 987{
@@ -1023,23 +1149,199 @@ static struct sort_dimension memory_sort_dimensions[] = {
1023 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb), 1149 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
1024 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl), 1150 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
1025 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop), 1151 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
1152 DIM(SORT_MEM_DCACHELINE, "dcacheline", sort_mem_dcacheline),
1153};
1154
1155#undef DIM
1156
1157struct hpp_dimension {
1158 const char *name;
1159 struct perf_hpp_fmt *fmt;
1160 int taken;
1161};
1162
1163#define DIM(d, n) { .name = n, .fmt = &perf_hpp__format[d], }
1164
1165static struct hpp_dimension hpp_sort_dimensions[] = {
1166 DIM(PERF_HPP__OVERHEAD, "overhead"),
1167 DIM(PERF_HPP__OVERHEAD_SYS, "overhead_sys"),
1168 DIM(PERF_HPP__OVERHEAD_US, "overhead_us"),
1169 DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"),
1170 DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"),
1171 DIM(PERF_HPP__OVERHEAD_ACC, "overhead_children"),
1172 DIM(PERF_HPP__SAMPLES, "sample"),
1173 DIM(PERF_HPP__PERIOD, "period"),
1026}; 1174};
1027 1175
1028#undef DIM 1176#undef DIM
1029 1177
1030static void __sort_dimension__add(struct sort_dimension *sd, enum sort_type idx) 1178struct hpp_sort_entry {
1179 struct perf_hpp_fmt hpp;
1180 struct sort_entry *se;
1181};
1182
1183bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1031{ 1184{
1032 if (sd->taken) 1185 struct hpp_sort_entry *hse_a;
1186 struct hpp_sort_entry *hse_b;
1187
1188 if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b))
1189 return false;
1190
1191 hse_a = container_of(a, struct hpp_sort_entry, hpp);
1192 hse_b = container_of(b, struct hpp_sort_entry, hpp);
1193
1194 return hse_a->se == hse_b->se;
1195}
1196
1197void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists)
1198{
1199 struct hpp_sort_entry *hse;
1200
1201 if (!perf_hpp__is_sort_entry(fmt))
1033 return; 1202 return;
1034 1203
1204 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1205 hists__new_col_len(hists, hse->se->se_width_idx,
1206 strlen(hse->se->se_header));
1207}
1208
1209static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1210 struct perf_evsel *evsel)
1211{
1212 struct hpp_sort_entry *hse;
1213 size_t len;
1214
1215 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1216 len = hists__col_len(&evsel->hists, hse->se->se_width_idx);
1217
1218 return scnprintf(hpp->buf, hpp->size, "%*s", len, hse->se->se_header);
1219}
1220
1221static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
1222 struct perf_hpp *hpp __maybe_unused,
1223 struct perf_evsel *evsel)
1224{
1225 struct hpp_sort_entry *hse;
1226
1227 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1228
1229 return hists__col_len(&evsel->hists, hse->se->se_width_idx);
1230}
1231
1232static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1233 struct hist_entry *he)
1234{
1235 struct hpp_sort_entry *hse;
1236 size_t len;
1237
1238 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1239 len = hists__col_len(he->hists, hse->se->se_width_idx);
1240
1241 return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
1242}
1243
1244static struct hpp_sort_entry *
1245__sort_dimension__alloc_hpp(struct sort_dimension *sd)
1246{
1247 struct hpp_sort_entry *hse;
1248
1249 hse = malloc(sizeof(*hse));
1250 if (hse == NULL) {
1251 pr_err("Memory allocation failed\n");
1252 return NULL;
1253 }
1254
1255 hse->se = sd->entry;
1256 hse->hpp.header = __sort__hpp_header;
1257 hse->hpp.width = __sort__hpp_width;
1258 hse->hpp.entry = __sort__hpp_entry;
1259 hse->hpp.color = NULL;
1260
1261 hse->hpp.cmp = sd->entry->se_cmp;
1262 hse->hpp.collapse = sd->entry->se_collapse ? : sd->entry->se_cmp;
1263 hse->hpp.sort = sd->entry->se_sort ? : hse->hpp.collapse;
1264
1265 INIT_LIST_HEAD(&hse->hpp.list);
1266 INIT_LIST_HEAD(&hse->hpp.sort_list);
1267 hse->hpp.elide = false;
1268
1269 return hse;
1270}
1271
1272bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format)
1273{
1274 return format->header == __sort__hpp_header;
1275}
1276
1277static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd)
1278{
1279 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1280
1281 if (hse == NULL)
1282 return -1;
1283
1284 perf_hpp__register_sort_field(&hse->hpp);
1285 return 0;
1286}
1287
1288static int __sort_dimension__add_hpp_output(struct sort_dimension *sd)
1289{
1290 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1291
1292 if (hse == NULL)
1293 return -1;
1294
1295 perf_hpp__column_register(&hse->hpp);
1296 return 0;
1297}
1298
1299static int __sort_dimension__add(struct sort_dimension *sd)
1300{
1301 if (sd->taken)
1302 return 0;
1303
1304 if (__sort_dimension__add_hpp_sort(sd) < 0)
1305 return -1;
1306
1035 if (sd->entry->se_collapse) 1307 if (sd->entry->se_collapse)
1036 sort__need_collapse = 1; 1308 sort__need_collapse = 1;
1037 1309
1038 if (list_empty(&hist_entry__sort_list)) 1310 sd->taken = 1;
1039 sort__first_dimension = idx; 1311
1312 return 0;
1313}
1314
1315static int __hpp_dimension__add(struct hpp_dimension *hd)
1316{
1317 if (!hd->taken) {
1318 hd->taken = 1;
1319
1320 perf_hpp__register_sort_field(hd->fmt);
1321 }
1322 return 0;
1323}
1324
1325static int __sort_dimension__add_output(struct sort_dimension *sd)
1326{
1327 if (sd->taken)
1328 return 0;
1329
1330 if (__sort_dimension__add_hpp_output(sd) < 0)
1331 return -1;
1040 1332
1041 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
1042 sd->taken = 1; 1333 sd->taken = 1;
1334 return 0;
1335}
1336
1337static int __hpp_dimension__add_output(struct hpp_dimension *hd)
1338{
1339 if (!hd->taken) {
1340 hd->taken = 1;
1341
1342 perf_hpp__column_register(hd->fmt);
1343 }
1344 return 0;
1043} 1345}
1044 1346
1045int sort_dimension__add(const char *tok) 1347int sort_dimension__add(const char *tok)
@@ -1068,8 +1370,16 @@ int sort_dimension__add(const char *tok)
1068 sort__has_dso = 1; 1370 sort__has_dso = 1;
1069 } 1371 }
1070 1372
1071 __sort_dimension__add(sd, i); 1373 return __sort_dimension__add(sd);
1072 return 0; 1374 }
1375
1376 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1377 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1378
1379 if (strncasecmp(tok, hd->name, strlen(tok)))
1380 continue;
1381
1382 return __hpp_dimension__add(hd);
1073 } 1383 }
1074 1384
1075 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) { 1385 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
@@ -1084,7 +1394,7 @@ int sort_dimension__add(const char *tok)
1084 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to) 1394 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
1085 sort__has_sym = 1; 1395 sort__has_sym = 1;
1086 1396
1087 __sort_dimension__add(sd, i + __SORT_BRANCH_STACK); 1397 __sort_dimension__add(sd);
1088 return 0; 1398 return 0;
1089 } 1399 }
1090 1400
@@ -1100,18 +1410,47 @@ int sort_dimension__add(const char *tok)
1100 if (sd->entry == &sort_mem_daddr_sym) 1410 if (sd->entry == &sort_mem_daddr_sym)
1101 sort__has_sym = 1; 1411 sort__has_sym = 1;
1102 1412
1103 __sort_dimension__add(sd, i + __SORT_MEMORY_MODE); 1413 __sort_dimension__add(sd);
1104 return 0; 1414 return 0;
1105 } 1415 }
1106 1416
1107 return -ESRCH; 1417 return -ESRCH;
1108} 1418}
1109 1419
1110int setup_sorting(void) 1420static const char *get_default_sort_order(void)
1421{
1422 const char *default_sort_orders[] = {
1423 default_sort_order,
1424 default_branch_sort_order,
1425 default_mem_sort_order,
1426 default_top_sort_order,
1427 default_diff_sort_order,
1428 };
1429
1430 BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders));
1431
1432 return default_sort_orders[sort__mode];
1433}
1434
1435static int __setup_sorting(void)
1111{ 1436{
1112 char *tmp, *tok, *str = strdup(sort_order); 1437 char *tmp, *tok, *str;
1438 const char *sort_keys = sort_order;
1113 int ret = 0; 1439 int ret = 0;
1114 1440
1441 if (sort_keys == NULL) {
1442 if (field_order) {
1443 /*
1444 * If user specified field order but no sort order,
1445 * we'll honor it and not add default sort orders.
1446 */
1447 return 0;
1448 }
1449
1450 sort_keys = get_default_sort_order();
1451 }
1452
1453 str = strdup(sort_keys);
1115 if (str == NULL) { 1454 if (str == NULL) {
1116 error("Not enough memory to setup sort keys"); 1455 error("Not enough memory to setup sort keys");
1117 return -ENOMEM; 1456 return -ENOMEM;
@@ -1133,66 +1472,235 @@ int setup_sorting(void)
1133 return ret; 1472 return ret;
1134} 1473}
1135 1474
1136static void sort_entry__setup_elide(struct sort_entry *se, 1475void perf_hpp__set_elide(int idx, bool elide)
1137 struct strlist *list, 1476{
1138 const char *list_name, FILE *fp) 1477 struct perf_hpp_fmt *fmt;
1478 struct hpp_sort_entry *hse;
1479
1480 perf_hpp__for_each_format(fmt) {
1481 if (!perf_hpp__is_sort_entry(fmt))
1482 continue;
1483
1484 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1485 if (hse->se->se_width_idx == idx) {
1486 fmt->elide = elide;
1487 break;
1488 }
1489 }
1490}
1491
1492static bool __get_elide(struct strlist *list, const char *list_name, FILE *fp)
1139{ 1493{
1140 if (list && strlist__nr_entries(list) == 1) { 1494 if (list && strlist__nr_entries(list) == 1) {
1141 if (fp != NULL) 1495 if (fp != NULL)
1142 fprintf(fp, "# %s: %s\n", list_name, 1496 fprintf(fp, "# %s: %s\n", list_name,
1143 strlist__entry(list, 0)->s); 1497 strlist__entry(list, 0)->s);
1144 se->elide = true; 1498 return true;
1145 } 1499 }
1500 return false;
1501}
1502
1503static bool get_elide(int idx, FILE *output)
1504{
1505 switch (idx) {
1506 case HISTC_SYMBOL:
1507 return __get_elide(symbol_conf.sym_list, "symbol", output);
1508 case HISTC_DSO:
1509 return __get_elide(symbol_conf.dso_list, "dso", output);
1510 case HISTC_COMM:
1511 return __get_elide(symbol_conf.comm_list, "comm", output);
1512 default:
1513 break;
1514 }
1515
1516 if (sort__mode != SORT_MODE__BRANCH)
1517 return false;
1518
1519 switch (idx) {
1520 case HISTC_SYMBOL_FROM:
1521 return __get_elide(symbol_conf.sym_from_list, "sym_from", output);
1522 case HISTC_SYMBOL_TO:
1523 return __get_elide(symbol_conf.sym_to_list, "sym_to", output);
1524 case HISTC_DSO_FROM:
1525 return __get_elide(symbol_conf.dso_from_list, "dso_from", output);
1526 case HISTC_DSO_TO:
1527 return __get_elide(symbol_conf.dso_to_list, "dso_to", output);
1528 default:
1529 break;
1530 }
1531
1532 return false;
1146} 1533}
1147 1534
1148void sort__setup_elide(FILE *output) 1535void sort__setup_elide(FILE *output)
1149{ 1536{
1150 struct sort_entry *se; 1537 struct perf_hpp_fmt *fmt;
1538 struct hpp_sort_entry *hse;
1539
1540 perf_hpp__for_each_format(fmt) {
1541 if (!perf_hpp__is_sort_entry(fmt))
1542 continue;
1151 1543
1152 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, 1544 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1153 "dso", output); 1545 fmt->elide = get_elide(hse->se->se_width_idx, output);
1154 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list,
1155 "comm", output);
1156 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list,
1157 "symbol", output);
1158
1159 if (sort__mode == SORT_MODE__BRANCH) {
1160 sort_entry__setup_elide(&sort_dso_from,
1161 symbol_conf.dso_from_list,
1162 "dso_from", output);
1163 sort_entry__setup_elide(&sort_dso_to,
1164 symbol_conf.dso_to_list,
1165 "dso_to", output);
1166 sort_entry__setup_elide(&sort_sym_from,
1167 symbol_conf.sym_from_list,
1168 "sym_from", output);
1169 sort_entry__setup_elide(&sort_sym_to,
1170 symbol_conf.sym_to_list,
1171 "sym_to", output);
1172 } else if (sort__mode == SORT_MODE__MEMORY) {
1173 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1174 "symbol_daddr", output);
1175 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1176 "dso_daddr", output);
1177 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1178 "mem", output);
1179 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1180 "local_weight", output);
1181 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1182 "tlb", output);
1183 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1184 "snoop", output);
1185 } 1546 }
1186 1547
1187 /* 1548 /*
1188 * It makes no sense to elide all of sort entries. 1549 * It makes no sense to elide all of sort entries.
1189 * Just revert them to show up again. 1550 * Just revert them to show up again.
1190 */ 1551 */
1191 list_for_each_entry(se, &hist_entry__sort_list, list) { 1552 perf_hpp__for_each_format(fmt) {
1192 if (!se->elide) 1553 if (!perf_hpp__is_sort_entry(fmt))
1554 continue;
1555
1556 if (!fmt->elide)
1193 return; 1557 return;
1194 } 1558 }
1195 1559
1196 list_for_each_entry(se, &hist_entry__sort_list, list) 1560 perf_hpp__for_each_format(fmt) {
1197 se->elide = false; 1561 if (!perf_hpp__is_sort_entry(fmt))
1562 continue;
1563
1564 fmt->elide = false;
1565 }
1566}
1567
1568static int output_field_add(char *tok)
1569{
1570 unsigned int i;
1571
1572 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1573 struct sort_dimension *sd = &common_sort_dimensions[i];
1574
1575 if (strncasecmp(tok, sd->name, strlen(tok)))
1576 continue;
1577
1578 return __sort_dimension__add_output(sd);
1579 }
1580
1581 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1582 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1583
1584 if (strncasecmp(tok, hd->name, strlen(tok)))
1585 continue;
1586
1587 return __hpp_dimension__add_output(hd);
1588 }
1589
1590 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1591 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1592
1593 if (strncasecmp(tok, sd->name, strlen(tok)))
1594 continue;
1595
1596 return __sort_dimension__add_output(sd);
1597 }
1598
1599 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1600 struct sort_dimension *sd = &memory_sort_dimensions[i];
1601
1602 if (strncasecmp(tok, sd->name, strlen(tok)))
1603 continue;
1604
1605 return __sort_dimension__add_output(sd);
1606 }
1607
1608 return -ESRCH;
1609}
1610
1611static void reset_dimensions(void)
1612{
1613 unsigned int i;
1614
1615 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++)
1616 common_sort_dimensions[i].taken = 0;
1617
1618 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++)
1619 hpp_sort_dimensions[i].taken = 0;
1620
1621 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++)
1622 bstack_sort_dimensions[i].taken = 0;
1623
1624 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++)
1625 memory_sort_dimensions[i].taken = 0;
1626}
1627
1628static int __setup_output_field(void)
1629{
1630 char *tmp, *tok, *str;
1631 int ret = 0;
1632
1633 if (field_order == NULL)
1634 return 0;
1635
1636 reset_dimensions();
1637
1638 str = strdup(field_order);
1639 if (str == NULL) {
1640 error("Not enough memory to setup output fields");
1641 return -ENOMEM;
1642 }
1643
1644 for (tok = strtok_r(str, ", ", &tmp);
1645 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1646 ret = output_field_add(tok);
1647 if (ret == -EINVAL) {
1648 error("Invalid --fields key: `%s'", tok);
1649 break;
1650 } else if (ret == -ESRCH) {
1651 error("Unknown --fields key: `%s'", tok);
1652 break;
1653 }
1654 }
1655
1656 free(str);
1657 return ret;
1658}
1659
1660int setup_sorting(void)
1661{
1662 int err;
1663
1664 err = __setup_sorting();
1665 if (err < 0)
1666 return err;
1667
1668 if (parent_pattern != default_parent_pattern) {
1669 err = sort_dimension__add("parent");
1670 if (err < 0)
1671 return err;
1672 }
1673
1674 reset_dimensions();
1675
1676 /*
1677 * perf diff doesn't use default hpp output fields.
1678 */
1679 if (sort__mode != SORT_MODE__DIFF)
1680 perf_hpp__init();
1681
1682 err = __setup_output_field();
1683 if (err < 0)
1684 return err;
1685
1686 /* copy sort keys to output fields */
1687 perf_hpp__setup_output_field();
1688 /* and then copy output fields to sort keys */
1689 perf_hpp__append_sort_keys();
1690
1691 return 0;
1692}
1693
1694void reset_output_field(void)
1695{
1696 sort__need_collapse = 0;
1697 sort__has_parent = 0;
1698 sort__has_sym = 0;
1699 sort__has_dso = 0;
1700
1701 field_order = NULL;
1702 sort_order = NULL;
1703
1704 reset_dimensions();
1705 perf_hpp__reset_output_field();
1198} 1706}
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 43e5ff42a609..041f0c9cea2b 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -20,11 +20,12 @@
20 20
21#include "parse-options.h" 21#include "parse-options.h"
22#include "parse-events.h" 22#include "parse-events.h"
23 23#include "hist.h"
24#include "thread.h" 24#include "thread.h"
25 25
26extern regex_t parent_regex; 26extern regex_t parent_regex;
27extern const char *sort_order; 27extern const char *sort_order;
28extern const char *field_order;
28extern const char default_parent_pattern[]; 29extern const char default_parent_pattern[];
29extern const char *parent_pattern; 30extern const char *parent_pattern;
30extern const char default_sort_order[]; 31extern const char default_sort_order[];
@@ -81,12 +82,14 @@ struct hist_entry {
81 struct list_head head; 82 struct list_head head;
82 } pairs; 83 } pairs;
83 struct he_stat stat; 84 struct he_stat stat;
85 struct he_stat *stat_acc;
84 struct map_symbol ms; 86 struct map_symbol ms;
85 struct thread *thread; 87 struct thread *thread;
86 struct comm *comm; 88 struct comm *comm;
87 u64 ip; 89 u64 ip;
88 u64 transaction; 90 u64 transaction;
89 s32 cpu; 91 s32 cpu;
92 u8 cpumode;
90 93
91 struct hist_entry_diff diff; 94 struct hist_entry_diff diff;
92 95
@@ -129,10 +132,27 @@ static inline void hist_entry__add_pair(struct hist_entry *pair,
129 list_add_tail(&pair->pairs.node, &he->pairs.head); 132 list_add_tail(&pair->pairs.node, &he->pairs.head);
130} 133}
131 134
135static inline float hist_entry__get_percent_limit(struct hist_entry *he)
136{
137 u64 period = he->stat.period;
138 u64 total_period = hists__total_period(he->hists);
139
140 if (unlikely(total_period == 0))
141 return 0;
142
143 if (symbol_conf.cumulate_callchain)
144 period = he->stat_acc->period;
145
146 return period * 100.0 / total_period;
147}
148
149
132enum sort_mode { 150enum sort_mode {
133 SORT_MODE__NORMAL, 151 SORT_MODE__NORMAL,
134 SORT_MODE__BRANCH, 152 SORT_MODE__BRANCH,
135 SORT_MODE__MEMORY, 153 SORT_MODE__MEMORY,
154 SORT_MODE__TOP,
155 SORT_MODE__DIFF,
136}; 156};
137 157
138enum sort_type { 158enum sort_type {
@@ -166,6 +186,7 @@ enum sort_type {
166 SORT_MEM_TLB, 186 SORT_MEM_TLB,
167 SORT_MEM_LVL, 187 SORT_MEM_LVL,
168 SORT_MEM_SNOOP, 188 SORT_MEM_SNOOP,
189 SORT_MEM_DCACHELINE,
169}; 190};
170 191
171/* 192/*
@@ -179,18 +200,21 @@ struct sort_entry {
179 200
180 int64_t (*se_cmp)(struct hist_entry *, struct hist_entry *); 201 int64_t (*se_cmp)(struct hist_entry *, struct hist_entry *);
181 int64_t (*se_collapse)(struct hist_entry *, struct hist_entry *); 202 int64_t (*se_collapse)(struct hist_entry *, struct hist_entry *);
203 int64_t (*se_sort)(struct hist_entry *, struct hist_entry *);
182 int (*se_snprintf)(struct hist_entry *he, char *bf, size_t size, 204 int (*se_snprintf)(struct hist_entry *he, char *bf, size_t size,
183 unsigned int width); 205 unsigned int width);
184 u8 se_width_idx; 206 u8 se_width_idx;
185 bool elide;
186}; 207};
187 208
188extern struct sort_entry sort_thread; 209extern struct sort_entry sort_thread;
189extern struct list_head hist_entry__sort_list; 210extern struct list_head hist_entry__sort_list;
190 211
191int setup_sorting(void); 212int setup_sorting(void);
213int setup_output_field(void);
214void reset_output_field(void);
192extern int sort_dimension__add(const char *); 215extern int sort_dimension__add(const char *);
193void sort__setup_elide(FILE *fp); 216void sort__setup_elide(FILE *fp);
217void perf_hpp__set_elide(int idx, bool elide);
194 218
195int report_parse_ignore_callees_opt(const struct option *opt, const char *arg, int unset); 219int report_parse_ignore_callees_opt(const struct option *opt, const char *arg, int unset);
196 220
diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h
index ae8ccd7227cf..5667fc3e39cf 100644
--- a/tools/perf/util/stat.h
+++ b/tools/perf/util/stat.h
@@ -1,7 +1,7 @@
1#ifndef __PERF_STATS_H 1#ifndef __PERF_STATS_H
2#define __PERF_STATS_H 2#define __PERF_STATS_H
3 3
4#include "types.h" 4#include <linux/types.h>
5 5
6struct stats 6struct stats
7{ 7{
diff --git a/tools/perf/util/svghelper.c b/tools/perf/util/svghelper.c
index 43262b83c541..6a0a13d07a28 100644
--- a/tools/perf/util/svghelper.c
+++ b/tools/perf/util/svghelper.c
@@ -17,7 +17,7 @@
17#include <stdlib.h> 17#include <stdlib.h>
18#include <unistd.h> 18#include <unistd.h>
19#include <string.h> 19#include <string.h>
20#include <linux/bitops.h> 20#include <linux/bitmap.h>
21 21
22#include "perf.h" 22#include "perf.h"
23#include "svghelper.h" 23#include "svghelper.h"
diff --git a/tools/perf/util/svghelper.h b/tools/perf/util/svghelper.h
index f7b4d6e699ea..e3aff5332e30 100644
--- a/tools/perf/util/svghelper.h
+++ b/tools/perf/util/svghelper.h
@@ -1,7 +1,7 @@
1#ifndef __PERF_SVGHELPER_H 1#ifndef __PERF_SVGHELPER_H
2#define __PERF_SVGHELPER_H 2#define __PERF_SVGHELPER_H
3 3
4#include "types.h" 4#include <linux/types.h>
5 5
6extern void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end); 6extern void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end);
7extern void svg_box(int Yslot, u64 start, u64 end, const char *type); 7extern void svg_box(int Yslot, u64 start, u64 end, const char *type);
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 95e249779931..7b9096f29cdb 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -29,11 +29,12 @@ int vmlinux_path__nr_entries;
29char **vmlinux_path; 29char **vmlinux_path;
30 30
31struct symbol_conf symbol_conf = { 31struct symbol_conf symbol_conf = {
32 .use_modules = true, 32 .use_modules = true,
33 .try_vmlinux_path = true, 33 .try_vmlinux_path = true,
34 .annotate_src = true, 34 .annotate_src = true,
35 .demangle = true, 35 .demangle = true,
36 .symfs = "", 36 .cumulate_callchain = true,
37 .symfs = "",
37}; 38};
38 39
39static enum dso_binary_type binary_type_symtab[] = { 40static enum dso_binary_type binary_type_symtab[] = {
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 501e4e722e8e..615c752dd767 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -12,6 +12,7 @@
12#include <byteswap.h> 12#include <byteswap.h>
13#include <libgen.h> 13#include <libgen.h>
14#include "build-id.h" 14#include "build-id.h"
15#include "event.h"
15 16
16#ifdef HAVE_LIBELF_SUPPORT 17#ifdef HAVE_LIBELF_SUPPORT
17#include <libelf.h> 18#include <libelf.h>
@@ -108,6 +109,7 @@ struct symbol_conf {
108 show_nr_samples, 109 show_nr_samples,
109 show_total_period, 110 show_total_period,
110 use_callchain, 111 use_callchain,
112 cumulate_callchain,
111 exclude_other, 113 exclude_other,
112 show_cpu_utilization, 114 show_cpu_utilization,
113 initialized, 115 initialized,
@@ -115,7 +117,8 @@ struct symbol_conf {
115 annotate_asm_raw, 117 annotate_asm_raw,
116 annotate_src, 118 annotate_src,
117 event_group, 119 event_group,
118 demangle; 120 demangle,
121 filter_relative;
119 const char *vmlinux_name, 122 const char *vmlinux_name,
120 *kallsyms_name, 123 *kallsyms_name,
121 *source_prefix, 124 *source_prefix,
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 3ce0498bdae6..2fde0d5e40b5 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -8,6 +8,22 @@
8#include "debug.h" 8#include "debug.h"
9#include "comm.h" 9#include "comm.h"
10 10
11int thread__init_map_groups(struct thread *thread, struct machine *machine)
12{
13 struct thread *leader;
14 pid_t pid = thread->pid_;
15
16 if (pid == thread->tid) {
17 thread->mg = map_groups__new();
18 } else {
19 leader = machine__findnew_thread(machine, pid, pid);
20 if (leader)
21 thread->mg = map_groups__get(leader->mg);
22 }
23
24 return thread->mg ? 0 : -1;
25}
26
11struct thread *thread__new(pid_t pid, pid_t tid) 27struct thread *thread__new(pid_t pid, pid_t tid)
12{ 28{
13 char *comm_str; 29 char *comm_str;
@@ -15,7 +31,6 @@ struct thread *thread__new(pid_t pid, pid_t tid)
15 struct thread *thread = zalloc(sizeof(*thread)); 31 struct thread *thread = zalloc(sizeof(*thread));
16 32
17 if (thread != NULL) { 33 if (thread != NULL) {
18 map_groups__init(&thread->mg);
19 thread->pid_ = pid; 34 thread->pid_ = pid;
20 thread->tid = tid; 35 thread->tid = tid;
21 thread->ppid = -1; 36 thread->ppid = -1;
@@ -45,7 +60,8 @@ void thread__delete(struct thread *thread)
45{ 60{
46 struct comm *comm, *tmp; 61 struct comm *comm, *tmp;
47 62
48 map_groups__exit(&thread->mg); 63 map_groups__put(thread->mg);
64 thread->mg = NULL;
49 list_for_each_entry_safe(comm, tmp, &thread->comm_list, list) { 65 list_for_each_entry_safe(comm, tmp, &thread->comm_list, list) {
50 list_del(&comm->list); 66 list_del(&comm->list);
51 comm__free(comm); 67 comm__free(comm);
@@ -111,18 +127,35 @@ int thread__comm_len(struct thread *thread)
111size_t thread__fprintf(struct thread *thread, FILE *fp) 127size_t thread__fprintf(struct thread *thread, FILE *fp)
112{ 128{
113 return fprintf(fp, "Thread %d %s\n", thread->tid, thread__comm_str(thread)) + 129 return fprintf(fp, "Thread %d %s\n", thread->tid, thread__comm_str(thread)) +
114 map_groups__fprintf(&thread->mg, verbose, fp); 130 map_groups__fprintf(thread->mg, verbose, fp);
115} 131}
116 132
117void thread__insert_map(struct thread *thread, struct map *map) 133void thread__insert_map(struct thread *thread, struct map *map)
118{ 134{
119 map_groups__fixup_overlappings(&thread->mg, map, verbose, stderr); 135 map_groups__fixup_overlappings(thread->mg, map, verbose, stderr);
120 map_groups__insert(&thread->mg, map); 136 map_groups__insert(thread->mg, map);
137}
138
139static int thread__clone_map_groups(struct thread *thread,
140 struct thread *parent)
141{
142 int i;
143
144 /* This is new thread, we share map groups for process. */
145 if (thread->pid_ == parent->pid_)
146 return 0;
147
148 /* But this one is new process, copy maps. */
149 for (i = 0; i < MAP__NR_TYPES; ++i)
150 if (map_groups__clone(thread->mg, parent->mg, i) < 0)
151 return -ENOMEM;
152
153 return 0;
121} 154}
122 155
123int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp) 156int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp)
124{ 157{
125 int i, err; 158 int err;
126 159
127 if (parent->comm_set) { 160 if (parent->comm_set) {
128 const char *comm = thread__comm_str(parent); 161 const char *comm = thread__comm_str(parent);
@@ -134,13 +167,8 @@ int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp)
134 thread->comm_set = true; 167 thread->comm_set = true;
135 } 168 }
136 169
137 for (i = 0; i < MAP__NR_TYPES; ++i)
138 if (map_groups__clone(&thread->mg, &parent->mg, i) < 0)
139 return -ENOMEM;
140
141 thread->ppid = parent->tid; 170 thread->ppid = parent->tid;
142 171 return thread__clone_map_groups(thread, parent);
143 return 0;
144} 172}
145 173
146void thread__find_cpumode_addr_location(struct thread *thread, 174void thread__find_cpumode_addr_location(struct thread *thread,
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 9b29f085aede..3c0c2724f82c 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -13,7 +13,7 @@ struct thread {
13 struct rb_node rb_node; 13 struct rb_node rb_node;
14 struct list_head node; 14 struct list_head node;
15 }; 15 };
16 struct map_groups mg; 16 struct map_groups *mg;
17 pid_t pid_; /* Not all tools update this */ 17 pid_t pid_; /* Not all tools update this */
18 pid_t tid; 18 pid_t tid;
19 pid_t ppid; 19 pid_t ppid;
@@ -30,6 +30,7 @@ struct machine;
30struct comm; 30struct comm;
31 31
32struct thread *thread__new(pid_t pid, pid_t tid); 32struct thread *thread__new(pid_t pid, pid_t tid);
33int thread__init_map_groups(struct thread *thread, struct machine *machine);
33void thread__delete(struct thread *thread); 34void thread__delete(struct thread *thread);
34static inline void thread__exited(struct thread *thread) 35static inline void thread__exited(struct thread *thread)
35{ 36{
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index dab14d0ad3d0..f92c37abb0a8 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -2,7 +2,7 @@
2#define __PERF_TOP_H 1 2#define __PERF_TOP_H 1
3 3
4#include "tool.h" 4#include "tool.h"
5#include "types.h" 5#include <linux/types.h>
6#include <stddef.h> 6#include <stddef.h>
7#include <stdbool.h> 7#include <stdbool.h>
8#include <termios.h> 8#include <termios.h>
diff --git a/tools/perf/util/types.h b/tools/perf/util/types.h
deleted file mode 100644
index c51fa6b70a28..000000000000
--- a/tools/perf/util/types.h
+++ /dev/null
@@ -1,24 +0,0 @@
1#ifndef __PERF_TYPES_H
2#define __PERF_TYPES_H
3
4#include <stdint.h>
5
6/*
7 * We define u64 as uint64_t for every architecture
8 * so that we can print it with "%"PRIx64 without getting warnings.
9 */
10typedef uint64_t u64;
11typedef int64_t s64;
12typedef unsigned int u32;
13typedef signed int s32;
14typedef unsigned short u16;
15typedef signed short s16;
16typedef unsigned char u8;
17typedef signed char s8;
18
19union u64_swap {
20 u64 val64;
21 u32 val32[2];
22};
23
24#endif /* __PERF_TYPES_H */
diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
index 67db73ec3dab..5ec80a575b50 100644
--- a/tools/perf/util/unwind-libdw.c
+++ b/tools/perf/util/unwind-libdw.c
@@ -7,7 +7,7 @@
7#include "unwind-libdw.h" 7#include "unwind-libdw.h"
8#include "machine.h" 8#include "machine.h"
9#include "thread.h" 9#include "thread.h"
10#include "types.h" 10#include <linux/types.h>
11#include "event.h" 11#include "event.h"
12#include "perf_regs.h" 12#include "perf_regs.h"
13 13
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
index bd5768d74f01..25578b98f5c5 100644
--- a/tools/perf/util/unwind-libunwind.c
+++ b/tools/perf/util/unwind-libunwind.c
@@ -250,7 +250,6 @@ static int read_unwind_spec_eh_frame(struct dso *dso, struct machine *machine,
250 250
251 /* Check the .eh_frame section for unwinding info */ 251 /* Check the .eh_frame section for unwinding info */
252 offset = elf_section_offset(fd, ".eh_frame_hdr"); 252 offset = elf_section_offset(fd, ".eh_frame_hdr");
253 close(fd);
254 253
255 if (offset) 254 if (offset)
256 ret = unwind_spec_ehframe(dso, machine, offset, 255 ret = unwind_spec_ehframe(dso, machine, offset,
@@ -271,7 +270,6 @@ static int read_unwind_spec_debug_frame(struct dso *dso,
271 270
272 /* Check the .debug_frame section for unwinding info */ 271 /* Check the .debug_frame section for unwinding info */
273 *offset = elf_section_offset(fd, ".debug_frame"); 272 *offset = elf_section_offset(fd, ".debug_frame");
274 close(fd);
275 273
276 if (*offset) 274 if (*offset)
277 return 0; 275 return 0;
diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h
index b031316f221a..f03061260b4e 100644
--- a/tools/perf/util/unwind.h
+++ b/tools/perf/util/unwind.h
@@ -1,7 +1,7 @@
1#ifndef __UNWIND_H 1#ifndef __UNWIND_H
2#define __UNWIND_H 2#define __UNWIND_H
3 3
4#include "types.h" 4#include <linux/types.h>
5#include "event.h" 5#include "event.h"
6#include "symbol.h" 6#include "symbol.h"
7 7
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 9f66549562bd..95aefa78bb07 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -17,6 +17,7 @@
17 * XXX We need to find a better place for these things... 17 * XXX We need to find a better place for these things...
18 */ 18 */
19unsigned int page_size; 19unsigned int page_size;
20int cacheline_size;
20 21
21bool test_attr__enabled; 22bool test_attr__enabled;
22 23
@@ -166,6 +167,8 @@ static ssize_t ion(bool is_read, int fd, void *buf, size_t n)
166 ssize_t ret = is_read ? read(fd, buf, left) : 167 ssize_t ret = is_read ? read(fd, buf, left) :
167 write(fd, buf, left); 168 write(fd, buf, left);
168 169
170 if (ret < 0 && errno == EINTR)
171 continue;
169 if (ret <= 0) 172 if (ret <= 0)
170 return ret; 173 return ret;
171 174
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 6995d66f225c..66864364ccb4 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -69,7 +69,7 @@
69#include <sys/ioctl.h> 69#include <sys/ioctl.h>
70#include <inttypes.h> 70#include <inttypes.h>
71#include <linux/magic.h> 71#include <linux/magic.h>
72#include "types.h" 72#include <linux/types.h>
73#include <sys/ttydefaults.h> 73#include <sys/ttydefaults.h>
74#include <api/fs/debugfs.h> 74#include <api/fs/debugfs.h>
75#include <termios.h> 75#include <termios.h>
@@ -304,6 +304,7 @@ char *rtrim(char *s);
304void dump_stack(void); 304void dump_stack(void);
305 305
306extern unsigned int page_size; 306extern unsigned int page_size;
307extern int cacheline_size;
307 308
308void get_term_dimensions(struct winsize *ws); 309void get_term_dimensions(struct winsize *ws);
309 310
diff --git a/tools/perf/util/values.h b/tools/perf/util/values.h
index 2fa967e1a88a..b21a80c6cf8d 100644
--- a/tools/perf/util/values.h
+++ b/tools/perf/util/values.h
@@ -1,7 +1,7 @@
1#ifndef __PERF_VALUES_H 1#ifndef __PERF_VALUES_H
2#define __PERF_VALUES_H 2#define __PERF_VALUES_H
3 3
4#include "types.h" 4#include <linux/types.h>
5 5
6struct perf_read_values { 6struct perf_read_values {
7 int threads; 7 int threads;
diff --git a/tools/power/acpi/Makefile b/tools/power/acpi/Makefile
index c2c0f20067a5..e5a3c4be2a10 100644
--- a/tools/power/acpi/Makefile
+++ b/tools/power/acpi/Makefile
@@ -19,6 +19,8 @@ OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd)
19$(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist)) 19$(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist))
20endif 20endif
21 21
22SUBDIRS = tools/ec
23
22# --- CONFIGURATION BEGIN --- 24# --- CONFIGURATION BEGIN ---
23 25
24# Set the following to `true' to make a unstripped, unoptimized 26# Set the following to `true' to make a unstripped, unoptimized
@@ -68,7 +70,8 @@ WARNINGS += $(call cc-supports,-Wstrict-prototypes)
68WARNINGS += $(call cc-supports,-Wdeclaration-after-statement) 70WARNINGS += $(call cc-supports,-Wdeclaration-after-statement)
69 71
70KERNEL_INCLUDE := ../../../include 72KERNEL_INCLUDE := ../../../include
71CFLAGS += -D_LINUX -DDEFINE_ALTERNATE_TYPES -I$(KERNEL_INCLUDE) 73ACPICA_INCLUDE := ../../../drivers/acpi/acpica
74CFLAGS += -D_LINUX -I$(KERNEL_INCLUDE) -I$(ACPICA_INCLUDE)
72CFLAGS += $(WARNINGS) 75CFLAGS += $(WARNINGS)
73 76
74ifeq ($(strip $(V)),false) 77ifeq ($(strip $(V)),false)
@@ -92,10 +95,29 @@ endif
92# --- ACPIDUMP BEGIN --- 95# --- ACPIDUMP BEGIN ---
93 96
94vpath %.c \ 97vpath %.c \
95 tools/acpidump 98 ../../../drivers/acpi/acpica\
99 tools/acpidump\
100 common\
101 os_specific/service_layers
102
103CFLAGS += -DACPI_DUMP_APP -Itools/acpidump
96 104
97DUMP_OBJS = \ 105DUMP_OBJS = \
98 acpidump.o 106 apdump.o\
107 apfiles.o\
108 apmain.o\
109 osunixdir.o\
110 osunixmap.o\
111 tbprint.o\
112 tbxfroot.o\
113 utbuffer.o\
114 utexcep.o\
115 utmath.o\
116 utstring.o\
117 utxferror.o\
118 oslinuxtbl.o\
119 cmfsize.o\
120 getopt.o
99 121
100DUMP_OBJS := $(addprefix $(OUTPUT)tools/acpidump/,$(DUMP_OBJS)) 122DUMP_OBJS := $(addprefix $(OUTPUT)tools/acpidump/,$(DUMP_OBJS))
101 123
diff --git a/tools/power/acpi/common/cmfsize.c b/tools/power/acpi/common/cmfsize.c
new file mode 100644
index 000000000000..5140e5edae1f
--- /dev/null
+++ b/tools/power/acpi/common/cmfsize.c
@@ -0,0 +1,101 @@
1/******************************************************************************
2 *
3 * Module Name: cfsize - Common get file size function
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2014, Intel Corp.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions, and the following disclaimer,
16 * without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 * substantially similar to the "NO WARRANTY" disclaimer below
19 * ("Disclaimer") and any redistribution must be conditioned upon
20 * including a substantially similar Disclaimer requirement for further
21 * binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 * of any contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
29 *
30 * NO WARRANTY
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
42 */
43
44#include <acpi/acpi.h>
45#include "accommon.h"
46#include "acapps.h"
47#include <stdio.h>
48
49#define _COMPONENT ACPI_TOOLS
50ACPI_MODULE_NAME("cmfsize")
51
52/*******************************************************************************
53 *
54 * FUNCTION: cm_get_file_size
55 *
56 * PARAMETERS: file - Open file descriptor
57 *
58 * RETURN: File Size. On error, -1 (ACPI_UINT32_MAX)
59 *
60 * DESCRIPTION: Get the size of a file. Uses seek-to-EOF. File must be open.
61 * Does not disturb the current file pointer. Uses perror for
62 * error messages.
63 *
64 ******************************************************************************/
65u32 cm_get_file_size(FILE * file)
66{
67 long file_size;
68 long current_offset;
69
70 /* Save the current file pointer, seek to EOF to obtain file size */
71
72 current_offset = ftell(file);
73 if (current_offset < 0) {
74 goto offset_error;
75 }
76
77 if (fseek(file, 0, SEEK_END)) {
78 goto seek_error;
79 }
80
81 file_size = ftell(file);
82 if (file_size < 0) {
83 goto offset_error;
84 }
85
86 /* Restore original file pointer */
87
88 if (fseek(file, current_offset, SEEK_SET)) {
89 goto seek_error;
90 }
91
92 return ((u32)file_size);
93
94offset_error:
95 perror("Could not get file offset");
96 return (ACPI_UINT32_MAX);
97
98seek_error:
99 perror("Could not seek file");
100 return (ACPI_UINT32_MAX);
101}
diff --git a/tools/power/acpi/common/getopt.c b/tools/power/acpi/common/getopt.c
new file mode 100644
index 000000000000..a302f52e4fd3
--- /dev/null
+++ b/tools/power/acpi/common/getopt.c
@@ -0,0 +1,239 @@
1/******************************************************************************
2 *
3 * Module Name: getopt
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2014, Intel Corp.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions, and the following disclaimer,
16 * without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 * substantially similar to the "NO WARRANTY" disclaimer below
19 * ("Disclaimer") and any redistribution must be conditioned upon
20 * including a substantially similar Disclaimer requirement for further
21 * binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 * of any contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
29 *
30 * NO WARRANTY
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
42 */
43
44/*
45 * ACPICA getopt() implementation
46 *
47 * Option strings:
48 * "f" - Option has no arguments
49 * "f:" - Option requires an argument
50 * "f^" - Option has optional single-char sub-options
51 * "f|" - Option has required single-char sub-options
52 */
53
54#include <stdio.h>
55#include <string.h>
56#include <acpi/acpi.h>
57#include "accommon.h"
58#include "acapps.h"
59
60#define ACPI_OPTION_ERROR(msg, badchar) \
61 if (acpi_gbl_opterr) {fprintf (stderr, "%s%c\n", msg, badchar);}
62
63int acpi_gbl_opterr = 1;
64int acpi_gbl_optind = 1;
65int acpi_gbl_sub_opt_char = 0;
66char *acpi_gbl_optarg;
67
68static int current_char_ptr = 1;
69
70/*******************************************************************************
71 *
72 * FUNCTION: acpi_getopt_argument
73 *
74 * PARAMETERS: argc, argv - from main
75 *
76 * RETURN: 0 if an argument was found, -1 otherwise. Sets acpi_gbl_Optarg
77 * to point to the next argument.
78 *
79 * DESCRIPTION: Get the next argument. Used to obtain arguments for the
80 * two-character options after the original call to acpi_getopt.
81 * Note: Either the argument starts at the next character after
82 * the option, or it is pointed to by the next argv entry.
83 * (After call to acpi_getopt, we need to backup to the previous
84 * argv entry).
85 *
86 ******************************************************************************/
87
88int acpi_getopt_argument(int argc, char **argv)
89{
90 acpi_gbl_optind--;
91 current_char_ptr++;
92
93 if (argv[acpi_gbl_optind][(int)(current_char_ptr + 1)] != '\0') {
94 acpi_gbl_optarg =
95 &argv[acpi_gbl_optind++][(int)(current_char_ptr + 1)];
96 } else if (++acpi_gbl_optind >= argc) {
97 ACPI_OPTION_ERROR("Option requires an argument: -", 'v');
98
99 current_char_ptr = 1;
100 return (-1);
101 } else {
102 acpi_gbl_optarg = argv[acpi_gbl_optind++];
103 }
104
105 current_char_ptr = 1;
106 return (0);
107}
108
109/*******************************************************************************
110 *
111 * FUNCTION: acpi_getopt
112 *
113 * PARAMETERS: argc, argv - from main
114 * opts - options info list
115 *
116 * RETURN: Option character or EOF
117 *
118 * DESCRIPTION: Get the next option
119 *
120 ******************************************************************************/
121
122int acpi_getopt(int argc, char **argv, char *opts)
123{
124 int current_char;
125 char *opts_ptr;
126
127 if (current_char_ptr == 1) {
128 if (acpi_gbl_optind >= argc ||
129 argv[acpi_gbl_optind][0] != '-' ||
130 argv[acpi_gbl_optind][1] == '\0') {
131 return (EOF);
132 } else if (strcmp(argv[acpi_gbl_optind], "--") == 0) {
133 acpi_gbl_optind++;
134 return (EOF);
135 }
136 }
137
138 /* Get the option */
139
140 current_char = argv[acpi_gbl_optind][current_char_ptr];
141
142 /* Make sure that the option is legal */
143
144 if (current_char == ':' ||
145 (opts_ptr = strchr(opts, current_char)) == NULL) {
146 ACPI_OPTION_ERROR("Illegal option: -", current_char);
147
148 if (argv[acpi_gbl_optind][++current_char_ptr] == '\0') {
149 acpi_gbl_optind++;
150 current_char_ptr = 1;
151 }
152
153 return ('?');
154 }
155
156 /* Option requires an argument? */
157
158 if (*++opts_ptr == ':') {
159 if (argv[acpi_gbl_optind][(int)(current_char_ptr + 1)] != '\0') {
160 acpi_gbl_optarg =
161 &argv[acpi_gbl_optind++][(int)
162 (current_char_ptr + 1)];
163 } else if (++acpi_gbl_optind >= argc) {
164 ACPI_OPTION_ERROR("Option requires an argument: -",
165 current_char);
166
167 current_char_ptr = 1;
168 return ('?');
169 } else {
170 acpi_gbl_optarg = argv[acpi_gbl_optind++];
171 }
172
173 current_char_ptr = 1;
174 }
175
176 /* Option has an optional argument? */
177
178 else if (*opts_ptr == '+') {
179 if (argv[acpi_gbl_optind][(int)(current_char_ptr + 1)] != '\0') {
180 acpi_gbl_optarg =
181 &argv[acpi_gbl_optind++][(int)
182 (current_char_ptr + 1)];
183 } else if (++acpi_gbl_optind >= argc) {
184 acpi_gbl_optarg = NULL;
185 } else {
186 acpi_gbl_optarg = argv[acpi_gbl_optind++];
187 }
188
189 current_char_ptr = 1;
190 }
191
192 /* Option has optional single-char arguments? */
193
194 else if (*opts_ptr == '^') {
195 if (argv[acpi_gbl_optind][(int)(current_char_ptr + 1)] != '\0') {
196 acpi_gbl_optarg =
197 &argv[acpi_gbl_optind][(int)(current_char_ptr + 1)];
198 } else {
199 acpi_gbl_optarg = "^";
200 }
201
202 acpi_gbl_sub_opt_char = acpi_gbl_optarg[0];
203 acpi_gbl_optind++;
204 current_char_ptr = 1;
205 }
206
207 /* Option has a required single-char argument? */
208
209 else if (*opts_ptr == '|') {
210 if (argv[acpi_gbl_optind][(int)(current_char_ptr + 1)] != '\0') {
211 acpi_gbl_optarg =
212 &argv[acpi_gbl_optind][(int)(current_char_ptr + 1)];
213 } else {
214 ACPI_OPTION_ERROR
215 ("Option requires a single-character suboption: -",
216 current_char);
217
218 current_char_ptr = 1;
219 return ('?');
220 }
221
222 acpi_gbl_sub_opt_char = acpi_gbl_optarg[0];
223 acpi_gbl_optind++;
224 current_char_ptr = 1;
225 }
226
227 /* Option with no arguments */
228
229 else {
230 if (argv[acpi_gbl_optind][++current_char_ptr] == '\0') {
231 current_char_ptr = 1;
232 acpi_gbl_optind++;
233 }
234
235 acpi_gbl_optarg = NULL;
236 }
237
238 return (current_char);
239}
diff --git a/tools/power/acpi/man/acpidump.8 b/tools/power/acpi/man/acpidump.8
index adfa99166e5e..38f095d86b52 100644
--- a/tools/power/acpi/man/acpidump.8
+++ b/tools/power/acpi/man/acpidump.8
@@ -1,18 +1,64 @@
1.TH ACPIDUMP 8 1.TH ACPIDUMP 8
2.SH NAME 2.SH NAME
3acpidump \- Dump system's ACPI tables to an ASCII file. 3acpidump \- dump a system's ACPI tables to an ASCII file
4
4.SH SYNOPSIS 5.SH SYNOPSIS
5.ft B 6.B acpidump
6.B acpidump > acpidump.out 7.RI [ options ]
8.br
9
7.SH DESCRIPTION 10.SH DESCRIPTION
8\fBacpidump \fP dumps the systems ACPI tables to an ASCII file 11.B acpidump
9appropriate for attaching to a bug report. 12dumps the systems ACPI tables to an ASCII file appropriate for
13attaching to a bug report.
10 14
11Subsequently, they can be processed by utilities in the ACPICA package. 15Subsequently, they can be processed by utilities in the ACPICA package.
12.SS Options 16
13no options worth worrying about. 17.SH OPTIONS
14.PP 18acpidump options are as follow:
15.SH EXAMPLE 19.TP
20.B Options
21.TP
22.B \-b
23Dump tables to binary files
24.TP
25.B \-c
26Dump customized tables
27.TP
28.B \-h \-?
29This help message
30.TP
31.B \-o <File>
32Redirect output to file
33.TP
34.B \-r <Address>
35Dump tables from specified RSDP
36.TP
37.B \-s
38Print table summaries only
39.TP
40.B \-v
41Display version information
42.TP
43.B \-z
44Verbose mode
45.TP
46.B Table Options
47.TP
48.B \-a <Address>
49Get table via a physical address
50.TP
51.B \-f <BinaryFile>
52Get table via a binary file
53.TP
54.B \-n <Signature>
55Get table via a name/signature
56.TP
57Invocation without parameters dumps all available tables
58.TP
59Multiple mixed instances of -a, -f, and -n are supported
60
61.SH EXAMPLES
16 62
17.nf 63.nf
18# acpidump > acpidump.out 64# acpidump > acpidump.out
@@ -50,10 +96,25 @@ ACPICA: https://acpica.org/
50.ta 96.ta
51.nf 97.nf
52/dev/mem 98/dev/mem
99/sys/firmware/acpi/tables/*
53/sys/firmware/acpi/tables/dynamic/* 100/sys/firmware/acpi/tables/dynamic/*
101/sys/firmware/efi/systab
54.fi 102.fi
55 103
56.PP
57.SH AUTHOR 104.SH AUTHOR
58.nf 105.TP
59Written by Len Brown <len.brown@intel.com> 106Original by:
107 Len Brown <len.brown@intel.com>
108.TP
109Written by:
110 Chao Guan <chao.guan@intel.com>
111.TP
112Updated by:
113 Bob Moore <robert.moore@intel.com>
114 Lv Zheng <lv.zheng@intel.com>
115
116.SH SEE ALSO
117\&\fIacpixtract\fR\|(8), \fIiasl\fR\|(8).
118
119.SH COPYRIGHT
120COPYRIGHT (c) 2013, Intel Corporation.
diff --git a/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c
new file mode 100644
index 000000000000..28c52008e854
--- /dev/null
+++ b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c
@@ -0,0 +1,1329 @@
1/******************************************************************************
2 *
3 * Module Name: oslinuxtbl - Linux OSL for obtaining ACPI tables
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2014, Intel Corp.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions, and the following disclaimer,
16 * without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 * substantially similar to the "NO WARRANTY" disclaimer below
19 * ("Disclaimer") and any redistribution must be conditioned upon
20 * including a substantially similar Disclaimer requirement for further
21 * binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 * of any contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
29 *
30 * NO WARRANTY
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
42 */
43
44#include "acpidump.h"
45
46#define _COMPONENT ACPI_OS_SERVICES
47ACPI_MODULE_NAME("oslinuxtbl")
48
49#ifndef PATH_MAX
50#define PATH_MAX 256
51#endif
52/* List of information about obtained ACPI tables */
53typedef struct osl_table_info {
54 struct osl_table_info *next;
55 u32 instance;
56 char signature[ACPI_NAME_SIZE];
57
58} osl_table_info;
59
60/* Local prototypes */
61
62static acpi_status osl_table_initialize(void);
63
64static acpi_status
65osl_table_name_from_file(char *filename, char *signature, u32 *instance);
66
67static acpi_status osl_add_table_to_list(char *signature, u32 instance);
68
69static acpi_status
70osl_read_table_from_file(char *filename,
71 acpi_size file_offset,
72 char *signature, struct acpi_table_header **table);
73
74static acpi_status
75osl_map_table(acpi_size address,
76 char *signature, struct acpi_table_header **table);
77
78static void osl_unmap_table(struct acpi_table_header *table);
79
80static acpi_physical_address osl_find_rsdp_via_efi(void);
81
82static acpi_status osl_load_rsdp(void);
83
84static acpi_status osl_list_customized_tables(char *directory);
85
86static acpi_status
87osl_get_customized_table(char *pathname,
88 char *signature,
89 u32 instance,
90 struct acpi_table_header **table,
91 acpi_physical_address * address);
92
93static acpi_status osl_list_bios_tables(void);
94
95static acpi_status
96osl_get_bios_table(char *signature,
97 u32 instance,
98 struct acpi_table_header **table,
99 acpi_physical_address * address);
100
101static acpi_status osl_get_last_status(acpi_status default_status);
102
103/* File locations */
104
105#define DYNAMIC_TABLE_DIR "/sys/firmware/acpi/tables/dynamic"
106#define STATIC_TABLE_DIR "/sys/firmware/acpi/tables"
107#define EFI_SYSTAB "/sys/firmware/efi/systab"
108
109/* Should we get dynamically loaded SSDTs from DYNAMIC_TABLE_DIR? */
110
111u8 gbl_dump_dynamic_tables = TRUE;
112
113/* Initialization flags */
114
115u8 gbl_table_list_initialized = FALSE;
116
117/* Local copies of main ACPI tables */
118
119struct acpi_table_rsdp gbl_rsdp;
120struct acpi_table_fadt *gbl_fadt = NULL;
121struct acpi_table_rsdt *gbl_rsdt = NULL;
122struct acpi_table_xsdt *gbl_xsdt = NULL;
123
124/* Table addresses */
125
126acpi_physical_address gbl_fadt_address = 0;
127acpi_physical_address gbl_rsdp_address = 0;
128
129/* Revision of RSD PTR */
130
131u8 gbl_revision = 0;
132
133struct osl_table_info *gbl_table_list_head = NULL;
134u32 gbl_table_count = 0;
135
136/******************************************************************************
137 *
138 * FUNCTION: osl_get_last_status
139 *
140 * PARAMETERS: default_status - Default error status to return
141 *
142 * RETURN: Status; Converted from errno.
143 *
144 * DESCRIPTION: Get last errno and conver it to acpi_status.
145 *
146 *****************************************************************************/
147
148static acpi_status osl_get_last_status(acpi_status default_status)
149{
150
151 switch (errno) {
152 case EACCES:
153 case EPERM:
154
155 return (AE_ACCESS);
156
157 case ENOENT:
158
159 return (AE_NOT_FOUND);
160
161 case ENOMEM:
162
163 return (AE_NO_MEMORY);
164
165 default:
166
167 return (default_status);
168 }
169}
170
171/******************************************************************************
172 *
173 * FUNCTION: acpi_os_get_table_by_address
174 *
175 * PARAMETERS: address - Physical address of the ACPI table
176 * table - Where a pointer to the table is returned
177 *
178 * RETURN: Status; Table buffer is returned if AE_OK.
179 * AE_NOT_FOUND: A valid table was not found at the address
180 *
181 * DESCRIPTION: Get an ACPI table via a physical memory address.
182 *
183 *****************************************************************************/
184
185acpi_status
186acpi_os_get_table_by_address(acpi_physical_address address,
187 struct acpi_table_header ** table)
188{
189 u32 table_length;
190 struct acpi_table_header *mapped_table;
191 struct acpi_table_header *local_table = NULL;
192 acpi_status status = AE_OK;
193
194 /* Get main ACPI tables from memory on first invocation of this function */
195
196 status = osl_table_initialize();
197 if (ACPI_FAILURE(status)) {
198 return (status);
199 }
200
201 /* Map the table and validate it */
202
203 status = osl_map_table(address, NULL, &mapped_table);
204 if (ACPI_FAILURE(status)) {
205 return (status);
206 }
207
208 /* Copy table to local buffer and return it */
209
210 table_length = ap_get_table_length(mapped_table);
211 if (table_length == 0) {
212 status = AE_BAD_HEADER;
213 goto exit;
214 }
215
216 local_table = calloc(1, table_length);
217 if (!local_table) {
218 status = AE_NO_MEMORY;
219 goto exit;
220 }
221
222 ACPI_MEMCPY(local_table, mapped_table, table_length);
223
224exit:
225 osl_unmap_table(mapped_table);
226 *table = local_table;
227 return (status);
228}
229
230/******************************************************************************
231 *
232 * FUNCTION: acpi_os_get_table_by_name
233 *
234 * PARAMETERS: signature - ACPI Signature for desired table. Must be
235 * a null terminated 4-character string.
236 * instance - Multiple table support for SSDT/UEFI (0...n)
237 * Must be 0 for other tables.
238 * table - Where a pointer to the table is returned
239 * address - Where the table physical address is returned
240 *
241 * RETURN: Status; Table buffer and physical address returned if AE_OK.
242 * AE_LIMIT: Instance is beyond valid limit
243 * AE_NOT_FOUND: A table with the signature was not found
244 *
245 * NOTE: Assumes the input signature is uppercase.
246 *
247 *****************************************************************************/
248
249acpi_status
250acpi_os_get_table_by_name(char *signature,
251 u32 instance,
252 struct acpi_table_header ** table,
253 acpi_physical_address * address)
254{
255 acpi_status status;
256
257 /* Get main ACPI tables from memory on first invocation of this function */
258
259 status = osl_table_initialize();
260 if (ACPI_FAILURE(status)) {
261 return (status);
262 }
263
264 /* Not a main ACPI table, attempt to extract it from the RSDT/XSDT */
265
266 if (!gbl_dump_customized_tables) {
267
268 /* Attempt to get the table from the memory */
269
270 status =
271 osl_get_bios_table(signature, instance, table, address);
272 } else {
273 /* Attempt to get the table from the static directory */
274
275 status = osl_get_customized_table(STATIC_TABLE_DIR, signature,
276 instance, table, address);
277 }
278
279 if (ACPI_FAILURE(status) && status == AE_LIMIT) {
280 if (gbl_dump_dynamic_tables) {
281
282 /* Attempt to get a dynamic table */
283
284 status =
285 osl_get_customized_table(DYNAMIC_TABLE_DIR,
286 signature, instance, table,
287 address);
288 }
289 }
290
291 return (status);
292}
293
294/******************************************************************************
295 *
296 * FUNCTION: osl_add_table_to_list
297 *
298 * PARAMETERS: signature - Table signature
299 * instance - Table instance
300 *
301 * RETURN: Status; Successfully added if AE_OK.
302 * AE_NO_MEMORY: Memory allocation error
303 *
304 * DESCRIPTION: Insert a table structure into OSL table list.
305 *
306 *****************************************************************************/
307
308static acpi_status osl_add_table_to_list(char *signature, u32 instance)
309{
310 struct osl_table_info *new_info;
311 struct osl_table_info *next;
312 u32 next_instance = 0;
313 u8 found = FALSE;
314
315 new_info = calloc(1, sizeof(struct osl_table_info));
316 if (!new_info) {
317 return (AE_NO_MEMORY);
318 }
319
320 ACPI_MOVE_NAME(new_info->signature, signature);
321
322 if (!gbl_table_list_head) {
323 gbl_table_list_head = new_info;
324 } else {
325 next = gbl_table_list_head;
326 while (1) {
327 if (ACPI_COMPARE_NAME(next->signature, signature)) {
328 if (next->instance == instance) {
329 found = TRUE;
330 }
331 if (next->instance >= next_instance) {
332 next_instance = next->instance + 1;
333 }
334 }
335
336 if (!next->next) {
337 break;
338 }
339 next = next->next;
340 }
341 next->next = new_info;
342 }
343
344 if (found) {
345 if (instance) {
346 fprintf(stderr,
347 "%4.4s: Warning unmatched table instance %d, expected %d\n",
348 signature, instance, next_instance);
349 }
350 instance = next_instance;
351 }
352
353 new_info->instance = instance;
354 gbl_table_count++;
355
356 return (AE_OK);
357}
358
359/******************************************************************************
360 *
361 * FUNCTION: acpi_os_get_table_by_index
362 *
363 * PARAMETERS: index - Which table to get
364 * table - Where a pointer to the table is returned
365 * instance - Where a pointer to the table instance no. is
366 * returned
367 * address - Where the table physical address is returned
368 *
369 * RETURN: Status; Table buffer and physical address returned if AE_OK.
370 * AE_LIMIT: Index is beyond valid limit
371 *
372 * DESCRIPTION: Get an ACPI table via an index value (0 through n). Returns
373 * AE_LIMIT when an invalid index is reached. Index is not
374 * necessarily an index into the RSDT/XSDT.
375 *
376 *****************************************************************************/
377
378acpi_status
379acpi_os_get_table_by_index(u32 index,
380 struct acpi_table_header ** table,
381 u32 *instance, acpi_physical_address * address)
382{
383 struct osl_table_info *info;
384 acpi_status status;
385 u32 i;
386
387 /* Get main ACPI tables from memory on first invocation of this function */
388
389 status = osl_table_initialize();
390 if (ACPI_FAILURE(status)) {
391 return (status);
392 }
393
394 /* Validate Index */
395
396 if (index >= gbl_table_count) {
397 return (AE_LIMIT);
398 }
399
400 /* Point to the table list entry specified by the Index argument */
401
402 info = gbl_table_list_head;
403 for (i = 0; i < index; i++) {
404 info = info->next;
405 }
406
407 /* Now we can just get the table via the signature */
408
409 status = acpi_os_get_table_by_name(info->signature, info->instance,
410 table, address);
411
412 if (ACPI_SUCCESS(status)) {
413 *instance = info->instance;
414 }
415 return (status);
416}
417
418/******************************************************************************
419 *
420 * FUNCTION: osl_find_rsdp_via_efi
421 *
422 * PARAMETERS: None
423 *
424 * RETURN: RSDP address if found
425 *
426 * DESCRIPTION: Find RSDP address via EFI.
427 *
428 *****************************************************************************/
429
430static acpi_physical_address osl_find_rsdp_via_efi(void)
431{
432 FILE *file;
433 char buffer[80];
434 unsigned long address = 0;
435
436 file = fopen(EFI_SYSTAB, "r");
437 if (file) {
438 while (fgets(buffer, 80, file)) {
439 if (sscanf(buffer, "ACPI20=0x%lx", &address) == 1) {
440 break;
441 }
442 }
443 fclose(file);
444 }
445
446 return ((acpi_physical_address) (address));
447}
448
449/******************************************************************************
450 *
451 * FUNCTION: osl_load_rsdp
452 *
453 * PARAMETERS: None
454 *
455 * RETURN: Status
456 *
457 * DESCRIPTION: Scan and load RSDP.
458 *
459 *****************************************************************************/
460
461static acpi_status osl_load_rsdp(void)
462{
463 struct acpi_table_header *mapped_table;
464 u8 *rsdp_address;
465 acpi_physical_address rsdp_base;
466 acpi_size rsdp_size;
467
468 /* Get RSDP from memory */
469
470 rsdp_size = sizeof(struct acpi_table_rsdp);
471 if (gbl_rsdp_base) {
472 rsdp_base = gbl_rsdp_base;
473 } else {
474 rsdp_base = osl_find_rsdp_via_efi();
475 }
476
477 if (!rsdp_base) {
478 rsdp_base = ACPI_HI_RSDP_WINDOW_BASE;
479 rsdp_size = ACPI_HI_RSDP_WINDOW_SIZE;
480 }
481
482 rsdp_address = acpi_os_map_memory(rsdp_base, rsdp_size);
483 if (!rsdp_address) {
484 return (osl_get_last_status(AE_BAD_ADDRESS));
485 }
486
487 /* Search low memory for the RSDP */
488
489 mapped_table = ACPI_CAST_PTR(struct acpi_table_header,
490 acpi_tb_scan_memory_for_rsdp(rsdp_address,
491 rsdp_size));
492 if (!mapped_table) {
493 acpi_os_unmap_memory(rsdp_address, rsdp_size);
494 return (AE_NOT_FOUND);
495 }
496
497 gbl_rsdp_address =
498 rsdp_base + (ACPI_CAST8(mapped_table) - rsdp_address);
499
500 ACPI_MEMCPY(&gbl_rsdp, mapped_table, sizeof(struct acpi_table_rsdp));
501 acpi_os_unmap_memory(rsdp_address, rsdp_size);
502
503 return (AE_OK);
504}
505
506/******************************************************************************
507 *
508 * FUNCTION: osl_can_use_xsdt
509 *
510 * PARAMETERS: None
511 *
512 * RETURN: TRUE if XSDT is allowed to be used.
513 *
514 * DESCRIPTION: This function collects logic that can be used to determine if
515 * XSDT should be used instead of RSDT.
516 *
517 *****************************************************************************/
518
519static u8 osl_can_use_xsdt(void)
520{
521 if (gbl_revision && !acpi_gbl_do_not_use_xsdt) {
522 return (TRUE);
523 } else {
524 return (FALSE);
525 }
526}
527
528/******************************************************************************
529 *
530 * FUNCTION: osl_table_initialize
531 *
532 * PARAMETERS: None
533 *
534 * RETURN: Status
535 *
536 * DESCRIPTION: Initialize ACPI table data. Get and store main ACPI tables to
537 * local variables. Main ACPI tables include RSDT, FADT, RSDT,
538 * and/or XSDT.
539 *
540 *****************************************************************************/
541
542static acpi_status osl_table_initialize(void)
543{
544 acpi_status status;
545 acpi_physical_address address;
546
547 if (gbl_table_list_initialized) {
548 return (AE_OK);
549 }
550
551 /* Get RSDP from memory */
552
553 status = osl_load_rsdp();
554 if (ACPI_FAILURE(status)) {
555 return (status);
556 }
557
558 /* Get XSDT from memory */
559
560 if (gbl_rsdp.revision && !gbl_do_not_dump_xsdt) {
561 if (gbl_xsdt) {
562 free(gbl_xsdt);
563 gbl_xsdt = NULL;
564 }
565
566 gbl_revision = 2;
567 status = osl_get_bios_table(ACPI_SIG_XSDT, 0,
568 ACPI_CAST_PTR(struct
569 acpi_table_header *,
570 &gbl_xsdt), &address);
571 if (ACPI_FAILURE(status)) {
572 return (status);
573 }
574 }
575
576 /* Get RSDT from memory */
577
578 if (gbl_rsdp.rsdt_physical_address) {
579 if (gbl_rsdt) {
580 free(gbl_rsdt);
581 gbl_rsdt = NULL;
582 }
583
584 status = osl_get_bios_table(ACPI_SIG_RSDT, 0,
585 ACPI_CAST_PTR(struct
586 acpi_table_header *,
587 &gbl_rsdt), &address);
588 if (ACPI_FAILURE(status)) {
589 return (status);
590 }
591 }
592
593 /* Get FADT from memory */
594
595 if (gbl_fadt) {
596 free(gbl_fadt);
597 gbl_fadt = NULL;
598 }
599
600 status = osl_get_bios_table(ACPI_SIG_FADT, 0,
601 ACPI_CAST_PTR(struct acpi_table_header *,
602 &gbl_fadt),
603 &gbl_fadt_address);
604 if (ACPI_FAILURE(status)) {
605 return (status);
606 }
607
608 if (!gbl_dump_customized_tables) {
609
610 /* Add mandatory tables to global table list first */
611
612 status = osl_add_table_to_list(ACPI_RSDP_NAME, 0);
613 if (ACPI_FAILURE(status)) {
614 return (status);
615 }
616
617 status = osl_add_table_to_list(ACPI_SIG_RSDT, 0);
618 if (ACPI_FAILURE(status)) {
619 return (status);
620 }
621
622 if (gbl_revision == 2) {
623 status = osl_add_table_to_list(ACPI_SIG_XSDT, 0);
624 if (ACPI_FAILURE(status)) {
625 return (status);
626 }
627 }
628
629 status = osl_add_table_to_list(ACPI_SIG_DSDT, 0);
630 if (ACPI_FAILURE(status)) {
631 return (status);
632 }
633
634 status = osl_add_table_to_list(ACPI_SIG_FACS, 0);
635 if (ACPI_FAILURE(status)) {
636 return (status);
637 }
638
639 /* Add all tables found in the memory */
640
641 status = osl_list_bios_tables();
642 if (ACPI_FAILURE(status)) {
643 return (status);
644 }
645 } else {
646 /* Add all tables found in the static directory */
647
648 status = osl_list_customized_tables(STATIC_TABLE_DIR);
649 if (ACPI_FAILURE(status)) {
650 return (status);
651 }
652 }
653
654 if (gbl_dump_dynamic_tables) {
655
656 /* Add all dynamically loaded tables in the dynamic directory */
657
658 status = osl_list_customized_tables(DYNAMIC_TABLE_DIR);
659 if (ACPI_FAILURE(status)) {
660 return (status);
661 }
662 }
663
664 gbl_table_list_initialized = TRUE;
665 return (AE_OK);
666}
667
668/******************************************************************************
669 *
670 * FUNCTION: osl_list_bios_tables
671 *
672 * PARAMETERS: None
673 *
674 * RETURN: Status; Table list is initialized if AE_OK.
675 *
676 * DESCRIPTION: Add ACPI tables to the table list from memory.
677 *
678 * NOTE: This works on Linux as table customization does not modify the
679 * addresses stored in RSDP/RSDT/XSDT/FADT.
680 *
681 *****************************************************************************/
682
683static acpi_status osl_list_bios_tables(void)
684{
685 struct acpi_table_header *mapped_table = NULL;
686 u8 *table_data;
687 u8 number_of_tables;
688 u8 item_size;
689 acpi_physical_address table_address = 0;
690 acpi_status status = AE_OK;
691 u32 i;
692
693 if (osl_can_use_xsdt()) {
694 item_size = sizeof(u64);
695 table_data =
696 ACPI_CAST8(gbl_xsdt) + sizeof(struct acpi_table_header);
697 number_of_tables =
698 (u8)((gbl_xsdt->header.length -
699 sizeof(struct acpi_table_header))
700 / item_size);
701 } else { /* Use RSDT if XSDT is not available */
702
703 item_size = sizeof(u32);
704 table_data =
705 ACPI_CAST8(gbl_rsdt) + sizeof(struct acpi_table_header);
706 number_of_tables =
707 (u8)((gbl_rsdt->header.length -
708 sizeof(struct acpi_table_header))
709 / item_size);
710 }
711
712 /* Search RSDT/XSDT for the requested table */
713
714 for (i = 0; i < number_of_tables; ++i, table_data += item_size) {
715 if (osl_can_use_xsdt()) {
716 table_address =
717 (acpi_physical_address) (*ACPI_CAST64(table_data));
718 } else {
719 table_address =
720 (acpi_physical_address) (*ACPI_CAST32(table_data));
721 }
722
723 /* Skip NULL entries in RSDT/XSDT */
724
725 if (!table_address) {
726 continue;
727 }
728
729 status = osl_map_table(table_address, NULL, &mapped_table);
730 if (ACPI_FAILURE(status)) {
731 return (status);
732 }
733
734 osl_add_table_to_list(mapped_table->signature, 0);
735 osl_unmap_table(mapped_table);
736 }
737
738 return (AE_OK);
739}
740
741/******************************************************************************
742 *
743 * FUNCTION: osl_get_bios_table
744 *
745 * PARAMETERS: signature - ACPI Signature for common table. Must be
746 * a null terminated 4-character string.
747 * instance - Multiple table support for SSDT/UEFI (0...n)
748 * Must be 0 for other tables.
749 * table - Where a pointer to the table is returned
750 * address - Where the table physical address is returned
751 *
752 * RETURN: Status; Table buffer and physical address returned if AE_OK.
753 * AE_LIMIT: Instance is beyond valid limit
754 * AE_NOT_FOUND: A table with the signature was not found
755 *
756 * DESCRIPTION: Get a BIOS provided ACPI table
757 *
758 * NOTE: Assumes the input signature is uppercase.
759 *
760 *****************************************************************************/
761
762static acpi_status
763osl_get_bios_table(char *signature,
764 u32 instance,
765 struct acpi_table_header **table,
766 acpi_physical_address * address)
767{
768 struct acpi_table_header *local_table = NULL;
769 struct acpi_table_header *mapped_table = NULL;
770 u8 *table_data;
771 u8 number_of_tables;
772 u8 item_size;
773 u32 current_instance = 0;
774 acpi_physical_address table_address = 0;
775 u32 table_length = 0;
776 acpi_status status = AE_OK;
777 u32 i;
778
779 /* Handle special tables whose addresses are not in RSDT/XSDT */
780
781 if (ACPI_COMPARE_NAME(signature, ACPI_RSDP_NAME) ||
782 ACPI_COMPARE_NAME(signature, ACPI_SIG_RSDT) ||
783 ACPI_COMPARE_NAME(signature, ACPI_SIG_XSDT) ||
784 ACPI_COMPARE_NAME(signature, ACPI_SIG_DSDT) ||
785 ACPI_COMPARE_NAME(signature, ACPI_SIG_FACS)) {
786 if (instance > 0) {
787 return (AE_LIMIT);
788 }
789
790 /*
791 * Get the appropriate address, either 32-bit or 64-bit. Be very
792 * careful about the FADT length and validate table addresses.
793 * Note: The 64-bit addresses have priority.
794 */
795 if (ACPI_COMPARE_NAME(signature, ACPI_SIG_DSDT)) {
796 if ((gbl_fadt->header.length >= MIN_FADT_FOR_XDSDT) &&
797 gbl_fadt->Xdsdt) {
798 table_address =
799 (acpi_physical_address) gbl_fadt->Xdsdt;
800 } else
801 if ((gbl_fadt->header.length >= MIN_FADT_FOR_DSDT)
802 && gbl_fadt->dsdt) {
803 table_address =
804 (acpi_physical_address) gbl_fadt->dsdt;
805 }
806 } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_FACS)) {
807 if ((gbl_fadt->header.length >= MIN_FADT_FOR_XFACS) &&
808 gbl_fadt->Xfacs) {
809 table_address =
810 (acpi_physical_address) gbl_fadt->Xfacs;
811 } else
812 if ((gbl_fadt->header.length >= MIN_FADT_FOR_FACS)
813 && gbl_fadt->facs) {
814 table_address =
815 (acpi_physical_address) gbl_fadt->facs;
816 }
817 } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_XSDT)) {
818 if (!gbl_revision) {
819 return (AE_BAD_SIGNATURE);
820 }
821 table_address =
822 (acpi_physical_address) gbl_rsdp.
823 xsdt_physical_address;
824 } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_RSDT)) {
825 table_address =
826 (acpi_physical_address) gbl_rsdp.
827 rsdt_physical_address;
828 } else {
829 table_address =
830 (acpi_physical_address) gbl_rsdp_address;
831 signature = ACPI_SIG_RSDP;
832 }
833
834 /* Now we can get the requested special table */
835
836 status = osl_map_table(table_address, signature, &mapped_table);
837 if (ACPI_FAILURE(status)) {
838 return (status);
839 }
840
841 table_length = ap_get_table_length(mapped_table);
842 } else { /* Case for a normal ACPI table */
843
844 if (osl_can_use_xsdt()) {
845 item_size = sizeof(u64);
846 table_data =
847 ACPI_CAST8(gbl_xsdt) +
848 sizeof(struct acpi_table_header);
849 number_of_tables =
850 (u8)((gbl_xsdt->header.length -
851 sizeof(struct acpi_table_header))
852 / item_size);
853 } else { /* Use RSDT if XSDT is not available */
854
855 item_size = sizeof(u32);
856 table_data =
857 ACPI_CAST8(gbl_rsdt) +
858 sizeof(struct acpi_table_header);
859 number_of_tables =
860 (u8)((gbl_rsdt->header.length -
861 sizeof(struct acpi_table_header))
862 / item_size);
863 }
864
865 /* Search RSDT/XSDT for the requested table */
866
867 for (i = 0; i < number_of_tables; ++i, table_data += item_size) {
868 if (osl_can_use_xsdt()) {
869 table_address =
870 (acpi_physical_address) (*ACPI_CAST64
871 (table_data));
872 } else {
873 table_address =
874 (acpi_physical_address) (*ACPI_CAST32
875 (table_data));
876 }
877
878 /* Skip NULL entries in RSDT/XSDT */
879
880 if (!table_address) {
881 continue;
882 }
883
884 status =
885 osl_map_table(table_address, NULL, &mapped_table);
886 if (ACPI_FAILURE(status)) {
887 return (status);
888 }
889 table_length = mapped_table->length;
890
891 /* Does this table match the requested signature? */
892
893 if (!ACPI_COMPARE_NAME
894 (mapped_table->signature, signature)) {
895 osl_unmap_table(mapped_table);
896 mapped_table = NULL;
897 continue;
898 }
899
900 /* Match table instance (for SSDT/UEFI tables) */
901
902 if (current_instance != instance) {
903 osl_unmap_table(mapped_table);
904 mapped_table = NULL;
905 current_instance++;
906 continue;
907 }
908
909 break;
910 }
911 }
912
913 if (!mapped_table) {
914 return (AE_LIMIT);
915 }
916
917 if (table_length == 0) {
918 status = AE_BAD_HEADER;
919 goto exit;
920 }
921
922 /* Copy table to local buffer and return it */
923
924 local_table = calloc(1, table_length);
925 if (!local_table) {
926 status = AE_NO_MEMORY;
927 goto exit;
928 }
929
930 ACPI_MEMCPY(local_table, mapped_table, table_length);
931 *address = table_address;
932 *table = local_table;
933
934exit:
935 osl_unmap_table(mapped_table);
936 return (status);
937}
938
939/******************************************************************************
940 *
941 * FUNCTION: osl_list_customized_tables
942 *
943 * PARAMETERS: directory - Directory that contains the tables
944 *
945 * RETURN: Status; Table list is initialized if AE_OK.
946 *
947 * DESCRIPTION: Add ACPI tables to the table list from a directory.
948 *
949 *****************************************************************************/
950
951static acpi_status osl_list_customized_tables(char *directory)
952{
953 void *table_dir;
954 u32 instance;
955 char temp_name[ACPI_NAME_SIZE];
956 char *filename;
957 acpi_status status = AE_OK;
958
959 /* Open the requested directory */
960
961 table_dir = acpi_os_open_directory(directory, "*", REQUEST_FILE_ONLY);
962 if (!table_dir) {
963 return (osl_get_last_status(AE_NOT_FOUND));
964 }
965
966 /* Examine all entries in this directory */
967
968 while ((filename = acpi_os_get_next_filename(table_dir))) {
969
970 /* Extract table name and instance number */
971
972 status =
973 osl_table_name_from_file(filename, temp_name, &instance);
974
975 /* Ignore meaningless files */
976
977 if (ACPI_FAILURE(status)) {
978 continue;
979 }
980
981 /* Add new info node to global table list */
982
983 status = osl_add_table_to_list(temp_name, instance);
984 if (ACPI_FAILURE(status)) {
985 break;
986 }
987 }
988
989 acpi_os_close_directory(table_dir);
990 return (status);
991}
992
993/******************************************************************************
994 *
995 * FUNCTION: osl_map_table
996 *
997 * PARAMETERS: address - Address of the table in memory
998 * signature - Optional ACPI Signature for desired table.
999 * Null terminated 4-character string.
1000 * table - Where a pointer to the mapped table is
1001 * returned
1002 *
1003 * RETURN: Status; Mapped table is returned if AE_OK.
1004 * AE_NOT_FOUND: A valid table was not found at the address
1005 *
1006 * DESCRIPTION: Map entire ACPI table into caller's address space.
1007 *
1008 *****************************************************************************/
1009
1010static acpi_status
1011osl_map_table(acpi_size address,
1012 char *signature, struct acpi_table_header **table)
1013{
1014 struct acpi_table_header *mapped_table;
1015 u32 length;
1016
1017 if (!address) {
1018 return (AE_BAD_ADDRESS);
1019 }
1020
1021 /*
1022 * Map the header so we can get the table length.
1023 * Use sizeof (struct acpi_table_header) as:
1024 * 1. it is bigger than 24 to include RSDP->Length
1025 * 2. it is smaller than sizeof (struct acpi_table_rsdp)
1026 */
1027 mapped_table =
1028 acpi_os_map_memory(address, sizeof(struct acpi_table_header));
1029 if (!mapped_table) {
1030 fprintf(stderr, "Could not map table header at 0x%8.8X%8.8X\n",
1031 ACPI_FORMAT_UINT64(address));
1032 return (osl_get_last_status(AE_BAD_ADDRESS));
1033 }
1034
1035 /* If specified, signature must match */
1036
1037 if (signature) {
1038 if (ACPI_VALIDATE_RSDP_SIG(signature)) {
1039 if (!ACPI_VALIDATE_RSDP_SIG(mapped_table->signature)) {
1040 acpi_os_unmap_memory(mapped_table,
1041 sizeof(struct
1042 acpi_table_header));
1043 return (AE_BAD_SIGNATURE);
1044 }
1045 } else
1046 if (!ACPI_COMPARE_NAME(signature, mapped_table->signature))
1047 {
1048 acpi_os_unmap_memory(mapped_table,
1049 sizeof(struct acpi_table_header));
1050 return (AE_BAD_SIGNATURE);
1051 }
1052 }
1053
1054 /* Map the entire table */
1055
1056 length = ap_get_table_length(mapped_table);
1057 acpi_os_unmap_memory(mapped_table, sizeof(struct acpi_table_header));
1058 if (length == 0) {
1059 return (AE_BAD_HEADER);
1060 }
1061
1062 mapped_table = acpi_os_map_memory(address, length);
1063 if (!mapped_table) {
1064 fprintf(stderr,
1065 "Could not map table at 0x%8.8X%8.8X length %8.8X\n",
1066 ACPI_FORMAT_UINT64(address), length);
1067 return (osl_get_last_status(AE_INVALID_TABLE_LENGTH));
1068 }
1069
1070 (void)ap_is_valid_checksum(mapped_table);
1071
1072 *table = mapped_table;
1073 return (AE_OK);
1074}
1075
1076/******************************************************************************
1077 *
1078 * FUNCTION: osl_unmap_table
1079 *
1080 * PARAMETERS: table - A pointer to the mapped table
1081 *
1082 * RETURN: None
1083 *
1084 * DESCRIPTION: Unmap entire ACPI table.
1085 *
1086 *****************************************************************************/
1087
1088static void osl_unmap_table(struct acpi_table_header *table)
1089{
1090 if (table) {
1091 acpi_os_unmap_memory(table, ap_get_table_length(table));
1092 }
1093}
1094
1095/******************************************************************************
1096 *
1097 * FUNCTION: osl_table_name_from_file
1098 *
1099 * PARAMETERS: filename - File that contains the desired table
1100 * signature - Pointer to 4-character buffer to store
1101 * extracted table signature.
1102 * instance - Pointer to integer to store extracted
1103 * table instance number.
1104 *
1105 * RETURN: Status; Table name is extracted if AE_OK.
1106 *
1107 * DESCRIPTION: Extract table signature and instance number from a table file
1108 * name.
1109 *
1110 *****************************************************************************/
1111
1112static acpi_status
1113osl_table_name_from_file(char *filename, char *signature, u32 *instance)
1114{
1115
1116 /* Ignore meaningless files */
1117
1118 if (strlen(filename) < ACPI_NAME_SIZE) {
1119 return (AE_BAD_SIGNATURE);
1120 }
1121
1122 /* Extract instance number */
1123
1124 if (isdigit((int)filename[ACPI_NAME_SIZE])) {
1125 sscanf(&filename[ACPI_NAME_SIZE], "%d", instance);
1126 } else if (strlen(filename) != ACPI_NAME_SIZE) {
1127 return (AE_BAD_SIGNATURE);
1128 } else {
1129 *instance = 0;
1130 }
1131
1132 /* Extract signature */
1133
1134 ACPI_MOVE_NAME(signature, filename);
1135 return (AE_OK);
1136}
1137
1138/******************************************************************************
1139 *
1140 * FUNCTION: osl_read_table_from_file
1141 *
1142 * PARAMETERS: filename - File that contains the desired table
1143 * file_offset - Offset of the table in file
1144 * signature - Optional ACPI Signature for desired table.
1145 * A null terminated 4-character string.
1146 * table - Where a pointer to the table is returned
1147 *
1148 * RETURN: Status; Table buffer is returned if AE_OK.
1149 *
1150 * DESCRIPTION: Read a ACPI table from a file.
1151 *
1152 *****************************************************************************/
1153
1154static acpi_status
1155osl_read_table_from_file(char *filename,
1156 acpi_size file_offset,
1157 char *signature, struct acpi_table_header **table)
1158{
1159 FILE *table_file;
1160 struct acpi_table_header header;
1161 struct acpi_table_header *local_table = NULL;
1162 u32 table_length;
1163 s32 count;
1164 acpi_status status = AE_OK;
1165
1166 /* Open the file */
1167
1168 table_file = fopen(filename, "rb");
1169 if (table_file == NULL) {
1170 fprintf(stderr, "Could not open table file: %s\n", filename);
1171 return (osl_get_last_status(AE_NOT_FOUND));
1172 }
1173
1174 fseek(table_file, file_offset, SEEK_SET);
1175
1176 /* Read the Table header to get the table length */
1177
1178 count = fread(&header, 1, sizeof(struct acpi_table_header), table_file);
1179 if (count != sizeof(struct acpi_table_header)) {
1180 fprintf(stderr, "Could not read table header: %s\n", filename);
1181 status = AE_BAD_HEADER;
1182 goto exit;
1183 }
1184
1185 /* If signature is specified, it must match the table */
1186
1187 if (signature) {
1188 if (ACPI_VALIDATE_RSDP_SIG(signature)) {
1189 if (!ACPI_VALIDATE_RSDP_SIG(header.signature)) {
1190 fprintf(stderr,
1191 "Incorrect RSDP signature: found %8.8s\n",
1192 header.signature);
1193 status = AE_BAD_SIGNATURE;
1194 goto exit;
1195 }
1196 } else if (!ACPI_COMPARE_NAME(signature, header.signature)) {
1197 fprintf(stderr,
1198 "Incorrect signature: Expecting %4.4s, found %4.4s\n",
1199 signature, header.signature);
1200 status = AE_BAD_SIGNATURE;
1201 goto exit;
1202 }
1203 }
1204
1205 table_length = ap_get_table_length(&header);
1206 if (table_length == 0) {
1207 status = AE_BAD_HEADER;
1208 goto exit;
1209 }
1210
1211 /* Read the entire table into a local buffer */
1212
1213 local_table = calloc(1, table_length);
1214 if (!local_table) {
1215 fprintf(stderr,
1216 "%4.4s: Could not allocate buffer for table of length %X\n",
1217 header.signature, table_length);
1218 status = AE_NO_MEMORY;
1219 goto exit;
1220 }
1221
1222 fseek(table_file, file_offset, SEEK_SET);
1223
1224 count = fread(local_table, 1, table_length, table_file);
1225 if (count != table_length) {
1226 fprintf(stderr, "%4.4s: Could not read table content\n",
1227 header.signature);
1228 status = AE_INVALID_TABLE_LENGTH;
1229 goto exit;
1230 }
1231
1232 /* Validate checksum */
1233
1234 (void)ap_is_valid_checksum(local_table);
1235
1236exit:
1237 fclose(table_file);
1238 *table = local_table;
1239 return (status);
1240}
1241
1242/******************************************************************************
1243 *
1244 * FUNCTION: osl_get_customized_table
1245 *
1246 * PARAMETERS: pathname - Directory to find Linux customized table
1247 * signature - ACPI Signature for desired table. Must be
1248 * a null terminated 4-character string.
1249 * instance - Multiple table support for SSDT/UEFI (0...n)
1250 * Must be 0 for other tables.
1251 * table - Where a pointer to the table is returned
1252 * address - Where the table physical address is returned
1253 *
1254 * RETURN: Status; Table buffer is returned if AE_OK.
1255 * AE_LIMIT: Instance is beyond valid limit
1256 * AE_NOT_FOUND: A table with the signature was not found
1257 *
1258 * DESCRIPTION: Get an OS customized table.
1259 *
1260 *****************************************************************************/
1261
1262static acpi_status
1263osl_get_customized_table(char *pathname,
1264 char *signature,
1265 u32 instance,
1266 struct acpi_table_header **table,
1267 acpi_physical_address * address)
1268{
1269 void *table_dir;
1270 u32 current_instance = 0;
1271 char temp_name[ACPI_NAME_SIZE];
1272 char table_filename[PATH_MAX];
1273 char *filename;
1274 acpi_status status;
1275
1276 /* Open the directory for customized tables */
1277
1278 table_dir = acpi_os_open_directory(pathname, "*", REQUEST_FILE_ONLY);
1279 if (!table_dir) {
1280 return (osl_get_last_status(AE_NOT_FOUND));
1281 }
1282
1283 /* Attempt to find the table in the directory */
1284
1285 while ((filename = acpi_os_get_next_filename(table_dir))) {
1286
1287 /* Ignore meaningless files */
1288
1289 if (!ACPI_COMPARE_NAME(filename, signature)) {
1290 continue;
1291 }
1292
1293 /* Extract table name and instance number */
1294
1295 status =
1296 osl_table_name_from_file(filename, temp_name,
1297 &current_instance);
1298
1299 /* Ignore meaningless files */
1300
1301 if (ACPI_FAILURE(status) || current_instance != instance) {
1302 continue;
1303 }
1304
1305 /* Create the table pathname */
1306
1307 if (instance != 0) {
1308 sprintf(table_filename, "%s/%4.4s%d", pathname,
1309 temp_name, instance);
1310 } else {
1311 sprintf(table_filename, "%s/%4.4s", pathname,
1312 temp_name);
1313 }
1314 break;
1315 }
1316
1317 acpi_os_close_directory(table_dir);
1318
1319 if (!filename) {
1320 return (AE_LIMIT);
1321 }
1322
1323 /* There is no physical address saved for customized tables, use zero */
1324
1325 *address = 0;
1326 status = osl_read_table_from_file(table_filename, 0, NULL, table);
1327
1328 return (status);
1329}
diff --git a/tools/power/acpi/os_specific/service_layers/osunixdir.c b/tools/power/acpi/os_specific/service_layers/osunixdir.c
new file mode 100644
index 000000000000..733f9e490fc4
--- /dev/null
+++ b/tools/power/acpi/os_specific/service_layers/osunixdir.c
@@ -0,0 +1,204 @@
1/******************************************************************************
2 *
3 * Module Name: osunixdir - Unix directory access interfaces
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2014, Intel Corp.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions, and the following disclaimer,
16 * without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 * substantially similar to the "NO WARRANTY" disclaimer below
19 * ("Disclaimer") and any redistribution must be conditioned upon
20 * including a substantially similar Disclaimer requirement for further
21 * binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 * of any contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
29 *
30 * NO WARRANTY
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
42 */
43
44#include <acpi/acpi.h>
45
46#include <stdio.h>
47#include <stdlib.h>
48#include <string.h>
49#include <dirent.h>
50#include <fnmatch.h>
51#include <ctype.h>
52#include <sys/stat.h>
53
54/*
55 * Allocated structure returned from os_open_directory
56 */
57typedef struct external_find_info {
58 char *dir_pathname;
59 DIR *dir_ptr;
60 char temp_buffer[256];
61 char *wildcard_spec;
62 char requested_file_type;
63
64} external_find_info;
65
66/*******************************************************************************
67 *
68 * FUNCTION: acpi_os_open_directory
69 *
70 * PARAMETERS: dir_pathname - Full pathname to the directory
71 * wildcard_spec - string of the form "*.c", etc.
72 *
73 * RETURN: A directory "handle" to be used in subsequent search operations.
74 * NULL returned on failure.
75 *
76 * DESCRIPTION: Open a directory in preparation for a wildcard search
77 *
78 ******************************************************************************/
79
80void *acpi_os_open_directory(char *dir_pathname,
81 char *wildcard_spec, char requested_file_type)
82{
83 struct external_find_info *external_info;
84 DIR *dir;
85
86 /* Allocate the info struct that will be returned to the caller */
87
88 external_info = calloc(1, sizeof(struct external_find_info));
89 if (!external_info) {
90 return (NULL);
91 }
92
93 /* Get the directory stream */
94
95 dir = opendir(dir_pathname);
96 if (!dir) {
97 fprintf(stderr, "Cannot open directory - %s\n", dir_pathname);
98 free(external_info);
99 return (NULL);
100 }
101
102 /* Save the info in the return structure */
103
104 external_info->wildcard_spec = wildcard_spec;
105 external_info->requested_file_type = requested_file_type;
106 external_info->dir_pathname = dir_pathname;
107 external_info->dir_ptr = dir;
108 return (external_info);
109}
110
111/*******************************************************************************
112 *
113 * FUNCTION: acpi_os_get_next_filename
114 *
115 * PARAMETERS: dir_handle - Created via acpi_os_open_directory
116 *
117 * RETURN: Next filename matched. NULL if no more matches.
118 *
119 * DESCRIPTION: Get the next file in the directory that matches the wildcard
120 * specification.
121 *
122 ******************************************************************************/
123
124char *acpi_os_get_next_filename(void *dir_handle)
125{
126 struct external_find_info *external_info = dir_handle;
127 struct dirent *dir_entry;
128 char *temp_str;
129 int str_len;
130 struct stat temp_stat;
131 int err;
132
133 while ((dir_entry = readdir(external_info->dir_ptr))) {
134 if (!fnmatch
135 (external_info->wildcard_spec, dir_entry->d_name, 0)) {
136 if (dir_entry->d_name[0] == '.') {
137 continue;
138 }
139
140 str_len = strlen(dir_entry->d_name) +
141 strlen(external_info->dir_pathname) + 2;
142
143 temp_str = calloc(str_len, 1);
144 if (!temp_str) {
145 fprintf(stderr,
146 "Could not allocate buffer for temporary string\n");
147 return (NULL);
148 }
149
150 strcpy(temp_str, external_info->dir_pathname);
151 strcat(temp_str, "/");
152 strcat(temp_str, dir_entry->d_name);
153
154 err = stat(temp_str, &temp_stat);
155 if (err == -1) {
156 fprintf(stderr,
157 "Cannot stat file (should not happen) - %s\n",
158 temp_str);
159 free(temp_str);
160 return (NULL);
161 }
162
163 free(temp_str);
164
165 if ((S_ISDIR(temp_stat.st_mode)
166 && (external_info->requested_file_type ==
167 REQUEST_DIR_ONLY))
168 || ((!S_ISDIR(temp_stat.st_mode)
169 && external_info->requested_file_type ==
170 REQUEST_FILE_ONLY))) {
171
172 /* copy to a temp buffer because dir_entry struct is on the stack */
173
174 strcpy(external_info->temp_buffer,
175 dir_entry->d_name);
176 return (external_info->temp_buffer);
177 }
178 }
179 }
180
181 return (NULL);
182}
183
184/*******************************************************************************
185 *
186 * FUNCTION: acpi_os_close_directory
187 *
188 * PARAMETERS: dir_handle - Created via acpi_os_open_directory
189 *
190 * RETURN: None.
191 *
192 * DESCRIPTION: Close the open directory and cleanup.
193 *
194 ******************************************************************************/
195
196void acpi_os_close_directory(void *dir_handle)
197{
198 struct external_find_info *external_info = dir_handle;
199
200 /* Close the directory and free allocations */
201
202 closedir(external_info->dir_ptr);
203 free(dir_handle);
204}
diff --git a/tools/power/acpi/os_specific/service_layers/osunixmap.c b/tools/power/acpi/os_specific/service_layers/osunixmap.c
new file mode 100644
index 000000000000..99b47b6194a3
--- /dev/null
+++ b/tools/power/acpi/os_specific/service_layers/osunixmap.c
@@ -0,0 +1,151 @@
1/******************************************************************************
2 *
3 * Module Name: osunixmap - Unix OSL for file mappings
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2014, Intel Corp.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions, and the following disclaimer,
16 * without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 * substantially similar to the "NO WARRANTY" disclaimer below
19 * ("Disclaimer") and any redistribution must be conditioned upon
20 * including a substantially similar Disclaimer requirement for further
21 * binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 * of any contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
29 *
30 * NO WARRANTY
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
42 */
43
44#include "acpidump.h"
45#include <unistd.h>
46#include <sys/mman.h>
47#ifdef _free_BSD
48#include <sys/param.h>
49#endif
50
51#define _COMPONENT ACPI_OS_SERVICES
52ACPI_MODULE_NAME("osunixmap")
53
54#ifndef O_BINARY
55#define O_BINARY 0
56#endif
57#ifdef _free_BSD
58#define MMAP_FLAGS MAP_SHARED
59#else
60#define MMAP_FLAGS MAP_PRIVATE
61#endif
62#define SYSTEM_MEMORY "/dev/mem"
63/*******************************************************************************
64 *
65 * FUNCTION: acpi_os_get_page_size
66 *
67 * PARAMETERS: None
68 *
69 * RETURN: Page size of the platform.
70 *
71 * DESCRIPTION: Obtain page size of the platform.
72 *
73 ******************************************************************************/
74static acpi_size acpi_os_get_page_size(void)
75{
76
77#ifdef PAGE_SIZE
78 return PAGE_SIZE;
79#else
80 return sysconf(_SC_PAGESIZE);
81#endif
82}
83
84/******************************************************************************
85 *
86 * FUNCTION: acpi_os_map_memory
87 *
88 * PARAMETERS: where - Physical address of memory to be mapped
89 * length - How much memory to map
90 *
91 * RETURN: Pointer to mapped memory. Null on error.
92 *
93 * DESCRIPTION: Map physical memory into local address space.
94 *
95 *****************************************************************************/
96
97void *acpi_os_map_memory(acpi_physical_address where, acpi_size length)
98{
99 u8 *mapped_memory;
100 acpi_physical_address offset;
101 acpi_size page_size;
102 int fd;
103
104 fd = open(SYSTEM_MEMORY, O_RDONLY | O_BINARY);
105 if (fd < 0) {
106 fprintf(stderr, "Cannot open %s\n", SYSTEM_MEMORY);
107 return (NULL);
108 }
109
110 /* Align the offset to use mmap */
111
112 page_size = acpi_os_get_page_size();
113 offset = where % page_size;
114
115 /* Map the table header to get the length of the full table */
116
117 mapped_memory = mmap(NULL, (length + offset), PROT_READ, MMAP_FLAGS,
118 fd, (where - offset));
119 if (mapped_memory == MAP_FAILED) {
120 fprintf(stderr, "Cannot map %s\n", SYSTEM_MEMORY);
121 close(fd);
122 return (NULL);
123 }
124
125 close(fd);
126 return (ACPI_CAST8(mapped_memory + offset));
127}
128
129/******************************************************************************
130 *
131 * FUNCTION: acpi_os_unmap_memory
132 *
133 * PARAMETERS: where - Logical address of memory to be unmapped
134 * length - How much memory to unmap
135 *
136 * RETURN: None.
137 *
138 * DESCRIPTION: Delete a previously created mapping. Where and Length must
139 * correspond to a previous mapping exactly.
140 *
141 *****************************************************************************/
142
143void acpi_os_unmap_memory(void *where, acpi_size length)
144{
145 acpi_physical_address offset;
146 acpi_size page_size;
147
148 page_size = acpi_os_get_page_size();
149 offset = (acpi_physical_address) where % page_size;
150 munmap((u8 *)where - offset, (length + offset));
151}
diff --git a/tools/power/acpi/tools/acpidump/acpidump.c b/tools/power/acpi/tools/acpidump/acpidump.c
deleted file mode 100644
index a84553a0e0df..000000000000
--- a/tools/power/acpi/tools/acpidump/acpidump.c
+++ /dev/null
@@ -1,559 +0,0 @@
1/*
2 * (c) Alexey Starikovskiy, Intel, 2005-2006.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions, and the following disclaimer,
10 * without modification.
11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12 * substantially similar to the "NO WARRANTY" disclaimer below
13 * ("Disclaimer") and any redistribution must be conditioned upon
14 * including a substantially similar Disclaimer requirement for further
15 * binary redistribution.
16 * 3. Neither the names of the above-listed copyright holders nor the names
17 * of any contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * Alternatively, this software may be distributed under the terms of the
21 * GNU General Public License ("GPL") version 2 as published by the Free
22 * Software Foundation.
23 *
24 * NO WARRANTY
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
33 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
34 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGES.
36 */
37
38#ifdef DEFINE_ALTERNATE_TYPES
39/* hack to enable building old application with new headers -lenb */
40#define acpi_fadt_descriptor acpi_table_fadt
41#define acpi_rsdp_descriptor acpi_table_rsdp
42#define DSDT_SIG ACPI_SIG_DSDT
43#define FACS_SIG ACPI_SIG_FACS
44#define FADT_SIG ACPI_SIG_FADT
45#define xfirmware_ctrl Xfacs
46#define firmware_ctrl facs
47
48typedef int s32;
49typedef unsigned char u8;
50typedef unsigned short u16;
51typedef unsigned int u32;
52typedef unsigned long long u64;
53typedef long long s64;
54#endif
55
56#include <sys/mman.h>
57#include <sys/types.h>
58#include <sys/stat.h>
59#include <fcntl.h>
60#include <stdio.h>
61#include <string.h>
62#include <unistd.h>
63#include <getopt.h>
64
65#include <dirent.h>
66
67#include <acpi/acconfig.h>
68#include <acpi/platform/acenv.h>
69#include <acpi/actypes.h>
70#include <acpi/actbl.h>
71
72static inline u8 checksum(u8 * buffer, u32 length)
73{
74 u8 sum = 0, *i = buffer;
75 buffer += length;
76 for (; i < buffer; sum += *(i++));
77 return sum;
78}
79
80static unsigned long psz, addr, length;
81static int print, connect, skip;
82static u8 select_sig[4];
83
84static unsigned long read_efi_systab( void )
85{
86 char buffer[80];
87 unsigned long addr;
88 FILE *f = fopen("/sys/firmware/efi/systab", "r");
89 if (f) {
90 while (fgets(buffer, 80, f)) {
91 if (sscanf(buffer, "ACPI20=0x%lx", &addr) == 1)
92 return addr;
93 }
94 fclose(f);
95 }
96 return 0;
97}
98
99static u8 *acpi_map_memory(unsigned long where, unsigned length)
100{
101 unsigned long offset;
102 u8 *there;
103 int fd = open("/dev/mem", O_RDONLY);
104 if (fd < 0) {
105 fprintf(stderr, "acpi_os_map_memory: cannot open /dev/mem\n");
106 exit(1);
107 }
108 offset = where % psz;
109 there = mmap(NULL, length + offset, PROT_READ, MAP_PRIVATE,
110 fd, where - offset);
111 close(fd);
112 if (there == MAP_FAILED) return 0;
113 return (there + offset);
114}
115
116static void acpi_unmap_memory(u8 * there, unsigned length)
117{
118 unsigned long offset = (unsigned long)there % psz;
119 munmap(there - offset, length + offset);
120}
121
122static struct acpi_table_header *acpi_map_table(unsigned long where, char *sig)
123{
124 unsigned size;
125 struct acpi_table_header *tbl = (struct acpi_table_header *)
126 acpi_map_memory(where, sizeof(struct acpi_table_header));
127 if (!tbl || (sig && memcmp(sig, tbl->signature, 4))) return 0;
128 size = tbl->length;
129 acpi_unmap_memory((u8 *) tbl, sizeof(struct acpi_table_header));
130 return (struct acpi_table_header *)acpi_map_memory(where, size);
131}
132
133static void acpi_unmap_table(struct acpi_table_header *tbl)
134{
135 acpi_unmap_memory((u8 *)tbl, tbl->length);
136}
137
138static struct acpi_rsdp_descriptor *acpi_scan_for_rsdp(u8 *begin, u32 length)
139{
140 struct acpi_rsdp_descriptor *rsdp;
141 u8 *i, *end = begin + length;
142 /* Search from given start address for the requested length */
143 for (i = begin; i < end; i += ACPI_RSDP_SCAN_STEP) {
144 /* The signature and checksum must both be correct */
145 if (memcmp((char *)i, "RSD PTR ", 8)) continue;
146 rsdp = (struct acpi_rsdp_descriptor *)i;
147 /* Signature matches, check the appropriate checksum */
148 if (!checksum((u8 *) rsdp, (rsdp->revision < 2) ?
149 ACPI_RSDP_CHECKSUM_LENGTH :
150 ACPI_RSDP_XCHECKSUM_LENGTH))
151 /* Checksum valid, we have found a valid RSDP */
152 return rsdp;
153 }
154 /* Searched entire block, no RSDP was found */
155 return 0;
156}
157
158/*
159 * Output data
160 */
161static void acpi_show_data(int fd, u8 * data, int size)
162{
163 char buffer[256];
164 int len;
165 int i, remain = size;
166 while (remain > 0) {
167 len = snprintf(buffer, 256, " %04x:", size - remain);
168 for (i = 0; i < 16 && i < remain; i++) {
169 len +=
170 snprintf(&buffer[len], 256 - len, " %02x", data[i]);
171 }
172 for (; i < 16; i++) {
173 len += snprintf(&buffer[len], 256 - len, " ");
174 }
175 len += snprintf(&buffer[len], 256 - len, " ");
176 for (i = 0; i < 16 && i < remain; i++) {
177 buffer[len++] = (isprint(data[i])) ? data[i] : '.';
178 }
179 buffer[len++] = '\n';
180 write(fd, buffer, len);
181 data += 16;
182 remain -= 16;
183 }
184}
185
186/*
187 * Output ACPI table
188 */
189static void acpi_show_table(int fd, struct acpi_table_header *table, unsigned long addr)
190{
191 char buff[80];
192 int len = snprintf(buff, 80, "%.4s @ %p\n", table->signature, (void *)addr);
193 write(fd, buff, len);
194 acpi_show_data(fd, (u8 *) table, table->length);
195 buff[0] = '\n';
196 write(fd, buff, 1);
197}
198
199static void write_table(int fd, struct acpi_table_header *tbl, unsigned long addr)
200{
201 static int select_done = 0;
202 if (!select_sig[0]) {
203 if (print) {
204 acpi_show_table(fd, tbl, addr);
205 } else {
206 write(fd, tbl, tbl->length);
207 }
208 } else if (!select_done && !memcmp(select_sig, tbl->signature, 4)) {
209 if (skip > 0) {
210 --skip;
211 return;
212 }
213 if (print) {
214 acpi_show_table(fd, tbl, addr);
215 } else {
216 write(fd, tbl, tbl->length);
217 }
218 select_done = 1;
219 }
220}
221
222static void acpi_dump_FADT(int fd, struct acpi_table_header *tbl, unsigned long xaddr) {
223 struct acpi_fadt_descriptor x;
224 unsigned long addr;
225 size_t len = sizeof(struct acpi_fadt_descriptor);
226 if (len > tbl->length) len = tbl->length;
227 memcpy(&x, tbl, len);
228 x.header.length = len;
229 if (checksum((u8 *)tbl, len)) {
230 fprintf(stderr, "Wrong checksum for FADT!\n");
231 }
232 if (x.header.length >= 148 && x.Xdsdt) {
233 addr = (unsigned long)x.Xdsdt;
234 if (connect) {
235 x.Xdsdt = lseek(fd, 0, SEEK_CUR);
236 }
237 } else if (x.header.length >= 44 && x.dsdt) {
238 addr = (unsigned long)x.dsdt;
239 if (connect) {
240 x.dsdt = lseek(fd, 0, SEEK_CUR);
241 }
242 } else {
243 fprintf(stderr, "No DSDT in FADT!\n");
244 goto no_dsdt;
245 }
246 tbl = acpi_map_table(addr, DSDT_SIG);
247 if (!tbl) goto no_dsdt;
248 if (checksum((u8 *)tbl, tbl->length))
249 fprintf(stderr, "Wrong checksum for DSDT!\n");
250 write_table(fd, tbl, addr);
251 acpi_unmap_table(tbl);
252no_dsdt:
253 if (x.header.length >= 140 && x.xfirmware_ctrl) {
254 addr = (unsigned long)x.xfirmware_ctrl;
255 if (connect) {
256 x.xfirmware_ctrl = lseek(fd, 0, SEEK_CUR);
257 }
258 } else if (x.header.length >= 40 && x.firmware_ctrl) {
259 addr = (unsigned long)x.firmware_ctrl;
260 if (connect) {
261 x.firmware_ctrl = lseek(fd, 0, SEEK_CUR);
262 }
263 } else {
264 fprintf(stderr, "No FACS in FADT!\n");
265 goto no_facs;
266 }
267 tbl = acpi_map_table(addr, FACS_SIG);
268 if (!tbl) goto no_facs;
269 /* do not checksum FACS */
270 write_table(fd, tbl, addr);
271 acpi_unmap_table(tbl);
272no_facs:
273 write_table(fd, (struct acpi_table_header *)&x, xaddr);
274}
275
276static int acpi_dump_SDT(int fd, struct acpi_rsdp_descriptor *rsdp)
277{
278 struct acpi_table_header *sdt, *tbl = 0;
279 int xsdt = 1, i, num;
280 char *offset;
281 unsigned long addr;
282 if (rsdp->revision > 1 && rsdp->xsdt_physical_address) {
283 tbl = acpi_map_table(rsdp->xsdt_physical_address, "XSDT");
284 }
285 if (!tbl && rsdp->rsdt_physical_address) {
286 xsdt = 0;
287 tbl = acpi_map_table(rsdp->rsdt_physical_address, "RSDT");
288 }
289 if (!tbl) return 0;
290 sdt = malloc(tbl->length);
291 memcpy(sdt, tbl, tbl->length);
292 acpi_unmap_table(tbl);
293 if (checksum((u8 *)sdt, sdt->length))
294 fprintf(stderr, "Wrong checksum for %s!\n", (xsdt)?"XSDT":"RSDT");
295 num = (sdt->length - sizeof(struct acpi_table_header))/((xsdt)?sizeof(u64):sizeof(u32));
296 offset = (char *)sdt + sizeof(struct acpi_table_header);
297 for (i = 0; i < num; ++i, offset += ((xsdt) ? sizeof(u64) : sizeof(u32))) {
298 addr = (xsdt) ? (unsigned long)(*(u64 *)offset):
299 (unsigned long)(*(u32 *)offset);
300 if (!addr) continue;
301 tbl = acpi_map_table(addr, 0);
302 if (!tbl) continue;
303 if (!memcmp(tbl->signature, FADT_SIG, 4)) {
304 acpi_dump_FADT(fd, tbl, addr);
305 } else {
306 if (checksum((u8 *)tbl, tbl->length))
307 fprintf(stderr, "Wrong checksum for generic table!\n");
308 write_table(fd, tbl, addr);
309 }
310 acpi_unmap_table(tbl);
311 if (connect) {
312 if (xsdt)
313 (*(u64*)offset) = lseek(fd, 0, SEEK_CUR);
314 else
315 (*(u32*)offset) = lseek(fd, 0, SEEK_CUR);
316 }
317 }
318 if (xsdt) {
319 addr = (unsigned long)rsdp->xsdt_physical_address;
320 if (connect) {
321 rsdp->xsdt_physical_address = lseek(fd, 0, SEEK_CUR);
322 }
323 } else {
324 addr = (unsigned long)rsdp->rsdt_physical_address;
325 if (connect) {
326 rsdp->rsdt_physical_address = lseek(fd, 0, SEEK_CUR);
327 }
328 }
329 write_table(fd, sdt, addr);
330 free (sdt);
331 return 1;
332}
333
334#define DYNAMIC_SSDT "/sys/firmware/acpi/tables/dynamic"
335
336static void acpi_dump_dynamic_SSDT(int fd)
337{
338 struct stat file_stat;
339 char filename[256], *ptr;
340 DIR *tabledir;
341 struct dirent *entry;
342 FILE *fp;
343 int count, readcount, length;
344 struct acpi_table_header table_header, *ptable;
345
346 if (stat(DYNAMIC_SSDT, &file_stat) == -1) {
347 /* The directory doesn't exist */
348 return;
349 }
350 tabledir = opendir(DYNAMIC_SSDT);
351 if(!tabledir){
352 /*can't open the directory */
353 return;
354 }
355
356 while ((entry = readdir(tabledir)) != 0){
357 /* skip the file of . /.. */
358 if (entry->d_name[0] == '.')
359 continue;
360
361 sprintf(filename, "%s/%s", DYNAMIC_SSDT, entry->d_name);
362 fp = fopen(filename, "r");
363 if (fp == NULL) {
364 fprintf(stderr, "Can't open the file of %s\n",
365 filename);
366 continue;
367 }
368 /* Read the Table header to parse the table length */
369 count = fread(&table_header, 1, sizeof(struct acpi_table_header), fp);
370 if (count < sizeof(table_header)) {
371 /* the length is lessn than ACPI table header. skip it */
372 fclose(fp);
373 continue;
374 }
375 length = table_header.length;
376 ptr = malloc(table_header.length);
377 fseek(fp, 0, SEEK_SET);
378 readcount = 0;
379 while(!feof(fp) && readcount < length) {
380 count = fread(ptr + readcount, 1, 256, fp);
381 readcount += count;
382 }
383 fclose(fp);
384 ptable = (struct acpi_table_header *) ptr;
385 if (checksum((u8 *) ptable, ptable->length))
386 fprintf(stderr, "Wrong checksum "
387 "for dynamic SSDT table!\n");
388 write_table(fd, ptable, 0);
389 free(ptr);
390 }
391 closedir(tabledir);
392 return;
393}
394
395static void usage(const char *progname)
396{
397 puts("Usage:");
398 printf("%s [--addr 0x1234][--table DSDT][--output filename]"
399 "[--binary][--length 0x456][--help]\n", progname);
400 puts("\t--addr 0x1234 or -a 0x1234 -- look for tables at this physical address");
401 puts("\t--table DSDT or -t DSDT -- only dump table with DSDT signature");
402 puts("\t--output filename or -o filename -- redirect output from stdin to filename");
403 puts("\t--binary or -b -- dump data in binary form rather than in hex-dump format");
404 puts("\t--length 0x456 or -l 0x456 -- works only with --addr, dump physical memory"
405 "\n\t\tregion without trying to understand it's contents");
406 puts("\t--skip 2 or -s 2 -- skip 2 tables of the given name and output only 3rd one");
407 puts("\t--help or -h -- this help message");
408 exit(0);
409}
410
411static struct option long_options[] = {
412 {"addr", 1, 0, 0},
413 {"table", 1, 0, 0},
414 {"output", 1, 0, 0},
415 {"binary", 0, 0, 0},
416 {"length", 1, 0, 0},
417 {"skip", 1, 0, 0},
418 {"help", 0, 0, 0},
419 {0, 0, 0, 0}
420};
421int main(int argc, char **argv)
422{
423 int option_index, c, fd;
424 u8 *raw;
425 struct acpi_rsdp_descriptor rsdpx, *x = 0;
426 char *filename = 0;
427 char buff[80];
428 memset(select_sig, 0, 4);
429 print = 1;
430 connect = 0;
431 addr = length = 0;
432 skip = 0;
433 while (1) {
434 option_index = 0;
435 c = getopt_long(argc, argv, "a:t:o:bl:s:h",
436 long_options, &option_index);
437 if (c == -1)
438 break;
439
440 switch (c) {
441 case 0:
442 switch (option_index) {
443 case 0:
444 addr = strtoul(optarg, (char **)NULL, 16);
445 break;
446 case 1:
447 memcpy(select_sig, optarg, 4);
448 break;
449 case 2:
450 filename = optarg;
451 break;
452 case 3:
453 print = 0;
454 break;
455 case 4:
456 length = strtoul(optarg, (char **)NULL, 16);
457 break;
458 case 5:
459 skip = strtoul(optarg, (char **)NULL, 10);
460 break;
461 case 6:
462 usage(argv[0]);
463 exit(0);
464 }
465 break;
466 case 'a':
467 addr = strtoul(optarg, (char **)NULL, 16);
468 break;
469 case 't':
470 memcpy(select_sig, optarg, 4);
471 break;
472 case 'o':
473 filename = optarg;
474 break;
475 case 'b':
476 print = 0;
477 break;
478 case 'l':
479 length = strtoul(optarg, (char **)NULL, 16);
480 break;
481 case 's':
482 skip = strtoul(optarg, (char **)NULL, 10);
483 break;
484 case 'h':
485 usage(argv[0]);
486 exit(0);
487 default:
488 printf("Unknown option!\n");
489 usage(argv[0]);
490 exit(0);
491 }
492 }
493
494 fd = STDOUT_FILENO;
495 if (filename) {
496 fd = creat(filename, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
497 if (fd < 0)
498 return fd;
499 }
500
501 if (!select_sig[0] && !print) {
502 connect = 1;
503 }
504
505 psz = sysconf(_SC_PAGESIZE);
506 if (length && addr) {
507 /* We know length and address, it means we just want a memory dump */
508 if (!(raw = acpi_map_memory(addr, length)))
509 goto not_found;
510 write(fd, raw, length);
511 acpi_unmap_memory(raw, length);
512 close(fd);
513 return 0;
514 }
515
516 length = sizeof(struct acpi_rsdp_descriptor);
517 if (!addr) {
518 addr = read_efi_systab();
519 if (!addr) {
520 addr = ACPI_HI_RSDP_WINDOW_BASE;
521 length = ACPI_HI_RSDP_WINDOW_SIZE;
522 }
523 }
524
525 if (!(raw = acpi_map_memory(addr, length)) ||
526 !(x = acpi_scan_for_rsdp(raw, length)))
527 goto not_found;
528
529 /* Find RSDP and print all found tables */
530 memcpy(&rsdpx, x, sizeof(struct acpi_rsdp_descriptor));
531 acpi_unmap_memory(raw, length);
532 if (connect) {
533 lseek(fd, sizeof(struct acpi_rsdp_descriptor), SEEK_SET);
534 }
535 if (!acpi_dump_SDT(fd, &rsdpx))
536 goto not_found;
537 if (connect) {
538 lseek(fd, 0, SEEK_SET);
539 write(fd, x, (rsdpx.revision < 2) ?
540 ACPI_RSDP_CHECKSUM_LENGTH : ACPI_RSDP_XCHECKSUM_LENGTH);
541 } else if (!select_sig[0] || !memcmp("RSD PTR ", select_sig, 4)) {
542 addr += (long)x - (long)raw;
543 length = snprintf(buff, 80, "RSD PTR @ %p\n", (void *)addr);
544 write(fd, buff, length);
545 acpi_show_data(fd, (u8 *) & rsdpx, (rsdpx.revision < 2) ?
546 ACPI_RSDP_CHECKSUM_LENGTH : ACPI_RSDP_XCHECKSUM_LENGTH);
547 buff[0] = '\n';
548 write(fd, buff, 1);
549 }
550 acpi_dump_dynamic_SSDT(fd);
551 close(fd);
552 return 0;
553not_found:
554 close(fd);
555 fprintf(stderr, "ACPI tables were not found. If you know location "
556 "of RSD PTR table (from dmesg, etc), "
557 "supply it with either --addr or -a option\n");
558 return 1;
559}
diff --git a/tools/power/acpi/tools/acpidump/acpidump.h b/tools/power/acpi/tools/acpidump/acpidump.h
new file mode 100644
index 000000000000..46f519597fe5
--- /dev/null
+++ b/tools/power/acpi/tools/acpidump/acpidump.h
@@ -0,0 +1,130 @@
1/******************************************************************************
2 *
3 * Module Name: acpidump.h - Include file for acpi_dump utility
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2014, Intel Corp.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions, and the following disclaimer,
16 * without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 * substantially similar to the "NO WARRANTY" disclaimer below
19 * ("Disclaimer") and any redistribution must be conditioned upon
20 * including a substantially similar Disclaimer requirement for further
21 * binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 * of any contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
29 *
30 * NO WARRANTY
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
42 */
43
44/*
45 * Global variables. Defined in main.c only, externed in all other files
46 */
47#ifdef _DECLARE_GLOBALS
48#define EXTERN
49#define INIT_GLOBAL(a,b) a=b
50#define DEFINE_ACPI_GLOBALS 1
51#else
52#define EXTERN extern
53#define INIT_GLOBAL(a,b) a
54#endif
55
56#include <acpi/acpi.h>
57#include "accommon.h"
58#include "actables.h"
59
60#include <stdio.h>
61#include <fcntl.h>
62#include <errno.h>
63#include <sys/stat.h>
64
65/* Globals */
66
67EXTERN u8 INIT_GLOBAL(gbl_summary_mode, FALSE);
68EXTERN u8 INIT_GLOBAL(gbl_verbose_mode, FALSE);
69EXTERN u8 INIT_GLOBAL(gbl_binary_mode, FALSE);
70EXTERN u8 INIT_GLOBAL(gbl_dump_customized_tables, FALSE);
71EXTERN u8 INIT_GLOBAL(gbl_do_not_dump_xsdt, FALSE);
72EXTERN FILE INIT_GLOBAL(*gbl_output_file, NULL);
73EXTERN char INIT_GLOBAL(*gbl_output_filename, NULL);
74EXTERN u64 INIT_GLOBAL(gbl_rsdp_base, 0);
75
76/* Globals required for use with ACPICA modules */
77
78#ifdef _DECLARE_GLOBALS
79u8 acpi_gbl_integer_byte_width = 8;
80#endif
81
82/* Action table used to defer requested options */
83
84struct ap_dump_action {
85 char *argument;
86 u32 to_be_done;
87};
88
89#define AP_MAX_ACTIONS 32
90
91#define AP_DUMP_ALL_TABLES 0
92#define AP_DUMP_TABLE_BY_ADDRESS 1
93#define AP_DUMP_TABLE_BY_NAME 2
94#define AP_DUMP_TABLE_BY_FILE 3
95
96#define AP_MAX_ACPI_FILES 256 /* Prevent infinite loops */
97
98/* Minimum FADT sizes for various table addresses */
99
100#define MIN_FADT_FOR_DSDT (ACPI_FADT_OFFSET (dsdt) + sizeof (u32))
101#define MIN_FADT_FOR_FACS (ACPI_FADT_OFFSET (facs) + sizeof (u32))
102#define MIN_FADT_FOR_XDSDT (ACPI_FADT_OFFSET (Xdsdt) + sizeof (u64))
103#define MIN_FADT_FOR_XFACS (ACPI_FADT_OFFSET (Xfacs) + sizeof (u64))
104
105/*
106 * apdump - Table get/dump routines
107 */
108int ap_dump_table_from_file(char *pathname);
109
110int ap_dump_table_by_name(char *signature);
111
112int ap_dump_table_by_address(char *ascii_address);
113
114int ap_dump_all_tables(void);
115
116u8 ap_is_valid_header(struct acpi_table_header *table);
117
118u8 ap_is_valid_checksum(struct acpi_table_header *table);
119
120u32 ap_get_table_length(struct acpi_table_header *table);
121
122/*
123 * apfiles - File I/O utilities
124 */
125int ap_open_output_file(char *pathname);
126
127int ap_write_to_binary_file(struct acpi_table_header *table, u32 instance);
128
129struct acpi_table_header *ap_get_table_from_file(char *pathname,
130 u32 *file_size);
diff --git a/tools/power/acpi/tools/acpidump/apdump.c b/tools/power/acpi/tools/acpidump/apdump.c
new file mode 100644
index 000000000000..3cac12378366
--- /dev/null
+++ b/tools/power/acpi/tools/acpidump/apdump.c
@@ -0,0 +1,451 @@
1/******************************************************************************
2 *
3 * Module Name: apdump - Dump routines for ACPI tables (acpidump)
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2014, Intel Corp.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions, and the following disclaimer,
16 * without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 * substantially similar to the "NO WARRANTY" disclaimer below
19 * ("Disclaimer") and any redistribution must be conditioned upon
20 * including a substantially similar Disclaimer requirement for further
21 * binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 * of any contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
29 *
30 * NO WARRANTY
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
42 */
43
44#include "acpidump.h"
45
46/* Local prototypes */
47
48static int
49ap_dump_table_buffer(struct acpi_table_header *table,
50 u32 instance, acpi_physical_address address);
51
52/******************************************************************************
53 *
54 * FUNCTION: ap_is_valid_header
55 *
56 * PARAMETERS: table - Pointer to table to be validated
57 *
58 * RETURN: TRUE if the header appears to be valid. FALSE otherwise
59 *
60 * DESCRIPTION: Check for a valid ACPI table header
61 *
62 ******************************************************************************/
63
64u8 ap_is_valid_header(struct acpi_table_header *table)
65{
66
67 if (!ACPI_VALIDATE_RSDP_SIG(table->signature)) {
68
69 /* Make sure signature is all ASCII and a valid ACPI name */
70
71 if (!acpi_ut_valid_acpi_name(table->signature)) {
72 fprintf(stderr,
73 "Table signature (0x%8.8X) is invalid\n",
74 *(u32 *)table->signature);
75 return (FALSE);
76 }
77
78 /* Check for minimum table length */
79
80 if (table->length < sizeof(struct acpi_table_header)) {
81 fprintf(stderr, "Table length (0x%8.8X) is invalid\n",
82 table->length);
83 return (FALSE);
84 }
85 }
86
87 return (TRUE);
88}
89
90/******************************************************************************
91 *
92 * FUNCTION: ap_is_valid_checksum
93 *
94 * PARAMETERS: table - Pointer to table to be validated
95 *
96 * RETURN: TRUE if the checksum appears to be valid. FALSE otherwise.
97 *
98 * DESCRIPTION: Check for a valid ACPI table checksum.
99 *
100 ******************************************************************************/
101
102u8 ap_is_valid_checksum(struct acpi_table_header *table)
103{
104 acpi_status status;
105 struct acpi_table_rsdp *rsdp;
106
107 if (ACPI_VALIDATE_RSDP_SIG(table->signature)) {
108 /*
109 * Checksum for RSDP.
110 * Note: Other checksums are computed during the table dump.
111 */
112 rsdp = ACPI_CAST_PTR(struct acpi_table_rsdp, table);
113 status = acpi_tb_validate_rsdp(rsdp);
114 } else {
115 status = acpi_tb_verify_checksum(table, table->length);
116 }
117
118 if (ACPI_FAILURE(status)) {
119 fprintf(stderr, "%4.4s: Warning: wrong checksum in table\n",
120 table->signature);
121 }
122
123 return (AE_OK);
124}
125
126/******************************************************************************
127 *
128 * FUNCTION: ap_get_table_length
129 *
130 * PARAMETERS: table - Pointer to the table
131 *
132 * RETURN: Table length
133 *
134 * DESCRIPTION: Obtain table length according to table signature.
135 *
136 ******************************************************************************/
137
138u32 ap_get_table_length(struct acpi_table_header *table)
139{
140 struct acpi_table_rsdp *rsdp;
141
142 /* Check if table is valid */
143
144 if (!ap_is_valid_header(table)) {
145 return (0);
146 }
147
148 if (ACPI_VALIDATE_RSDP_SIG(table->signature)) {
149 rsdp = ACPI_CAST_PTR(struct acpi_table_rsdp, table);
150 return (rsdp->length);
151 }
152
153 /* Normal ACPI table */
154
155 return (table->length);
156}
157
158/******************************************************************************
159 *
160 * FUNCTION: ap_dump_table_buffer
161 *
162 * PARAMETERS: table - ACPI table to be dumped
163 * instance - ACPI table instance no. to be dumped
164 * address - Physical address of the table
165 *
166 * RETURN: None
167 *
168 * DESCRIPTION: Dump an ACPI table in standard ASCII hex format, with a
169 * header that is compatible with the acpi_xtract utility.
170 *
171 ******************************************************************************/
172
173static int
174ap_dump_table_buffer(struct acpi_table_header *table,
175 u32 instance, acpi_physical_address address)
176{
177 u32 table_length;
178
179 table_length = ap_get_table_length(table);
180
181 /* Print only the header if requested */
182
183 if (gbl_summary_mode) {
184 acpi_tb_print_table_header(address, table);
185 return (0);
186 }
187
188 /* Dump to binary file if requested */
189
190 if (gbl_binary_mode) {
191 return (ap_write_to_binary_file(table, instance));
192 }
193
194 /*
195 * Dump the table with header for use with acpixtract utility.
196 * Note: simplest to just always emit a 64-bit address. acpi_xtract
197 * utility can handle this.
198 */
199 printf("%4.4s @ 0x%8.8X%8.8X\n", table->signature,
200 ACPI_FORMAT_UINT64(address));
201
202 acpi_ut_dump_buffer(ACPI_CAST_PTR(u8, table), table_length,
203 DB_BYTE_DISPLAY, 0);
204 printf("\n");
205 return (0);
206}
207
208/******************************************************************************
209 *
210 * FUNCTION: ap_dump_all_tables
211 *
212 * PARAMETERS: None
213 *
214 * RETURN: Status
215 *
216 * DESCRIPTION: Get all tables from the RSDT/XSDT (or at least all of the
217 * tables that we can possibly get).
218 *
219 ******************************************************************************/
220
221int ap_dump_all_tables(void)
222{
223 struct acpi_table_header *table;
224 u32 instance = 0;
225 acpi_physical_address address;
226 acpi_status status;
227 int table_status;
228 u32 i;
229
230 /* Get and dump all available ACPI tables */
231
232 for (i = 0; i < AP_MAX_ACPI_FILES; i++) {
233 status =
234 acpi_os_get_table_by_index(i, &table, &instance, &address);
235 if (ACPI_FAILURE(status)) {
236
237 /* AE_LIMIT means that no more tables are available */
238
239 if (status == AE_LIMIT) {
240 return (0);
241 } else if (i == 0) {
242 fprintf(stderr,
243 "Could not get ACPI tables, %s\n",
244 acpi_format_exception(status));
245 return (-1);
246 } else {
247 fprintf(stderr,
248 "Could not get ACPI table at index %u, %s\n",
249 i, acpi_format_exception(status));
250 continue;
251 }
252 }
253
254 table_status = ap_dump_table_buffer(table, instance, address);
255 free(table);
256
257 if (table_status) {
258 break;
259 }
260 }
261
262 /* Something seriously bad happened if the loop terminates here */
263
264 return (-1);
265}
266
267/******************************************************************************
268 *
269 * FUNCTION: ap_dump_table_by_address
270 *
271 * PARAMETERS: ascii_address - Address for requested ACPI table
272 *
273 * RETURN: Status
274 *
275 * DESCRIPTION: Get an ACPI table via a physical address and dump it.
276 *
277 ******************************************************************************/
278
279int ap_dump_table_by_address(char *ascii_address)
280{
281 acpi_physical_address address;
282 struct acpi_table_header *table;
283 acpi_status status;
284 int table_status;
285 u64 long_address;
286
287 /* Convert argument to an integer physical address */
288
289 status = acpi_ut_strtoul64(ascii_address, 0, &long_address);
290 if (ACPI_FAILURE(status)) {
291 fprintf(stderr, "%s: Could not convert to a physical address\n",
292 ascii_address);
293 return (-1);
294 }
295
296 address = (acpi_physical_address) long_address;
297 status = acpi_os_get_table_by_address(address, &table);
298 if (ACPI_FAILURE(status)) {
299 fprintf(stderr, "Could not get table at 0x%8.8X%8.8X, %s\n",
300 ACPI_FORMAT_UINT64(address),
301 acpi_format_exception(status));
302 return (-1);
303 }
304
305 table_status = ap_dump_table_buffer(table, 0, address);
306 free(table);
307 return (table_status);
308}
309
310/******************************************************************************
311 *
312 * FUNCTION: ap_dump_table_by_name
313 *
314 * PARAMETERS: signature - Requested ACPI table signature
315 *
316 * RETURN: Status
317 *
318 * DESCRIPTION: Get an ACPI table via a signature and dump it. Handles
319 * multiple tables with the same signature (SSDTs).
320 *
321 ******************************************************************************/
322
323int ap_dump_table_by_name(char *signature)
324{
325 char local_signature[ACPI_NAME_SIZE + 1];
326 u32 instance;
327 struct acpi_table_header *table;
328 acpi_physical_address address;
329 acpi_status status;
330 int table_status;
331
332 if (strlen(signature) != ACPI_NAME_SIZE) {
333 fprintf(stderr,
334 "Invalid table signature [%s]: must be exactly 4 characters\n",
335 signature);
336 return (-1);
337 }
338
339 /* Table signatures are expected to be uppercase */
340
341 strcpy(local_signature, signature);
342 acpi_ut_strupr(local_signature);
343
344 /* To be friendly, handle tables whose signatures do not match the name */
345
346 if (ACPI_COMPARE_NAME(local_signature, "FADT")) {
347 strcpy(local_signature, ACPI_SIG_FADT);
348 } else if (ACPI_COMPARE_NAME(local_signature, "MADT")) {
349 strcpy(local_signature, ACPI_SIG_MADT);
350 }
351
352 /* Dump all instances of this signature (to handle multiple SSDTs) */
353
354 for (instance = 0; instance < AP_MAX_ACPI_FILES; instance++) {
355 status = acpi_os_get_table_by_name(local_signature, instance,
356 &table, &address);
357 if (ACPI_FAILURE(status)) {
358
359 /* AE_LIMIT means that no more tables are available */
360
361 if (status == AE_LIMIT) {
362 return (0);
363 }
364
365 fprintf(stderr,
366 "Could not get ACPI table with signature [%s], %s\n",
367 local_signature, acpi_format_exception(status));
368 return (-1);
369 }
370
371 table_status = ap_dump_table_buffer(table, instance, address);
372 free(table);
373
374 if (table_status) {
375 break;
376 }
377 }
378
379 /* Something seriously bad happened if the loop terminates here */
380
381 return (-1);
382}
383
384/******************************************************************************
385 *
386 * FUNCTION: ap_dump_table_from_file
387 *
388 * PARAMETERS: pathname - File containing the binary ACPI table
389 *
390 * RETURN: Status
391 *
392 * DESCRIPTION: Dump an ACPI table from a binary file
393 *
394 ******************************************************************************/
395
396int ap_dump_table_from_file(char *pathname)
397{
398 struct acpi_table_header *table;
399 u32 file_size = 0;
400 int table_status = -1;
401
402 /* Get the entire ACPI table from the file */
403
404 table = ap_get_table_from_file(pathname, &file_size);
405 if (!table) {
406 return (-1);
407 }
408
409 /* File must be at least as long as the table length */
410
411 if (table->length > file_size) {
412 fprintf(stderr,
413 "Table length (0x%X) is too large for input file (0x%X) %s\n",
414 table->length, file_size, pathname);
415 goto exit;
416 }
417
418 if (gbl_verbose_mode) {
419 fprintf(stderr,
420 "Input file: %s contains table [%4.4s], 0x%X (%u) bytes\n",
421 pathname, table->signature, file_size, file_size);
422 }
423
424 table_status = ap_dump_table_buffer(table, 0, 0);
425
426exit:
427 free(table);
428 return (table_status);
429}
430
431/******************************************************************************
432 *
433 * FUNCTION: acpi_os* print functions
434 *
435 * DESCRIPTION: Used for linkage with ACPICA modules
436 *
437 ******************************************************************************/
438
439void ACPI_INTERNAL_VAR_XFACE acpi_os_printf(const char *fmt, ...)
440{
441 va_list args;
442
443 va_start(args, fmt);
444 vfprintf(stdout, fmt, args);
445 va_end(args);
446}
447
448void acpi_os_vprintf(const char *fmt, va_list args)
449{
450 vfprintf(stdout, fmt, args);
451}
diff --git a/tools/power/acpi/tools/acpidump/apfiles.c b/tools/power/acpi/tools/acpidump/apfiles.c
new file mode 100644
index 000000000000..4488accc010b
--- /dev/null
+++ b/tools/power/acpi/tools/acpidump/apfiles.c
@@ -0,0 +1,228 @@
1/******************************************************************************
2 *
3 * Module Name: apfiles - File-related functions for acpidump utility
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2014, Intel Corp.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions, and the following disclaimer,
16 * without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 * substantially similar to the "NO WARRANTY" disclaimer below
19 * ("Disclaimer") and any redistribution must be conditioned upon
20 * including a substantially similar Disclaimer requirement for further
21 * binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 * of any contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
29 *
30 * NO WARRANTY
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
42 */
43
44#include "acpidump.h"
45#include "acapps.h"
46
47/******************************************************************************
48 *
49 * FUNCTION: ap_open_output_file
50 *
51 * PARAMETERS: pathname - Output filename
52 *
53 * RETURN: Open file handle
54 *
55 * DESCRIPTION: Open a text output file for acpidump. Checks if file already
56 * exists.
57 *
58 ******************************************************************************/
59
60int ap_open_output_file(char *pathname)
61{
62 struct stat stat_info;
63 FILE *file;
64
65 /* If file exists, prompt for overwrite */
66
67 if (!stat(pathname, &stat_info)) {
68 fprintf(stderr,
69 "Target path already exists, overwrite? [y|n] ");
70
71 if (getchar() != 'y') {
72 return (-1);
73 }
74 }
75
76 /* Point stdout to the file */
77
78 file = freopen(pathname, "w", stdout);
79 if (!file) {
80 perror("Could not open output file");
81 return (-1);
82 }
83
84 /* Save the file and path */
85
86 gbl_output_file = file;
87 gbl_output_filename = pathname;
88 return (0);
89}
90
91/******************************************************************************
92 *
93 * FUNCTION: ap_write_to_binary_file
94 *
95 * PARAMETERS: table - ACPI table to be written
96 * instance - ACPI table instance no. to be written
97 *
98 * RETURN: Status
99 *
100 * DESCRIPTION: Write an ACPI table to a binary file. Builds the output
101 * filename from the table signature.
102 *
103 ******************************************************************************/
104
105int ap_write_to_binary_file(struct acpi_table_header *table, u32 instance)
106{
107 char filename[ACPI_NAME_SIZE + 16];
108 char instance_str[16];
109 FILE *file;
110 size_t actual;
111 u32 table_length;
112
113 /* Obtain table length */
114
115 table_length = ap_get_table_length(table);
116
117 /* Construct lower-case filename from the table local signature */
118
119 if (ACPI_VALIDATE_RSDP_SIG(table->signature)) {
120 ACPI_MOVE_NAME(filename, ACPI_RSDP_NAME);
121 } else {
122 ACPI_MOVE_NAME(filename, table->signature);
123 }
124 filename[0] = (char)ACPI_TOLOWER(filename[0]);
125 filename[1] = (char)ACPI_TOLOWER(filename[1]);
126 filename[2] = (char)ACPI_TOLOWER(filename[2]);
127 filename[3] = (char)ACPI_TOLOWER(filename[3]);
128 filename[ACPI_NAME_SIZE] = 0;
129
130 /* Handle multiple SSDts - create different filenames for each */
131
132 if (instance > 0) {
133 sprintf(instance_str, "%u", instance);
134 strcat(filename, instance_str);
135 }
136
137 strcat(filename, ACPI_TABLE_FILE_SUFFIX);
138
139 if (gbl_verbose_mode) {
140 fprintf(stderr,
141 "Writing [%4.4s] to binary file: %s 0x%X (%u) bytes\n",
142 table->signature, filename, table->length,
143 table->length);
144 }
145
146 /* Open the file and dump the entire table in binary mode */
147
148 file = fopen(filename, "wb");
149 if (!file) {
150 perror("Could not open output file");
151 return (-1);
152 }
153
154 actual = fwrite(table, 1, table_length, file);
155 if (actual != table_length) {
156 perror("Error writing binary output file");
157 fclose(file);
158 return (-1);
159 }
160
161 fclose(file);
162 return (0);
163}
164
165/******************************************************************************
166 *
167 * FUNCTION: ap_get_table_from_file
168 *
169 * PARAMETERS: pathname - File containing the binary ACPI table
170 * out_file_size - Where the file size is returned
171 *
172 * RETURN: Buffer containing the ACPI table. NULL on error.
173 *
174 * DESCRIPTION: Open a file and read it entirely into a new buffer
175 *
176 ******************************************************************************/
177
178struct acpi_table_header *ap_get_table_from_file(char *pathname,
179 u32 *out_file_size)
180{
181 struct acpi_table_header *buffer = NULL;
182 FILE *file;
183 u32 file_size;
184 size_t actual;
185
186 /* Must use binary mode */
187
188 file = fopen(pathname, "rb");
189 if (!file) {
190 perror("Could not open input file");
191 return (NULL);
192 }
193
194 /* Need file size to allocate a buffer */
195
196 file_size = cm_get_file_size(file);
197 if (file_size == ACPI_UINT32_MAX) {
198 fprintf(stderr,
199 "Could not get input file size: %s\n", pathname);
200 goto cleanup;
201 }
202
203 /* Allocate a buffer for the entire file */
204
205 buffer = calloc(1, file_size);
206 if (!buffer) {
207 fprintf(stderr,
208 "Could not allocate file buffer of size: %u\n",
209 file_size);
210 goto cleanup;
211 }
212
213 /* Read the entire file */
214
215 actual = fread(buffer, 1, file_size, file);
216 if (actual != file_size) {
217 fprintf(stderr, "Could not read input file: %s\n", pathname);
218 free(buffer);
219 buffer = NULL;
220 goto cleanup;
221 }
222
223 *out_file_size = file_size;
224
225cleanup:
226 fclose(file);
227 return (buffer);
228}
diff --git a/tools/power/acpi/tools/acpidump/apmain.c b/tools/power/acpi/tools/acpidump/apmain.c
new file mode 100644
index 000000000000..51e8d638db18
--- /dev/null
+++ b/tools/power/acpi/tools/acpidump/apmain.c
@@ -0,0 +1,351 @@
1/******************************************************************************
2 *
3 * Module Name: apmain - Main module for the acpidump utility
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2014, Intel Corp.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions, and the following disclaimer,
16 * without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 * substantially similar to the "NO WARRANTY" disclaimer below
19 * ("Disclaimer") and any redistribution must be conditioned upon
20 * including a substantially similar Disclaimer requirement for further
21 * binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 * of any contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
29 *
30 * NO WARRANTY
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
42 */
43
44#define _DECLARE_GLOBALS
45#include "acpidump.h"
46#include "acapps.h"
47
48/*
49 * acpidump - A portable utility for obtaining system ACPI tables and dumping
50 * them in an ASCII hex format suitable for binary extraction via acpixtract.
51 *
52 * Obtaining the system ACPI tables is an OS-specific operation.
53 *
54 * This utility can be ported to any host operating system by providing a
55 * module containing system-specific versions of these interfaces:
56 *
57 * acpi_os_get_table_by_address
58 * acpi_os_get_table_by_index
59 * acpi_os_get_table_by_name
60 *
61 * See the ACPICA Reference Guide for the exact definitions of these
62 * interfaces. Also, see these ACPICA source code modules for example
63 * implementations:
64 *
65 * source/os_specific/service_layers/oswintbl.c
66 * source/os_specific/service_layers/oslinuxtbl.c
67 */
68
69/* Local prototypes */
70
71static void ap_display_usage(void);
72
73static int ap_do_options(int argc, char **argv);
74
75static void ap_insert_action(char *argument, u32 to_be_done);
76
77/* Table for deferred actions from command line options */
78
79struct ap_dump_action action_table[AP_MAX_ACTIONS];
80u32 current_action = 0;
81
82#define AP_UTILITY_NAME "ACPI Binary Table Dump Utility"
83#define AP_SUPPORTED_OPTIONS "?a:bcf:hn:o:r:svxz"
84
85/******************************************************************************
86 *
87 * FUNCTION: ap_display_usage
88 *
89 * DESCRIPTION: Usage message for the acpi_dump utility
90 *
91 ******************************************************************************/
92
93static void ap_display_usage(void)
94{
95
96 ACPI_USAGE_HEADER("acpidump [options]");
97
98 ACPI_OPTION("-b", "Dump tables to binary files");
99 ACPI_OPTION("-c", "Dump customized tables");
100 ACPI_OPTION("-h -?", "This help message");
101 ACPI_OPTION("-o <File>", "Redirect output to file");
102 ACPI_OPTION("-r <Address>", "Dump tables from specified RSDP");
103 ACPI_OPTION("-s", "Print table summaries only");
104 ACPI_OPTION("-v", "Display version information");
105 ACPI_OPTION("-z", "Verbose mode");
106
107 printf("\nTable Options:\n");
108
109 ACPI_OPTION("-a <Address>", "Get table via a physical address");
110 ACPI_OPTION("-f <BinaryFile>", "Get table via a binary file");
111 ACPI_OPTION("-n <Signature>", "Get table via a name/signature");
112 ACPI_OPTION("-x", "Do not use but dump XSDT");
113 ACPI_OPTION("-x -x", "Do not use or dump XSDT");
114
115 printf("\n"
116 "Invocation without parameters dumps all available tables\n"
117 "Multiple mixed instances of -a, -f, and -n are supported\n\n");
118}
119
120/******************************************************************************
121 *
122 * FUNCTION: ap_insert_action
123 *
124 * PARAMETERS: argument - Pointer to the argument for this action
125 * to_be_done - What to do to process this action
126 *
127 * RETURN: None. Exits program if action table becomes full.
128 *
129 * DESCRIPTION: Add an action item to the action table
130 *
131 ******************************************************************************/
132
133static void ap_insert_action(char *argument, u32 to_be_done)
134{
135
136 /* Insert action and check for table overflow */
137
138 action_table[current_action].argument = argument;
139 action_table[current_action].to_be_done = to_be_done;
140
141 current_action++;
142 if (current_action > AP_MAX_ACTIONS) {
143 fprintf(stderr, "Too many table options (max %u)\n",
144 AP_MAX_ACTIONS);
145 exit(-1);
146 }
147}
148
149/******************************************************************************
150 *
151 * FUNCTION: ap_do_options
152 *
153 * PARAMETERS: argc/argv - Standard argc/argv
154 *
155 * RETURN: Status
156 *
157 * DESCRIPTION: Command line option processing. The main actions for getting
158 * and dumping tables are deferred via the action table.
159 *
160 *****************************************************************************/
161
162static int ap_do_options(int argc, char **argv)
163{
164 int j;
165 acpi_status status;
166
167 /* Command line options */
168
169 while ((j = acpi_getopt(argc, argv, AP_SUPPORTED_OPTIONS)) != EOF)
170 switch (j) {
171 /*
172 * Global options
173 */
174 case 'b': /* Dump all input tables to binary files */
175
176 gbl_binary_mode = TRUE;
177 continue;
178
179 case 'c': /* Dump customized tables */
180
181 gbl_dump_customized_tables = TRUE;
182 continue;
183
184 case 'h':
185 case '?':
186
187 ap_display_usage();
188 exit(0);
189
190 case 'o': /* Redirect output to a single file */
191
192 if (ap_open_output_file(acpi_gbl_optarg)) {
193 exit(-1);
194 }
195 continue;
196
197 case 'r': /* Dump tables from specified RSDP */
198
199 status =
200 acpi_ut_strtoul64(acpi_gbl_optarg, 0,
201 &gbl_rsdp_base);
202 if (ACPI_FAILURE(status)) {
203 fprintf(stderr,
204 "%s: Could not convert to a physical address\n",
205 acpi_gbl_optarg);
206 exit(-1);
207 }
208 continue;
209
210 case 's': /* Print table summaries only */
211
212 gbl_summary_mode = TRUE;
213 continue;
214
215 case 'x': /* Do not use XSDT */
216
217 if (!acpi_gbl_do_not_use_xsdt) {
218 acpi_gbl_do_not_use_xsdt = TRUE;
219 } else {
220 gbl_do_not_dump_xsdt = TRUE;
221 }
222 continue;
223
224 case 'v': /* Revision/version */
225
226 printf(ACPI_COMMON_SIGNON(AP_UTILITY_NAME));
227 exit(0);
228
229 case 'z': /* Verbose mode */
230
231 gbl_verbose_mode = TRUE;
232 fprintf(stderr, ACPI_COMMON_SIGNON(AP_UTILITY_NAME));
233 continue;
234
235 /*
236 * Table options
237 */
238 case 'a': /* Get table by physical address */
239
240 ap_insert_action(acpi_gbl_optarg,
241 AP_DUMP_TABLE_BY_ADDRESS);
242 break;
243
244 case 'f': /* Get table from a file */
245
246 ap_insert_action(acpi_gbl_optarg,
247 AP_DUMP_TABLE_BY_FILE);
248 break;
249
250 case 'n': /* Get table by input name (signature) */
251
252 ap_insert_action(acpi_gbl_optarg,
253 AP_DUMP_TABLE_BY_NAME);
254 break;
255
256 default:
257
258 ap_display_usage();
259 exit(-1);
260 }
261
262 /* If there are no actions, this means "get/dump all tables" */
263
264 if (current_action == 0) {
265 ap_insert_action(NULL, AP_DUMP_ALL_TABLES);
266 }
267
268 return (0);
269}
270
271/******************************************************************************
272 *
273 * FUNCTION: main
274 *
275 * PARAMETERS: argc/argv - Standard argc/argv
276 *
277 * RETURN: Status
278 *
279 * DESCRIPTION: C main function for acpidump utility
280 *
281 ******************************************************************************/
282
283int ACPI_SYSTEM_XFACE main(int argc, char *argv[])
284{
285 int status = 0;
286 struct ap_dump_action *action;
287 u32 file_size;
288 u32 i;
289
290 ACPI_DEBUG_INITIALIZE(); /* For debug version only */
291
292 /* Process command line options */
293
294 if (ap_do_options(argc, argv)) {
295 return (-1);
296 }
297
298 /* Get/dump ACPI table(s) as requested */
299
300 for (i = 0; i < current_action; i++) {
301 action = &action_table[i];
302 switch (action->to_be_done) {
303 case AP_DUMP_ALL_TABLES:
304
305 status = ap_dump_all_tables();
306 break;
307
308 case AP_DUMP_TABLE_BY_ADDRESS:
309
310 status = ap_dump_table_by_address(action->argument);
311 break;
312
313 case AP_DUMP_TABLE_BY_NAME:
314
315 status = ap_dump_table_by_name(action->argument);
316 break;
317
318 case AP_DUMP_TABLE_BY_FILE:
319
320 status = ap_dump_table_from_file(action->argument);
321 break;
322
323 default:
324
325 fprintf(stderr,
326 "Internal error, invalid action: 0x%X\n",
327 action->to_be_done);
328 return (-1);
329 }
330
331 if (status) {
332 return (status);
333 }
334 }
335
336 if (gbl_output_file) {
337 if (gbl_verbose_mode) {
338
339 /* Summary for the output file */
340
341 file_size = cm_get_file_size(gbl_output_file);
342 fprintf(stderr,
343 "Output file %s contains 0x%X (%u) bytes\n\n",
344 gbl_output_filename, file_size, file_size);
345 }
346
347 fclose(gbl_output_file);
348 }
349
350 return (status);
351}
diff --git a/tools/power/acpi/tools/ec/Makefile b/tools/power/acpi/tools/ec/Makefile
new file mode 100644
index 000000000000..b7b0b929bd32
--- /dev/null
+++ b/tools/power/acpi/tools/ec/Makefile
@@ -0,0 +1,22 @@
1ec_access: ec_access.o
2 $(ECHO) " LD " $@
3 $(QUIET) $(LD) $(CFLAGS) $(LDFLAGS) $< -o $@
4 $(QUIET) $(STRIPCMD) $@
5
6%.o: %.c
7 $(ECHO) " CC " $@
8 $(QUIET) $(CC) -c $(CFLAGS) -o $@ $<
9
10all: ec_access
11
12install:
13 $(INSTALL) -d $(DESTDIR)${sbindir}
14 $(INSTALL_PROGRAM) ec_access $(DESTDIR)${sbindir}
15
16uninstall:
17 - rm -f $(DESTDIR)${sbindir}/ec_access
18
19clean:
20 -rm -f $(OUTPUT)ec_access
21
22.PHONY: all install uninstall
diff --git a/tools/power/acpi/tools/ec/ec_access.c b/tools/power/acpi/tools/ec/ec_access.c
new file mode 100644
index 000000000000..6b8aaed44f2c
--- /dev/null
+++ b/tools/power/acpi/tools/ec/ec_access.c
@@ -0,0 +1,238 @@
1/*
2 * ec_access.c
3 *
4 * Copyright (C) 2010 SUSE Linux Products GmbH
5 * Author:
6 * Thomas Renninger <trenn@suse.de>
7 *
8 * This work is licensed under the terms of the GNU GPL, version 2.
9 */
10
11#include <fcntl.h>
12#include <err.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <libgen.h>
16#include <unistd.h>
17#include <getopt.h>
18#include <stdint.h>
19#include <sys/types.h>
20#include <sys/stat.h>
21
22
23#define EC_SPACE_SIZE 256
24#define SYSFS_PATH "/sys/kernel/debug/ec/ec0/io"
25
26/* TBD/Enhancements:
27 - Provide param for accessing different ECs (not supported by kernel yet)
28*/
29
30static int read_mode = -1;
31static int sleep_time;
32static int write_byte_offset = -1;
33static int read_byte_offset = -1;
34static uint8_t write_value = -1;
35
36void usage(char progname[], int exit_status)
37{
38 printf("Usage:\n");
39 printf("1) %s -r [-s sleep]\n", basename(progname));
40 printf("2) %s -b byte_offset\n", basename(progname));
41 printf("3) %s -w byte_offset -v value\n\n", basename(progname));
42
43 puts("\t-r [-s sleep] : Dump EC registers");
44 puts("\t If sleep is given, sleep x seconds,");
45 puts("\t re-read EC registers and show changes");
46 puts("\t-b offset : Read value at byte_offset (in hex)");
47 puts("\t-w offset -v value : Write value at byte_offset");
48 puts("\t-h : Print this help\n\n");
49 puts("Offsets and values are in hexadecimal number sytem.");
50 puts("The offset and value must be between 0 and 0xff.");
51 exit(exit_status);
52}
53
54void parse_opts(int argc, char *argv[])
55{
56 int c;
57
58 while ((c = getopt(argc, argv, "rs:b:w:v:h")) != -1) {
59
60 switch (c) {
61 case 'r':
62 if (read_mode != -1)
63 usage(argv[0], EXIT_FAILURE);
64 read_mode = 1;
65 break;
66 case 's':
67 if (read_mode != -1 && read_mode != 1)
68 usage(argv[0], EXIT_FAILURE);
69
70 sleep_time = atoi(optarg);
71 if (sleep_time <= 0) {
72 sleep_time = 0;
73 usage(argv[0], EXIT_FAILURE);
74 printf("Bad sleep time: %s\n", optarg);
75 }
76 break;
77 case 'b':
78 if (read_mode != -1)
79 usage(argv[0], EXIT_FAILURE);
80 read_mode = 1;
81 read_byte_offset = strtoul(optarg, NULL, 16);
82 break;
83 case 'w':
84 if (read_mode != -1)
85 usage(argv[0], EXIT_FAILURE);
86 read_mode = 0;
87 write_byte_offset = strtoul(optarg, NULL, 16);
88 break;
89 case 'v':
90 write_value = strtoul(optarg, NULL, 16);
91 break;
92 case 'h':
93 usage(argv[0], EXIT_SUCCESS);
94 default:
95 fprintf(stderr, "Unknown option!\n");
96 usage(argv[0], EXIT_FAILURE);
97 }
98 }
99 if (read_mode == 0) {
100 if (write_byte_offset < 0 ||
101 write_byte_offset >= EC_SPACE_SIZE) {
102 fprintf(stderr, "Wrong byte offset 0x%.2x, valid: "
103 "[0-0x%.2x]\n",
104 write_byte_offset, EC_SPACE_SIZE - 1);
105 usage(argv[0], EXIT_FAILURE);
106 }
107 if (write_value < 0 ||
108 write_value >= 255) {
109 fprintf(stderr, "Wrong byte offset 0x%.2x, valid:"
110 "[0-0xff]\n", write_byte_offset);
111 usage(argv[0], EXIT_FAILURE);
112 }
113 }
114 if (read_mode == 1 && read_byte_offset != -1) {
115 if (read_byte_offset < -1 ||
116 read_byte_offset >= EC_SPACE_SIZE) {
117 fprintf(stderr, "Wrong byte offset 0x%.2x, valid: "
118 "[0-0x%.2x]\n",
119 read_byte_offset, EC_SPACE_SIZE - 1);
120 usage(argv[0], EXIT_FAILURE);
121 }
122 }
123 /* Add additional parameter checks here */
124}
125
126void dump_ec(int fd)
127{
128 char buf[EC_SPACE_SIZE];
129 char buf2[EC_SPACE_SIZE];
130 int byte_off, bytes_read;
131
132 bytes_read = read(fd, buf, EC_SPACE_SIZE);
133
134 if (bytes_read == -1)
135 err(EXIT_FAILURE, "Could not read from %s\n", SYSFS_PATH);
136
137 if (bytes_read != EC_SPACE_SIZE)
138 fprintf(stderr, "Could only read %d bytes\n", bytes_read);
139
140 printf(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
141 for (byte_off = 0; byte_off < bytes_read; byte_off++) {
142 if ((byte_off % 16) == 0)
143 printf("\n%.2X: ", byte_off);
144 printf(" %.2x ", (uint8_t)buf[byte_off]);
145 }
146 printf("\n");
147
148 if (!sleep_time)
149 return;
150
151 printf("\n");
152 lseek(fd, 0, SEEK_SET);
153 sleep(sleep_time);
154
155 bytes_read = read(fd, buf2, EC_SPACE_SIZE);
156
157 if (bytes_read == -1)
158 err(EXIT_FAILURE, "Could not read from %s\n", SYSFS_PATH);
159
160 if (bytes_read != EC_SPACE_SIZE)
161 fprintf(stderr, "Could only read %d bytes\n", bytes_read);
162
163 printf(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
164 for (byte_off = 0; byte_off < bytes_read; byte_off++) {
165 if ((byte_off % 16) == 0)
166 printf("\n%.2X: ", byte_off);
167
168 if (buf[byte_off] == buf2[byte_off])
169 printf(" %.2x ", (uint8_t)buf2[byte_off]);
170 else
171 printf("*%.2x ", (uint8_t)buf2[byte_off]);
172 }
173 printf("\n");
174}
175
176void read_ec_val(int fd, int byte_offset)
177{
178 uint8_t buf;
179 int error;
180
181 error = lseek(fd, byte_offset, SEEK_SET);
182 if (error != byte_offset)
183 err(EXIT_FAILURE, "Cannot set offset to 0x%.2x", byte_offset);
184
185 error = read(fd, &buf, 1);
186 if (error != 1)
187 err(EXIT_FAILURE, "Could not read byte 0x%.2x from %s\n",
188 byte_offset, SYSFS_PATH);
189 printf("0x%.2x\n", buf);
190 return;
191}
192
193void write_ec_val(int fd, int byte_offset, uint8_t value)
194{
195 int error;
196
197 error = lseek(fd, byte_offset, SEEK_SET);
198 if (error != byte_offset)
199 err(EXIT_FAILURE, "Cannot set offset to 0x%.2x", byte_offset);
200
201 error = write(fd, &value, 1);
202 if (error != 1)
203 err(EXIT_FAILURE, "Cannot write value 0x%.2x to offset 0x%.2x",
204 value, byte_offset);
205}
206
207int main(int argc, char *argv[])
208{
209 int file_mode = O_RDONLY;
210 int fd;
211
212 parse_opts(argc, argv);
213
214 if (read_mode == 0)
215 file_mode = O_WRONLY;
216 else if (read_mode == 1)
217 file_mode = O_RDONLY;
218 else
219 usage(argv[0], EXIT_FAILURE);
220
221 fd = open(SYSFS_PATH, file_mode);
222 if (fd == -1)
223 err(EXIT_FAILURE, "%s", SYSFS_PATH);
224
225 if (read_mode)
226 if (read_byte_offset == -1)
227 dump_ec(fd);
228 else if (read_byte_offset < 0 ||
229 read_byte_offset >= EC_SPACE_SIZE)
230 usage(argv[0], EXIT_FAILURE);
231 else
232 read_ec_val(fd, read_byte_offset);
233 else
234 write_ec_val(fd, write_byte_offset, write_value);
235 close(fd);
236
237 exit(EXIT_SUCCESS);
238}
diff --git a/tools/power/cpupower/Makefile b/tools/power/cpupower/Makefile
index cbfec92af327..2e2ba2efa0d9 100644
--- a/tools/power/cpupower/Makefile
+++ b/tools/power/cpupower/Makefile
@@ -62,7 +62,7 @@ LIB_MAJ= 0.0.0
62LIB_MIN= 0 62LIB_MIN= 0
63 63
64PACKAGE = cpupower 64PACKAGE = cpupower
65PACKAGE_BUGREPORT = cpufreq@vger.kernel.org 65PACKAGE_BUGREPORT = linux-pm@vger.kernel.org
66LANGUAGES = de fr it cs pt 66LANGUAGES = de fr it cs pt
67 67
68 68
@@ -274,6 +274,8 @@ install-man:
274 $(INSTALL_DATA) -D man/cpupower.1 $(DESTDIR)${mandir}/man1/cpupower.1 274 $(INSTALL_DATA) -D man/cpupower.1 $(DESTDIR)${mandir}/man1/cpupower.1
275 $(INSTALL_DATA) -D man/cpupower-frequency-set.1 $(DESTDIR)${mandir}/man1/cpupower-frequency-set.1 275 $(INSTALL_DATA) -D man/cpupower-frequency-set.1 $(DESTDIR)${mandir}/man1/cpupower-frequency-set.1
276 $(INSTALL_DATA) -D man/cpupower-frequency-info.1 $(DESTDIR)${mandir}/man1/cpupower-frequency-info.1 276 $(INSTALL_DATA) -D man/cpupower-frequency-info.1 $(DESTDIR)${mandir}/man1/cpupower-frequency-info.1
277 $(INSTALL_DATA) -D man/cpupower-idle-set.1 $(DESTDIR)${mandir}/man1/cpupower-idle-set.1
278 $(INSTALL_DATA) -D man/cpupower-idle-info.1 $(DESTDIR)${mandir}/man1/cpupower-idle-info.1
277 $(INSTALL_DATA) -D man/cpupower-set.1 $(DESTDIR)${mandir}/man1/cpupower-set.1 279 $(INSTALL_DATA) -D man/cpupower-set.1 $(DESTDIR)${mandir}/man1/cpupower-set.1
278 $(INSTALL_DATA) -D man/cpupower-info.1 $(DESTDIR)${mandir}/man1/cpupower-info.1 280 $(INSTALL_DATA) -D man/cpupower-info.1 $(DESTDIR)${mandir}/man1/cpupower-info.1
279 $(INSTALL_DATA) -D man/cpupower-monitor.1 $(DESTDIR)${mandir}/man1/cpupower-monitor.1 281 $(INSTALL_DATA) -D man/cpupower-monitor.1 $(DESTDIR)${mandir}/man1/cpupower-monitor.1
@@ -295,8 +297,12 @@ uninstall:
295 - rm -f $(DESTDIR)${libdir}/libcpupower.* 297 - rm -f $(DESTDIR)${libdir}/libcpupower.*
296 - rm -f $(DESTDIR)${includedir}/cpufreq.h 298 - rm -f $(DESTDIR)${includedir}/cpufreq.h
297 - rm -f $(DESTDIR)${bindir}/utils/cpupower 299 - rm -f $(DESTDIR)${bindir}/utils/cpupower
298 - rm -f $(DESTDIR)${mandir}/man1/cpufreq-set.1 300 - rm -f $(DESTDIR)${mandir}/man1/cpupower.1
299 - rm -f $(DESTDIR)${mandir}/man1/cpufreq-info.1 301 - rm -f $(DESTDIR)${mandir}/man1/cpupower-frequency-set.1
302 - rm -f $(DESTDIR)${mandir}/man1/cpupower-frequency-info.1
303 - rm -f $(DESTDIR)${mandir}/man1/cpupower-set.1
304 - rm -f $(DESTDIR)${mandir}/man1/cpupower-info.1
305 - rm -f $(DESTDIR)${mandir}/man1/cpupower-monitor.1
300 - for HLANG in $(LANGUAGES); do \ 306 - for HLANG in $(LANGUAGES); do \
301 rm -f $(DESTDIR)${localedir}/$$HLANG/LC_MESSAGES/cpupower.mo; \ 307 rm -f $(DESTDIR)${localedir}/$$HLANG/LC_MESSAGES/cpupower.mo; \
302 done; 308 done;
diff --git a/tools/power/cpupower/README b/tools/power/cpupower/README
index fd9d4c0d6688..1c68f47663b2 100644
--- a/tools/power/cpupower/README
+++ b/tools/power/cpupower/README
@@ -1,6 +1,4 @@
1The cpufrequtils package (homepage: 1The cpupower package consists of the following elements:
2http://www.kernel.org/pub/linux/utils/kernel/cpufreq/cpufrequtils.html )
3consists of the following elements:
4 2
5requirements 3requirements
6------------ 4------------
@@ -11,10 +9,10 @@ providing cpuid.h is needed.
11For both it's not explicitly checked for (yet). 9For both it's not explicitly checked for (yet).
12 10
13 11
14libcpufreq 12libcpupower
15---------- 13----------
16 14
17"libcpufreq" is a library which offers a unified access method for userspace 15"libcpupower" is a library which offers a unified access method for userspace
18tools and programs to the cpufreq core and drivers in the Linux kernel. This 16tools and programs to the cpufreq core and drivers in the Linux kernel. This
19allows for code reduction in userspace tools, a clean implementation of 17allows for code reduction in userspace tools, a clean implementation of
20the interaction to the cpufreq core, and support for both the sysfs and proc 18the interaction to the cpufreq core, and support for both the sysfs and proc
@@ -28,22 +26,22 @@ make
28su 26su
29make install 27make install
30 28
31should suffice on most systems. It builds default libcpufreq, 29should suffice on most systems. It builds libcpupower to put in
32cpufreq-set and cpufreq-info files and installs them in /usr/lib and 30/usr/lib; cpupower, cpufreq-bench_plot.sh to put in /usr/bin; and
33/usr/bin, respectively. If you want to set up the paths differently and/or 31cpufreq-bench to put in /usr/sbin. If you want to set up the paths
34want to configure the package to your specific needs, you need to open 32differently and/or want to configure the package to your specific
35"Makefile" with an editor of your choice and edit the block marked 33needs, you need to open "Makefile" with an editor of your choice and
36CONFIGURATION. 34edit the block marked CONFIGURATION.
37 35
38 36
39THANKS 37THANKS
40------ 38------
41Many thanks to Mattia Dongili who wrote the autotoolization and 39Many thanks to Mattia Dongili who wrote the autotoolization and
42libtoolization, the manpages and the italian language file for cpufrequtils; 40libtoolization, the manpages and the italian language file for cpupower;
43to Dave Jones for his feedback and his dump_psb tool; to Bruno Ducrot for his 41to Dave Jones for his feedback and his dump_psb tool; to Bruno Ducrot for his
44powernow-k8-decode and intel_gsic tools as well as the french language file; 42powernow-k8-decode and intel_gsic tools as well as the french language file;
45and to various others commenting on the previous (pre-)releases of 43and to various others commenting on the previous (pre-)releases of
46cpufrequtils. 44cpupower.
47 45
48 46
49 Dominik Brodowski 47 Dominik Brodowski
diff --git a/tools/power/cpupower/ToDo b/tools/power/cpupower/ToDo
index 874b78b586ee..6e8b89f282e6 100644
--- a/tools/power/cpupower/ToDo
+++ b/tools/power/cpupower/ToDo
@@ -3,7 +3,6 @@ ToDos sorted by priority:
3- Use bitmask functions to parse CPU topology more robust 3- Use bitmask functions to parse CPU topology more robust
4 (current implementation has issues on AMD) 4 (current implementation has issues on AMD)
5- Try to read out boost states and frequencies on Intel 5- Try to read out boost states and frequencies on Intel
6- Adjust README
7- Somewhere saw the ability to read power consumption of 6- Somewhere saw the ability to read power consumption of
8 RAM from HW on Intel SandyBridge -> another monitor? 7 RAM from HW on Intel SandyBridge -> another monitor?
9- Add another c1e debug idle monitor 8- Add another c1e debug idle monitor
diff --git a/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c b/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c
index 0f10b81e3322..5224ee5b392d 100644
--- a/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c
+++ b/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c
@@ -18,7 +18,7 @@
18 * 5.) if the third value, "diff_pmtmr", changes between 2. and 4., the 18 * 5.) if the third value, "diff_pmtmr", changes between 2. and 4., the
19 * TSC-based delay routine on the Linux kernel does not correctly 19 * TSC-based delay routine on the Linux kernel does not correctly
20 * handle the cpufreq transition. Please report this to 20 * handle the cpufreq transition. Please report this to
21 * cpufreq@vger.kernel.org 21 * linux-pm@vger.kernel.org
22 */ 22 */
23 23
24#include <linux/kernel.h> 24#include <linux/kernel.h>
diff --git a/tools/power/cpupower/man/cpupower-frequency-info.1 b/tools/power/cpupower/man/cpupower-frequency-info.1
index 4a1918ea8f9c..9c85a382e355 100644
--- a/tools/power/cpupower/man/cpupower-frequency-info.1
+++ b/tools/power/cpupower/man/cpupower-frequency-info.1
@@ -50,6 +50,9 @@ Prints out information like provided by the /proc/cpufreq interface in 2.4. and
50\fB\-m\fR \fB\-\-human\fR 50\fB\-m\fR \fB\-\-human\fR
51human\-readable output for the \-f, \-w, \-s and \-y parameters. 51human\-readable output for the \-f, \-w, \-s and \-y parameters.
52.TP 52.TP
53\fB\-n\fR \fB\-\-no-rounding\fR
54Output frequencies and latencies without rounding off values.
55.TP
53.SH "REMARKS" 56.SH "REMARKS"
54.LP 57.LP
55By default only values of core zero are displayed. How to display settings of 58By default only values of core zero are displayed. How to display settings of
diff --git a/tools/power/cpupower/man/cpupower-idle-set.1 b/tools/power/cpupower/man/cpupower-idle-set.1
index 6b1607272a5b..3e6799d7a79f 100644
--- a/tools/power/cpupower/man/cpupower-idle-set.1
+++ b/tools/power/cpupower/man/cpupower-idle-set.1
@@ -13,11 +13,17 @@ sleep states. This can be handy for power vs performance tuning.
13.SH "OPTIONS" 13.SH "OPTIONS"
14.LP 14.LP
15.TP 15.TP
16\fB\-d\fR \fB\-\-disable\fR 16\fB\-d\fR \fB\-\-disable\fR <STATE_NO>
17Disable a specific processor sleep state. 17Disable a specific processor sleep state.
18.TP 18.TP
19\fB\-e\fR \fB\-\-enable\fR 19\fB\-e\fR \fB\-\-enable\fR <STATE_NO>
20Enable a specific processor sleep state. 20Enable a specific processor sleep state.
21.TP
22\fB\-D\fR \fB\-\-disable-by-latency\fR <LATENCY>
23Disable all idle states with a equal or higher latency than <LATENCY>
24.TP
25\fB\-E\fR \fB\-\-enable-all\fR
26Enable all idle states if not enabled already.
21 27
22.SH "REMARKS" 28.SH "REMARKS"
23.LP 29.LP
diff --git a/tools/power/cpupower/man/cpupower-info.1 b/tools/power/cpupower/man/cpupower-info.1
index 58e21196f17f..340bcd0be7de 100644
--- a/tools/power/cpupower/man/cpupower-info.1
+++ b/tools/power/cpupower/man/cpupower-info.1
@@ -3,7 +3,7 @@
3cpupower\-info \- Shows processor power related kernel or hardware configurations 3cpupower\-info \- Shows processor power related kernel or hardware configurations
4.SH SYNOPSIS 4.SH SYNOPSIS
5.ft B 5.ft B
6.B cpupower info [ \-b ] [ \-s ] [ \-m ] 6.B cpupower info [ \-b ]
7 7
8.SH DESCRIPTION 8.SH DESCRIPTION
9\fBcpupower info \fP shows kernel configurations or processor hardware 9\fBcpupower info \fP shows kernel configurations or processor hardware
diff --git a/tools/power/cpupower/man/cpupower-set.1 b/tools/power/cpupower/man/cpupower-set.1
index 9dbd536518ab..2bcc696f4496 100644
--- a/tools/power/cpupower/man/cpupower-set.1
+++ b/tools/power/cpupower/man/cpupower-set.1
@@ -3,7 +3,7 @@
3cpupower\-set \- Set processor power related kernel or hardware configurations 3cpupower\-set \- Set processor power related kernel or hardware configurations
4.SH SYNOPSIS 4.SH SYNOPSIS
5.ft B 5.ft B
6.B cpupower set [ \-b VAL ] [ \-s VAL ] [ \-m VAL ] 6.B cpupower set [ \-b VAL ]
7 7
8 8
9.SH DESCRIPTION 9.SH DESCRIPTION
@@ -55,35 +55,6 @@ Use \fBcpupower -c all info -b\fP to verify.
55 55
56This options needs the msr kernel driver (CONFIG_X86_MSR) loaded. 56This options needs the msr kernel driver (CONFIG_X86_MSR) loaded.
57.RE 57.RE
58.PP
59\-\-sched\-mc, \-m [ VAL ]
60.RE
61\-\-sched\-smt, \-s [ VAL ]
62.RS 4
63\-\-sched\-mc utilizes cores in one processor package/socket first before
64processes are scheduled to other processor packages/sockets.
65
66\-\-sched\-smt utilizes thread siblings of one processor core first before
67processes are scheduled to other cores.
68
69The impact on power consumption and performance (positiv or negativ) heavily
70depends on processor support for deep sleep states, frequency scaling and
71frequency boost modes and their dependencies between other thread siblings
72and processor cores.
73
74Taken over from kernel documentation:
75
76Adjust the kernel's multi-core scheduler support.
77
78Possible values are:
79.RS 2
800 - No power saving load balance (default value)
81
821 - Fill one thread/core/package first for long running threads
83
842 - Also bias task wakeups to semi-idle cpu package for power
85savings
86.RE
87 58
88.SH "SEE ALSO" 59.SH "SEE ALSO"
89cpupower-info(1), cpupower-monitor(1), powertop(1) 60cpupower-info(1), cpupower-monitor(1), powertop(1)
diff --git a/tools/power/cpupower/utils/cpufreq-info.c b/tools/power/cpupower/utils/cpufreq-info.c
index 28953c9a7bd5..b4b90a97662c 100644
--- a/tools/power/cpupower/utils/cpufreq-info.c
+++ b/tools/power/cpupower/utils/cpufreq-info.c
@@ -82,29 +82,42 @@ static void proc_cpufreq_output(void)
82 } 82 }
83} 83}
84 84
85static int no_rounding;
85static void print_speed(unsigned long speed) 86static void print_speed(unsigned long speed)
86{ 87{
87 unsigned long tmp; 88 unsigned long tmp;
88 89
89 if (speed > 1000000) { 90 if (no_rounding) {
90 tmp = speed % 10000; 91 if (speed > 1000000)
91 if (tmp >= 5000) 92 printf("%u.%06u GHz", ((unsigned int) speed/1000000),
92 speed += 10000; 93 ((unsigned int) speed%1000000));
93 printf("%u.%02u GHz", ((unsigned int) speed/1000000), 94 else if (speed > 100000)
94 ((unsigned int) (speed%1000000)/10000)); 95 printf("%u MHz", (unsigned int) speed);
95 } else if (speed > 100000) { 96 else if (speed > 1000)
96 tmp = speed % 1000; 97 printf("%u.%03u MHz", ((unsigned int) speed/1000),
97 if (tmp >= 500) 98 (unsigned int) (speed%1000));
98 speed += 1000; 99 else
99 printf("%u MHz", ((unsigned int) speed / 1000)); 100 printf("%lu kHz", speed);
100 } else if (speed > 1000) { 101 } else {
101 tmp = speed % 100; 102 if (speed > 1000000) {
102 if (tmp >= 50) 103 tmp = speed%10000;
103 speed += 100; 104 if (tmp >= 5000)
104 printf("%u.%01u MHz", ((unsigned int) speed/1000), 105 speed += 10000;
105 ((unsigned int) (speed%1000)/100)); 106 printf("%u.%02u GHz", ((unsigned int) speed/1000000),
106 } else 107 ((unsigned int) (speed%1000000)/10000));
107 printf("%lu kHz", speed); 108 } else if (speed > 100000) {
109 tmp = speed%1000;
110 if (tmp >= 500)
111 speed += 1000;
112 printf("%u MHz", ((unsigned int) speed/1000));
113 } else if (speed > 1000) {
114 tmp = speed%100;
115 if (tmp >= 50)
116 speed += 100;
117 printf("%u.%01u MHz", ((unsigned int) speed/1000),
118 ((unsigned int) (speed%1000)/100));
119 }
120 }
108 121
109 return; 122 return;
110} 123}
@@ -113,26 +126,38 @@ static void print_duration(unsigned long duration)
113{ 126{
114 unsigned long tmp; 127 unsigned long tmp;
115 128
116 if (duration > 1000000) { 129 if (no_rounding) {
117 tmp = duration % 10000; 130 if (duration > 1000000)
118 if (tmp >= 5000) 131 printf("%u.%06u ms", ((unsigned int) duration/1000000),
119 duration += 10000; 132 ((unsigned int) duration%1000000));
120 printf("%u.%02u ms", ((unsigned int) duration/1000000), 133 else if (duration > 100000)
121 ((unsigned int) (duration%1000000)/10000)); 134 printf("%u us", ((unsigned int) duration/1000));
122 } else if (duration > 100000) { 135 else if (duration > 1000)
123 tmp = duration % 1000; 136 printf("%u.%03u us", ((unsigned int) duration/1000),
124 if (tmp >= 500) 137 ((unsigned int) duration%1000));
125 duration += 1000; 138 else
126 printf("%u us", ((unsigned int) duration / 1000)); 139 printf("%lu ns", duration);
127 } else if (duration > 1000) { 140 } else {
128 tmp = duration % 100; 141 if (duration > 1000000) {
129 if (tmp >= 50) 142 tmp = duration%10000;
130 duration += 100; 143 if (tmp >= 5000)
131 printf("%u.%01u us", ((unsigned int) duration/1000), 144 duration += 10000;
132 ((unsigned int) (duration%1000)/100)); 145 printf("%u.%02u ms", ((unsigned int) duration/1000000),
133 } else 146 ((unsigned int) (duration%1000000)/10000));
134 printf("%lu ns", duration); 147 } else if (duration > 100000) {
135 148 tmp = duration%1000;
149 if (tmp >= 500)
150 duration += 1000;
151 printf("%u us", ((unsigned int) duration / 1000));
152 } else if (duration > 1000) {
153 tmp = duration%100;
154 if (tmp >= 50)
155 duration += 100;
156 printf("%u.%01u us", ((unsigned int) duration/1000),
157 ((unsigned int) (duration%1000)/100));
158 } else
159 printf("%lu ns", duration);
160 }
136 return; 161 return;
137} 162}
138 163
@@ -525,6 +550,7 @@ static struct option info_opts[] = {
525 { .name = "latency", .has_arg = no_argument, .flag = NULL, .val = 'y'}, 550 { .name = "latency", .has_arg = no_argument, .flag = NULL, .val = 'y'},
526 { .name = "proc", .has_arg = no_argument, .flag = NULL, .val = 'o'}, 551 { .name = "proc", .has_arg = no_argument, .flag = NULL, .val = 'o'},
527 { .name = "human", .has_arg = no_argument, .flag = NULL, .val = 'm'}, 552 { .name = "human", .has_arg = no_argument, .flag = NULL, .val = 'm'},
553 { .name = "no-rounding", .has_arg = no_argument, .flag = NULL, .val = 'n'},
528 { }, 554 { },
529}; 555};
530 556
@@ -538,7 +564,8 @@ int cmd_freq_info(int argc, char **argv)
538 int output_param = 0; 564 int output_param = 0;
539 565
540 do { 566 do {
541 ret = getopt_long(argc, argv, "oefwldpgrasmyb", info_opts, NULL); 567 ret = getopt_long(argc, argv, "oefwldpgrasmybn", info_opts,
568 NULL);
542 switch (ret) { 569 switch (ret) {
543 case '?': 570 case '?':
544 output_param = '?'; 571 output_param = '?';
@@ -575,6 +602,9 @@ int cmd_freq_info(int argc, char **argv)
575 } 602 }
576 human = 1; 603 human = 1;
577 break; 604 break;
605 case 'n':
606 no_rounding = 1;
607 break;
578 default: 608 default:
579 fprintf(stderr, "invalid or unknown argument\n"); 609 fprintf(stderr, "invalid or unknown argument\n");
580 return EXIT_FAILURE; 610 return EXIT_FAILURE;
diff --git a/tools/power/cpupower/utils/cpuidle-set.c b/tools/power/cpupower/utils/cpuidle-set.c
index c78141c5dfac..d45d8d775c02 100644
--- a/tools/power/cpupower/utils/cpuidle-set.c
+++ b/tools/power/cpupower/utils/cpuidle-set.c
@@ -13,8 +13,14 @@
13#include "helpers/sysfs.h" 13#include "helpers/sysfs.h"
14 14
15static struct option info_opts[] = { 15static struct option info_opts[] = {
16 { .name = "disable", .has_arg = required_argument, .flag = NULL, .val = 'd'}, 16 { .name = "disable",
17 { .name = "enable", .has_arg = required_argument, .flag = NULL, .val = 'e'}, 17 .has_arg = required_argument, .flag = NULL, .val = 'd'},
18 { .name = "enable",
19 .has_arg = required_argument, .flag = NULL, .val = 'e'},
20 { .name = "disable-by-latency",
21 .has_arg = required_argument, .flag = NULL, .val = 'D'},
22 { .name = "enable-all",
23 .has_arg = no_argument, .flag = NULL, .val = 'E'},
18 { }, 24 { },
19}; 25};
20 26
@@ -23,11 +29,13 @@ int cmd_idle_set(int argc, char **argv)
23{ 29{
24 extern char *optarg; 30 extern char *optarg;
25 extern int optind, opterr, optopt; 31 extern int optind, opterr, optopt;
26 int ret = 0, cont = 1, param = 0, idlestate = 0; 32 int ret = 0, cont = 1, param = 0, disabled;
27 unsigned int cpu = 0; 33 unsigned long long latency = 0, state_latency;
34 unsigned int cpu = 0, idlestate = 0, idlestates = 0;
35 char *endptr;
28 36
29 do { 37 do {
30 ret = getopt_long(argc, argv, "d:e:", info_opts, NULL); 38 ret = getopt_long(argc, argv, "d:e:ED:", info_opts, NULL);
31 if (ret == -1) 39 if (ret == -1)
32 break; 40 break;
33 switch (ret) { 41 switch (ret) {
@@ -53,6 +61,27 @@ int cmd_idle_set(int argc, char **argv)
53 param = ret; 61 param = ret;
54 idlestate = atoi(optarg); 62 idlestate = atoi(optarg);
55 break; 63 break;
64 case 'D':
65 if (param) {
66 param = -1;
67 cont = 0;
68 break;
69 }
70 param = ret;
71 latency = strtoull(optarg, &endptr, 10);
72 if (*endptr != '\0') {
73 printf(_("Bad latency value: %s\n"), optarg);
74 exit(EXIT_FAILURE);
75 }
76 break;
77 case 'E':
78 if (param) {
79 param = -1;
80 cont = 0;
81 break;
82 }
83 param = ret;
84 break;
56 case -1: 85 case -1:
57 cont = 0; 86 cont = 0;
58 break; 87 break;
@@ -79,8 +108,14 @@ int cmd_idle_set(int argc, char **argv)
79 if (!bitmask_isbitset(cpus_chosen, cpu)) 108 if (!bitmask_isbitset(cpus_chosen, cpu))
80 continue; 109 continue;
81 110
82 switch (param) { 111 if (sysfs_is_cpu_online(cpu) != 1)
112 continue;
113
114 idlestates = sysfs_get_idlestate_count(cpu);
115 if (idlestates <= 0)
116 continue;
83 117
118 switch (param) {
84 case 'd': 119 case 'd':
85 ret = sysfs_idlestate_disable(cpu, idlestate, 1); 120 ret = sysfs_idlestate_disable(cpu, idlestate, 1);
86 if (ret == 0) 121 if (ret == 0)
@@ -107,6 +142,34 @@ int cmd_idle_set(int argc, char **argv)
107 printf(_("Idlestate %u not enabled on CPU %u\n"), 142 printf(_("Idlestate %u not enabled on CPU %u\n"),
108 idlestate, cpu); 143 idlestate, cpu);
109 break; 144 break;
145 case 'D':
146 for (idlestate = 0; idlestate < idlestates; idlestate++) {
147 disabled = sysfs_is_idlestate_disabled
148 (cpu, idlestate);
149 state_latency = sysfs_get_idlestate_latency
150 (cpu, idlestate);
151 printf("CPU: %u - idlestate %u - state_latency: %llu - latency: %llu\n",
152 cpu, idlestate, state_latency, latency);
153 if (disabled == 1 || latency > state_latency)
154 continue;
155 ret = sysfs_idlestate_disable
156 (cpu, idlestate, 1);
157 if (ret == 0)
158 printf(_("Idlestate %u disabled on CPU %u\n"), idlestate, cpu);
159 }
160 break;
161 case 'E':
162 for (idlestate = 0; idlestate < idlestates; idlestate++) {
163 disabled = sysfs_is_idlestate_disabled
164 (cpu, idlestate);
165 if (disabled == 1) {
166 ret = sysfs_idlestate_disable
167 (cpu, idlestate, 0);
168 if (ret == 0)
169 printf(_("Idlestate %u enabled on CPU %u\n"), idlestate, cpu);
170 }
171 }
172 break;
110 default: 173 default:
111 /* Not reachable with proper args checking */ 174 /* Not reachable with proper args checking */
112 printf(_("Invalid or unknown argument\n")); 175 printf(_("Invalid or unknown argument\n"));
diff --git a/tools/power/cpupower/utils/cpupower-info.c b/tools/power/cpupower/utils/cpupower-info.c
index 3f68632c28c7..136d979e9586 100644
--- a/tools/power/cpupower/utils/cpupower-info.c
+++ b/tools/power/cpupower/utils/cpupower-info.c
@@ -18,8 +18,6 @@
18 18
19static struct option set_opts[] = { 19static struct option set_opts[] = {
20 { .name = "perf-bias", .has_arg = optional_argument, .flag = NULL, .val = 'b'}, 20 { .name = "perf-bias", .has_arg = optional_argument, .flag = NULL, .val = 'b'},
21 { .name = "sched-mc", .has_arg = optional_argument, .flag = NULL, .val = 'm'},
22 { .name = "sched-smt", .has_arg = optional_argument, .flag = NULL, .val = 's'},
23 { }, 21 { },
24}; 22};
25 23
@@ -37,8 +35,6 @@ int cmd_info(int argc, char **argv)
37 35
38 union { 36 union {
39 struct { 37 struct {
40 int sched_mc:1;
41 int sched_smt:1;
42 int perf_bias:1; 38 int perf_bias:1;
43 }; 39 };
44 int params; 40 int params;
@@ -49,23 +45,13 @@ int cmd_info(int argc, char **argv)
49 textdomain(PACKAGE); 45 textdomain(PACKAGE);
50 46
51 /* parameter parsing */ 47 /* parameter parsing */
52 while ((ret = getopt_long(argc, argv, "msb", set_opts, NULL)) != -1) { 48 while ((ret = getopt_long(argc, argv, "b", set_opts, NULL)) != -1) {
53 switch (ret) { 49 switch (ret) {
54 case 'b': 50 case 'b':
55 if (params.perf_bias) 51 if (params.perf_bias)
56 print_wrong_arg_exit(); 52 print_wrong_arg_exit();
57 params.perf_bias = 1; 53 params.perf_bias = 1;
58 break; 54 break;
59 case 'm':
60 if (params.sched_mc)
61 print_wrong_arg_exit();
62 params.sched_mc = 1;
63 break;
64 case 's':
65 if (params.sched_smt)
66 print_wrong_arg_exit();
67 params.sched_smt = 1;
68 break;
69 default: 55 default:
70 print_wrong_arg_exit(); 56 print_wrong_arg_exit();
71 } 57 }
@@ -78,25 +64,6 @@ int cmd_info(int argc, char **argv)
78 if (bitmask_isallclear(cpus_chosen)) 64 if (bitmask_isallclear(cpus_chosen))
79 bitmask_setbit(cpus_chosen, 0); 65 bitmask_setbit(cpus_chosen, 0);
80 66
81 if (params.sched_mc) {
82 ret = sysfs_get_sched("mc");
83 printf(_("System's multi core scheduler setting: "));
84 if (ret < 0)
85 /* if sysfs file is missing it's: errno == ENOENT */
86 printf(_("not supported\n"));
87 else
88 printf("%d\n", ret);
89 }
90 if (params.sched_smt) {
91 ret = sysfs_get_sched("smt");
92 printf(_("System's thread sibling scheduler setting: "));
93 if (ret < 0)
94 /* if sysfs file is missing it's: errno == ENOENT */
95 printf(_("not supported\n"));
96 else
97 printf("%d\n", ret);
98 }
99
100 /* Add more per cpu options here */ 67 /* Add more per cpu options here */
101 if (!params.perf_bias) 68 if (!params.perf_bias)
102 return ret; 69 return ret;
@@ -125,11 +92,12 @@ int cmd_info(int argc, char **argv)
125 if (params.perf_bias) { 92 if (params.perf_bias) {
126 ret = msr_intel_get_perf_bias(cpu); 93 ret = msr_intel_get_perf_bias(cpu);
127 if (ret < 0) { 94 if (ret < 0) {
128 printf(_("Could not read perf-bias value\n")); 95 fprintf(stderr,
129 break; 96 _("Could not read perf-bias value[%d]\n"), ret);
97 exit(EXIT_FAILURE);
130 } else 98 } else
131 printf(_("perf-bias: %d\n"), ret); 99 printf(_("perf-bias: %d\n"), ret);
132 } 100 }
133 } 101 }
134 return ret; 102 return 0;
135} 103}
diff --git a/tools/power/cpupower/utils/cpupower-set.c b/tools/power/cpupower/utils/cpupower-set.c
index bcf1d2f0b791..573c75f8e3f5 100644
--- a/tools/power/cpupower/utils/cpupower-set.c
+++ b/tools/power/cpupower/utils/cpupower-set.c
@@ -19,8 +19,6 @@
19 19
20static struct option set_opts[] = { 20static struct option set_opts[] = {
21 { .name = "perf-bias", .has_arg = required_argument, .flag = NULL, .val = 'b'}, 21 { .name = "perf-bias", .has_arg = required_argument, .flag = NULL, .val = 'b'},
22 { .name = "sched-mc", .has_arg = required_argument, .flag = NULL, .val = 'm'},
23 { .name = "sched-smt", .has_arg = required_argument, .flag = NULL, .val = 's'},
24 { }, 22 { },
25}; 23};
26 24
@@ -38,13 +36,11 @@ int cmd_set(int argc, char **argv)
38 36
39 union { 37 union {
40 struct { 38 struct {
41 int sched_mc:1;
42 int sched_smt:1;
43 int perf_bias:1; 39 int perf_bias:1;
44 }; 40 };
45 int params; 41 int params;
46 } params; 42 } params;
47 int sched_mc = 0, sched_smt = 0, perf_bias = 0; 43 int perf_bias = 0;
48 int ret = 0; 44 int ret = 0;
49 45
50 setlocale(LC_ALL, ""); 46 setlocale(LC_ALL, "");
@@ -52,7 +48,7 @@ int cmd_set(int argc, char **argv)
52 48
53 params.params = 0; 49 params.params = 0;
54 /* parameter parsing */ 50 /* parameter parsing */
55 while ((ret = getopt_long(argc, argv, "m:s:b:", 51 while ((ret = getopt_long(argc, argv, "b:",
56 set_opts, NULL)) != -1) { 52 set_opts, NULL)) != -1) {
57 switch (ret) { 53 switch (ret) {
58 case 'b': 54 case 'b':
@@ -66,28 +62,6 @@ int cmd_set(int argc, char **argv)
66 } 62 }
67 params.perf_bias = 1; 63 params.perf_bias = 1;
68 break; 64 break;
69 case 'm':
70 if (params.sched_mc)
71 print_wrong_arg_exit();
72 sched_mc = atoi(optarg);
73 if (sched_mc < 0 || sched_mc > 2) {
74 printf(_("--sched-mc param out "
75 "of range [0-%d]\n"), 2);
76 print_wrong_arg_exit();
77 }
78 params.sched_mc = 1;
79 break;
80 case 's':
81 if (params.sched_smt)
82 print_wrong_arg_exit();
83 sched_smt = atoi(optarg);
84 if (sched_smt < 0 || sched_smt > 2) {
85 printf(_("--sched-smt param out "
86 "of range [0-%d]\n"), 2);
87 print_wrong_arg_exit();
88 }
89 params.sched_smt = 1;
90 break;
91 default: 65 default:
92 print_wrong_arg_exit(); 66 print_wrong_arg_exit();
93 } 67 }
@@ -96,19 +70,6 @@ int cmd_set(int argc, char **argv)
96 if (!params.params) 70 if (!params.params)
97 print_wrong_arg_exit(); 71 print_wrong_arg_exit();
98 72
99 if (params.sched_mc) {
100 ret = sysfs_set_sched("mc", sched_mc);
101 if (ret)
102 fprintf(stderr, _("Error setting sched-mc %s\n"),
103 (ret == -ENODEV) ? "not supported" : "");
104 }
105 if (params.sched_smt) {
106 ret = sysfs_set_sched("smt", sched_smt);
107 if (ret)
108 fprintf(stderr, _("Error setting sched-smt %s\n"),
109 (ret == -ENODEV) ? "not supported" : "");
110 }
111
112 /* Default is: set all CPUs */ 73 /* Default is: set all CPUs */
113 if (bitmask_isallclear(cpus_chosen)) 74 if (bitmask_isallclear(cpus_chosen))
114 bitmask_setall(cpus_chosen); 75 bitmask_setall(cpus_chosen);
diff --git a/tools/power/cpupower/utils/cpupower.c b/tools/power/cpupower/utils/cpupower.c
index 7efc570ffbaa..7cdcf88659c7 100644
--- a/tools/power/cpupower/utils/cpupower.c
+++ b/tools/power/cpupower/utils/cpupower.c
@@ -12,6 +12,9 @@
12#include <string.h> 12#include <string.h>
13#include <unistd.h> 13#include <unistd.h>
14#include <errno.h> 14#include <errno.h>
15#include <sys/types.h>
16#include <sys/stat.h>
17#include <sys/utsname.h>
15 18
16#include "builtin.h" 19#include "builtin.h"
17#include "helpers/helpers.h" 20#include "helpers/helpers.h"
@@ -169,6 +172,8 @@ int main(int argc, const char *argv[])
169{ 172{
170 const char *cmd; 173 const char *cmd;
171 unsigned int i, ret; 174 unsigned int i, ret;
175 struct stat statbuf;
176 struct utsname uts;
172 177
173 cpus_chosen = bitmask_alloc(sysconf(_SC_NPROCESSORS_CONF)); 178 cpus_chosen = bitmask_alloc(sysconf(_SC_NPROCESSORS_CONF));
174 179
@@ -195,6 +200,15 @@ int main(int argc, const char *argv[])
195 200
196 get_cpu_info(0, &cpupower_cpu_info); 201 get_cpu_info(0, &cpupower_cpu_info);
197 run_as_root = !getuid(); 202 run_as_root = !getuid();
203 if (run_as_root) {
204 ret = uname(&uts);
205 if (!ret && !strcmp(uts.machine, "x86_64") &&
206 stat("/dev/cpu/0/msr", &statbuf) != 0) {
207 if (system("modprobe msr") == -1)
208 fprintf(stderr, _("MSR access not available.\n"));
209 }
210 }
211
198 212
199 for (i = 0; i < ARRAY_SIZE(commands); i++) { 213 for (i = 0; i < ARRAY_SIZE(commands); i++) {
200 struct cmd_struct *p = commands + i; 214 struct cmd_struct *p = commands + i;
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
index 7c9d8e71eb9e..d0396af99fa0 100644
--- a/tools/power/x86/turbostat/turbostat.c
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -1971,13 +1971,13 @@ int set_temperature_target(struct thread_data *t, struct core_data *c, struct pk
1971 if (get_msr(0, MSR_IA32_TEMPERATURE_TARGET, &msr)) 1971 if (get_msr(0, MSR_IA32_TEMPERATURE_TARGET, &msr))
1972 goto guess; 1972 goto guess;
1973 1973
1974 target_c_local = (msr >> 16) & 0x7F; 1974 target_c_local = (msr >> 16) & 0xFF;
1975 1975
1976 if (verbose) 1976 if (verbose)
1977 fprintf(stderr, "cpu%d: MSR_IA32_TEMPERATURE_TARGET: 0x%08llx (%d C)\n", 1977 fprintf(stderr, "cpu%d: MSR_IA32_TEMPERATURE_TARGET: 0x%08llx (%d C)\n",
1978 cpu, msr, target_c_local); 1978 cpu, msr, target_c_local);
1979 1979
1980 if (target_c_local < 85 || target_c_local > 127) 1980 if (!target_c_local)
1981 goto guess; 1981 goto guess;
1982 1982
1983 tcc_activation_temp = target_c_local; 1983 tcc_activation_temp = target_c_local;
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index 32487ed18354..e66e710cc595 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -10,6 +10,7 @@ TARGETS += timers
10TARGETS += vm 10TARGETS += vm
11TARGETS += powerpc 11TARGETS += powerpc
12TARGETS += user 12TARGETS += user
13TARGETS += sysctl
13 14
14all: 15all:
15 for TARGET in $(TARGETS); do \ 16 for TARGET in $(TARGETS); do \
diff --git a/tools/testing/selftests/cpu-hotplug/Makefile b/tools/testing/selftests/cpu-hotplug/Makefile
index ae5faf9aade2..790c23a9db44 100644
--- a/tools/testing/selftests/cpu-hotplug/Makefile
+++ b/tools/testing/selftests/cpu-hotplug/Makefile
@@ -1,6 +1,6 @@
1all: 1all:
2 2
3run_tests: 3run_tests:
4 @/bin/sh ./on-off-test.sh || echo "cpu-hotplug selftests: [FAIL]" 4 @/bin/bash ./on-off-test.sh || echo "cpu-hotplug selftests: [FAIL]"
5 5
6clean: 6clean:
diff --git a/tools/testing/selftests/ipc/msgque.c b/tools/testing/selftests/ipc/msgque.c
index aa290c0de6f5..552f0810bffb 100644
--- a/tools/testing/selftests/ipc/msgque.c
+++ b/tools/testing/selftests/ipc/msgque.c
@@ -193,6 +193,11 @@ int main(int argc, char **argv)
193 int msg, pid, err; 193 int msg, pid, err;
194 struct msgque_data msgque; 194 struct msgque_data msgque;
195 195
196 if (getuid() != 0) {
197 printf("Please run the test as root - Exiting.\n");
198 exit(1);
199 }
200
196 msgque.key = ftok(argv[0], 822155650); 201 msgque.key = ftok(argv[0], 822155650);
197 if (msgque.key == -1) { 202 if (msgque.key == -1) {
198 printf("Can't make key\n"); 203 printf("Can't make key\n");
diff --git a/tools/testing/selftests/memory-hotplug/Makefile b/tools/testing/selftests/memory-hotplug/Makefile
index 350bfeda3aa8..058c76f5d102 100644
--- a/tools/testing/selftests/memory-hotplug/Makefile
+++ b/tools/testing/selftests/memory-hotplug/Makefile
@@ -1,6 +1,6 @@
1all: 1all:
2 2
3run_tests: 3run_tests:
4 @/bin/sh ./on-off-test.sh || echo "memory-hotplug selftests: [FAIL]" 4 @/bin/bash ./on-off-test.sh || echo "memory-hotplug selftests: [FAIL]"
5 5
6clean: 6clean:
diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile
index 750512ba2c88..c7493b8f9b0e 100644
--- a/tools/testing/selftests/net/Makefile
+++ b/tools/testing/selftests/net/Makefile
@@ -14,6 +14,12 @@ all: $(NET_PROGS)
14run_tests: all 14run_tests: all
15 @/bin/sh ./run_netsocktests || echo "sockettests: [FAIL]" 15 @/bin/sh ./run_netsocktests || echo "sockettests: [FAIL]"
16 @/bin/sh ./run_afpackettests || echo "afpackettests: [FAIL]" 16 @/bin/sh ./run_afpackettests || echo "afpackettests: [FAIL]"
17 17 @if /sbin/modprobe test_bpf ; then \
18 /sbin/rmmod test_bpf; \
19 echo "test_bpf: ok"; \
20 else \
21 echo "test_bpf: [FAIL]"; \
22 exit 1; \
23 fi
18clean: 24clean:
19 $(RM) $(NET_PROGS) 25 $(RM) $(NET_PROGS)
diff --git a/tools/testing/selftests/powerpc/Makefile b/tools/testing/selftests/powerpc/Makefile
index 316194f26ff4..54833a791a44 100644
--- a/tools/testing/selftests/powerpc/Makefile
+++ b/tools/testing/selftests/powerpc/Makefile
@@ -13,7 +13,7 @@ CFLAGS := -Wall -O2 -flto -Wall -Werror -DGIT_VERSION='"$(GIT_VERSION)"' -I$(CUR
13 13
14export CC CFLAGS 14export CC CFLAGS
15 15
16TARGETS = pmu copyloops 16TARGETS = pmu copyloops mm tm
17 17
18endif 18endif
19 19
diff --git a/tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h b/tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h
index ccd9c84c4e3f..d1dc37425510 100644
--- a/tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h
+++ b/tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h
@@ -46,12 +46,15 @@
46#define R20 r20 46#define R20 r20
47#define R21 r21 47#define R21 r21
48#define R22 r22 48#define R22 r22
49#define R29 r29
50#define R30 r30
51#define R31 r31
49 52
50#define STACKFRAMESIZE 256 53#define STACKFRAMESIZE 256
51#define STK_PARAM(i) (48 + ((i)-3)*8)
52#define STK_REG(i) (112 + ((i)-14)*8) 54#define STK_REG(i) (112 + ((i)-14)*8)
53 55
54#define _GLOBAL(A) FUNC_START(test_ ## A) 56#define _GLOBAL(A) FUNC_START(test_ ## A)
57#define _GLOBAL_TOC(A) _GLOBAL(A)
55 58
56#define PPC_MTOCRF(A, B) mtocrf A, B 59#define PPC_MTOCRF(A, B) mtocrf A, B
57 60
diff --git a/tools/testing/selftests/powerpc/harness.c b/tools/testing/selftests/powerpc/harness.c
index e80c42a584fe..8ebc58a09311 100644
--- a/tools/testing/selftests/powerpc/harness.c
+++ b/tools/testing/selftests/powerpc/harness.c
@@ -30,12 +30,15 @@ int run_test(int (test_function)(void), char *name)
30 30
31 pid = fork(); 31 pid = fork();
32 if (pid == 0) { 32 if (pid == 0) {
33 setpgid(0, 0);
33 exit(test_function()); 34 exit(test_function());
34 } else if (pid == -1) { 35 } else if (pid == -1) {
35 perror("fork"); 36 perror("fork");
36 return 1; 37 return 1;
37 } 38 }
38 39
40 setpgid(pid, pid);
41
39 /* Wake us up in timeout seconds */ 42 /* Wake us up in timeout seconds */
40 alarm(TIMEOUT); 43 alarm(TIMEOUT);
41 terminated = false; 44 terminated = false;
@@ -50,17 +53,20 @@ wait:
50 53
51 if (terminated) { 54 if (terminated) {
52 printf("!! force killing %s\n", name); 55 printf("!! force killing %s\n", name);
53 kill(pid, SIGKILL); 56 kill(-pid, SIGKILL);
54 return 1; 57 return 1;
55 } else { 58 } else {
56 printf("!! killing %s\n", name); 59 printf("!! killing %s\n", name);
57 kill(pid, SIGTERM); 60 kill(-pid, SIGTERM);
58 terminated = true; 61 terminated = true;
59 alarm(KILL_TIMEOUT); 62 alarm(KILL_TIMEOUT);
60 goto wait; 63 goto wait;
61 } 64 }
62 } 65 }
63 66
67 /* Kill anything else in the process group that is still running */
68 kill(-pid, SIGTERM);
69
64 if (WIFEXITED(status)) 70 if (WIFEXITED(status))
65 status = WEXITSTATUS(status); 71 status = WEXITSTATUS(status);
66 else { 72 else {
@@ -99,7 +105,10 @@ int test_harness(int (test_function)(void), char *name)
99 105
100 rc = run_test(test_function, name); 106 rc = run_test(test_function, name);
101 107
102 test_finish(name, rc); 108 if (rc == MAGIC_SKIP_RETURN_VALUE)
109 test_skip(name);
110 else
111 test_finish(name, rc);
103 112
104 return rc; 113 return rc;
105} 114}
diff --git a/tools/testing/selftests/powerpc/mm/Makefile b/tools/testing/selftests/powerpc/mm/Makefile
new file mode 100644
index 000000000000..357ccbd6bad9
--- /dev/null
+++ b/tools/testing/selftests/powerpc/mm/Makefile
@@ -0,0 +1,18 @@
1noarg:
2 $(MAKE) -C ../
3
4PROGS := hugetlb_vs_thp_test
5
6all: $(PROGS)
7
8$(PROGS): ../harness.c
9
10run_tests: all
11 @-for PROG in $(PROGS); do \
12 ./$$PROG; \
13 done;
14
15clean:
16 rm -f $(PROGS)
17
18.PHONY: all run_tests clean
diff --git a/tools/testing/selftests/powerpc/mm/hugetlb_vs_thp_test.c b/tools/testing/selftests/powerpc/mm/hugetlb_vs_thp_test.c
new file mode 100644
index 000000000000..3d8e5b033e1d
--- /dev/null
+++ b/tools/testing/selftests/powerpc/mm/hugetlb_vs_thp_test.c
@@ -0,0 +1,72 @@
1#include <stdio.h>
2#include <sys/mman.h>
3#include <unistd.h>
4
5#include "utils.h"
6
7/* This must match the huge page & THP size */
8#define SIZE (16 * 1024 * 1024)
9
10static int test_body(void)
11{
12 void *addr;
13 char *p;
14
15 addr = (void *)0xa0000000;
16
17 p = mmap(addr, SIZE, PROT_READ | PROT_WRITE,
18 MAP_HUGETLB | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
19 if (p != MAP_FAILED) {
20 /*
21 * Typically the mmap will fail because no huge pages are
22 * allocated on the system. But if there are huge pages
23 * allocated the mmap will succeed. That's fine too, we just
24 * munmap here before continuing.
25 */
26 munmap(addr, SIZE);
27 }
28
29 p = mmap(addr, SIZE, PROT_READ | PROT_WRITE,
30 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
31 if (p == MAP_FAILED) {
32 printf("Mapping failed @ %p\n", addr);
33 perror("mmap");
34 return 1;
35 }
36
37 /*
38 * Either a user or kernel access is sufficient to trigger the bug.
39 * A kernel access is easier to spot & debug, as it will trigger the
40 * softlockup or RCU stall detectors, and when the system is kicked
41 * into xmon we get a backtrace in the kernel.
42 *
43 * A good option is:
44 * getcwd(p, SIZE);
45 *
46 * For the purposes of this testcase it's preferable to spin in
47 * userspace, so the harness can kill us if we get stuck. That way we
48 * see a test failure rather than a dead system.
49 */
50 *p = 0xf;
51
52 munmap(addr, SIZE);
53
54 return 0;
55}
56
57static int test_main(void)
58{
59 int i;
60
61 /* 10,000 because it's a "bunch", and completes reasonably quickly */
62 for (i = 0; i < 10000; i++)
63 if (test_body())
64 return 1;
65
66 return 0;
67}
68
69int main(void)
70{
71 return test_harness(test_main, "hugetlb_vs_thp");
72}
diff --git a/tools/testing/selftests/powerpc/pmu/Makefile b/tools/testing/selftests/powerpc/pmu/Makefile
index 7216f0091655..b9ff0db42c79 100644
--- a/tools/testing/selftests/powerpc/pmu/Makefile
+++ b/tools/testing/selftests/powerpc/pmu/Makefile
@@ -4,7 +4,7 @@ noarg:
4PROGS := count_instructions 4PROGS := count_instructions
5EXTRA_SOURCES := ../harness.c event.c 5EXTRA_SOURCES := ../harness.c event.c
6 6
7all: $(PROGS) 7all: $(PROGS) sub_all
8 8
9$(PROGS): $(EXTRA_SOURCES) 9$(PROGS): $(EXTRA_SOURCES)
10 10
@@ -12,12 +12,30 @@ $(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
15run_tests: all 15run_tests: all sub_run_tests
16 @-for PROG in $(PROGS); do \ 16 @-for PROG in $(PROGS); do \
17 ./$$PROG; \ 17 ./$$PROG; \
18 done; 18 done;
19 19
20clean: 20clean: sub_clean
21 rm -f $(PROGS) loop.o 21 rm -f $(PROGS) loop.o
22 22
23.PHONY: all run_tests clean 23
24SUB_TARGETS = ebb
25
26sub_all:
27 @for TARGET in $(SUB_TARGETS); do \
28 $(MAKE) -C $$TARGET all; \
29 done;
30
31sub_run_tests: all
32 @for TARGET in $(SUB_TARGETS); do \
33 $(MAKE) -C $$TARGET run_tests; \
34 done;
35
36sub_clean:
37 @for TARGET in $(SUB_TARGETS); do \
38 $(MAKE) -C $$TARGET clean; \
39 done;
40
41.PHONY: all run_tests clean sub_all sub_run_tests sub_clean
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/Makefile b/tools/testing/selftests/powerpc/pmu/ebb/Makefile
new file mode 100644
index 000000000000..edbba2affc2c
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/Makefile
@@ -0,0 +1,32 @@
1noarg:
2 $(MAKE) -C ../../
3
4# The EBB handler is 64-bit code and everything links against it
5CFLAGS += -m64
6
7PROGS := reg_access_test event_attributes_test cycles_test \
8 cycles_with_freeze_test pmc56_overflow_test \
9 ebb_vs_cpu_event_test cpu_event_vs_ebb_test \
10 cpu_event_pinned_vs_ebb_test task_event_vs_ebb_test \
11 task_event_pinned_vs_ebb_test multi_ebb_procs_test \
12 multi_counter_test pmae_handling_test \
13 close_clears_pmcc_test instruction_count_test \
14 fork_cleanup_test ebb_on_child_test \
15 ebb_on_willing_child_test back_to_back_ebbs_test \
16 lost_exception_test no_handler_test
17
18all: $(PROGS)
19
20$(PROGS): ../../harness.c ../event.c ../lib.c ebb.c ebb_handler.S trace.c
21
22instruction_count_test: ../loop.S
23
24lost_exception_test: ../lib.c
25
26run_tests: all
27 @-for PROG in $(PROGS); do \
28 ./$$PROG; \
29 done;
30
31clean:
32 rm -f $(PROGS)
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/back_to_back_ebbs_test.c b/tools/testing/selftests/powerpc/pmu/ebb/back_to_back_ebbs_test.c
new file mode 100644
index 000000000000..66ea765c0e72
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/back_to_back_ebbs_test.c
@@ -0,0 +1,106 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <stdbool.h>
7#include <stdio.h>
8#include <stdlib.h>
9
10#include "ebb.h"
11
12
13#define NUMBER_OF_EBBS 50
14
15/*
16 * Test that if we overflow the counter while in the EBB handler, we take
17 * another EBB on exiting from the handler.
18 *
19 * We do this by counting with a stupidly low sample period, causing us to
20 * overflow the PMU while we're still in the EBB handler, leading to another
21 * EBB.
22 *
23 * We get out of what would otherwise be an infinite loop by leaving the
24 * counter frozen once we've taken enough EBBs.
25 */
26
27static void ebb_callee(void)
28{
29 uint64_t siar, val;
30
31 val = mfspr(SPRN_BESCR);
32 if (!(val & BESCR_PMEO)) {
33 ebb_state.stats.spurious++;
34 goto out;
35 }
36
37 ebb_state.stats.ebb_count++;
38 trace_log_counter(ebb_state.trace, ebb_state.stats.ebb_count);
39
40 /* Resets the PMC */
41 count_pmc(1, sample_period);
42
43out:
44 if (ebb_state.stats.ebb_count == NUMBER_OF_EBBS)
45 /* Reset but leave counters frozen */
46 reset_ebb_with_clear_mask(MMCR0_PMAO);
47 else
48 /* Unfreezes */
49 reset_ebb();
50
51 /* Do some stuff to chew some cycles and pop the counter */
52 siar = mfspr(SPRN_SIAR);
53 trace_log_reg(ebb_state.trace, SPRN_SIAR, siar);
54
55 val = mfspr(SPRN_PMC1);
56 trace_log_reg(ebb_state.trace, SPRN_PMC1, val);
57
58 val = mfspr(SPRN_MMCR0);
59 trace_log_reg(ebb_state.trace, SPRN_MMCR0, val);
60}
61
62int back_to_back_ebbs(void)
63{
64 struct event event;
65
66 event_init_named(&event, 0x1001e, "cycles");
67 event_leader_ebb_init(&event);
68
69 event.attr.exclude_kernel = 1;
70 event.attr.exclude_hv = 1;
71 event.attr.exclude_idle = 1;
72
73 FAIL_IF(event_open(&event));
74
75 setup_ebb_handler(ebb_callee);
76
77 FAIL_IF(ebb_event_enable(&event));
78
79 sample_period = 5;
80
81 ebb_freeze_pmcs();
82 mtspr(SPRN_PMC1, pmc_sample_period(sample_period));
83 ebb_global_enable();
84 ebb_unfreeze_pmcs();
85
86 while (ebb_state.stats.ebb_count < NUMBER_OF_EBBS)
87 FAIL_IF(core_busy_loop());
88
89 ebb_global_disable();
90 ebb_freeze_pmcs();
91
92 count_pmc(1, sample_period);
93
94 dump_ebb_state();
95
96 event_close(&event);
97
98 FAIL_IF(ebb_state.stats.ebb_count != NUMBER_OF_EBBS);
99
100 return 0;
101}
102
103int main(void)
104{
105 return test_harness(back_to_back_ebbs, "back_to_back_ebbs");
106}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/close_clears_pmcc_test.c b/tools/testing/selftests/powerpc/pmu/ebb/close_clears_pmcc_test.c
new file mode 100644
index 000000000000..0f0423dba18b
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/close_clears_pmcc_test.c
@@ -0,0 +1,59 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <stdio.h>
7#include <stdlib.h>
8#include <setjmp.h>
9#include <signal.h>
10
11#include "ebb.h"
12
13
14/*
15 * Test that closing the EBB event clears MMCR0_PMCC, preventing further access
16 * by userspace to the PMU hardware.
17 */
18
19int close_clears_pmcc(void)
20{
21 struct event event;
22
23 event_init_named(&event, 0x1001e, "cycles");
24 event_leader_ebb_init(&event);
25
26 FAIL_IF(event_open(&event));
27
28 ebb_enable_pmc_counting(1);
29 setup_ebb_handler(standard_ebb_callee);
30 ebb_global_enable();
31 FAIL_IF(ebb_event_enable(&event));
32
33 mtspr(SPRN_PMC1, pmc_sample_period(sample_period));
34
35 while (ebb_state.stats.ebb_count < 1)
36 FAIL_IF(core_busy_loop());
37
38 ebb_global_disable();
39 event_close(&event);
40
41 FAIL_IF(ebb_state.stats.ebb_count == 0);
42
43 /* The real test is here, do we take a SIGILL when writing PMU regs now
44 * that we have closed the event. We expect that we will. */
45
46 FAIL_IF(catch_sigill(write_pmc1));
47
48 /* We should still be able to read EBB regs though */
49 mfspr(SPRN_EBBHR);
50 mfspr(SPRN_EBBRR);
51 mfspr(SPRN_BESCR);
52
53 return 0;
54}
55
56int main(void)
57{
58 return test_harness(close_clears_pmcc, "close_clears_pmcc");
59}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/cpu_event_pinned_vs_ebb_test.c b/tools/testing/selftests/powerpc/pmu/ebb/cpu_event_pinned_vs_ebb_test.c
new file mode 100644
index 000000000000..d3ed64d5d6c0
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/cpu_event_pinned_vs_ebb_test.c
@@ -0,0 +1,93 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <signal.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <stdbool.h>
10#include <sys/types.h>
11#include <sys/wait.h>
12#include <unistd.h>
13
14#include "ebb.h"
15
16
17/*
18 * Tests a pinned cpu event vs an EBB - in that order. The pinned cpu event
19 * should remain and the EBB event should fail to enable.
20 */
21
22static int setup_cpu_event(struct event *event, int cpu)
23{
24 event_init_named(event, 0x400FA, "PM_RUN_INST_CMPL");
25
26 event->attr.pinned = 1;
27
28 event->attr.exclude_kernel = 1;
29 event->attr.exclude_hv = 1;
30 event->attr.exclude_idle = 1;
31
32 SKIP_IF(require_paranoia_below(1));
33 FAIL_IF(event_open_with_cpu(event, cpu));
34 FAIL_IF(event_enable(event));
35
36 return 0;
37}
38
39int cpu_event_pinned_vs_ebb(void)
40{
41 union pipe read_pipe, write_pipe;
42 struct event event;
43 int cpu, rc;
44 pid_t pid;
45
46 cpu = pick_online_cpu();
47 FAIL_IF(cpu < 0);
48 FAIL_IF(bind_to_cpu(cpu));
49
50 FAIL_IF(pipe(read_pipe.fds) == -1);
51 FAIL_IF(pipe(write_pipe.fds) == -1);
52
53 pid = fork();
54 if (pid == 0) {
55 /* NB order of pipes looks reversed */
56 exit(ebb_child(write_pipe, read_pipe));
57 }
58
59 /* We setup the cpu event first */
60 rc = setup_cpu_event(&event, cpu);
61 if (rc) {
62 kill_child_and_wait(pid);
63 return rc;
64 }
65
66 /* Signal the child to install its EBB event and wait */
67 if (sync_with_child(read_pipe, write_pipe))
68 /* If it fails, wait for it to exit */
69 goto wait;
70
71 /* Signal the child to run */
72 FAIL_IF(sync_with_child(read_pipe, write_pipe));
73
74wait:
75 /* We expect it to fail to read the event */
76 FAIL_IF(wait_for_child(pid) != 2);
77
78 FAIL_IF(event_disable(&event));
79 FAIL_IF(event_read(&event));
80
81 event_report(&event);
82
83 /* The cpu event should have run */
84 FAIL_IF(event.result.value == 0);
85 FAIL_IF(event.result.enabled != event.result.running);
86
87 return 0;
88}
89
90int main(void)
91{
92 return test_harness(cpu_event_pinned_vs_ebb, "cpu_event_pinned_vs_ebb");
93}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/cpu_event_vs_ebb_test.c b/tools/testing/selftests/powerpc/pmu/ebb/cpu_event_vs_ebb_test.c
new file mode 100644
index 000000000000..8b972c2aa392
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/cpu_event_vs_ebb_test.c
@@ -0,0 +1,89 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <signal.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <stdbool.h>
10#include <sys/types.h>
11#include <sys/wait.h>
12#include <unistd.h>
13
14#include "ebb.h"
15
16
17/*
18 * Tests a cpu event vs an EBB - in that order. The EBB should force the cpu
19 * event off the PMU.
20 */
21
22static int setup_cpu_event(struct event *event, int cpu)
23{
24 event_init_named(event, 0x400FA, "PM_RUN_INST_CMPL");
25
26 event->attr.exclude_kernel = 1;
27 event->attr.exclude_hv = 1;
28 event->attr.exclude_idle = 1;
29
30 SKIP_IF(require_paranoia_below(1));
31 FAIL_IF(event_open_with_cpu(event, cpu));
32 FAIL_IF(event_enable(event));
33
34 return 0;
35}
36
37int cpu_event_vs_ebb(void)
38{
39 union pipe read_pipe, write_pipe;
40 struct event event;
41 int cpu, rc;
42 pid_t pid;
43
44 cpu = pick_online_cpu();
45 FAIL_IF(cpu < 0);
46 FAIL_IF(bind_to_cpu(cpu));
47
48 FAIL_IF(pipe(read_pipe.fds) == -1);
49 FAIL_IF(pipe(write_pipe.fds) == -1);
50
51 pid = fork();
52 if (pid == 0) {
53 /* NB order of pipes looks reversed */
54 exit(ebb_child(write_pipe, read_pipe));
55 }
56
57 /* We setup the cpu event first */
58 rc = setup_cpu_event(&event, cpu);
59 if (rc) {
60 kill_child_and_wait(pid);
61 return rc;
62 }
63
64 /* Signal the child to install its EBB event and wait */
65 if (sync_with_child(read_pipe, write_pipe))
66 /* If it fails, wait for it to exit */
67 goto wait;
68
69 /* Signal the child to run */
70 FAIL_IF(sync_with_child(read_pipe, write_pipe));
71
72wait:
73 /* We expect the child to succeed */
74 FAIL_IF(wait_for_child(pid));
75
76 FAIL_IF(event_disable(&event));
77 FAIL_IF(event_read(&event));
78
79 event_report(&event);
80
81 /* The cpu event may have run */
82
83 return 0;
84}
85
86int main(void)
87{
88 return test_harness(cpu_event_vs_ebb, "cpu_event_vs_ebb");
89}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/cycles_test.c b/tools/testing/selftests/powerpc/pmu/ebb/cycles_test.c
new file mode 100644
index 000000000000..8590fc1bfc0d
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/cycles_test.c
@@ -0,0 +1,58 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <stdio.h>
7#include <stdlib.h>
8
9#include "ebb.h"
10
11
12/*
13 * Basic test that counts user cycles and takes EBBs.
14 */
15int cycles(void)
16{
17 struct event event;
18
19 event_init_named(&event, 0x1001e, "cycles");
20 event_leader_ebb_init(&event);
21
22 event.attr.exclude_kernel = 1;
23 event.attr.exclude_hv = 1;
24 event.attr.exclude_idle = 1;
25
26 FAIL_IF(event_open(&event));
27
28 ebb_enable_pmc_counting(1);
29 setup_ebb_handler(standard_ebb_callee);
30 ebb_global_enable();
31 FAIL_IF(ebb_event_enable(&event));
32
33 mtspr(SPRN_PMC1, pmc_sample_period(sample_period));
34
35 while (ebb_state.stats.ebb_count < 10) {
36 FAIL_IF(core_busy_loop());
37 FAIL_IF(ebb_check_mmcr0());
38 }
39
40 ebb_global_disable();
41 ebb_freeze_pmcs();
42
43 count_pmc(1, sample_period);
44
45 dump_ebb_state();
46
47 event_close(&event);
48
49 FAIL_IF(ebb_state.stats.ebb_count == 0);
50 FAIL_IF(!ebb_check_count(1, sample_period, 100));
51
52 return 0;
53}
54
55int main(void)
56{
57 return test_harness(cycles, "cycles");
58}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/cycles_with_freeze_test.c b/tools/testing/selftests/powerpc/pmu/ebb/cycles_with_freeze_test.c
new file mode 100644
index 000000000000..754b3f2008d3
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/cycles_with_freeze_test.c
@@ -0,0 +1,117 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <stdio.h>
7#include <stdlib.h>
8#include <stdbool.h>
9
10#include "ebb.h"
11
12
13/*
14 * Test of counting cycles while using MMCR0_FC (freeze counters) to only count
15 * parts of the code. This is complicated by the fact that FC is set by the
16 * hardware when the event overflows. We may take the EBB after we have set FC,
17 * so we have to be careful about whether we clear FC at the end of the EBB
18 * handler or not.
19 */
20
21static bool counters_frozen = false;
22static int ebbs_while_frozen = 0;
23
24static void ebb_callee(void)
25{
26 uint64_t mask, val;
27
28 mask = MMCR0_PMAO | MMCR0_FC;
29
30 val = mfspr(SPRN_BESCR);
31 if (!(val & BESCR_PMEO)) {
32 ebb_state.stats.spurious++;
33 goto out;
34 }
35
36 ebb_state.stats.ebb_count++;
37 trace_log_counter(ebb_state.trace, ebb_state.stats.ebb_count);
38
39 val = mfspr(SPRN_MMCR0);
40 trace_log_reg(ebb_state.trace, SPRN_MMCR0, val);
41
42 if (counters_frozen) {
43 trace_log_string(ebb_state.trace, "frozen");
44 ebbs_while_frozen++;
45 mask &= ~MMCR0_FC;
46 }
47
48 count_pmc(1, sample_period);
49out:
50 reset_ebb_with_clear_mask(mask);
51}
52
53int cycles_with_freeze(void)
54{
55 struct event event;
56 uint64_t val;
57 bool fc_cleared;
58
59 event_init_named(&event, 0x1001e, "cycles");
60 event_leader_ebb_init(&event);
61
62 event.attr.exclude_kernel = 1;
63 event.attr.exclude_hv = 1;
64 event.attr.exclude_idle = 1;
65
66 FAIL_IF(event_open(&event));
67
68 setup_ebb_handler(ebb_callee);
69 ebb_global_enable();
70 FAIL_IF(ebb_event_enable(&event));
71
72 mtspr(SPRN_PMC1, pmc_sample_period(sample_period));
73
74 fc_cleared = false;
75
76 /* Make sure we loop until we take at least one EBB */
77 while ((ebb_state.stats.ebb_count < 20 && !fc_cleared) ||
78 ebb_state.stats.ebb_count < 1)
79 {
80 counters_frozen = false;
81 mb();
82 mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_FC);
83
84 FAIL_IF(core_busy_loop());
85
86 counters_frozen = true;
87 mb();
88 mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) | MMCR0_FC);
89
90 val = mfspr(SPRN_MMCR0);
91 if (! (val & MMCR0_FC)) {
92 printf("Outside of loop, FC NOT set MMCR0 0x%lx\n", val);
93 fc_cleared = true;
94 }
95 }
96
97 ebb_global_disable();
98 ebb_freeze_pmcs();
99
100 count_pmc(1, sample_period);
101
102 dump_ebb_state();
103
104 printf("EBBs while frozen %d\n", ebbs_while_frozen);
105
106 event_close(&event);
107
108 FAIL_IF(ebb_state.stats.ebb_count == 0);
109 FAIL_IF(fc_cleared);
110
111 return 0;
112}
113
114int main(void)
115{
116 return test_harness(cycles_with_freeze, "cycles_with_freeze");
117}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/ebb.c b/tools/testing/selftests/powerpc/pmu/ebb/ebb.c
new file mode 100644
index 000000000000..1b46be94b64c
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/ebb.c
@@ -0,0 +1,727 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#define _GNU_SOURCE /* For CPU_ZERO etc. */
7
8#include <sched.h>
9#include <sys/wait.h>
10#include <setjmp.h>
11#include <signal.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <sys/ioctl.h>
16
17#include "trace.h"
18#include "reg.h"
19#include "ebb.h"
20
21
22void (*ebb_user_func)(void);
23
24void ebb_hook(void)
25{
26 if (ebb_user_func)
27 ebb_user_func();
28}
29
30struct ebb_state ebb_state;
31
32u64 sample_period = 0x40000000ull;
33
34void reset_ebb_with_clear_mask(unsigned long mmcr0_clear_mask)
35{
36 u64 val;
37
38 /* 2) clear MMCR0[PMAO] - docs say BESCR[PMEO] should do this */
39 /* 3) set MMCR0[PMAE] - docs say BESCR[PME] should do this */
40 val = mfspr(SPRN_MMCR0);
41 mtspr(SPRN_MMCR0, (val & ~mmcr0_clear_mask) | MMCR0_PMAE);
42
43 /* 4) clear BESCR[PMEO] */
44 mtspr(SPRN_BESCRR, BESCR_PMEO);
45
46 /* 5) set BESCR[PME] */
47 mtspr(SPRN_BESCRS, BESCR_PME);
48
49 /* 6) rfebb 1 - done in our caller */
50}
51
52void reset_ebb(void)
53{
54 reset_ebb_with_clear_mask(MMCR0_PMAO | MMCR0_FC);
55}
56
57/* Called outside of the EBB handler to check MMCR0 is sane */
58int ebb_check_mmcr0(void)
59{
60 u64 val;
61
62 val = mfspr(SPRN_MMCR0);
63 if ((val & (MMCR0_FC | MMCR0_PMAO)) == MMCR0_FC) {
64 /* It's OK if we see FC & PMAO, but not FC by itself */
65 printf("Outside of loop, only FC set 0x%llx\n", val);
66 return 1;
67 }
68
69 return 0;
70}
71
72bool ebb_check_count(int pmc, u64 sample_period, int fudge)
73{
74 u64 count, upper, lower;
75
76 count = ebb_state.stats.pmc_count[PMC_INDEX(pmc)];
77
78 lower = ebb_state.stats.ebb_count * (sample_period - fudge);
79
80 if (count < lower) {
81 printf("PMC%d count (0x%llx) below lower limit 0x%llx (-0x%llx)\n",
82 pmc, count, lower, lower - count);
83 return false;
84 }
85
86 upper = ebb_state.stats.ebb_count * (sample_period + fudge);
87
88 if (count > upper) {
89 printf("PMC%d count (0x%llx) above upper limit 0x%llx (+0x%llx)\n",
90 pmc, count, upper, count - upper);
91 return false;
92 }
93
94 printf("PMC%d count (0x%llx) is between 0x%llx and 0x%llx delta +0x%llx/-0x%llx\n",
95 pmc, count, lower, upper, count - lower, upper - count);
96
97 return true;
98}
99
100void standard_ebb_callee(void)
101{
102 int found, i;
103 u64 val;
104
105 val = mfspr(SPRN_BESCR);
106 if (!(val & BESCR_PMEO)) {
107 ebb_state.stats.spurious++;
108 goto out;
109 }
110
111 ebb_state.stats.ebb_count++;
112 trace_log_counter(ebb_state.trace, ebb_state.stats.ebb_count);
113
114 val = mfspr(SPRN_MMCR0);
115 trace_log_reg(ebb_state.trace, SPRN_MMCR0, val);
116
117 found = 0;
118 for (i = 1; i <= 6; i++) {
119 if (ebb_state.pmc_enable[PMC_INDEX(i)])
120 found += count_pmc(i, sample_period);
121 }
122
123 if (!found)
124 ebb_state.stats.no_overflow++;
125
126out:
127 reset_ebb();
128}
129
130extern void ebb_handler(void);
131
132void setup_ebb_handler(void (*callee)(void))
133{
134 u64 entry;
135
136#if defined(_CALL_ELF) && _CALL_ELF == 2
137 entry = (u64)ebb_handler;
138#else
139 struct opd
140 {
141 u64 entry;
142 u64 toc;
143 } *opd;
144
145 opd = (struct opd *)ebb_handler;
146 entry = opd->entry;
147#endif
148 printf("EBB Handler is at %#llx\n", entry);
149
150 ebb_user_func = callee;
151
152 /* Ensure ebb_user_func is set before we set the handler */
153 mb();
154 mtspr(SPRN_EBBHR, entry);
155
156 /* Make sure the handler is set before we return */
157 mb();
158}
159
160void clear_ebb_stats(void)
161{
162 memset(&ebb_state.stats, 0, sizeof(ebb_state.stats));
163}
164
165void dump_summary_ebb_state(void)
166{
167 printf("ebb_state:\n" \
168 " ebb_count = %d\n" \
169 " spurious = %d\n" \
170 " negative = %d\n" \
171 " no_overflow = %d\n" \
172 " pmc[1] count = 0x%llx\n" \
173 " pmc[2] count = 0x%llx\n" \
174 " pmc[3] count = 0x%llx\n" \
175 " pmc[4] count = 0x%llx\n" \
176 " pmc[5] count = 0x%llx\n" \
177 " pmc[6] count = 0x%llx\n",
178 ebb_state.stats.ebb_count, ebb_state.stats.spurious,
179 ebb_state.stats.negative, ebb_state.stats.no_overflow,
180 ebb_state.stats.pmc_count[0], ebb_state.stats.pmc_count[1],
181 ebb_state.stats.pmc_count[2], ebb_state.stats.pmc_count[3],
182 ebb_state.stats.pmc_count[4], ebb_state.stats.pmc_count[5]);
183}
184
185static char *decode_mmcr0(u32 value)
186{
187 static char buf[16];
188
189 buf[0] = '\0';
190
191 if (value & (1 << 31))
192 strcat(buf, "FC ");
193 if (value & (1 << 26))
194 strcat(buf, "PMAE ");
195 if (value & (1 << 7))
196 strcat(buf, "PMAO ");
197
198 return buf;
199}
200
201static char *decode_bescr(u64 value)
202{
203 static char buf[16];
204
205 buf[0] = '\0';
206
207 if (value & (1ull << 63))
208 strcat(buf, "GE ");
209 if (value & (1ull << 32))
210 strcat(buf, "PMAE ");
211 if (value & 1)
212 strcat(buf, "PMAO ");
213
214 return buf;
215}
216
217void dump_ebb_hw_state(void)
218{
219 u64 bescr;
220 u32 mmcr0;
221
222 mmcr0 = mfspr(SPRN_MMCR0);
223 bescr = mfspr(SPRN_BESCR);
224
225 printf("HW state:\n" \
226 "MMCR0 0x%016x %s\n" \
227 "EBBHR 0x%016lx\n" \
228 "BESCR 0x%016llx %s\n" \
229 "PMC1 0x%016lx\n" \
230 "PMC2 0x%016lx\n" \
231 "PMC3 0x%016lx\n" \
232 "PMC4 0x%016lx\n" \
233 "PMC5 0x%016lx\n" \
234 "PMC6 0x%016lx\n" \
235 "SIAR 0x%016lx\n",
236 mmcr0, decode_mmcr0(mmcr0), mfspr(SPRN_EBBHR), bescr,
237 decode_bescr(bescr), mfspr(SPRN_PMC1), mfspr(SPRN_PMC2),
238 mfspr(SPRN_PMC3), mfspr(SPRN_PMC4), mfspr(SPRN_PMC5),
239 mfspr(SPRN_PMC6), mfspr(SPRN_SIAR));
240}
241
242void dump_ebb_state(void)
243{
244 dump_summary_ebb_state();
245
246 dump_ebb_hw_state();
247
248 trace_buffer_print(ebb_state.trace);
249}
250
251int count_pmc(int pmc, uint32_t sample_period)
252{
253 uint32_t start_value;
254 u64 val;
255
256 /* 0) Read PMC */
257 start_value = pmc_sample_period(sample_period);
258
259 val = read_pmc(pmc);
260 if (val < start_value)
261 ebb_state.stats.negative++;
262 else
263 ebb_state.stats.pmc_count[PMC_INDEX(pmc)] += val - start_value;
264
265 trace_log_reg(ebb_state.trace, SPRN_PMC1 + pmc - 1, val);
266
267 /* 1) Reset PMC */
268 write_pmc(pmc, start_value);
269
270 /* Report if we overflowed */
271 return val >= COUNTER_OVERFLOW;
272}
273
274int ebb_event_enable(struct event *e)
275{
276 int rc;
277
278 /* Ensure any SPR writes are ordered vs us */
279 mb();
280
281 rc = ioctl(e->fd, PERF_EVENT_IOC_ENABLE);
282 if (rc)
283 return rc;
284
285 rc = event_read(e);
286
287 /* Ditto */
288 mb();
289
290 return rc;
291}
292
293void ebb_freeze_pmcs(void)
294{
295 mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) | MMCR0_FC);
296 mb();
297}
298
299void ebb_unfreeze_pmcs(void)
300{
301 /* Unfreeze counters */
302 mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_FC);
303 mb();
304}
305
306void ebb_global_enable(void)
307{
308 /* Enable EBBs globally and PMU EBBs */
309 mtspr(SPRN_BESCR, 0x8000000100000000ull);
310 mb();
311}
312
313void ebb_global_disable(void)
314{
315 /* Disable EBBs & freeze counters, events are still scheduled */
316 mtspr(SPRN_BESCRR, BESCR_PME);
317 mb();
318}
319
320void event_ebb_init(struct event *e)
321{
322 e->attr.config |= (1ull << 63);
323}
324
325void event_bhrb_init(struct event *e, unsigned ifm)
326{
327 e->attr.config |= (1ull << 62) | ((u64)ifm << 60);
328}
329
330void event_leader_ebb_init(struct event *e)
331{
332 event_ebb_init(e);
333
334 e->attr.exclusive = 1;
335 e->attr.pinned = 1;
336}
337
338int core_busy_loop(void)
339{
340 int rc;
341
342 asm volatile (
343 "li 3, 0x3030\n"
344 "std 3, -96(1)\n"
345 "li 4, 0x4040\n"
346 "std 4, -104(1)\n"
347 "li 5, 0x5050\n"
348 "std 5, -112(1)\n"
349 "li 6, 0x6060\n"
350 "std 6, -120(1)\n"
351 "li 7, 0x7070\n"
352 "std 7, -128(1)\n"
353 "li 8, 0x0808\n"
354 "std 8, -136(1)\n"
355 "li 9, 0x0909\n"
356 "std 9, -144(1)\n"
357 "li 10, 0x1010\n"
358 "std 10, -152(1)\n"
359 "li 11, 0x1111\n"
360 "std 11, -160(1)\n"
361 "li 14, 0x1414\n"
362 "std 14, -168(1)\n"
363 "li 15, 0x1515\n"
364 "std 15, -176(1)\n"
365 "li 16, 0x1616\n"
366 "std 16, -184(1)\n"
367 "li 17, 0x1717\n"
368 "std 17, -192(1)\n"
369 "li 18, 0x1818\n"
370 "std 18, -200(1)\n"
371 "li 19, 0x1919\n"
372 "std 19, -208(1)\n"
373 "li 20, 0x2020\n"
374 "std 20, -216(1)\n"
375 "li 21, 0x2121\n"
376 "std 21, -224(1)\n"
377 "li 22, 0x2222\n"
378 "std 22, -232(1)\n"
379 "li 23, 0x2323\n"
380 "std 23, -240(1)\n"
381 "li 24, 0x2424\n"
382 "std 24, -248(1)\n"
383 "li 25, 0x2525\n"
384 "std 25, -256(1)\n"
385 "li 26, 0x2626\n"
386 "std 26, -264(1)\n"
387 "li 27, 0x2727\n"
388 "std 27, -272(1)\n"
389 "li 28, 0x2828\n"
390 "std 28, -280(1)\n"
391 "li 29, 0x2929\n"
392 "std 29, -288(1)\n"
393 "li 30, 0x3030\n"
394 "li 31, 0x3131\n"
395
396 "li 3, 0\n"
397 "0: "
398 "addi 3, 3, 1\n"
399 "cmpwi 3, 100\n"
400 "blt 0b\n"
401
402 /* Return 1 (fail) unless we get through all the checks */
403 "li 0, 1\n"
404
405 /* Check none of our registers have been corrupted */
406 "cmpwi 4, 0x4040\n"
407 "bne 1f\n"
408 "cmpwi 5, 0x5050\n"
409 "bne 1f\n"
410 "cmpwi 6, 0x6060\n"
411 "bne 1f\n"
412 "cmpwi 7, 0x7070\n"
413 "bne 1f\n"
414 "cmpwi 8, 0x0808\n"
415 "bne 1f\n"
416 "cmpwi 9, 0x0909\n"
417 "bne 1f\n"
418 "cmpwi 10, 0x1010\n"
419 "bne 1f\n"
420 "cmpwi 11, 0x1111\n"
421 "bne 1f\n"
422 "cmpwi 14, 0x1414\n"
423 "bne 1f\n"
424 "cmpwi 15, 0x1515\n"
425 "bne 1f\n"
426 "cmpwi 16, 0x1616\n"
427 "bne 1f\n"
428 "cmpwi 17, 0x1717\n"
429 "bne 1f\n"
430 "cmpwi 18, 0x1818\n"
431 "bne 1f\n"
432 "cmpwi 19, 0x1919\n"
433 "bne 1f\n"
434 "cmpwi 20, 0x2020\n"
435 "bne 1f\n"
436 "cmpwi 21, 0x2121\n"
437 "bne 1f\n"
438 "cmpwi 22, 0x2222\n"
439 "bne 1f\n"
440 "cmpwi 23, 0x2323\n"
441 "bne 1f\n"
442 "cmpwi 24, 0x2424\n"
443 "bne 1f\n"
444 "cmpwi 25, 0x2525\n"
445 "bne 1f\n"
446 "cmpwi 26, 0x2626\n"
447 "bne 1f\n"
448 "cmpwi 27, 0x2727\n"
449 "bne 1f\n"
450 "cmpwi 28, 0x2828\n"
451 "bne 1f\n"
452 "cmpwi 29, 0x2929\n"
453 "bne 1f\n"
454 "cmpwi 30, 0x3030\n"
455 "bne 1f\n"
456 "cmpwi 31, 0x3131\n"
457 "bne 1f\n"
458
459 /* Load junk into all our registers before we reload them from the stack. */
460 "li 3, 0xde\n"
461 "li 4, 0xad\n"
462 "li 5, 0xbe\n"
463 "li 6, 0xef\n"
464 "li 7, 0xde\n"
465 "li 8, 0xad\n"
466 "li 9, 0xbe\n"
467 "li 10, 0xef\n"
468 "li 11, 0xde\n"
469 "li 14, 0xad\n"
470 "li 15, 0xbe\n"
471 "li 16, 0xef\n"
472 "li 17, 0xde\n"
473 "li 18, 0xad\n"
474 "li 19, 0xbe\n"
475 "li 20, 0xef\n"
476 "li 21, 0xde\n"
477 "li 22, 0xad\n"
478 "li 23, 0xbe\n"
479 "li 24, 0xef\n"
480 "li 25, 0xde\n"
481 "li 26, 0xad\n"
482 "li 27, 0xbe\n"
483 "li 28, 0xef\n"
484 "li 29, 0xdd\n"
485
486 "ld 3, -96(1)\n"
487 "cmpwi 3, 0x3030\n"
488 "bne 1f\n"
489 "ld 4, -104(1)\n"
490 "cmpwi 4, 0x4040\n"
491 "bne 1f\n"
492 "ld 5, -112(1)\n"
493 "cmpwi 5, 0x5050\n"
494 "bne 1f\n"
495 "ld 6, -120(1)\n"
496 "cmpwi 6, 0x6060\n"
497 "bne 1f\n"
498 "ld 7, -128(1)\n"
499 "cmpwi 7, 0x7070\n"
500 "bne 1f\n"
501 "ld 8, -136(1)\n"
502 "cmpwi 8, 0x0808\n"
503 "bne 1f\n"
504 "ld 9, -144(1)\n"
505 "cmpwi 9, 0x0909\n"
506 "bne 1f\n"
507 "ld 10, -152(1)\n"
508 "cmpwi 10, 0x1010\n"
509 "bne 1f\n"
510 "ld 11, -160(1)\n"
511 "cmpwi 11, 0x1111\n"
512 "bne 1f\n"
513 "ld 14, -168(1)\n"
514 "cmpwi 14, 0x1414\n"
515 "bne 1f\n"
516 "ld 15, -176(1)\n"
517 "cmpwi 15, 0x1515\n"
518 "bne 1f\n"
519 "ld 16, -184(1)\n"
520 "cmpwi 16, 0x1616\n"
521 "bne 1f\n"
522 "ld 17, -192(1)\n"
523 "cmpwi 17, 0x1717\n"
524 "bne 1f\n"
525 "ld 18, -200(1)\n"
526 "cmpwi 18, 0x1818\n"
527 "bne 1f\n"
528 "ld 19, -208(1)\n"
529 "cmpwi 19, 0x1919\n"
530 "bne 1f\n"
531 "ld 20, -216(1)\n"
532 "cmpwi 20, 0x2020\n"
533 "bne 1f\n"
534 "ld 21, -224(1)\n"
535 "cmpwi 21, 0x2121\n"
536 "bne 1f\n"
537 "ld 22, -232(1)\n"
538 "cmpwi 22, 0x2222\n"
539 "bne 1f\n"
540 "ld 23, -240(1)\n"
541 "cmpwi 23, 0x2323\n"
542 "bne 1f\n"
543 "ld 24, -248(1)\n"
544 "cmpwi 24, 0x2424\n"
545 "bne 1f\n"
546 "ld 25, -256(1)\n"
547 "cmpwi 25, 0x2525\n"
548 "bne 1f\n"
549 "ld 26, -264(1)\n"
550 "cmpwi 26, 0x2626\n"
551 "bne 1f\n"
552 "ld 27, -272(1)\n"
553 "cmpwi 27, 0x2727\n"
554 "bne 1f\n"
555 "ld 28, -280(1)\n"
556 "cmpwi 28, 0x2828\n"
557 "bne 1f\n"
558 "ld 29, -288(1)\n"
559 "cmpwi 29, 0x2929\n"
560 "bne 1f\n"
561
562 /* Load 0 (success) to return */
563 "li 0, 0\n"
564
565 "1: mr %0, 0\n"
566
567 : "=r" (rc)
568 : /* no inputs */
569 : "3", "4", "5", "6", "7", "8", "9", "10", "11", "14",
570 "15", "16", "17", "18", "19", "20", "21", "22", "23",
571 "24", "25", "26", "27", "28", "29", "30", "31",
572 "memory"
573 );
574
575 return rc;
576}
577
578int core_busy_loop_with_freeze(void)
579{
580 int rc;
581
582 mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_FC);
583 rc = core_busy_loop();
584 mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) | MMCR0_FC);
585
586 return rc;
587}
588
589int ebb_child(union pipe read_pipe, union pipe write_pipe)
590{
591 struct event event;
592 uint64_t val;
593
594 FAIL_IF(wait_for_parent(read_pipe));
595
596 event_init_named(&event, 0x1001e, "cycles");
597 event_leader_ebb_init(&event);
598
599 event.attr.exclude_kernel = 1;
600 event.attr.exclude_hv = 1;
601 event.attr.exclude_idle = 1;
602
603 FAIL_IF(event_open(&event));
604
605 ebb_enable_pmc_counting(1);
606 setup_ebb_handler(standard_ebb_callee);
607 ebb_global_enable();
608
609 FAIL_IF(event_enable(&event));
610
611 if (event_read(&event)) {
612 /*
613 * Some tests expect to fail here, so don't report an error on
614 * this line, and return a distinguisable error code. Tell the
615 * parent an error happened.
616 */
617 notify_parent_of_error(write_pipe);
618 return 2;
619 }
620
621 mtspr(SPRN_PMC1, pmc_sample_period(sample_period));
622
623 FAIL_IF(notify_parent(write_pipe));
624 FAIL_IF(wait_for_parent(read_pipe));
625 FAIL_IF(notify_parent(write_pipe));
626
627 while (ebb_state.stats.ebb_count < 20) {
628 FAIL_IF(core_busy_loop());
629
630 /* To try and hit SIGILL case */
631 val = mfspr(SPRN_MMCRA);
632 val |= mfspr(SPRN_MMCR2);
633 val |= mfspr(SPRN_MMCR0);
634 }
635
636 ebb_global_disable();
637 ebb_freeze_pmcs();
638
639 count_pmc(1, sample_period);
640
641 dump_ebb_state();
642
643 event_close(&event);
644
645 FAIL_IF(ebb_state.stats.ebb_count == 0);
646
647 return 0;
648}
649
650static jmp_buf setjmp_env;
651
652static void sigill_handler(int signal)
653{
654 printf("Took sigill\n");
655 longjmp(setjmp_env, 1);
656}
657
658static struct sigaction sigill_action = {
659 .sa_handler = sigill_handler,
660};
661
662int catch_sigill(void (*func)(void))
663{
664 if (sigaction(SIGILL, &sigill_action, NULL)) {
665 perror("sigaction");
666 return 1;
667 }
668
669 if (setjmp(setjmp_env) == 0) {
670 func();
671 return 1;
672 }
673
674 return 0;
675}
676
677void write_pmc1(void)
678{
679 mtspr(SPRN_PMC1, 0);
680}
681
682void write_pmc(int pmc, u64 value)
683{
684 switch (pmc) {
685 case 1: mtspr(SPRN_PMC1, value); break;
686 case 2: mtspr(SPRN_PMC2, value); break;
687 case 3: mtspr(SPRN_PMC3, value); break;
688 case 4: mtspr(SPRN_PMC4, value); break;
689 case 5: mtspr(SPRN_PMC5, value); break;
690 case 6: mtspr(SPRN_PMC6, value); break;
691 }
692}
693
694u64 read_pmc(int pmc)
695{
696 switch (pmc) {
697 case 1: return mfspr(SPRN_PMC1);
698 case 2: return mfspr(SPRN_PMC2);
699 case 3: return mfspr(SPRN_PMC3);
700 case 4: return mfspr(SPRN_PMC4);
701 case 5: return mfspr(SPRN_PMC5);
702 case 6: return mfspr(SPRN_PMC6);
703 }
704
705 return 0;
706}
707
708static void term_handler(int signal)
709{
710 dump_summary_ebb_state();
711 dump_ebb_hw_state();
712 abort();
713}
714
715struct sigaction term_action = {
716 .sa_handler = term_handler,
717};
718
719static void __attribute__((constructor)) ebb_init(void)
720{
721 clear_ebb_stats();
722
723 if (sigaction(SIGTERM, &term_action, NULL))
724 perror("sigaction");
725
726 ebb_state.trace = trace_buffer_allocate(1 * 1024 * 1024);
727}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/ebb.h b/tools/testing/selftests/powerpc/pmu/ebb/ebb.h
new file mode 100644
index 000000000000..e62bde05bf78
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/ebb.h
@@ -0,0 +1,78 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#ifndef _SELFTESTS_POWERPC_PMU_EBB_EBB_H
7#define _SELFTESTS_POWERPC_PMU_EBB_EBB_H
8
9#include "../event.h"
10#include "../lib.h"
11#include "trace.h"
12#include "reg.h"
13
14#define PMC_INDEX(pmc) ((pmc)-1)
15
16#define NUM_PMC_VALUES 128
17
18struct ebb_state
19{
20 struct {
21 u64 pmc_count[6];
22 volatile int ebb_count;
23 int spurious;
24 int negative;
25 int no_overflow;
26 } stats;
27
28 bool pmc_enable[6];
29 struct trace_buffer *trace;
30};
31
32extern struct ebb_state ebb_state;
33
34#define COUNTER_OVERFLOW 0x80000000ull
35
36static inline uint32_t pmc_sample_period(uint32_t value)
37{
38 return COUNTER_OVERFLOW - value;
39}
40
41static inline void ebb_enable_pmc_counting(int pmc)
42{
43 ebb_state.pmc_enable[PMC_INDEX(pmc)] = true;
44}
45
46bool ebb_check_count(int pmc, u64 sample_period, int fudge);
47void event_leader_ebb_init(struct event *e);
48void event_ebb_init(struct event *e);
49void event_bhrb_init(struct event *e, unsigned ifm);
50void setup_ebb_handler(void (*callee)(void));
51void standard_ebb_callee(void);
52int ebb_event_enable(struct event *e);
53void ebb_global_enable(void);
54void ebb_global_disable(void);
55void ebb_freeze_pmcs(void);
56void ebb_unfreeze_pmcs(void);
57void event_ebb_init(struct event *e);
58void event_leader_ebb_init(struct event *e);
59int count_pmc(int pmc, uint32_t sample_period);
60void dump_ebb_state(void);
61void dump_summary_ebb_state(void);
62void dump_ebb_hw_state(void);
63void clear_ebb_stats(void);
64void write_pmc(int pmc, u64 value);
65u64 read_pmc(int pmc);
66void reset_ebb_with_clear_mask(unsigned long mmcr0_clear_mask);
67void reset_ebb(void);
68int ebb_check_mmcr0(void);
69
70extern u64 sample_period;
71
72int core_busy_loop(void);
73int core_busy_loop_with_freeze(void);
74int ebb_child(union pipe read_pipe, union pipe write_pipe);
75int catch_sigill(void (*func)(void));
76void write_pmc1(void);
77
78#endif /* _SELFTESTS_POWERPC_PMU_EBB_EBB_H */
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/ebb_handler.S b/tools/testing/selftests/powerpc/pmu/ebb/ebb_handler.S
new file mode 100644
index 000000000000..14274ea206e5
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/ebb_handler.S
@@ -0,0 +1,365 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <ppc-asm.h>
7#include "reg.h"
8
9
10/* ppc-asm.h defines most of the reg aliases, but not r1/r2. */
11#define r1 1
12#define r2 2
13
14#define RFEBB .long 0x4c000924
15
16/* Stack layout:
17 *
18 * ^
19 * User stack |
20 * Back chain ------+ <- r1 <-------+
21 * ... |
22 * Red zone / ABI Gap |
23 * ... |
24 * vr63 <+ |
25 * vr0 | |
26 * VSCR | |
27 * FSCR | |
28 * r31 | Save area |
29 * r0 | |
30 * XER | |
31 * CTR | |
32 * LR | |
33 * CCR <+ |
34 * ... <+ |
35 * LR | Caller frame |
36 * CCR | |
37 * Back chain <+ <- updated r1 --------+
38 *
39 */
40
41#if defined(_CALL_ELF) && _CALL_ELF == 2
42#define ABIGAP 512
43#else
44#define ABIGAP 288
45#endif
46
47#define NR_GPR 32
48#define NR_SPR 6
49#define NR_VSR 64
50
51#define SAVE_AREA ((NR_GPR + NR_SPR) * 8 + (NR_VSR * 16))
52#define CALLER_FRAME 112
53
54#define STACK_FRAME (ABIGAP + SAVE_AREA + CALLER_FRAME)
55
56#define CCR_SAVE (CALLER_FRAME)
57#define LR_SAVE (CCR_SAVE + 8)
58#define CTR_SAVE (LR_SAVE + 8)
59#define XER_SAVE (CTR_SAVE + 8)
60#define GPR_SAVE(n) (XER_SAVE + 8 + (8 * n))
61#define FSCR_SAVE (GPR_SAVE(31) + 8)
62#define VSCR_SAVE (FSCR_SAVE + 8)
63#define VSR_SAVE(n) (VSCR_SAVE + 8 + (16 * n))
64
65#define SAVE_GPR(n) std n,GPR_SAVE(n)(r1)
66#define REST_GPR(n) ld n,GPR_SAVE(n)(r1)
67#define TRASH_GPR(n) lis n,0xaaaa
68
69#define SAVE_VSR(n, b) li b, VSR_SAVE(n); stxvd2x n,b,r1
70#define LOAD_VSR(n, b) li b, VSR_SAVE(n); lxvd2x n,b,r1
71
72#define LOAD_REG_IMMEDIATE(reg,expr) \
73 lis reg,(expr)@highest; \
74 ori reg,reg,(expr)@higher; \
75 rldicr reg,reg,32,31; \
76 oris reg,reg,(expr)@h; \
77 ori reg,reg,(expr)@l;
78
79
80#if defined(_CALL_ELF) && _CALL_ELF == 2
81#define ENTRY_POINT(name) \
82 .type FUNC_NAME(name),@function; \
83 .globl FUNC_NAME(name); \
84 FUNC_NAME(name):
85
86#define RESTORE_TOC(name) \
87 /* Restore our TOC pointer using our entry point */ \
88 LOAD_REG_IMMEDIATE(r12, name) \
890: addis r2,r12,(.TOC.-0b)@ha; \
90 addi r2,r2,(.TOC.-0b)@l;
91
92#else
93#define ENTRY_POINT(name) FUNC_START(name)
94#define RESTORE_TOC(name) \
95 /* Restore our TOC pointer via our opd entry */ \
96 LOAD_REG_IMMEDIATE(r2, name) \
97 ld r2,8(r2);
98#endif
99
100 .text
101
102ENTRY_POINT(ebb_handler)
103 stdu r1,-STACK_FRAME(r1)
104 SAVE_GPR(0)
105 mflr r0
106 std r0,LR_SAVE(r1)
107 mfcr r0
108 std r0,CCR_SAVE(r1)
109 mfctr r0
110 std r0,CTR_SAVE(r1)
111 mfxer r0
112 std r0,XER_SAVE(r1)
113 SAVE_GPR(2)
114 SAVE_GPR(3)
115 SAVE_GPR(4)
116 SAVE_GPR(5)
117 SAVE_GPR(6)
118 SAVE_GPR(7)
119 SAVE_GPR(8)
120 SAVE_GPR(9)
121 SAVE_GPR(10)
122 SAVE_GPR(11)
123 SAVE_GPR(12)
124 SAVE_GPR(13)
125 SAVE_GPR(14)
126 SAVE_GPR(15)
127 SAVE_GPR(16)
128 SAVE_GPR(17)
129 SAVE_GPR(18)
130 SAVE_GPR(19)
131 SAVE_GPR(20)
132 SAVE_GPR(21)
133 SAVE_GPR(22)
134 SAVE_GPR(23)
135 SAVE_GPR(24)
136 SAVE_GPR(25)
137 SAVE_GPR(26)
138 SAVE_GPR(27)
139 SAVE_GPR(28)
140 SAVE_GPR(29)
141 SAVE_GPR(30)
142 SAVE_GPR(31)
143 SAVE_VSR(0, r3)
144 mffs f0
145 stfd f0, FSCR_SAVE(r1)
146 mfvscr f0
147 stfd f0, VSCR_SAVE(r1)
148 SAVE_VSR(1, r3)
149 SAVE_VSR(2, r3)
150 SAVE_VSR(3, r3)
151 SAVE_VSR(4, r3)
152 SAVE_VSR(5, r3)
153 SAVE_VSR(6, r3)
154 SAVE_VSR(7, r3)
155 SAVE_VSR(8, r3)
156 SAVE_VSR(9, r3)
157 SAVE_VSR(10, r3)
158 SAVE_VSR(11, r3)
159 SAVE_VSR(12, r3)
160 SAVE_VSR(13, r3)
161 SAVE_VSR(14, r3)
162 SAVE_VSR(15, r3)
163 SAVE_VSR(16, r3)
164 SAVE_VSR(17, r3)
165 SAVE_VSR(18, r3)
166 SAVE_VSR(19, r3)
167 SAVE_VSR(20, r3)
168 SAVE_VSR(21, r3)
169 SAVE_VSR(22, r3)
170 SAVE_VSR(23, r3)
171 SAVE_VSR(24, r3)
172 SAVE_VSR(25, r3)
173 SAVE_VSR(26, r3)
174 SAVE_VSR(27, r3)
175 SAVE_VSR(28, r3)
176 SAVE_VSR(29, r3)
177 SAVE_VSR(30, r3)
178 SAVE_VSR(31, r3)
179 SAVE_VSR(32, r3)
180 SAVE_VSR(33, r3)
181 SAVE_VSR(34, r3)
182 SAVE_VSR(35, r3)
183 SAVE_VSR(36, r3)
184 SAVE_VSR(37, r3)
185 SAVE_VSR(38, r3)
186 SAVE_VSR(39, r3)
187 SAVE_VSR(40, r3)
188 SAVE_VSR(41, r3)
189 SAVE_VSR(42, r3)
190 SAVE_VSR(43, r3)
191 SAVE_VSR(44, r3)
192 SAVE_VSR(45, r3)
193 SAVE_VSR(46, r3)
194 SAVE_VSR(47, r3)
195 SAVE_VSR(48, r3)
196 SAVE_VSR(49, r3)
197 SAVE_VSR(50, r3)
198 SAVE_VSR(51, r3)
199 SAVE_VSR(52, r3)
200 SAVE_VSR(53, r3)
201 SAVE_VSR(54, r3)
202 SAVE_VSR(55, r3)
203 SAVE_VSR(56, r3)
204 SAVE_VSR(57, r3)
205 SAVE_VSR(58, r3)
206 SAVE_VSR(59, r3)
207 SAVE_VSR(60, r3)
208 SAVE_VSR(61, r3)
209 SAVE_VSR(62, r3)
210 SAVE_VSR(63, r3)
211
212 TRASH_GPR(2)
213 TRASH_GPR(3)
214 TRASH_GPR(4)
215 TRASH_GPR(5)
216 TRASH_GPR(6)
217 TRASH_GPR(7)
218 TRASH_GPR(8)
219 TRASH_GPR(9)
220 TRASH_GPR(10)
221 TRASH_GPR(11)
222 TRASH_GPR(12)
223 TRASH_GPR(14)
224 TRASH_GPR(15)
225 TRASH_GPR(16)
226 TRASH_GPR(17)
227 TRASH_GPR(18)
228 TRASH_GPR(19)
229 TRASH_GPR(20)
230 TRASH_GPR(21)
231 TRASH_GPR(22)
232 TRASH_GPR(23)
233 TRASH_GPR(24)
234 TRASH_GPR(25)
235 TRASH_GPR(26)
236 TRASH_GPR(27)
237 TRASH_GPR(28)
238 TRASH_GPR(29)
239 TRASH_GPR(30)
240 TRASH_GPR(31)
241
242 RESTORE_TOC(ebb_handler)
243
244 /*
245 * r13 is our TLS pointer. We leave whatever value was in there when the
246 * EBB fired. That seems to be OK because once set the TLS pointer is not
247 * changed - but presumably that could change in future.
248 */
249
250 bl ebb_hook
251 nop
252
253 /* r2 may be changed here but we don't care */
254
255 lfd f0, FSCR_SAVE(r1)
256 mtfsf 0xff,f0
257 lfd f0, VSCR_SAVE(r1)
258 mtvscr f0
259 LOAD_VSR(0, r3)
260 LOAD_VSR(1, r3)
261 LOAD_VSR(2, r3)
262 LOAD_VSR(3, r3)
263 LOAD_VSR(4, r3)
264 LOAD_VSR(5, r3)
265 LOAD_VSR(6, r3)
266 LOAD_VSR(7, r3)
267 LOAD_VSR(8, r3)
268 LOAD_VSR(9, r3)
269 LOAD_VSR(10, r3)
270 LOAD_VSR(11, r3)
271 LOAD_VSR(12, r3)
272 LOAD_VSR(13, r3)
273 LOAD_VSR(14, r3)
274 LOAD_VSR(15, r3)
275 LOAD_VSR(16, r3)
276 LOAD_VSR(17, r3)
277 LOAD_VSR(18, r3)
278 LOAD_VSR(19, r3)
279 LOAD_VSR(20, r3)
280 LOAD_VSR(21, r3)
281 LOAD_VSR(22, r3)
282 LOAD_VSR(23, r3)
283 LOAD_VSR(24, r3)
284 LOAD_VSR(25, r3)
285 LOAD_VSR(26, r3)
286 LOAD_VSR(27, r3)
287 LOAD_VSR(28, r3)
288 LOAD_VSR(29, r3)
289 LOAD_VSR(30, r3)
290 LOAD_VSR(31, r3)
291 LOAD_VSR(32, r3)
292 LOAD_VSR(33, r3)
293 LOAD_VSR(34, r3)
294 LOAD_VSR(35, r3)
295 LOAD_VSR(36, r3)
296 LOAD_VSR(37, r3)
297 LOAD_VSR(38, r3)
298 LOAD_VSR(39, r3)
299 LOAD_VSR(40, r3)
300 LOAD_VSR(41, r3)
301 LOAD_VSR(42, r3)
302 LOAD_VSR(43, r3)
303 LOAD_VSR(44, r3)
304 LOAD_VSR(45, r3)
305 LOAD_VSR(46, r3)
306 LOAD_VSR(47, r3)
307 LOAD_VSR(48, r3)
308 LOAD_VSR(49, r3)
309 LOAD_VSR(50, r3)
310 LOAD_VSR(51, r3)
311 LOAD_VSR(52, r3)
312 LOAD_VSR(53, r3)
313 LOAD_VSR(54, r3)
314 LOAD_VSR(55, r3)
315 LOAD_VSR(56, r3)
316 LOAD_VSR(57, r3)
317 LOAD_VSR(58, r3)
318 LOAD_VSR(59, r3)
319 LOAD_VSR(60, r3)
320 LOAD_VSR(61, r3)
321 LOAD_VSR(62, r3)
322 LOAD_VSR(63, r3)
323
324 ld r0,XER_SAVE(r1)
325 mtxer r0
326 ld r0,CTR_SAVE(r1)
327 mtctr r0
328 ld r0,LR_SAVE(r1)
329 mtlr r0
330 ld r0,CCR_SAVE(r1)
331 mtcr r0
332 REST_GPR(0)
333 REST_GPR(2)
334 REST_GPR(3)
335 REST_GPR(4)
336 REST_GPR(5)
337 REST_GPR(6)
338 REST_GPR(7)
339 REST_GPR(8)
340 REST_GPR(9)
341 REST_GPR(10)
342 REST_GPR(11)
343 REST_GPR(12)
344 REST_GPR(13)
345 REST_GPR(14)
346 REST_GPR(15)
347 REST_GPR(16)
348 REST_GPR(17)
349 REST_GPR(18)
350 REST_GPR(19)
351 REST_GPR(20)
352 REST_GPR(21)
353 REST_GPR(22)
354 REST_GPR(23)
355 REST_GPR(24)
356 REST_GPR(25)
357 REST_GPR(26)
358 REST_GPR(27)
359 REST_GPR(28)
360 REST_GPR(29)
361 REST_GPR(30)
362 REST_GPR(31)
363 addi r1,r1,STACK_FRAME
364 RFEBB
365FUNC_END(ebb_handler)
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/ebb_on_child_test.c b/tools/testing/selftests/powerpc/pmu/ebb/ebb_on_child_test.c
new file mode 100644
index 000000000000..c45f948148e1
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/ebb_on_child_test.c
@@ -0,0 +1,86 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <signal.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <stdbool.h>
10#include <sys/types.h>
11#include <sys/wait.h>
12#include <unistd.h>
13
14#include "ebb.h"
15
16
17/*
18 * Tests we can setup an EBB on our child. Nothing interesting happens, because
19 * even though the event is enabled and running the child hasn't enabled the
20 * actual delivery of the EBBs.
21 */
22
23static int victim_child(union pipe read_pipe, union pipe write_pipe)
24{
25 int i;
26
27 FAIL_IF(wait_for_parent(read_pipe));
28 FAIL_IF(notify_parent(write_pipe));
29
30 /* Parent creates EBB event */
31
32 FAIL_IF(wait_for_parent(read_pipe));
33 FAIL_IF(notify_parent(write_pipe));
34
35 /* Check the EBB is enabled by writing PMC1 */
36 write_pmc1();
37
38 /* EBB event is enabled here */
39 for (i = 0; i < 1000000; i++) ;
40
41 return 0;
42}
43
44int ebb_on_child(void)
45{
46 union pipe read_pipe, write_pipe;
47 struct event event;
48 pid_t pid;
49
50 FAIL_IF(pipe(read_pipe.fds) == -1);
51 FAIL_IF(pipe(write_pipe.fds) == -1);
52
53 pid = fork();
54 if (pid == 0) {
55 /* NB order of pipes looks reversed */
56 exit(victim_child(write_pipe, read_pipe));
57 }
58
59 FAIL_IF(sync_with_child(read_pipe, write_pipe));
60
61 /* Child is running now */
62
63 event_init_named(&event, 0x1001e, "cycles");
64 event_leader_ebb_init(&event);
65
66 event.attr.exclude_kernel = 1;
67 event.attr.exclude_hv = 1;
68 event.attr.exclude_idle = 1;
69
70 FAIL_IF(event_open_with_pid(&event, pid));
71 FAIL_IF(ebb_event_enable(&event));
72
73 FAIL_IF(sync_with_child(read_pipe, write_pipe));
74
75 /* Child should just exit happily */
76 FAIL_IF(wait_for_child(pid));
77
78 event_close(&event);
79
80 return 0;
81}
82
83int main(void)
84{
85 return test_harness(ebb_on_child, "ebb_on_child");
86}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/ebb_on_willing_child_test.c b/tools/testing/selftests/powerpc/pmu/ebb/ebb_on_willing_child_test.c
new file mode 100644
index 000000000000..11acf1d55f8d
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/ebb_on_willing_child_test.c
@@ -0,0 +1,92 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <signal.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <stdbool.h>
10#include <sys/types.h>
11#include <sys/wait.h>
12#include <unistd.h>
13
14#include "ebb.h"
15
16
17/*
18 * Tests we can setup an EBB on our child. The child expects this and enables
19 * EBBs, which are then delivered to the child, even though the event is
20 * created by the parent.
21 */
22
23static int victim_child(union pipe read_pipe, union pipe write_pipe)
24{
25 FAIL_IF(wait_for_parent(read_pipe));
26
27 /* Setup our EBB handler, before the EBB event is created */
28 ebb_enable_pmc_counting(1);
29 setup_ebb_handler(standard_ebb_callee);
30 ebb_global_enable();
31
32 FAIL_IF(notify_parent(write_pipe));
33
34 while (ebb_state.stats.ebb_count < 20) {
35 FAIL_IF(core_busy_loop());
36 }
37
38 ebb_global_disable();
39 ebb_freeze_pmcs();
40
41 count_pmc(1, sample_period);
42
43 dump_ebb_state();
44
45 FAIL_IF(ebb_state.stats.ebb_count == 0);
46
47 return 0;
48}
49
50/* Tests we can setup an EBB on our child - if it's expecting it */
51int ebb_on_willing_child(void)
52{
53 union pipe read_pipe, write_pipe;
54 struct event event;
55 pid_t pid;
56
57 FAIL_IF(pipe(read_pipe.fds) == -1);
58 FAIL_IF(pipe(write_pipe.fds) == -1);
59
60 pid = fork();
61 if (pid == 0) {
62 /* NB order of pipes looks reversed */
63 exit(victim_child(write_pipe, read_pipe));
64 }
65
66 /* Signal the child to setup its EBB handler */
67 FAIL_IF(sync_with_child(read_pipe, write_pipe));
68
69 /* Child is running now */
70
71 event_init_named(&event, 0x1001e, "cycles");
72 event_leader_ebb_init(&event);
73
74 event.attr.exclude_kernel = 1;
75 event.attr.exclude_hv = 1;
76 event.attr.exclude_idle = 1;
77
78 FAIL_IF(event_open_with_pid(&event, pid));
79 FAIL_IF(ebb_event_enable(&event));
80
81 /* Child show now take EBBs and then exit */
82 FAIL_IF(wait_for_child(pid));
83
84 event_close(&event);
85
86 return 0;
87}
88
89int main(void)
90{
91 return test_harness(ebb_on_willing_child, "ebb_on_willing_child");
92}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/ebb_vs_cpu_event_test.c b/tools/testing/selftests/powerpc/pmu/ebb/ebb_vs_cpu_event_test.c
new file mode 100644
index 000000000000..be4dd5a4e98e
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/ebb_vs_cpu_event_test.c
@@ -0,0 +1,86 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <signal.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <stdbool.h>
10#include <sys/types.h>
11#include <sys/wait.h>
12#include <unistd.h>
13
14#include "ebb.h"
15
16
17/*
18 * Tests an EBB vs a cpu event - in that order. The EBB should force the cpu
19 * event off the PMU.
20 */
21
22static int setup_cpu_event(struct event *event, int cpu)
23{
24 event_init_named(event, 0x400FA, "PM_RUN_INST_CMPL");
25
26 event->attr.exclude_kernel = 1;
27 event->attr.exclude_hv = 1;
28 event->attr.exclude_idle = 1;
29
30 SKIP_IF(require_paranoia_below(1));
31 FAIL_IF(event_open_with_cpu(event, cpu));
32 FAIL_IF(event_enable(event));
33
34 return 0;
35}
36
37int ebb_vs_cpu_event(void)
38{
39 union pipe read_pipe, write_pipe;
40 struct event event;
41 int cpu, rc;
42 pid_t pid;
43
44 cpu = pick_online_cpu();
45 FAIL_IF(cpu < 0);
46 FAIL_IF(bind_to_cpu(cpu));
47
48 FAIL_IF(pipe(read_pipe.fds) == -1);
49 FAIL_IF(pipe(write_pipe.fds) == -1);
50
51 pid = fork();
52 if (pid == 0) {
53 /* NB order of pipes looks reversed */
54 exit(ebb_child(write_pipe, read_pipe));
55 }
56
57 /* Signal the child to install its EBB event and wait */
58 FAIL_IF(sync_with_child(read_pipe, write_pipe));
59
60 /* Now try to install our CPU event */
61 rc = setup_cpu_event(&event, cpu);
62 if (rc) {
63 kill_child_and_wait(pid);
64 return rc;
65 }
66
67 /* Signal the child to run */
68 FAIL_IF(sync_with_child(read_pipe, write_pipe));
69
70 /* .. and wait for it to complete */
71 FAIL_IF(wait_for_child(pid));
72 FAIL_IF(event_disable(&event));
73 FAIL_IF(event_read(&event));
74
75 event_report(&event);
76
77 /* The cpu event may have run, but we don't expect 100% */
78 FAIL_IF(event.result.enabled >= event.result.running);
79
80 return 0;
81}
82
83int main(void)
84{
85 return test_harness(ebb_vs_cpu_event, "ebb_vs_cpu_event");
86}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/event_attributes_test.c b/tools/testing/selftests/powerpc/pmu/ebb/event_attributes_test.c
new file mode 100644
index 000000000000..7e78153f08eb
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/event_attributes_test.c
@@ -0,0 +1,131 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <stdio.h>
7#include <stdlib.h>
8
9#include "ebb.h"
10
11
12/*
13 * Test various attributes of the EBB event are enforced.
14 */
15int event_attributes(void)
16{
17 struct event event, leader;
18
19 event_init(&event, 0x1001e);
20 event_leader_ebb_init(&event);
21 /* Expected to succeed */
22 FAIL_IF(event_open(&event));
23 event_close(&event);
24
25
26 event_init(&event, 0x001e); /* CYCLES - no PMC specified */
27 event_leader_ebb_init(&event);
28 /* Expected to fail, no PMC specified */
29 FAIL_IF(event_open(&event) == 0);
30
31
32 event_init(&event, 0x2001e);
33 event_leader_ebb_init(&event);
34 event.attr.exclusive = 0;
35 /* Expected to fail, not exclusive */
36 FAIL_IF(event_open(&event) == 0);
37
38
39 event_init(&event, 0x3001e);
40 event_leader_ebb_init(&event);
41 event.attr.freq = 1;
42 /* Expected to fail, sets freq */
43 FAIL_IF(event_open(&event) == 0);
44
45
46 event_init(&event, 0x4001e);
47 event_leader_ebb_init(&event);
48 event.attr.sample_period = 1;
49 /* Expected to fail, sets sample_period */
50 FAIL_IF(event_open(&event) == 0);
51
52
53 event_init(&event, 0x1001e);
54 event_leader_ebb_init(&event);
55 event.attr.enable_on_exec = 1;
56 /* Expected to fail, sets enable_on_exec */
57 FAIL_IF(event_open(&event) == 0);
58
59
60 event_init(&event, 0x1001e);
61 event_leader_ebb_init(&event);
62 event.attr.inherit = 1;
63 /* Expected to fail, sets inherit */
64 FAIL_IF(event_open(&event) == 0);
65
66
67 event_init(&leader, 0x1001e);
68 event_leader_ebb_init(&leader);
69 FAIL_IF(event_open(&leader));
70
71 event_init(&event, 0x20002);
72 event_ebb_init(&event);
73
74 /* Expected to succeed */
75 FAIL_IF(event_open_with_group(&event, leader.fd));
76 event_close(&leader);
77 event_close(&event);
78
79
80 event_init(&leader, 0x1001e);
81 event_leader_ebb_init(&leader);
82 FAIL_IF(event_open(&leader));
83
84 event_init(&event, 0x20002);
85
86 /* Expected to fail, event doesn't request EBB, leader does */
87 FAIL_IF(event_open_with_group(&event, leader.fd) == 0);
88 event_close(&leader);
89
90
91 event_init(&leader, 0x1001e);
92 event_leader_ebb_init(&leader);
93 /* Clear the EBB flag */
94 leader.attr.config &= ~(1ull << 63);
95
96 FAIL_IF(event_open(&leader));
97
98 event_init(&event, 0x20002);
99 event_ebb_init(&event);
100
101 /* Expected to fail, leader doesn't request EBB */
102 FAIL_IF(event_open_with_group(&event, leader.fd) == 0);
103 event_close(&leader);
104
105
106 event_init(&leader, 0x1001e);
107 event_leader_ebb_init(&leader);
108 leader.attr.exclusive = 0;
109 /* Expected to fail, leader isn't exclusive */
110 FAIL_IF(event_open(&leader) == 0);
111
112
113 event_init(&leader, 0x1001e);
114 event_leader_ebb_init(&leader);
115 leader.attr.pinned = 0;
116 /* Expected to fail, leader isn't pinned */
117 FAIL_IF(event_open(&leader) == 0);
118
119 event_init(&event, 0x1001e);
120 event_leader_ebb_init(&event);
121 /* Expected to fail, not a task event */
122 SKIP_IF(require_paranoia_below(1));
123 FAIL_IF(event_open_with_cpu(&event, 0) == 0);
124
125 return 0;
126}
127
128int main(void)
129{
130 return test_harness(event_attributes, "event_attributes");
131}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/fixed_instruction_loop.S b/tools/testing/selftests/powerpc/pmu/ebb/fixed_instruction_loop.S
new file mode 100644
index 000000000000..b866a0581d32
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/fixed_instruction_loop.S
@@ -0,0 +1,43 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <ppc-asm.h>
7
8 .text
9
10FUNC_START(thirty_two_instruction_loop)
11 cmpwi r3,0
12 beqlr
13 addi r4,r3,1
14 addi r4,r4,1
15 addi r4,r4,1
16 addi r4,r4,1
17 addi r4,r4,1
18 addi r4,r4,1
19 addi r4,r4,1
20 addi r4,r4,1
21 addi r4,r4,1
22 addi r4,r4,1
23 addi r4,r4,1
24 addi r4,r4,1
25 addi r4,r4,1
26 addi r4,r4,1
27 addi r4,r4,1
28 addi r4,r4,1
29 addi r4,r4,1
30 addi r4,r4,1
31 addi r4,r4,1
32 addi r4,r4,1
33 addi r4,r4,1
34 addi r4,r4,1
35 addi r4,r4,1
36 addi r4,r4,1
37 addi r4,r4,1
38 addi r4,r4,1
39 addi r4,r4,1
40 addi r4,r4,1 # 28 addi's
41 subi r3,r3,1
42 b FUNC_NAME(thirty_two_instruction_loop)
43FUNC_END(thirty_two_instruction_loop)
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/fork_cleanup_test.c b/tools/testing/selftests/powerpc/pmu/ebb/fork_cleanup_test.c
new file mode 100644
index 000000000000..9e7af6e76622
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/fork_cleanup_test.c
@@ -0,0 +1,79 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <signal.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <stdbool.h>
10#include <sys/types.h>
11#include <sys/wait.h>
12#include <unistd.h>
13#include <setjmp.h>
14#include <signal.h>
15
16#include "ebb.h"
17
18
19/*
20 * Test that a fork clears the PMU state of the child. eg. BESCR/EBBHR/EBBRR
21 * are cleared, and MMCR0_PMCC is reset, preventing the child from accessing
22 * the PMU.
23 */
24
25static struct event event;
26
27static int child(void)
28{
29 /* Even though we have EBE=0 we can still see the EBB regs */
30 FAIL_IF(mfspr(SPRN_BESCR) != 0);
31 FAIL_IF(mfspr(SPRN_EBBHR) != 0);
32 FAIL_IF(mfspr(SPRN_EBBRR) != 0);
33
34 FAIL_IF(catch_sigill(write_pmc1));
35
36 /* We can still read from the event, though it is on our parent */
37 FAIL_IF(event_read(&event));
38
39 return 0;
40}
41
42/* Tests that fork clears EBB state */
43int fork_cleanup(void)
44{
45 pid_t pid;
46
47 event_init_named(&event, 0x1001e, "cycles");
48 event_leader_ebb_init(&event);
49
50 FAIL_IF(event_open(&event));
51
52 ebb_enable_pmc_counting(1);
53 setup_ebb_handler(standard_ebb_callee);
54 ebb_global_enable();
55
56 FAIL_IF(ebb_event_enable(&event));
57
58 mtspr(SPRN_MMCR0, MMCR0_FC);
59 mtspr(SPRN_PMC1, pmc_sample_period(sample_period));
60
61 /* Don't need to actually take any EBBs */
62
63 pid = fork();
64 if (pid == 0)
65 exit(child());
66
67 /* Child does the actual testing */
68 FAIL_IF(wait_for_child(pid));
69
70 /* After fork */
71 event_close(&event);
72
73 return 0;
74}
75
76int main(void)
77{
78 return test_harness(fork_cleanup, "fork_cleanup");
79}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/instruction_count_test.c b/tools/testing/selftests/powerpc/pmu/ebb/instruction_count_test.c
new file mode 100644
index 000000000000..f8190fa29592
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/instruction_count_test.c
@@ -0,0 +1,164 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#define _GNU_SOURCE
7
8#include <stdio.h>
9#include <stdbool.h>
10#include <string.h>
11#include <sys/prctl.h>
12
13#include "ebb.h"
14
15
16/*
17 * Run a calibrated instruction loop and count instructions executed using
18 * EBBs. Make sure the counts look right.
19 */
20
21extern void thirty_two_instruction_loop(uint64_t loops);
22
23static bool counters_frozen = true;
24
25static int do_count_loop(struct event *event, uint64_t instructions,
26 uint64_t overhead, bool report)
27{
28 int64_t difference, expected;
29 double percentage;
30
31 clear_ebb_stats();
32
33 counters_frozen = false;
34 mb();
35 mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_FC);
36
37 thirty_two_instruction_loop(instructions >> 5);
38
39 counters_frozen = true;
40 mb();
41 mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) | MMCR0_FC);
42
43 count_pmc(4, sample_period);
44
45 event->result.value = ebb_state.stats.pmc_count[4-1];
46 expected = instructions + overhead;
47 difference = event->result.value - expected;
48 percentage = (double)difference / event->result.value * 100;
49
50 if (report) {
51 printf("Looped for %lu instructions, overhead %lu\n", instructions, overhead);
52 printf("Expected %lu\n", expected);
53 printf("Actual %llu\n", event->result.value);
54 printf("Error %ld, %f%%\n", difference, percentage);
55 printf("Took %d EBBs\n", ebb_state.stats.ebb_count);
56 }
57
58 if (difference < 0)
59 difference = -difference;
60
61 /* Tolerate a difference of up to 0.0001 % */
62 difference *= 10000 * 100;
63 if (difference / event->result.value)
64 return -1;
65
66 return 0;
67}
68
69/* Count how many instructions it takes to do a null loop */
70static uint64_t determine_overhead(struct event *event)
71{
72 uint64_t current, overhead;
73 int i;
74
75 do_count_loop(event, 0, 0, false);
76 overhead = event->result.value;
77
78 for (i = 0; i < 100; i++) {
79 do_count_loop(event, 0, 0, false);
80 current = event->result.value;
81 if (current < overhead) {
82 printf("Replacing overhead %lu with %lu\n", overhead, current);
83 overhead = current;
84 }
85 }
86
87 return overhead;
88}
89
90static void pmc4_ebb_callee(void)
91{
92 uint64_t val;
93
94 val = mfspr(SPRN_BESCR);
95 if (!(val & BESCR_PMEO)) {
96 ebb_state.stats.spurious++;
97 goto out;
98 }
99
100 ebb_state.stats.ebb_count++;
101 count_pmc(4, sample_period);
102out:
103 if (counters_frozen)
104 reset_ebb_with_clear_mask(MMCR0_PMAO);
105 else
106 reset_ebb();
107}
108
109int instruction_count(void)
110{
111 struct event event;
112 uint64_t overhead;
113
114 event_init_named(&event, 0x400FA, "PM_RUN_INST_CMPL");
115 event_leader_ebb_init(&event);
116 event.attr.exclude_kernel = 1;
117 event.attr.exclude_hv = 1;
118 event.attr.exclude_idle = 1;
119
120 FAIL_IF(event_open(&event));
121 FAIL_IF(ebb_event_enable(&event));
122
123 sample_period = COUNTER_OVERFLOW;
124
125 setup_ebb_handler(pmc4_ebb_callee);
126 mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_FC);
127 ebb_global_enable();
128
129 overhead = determine_overhead(&event);
130 printf("Overhead of null loop: %lu instructions\n", overhead);
131
132 /* Run for 1M instructions */
133 FAIL_IF(do_count_loop(&event, 0x100000, overhead, true));
134
135 /* Run for 10M instructions */
136 FAIL_IF(do_count_loop(&event, 0xa00000, overhead, true));
137
138 /* Run for 100M instructions */
139 FAIL_IF(do_count_loop(&event, 0x6400000, overhead, true));
140
141 /* Run for 1G instructions */
142 FAIL_IF(do_count_loop(&event, 0x40000000, overhead, true));
143
144 /* Run for 16G instructions */
145 FAIL_IF(do_count_loop(&event, 0x400000000, overhead, true));
146
147 /* Run for 64G instructions */
148 FAIL_IF(do_count_loop(&event, 0x1000000000, overhead, true));
149
150 /* Run for 128G instructions */
151 FAIL_IF(do_count_loop(&event, 0x2000000000, overhead, true));
152
153 ebb_global_disable();
154 event_close(&event);
155
156 printf("Finished OK\n");
157
158 return 0;
159}
160
161int main(void)
162{
163 return test_harness(instruction_count, "instruction_count");
164}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/lost_exception_test.c b/tools/testing/selftests/powerpc/pmu/ebb/lost_exception_test.c
new file mode 100644
index 000000000000..0c9dd9b2e39d
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/lost_exception_test.c
@@ -0,0 +1,100 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <sched.h>
7#include <signal.h>
8#include <stdio.h>
9#include <stdlib.h>
10#include <sys/mman.h>
11
12#include "ebb.h"
13
14
15/*
16 * Test that tries to trigger CPU_FTR_PMAO_BUG. Which is a hardware defect
17 * where an exception triggers but we context switch before it is delivered and
18 * lose the exception.
19 */
20
21static int test_body(void)
22{
23 int i, orig_period, max_period;
24 struct event event;
25
26 /* We use PMC4 to make sure the kernel switches all counters correctly */
27 event_init_named(&event, 0x40002, "instructions");
28 event_leader_ebb_init(&event);
29
30 event.attr.exclude_kernel = 1;
31 event.attr.exclude_hv = 1;
32 event.attr.exclude_idle = 1;
33
34 FAIL_IF(event_open(&event));
35
36 ebb_enable_pmc_counting(4);
37 setup_ebb_handler(standard_ebb_callee);
38 ebb_global_enable();
39 FAIL_IF(ebb_event_enable(&event));
40
41 /*
42 * We want a low sample period, but we also want to get out of the EBB
43 * handler without tripping up again.
44 *
45 * This value picked after much experimentation.
46 */
47 orig_period = max_period = sample_period = 400;
48
49 mtspr(SPRN_PMC4, pmc_sample_period(sample_period));
50
51 while (ebb_state.stats.ebb_count < 1000000) {
52 /*
53 * We are trying to get the EBB exception to race exactly with
54 * us entering the kernel to do the syscall. We then need the
55 * kernel to decide our timeslice is up and context switch to
56 * the other thread. When we come back our EBB will have been
57 * lost and we'll spin in this while loop forever.
58 */
59
60 for (i = 0; i < 100000; i++)
61 sched_yield();
62
63 /* Change the sample period slightly to try and hit the race */
64 if (sample_period >= (orig_period + 200))
65 sample_period = orig_period;
66 else
67 sample_period++;
68
69 if (sample_period > max_period)
70 max_period = sample_period;
71 }
72
73 ebb_freeze_pmcs();
74 ebb_global_disable();
75
76 count_pmc(4, sample_period);
77 mtspr(SPRN_PMC4, 0xdead);
78
79 dump_summary_ebb_state();
80 dump_ebb_hw_state();
81
82 event_close(&event);
83
84 FAIL_IF(ebb_state.stats.ebb_count == 0);
85
86 /* We vary our sample period so we need extra fudge here */
87 FAIL_IF(!ebb_check_count(4, orig_period, 2 * (max_period - orig_period)));
88
89 return 0;
90}
91
92static int lost_exception(void)
93{
94 return eat_cpu(test_body);
95}
96
97int main(void)
98{
99 return test_harness(lost_exception, "lost_exception");
100}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/multi_counter_test.c b/tools/testing/selftests/powerpc/pmu/ebb/multi_counter_test.c
new file mode 100644
index 000000000000..67d78af3284c
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/multi_counter_test.c
@@ -0,0 +1,91 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <stdio.h>
7#include <stdlib.h>
8#include <sys/ioctl.h>
9
10#include "ebb.h"
11
12
13/*
14 * Test counting multiple events using EBBs.
15 */
16int multi_counter(void)
17{
18 struct event events[6];
19 int i, group_fd;
20
21 event_init_named(&events[0], 0x1001C, "PM_CMPLU_STALL_THRD");
22 event_init_named(&events[1], 0x2D016, "PM_CMPLU_STALL_FXU");
23 event_init_named(&events[2], 0x30006, "PM_CMPLU_STALL_OTHER_CMPL");
24 event_init_named(&events[3], 0x4000A, "PM_CMPLU_STALL");
25 event_init_named(&events[4], 0x600f4, "PM_RUN_CYC");
26 event_init_named(&events[5], 0x500fa, "PM_RUN_INST_CMPL");
27
28 event_leader_ebb_init(&events[0]);
29 for (i = 1; i < 6; i++)
30 event_ebb_init(&events[i]);
31
32 group_fd = -1;
33 for (i = 0; i < 6; i++) {
34 events[i].attr.exclude_kernel = 1;
35 events[i].attr.exclude_hv = 1;
36 events[i].attr.exclude_idle = 1;
37
38 FAIL_IF(event_open_with_group(&events[i], group_fd));
39 if (group_fd == -1)
40 group_fd = events[0].fd;
41 }
42
43 ebb_enable_pmc_counting(1);
44 ebb_enable_pmc_counting(2);
45 ebb_enable_pmc_counting(3);
46 ebb_enable_pmc_counting(4);
47 ebb_enable_pmc_counting(5);
48 ebb_enable_pmc_counting(6);
49 setup_ebb_handler(standard_ebb_callee);
50
51 FAIL_IF(ioctl(events[0].fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP));
52 FAIL_IF(event_read(&events[0]));
53
54 ebb_global_enable();
55
56 mtspr(SPRN_PMC1, pmc_sample_period(sample_period));
57 mtspr(SPRN_PMC2, pmc_sample_period(sample_period));
58 mtspr(SPRN_PMC3, pmc_sample_period(sample_period));
59 mtspr(SPRN_PMC4, pmc_sample_period(sample_period));
60 mtspr(SPRN_PMC5, pmc_sample_period(sample_period));
61 mtspr(SPRN_PMC6, pmc_sample_period(sample_period));
62
63 while (ebb_state.stats.ebb_count < 50) {
64 FAIL_IF(core_busy_loop());
65 FAIL_IF(ebb_check_mmcr0());
66 }
67
68 ebb_global_disable();
69 ebb_freeze_pmcs();
70
71 count_pmc(1, sample_period);
72 count_pmc(2, sample_period);
73 count_pmc(3, sample_period);
74 count_pmc(4, sample_period);
75 count_pmc(5, sample_period);
76 count_pmc(6, sample_period);
77
78 dump_ebb_state();
79
80 for (i = 0; i < 6; i++)
81 event_close(&events[i]);
82
83 FAIL_IF(ebb_state.stats.ebb_count == 0);
84
85 return 0;
86}
87
88int main(void)
89{
90 return test_harness(multi_counter, "multi_counter");
91}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/multi_ebb_procs_test.c b/tools/testing/selftests/powerpc/pmu/ebb/multi_ebb_procs_test.c
new file mode 100644
index 000000000000..b8dc371f9338
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/multi_ebb_procs_test.c
@@ -0,0 +1,109 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <stdbool.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <signal.h>
10
11#include "ebb.h"
12
13
14/*
15 * Test running multiple EBB using processes at once on a single CPU. They
16 * should all run happily without interfering with each other.
17 */
18
19static bool child_should_exit;
20
21static void sigint_handler(int signal)
22{
23 child_should_exit = true;
24}
25
26struct sigaction sigint_action = {
27 .sa_handler = sigint_handler,
28};
29
30static int cycles_child(void)
31{
32 struct event event;
33
34 if (sigaction(SIGINT, &sigint_action, NULL)) {
35 perror("sigaction");
36 return 1;
37 }
38
39 event_init_named(&event, 0x1001e, "cycles");
40 event_leader_ebb_init(&event);
41
42 event.attr.exclude_kernel = 1;
43 event.attr.exclude_hv = 1;
44 event.attr.exclude_idle = 1;
45
46 FAIL_IF(event_open(&event));
47
48 ebb_enable_pmc_counting(1);
49 setup_ebb_handler(standard_ebb_callee);
50 ebb_global_enable();
51
52 FAIL_IF(ebb_event_enable(&event));
53
54 mtspr(SPRN_PMC1, pmc_sample_period(sample_period));
55
56 while (!child_should_exit) {
57 FAIL_IF(core_busy_loop());
58 FAIL_IF(ebb_check_mmcr0());
59 }
60
61 ebb_global_disable();
62 ebb_freeze_pmcs();
63
64 count_pmc(1, sample_period);
65
66 dump_summary_ebb_state();
67
68 event_close(&event);
69
70 FAIL_IF(ebb_state.stats.ebb_count == 0);
71
72 return 0;
73}
74
75#define NR_CHILDREN 4
76
77int multi_ebb_procs(void)
78{
79 pid_t pids[NR_CHILDREN];
80 int cpu, rc, i;
81
82 cpu = pick_online_cpu();
83 FAIL_IF(cpu < 0);
84 FAIL_IF(bind_to_cpu(cpu));
85
86 for (i = 0; i < NR_CHILDREN; i++) {
87 pids[i] = fork();
88 if (pids[i] == 0)
89 exit(cycles_child());
90 }
91
92 /* Have them all run for "a while" */
93 sleep(10);
94
95 rc = 0;
96 for (i = 0; i < NR_CHILDREN; i++) {
97 /* Tell them to stop */
98 kill(pids[i], SIGINT);
99 /* And wait */
100 rc |= wait_for_child(pids[i]);
101 }
102
103 return rc;
104}
105
106int main(void)
107{
108 return test_harness(multi_ebb_procs, "multi_ebb_procs");
109}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/no_handler_test.c b/tools/testing/selftests/powerpc/pmu/ebb/no_handler_test.c
new file mode 100644
index 000000000000..2f9bf8edfa60
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/no_handler_test.c
@@ -0,0 +1,61 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <stdio.h>
7#include <stdlib.h>
8#include <setjmp.h>
9#include <signal.h>
10
11#include "ebb.h"
12
13
14/* Test that things work sanely if we have no handler */
15
16static int no_handler_test(void)
17{
18 struct event event;
19 u64 val;
20 int i;
21
22 event_init_named(&event, 0x1001e, "cycles");
23 event_leader_ebb_init(&event);
24
25 event.attr.exclude_kernel = 1;
26 event.attr.exclude_hv = 1;
27 event.attr.exclude_idle = 1;
28
29 FAIL_IF(event_open(&event));
30 FAIL_IF(ebb_event_enable(&event));
31
32 val = mfspr(SPRN_EBBHR);
33 FAIL_IF(val != 0);
34
35 /* Make sure it overflows quickly */
36 sample_period = 1000;
37 mtspr(SPRN_PMC1, pmc_sample_period(sample_period));
38
39 /* Spin to make sure the event has time to overflow */
40 for (i = 0; i < 1000; i++)
41 mb();
42
43 dump_ebb_state();
44
45 /* We expect to see the PMU frozen & PMAO set */
46 val = mfspr(SPRN_MMCR0);
47 FAIL_IF(val != 0x0000000080000080);
48
49 event_close(&event);
50
51 dump_ebb_state();
52
53 /* The real test is that we never took an EBB at 0x0 */
54
55 return 0;
56}
57
58int main(void)
59{
60 return test_harness(no_handler_test,"no_handler_test");
61}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/pmae_handling_test.c b/tools/testing/selftests/powerpc/pmu/ebb/pmae_handling_test.c
new file mode 100644
index 000000000000..986500fd2131
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/pmae_handling_test.c
@@ -0,0 +1,106 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <sched.h>
7#include <signal.h>
8#include <stdbool.h>
9#include <stdio.h>
10#include <stdlib.h>
11
12#include "ebb.h"
13
14
15/*
16 * Test that the kernel properly handles PMAE across context switches.
17 *
18 * We test this by calling into the kernel inside our EBB handler, where PMAE
19 * is clear. A cpu eater companion thread is running on the same CPU as us to
20 * encourage the scheduler to switch us.
21 *
22 * The kernel must make sure that when it context switches us back in, it
23 * honours the fact that we had PMAE clear.
24 *
25 * Observed to hit the failing case on the first EBB with a broken kernel.
26 */
27
28static bool mmcr0_mismatch;
29static uint64_t before, after;
30
31static void syscall_ebb_callee(void)
32{
33 uint64_t val;
34
35 val = mfspr(SPRN_BESCR);
36 if (!(val & BESCR_PMEO)) {
37 ebb_state.stats.spurious++;
38 goto out;
39 }
40
41 ebb_state.stats.ebb_count++;
42 count_pmc(1, sample_period);
43
44 before = mfspr(SPRN_MMCR0);
45
46 /* Try and get ourselves scheduled, to force a PMU context switch */
47 sched_yield();
48
49 after = mfspr(SPRN_MMCR0);
50 if (before != after)
51 mmcr0_mismatch = true;
52
53out:
54 reset_ebb();
55}
56
57static int test_body(void)
58{
59 struct event event;
60
61 event_init_named(&event, 0x1001e, "cycles");
62 event_leader_ebb_init(&event);
63
64 event.attr.exclude_kernel = 1;
65 event.attr.exclude_hv = 1;
66 event.attr.exclude_idle = 1;
67
68 FAIL_IF(event_open(&event));
69
70 setup_ebb_handler(syscall_ebb_callee);
71 ebb_global_enable();
72
73 FAIL_IF(ebb_event_enable(&event));
74
75 mtspr(SPRN_PMC1, pmc_sample_period(sample_period));
76
77 while (ebb_state.stats.ebb_count < 20 && !mmcr0_mismatch)
78 FAIL_IF(core_busy_loop());
79
80 ebb_global_disable();
81 ebb_freeze_pmcs();
82
83 count_pmc(1, sample_period);
84
85 dump_ebb_state();
86
87 if (mmcr0_mismatch)
88 printf("Saw MMCR0 before 0x%lx after 0x%lx\n", before, after);
89
90 event_close(&event);
91
92 FAIL_IF(ebb_state.stats.ebb_count == 0);
93 FAIL_IF(mmcr0_mismatch);
94
95 return 0;
96}
97
98int pmae_handling(void)
99{
100 return eat_cpu(test_body);
101}
102
103int main(void)
104{
105 return test_harness(pmae_handling, "pmae_handling");
106}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/pmc56_overflow_test.c b/tools/testing/selftests/powerpc/pmu/ebb/pmc56_overflow_test.c
new file mode 100644
index 000000000000..a503fa70c950
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/pmc56_overflow_test.c
@@ -0,0 +1,93 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <stdio.h>
7#include <stdlib.h>
8
9#include "ebb.h"
10
11
12/*
13 * Test that PMC5 & 6 are frozen (ie. don't overflow) when they are not being
14 * used. Tests the MMCR0_FC56 logic in the kernel.
15 */
16
17static int pmc56_overflowed;
18
19static void ebb_callee(void)
20{
21 uint64_t val;
22
23 val = mfspr(SPRN_BESCR);
24 if (!(val & BESCR_PMEO)) {
25 ebb_state.stats.spurious++;
26 goto out;
27 }
28
29 ebb_state.stats.ebb_count++;
30 count_pmc(2, sample_period);
31
32 val = mfspr(SPRN_PMC5);
33 if (val >= COUNTER_OVERFLOW)
34 pmc56_overflowed++;
35
36 count_pmc(5, COUNTER_OVERFLOW);
37
38 val = mfspr(SPRN_PMC6);
39 if (val >= COUNTER_OVERFLOW)
40 pmc56_overflowed++;
41
42 count_pmc(6, COUNTER_OVERFLOW);
43
44out:
45 reset_ebb();
46}
47
48int pmc56_overflow(void)
49{
50 struct event event;
51
52 /* Use PMC2 so we set PMCjCE, which enables PMC5/6 */
53 event_init(&event, 0x2001e);
54 event_leader_ebb_init(&event);
55
56 event.attr.exclude_kernel = 1;
57 event.attr.exclude_hv = 1;
58 event.attr.exclude_idle = 1;
59
60 FAIL_IF(event_open(&event));
61
62 setup_ebb_handler(ebb_callee);
63 ebb_global_enable();
64
65 FAIL_IF(ebb_event_enable(&event));
66
67 mtspr(SPRN_PMC1, pmc_sample_period(sample_period));
68 mtspr(SPRN_PMC5, 0);
69 mtspr(SPRN_PMC6, 0);
70
71 while (ebb_state.stats.ebb_count < 10)
72 FAIL_IF(core_busy_loop());
73
74 ebb_global_disable();
75 ebb_freeze_pmcs();
76
77 count_pmc(2, sample_period);
78
79 dump_ebb_state();
80
81 printf("PMC5/6 overflow %d\n", pmc56_overflowed);
82
83 event_close(&event);
84
85 FAIL_IF(ebb_state.stats.ebb_count == 0 || pmc56_overflowed != 0);
86
87 return 0;
88}
89
90int main(void)
91{
92 return test_harness(pmc56_overflow, "pmc56_overflow");
93}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/reg.h b/tools/testing/selftests/powerpc/pmu/ebb/reg.h
new file mode 100644
index 000000000000..5921b0dfe2e9
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/reg.h
@@ -0,0 +1,49 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#ifndef _SELFTESTS_POWERPC_REG_H
7#define _SELFTESTS_POWERPC_REG_H
8
9#define __stringify_1(x) #x
10#define __stringify(x) __stringify_1(x)
11
12#define mfspr(rn) ({unsigned long rval; \
13 asm volatile("mfspr %0," __stringify(rn) \
14 : "=r" (rval)); rval; })
15#define mtspr(rn, v) asm volatile("mtspr " __stringify(rn) ",%0" : \
16 : "r" ((unsigned long)(v)) \
17 : "memory")
18
19#define mb() asm volatile("sync" : : : "memory");
20
21#define SPRN_MMCR2 769
22#define SPRN_MMCRA 770
23#define SPRN_MMCR0 779
24#define MMCR0_PMAO 0x00000080
25#define MMCR0_PMAE 0x04000000
26#define MMCR0_FC 0x80000000
27#define SPRN_EBBHR 804
28#define SPRN_EBBRR 805
29#define SPRN_BESCR 806 /* Branch event status & control register */
30#define SPRN_BESCRS 800 /* Branch event status & control set (1 bits set to 1) */
31#define SPRN_BESCRSU 801 /* Branch event status & control set upper */
32#define SPRN_BESCRR 802 /* Branch event status & control REset (1 bits set to 0) */
33#define SPRN_BESCRRU 803 /* Branch event status & control REset upper */
34
35#define BESCR_PMEO 0x1 /* PMU Event-based exception Occurred */
36#define BESCR_PME (0x1ul << 32) /* PMU Event-based exception Enable */
37
38#define SPRN_PMC1 771
39#define SPRN_PMC2 772
40#define SPRN_PMC3 773
41#define SPRN_PMC4 774
42#define SPRN_PMC5 775
43#define SPRN_PMC6 776
44
45#define SPRN_SIAR 780
46#define SPRN_SDAR 781
47#define SPRN_SIER 768
48
49#endif /* _SELFTESTS_POWERPC_REG_H */
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/reg_access_test.c b/tools/testing/selftests/powerpc/pmu/ebb/reg_access_test.c
new file mode 100644
index 000000000000..0cae66f659a3
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/reg_access_test.c
@@ -0,0 +1,39 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <stdio.h>
7#include <stdlib.h>
8
9#include "ebb.h"
10#include "reg.h"
11
12
13/*
14 * Test basic access to the EBB regs, they should be user accessible with no
15 * kernel interaction required.
16 */
17int reg_access(void)
18{
19 uint64_t val, expected;
20
21 expected = 0x8000000100000000ull;
22 mtspr(SPRN_BESCR, expected);
23 val = mfspr(SPRN_BESCR);
24
25 FAIL_IF(val != expected);
26
27 expected = 0x0000000001000000ull;
28 mtspr(SPRN_EBBHR, expected);
29 val = mfspr(SPRN_EBBHR);
30
31 FAIL_IF(val != expected);
32
33 return 0;
34}
35
36int main(void)
37{
38 return test_harness(reg_access, "reg_access");
39}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/task_event_pinned_vs_ebb_test.c b/tools/testing/selftests/powerpc/pmu/ebb/task_event_pinned_vs_ebb_test.c
new file mode 100644
index 000000000000..d56607e4ffab
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/task_event_pinned_vs_ebb_test.c
@@ -0,0 +1,91 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <signal.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <stdbool.h>
10#include <sys/types.h>
11#include <sys/wait.h>
12#include <unistd.h>
13
14#include "ebb.h"
15
16
17/*
18 * Tests a pinned per-task event vs an EBB - in that order. The pinned per-task
19 * event should prevent the EBB event from being enabled.
20 */
21
22static int setup_child_event(struct event *event, pid_t child_pid)
23{
24 event_init_named(event, 0x400FA, "PM_RUN_INST_CMPL");
25
26 event->attr.pinned = 1;
27
28 event->attr.exclude_kernel = 1;
29 event->attr.exclude_hv = 1;
30 event->attr.exclude_idle = 1;
31
32 FAIL_IF(event_open_with_pid(event, child_pid));
33 FAIL_IF(event_enable(event));
34
35 return 0;
36}
37
38int task_event_pinned_vs_ebb(void)
39{
40 union pipe read_pipe, write_pipe;
41 struct event event;
42 pid_t pid;
43 int rc;
44
45 FAIL_IF(pipe(read_pipe.fds) == -1);
46 FAIL_IF(pipe(write_pipe.fds) == -1);
47
48 pid = fork();
49 if (pid == 0) {
50 /* NB order of pipes looks reversed */
51 exit(ebb_child(write_pipe, read_pipe));
52 }
53
54 /* We setup the task event first */
55 rc = setup_child_event(&event, pid);
56 if (rc) {
57 kill_child_and_wait(pid);
58 return rc;
59 }
60
61 /* Signal the child to install its EBB event and wait */
62 if (sync_with_child(read_pipe, write_pipe))
63 /* If it fails, wait for it to exit */
64 goto wait;
65
66 /* Signal the child to run */
67 FAIL_IF(sync_with_child(read_pipe, write_pipe));
68
69wait:
70 /* We expect it to fail to read the event */
71 FAIL_IF(wait_for_child(pid) != 2);
72 FAIL_IF(event_disable(&event));
73 FAIL_IF(event_read(&event));
74
75 event_report(&event);
76
77 FAIL_IF(event.result.value == 0);
78 /*
79 * For reasons I don't understand enabled is usually just slightly
80 * lower than running. Would be good to confirm why.
81 */
82 FAIL_IF(event.result.enabled == 0);
83 FAIL_IF(event.result.running == 0);
84
85 return 0;
86}
87
88int main(void)
89{
90 return test_harness(task_event_pinned_vs_ebb, "task_event_pinned_vs_ebb");
91}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/task_event_vs_ebb_test.c b/tools/testing/selftests/powerpc/pmu/ebb/task_event_vs_ebb_test.c
new file mode 100644
index 000000000000..eba32196dbbf
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/task_event_vs_ebb_test.c
@@ -0,0 +1,83 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <signal.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <stdbool.h>
10#include <sys/types.h>
11#include <sys/wait.h>
12#include <unistd.h>
13
14#include "ebb.h"
15
16
17/*
18 * Tests a per-task event vs an EBB - in that order. The EBB should push the
19 * per-task event off the PMU.
20 */
21
22static int setup_child_event(struct event *event, pid_t child_pid)
23{
24 event_init_named(event, 0x400FA, "PM_RUN_INST_CMPL");
25
26 event->attr.exclude_kernel = 1;
27 event->attr.exclude_hv = 1;
28 event->attr.exclude_idle = 1;
29
30 FAIL_IF(event_open_with_pid(event, child_pid));
31 FAIL_IF(event_enable(event));
32
33 return 0;
34}
35
36int task_event_vs_ebb(void)
37{
38 union pipe read_pipe, write_pipe;
39 struct event event;
40 pid_t pid;
41 int rc;
42
43 FAIL_IF(pipe(read_pipe.fds) == -1);
44 FAIL_IF(pipe(write_pipe.fds) == -1);
45
46 pid = fork();
47 if (pid == 0) {
48 /* NB order of pipes looks reversed */
49 exit(ebb_child(write_pipe, read_pipe));
50 }
51
52 /* We setup the task event first */
53 rc = setup_child_event(&event, pid);
54 if (rc) {
55 kill_child_and_wait(pid);
56 return rc;
57 }
58
59 /* Signal the child to install its EBB event and wait */
60 if (sync_with_child(read_pipe, write_pipe))
61 /* If it fails, wait for it to exit */
62 goto wait;
63
64 /* Signal the child to run */
65 FAIL_IF(sync_with_child(read_pipe, write_pipe));
66
67wait:
68 /* The EBB event should push the task event off so the child should succeed */
69 FAIL_IF(wait_for_child(pid));
70 FAIL_IF(event_disable(&event));
71 FAIL_IF(event_read(&event));
72
73 event_report(&event);
74
75 /* The task event may have run, or not so we can't assert anything about it */
76
77 return 0;
78}
79
80int main(void)
81{
82 return test_harness(task_event_vs_ebb, "task_event_vs_ebb");
83}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/trace.c b/tools/testing/selftests/powerpc/pmu/ebb/trace.c
new file mode 100644
index 000000000000..251e66ab2aa7
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/trace.c
@@ -0,0 +1,300 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <errno.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10#include <sys/mman.h>
11
12#include "trace.h"
13
14
15struct trace_buffer *trace_buffer_allocate(u64 size)
16{
17 struct trace_buffer *tb;
18
19 if (size < sizeof(*tb)) {
20 fprintf(stderr, "Error: trace buffer too small\n");
21 return NULL;
22 }
23
24 tb = mmap(NULL, size, PROT_READ | PROT_WRITE,
25 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
26 if (tb == MAP_FAILED) {
27 perror("mmap");
28 return NULL;
29 }
30
31 tb->size = size;
32 tb->tail = tb->data;
33 tb->overflow = false;
34
35 return tb;
36}
37
38static bool trace_check_bounds(struct trace_buffer *tb, void *p)
39{
40 return p < ((void *)tb + tb->size);
41}
42
43static bool trace_check_alloc(struct trace_buffer *tb, void *p)
44{
45 /*
46 * If we ever overflowed don't allow any more input. This prevents us
47 * from dropping a large item and then later logging a small one. The
48 * buffer should just stop when overflow happened, not be patchy. If
49 * you're overflowing, make your buffer bigger.
50 */
51 if (tb->overflow)
52 return false;
53
54 if (!trace_check_bounds(tb, p)) {
55 tb->overflow = true;
56 return false;
57 }
58
59 return true;
60}
61
62static void *trace_alloc(struct trace_buffer *tb, int bytes)
63{
64 void *p, *newtail;
65
66 p = tb->tail;
67 newtail = tb->tail + bytes;
68 if (!trace_check_alloc(tb, newtail))
69 return NULL;
70
71 tb->tail = newtail;
72
73 return p;
74}
75
76static struct trace_entry *trace_alloc_entry(struct trace_buffer *tb, int payload_size)
77{
78 struct trace_entry *e;
79
80 e = trace_alloc(tb, sizeof(*e) + payload_size);
81 if (e)
82 e->length = payload_size;
83
84 return e;
85}
86
87int trace_log_reg(struct trace_buffer *tb, u64 reg, u64 value)
88{
89 struct trace_entry *e;
90 u64 *p;
91
92 e = trace_alloc_entry(tb, sizeof(reg) + sizeof(value));
93 if (!e)
94 return -ENOSPC;
95
96 e->type = TRACE_TYPE_REG;
97 p = (u64 *)e->data;
98 *p++ = reg;
99 *p++ = value;
100
101 return 0;
102}
103
104int trace_log_counter(struct trace_buffer *tb, u64 value)
105{
106 struct trace_entry *e;
107 u64 *p;
108
109 e = trace_alloc_entry(tb, sizeof(value));
110 if (!e)
111 return -ENOSPC;
112
113 e->type = TRACE_TYPE_COUNTER;
114 p = (u64 *)e->data;
115 *p++ = value;
116
117 return 0;
118}
119
120int trace_log_string(struct trace_buffer *tb, char *str)
121{
122 struct trace_entry *e;
123 char *p;
124 int len;
125
126 len = strlen(str);
127
128 /* We NULL terminate to make printing easier */
129 e = trace_alloc_entry(tb, len + 1);
130 if (!e)
131 return -ENOSPC;
132
133 e->type = TRACE_TYPE_STRING;
134 p = (char *)e->data;
135 memcpy(p, str, len);
136 p += len;
137 *p = '\0';
138
139 return 0;
140}
141
142int trace_log_indent(struct trace_buffer *tb)
143{
144 struct trace_entry *e;
145
146 e = trace_alloc_entry(tb, 0);
147 if (!e)
148 return -ENOSPC;
149
150 e->type = TRACE_TYPE_INDENT;
151
152 return 0;
153}
154
155int trace_log_outdent(struct trace_buffer *tb)
156{
157 struct trace_entry *e;
158
159 e = trace_alloc_entry(tb, 0);
160 if (!e)
161 return -ENOSPC;
162
163 e->type = TRACE_TYPE_OUTDENT;
164
165 return 0;
166}
167
168static void trace_print_header(int seq, int prefix)
169{
170 printf("%*s[%d]: ", prefix, "", seq);
171}
172
173static char *trace_decode_reg(int reg)
174{
175 switch (reg) {
176 case 769: return "SPRN_MMCR2"; break;
177 case 770: return "SPRN_MMCRA"; break;
178 case 779: return "SPRN_MMCR0"; break;
179 case 804: return "SPRN_EBBHR"; break;
180 case 805: return "SPRN_EBBRR"; break;
181 case 806: return "SPRN_BESCR"; break;
182 case 800: return "SPRN_BESCRS"; break;
183 case 801: return "SPRN_BESCRSU"; break;
184 case 802: return "SPRN_BESCRR"; break;
185 case 803: return "SPRN_BESCRRU"; break;
186 case 771: return "SPRN_PMC1"; break;
187 case 772: return "SPRN_PMC2"; break;
188 case 773: return "SPRN_PMC3"; break;
189 case 774: return "SPRN_PMC4"; break;
190 case 775: return "SPRN_PMC5"; break;
191 case 776: return "SPRN_PMC6"; break;
192 case 780: return "SPRN_SIAR"; break;
193 case 781: return "SPRN_SDAR"; break;
194 case 768: return "SPRN_SIER"; break;
195 }
196
197 return NULL;
198}
199
200static void trace_print_reg(struct trace_entry *e)
201{
202 u64 *p, *reg, *value;
203 char *name;
204
205 p = (u64 *)e->data;
206 reg = p++;
207 value = p;
208
209 name = trace_decode_reg(*reg);
210 if (name)
211 printf("register %-10s = 0x%016llx\n", name, *value);
212 else
213 printf("register %lld = 0x%016llx\n", *reg, *value);
214}
215
216static void trace_print_counter(struct trace_entry *e)
217{
218 u64 *value;
219
220 value = (u64 *)e->data;
221 printf("counter = %lld\n", *value);
222}
223
224static void trace_print_string(struct trace_entry *e)
225{
226 char *str;
227
228 str = (char *)e->data;
229 puts(str);
230}
231
232#define BASE_PREFIX 2
233#define PREFIX_DELTA 8
234
235static void trace_print_entry(struct trace_entry *e, int seq, int *prefix)
236{
237 switch (e->type) {
238 case TRACE_TYPE_REG:
239 trace_print_header(seq, *prefix);
240 trace_print_reg(e);
241 break;
242 case TRACE_TYPE_COUNTER:
243 trace_print_header(seq, *prefix);
244 trace_print_counter(e);
245 break;
246 case TRACE_TYPE_STRING:
247 trace_print_header(seq, *prefix);
248 trace_print_string(e);
249 break;
250 case TRACE_TYPE_INDENT:
251 trace_print_header(seq, *prefix);
252 puts("{");
253 *prefix += PREFIX_DELTA;
254 break;
255 case TRACE_TYPE_OUTDENT:
256 *prefix -= PREFIX_DELTA;
257 if (*prefix < BASE_PREFIX)
258 *prefix = BASE_PREFIX;
259 trace_print_header(seq, *prefix);
260 puts("}");
261 break;
262 default:
263 trace_print_header(seq, *prefix);
264 printf("entry @ %p type %d\n", e, e->type);
265 break;
266 }
267}
268
269void trace_buffer_print(struct trace_buffer *tb)
270{
271 struct trace_entry *e;
272 int i, prefix;
273 void *p;
274
275 printf("Trace buffer dump:\n");
276 printf(" address %p \n", tb);
277 printf(" tail %p\n", tb->tail);
278 printf(" size %llu\n", tb->size);
279 printf(" overflow %s\n", tb->overflow ? "TRUE" : "false");
280 printf(" Content:\n");
281
282 p = tb->data;
283
284 i = 0;
285 prefix = BASE_PREFIX;
286
287 while (trace_check_bounds(tb, p) && p < tb->tail) {
288 e = p;
289
290 trace_print_entry(e, i, &prefix);
291
292 i++;
293 p = (void *)e + sizeof(*e) + e->length;
294 }
295}
296
297void trace_print_location(struct trace_buffer *tb)
298{
299 printf("Trace buffer 0x%llx bytes @ %p\n", tb->size, tb);
300}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/trace.h b/tools/testing/selftests/powerpc/pmu/ebb/trace.h
new file mode 100644
index 000000000000..926458e28c8b
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/trace.h
@@ -0,0 +1,41 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#ifndef _SELFTESTS_POWERPC_PMU_EBB_TRACE_H
7#define _SELFTESTS_POWERPC_PMU_EBB_TRACE_H
8
9#include "utils.h"
10
11#define TRACE_TYPE_REG 1
12#define TRACE_TYPE_COUNTER 2
13#define TRACE_TYPE_STRING 3
14#define TRACE_TYPE_INDENT 4
15#define TRACE_TYPE_OUTDENT 5
16
17struct trace_entry
18{
19 u8 type;
20 u8 length;
21 u8 data[0];
22};
23
24struct trace_buffer
25{
26 u64 size;
27 bool overflow;
28 void *tail;
29 u8 data[0];
30};
31
32struct trace_buffer *trace_buffer_allocate(u64 size);
33int trace_log_reg(struct trace_buffer *tb, u64 reg, u64 value);
34int trace_log_counter(struct trace_buffer *tb, u64 value);
35int trace_log_string(struct trace_buffer *tb, char *str);
36int trace_log_indent(struct trace_buffer *tb);
37int trace_log_outdent(struct trace_buffer *tb);
38void trace_buffer_print(struct trace_buffer *tb);
39void trace_print_location(struct trace_buffer *tb);
40
41#endif /* _SELFTESTS_POWERPC_PMU_EBB_TRACE_H */
diff --git a/tools/testing/selftests/powerpc/pmu/event.c b/tools/testing/selftests/powerpc/pmu/event.c
index 2b2d11df2450..184b36807d48 100644
--- a/tools/testing/selftests/powerpc/pmu/event.c
+++ b/tools/testing/selftests/powerpc/pmu/event.c
@@ -39,7 +39,13 @@ void event_init_named(struct event *e, u64 config, char *name)
39 event_init_opts(e, config, PERF_TYPE_RAW, name); 39 event_init_opts(e, config, PERF_TYPE_RAW, name);
40} 40}
41 41
42void event_init(struct event *e, u64 config)
43{
44 event_init_opts(e, config, PERF_TYPE_RAW, "event");
45}
46
42#define PERF_CURRENT_PID 0 47#define PERF_CURRENT_PID 0
48#define PERF_NO_PID -1
43#define PERF_NO_CPU -1 49#define PERF_NO_CPU -1
44#define PERF_NO_GROUP -1 50#define PERF_NO_GROUP -1
45 51
@@ -59,6 +65,16 @@ int event_open_with_group(struct event *e, int group_fd)
59 return event_open_with_options(e, PERF_CURRENT_PID, PERF_NO_CPU, group_fd); 65 return event_open_with_options(e, PERF_CURRENT_PID, PERF_NO_CPU, group_fd);
60} 66}
61 67
68int event_open_with_pid(struct event *e, pid_t pid)
69{
70 return event_open_with_options(e, pid, PERF_NO_CPU, PERF_NO_GROUP);
71}
72
73int event_open_with_cpu(struct event *e, int cpu)
74{
75 return event_open_with_options(e, PERF_NO_PID, cpu, PERF_NO_GROUP);
76}
77
62int event_open(struct event *e) 78int event_open(struct event *e)
63{ 79{
64 return event_open_with_options(e, PERF_CURRENT_PID, PERF_NO_CPU, PERF_NO_GROUP); 80 return event_open_with_options(e, PERF_CURRENT_PID, PERF_NO_CPU, PERF_NO_GROUP);
@@ -69,6 +85,16 @@ void event_close(struct event *e)
69 close(e->fd); 85 close(e->fd);
70} 86}
71 87
88int event_enable(struct event *e)
89{
90 return ioctl(e->fd, PERF_EVENT_IOC_ENABLE);
91}
92
93int event_disable(struct event *e)
94{
95 return ioctl(e->fd, PERF_EVENT_IOC_DISABLE);
96}
97
72int event_reset(struct event *e) 98int event_reset(struct event *e)
73{ 99{
74 return ioctl(e->fd, PERF_EVENT_IOC_RESET); 100 return ioctl(e->fd, PERF_EVENT_IOC_RESET);
diff --git a/tools/testing/selftests/powerpc/pmu/event.h b/tools/testing/selftests/powerpc/pmu/event.h
index e6993192ff34..a0ea6b1eef73 100644
--- a/tools/testing/selftests/powerpc/pmu/event.h
+++ b/tools/testing/selftests/powerpc/pmu/event.h
@@ -29,8 +29,12 @@ void event_init_named(struct event *e, u64 config, char *name);
29void event_init_opts(struct event *e, u64 config, int type, char *name); 29void event_init_opts(struct event *e, u64 config, int type, char *name);
30int event_open_with_options(struct event *e, pid_t pid, int cpu, int group_fd); 30int event_open_with_options(struct event *e, pid_t pid, int cpu, int group_fd);
31int event_open_with_group(struct event *e, int group_fd); 31int event_open_with_group(struct event *e, int group_fd);
32int event_open_with_pid(struct event *e, pid_t pid);
33int event_open_with_cpu(struct event *e, int cpu);
32int event_open(struct event *e); 34int event_open(struct event *e);
33void event_close(struct event *e); 35void event_close(struct event *e);
36int event_enable(struct event *e);
37int event_disable(struct event *e);
34int event_reset(struct event *e); 38int event_reset(struct event *e);
35int event_read(struct event *e); 39int event_read(struct event *e);
36void event_report_justified(struct event *e, int name_width, int result_width); 40void event_report_justified(struct event *e, int name_width, int result_width);
diff --git a/tools/testing/selftests/powerpc/pmu/lib.c b/tools/testing/selftests/powerpc/pmu/lib.c
new file mode 100644
index 000000000000..0f6a4731d546
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/lib.c
@@ -0,0 +1,252 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#define _GNU_SOURCE /* For CPU_ZERO etc. */
7
8#include <errno.h>
9#include <sched.h>
10#include <setjmp.h>
11#include <stdlib.h>
12#include <sys/wait.h>
13
14#include "utils.h"
15#include "lib.h"
16
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)
45{
46 cpu_set_t mask;
47
48 printf("Binding to cpu %d\n", cpu);
49
50 CPU_ZERO(&mask);
51 CPU_SET(cpu, &mask);
52
53 return sched_setaffinity(0, sizeof(mask), &mask);
54}
55
56#define PARENT_TOKEN 0xAA
57#define CHILD_TOKEN 0x55
58
59int sync_with_child(union pipe read_pipe, union pipe write_pipe)
60{
61 char c = PARENT_TOKEN;
62
63 FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1);
64 FAIL_IF(read(read_pipe.read_fd, &c, 1) != 1);
65 if (c != CHILD_TOKEN) /* sometimes expected */
66 return 1;
67
68 return 0;
69}
70
71int wait_for_parent(union pipe read_pipe)
72{
73 char c;
74
75 FAIL_IF(read(read_pipe.read_fd, &c, 1) != 1);
76 FAIL_IF(c != PARENT_TOKEN);
77
78 return 0;
79}
80
81int notify_parent(union pipe write_pipe)
82{
83 char c = CHILD_TOKEN;
84
85 FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1);
86
87 return 0;
88}
89
90int notify_parent_of_error(union pipe write_pipe)
91{
92 char c = ~CHILD_TOKEN;
93
94 FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1);
95
96 return 0;
97}
98
99int wait_for_child(pid_t child_pid)
100{
101 int rc;
102
103 if (waitpid(child_pid, &rc, 0) == -1) {
104 perror("waitpid");
105 return 1;
106 }
107
108 if (WIFEXITED(rc))
109 rc = WEXITSTATUS(rc);
110 else
111 rc = 1; /* Signal or other */
112
113 return rc;
114}
115
116int kill_child_and_wait(pid_t child_pid)
117{
118 kill(child_pid, SIGTERM);
119
120 return wait_for_child(child_pid);
121}
122
123static int eat_cpu_child(union pipe read_pipe, union pipe write_pipe)
124{
125 volatile int i = 0;
126
127 /*
128 * We are just here to eat cpu and die. So make sure we can be killed,
129 * and also don't do any custom SIGTERM handling.
130 */
131 signal(SIGTERM, SIG_DFL);
132
133 notify_parent(write_pipe);
134 wait_for_parent(read_pipe);
135
136 /* Soak up cpu forever */
137 while (1) i++;
138
139 return 0;
140}
141
142pid_t eat_cpu(int (test_function)(void))
143{
144 union pipe read_pipe, write_pipe;
145 int cpu, rc;
146 pid_t pid;
147
148 cpu = pick_online_cpu();
149 FAIL_IF(cpu < 0);
150 FAIL_IF(bind_to_cpu(cpu));
151
152 if (pipe(read_pipe.fds) == -1)
153 return -1;
154
155 if (pipe(write_pipe.fds) == -1)
156 return -1;
157
158 pid = fork();
159 if (pid == 0)
160 exit(eat_cpu_child(write_pipe, read_pipe));
161
162 if (sync_with_child(read_pipe, write_pipe)) {
163 rc = -1;
164 goto out;
165 }
166
167 printf("main test running as pid %d\n", getpid());
168
169 rc = test_function();
170out:
171 kill(pid, SIGKILL);
172
173 return rc;
174}
175
176struct addr_range libc, vdso;
177
178int parse_proc_maps(void)
179{
180 char execute, name[128];
181 uint64_t start, end;
182 FILE *f;
183 int rc;
184
185 f = fopen("/proc/self/maps", "r");
186 if (!f) {
187 perror("fopen");
188 return -1;
189 }
190
191 do {
192 /* This skips line with no executable which is what we want */
193 rc = fscanf(f, "%lx-%lx %*c%*c%c%*c %*x %*d:%*d %*d %127s\n",
194 &start, &end, &execute, name);
195 if (rc <= 0)
196 break;
197
198 if (execute != 'x')
199 continue;
200
201 if (strstr(name, "libc")) {
202 libc.first = start;
203 libc.last = end - 1;
204 } else if (strstr(name, "[vdso]")) {
205 vdso.first = start;
206 vdso.last = end - 1;
207 }
208 } while(1);
209
210 fclose(f);
211
212 return 0;
213}
214
215#define PARANOID_PATH "/proc/sys/kernel/perf_event_paranoid"
216
217bool require_paranoia_below(int level)
218{
219 unsigned long current;
220 char *end, buf[16];
221 FILE *f;
222 int rc;
223
224 rc = -1;
225
226 f = fopen(PARANOID_PATH, "r");
227 if (!f) {
228 perror("fopen");
229 goto out;
230 }
231
232 if (!fgets(buf, sizeof(buf), f)) {
233 printf("Couldn't read " PARANOID_PATH "?\n");
234 goto out_close;
235 }
236
237 current = strtoul(buf, &end, 10);
238
239 if (end == buf) {
240 printf("Couldn't parse " PARANOID_PATH "?\n");
241 goto out_close;
242 }
243
244 if (current >= level)
245 goto out;
246
247 rc = 0;
248out_close:
249 fclose(f);
250out:
251 return rc;
252}
diff --git a/tools/testing/selftests/powerpc/pmu/lib.h b/tools/testing/selftests/powerpc/pmu/lib.h
new file mode 100644
index 000000000000..ca5d72ae3be6
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/lib.h
@@ -0,0 +1,41 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#ifndef __SELFTESTS_POWERPC_PMU_LIB_H
7#define __SELFTESTS_POWERPC_PMU_LIB_H
8
9#include <stdio.h>
10#include <stdint.h>
11#include <string.h>
12#include <unistd.h>
13
14union pipe {
15 struct {
16 int read_fd;
17 int write_fd;
18 };
19 int fds[2];
20};
21
22extern int pick_online_cpu(void);
23extern int bind_to_cpu(int cpu);
24extern int kill_child_and_wait(pid_t child_pid);
25extern int wait_for_child(pid_t child_pid);
26extern int sync_with_child(union pipe read_pipe, union pipe write_pipe);
27extern int wait_for_parent(union pipe read_pipe);
28extern int notify_parent(union pipe write_pipe);
29extern int notify_parent_of_error(union pipe write_pipe);
30extern pid_t eat_cpu(int (test_function)(void));
31extern bool require_paranoia_below(int level);
32
33struct addr_range {
34 uint64_t first, last;
35};
36
37extern struct addr_range libc, vdso;
38
39int parse_proc_maps(void);
40
41#endif /* __SELFTESTS_POWERPC_PMU_LIB_H */
diff --git a/tools/testing/selftests/powerpc/pmu/loop.S b/tools/testing/selftests/powerpc/pmu/loop.S
index 8820e3df1444..20c1f0876c47 100644
--- a/tools/testing/selftests/powerpc/pmu/loop.S
+++ b/tools/testing/selftests/powerpc/pmu/loop.S
@@ -3,44 +3,41 @@
3 * Licensed under GPLv2. 3 * Licensed under GPLv2.
4 */ 4 */
5 5
6#include <ppc-asm.h>
7
6 .text 8 .text
7 9
8 .global thirty_two_instruction_loop 10FUNC_START(thirty_two_instruction_loop)
9 .type .thirty_two_instruction_loop,@function 11 cmpdi r3,0
10 .section ".opd","aw",@progbits
11thirty_two_instruction_loop:
12 .quad .thirty_two_instruction_loop, .TOC.@tocbase, 0
13 .previous
14.thirty_two_instruction_loop:
15 cmpwi %r3,0
16 beqlr 12 beqlr
17 addi %r4,%r3,1 13 addi r4,r3,1
18 addi %r4,%r4,1 14 addi r4,r4,1
19 addi %r4,%r4,1 15 addi r4,r4,1
20 addi %r4,%r4,1 16 addi r4,r4,1
21 addi %r4,%r4,1 17 addi r4,r4,1
22 addi %r4,%r4,1 18 addi r4,r4,1
23 addi %r4,%r4,1 19 addi r4,r4,1
24 addi %r4,%r4,1 20 addi r4,r4,1
25 addi %r4,%r4,1 21 addi r4,r4,1
26 addi %r4,%r4,1 22 addi r4,r4,1
27 addi %r4,%r4,1 23 addi r4,r4,1
28 addi %r4,%r4,1 24 addi r4,r4,1
29 addi %r4,%r4,1 25 addi r4,r4,1
30 addi %r4,%r4,1 26 addi r4,r4,1
31 addi %r4,%r4,1 27 addi r4,r4,1
32 addi %r4,%r4,1 28 addi r4,r4,1
33 addi %r4,%r4,1 29 addi r4,r4,1
34 addi %r4,%r4,1 30 addi r4,r4,1
35 addi %r4,%r4,1 31 addi r4,r4,1
36 addi %r4,%r4,1 32 addi r4,r4,1
37 addi %r4,%r4,1 33 addi r4,r4,1
38 addi %r4,%r4,1 34 addi r4,r4,1
39 addi %r4,%r4,1 35 addi r4,r4,1
40 addi %r4,%r4,1 36 addi r4,r4,1
41 addi %r4,%r4,1 37 addi r4,r4,1
42 addi %r4,%r4,1 38 addi r4,r4,1
43 addi %r4,%r4,1 39 addi r4,r4,1
44 addi %r4,%r4,1 # 28 addi's 40 addi r4,r4,1 # 28 addi's
45 subi %r3,%r3,1 41 subi r3,r3,1
46 b .thirty_two_instruction_loop 42 b FUNC_NAME(thirty_two_instruction_loop)
43FUNC_END(thirty_two_instruction_loop)
diff --git a/tools/testing/selftests/powerpc/subunit.h b/tools/testing/selftests/powerpc/subunit.h
index 98a22920792d..9c6c4e901ab6 100644
--- a/tools/testing/selftests/powerpc/subunit.h
+++ b/tools/testing/selftests/powerpc/subunit.h
@@ -26,6 +26,11 @@ static inline void test_error(char *name)
26 printf("error: %s\n", name); 26 printf("error: %s\n", name);
27} 27}
28 28
29static inline void test_skip(char *name)
30{
31 printf("skip: %s\n", name);
32}
33
29static inline void test_success(char *name) 34static inline void test_success(char *name)
30{ 35{
31 printf("success: %s\n", name); 36 printf("success: %s\n", name);
diff --git a/tools/testing/selftests/powerpc/tm/Makefile b/tools/testing/selftests/powerpc/tm/Makefile
new file mode 100644
index 000000000000..2cede239a074
--- /dev/null
+++ b/tools/testing/selftests/powerpc/tm/Makefile
@@ -0,0 +1,15 @@
1PROGS := tm-resched-dscr
2
3all: $(PROGS)
4
5$(PROGS): ../harness.c
6
7run_tests: all
8 @-for PROG in $(PROGS); do \
9 ./$$PROG; \
10 done;
11
12clean:
13 rm -f $(PROGS) *.o
14
15.PHONY: all run_tests clean
diff --git a/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c b/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c
new file mode 100644
index 000000000000..42d4c8caad81
--- /dev/null
+++ b/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c
@@ -0,0 +1,98 @@
1/* Test context switching to see if the DSCR SPR is correctly preserved
2 * when within a transaction.
3 *
4 * Note: We assume that the DSCR has been left at the default value (0)
5 * for all CPUs.
6 *
7 * Method:
8 *
9 * Set a value into the DSCR.
10 *
11 * Start a transaction, and suspend it (*).
12 *
13 * Hard loop checking to see if the transaction has become doomed.
14 *
15 * Now that we *may* have been preempted, record the DSCR and TEXASR SPRS.
16 *
17 * If the abort was because of a context switch, check the DSCR value.
18 * Otherwise, try again.
19 *
20 * (*) If the transaction is not suspended we can't see the problem because
21 * the transaction abort handler will restore the DSCR to it's checkpointed
22 * value before we regain control.
23 */
24
25#include <inttypes.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <assert.h>
29#include <asm/tm.h>
30
31#include "utils.h"
32
33#define TBEGIN ".long 0x7C00051D ;"
34#define TEND ".long 0x7C00055D ;"
35#define TCHECK ".long 0x7C00059C ;"
36#define TSUSPEND ".long 0x7C0005DD ;"
37#define TRESUME ".long 0x7C2005DD ;"
38#define SPRN_TEXASR 0x82
39#define SPRN_DSCR 0x03
40
41int test_body(void)
42{
43 uint64_t rv, dscr1 = 1, dscr2, texasr;
44
45 printf("Check DSCR TM context switch: ");
46 fflush(stdout);
47 for (;;) {
48 rv = 1;
49 asm __volatile__ (
50 /* set a known value into the DSCR */
51 "ld 3, %[dscr1];"
52 "mtspr %[sprn_dscr], 3;"
53
54 /* start and suspend a transaction */
55 TBEGIN
56 "beq 1f;"
57 TSUSPEND
58
59 /* hard loop until the transaction becomes doomed */
60 "2: ;"
61 TCHECK
62 "bc 4, 0, 2b;"
63
64 /* record DSCR and TEXASR */
65 "mfspr 3, %[sprn_dscr];"
66 "std 3, %[dscr2];"
67 "mfspr 3, %[sprn_texasr];"
68 "std 3, %[texasr];"
69
70 TRESUME
71 TEND
72 "li %[rv], 0;"
73 "1: ;"
74 : [rv]"=r"(rv), [dscr2]"=m"(dscr2), [texasr]"=m"(texasr)
75 : [dscr1]"m"(dscr1)
76 , [sprn_dscr]"i"(SPRN_DSCR), [sprn_texasr]"i"(SPRN_TEXASR)
77 : "memory", "r3"
78 );
79 assert(rv); /* make sure the transaction aborted */
80 if ((texasr >> 56) != TM_CAUSE_RESCHED) {
81 putchar('.');
82 fflush(stdout);
83 continue;
84 }
85 if (dscr2 != dscr1) {
86 printf(" FAIL\n");
87 return 1;
88 } else {
89 printf(" OK\n");
90 return 0;
91 }
92 }
93}
94
95int main(void)
96{
97 return test_harness(test_body, "tm_resched_dscr");
98}
diff --git a/tools/testing/selftests/powerpc/utils.h b/tools/testing/selftests/powerpc/utils.h
index 0de064406dab..a93777ae0684 100644
--- a/tools/testing/selftests/powerpc/utils.h
+++ b/tools/testing/selftests/powerpc/utils.h
@@ -31,6 +31,18 @@ do { \
31 } \ 31 } \
32} while (0) 32} while (0)
33 33
34/* The test harness uses this, yes it's gross */
35#define MAGIC_SKIP_RETURN_VALUE 99
36
37#define SKIP_IF(x) \
38do { \
39 if ((x)) { \
40 fprintf(stderr, \
41 "[SKIP] Test skipped on line %d\n", __LINE__); \
42 return MAGIC_SKIP_RETURN_VALUE; \
43 } \
44} while (0)
45
34#define _str(s) #s 46#define _str(s) #s
35#define str(s) _str(s) 47#define str(s) _str(s)
36 48
diff --git a/tools/testing/selftests/rcutorture/bin/configinit.sh b/tools/testing/selftests/rcutorture/bin/configinit.sh
index a1be6e62add1..9c3f3d39b934 100755
--- a/tools/testing/selftests/rcutorture/bin/configinit.sh
+++ b/tools/testing/selftests/rcutorture/bin/configinit.sh
@@ -62,7 +62,7 @@ grep '^grep' < $T/u.sh > $T/upd.sh
62echo "cat - $c" >> $T/upd.sh 62echo "cat - $c" >> $T/upd.sh
63make mrproper 63make mrproper
64make $buildloc distclean > $builddir/Make.distclean 2>&1 64make $buildloc distclean > $builddir/Make.distclean 2>&1
65make $buildloc defconfig > $builddir/Make.defconfig.out 2>&1 65make $buildloc $TORTURE_DEFCONFIG > $builddir/Make.defconfig.out 2>&1
66mv $builddir/.config $builddir/.config.sav 66mv $builddir/.config $builddir/.config.sav
67sh $T/upd.sh < $builddir/.config.sav > $builddir/.config 67sh $T/upd.sh < $builddir/.config.sav > $builddir/.config
68cp $builddir/.config $builddir/.config.new 68cp $builddir/.config $builddir/.config.new
diff --git a/tools/testing/selftests/rcutorture/bin/functions.sh b/tools/testing/selftests/rcutorture/bin/functions.sh
index 9b17e810ddc3..d01b865bb100 100644
--- a/tools/testing/selftests/rcutorture/bin/functions.sh
+++ b/tools/testing/selftests/rcutorture/bin/functions.sh
@@ -76,15 +76,39 @@ configfrag_hotplug_cpu () {
76 grep -q '^CONFIG_HOTPLUG_CPU=y$' "$1" 76 grep -q '^CONFIG_HOTPLUG_CPU=y$' "$1"
77} 77}
78 78
79# identify_boot_image qemu-cmd
80#
81# Returns the relative path to the kernel build image. This will be
82# arch/<arch>/boot/bzImage unless overridden with the TORTURE_BOOT_IMAGE
83# environment variable.
84identify_boot_image () {
85 if test -n "$TORTURE_BOOT_IMAGE"
86 then
87 echo $TORTURE_BOOT_IMAGE
88 else
89 case "$1" in
90 qemu-system-x86_64|qemu-system-i386)
91 echo arch/x86/boot/bzImage
92 ;;
93 qemu-system-ppc64)
94 echo arch/powerpc/boot/bzImage
95 ;;
96 *)
97 echo ""
98 ;;
99 esac
100 fi
101}
102
79# identify_qemu builddir 103# identify_qemu builddir
80# 104#
81# Returns our best guess as to which qemu command is appropriate for 105# Returns our best guess as to which qemu command is appropriate for
82# the kernel at hand. Override with the RCU_QEMU_CMD environment variable. 106# the kernel at hand. Override with the TORTURE_QEMU_CMD environment variable.
83identify_qemu () { 107identify_qemu () {
84 local u="`file "$1"`" 108 local u="`file "$1"`"
85 if test -n "$RCU_QEMU_CMD" 109 if test -n "$TORTURE_QEMU_CMD"
86 then 110 then
87 echo $RCU_QEMU_CMD 111 echo $TORTURE_QEMU_CMD
88 elif echo $u | grep -q x86-64 112 elif echo $u | grep -q x86-64
89 then 113 then
90 echo qemu-system-x86_64 114 echo qemu-system-x86_64
@@ -98,7 +122,7 @@ identify_qemu () {
98 echo Cannot figure out what qemu command to use! 1>&2 122 echo Cannot figure out what qemu command to use! 1>&2
99 echo file $1 output: $u 123 echo file $1 output: $u
100 # Usually this will be one of /usr/bin/qemu-system-* 124 # Usually this will be one of /usr/bin/qemu-system-*
101 # Use RCU_QEMU_CMD environment variable or appropriate 125 # Use TORTURE_QEMU_CMD environment variable or appropriate
102 # argument to top-level script. 126 # argument to top-level script.
103 exit 1 127 exit 1
104 fi 128 fi
@@ -107,14 +131,14 @@ identify_qemu () {
107# identify_qemu_append qemu-cmd 131# identify_qemu_append qemu-cmd
108# 132#
109# Output arguments for the qemu "-append" string based on CPU type 133# Output arguments for the qemu "-append" string based on CPU type
110# and the RCU_QEMU_INTERACTIVE environment variable. 134# and the TORTURE_QEMU_INTERACTIVE environment variable.
111identify_qemu_append () { 135identify_qemu_append () {
112 case "$1" in 136 case "$1" in
113 qemu-system-x86_64|qemu-system-i386) 137 qemu-system-x86_64|qemu-system-i386)
114 echo noapic selinux=0 initcall_debug debug 138 echo noapic selinux=0 initcall_debug debug
115 ;; 139 ;;
116 esac 140 esac
117 if test -n "$RCU_QEMU_INTERACTIVE" 141 if test -n "$TORTURE_QEMU_INTERACTIVE"
118 then 142 then
119 echo root=/dev/sda 143 echo root=/dev/sda
120 else 144 else
@@ -124,8 +148,8 @@ identify_qemu_append () {
124 148
125# identify_qemu_args qemu-cmd serial-file 149# identify_qemu_args qemu-cmd serial-file
126# 150#
127# Output arguments for qemu arguments based on the RCU_QEMU_MAC 151# Output arguments for qemu arguments based on the TORTURE_QEMU_MAC
128# and RCU_QEMU_INTERACTIVE environment variables. 152# and TORTURE_QEMU_INTERACTIVE environment variables.
129identify_qemu_args () { 153identify_qemu_args () {
130 case "$1" in 154 case "$1" in
131 qemu-system-x86_64|qemu-system-i386) 155 qemu-system-x86_64|qemu-system-i386)
@@ -133,17 +157,17 @@ identify_qemu_args () {
133 qemu-system-ppc64) 157 qemu-system-ppc64)
134 echo -enable-kvm -M pseries -cpu POWER7 -nodefaults 158 echo -enable-kvm -M pseries -cpu POWER7 -nodefaults
135 echo -device spapr-vscsi 159 echo -device spapr-vscsi
136 if test -n "$RCU_QEMU_INTERACTIVE" -a -n "$RCU_QEMU_MAC" 160 if test -n "$TORTURE_QEMU_INTERACTIVE" -a -n "$TORTURE_QEMU_MAC"
137 then 161 then
138 echo -device spapr-vlan,netdev=net0,mac=$RCU_QEMU_MAC 162 echo -device spapr-vlan,netdev=net0,mac=$TORTURE_QEMU_MAC
139 echo -netdev bridge,br=br0,id=net0 163 echo -netdev bridge,br=br0,id=net0
140 elif test -n "$RCU_QEMU_INTERACTIVE" 164 elif test -n "$TORTURE_QEMU_INTERACTIVE"
141 then 165 then
142 echo -net nic -net user 166 echo -net nic -net user
143 fi 167 fi
144 ;; 168 ;;
145 esac 169 esac
146 if test -n "$RCU_QEMU_INTERACTIVE" 170 if test -n "$TORTURE_QEMU_INTERACTIVE"
147 then 171 then
148 echo -monitor stdio -serial pty -S 172 echo -monitor stdio -serial pty -S
149 else 173 else
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-build.sh b/tools/testing/selftests/rcutorture/bin/kvm-build.sh
index 197901ec10bf..7c1e56b46de4 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm-build.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm-build.sh
@@ -45,9 +45,9 @@ T=/tmp/test-linux.sh.$$
45trap 'rm -rf $T' 0 45trap 'rm -rf $T' 0
46mkdir $T 46mkdir $T
47 47
48cat ${config_template} | grep -v CONFIG_RCU_TORTURE_TEST > $T/config 48grep -v 'CONFIG_[A-Z]*_TORTURE_TEST' < ${config_template} > $T/config
49cat << ___EOF___ >> $T/config 49cat << ___EOF___ >> $T/config
50CONFIG_INITRAMFS_SOURCE="$RCU_INITRD" 50CONFIG_INITRAMFS_SOURCE="$TORTURE_INITRD"
51CONFIG_VIRTIO_PCI=y 51CONFIG_VIRTIO_PCI=y
52CONFIG_VIRTIO_CONSOLE=y 52CONFIG_VIRTIO_CONSOLE=y
53___EOF___ 53___EOF___
@@ -60,7 +60,7 @@ then
60 exit 2 60 exit 2
61fi 61fi
62ncpus=`cpus2use.sh` 62ncpus=`cpus2use.sh`
63make O=$builddir -j$ncpus $RCU_KMAKE_ARG > $builddir/Make.out 2>&1 63make O=$builddir -j$ncpus $TORTURE_KMAKE_ARG > $builddir/Make.out 2>&1
64retval=$? 64retval=$?
65if test $retval -ne 0 || grep "rcu[^/]*": < $builddir/Make.out | egrep -q "Stop|Error|error:|warning:" || egrep -q "Stop|Error|error:" < $builddir/Make.out 65if test $retval -ne 0 || grep "rcu[^/]*": < $builddir/Make.out | egrep -q "Stop|Error|error:|warning:" || egrep -q "Stop|Error|error:" < $builddir/Make.out
66then 66then
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-recheck-lock.sh b/tools/testing/selftests/rcutorture/bin/kvm-recheck-lock.sh
index 829186e19eb1..7f1ff1a8fc4b 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm-recheck-lock.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm-recheck-lock.sh
@@ -35,7 +35,7 @@ configfile=`echo $i | sed -e 's/^.*\///'`
35ncs=`grep "Writes: Total:" $i/console.log 2> /dev/null | tail -1 | sed -e 's/^.* Total: //' -e 's/ .*$//'` 35ncs=`grep "Writes: Total:" $i/console.log 2> /dev/null | tail -1 | sed -e 's/^.* Total: //' -e 's/ .*$//'`
36if test -z "$ncs" 36if test -z "$ncs"
37then 37then
38 echo $configfile 38 echo "$configfile -------"
39else 39else
40 title="$configfile ------- $ncs acquisitions/releases" 40 title="$configfile ------- $ncs acquisitions/releases"
41 dur=`sed -e 's/^.* locktorture.shutdown_secs=//' -e 's/ .*$//' < $i/qemu-cmd 2> /dev/null` 41 dur=`sed -e 's/^.* locktorture.shutdown_secs=//' -e 's/ .*$//' < $i/qemu-cmd 2> /dev/null`
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcu.sh b/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcu.sh
index d75b1dc5ae53..307c4b95f325 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcu.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcu.sh
@@ -35,7 +35,7 @@ configfile=`echo $i | sed -e 's/^.*\///'`
35ngps=`grep ver: $i/console.log 2> /dev/null | tail -1 | sed -e 's/^.* ver: //' -e 's/ .*$//'` 35ngps=`grep ver: $i/console.log 2> /dev/null | tail -1 | sed -e 's/^.* ver: //' -e 's/ .*$//'`
36if test -z "$ngps" 36if test -z "$ngps"
37then 37then
38 echo $configfile 38 echo "$configfile -------"
39else 39else
40 title="$configfile ------- $ngps grace periods" 40 title="$configfile ------- $ngps grace periods"
41 dur=`sed -e 's/^.* rcutorture.shutdown_secs=//' -e 's/ .*$//' < $i/qemu-cmd 2> /dev/null` 41 dur=`sed -e 's/^.* rcutorture.shutdown_secs=//' -e 's/ .*$//' < $i/qemu-cmd 2> /dev/null`
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh b/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh
index a44daaa259a9..ee1f6cae3d70 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh
@@ -25,6 +25,7 @@
25# Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com> 25# Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
26 26
27PATH=`pwd`/tools/testing/selftests/rcutorture/bin:$PATH; export PATH 27PATH=`pwd`/tools/testing/selftests/rcutorture/bin:$PATH; export PATH
28. tools/testing/selftests/rcutorture/bin/functions.sh
28for rd in "$@" 29for rd in "$@"
29do 30do
30 firsttime=1 31 firsttime=1
@@ -39,13 +40,24 @@ do
39 fi 40 fi
40 TORTURE_SUITE="`cat $i/../TORTURE_SUITE`" 41 TORTURE_SUITE="`cat $i/../TORTURE_SUITE`"
41 kvm-recheck-${TORTURE_SUITE}.sh $i 42 kvm-recheck-${TORTURE_SUITE}.sh $i
42 configcheck.sh $i/.config $i/ConfigFragment 43 if test -f "$i/console.log"
43 parse-build.sh $i/Make.out $configfile
44 parse-rcutorture.sh $i/console.log $configfile
45 parse-console.sh $i/console.log $configfile
46 if test -r $i/Warnings
47 then 44 then
48 cat $i/Warnings 45 configcheck.sh $i/.config $i/ConfigFragment
46 parse-build.sh $i/Make.out $configfile
47 parse-torture.sh $i/console.log $configfile
48 parse-console.sh $i/console.log $configfile
49 if test -r $i/Warnings
50 then
51 cat $i/Warnings
52 fi
53 else
54 if test -f "$i/qemu-cmd"
55 then
56 print_bug qemu failed
57 else
58 print_bug Build failed
59 fi
60 echo " $i"
49 fi 61 fi
50 done 62 done
51done 63done
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 94b28bb37d36..27e544e29510 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh
@@ -94,9 +94,17 @@ fi
94# CONFIG_YENTA=n 94# CONFIG_YENTA=n
95if kvm-build.sh $config_template $builddir $T 95if kvm-build.sh $config_template $builddir $T
96then 96then
97 QEMU="`identify_qemu $builddir/vmlinux`"
98 BOOT_IMAGE="`identify_boot_image $QEMU`"
97 cp $builddir/Make*.out $resdir 99 cp $builddir/Make*.out $resdir
98 cp $builddir/.config $resdir 100 cp $builddir/.config $resdir
99 cp $builddir/arch/x86/boot/bzImage $resdir 101 if test -n "$BOOT_IMAGE"
102 then
103 cp $builddir/$BOOT_IMAGE $resdir
104 else
105 echo No identifiable boot image, not running KVM, see $resdir.
106 echo Do the torture scripts know about your architecture?
107 fi
100 parse-build.sh $resdir/Make.out $title 108 parse-build.sh $resdir/Make.out $title
101 if test -f $builddir.wait 109 if test -f $builddir.wait
102 then 110 then
@@ -104,6 +112,7 @@ then
104 fi 112 fi
105else 113else
106 cp $builddir/Make*.out $resdir 114 cp $builddir/Make*.out $resdir
115 cp $builddir/.config $resdir || :
107 echo Build failed, not running KVM, see $resdir. 116 echo Build failed, not running KVM, see $resdir.
108 if test -f $builddir.wait 117 if test -f $builddir.wait
109 then 118 then
@@ -124,9 +133,6 @@ cd $KVM
124kstarttime=`awk 'BEGIN { print systime() }' < /dev/null` 133kstarttime=`awk 'BEGIN { print systime() }' < /dev/null`
125echo ' ---' `date`: Starting kernel 134echo ' ---' `date`: Starting kernel
126 135
127# Determine the appropriate flavor of qemu command.
128QEMU="`identify_qemu $builddir/vmlinux`"
129
130# Generate -smp qemu argument. 136# Generate -smp qemu argument.
131qemu_args="-nographic $qemu_args" 137qemu_args="-nographic $qemu_args"
132cpu_count=`configNR_CPUS.sh $config_template` 138cpu_count=`configNR_CPUS.sh $config_template`
@@ -151,27 +157,38 @@ boot_args="`configfrag_boot_params "$boot_args" "$config_template"`"
151# Generate kernel-version-specific boot parameters 157# Generate kernel-version-specific boot parameters
152boot_args="`per_version_boot_params "$boot_args" $builddir/.config $seconds`" 158boot_args="`per_version_boot_params "$boot_args" $builddir/.config $seconds`"
153 159
154echo $QEMU $qemu_args -m 512 -kernel $builddir/arch/x86/boot/bzImage -append \"$qemu_append $boot_args\" > $resdir/qemu-cmd 160echo $QEMU $qemu_args -m 512 -kernel $builddir/$BOOT_IMAGE -append \"$qemu_append $boot_args\" > $resdir/qemu-cmd
155if test -n "$RCU_BUILDONLY" 161if test -n "$TORTURE_BUILDONLY"
156then 162then
157 echo Build-only run specified, boot/test omitted. 163 echo Build-only run specified, boot/test omitted.
158 exit 0 164 exit 0
159fi 165fi
160$QEMU $qemu_args -m 512 -kernel $builddir/arch/x86/boot/bzImage -append "$qemu_append $boot_args" & 166( $QEMU $qemu_args -m 512 -kernel $builddir/$BOOT_IMAGE -append "$qemu_append $boot_args"; echo $? > $resdir/qemu-retval ) &
161qemu_pid=$! 167qemu_pid=$!
162commandcompleted=0 168commandcompleted=0
163echo Monitoring qemu job at pid $qemu_pid 169echo Monitoring qemu job at pid $qemu_pid
164for ((i=0;i<$seconds;i++)) 170while :
165do 171do
172 kruntime=`awk 'BEGIN { print systime() - '"$kstarttime"' }' < /dev/null`
166 if kill -0 $qemu_pid > /dev/null 2>&1 173 if kill -0 $qemu_pid > /dev/null 2>&1
167 then 174 then
175 if test $kruntime -ge $seconds
176 then
177 break;
178 fi
168 sleep 1 179 sleep 1
169 else 180 else
170 commandcompleted=1 181 commandcompleted=1
171 kruntime=`awk 'BEGIN { print systime() - '"$kstarttime"' }' < /dev/null`
172 if test $kruntime -lt $seconds 182 if test $kruntime -lt $seconds
173 then 183 then
174 echo Completed in $kruntime vs. $seconds >> $resdir/Warnings 2>&1 184 echo Completed in $kruntime vs. $seconds >> $resdir/Warnings 2>&1
185 grep "^(qemu) qemu:" $resdir/kvm-test-1-run.sh.out >> $resdir/Warnings 2>&1
186 killpid="`sed -n "s/^(qemu) qemu: terminating on signal [0-9]* from pid \([0-9]*\).*$/\1/p" $resdir/Warnings`"
187 if test -n "$killpid"
188 then
189 echo "ps -fp $killpid" >> $resdir/Warnings 2>&1
190 ps -fp $killpid >> $resdir/Warnings 2>&1
191 fi
175 else 192 else
176 echo ' ---' `date`: Kernel done 193 echo ' ---' `date`: Kernel done
177 fi 194 fi
@@ -181,23 +198,25 @@ done
181if test $commandcompleted -eq 0 198if test $commandcompleted -eq 0
182then 199then
183 echo Grace period for qemu job at pid $qemu_pid 200 echo Grace period for qemu job at pid $qemu_pid
184 for ((i=0;i<=$grace;i++)) 201 while :
185 do 202 do
203 kruntime=`awk 'BEGIN { print systime() - '"$kstarttime"' }' < /dev/null`
186 if kill -0 $qemu_pid > /dev/null 2>&1 204 if kill -0 $qemu_pid > /dev/null 2>&1
187 then 205 then
188 sleep 1 206 :
189 else 207 else
190 break 208 break
191 fi 209 fi
192 if test $i -eq $grace 210 if test $kruntime -ge $((seconds + grace))
193 then 211 then
194 kruntime=`awk 'BEGIN { print systime() - '"$kstarttime"' }'`
195 echo "!!! Hang at $kruntime vs. $seconds seconds" >> $resdir/Warnings 2>&1 212 echo "!!! Hang at $kruntime vs. $seconds seconds" >> $resdir/Warnings 2>&1
196 kill -KILL $qemu_pid 213 kill -KILL $qemu_pid
214 break
197 fi 215 fi
216 sleep 1
198 done 217 done
199fi 218fi
200 219
201cp $builddir/console.log $resdir 220cp $builddir/console.log $resdir
202parse-${TORTURE_SUITE}torture.sh $resdir/console.log $title 221parse-torture.sh $resdir/console.log $title
203parse-console.sh $resdir/console.log $title 222parse-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 5a78cbf55f06..40285c58653e 100644
--- a/tools/testing/selftests/rcutorture/bin/kvm.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm.sh
@@ -38,9 +38,10 @@ dur=30
38dryrun="" 38dryrun=""
39KVM="`pwd`/tools/testing/selftests/rcutorture"; export KVM 39KVM="`pwd`/tools/testing/selftests/rcutorture"; export KVM
40PATH=${KVM}/bin:$PATH; export PATH 40PATH=${KVM}/bin:$PATH; export PATH
41builddir="${KVM}/b1" 41TORTURE_DEFCONFIG=defconfig
42RCU_INITRD="$KVM/initrd"; export RCU_INITRD 42TORTURE_BOOT_IMAGE=""
43RCU_KMAKE_ARG=""; export RCU_KMAKE_ARG 43TORTURE_INITRD="$KVM/initrd"; export TORTURE_INITRD
44TORTURE_KMAKE_ARG=""
44TORTURE_SUITE=rcu 45TORTURE_SUITE=rcu
45resdir="" 46resdir=""
46configs="" 47configs=""
@@ -53,11 +54,12 @@ kversion=""
53usage () { 54usage () {
54 echo "Usage: $scriptname optional arguments:" 55 echo "Usage: $scriptname optional arguments:"
55 echo " --bootargs kernel-boot-arguments" 56 echo " --bootargs kernel-boot-arguments"
56 echo " --builddir absolute-pathname" 57 echo " --bootimage relative-path-to-kernel-boot-image"
57 echo " --buildonly" 58 echo " --buildonly"
58 echo " --configs \"config-file list\"" 59 echo " --configs \"config-file list\""
59 echo " --cpus N" 60 echo " --cpus N"
60 echo " --datestamp string" 61 echo " --datestamp string"
62 echo " --defconfig string"
61 echo " --dryrun sched|script" 63 echo " --dryrun sched|script"
62 echo " --duration minutes" 64 echo " --duration minutes"
63 echo " --interactive" 65 echo " --interactive"
@@ -67,7 +69,6 @@ usage () {
67 echo " --no-initrd" 69 echo " --no-initrd"
68 echo " --qemu-args qemu-system-..." 70 echo " --qemu-args qemu-system-..."
69 echo " --qemu-cmd qemu-system-..." 71 echo " --qemu-cmd qemu-system-..."
70 echo " --relbuilddir relative-pathname"
71 echo " --results absolute-pathname" 72 echo " --results absolute-pathname"
72 echo " --torture rcu" 73 echo " --torture rcu"
73 exit 1 74 exit 1
@@ -78,17 +79,16 @@ do
78 case "$1" in 79 case "$1" in
79 --bootargs) 80 --bootargs)
80 checkarg --bootargs "(list of kernel boot arguments)" "$#" "$2" '.*' '^--' 81 checkarg --bootargs "(list of kernel boot arguments)" "$#" "$2" '.*' '^--'
81 RCU_BOOTARGS="$2" 82 TORTURE_BOOTARGS="$2"
82 shift 83 shift
83 ;; 84 ;;
84 --builddir) 85 --bootimage)
85 checkarg --builddir "(absolute pathname)" "$#" "$2" '^/' '^error' 86 checkarg --bootimage "(relative path to kernel boot image)" "$#" "$2" '[a-zA-Z0-9][a-zA-Z0-9_]*' '^--'
86 builddir=$2 87 TORTURE_BOOT_IMAGE="$2"
87 gotbuilddir=1
88 shift 88 shift
89 ;; 89 ;;
90 --buildonly) 90 --buildonly)
91 RCU_BUILDONLY=1; export RCU_BUILDONLY 91 TORTURE_BUILDONLY=1
92 ;; 92 ;;
93 --configs) 93 --configs)
94 checkarg --configs "(list of config files)" "$#" "$2" '^[^/]*$' '^--' 94 checkarg --configs "(list of config files)" "$#" "$2" '^[^/]*$' '^--'
@@ -105,6 +105,11 @@ do
105 ds=$2 105 ds=$2
106 shift 106 shift
107 ;; 107 ;;
108 --defconfig)
109 checkarg --defconfig "defconfigtype" "$#" "$2" '^[^/][^/]*$' '^--'
110 TORTURE_DEFCONFIG=$2
111 shift
112 ;;
108 --dryrun) 113 --dryrun)
109 checkarg --dryrun "sched|script" $# "$2" 'sched\|script' '^--' 114 checkarg --dryrun "sched|script" $# "$2" 'sched\|script' '^--'
110 dryrun=$2 115 dryrun=$2
@@ -116,11 +121,11 @@ do
116 shift 121 shift
117 ;; 122 ;;
118 --interactive) 123 --interactive)
119 RCU_QEMU_INTERACTIVE=1; export RCU_QEMU_INTERACTIVE 124 TORTURE_QEMU_INTERACTIVE=1; export TORTURE_QEMU_INTERACTIVE
120 ;; 125 ;;
121 --kmake-arg) 126 --kmake-arg)
122 checkarg --kmake-arg "(kernel make arguments)" $# "$2" '.*' '^error$' 127 checkarg --kmake-arg "(kernel make arguments)" $# "$2" '.*' '^error$'
123 RCU_KMAKE_ARG="$2"; export RCU_KMAKE_ARG 128 TORTURE_KMAKE_ARG="$2"
124 shift 129 shift
125 ;; 130 ;;
126 --kversion) 131 --kversion)
@@ -130,27 +135,20 @@ do
130 ;; 135 ;;
131 --mac) 136 --mac)
132 checkarg --mac "(MAC address)" $# "$2" '^\([0-9a-fA-F]\{2\}:\)\{5\}[0-9a-fA-F]\{2\}$' error 137 checkarg --mac "(MAC address)" $# "$2" '^\([0-9a-fA-F]\{2\}:\)\{5\}[0-9a-fA-F]\{2\}$' error
133 RCU_QEMU_MAC=$2; export RCU_QEMU_MAC 138 TORTURE_QEMU_MAC=$2
134 shift 139 shift
135 ;; 140 ;;
136 --no-initrd) 141 --no-initrd)
137 RCU_INITRD=""; export RCU_INITRD 142 TORTURE_INITRD=""; export TORTURE_INITRD
138 ;; 143 ;;
139 --qemu-args) 144 --qemu-args)
140 checkarg --qemu-args "-qemu args" $# "$2" '^-' '^error' 145 checkarg --qemu-args "-qemu args" $# "$2" '^-' '^error'
141 RCU_QEMU_ARG="$2" 146 TORTURE_QEMU_ARG="$2"
142 shift 147 shift
143 ;; 148 ;;
144 --qemu-cmd) 149 --qemu-cmd)
145 checkarg --qemu-cmd "(qemu-system-...)" $# "$2" 'qemu-system-' '^--' 150 checkarg --qemu-cmd "(qemu-system-...)" $# "$2" 'qemu-system-' '^--'
146 RCU_QEMU_CMD="$2"; export RCU_QEMU_CMD 151 TORTURE_QEMU_CMD="$2"
147 shift
148 ;;
149 --relbuilddir)
150 checkarg --relbuilddir "(relative pathname)" "$#" "$2" '^[^/]*$' '^--'
151 relbuilddir=$2
152 gotrelbuilddir=1
153 builddir=${KVM}/${relbuilddir}
154 shift 152 shift
155 ;; 153 ;;
156 --results) 154 --results)
@@ -184,30 +182,6 @@ then
184 resdir=$KVM/res 182 resdir=$KVM/res
185fi 183fi
186 184
187if test "$dryrun" = ""
188then
189 if ! test -e $resdir
190 then
191 mkdir -p "$resdir" || :
192 fi
193 mkdir $resdir/$ds
194
195 # Be noisy only if running the script.
196 echo Results directory: $resdir/$ds
197 echo $scriptname $args
198
199 touch $resdir/$ds/log
200 echo $scriptname $args >> $resdir/$ds/log
201 echo ${TORTURE_SUITE} > $resdir/$ds/TORTURE_SUITE
202
203 pwd > $resdir/$ds/testid.txt
204 if test -d .git
205 then
206 git status >> $resdir/$ds/testid.txt
207 git rev-parse HEAD >> $resdir/$ds/testid.txt
208 fi
209fi
210
211# Create a file of test-name/#cpus pairs, sorted by decreasing #cpus. 185# Create a file of test-name/#cpus pairs, sorted by decreasing #cpus.
212touch $T/cfgcpu 186touch $T/cfgcpu
213for CF in $configs 187for CF in $configs
@@ -274,7 +248,39 @@ END {
274 248
275# Generate a script to execute the tests in appropriate batches. 249# Generate a script to execute the tests in appropriate batches.
276cat << ___EOF___ > $T/script 250cat << ___EOF___ > $T/script
251CONFIGFRAG="$CONFIGFRAG"; export CONFIGFRAG
252KVM="$KVM"; export KVM
253KVPATH="$KVPATH"; export KVPATH
254PATH="$PATH"; export PATH
255TORTURE_BOOT_IMAGE="$TORTURE_BOOT_IMAGE"; export TORTURE_BOOT_IMAGE
256TORTURE_BUILDONLY="$TORTURE_BUILDONLY"; export TORTURE_BUILDONLY
257TORTURE_DEFCONFIG="$TORTURE_DEFCONFIG"; export TORTURE_DEFCONFIG
258TORTURE_INITRD="$TORTURE_INITRD"; export TORTURE_INITRD
259TORTURE_KMAKE_ARG="$TORTURE_KMAKE_ARG"; export TORTURE_KMAKE_ARG
260TORTURE_QEMU_CMD="$TORTURE_QEMU_CMD"; export TORTURE_QEMU_CMD
261TORTURE_QEMU_INTERACTIVE="$TORTURE_QEMU_INTERACTIVE"; export TORTURE_QEMU_INTERACTIVE
262TORTURE_QEMU_MAC="$TORTURE_QEMU_MAC"; export TORTURE_QEMU_MAC
277TORTURE_SUITE="$TORTURE_SUITE"; export TORTURE_SUITE 263TORTURE_SUITE="$TORTURE_SUITE"; export TORTURE_SUITE
264if ! test -e $resdir
265then
266 mkdir -p "$resdir" || :
267fi
268mkdir $resdir/$ds
269echo Results directory: $resdir/$ds
270echo $scriptname $args
271touch $resdir/$ds/log
272echo $scriptname $args >> $resdir/$ds/log
273echo ${TORTURE_SUITE} > $resdir/$ds/TORTURE_SUITE
274pwd > $resdir/$ds/testid.txt
275if test -d .git
276then
277 git status >> $resdir/$ds/testid.txt
278 git rev-parse HEAD >> $resdir/$ds/testid.txt
279 if ! git diff HEAD > $T/git-diff 2>&1
280 then
281 cp $T/git-diff $resdir/$ds
282 fi
283fi
278___EOF___ 284___EOF___
279awk < $T/cfgcpu.pack \ 285awk < $T/cfgcpu.pack \
280 -v CONFIGDIR="$CONFIGFRAG/$kversion/" \ 286 -v CONFIGDIR="$CONFIGFRAG/$kversion/" \
@@ -282,8 +288,8 @@ awk < $T/cfgcpu.pack \
282 -v ncpus=$cpus \ 288 -v ncpus=$cpus \
283 -v rd=$resdir/$ds/ \ 289 -v rd=$resdir/$ds/ \
284 -v dur=$dur \ 290 -v dur=$dur \
285 -v RCU_QEMU_ARG=$RCU_QEMU_ARG \ 291 -v TORTURE_QEMU_ARG="$TORTURE_QEMU_ARG" \
286 -v RCU_BOOTARGS=$RCU_BOOTARGS \ 292 -v TORTURE_BOOTARGS="$TORTURE_BOOTARGS" \
287'BEGIN { 293'BEGIN {
288 i = 0; 294 i = 0;
289} 295}
@@ -320,7 +326,7 @@ function dump(first, pastlast)
320 print "touch " builddir ".wait"; 326 print "touch " builddir ".wait";
321 print "mkdir " builddir " > /dev/null 2>&1 || :"; 327 print "mkdir " builddir " > /dev/null 2>&1 || :";
322 print "mkdir " rd cfr[jn] " || :"; 328 print "mkdir " rd cfr[jn] " || :";
323 print "kvm-test-1-run.sh " CONFIGDIR cf[j], builddir, rd cfr[jn], dur " \"" RCU_QEMU_ARG "\" \"" RCU_BOOTARGS "\" > " rd cfr[jn] "/kvm-test-1-run.sh.out 2>&1 &" 329 print "kvm-test-1-run.sh " CONFIGDIR cf[j], builddir, rd cfr[jn], dur " \"" TORTURE_QEMU_ARG "\" \"" TORTURE_BOOTARGS "\" > " rd cfr[jn] "/kvm-test-1-run.sh.out 2>&1 &"
324 print "echo ", cfr[jn], cpusr[jn] ovf ": Waiting for build to complete. `date`"; 330 print "echo ", cfr[jn], cpusr[jn] ovf ": Waiting for build to complete. `date`";
325 print "echo ", cfr[jn], cpusr[jn] ovf ": Waiting for build to complete. `date` >> " rd "/log"; 331 print "echo ", cfr[jn], cpusr[jn] ovf ": Waiting for build to complete. `date` >> " rd "/log";
326 print "while test -f " builddir ".wait" 332 print "while test -f " builddir ".wait"
@@ -374,28 +380,26 @@ END {
374 dump(first, i); 380 dump(first, i);
375}' >> $T/script 381}' >> $T/script
376 382
383cat << ___EOF___ >> $T/script
384echo
385echo
386echo " --- `date` Test summary:"
387echo Results directory: $resdir/$ds
388if test -z "$TORTURE_BUILDONLY"
389then
390 kvm-recheck.sh $resdir/$ds
391fi
392___EOF___
393
377if test "$dryrun" = script 394if test "$dryrun" = script
378then 395then
379 # Dump out the script, but define the environment variables that
380 # it needs to run standalone.
381 echo CONFIGFRAG="$CONFIGFRAG; export CONFIGFRAG"
382 echo KVM="$KVM; export KVM"
383 echo KVPATH="$KVPATH; export KVPATH"
384 echo PATH="$PATH; export PATH"
385 echo RCU_BUILDONLY="$RCU_BUILDONLY; export RCU_BUILDONLY"
386 echo RCU_INITRD="$RCU_INITRD; export RCU_INITRD"
387 echo RCU_KMAKE_ARG="$RCU_KMAKE_ARG; export RCU_KMAKE_ARG"
388 echo RCU_QEMU_CMD="$RCU_QEMU_CMD; export RCU_QEMU_CMD"
389 echo RCU_QEMU_INTERACTIVE="$RCU_QEMU_INTERACTIVE; export RCU_QEMU_INTERACTIVE"
390 echo RCU_QEMU_MAC="$RCU_QEMU_MAC; export RCU_QEMU_MAC"
391 echo "mkdir -p "$resdir" || :"
392 echo "mkdir $resdir/$ds"
393 cat $T/script 396 cat $T/script
394 exit 0 397 exit 0
395elif test "$dryrun" = sched 398elif test "$dryrun" = sched
396then 399then
397 # Extract the test run schedule from the script. 400 # Extract the test run schedule from the script.
398 egrep 'start batch|Starting build\.' $T/script | 401 egrep 'Start batch|Starting build\.' $T/script |
402 grep -v ">>" |
399 sed -e 's/:.*$//' -e 's/^echo //' 403 sed -e 's/:.*$//' -e 's/^echo //'
400 exit 0 404 exit 0
401else 405else
@@ -404,9 +408,3 @@ else
404fi 408fi
405 409
406# Tracing: trace_event=rcu:rcu_grace_period,rcu:rcu_future_grace_period,rcu:rcu_grace_period_init,rcu:rcu_nocb_wake,rcu:rcu_preempt_task,rcu:rcu_unlock_preempted_task,rcu:rcu_quiescent_state_report,rcu:rcu_fqs,rcu:rcu_callback,rcu:rcu_kfree_callback,rcu:rcu_batch_start,rcu:rcu_invoke_callback,rcu:rcu_invoke_kfree_callback,rcu:rcu_batch_end,rcu:rcu_torture_read,rcu:rcu_barrier 410# Tracing: trace_event=rcu:rcu_grace_period,rcu:rcu_future_grace_period,rcu:rcu_grace_period_init,rcu:rcu_nocb_wake,rcu:rcu_preempt_task,rcu:rcu_unlock_preempted_task,rcu:rcu_quiescent_state_report,rcu:rcu_fqs,rcu:rcu_callback,rcu:rcu_kfree_callback,rcu:rcu_batch_start,rcu:rcu_invoke_callback,rcu:rcu_invoke_kfree_callback,rcu:rcu_batch_end,rcu:rcu_torture_read,rcu:rcu_barrier
407
408echo
409echo
410echo " --- `date` Test summary:"
411echo Results directory: $resdir/$ds
412kvm-recheck.sh $resdir/$ds
diff --git a/tools/testing/selftests/rcutorture/bin/parse-rcutorture.sh b/tools/testing/selftests/rcutorture/bin/parse-torture.sh
index dd0a275d9796..3455560ab4e4 100755
--- a/tools/testing/selftests/rcutorture/bin/parse-rcutorture.sh
+++ b/tools/testing/selftests/rcutorture/bin/parse-torture.sh
@@ -1,14 +1,14 @@
1#!/bin/sh 1#!/bin/sh
2# 2#
3# Check the console output from an rcutorture run for goodness. 3# Check the console output from a torture run for goodness.
4# The "file" is a pathname on the local system, and "title" is 4# The "file" is a pathname on the local system, and "title" is
5# a text string for error-message purposes. 5# a text string for error-message purposes.
6# 6#
7# The file must contain rcutorture output, but can be interspersed 7# The file must contain torture output, but can be interspersed
8# with other dmesg text. 8# with other dmesg text, as in console-log output.
9# 9#
10# Usage: 10# Usage:
11# sh parse-rcutorture.sh file title 11# sh parse-torture.sh file title
12# 12#
13# This program is free software; you can redistribute it and/or modify 13# This program is free software; you can redistribute it and/or modify
14# it under the terms of the GNU General Public License as published by 14# it under the terms of the GNU General Public License as published by
@@ -28,7 +28,7 @@
28# 28#
29# Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com> 29# Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
30 30
31T=/tmp/parse-rcutorture.sh.$$ 31T=/tmp/parse-torture.sh.$$
32file="$1" 32file="$1"
33title="$2" 33title="$2"
34 34
@@ -36,13 +36,13 @@ trap 'rm -f $T.seq' 0
36 36
37. functions.sh 37. functions.sh
38 38
39# check for presence of rcutorture.txt file 39# check for presence of torture output file.
40 40
41if test -f "$file" -a -r "$file" 41if test -f "$file" -a -r "$file"
42then 42then
43 : 43 :
44else 44else
45 echo $title unreadable rcutorture.txt file: $file 45 echo $title unreadable torture output file: $file
46 exit 1 46 exit 1
47fi 47fi
48 48
@@ -76,9 +76,9 @@ BEGIN {
76END { 76END {
77 if (badseq) { 77 if (badseq) {
78 if (badseqno1 == badseqno2 && badseqno2 == ver) 78 if (badseqno1 == badseqno2 && badseqno2 == ver)
79 print "RCU GP HANG at " ver " rcutorture stat " badseqnr; 79 print "GP HANG at " ver " torture stat " badseqnr;
80 else 80 else
81 print "BAD SEQ " badseqno1 ":" badseqno2 " last:" ver " RCU version " badseqnr; 81 print "BAD SEQ " badseqno1 ":" badseqno2 " last:" ver " version " badseqnr;
82 } 82 }
83 }' > $T.seq 83 }' > $T.seq
84 84
@@ -91,13 +91,13 @@ then
91 exit 2 91 exit 2
92 fi 92 fi
93else 93else
94 if grep -q RCU_HOTPLUG $file 94 if grep -q "_HOTPLUG:" $file
95 then 95 then
96 print_warning HOTPLUG FAILURES $title `cat $T.seq` 96 print_warning HOTPLUG FAILURES $title `cat $T.seq`
97 echo " " $file 97 echo " " $file
98 exit 3 98 exit 3
99 fi 99 fi
100 echo $title no success message, `grep --binary-files=text 'ver:' $file | wc -l` successful RCU version messages 100 echo $title no success message, `grep --binary-files=text 'ver:' $file | wc -l` successful version messages
101 if test -s $T.seq 101 if test -s $T.seq
102 then 102 then
103 print_warning $title `cat $T.seq` 103 print_warning $title `cat $T.seq`
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE02-T b/tools/testing/selftests/rcutorture/configs/rcu/TREE02-T
new file mode 100644
index 000000000000..61c8d9ce5bb2
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE02-T
@@ -0,0 +1,25 @@
1CONFIG_SMP=y
2CONFIG_NR_CPUS=8
3CONFIG_PREEMPT_NONE=n
4CONFIG_PREEMPT_VOLUNTARY=n
5CONFIG_PREEMPT=y
6#CHECK#CONFIG_TREE_PREEMPT_RCU=y
7CONFIG_HZ_PERIODIC=n
8CONFIG_NO_HZ_IDLE=y
9CONFIG_NO_HZ_FULL=n
10CONFIG_RCU_FAST_NO_HZ=n
11CONFIG_RCU_TRACE=y
12CONFIG_HOTPLUG_CPU=n
13CONFIG_SUSPEND=n
14CONFIG_HIBERNATION=n
15CONFIG_RCU_FANOUT=3
16CONFIG_RCU_FANOUT_LEAF=3
17CONFIG_RCU_FANOUT_EXACT=n
18CONFIG_RCU_NOCB_CPU=n
19CONFIG_DEBUG_LOCK_ALLOC=y
20CONFIG_PROVE_LOCKING=n
21CONFIG_PROVE_RCU_DELAY=n
22CONFIG_RCU_CPU_STALL_INFO=n
23CONFIG_RCU_CPU_STALL_VERBOSE=y
24CONFIG_RCU_BOOST=n
25CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE08.boot b/tools/testing/selftests/rcutorture/configs/rcu/TREE08.boot
new file mode 100644
index 000000000000..3b42b8b033cd
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE08.boot
@@ -0,0 +1 @@
rcutorture.torture_type=sched
diff --git a/tools/testing/selftests/sysctl/Makefile b/tools/testing/selftests/sysctl/Makefile
new file mode 100644
index 000000000000..0a92adaf0865
--- /dev/null
+++ b/tools/testing/selftests/sysctl/Makefile
@@ -0,0 +1,19 @@
1# Makefile for sysctl selftests.
2# Expects kernel.sysctl_writes_strict=1.
3
4# No binaries, but make sure arg-less "make" doesn't trigger "run_tests".
5all:
6
7# Allow specific tests to be selected.
8test_num:
9 @/bin/sh ./run_numerictests
10
11test_string:
12 @/bin/sh ./run_stringtests
13
14run_tests: all test_num test_string
15
16# Nothing to clean up.
17clean:
18
19.PHONY: all run_tests clean test_num test_string
diff --git a/tools/testing/selftests/sysctl/common_tests b/tools/testing/selftests/sysctl/common_tests
new file mode 100644
index 000000000000..17d534b1b7b4
--- /dev/null
+++ b/tools/testing/selftests/sysctl/common_tests
@@ -0,0 +1,109 @@
1#!/bin/sh
2
3TEST_FILE=$(mktemp)
4
5echo "== Testing sysctl behavior against ${TARGET} =="
6
7set_orig()
8{
9 echo "${ORIG}" > "${TARGET}"
10}
11
12set_test()
13{
14 echo "${TEST_STR}" > "${TARGET}"
15}
16
17verify()
18{
19 local seen
20 seen=$(cat "$1")
21 if [ "${seen}" != "${TEST_STR}" ]; then
22 return 1
23 fi
24 return 0
25}
26
27trap 'set_orig; rm -f "${TEST_FILE}"' EXIT
28
29rc=0
30
31echo -n "Writing test file ... "
32echo "${TEST_STR}" > "${TEST_FILE}"
33if ! verify "${TEST_FILE}"; then
34 echo "FAIL" >&2
35 exit 1
36else
37 echo "ok"
38fi
39
40echo -n "Checking sysctl is not set to test value ... "
41if verify "${TARGET}"; then
42 echo "FAIL" >&2
43 exit 1
44else
45 echo "ok"
46fi
47
48echo -n "Writing sysctl from shell ... "
49set_test
50if ! verify "${TARGET}"; then
51 echo "FAIL" >&2
52 exit 1
53else
54 echo "ok"
55fi
56
57echo -n "Resetting sysctl to original value ... "
58set_orig
59if verify "${TARGET}"; then
60 echo "FAIL" >&2
61 exit 1
62else
63 echo "ok"
64fi
65
66# Now that we've validated the sanity of "set_test" and "set_orig",
67# we can use those functions to set starting states before running
68# specific behavioral tests.
69
70echo -n "Writing entire sysctl in single write ... "
71set_orig
72dd if="${TEST_FILE}" of="${TARGET}" bs=4096 2>/dev/null
73if ! verify "${TARGET}"; then
74 echo "FAIL" >&2
75 rc=1
76else
77 echo "ok"
78fi
79
80echo -n "Writing middle of sysctl after synchronized seek ... "
81set_test
82dd if="${TEST_FILE}" of="${TARGET}" bs=1 seek=1 skip=1 2>/dev/null
83if ! verify "${TARGET}"; then
84 echo "FAIL" >&2
85 rc=1
86else
87 echo "ok"
88fi
89
90echo -n "Writing beyond end of sysctl ... "
91set_orig
92dd if="${TEST_FILE}" of="${TARGET}" bs=20 seek=2 2>/dev/null
93if verify "${TARGET}"; then
94 echo "FAIL" >&2
95 rc=1
96else
97 echo "ok"
98fi
99
100echo -n "Writing sysctl with multiple long writes ... "
101set_orig
102(perl -e 'print "A" x 50;'; echo "${TEST_STR}") | \
103 dd of="${TARGET}" bs=50 2>/dev/null
104if verify "${TARGET}"; then
105 echo "FAIL" >&2
106 rc=1
107else
108 echo "ok"
109fi
diff --git a/tools/testing/selftests/sysctl/run_numerictests b/tools/testing/selftests/sysctl/run_numerictests
new file mode 100644
index 000000000000..8510f93f2d14
--- /dev/null
+++ b/tools/testing/selftests/sysctl/run_numerictests
@@ -0,0 +1,10 @@
1#!/bin/sh
2
3SYSCTL="/proc/sys"
4TARGET="${SYSCTL}/vm/swappiness"
5ORIG=$(cat "${TARGET}")
6TEST_STR=$(( $ORIG + 1 ))
7
8. ./common_tests
9
10exit $rc
diff --git a/tools/testing/selftests/sysctl/run_stringtests b/tools/testing/selftests/sysctl/run_stringtests
new file mode 100644
index 000000000000..90a9293d520c
--- /dev/null
+++ b/tools/testing/selftests/sysctl/run_stringtests
@@ -0,0 +1,77 @@
1#!/bin/sh
2
3SYSCTL="/proc/sys"
4TARGET="${SYSCTL}/kernel/domainname"
5ORIG=$(cat "${TARGET}")
6TEST_STR="Testing sysctl"
7
8. ./common_tests
9
10# Only string sysctls support seeking/appending.
11MAXLEN=65
12
13echo -n "Writing entire sysctl in short writes ... "
14set_orig
15dd if="${TEST_FILE}" of="${TARGET}" bs=1 2>/dev/null
16if ! verify "${TARGET}"; then
17 echo "FAIL" >&2
18 rc=1
19else
20 echo "ok"
21fi
22
23echo -n "Writing middle of sysctl after unsynchronized seek ... "
24set_test
25dd if="${TEST_FILE}" of="${TARGET}" bs=1 seek=1 2>/dev/null
26if verify "${TARGET}"; then
27 echo "FAIL" >&2
28 rc=1
29else
30 echo "ok"
31fi
32
33echo -n "Checking sysctl maxlen is at least $MAXLEN ... "
34set_orig
35perl -e 'print "A" x ('"${MAXLEN}"'-2), "B";' | \
36 dd of="${TARGET}" bs="${MAXLEN}" 2>/dev/null
37if ! grep -q B "${TARGET}"; then
38 echo "FAIL" >&2
39 rc=1
40else
41 echo "ok"
42fi
43
44echo -n "Checking sysctl keeps original string on overflow append ... "
45set_orig
46perl -e 'print "A" x ('"${MAXLEN}"'-1), "B";' | \
47 dd of="${TARGET}" bs=$(( MAXLEN - 1 )) 2>/dev/null
48if grep -q B "${TARGET}"; then
49 echo "FAIL" >&2
50 rc=1
51else
52 echo "ok"
53fi
54
55echo -n "Checking sysctl stays NULL terminated on write ... "
56set_orig
57perl -e 'print "A" x ('"${MAXLEN}"'-1), "B";' | \
58 dd of="${TARGET}" bs="${MAXLEN}" 2>/dev/null
59if grep -q B "${TARGET}"; then
60 echo "FAIL" >&2
61 rc=1
62else
63 echo "ok"
64fi
65
66echo -n "Checking sysctl stays NULL terminated on overwrite ... "
67set_orig
68perl -e 'print "A" x ('"${MAXLEN}"'-1), "BB";' | \
69 dd of="${TARGET}" bs=$(( $MAXLEN + 1 )) 2>/dev/null
70if grep -q B "${TARGET}"; then
71 echo "FAIL" >&2
72 rc=1
73else
74 echo "ok"
75fi
76
77exit $rc
diff --git a/tools/thermal/tmon/Makefile b/tools/thermal/tmon/Makefile
index 447321104ec0..e775adcbd29f 100644
--- a/tools/thermal/tmon/Makefile
+++ b/tools/thermal/tmon/Makefile
@@ -21,7 +21,7 @@ OBJS = tmon.o tui.o sysfs.o pid.o
21OBJS += 21OBJS +=
22 22
23tmon: $(OBJS) Makefile tmon.h 23tmon: $(OBJS) Makefile tmon.h
24 $(CC) ${CFLAGS} $(LDFLAGS) $(OBJS) -o $(TARGET) -lm -lpanel -lncursesw -lpthread 24 $(CC) ${CFLAGS} $(LDFLAGS) $(OBJS) -o $(TARGET) -lm -lpanel -lncursesw -ltinfo -lpthread
25 25
26valgrind: tmon 26valgrind: tmon
27 sudo valgrind -v --track-origins=yes --tool=memcheck --leak-check=yes --show-reachable=yes --num-callers=20 --track-fds=yes ./$(TARGET) 1> /dev/null 27 sudo valgrind -v --track-origins=yes --tool=memcheck --leak-check=yes --show-reachable=yes --num-callers=20 --track-fds=yes ./$(TARGET) 1> /dev/null
diff --git a/tools/thermal/tmon/tmon.c b/tools/thermal/tmon/tmon.c
index b30f531173e4..09b7c3218334 100644
--- a/tools/thermal/tmon/tmon.c
+++ b/tools/thermal/tmon/tmon.c
@@ -142,6 +142,7 @@ static void start_syslog(void)
142static void prepare_logging(void) 142static void prepare_logging(void)
143{ 143{
144 int i; 144 int i;
145 struct stat logstat;
145 146
146 if (!logging) 147 if (!logging)
147 return; 148 return;
@@ -152,6 +153,29 @@ static void prepare_logging(void)
152 return; 153 return;
153 } 154 }
154 155
156 if (lstat(TMON_LOG_FILE, &logstat) < 0) {
157 syslog(LOG_ERR, "Unable to stat log file %s\n", TMON_LOG_FILE);
158 fclose(tmon_log);
159 tmon_log = NULL;
160 return;
161 }
162
163 /* The log file must be a regular file owned by us */
164 if (S_ISLNK(logstat.st_mode)) {
165 syslog(LOG_ERR, "Log file is a symlink. Will not log\n");
166 fclose(tmon_log);
167 tmon_log = NULL;
168 return;
169 }
170
171 if (logstat.st_uid != getuid()) {
172 syslog(LOG_ERR, "We don't own the log file. Not logging\n");
173 fclose(tmon_log);
174 tmon_log = NULL;
175 return;
176 }
177
178
155 fprintf(tmon_log, "#----------- THERMAL SYSTEM CONFIG -------------\n"); 179 fprintf(tmon_log, "#----------- THERMAL SYSTEM CONFIG -------------\n");
156 for (i = 0; i < ptdata.nr_tz_sensor; i++) { 180 for (i = 0; i < ptdata.nr_tz_sensor; i++) {
157 char binding_str[33]; /* size of long + 1 */ 181 char binding_str[33]; /* size of long + 1 */
@@ -331,7 +355,7 @@ static void start_daemon_mode()
331 disable_tui(); 355 disable_tui();
332 356
333 /* change the file mode mask */ 357 /* change the file mode mask */
334 umask(0); 358 umask(S_IWGRP | S_IWOTH);
335 359
336 /* new SID for the daemon process */ 360 /* new SID for the daemon process */
337 sid = setsid(); 361 sid = setsid();
diff --git a/tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c b/tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c
new file mode 100644
index 000000000000..87216a0c4a8b
--- /dev/null
+++ b/tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c
@@ -0,0 +1,349 @@
1#define _BSD_SOURCE /* for endian.h */
2
3#include <endian.h>
4#include <errno.h>
5#include <fcntl.h>
6#include <stdarg.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10#include <sys/ioctl.h>
11#include <sys/stat.h>
12#include <sys/types.h>
13#include <sys/poll.h>
14#include <unistd.h>
15#include <stdbool.h>
16#include <sys/eventfd.h>
17
18#include "libaio.h"
19#define IOCB_FLAG_RESFD (1 << 0)
20
21#include <linux/usb/functionfs.h>
22
23#define BUF_LEN 8192
24#define BUFS_MAX 128
25#define AIO_MAX (BUFS_MAX*2)
26
27/******************** Descriptors and Strings *******************************/
28
29static const struct {
30 struct usb_functionfs_descs_head header;
31 struct {
32 struct usb_interface_descriptor intf;
33 struct usb_endpoint_descriptor_no_audio bulk_sink;
34 struct usb_endpoint_descriptor_no_audio bulk_source;
35 } __attribute__ ((__packed__)) fs_descs, hs_descs;
36} __attribute__ ((__packed__)) descriptors = {
37 .header = {
38 .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC),
39 .length = htole32(sizeof(descriptors)),
40 .fs_count = 3,
41 .hs_count = 3,
42 },
43 .fs_descs = {
44 .intf = {
45 .bLength = sizeof(descriptors.fs_descs.intf),
46 .bDescriptorType = USB_DT_INTERFACE,
47 .bNumEndpoints = 2,
48 .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
49 .iInterface = 1,
50 },
51 .bulk_sink = {
52 .bLength = sizeof(descriptors.fs_descs.bulk_sink),
53 .bDescriptorType = USB_DT_ENDPOINT,
54 .bEndpointAddress = 1 | USB_DIR_IN,
55 .bmAttributes = USB_ENDPOINT_XFER_BULK,
56 },
57 .bulk_source = {
58 .bLength = sizeof(descriptors.fs_descs.bulk_source),
59 .bDescriptorType = USB_DT_ENDPOINT,
60 .bEndpointAddress = 2 | USB_DIR_OUT,
61 .bmAttributes = USB_ENDPOINT_XFER_BULK,
62 },
63 },
64 .hs_descs = {
65 .intf = {
66 .bLength = sizeof(descriptors.hs_descs.intf),
67 .bDescriptorType = USB_DT_INTERFACE,
68 .bNumEndpoints = 2,
69 .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
70 .iInterface = 1,
71 },
72 .bulk_sink = {
73 .bLength = sizeof(descriptors.hs_descs.bulk_sink),
74 .bDescriptorType = USB_DT_ENDPOINT,
75 .bEndpointAddress = 1 | USB_DIR_IN,
76 .bmAttributes = USB_ENDPOINT_XFER_BULK,
77 .wMaxPacketSize = htole16(512),
78 },
79 .bulk_source = {
80 .bLength = sizeof(descriptors.hs_descs.bulk_source),
81 .bDescriptorType = USB_DT_ENDPOINT,
82 .bEndpointAddress = 2 | USB_DIR_OUT,
83 .bmAttributes = USB_ENDPOINT_XFER_BULK,
84 .wMaxPacketSize = htole16(512),
85 },
86 },
87};
88
89#define STR_INTERFACE "AIO Test"
90
91static const struct {
92 struct usb_functionfs_strings_head header;
93 struct {
94 __le16 code;
95 const char str1[sizeof(STR_INTERFACE)];
96 } __attribute__ ((__packed__)) lang0;
97} __attribute__ ((__packed__)) strings = {
98 .header = {
99 .magic = htole32(FUNCTIONFS_STRINGS_MAGIC),
100 .length = htole32(sizeof(strings)),
101 .str_count = htole32(1),
102 .lang_count = htole32(1),
103 },
104 .lang0 = {
105 htole16(0x0409), /* en-us */
106 STR_INTERFACE,
107 },
108};
109
110/********************** Buffer structure *******************************/
111
112struct io_buffer {
113 struct iocb **iocb;
114 unsigned char **buf;
115 unsigned cnt;
116 unsigned len;
117 unsigned requested;
118};
119
120/******************** Endpoints handling *******************************/
121
122static void display_event(struct usb_functionfs_event *event)
123{
124 static const char *const names[] = {
125 [FUNCTIONFS_BIND] = "BIND",
126 [FUNCTIONFS_UNBIND] = "UNBIND",
127 [FUNCTIONFS_ENABLE] = "ENABLE",
128 [FUNCTIONFS_DISABLE] = "DISABLE",
129 [FUNCTIONFS_SETUP] = "SETUP",
130 [FUNCTIONFS_SUSPEND] = "SUSPEND",
131 [FUNCTIONFS_RESUME] = "RESUME",
132 };
133 switch (event->type) {
134 case FUNCTIONFS_BIND:
135 case FUNCTIONFS_UNBIND:
136 case FUNCTIONFS_ENABLE:
137 case FUNCTIONFS_DISABLE:
138 case FUNCTIONFS_SETUP:
139 case FUNCTIONFS_SUSPEND:
140 case FUNCTIONFS_RESUME:
141 printf("Event %s\n", names[event->type]);
142 }
143}
144
145static void handle_ep0(int ep0, bool *ready)
146{
147 int ret;
148 struct usb_functionfs_event event;
149
150 ret = read(ep0, &event, sizeof(event));
151 if (!ret) {
152 perror("unable to read event from ep0");
153 return;
154 }
155 display_event(&event);
156 switch (event.type) {
157 case FUNCTIONFS_SETUP:
158 if (event.u.setup.bRequestType & USB_DIR_IN)
159 write(ep0, NULL, 0);
160 else
161 read(ep0, NULL, 0);
162 break;
163
164 case FUNCTIONFS_ENABLE:
165 *ready = true;
166 break;
167
168 case FUNCTIONFS_DISABLE:
169 *ready = false;
170 break;
171
172 default:
173 break;
174 }
175}
176
177void init_bufs(struct io_buffer *iobuf, unsigned n, unsigned len)
178{
179 unsigned i;
180 iobuf->buf = malloc(n*sizeof(*iobuf->buf));
181 iobuf->iocb = malloc(n*sizeof(*iobuf->iocb));
182 iobuf->cnt = n;
183 iobuf->len = len;
184 iobuf->requested = 0;
185 for (i = 0; i < n; ++i) {
186 iobuf->buf[i] = malloc(len*sizeof(**iobuf->buf));
187 iobuf->iocb[i] = malloc(sizeof(**iobuf->iocb));
188 }
189 iobuf->cnt = n;
190}
191
192void delete_bufs(struct io_buffer *iobuf)
193{
194 unsigned i;
195 for (i = 0; i < iobuf->cnt; ++i) {
196 free(iobuf->buf[i]);
197 free(iobuf->iocb[i]);
198 }
199 free(iobuf->buf);
200 free(iobuf->iocb);
201}
202
203int main(int argc, char *argv[])
204{
205 int ret;
206 unsigned i, j;
207 char *ep_path;
208
209 int ep0, ep1;
210
211 io_context_t ctx;
212
213 int evfd;
214 fd_set rfds;
215
216 struct io_buffer iobuf[2];
217 int actual = 0;
218 bool ready;
219
220 if (argc != 2) {
221 printf("ffs directory not specified!\n");
222 return 1;
223 }
224
225 ep_path = malloc(strlen(argv[1]) + 4 /* "/ep#" */ + 1 /* '\0' */);
226 if (!ep_path) {
227 perror("malloc");
228 return 1;
229 }
230
231 /* open endpoint files */
232 sprintf(ep_path, "%s/ep0", argv[1]);
233 ep0 = open(ep_path, O_RDWR);
234 if (ep0 < 0) {
235 perror("unable to open ep0");
236 return 1;
237 }
238 if (write(ep0, &descriptors, sizeof(descriptors)) < 0) {
239 perror("unable do write descriptors");
240 return 1;
241 }
242 if (write(ep0, &strings, sizeof(strings)) < 0) {
243 perror("unable to write strings");
244 return 1;
245 }
246 sprintf(ep_path, "%s/ep1", argv[1]);
247 ep1 = open(ep_path, O_RDWR);
248 if (ep1 < 0) {
249 perror("unable to open ep1");
250 return 1;
251 }
252
253 free(ep_path);
254
255 memset(&ctx, 0, sizeof(ctx));
256 /* setup aio context to handle up to AIO_MAX requests */
257 if (io_setup(AIO_MAX, &ctx) < 0) {
258 perror("unable to setup aio");
259 return 1;
260 }
261
262 evfd = eventfd(0, 0);
263 if (evfd < 0) {
264 perror("unable to open eventfd");
265 return 1;
266 }
267
268 for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i)
269 init_bufs(&iobuf[i], BUFS_MAX, BUF_LEN);
270
271 while (1) {
272 FD_ZERO(&rfds);
273 FD_SET(ep0, &rfds);
274 FD_SET(evfd, &rfds);
275
276 ret = select(((ep0 > evfd) ? ep0 : evfd)+1,
277 &rfds, NULL, NULL, NULL);
278 if (ret < 0) {
279 if (errno == EINTR)
280 continue;
281 perror("select");
282 break;
283 }
284
285 if (FD_ISSET(ep0, &rfds))
286 handle_ep0(ep0, &ready);
287
288 /* we are waiting for function ENABLE */
289 if (!ready)
290 continue;
291
292 /*
293 * when we're preparing new data to submit,
294 * second buffer being transmitted
295 */
296 for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i) {
297 if (iobuf[i].requested)
298 continue;
299 /* prepare requests */
300 for (j = 0; j < iobuf[i].cnt; ++j) {
301 io_prep_pwrite(iobuf[i].iocb[j], ep1,
302 iobuf[i].buf[j],
303 iobuf[i].len, 0);
304 /* enable eventfd notification */
305 iobuf[i].iocb[j]->u.c.flags |= IOCB_FLAG_RESFD;
306 iobuf[i].iocb[j]->u.c.resfd = evfd;
307 }
308 /* submit table of requests */
309 ret = io_submit(ctx, iobuf[i].cnt, iobuf[i].iocb);
310 if (ret >= 0) {
311 iobuf[i].requested = ret;
312 printf("submit: %d requests buf: %d\n", ret, i);
313 } else
314 perror("unable to submit reqests");
315 }
316
317 /* if event is ready to read */
318 if (!FD_ISSET(evfd, &rfds))
319 continue;
320
321 uint64_t ev_cnt;
322 ret = read(evfd, &ev_cnt, sizeof(ev_cnt));
323 if (ret < 0) {
324 perror("unable to read eventfd");
325 break;
326 }
327
328 struct io_event e[BUFS_MAX];
329 /* we read aio events */
330 ret = io_getevents(ctx, 1, BUFS_MAX, e, NULL);
331 if (ret > 0) /* if we got events */
332 iobuf[actual].requested -= ret;
333
334 /* if all req's from iocb completed */
335 if (!iobuf[actual].requested)
336 actual = (actual + 1)%(sizeof(iobuf)/sizeof(*iobuf));
337 }
338
339 /* free resources */
340
341 for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i)
342 delete_bufs(&iobuf[i]);
343 io_destroy(ctx);
344
345 close(ep1);
346 close(ep0);
347
348 return 0;
349}
diff --git a/tools/usb/ffs-aio-example/multibuff/host_app/Makefile b/tools/usb/ffs-aio-example/multibuff/host_app/Makefile
new file mode 100644
index 000000000000..8c4a6f0aa82d
--- /dev/null
+++ b/tools/usb/ffs-aio-example/multibuff/host_app/Makefile
@@ -0,0 +1,13 @@
1CC = gcc
2LIBUSB_CFLAGS = $(shell pkg-config --cflags libusb-1.0)
3LIBUSB_LIBS = $(shell pkg-config --libs libusb-1.0)
4WARNINGS = -Wall -Wextra
5CFLAGS = $(LIBUSB_CFLAGS) $(WARNINGS)
6LDFLAGS = $(LIBUSB_LIBS)
7
8all: test
9%: %.c
10 $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
11
12clean:
13 $(RM) test
diff --git a/tools/usb/ffs-aio-example/multibuff/host_app/test.c b/tools/usb/ffs-aio-example/multibuff/host_app/test.c
new file mode 100644
index 000000000000..b0ad8747d03f
--- /dev/null
+++ b/tools/usb/ffs-aio-example/multibuff/host_app/test.c
@@ -0,0 +1,146 @@
1#include <libusb.h>
2#include <stdio.h>
3#include <string.h>
4#include <unistd.h>
5
6#define VENDOR 0x1d6b
7#define PRODUCT 0x0105
8
9/* endpoints indexes */
10
11#define EP_BULK_IN (1 | LIBUSB_ENDPOINT_IN)
12#define EP_BULK_OUT (2 | LIBUSB_ENDPOINT_OUT)
13
14#define BUF_LEN 8192
15
16/*
17 * struct test_state - describes test program state
18 * @list: list of devices returned by libusb_get_device_list function
19 * @found: pointer to struct describing tested device
20 * @ctx: context, set to NULL
21 * @handle: handle of tested device
22 * @attached: indicates that device was attached to kernel, and has to be
23 * reattached at the end of test program
24 */
25
26struct test_state {
27 libusb_device *found;
28 libusb_context *ctx;
29 libusb_device_handle *handle;
30 int attached;
31};
32
33/*
34 * test_init - initialize test program
35 */
36
37int test_init(struct test_state *state)
38{
39 int i, ret;
40 ssize_t cnt;
41 libusb_device **list;
42
43 state->found = NULL;
44 state->ctx = NULL;
45 state->handle = NULL;
46 state->attached = 0;
47
48 ret = libusb_init(&state->ctx);
49 if (ret) {
50 printf("cannot init libusb: %s\n", libusb_error_name(ret));
51 return 1;
52 }
53
54 cnt = libusb_get_device_list(state->ctx, &list);
55 if (cnt <= 0) {
56 printf("no devices found\n");
57 goto error1;
58 }
59
60 for (i = 0; i < cnt; ++i) {
61 libusb_device *dev = list[i];
62 struct libusb_device_descriptor desc;
63 ret = libusb_get_device_descriptor(dev, &desc);
64 if (ret) {
65 printf("unable to get device descriptor: %s\n",
66 libusb_error_name(ret));
67 goto error2;
68 }
69 if (desc.idVendor == VENDOR && desc.idProduct == PRODUCT) {
70 state->found = dev;
71 break;
72 }
73 }
74
75 if (!state->found) {
76 printf("no devices found\n");
77 goto error2;
78 }
79
80 ret = libusb_open(state->found, &state->handle);
81 if (ret) {
82 printf("cannot open device: %s\n", libusb_error_name(ret));
83 goto error2;
84 }
85
86 if (libusb_claim_interface(state->handle, 0)) {
87 ret = libusb_detach_kernel_driver(state->handle, 0);
88 if (ret) {
89 printf("unable to detach kernel driver: %s\n",
90 libusb_error_name(ret));
91 goto error3;
92 }
93 state->attached = 1;
94 ret = libusb_claim_interface(state->handle, 0);
95 if (ret) {
96 printf("cannot claim interface: %s\n",
97 libusb_error_name(ret));
98 goto error4;
99 }
100 }
101
102 return 0;
103
104error4:
105 if (state->attached == 1)
106 libusb_attach_kernel_driver(state->handle, 0);
107
108error3:
109 libusb_close(state->handle);
110
111error2:
112 libusb_free_device_list(list, 1);
113
114error1:
115 libusb_exit(state->ctx);
116 return 1;
117}
118
119/*
120 * test_exit - cleanup test program
121 */
122
123void test_exit(struct test_state *state)
124{
125 libusb_release_interface(state->handle, 0);
126 if (state->attached == 1)
127 libusb_attach_kernel_driver(state->handle, 0);
128 libusb_close(state->handle);
129 libusb_exit(state->ctx);
130}
131
132int main(void)
133{
134 struct test_state state;
135
136 if (test_init(&state))
137 return 1;
138
139 while (1) {
140 static unsigned char buffer[BUF_LEN];
141 int bytes;
142 libusb_bulk_transfer(state.handle, EP_BULK_IN, buffer, BUF_LEN,
143 &bytes, 500);
144 }
145 test_exit(&state);
146}
diff --git a/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c b/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c
new file mode 100644
index 000000000000..f558664a3317
--- /dev/null
+++ b/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c
@@ -0,0 +1,335 @@
1#define _BSD_SOURCE /* for endian.h */
2
3#include <endian.h>
4#include <errno.h>
5#include <fcntl.h>
6#include <stdarg.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10#include <sys/ioctl.h>
11#include <sys/stat.h>
12#include <sys/types.h>
13#include <sys/poll.h>
14#include <unistd.h>
15#include <stdbool.h>
16#include <sys/eventfd.h>
17
18#include "libaio.h"
19#define IOCB_FLAG_RESFD (1 << 0)
20
21#include <linux/usb/functionfs.h>
22
23#define BUF_LEN 8192
24
25/******************** Descriptors and Strings *******************************/
26
27static const struct {
28 struct usb_functionfs_descs_head header;
29 struct {
30 struct usb_interface_descriptor intf;
31 struct usb_endpoint_descriptor_no_audio bulk_sink;
32 struct usb_endpoint_descriptor_no_audio bulk_source;
33 } __attribute__ ((__packed__)) fs_descs, hs_descs;
34} __attribute__ ((__packed__)) descriptors = {
35 .header = {
36 .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC),
37 .length = htole32(sizeof(descriptors)),
38 .fs_count = 3,
39 .hs_count = 3,
40 },
41 .fs_descs = {
42 .intf = {
43 .bLength = sizeof(descriptors.fs_descs.intf),
44 .bDescriptorType = USB_DT_INTERFACE,
45 .bNumEndpoints = 2,
46 .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
47 .iInterface = 1,
48 },
49 .bulk_sink = {
50 .bLength = sizeof(descriptors.fs_descs.bulk_sink),
51 .bDescriptorType = USB_DT_ENDPOINT,
52 .bEndpointAddress = 1 | USB_DIR_IN,
53 .bmAttributes = USB_ENDPOINT_XFER_BULK,
54 },
55 .bulk_source = {
56 .bLength = sizeof(descriptors.fs_descs.bulk_source),
57 .bDescriptorType = USB_DT_ENDPOINT,
58 .bEndpointAddress = 2 | USB_DIR_OUT,
59 .bmAttributes = USB_ENDPOINT_XFER_BULK,
60 },
61 },
62 .hs_descs = {
63 .intf = {
64 .bLength = sizeof(descriptors.hs_descs.intf),
65 .bDescriptorType = USB_DT_INTERFACE,
66 .bNumEndpoints = 2,
67 .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
68 .iInterface = 1,
69 },
70 .bulk_sink = {
71 .bLength = sizeof(descriptors.hs_descs.bulk_sink),
72 .bDescriptorType = USB_DT_ENDPOINT,
73 .bEndpointAddress = 1 | USB_DIR_IN,
74 .bmAttributes = USB_ENDPOINT_XFER_BULK,
75 },
76 .bulk_source = {
77 .bLength = sizeof(descriptors.hs_descs.bulk_source),
78 .bDescriptorType = USB_DT_ENDPOINT,
79 .bEndpointAddress = 2 | USB_DIR_OUT,
80 .bmAttributes = USB_ENDPOINT_XFER_BULK,
81 },
82 },
83};
84
85#define STR_INTERFACE "AIO Test"
86
87static const struct {
88 struct usb_functionfs_strings_head header;
89 struct {
90 __le16 code;
91 const char str1[sizeof(STR_INTERFACE)];
92 } __attribute__ ((__packed__)) lang0;
93} __attribute__ ((__packed__)) strings = {
94 .header = {
95 .magic = htole32(FUNCTIONFS_STRINGS_MAGIC),
96 .length = htole32(sizeof(strings)),
97 .str_count = htole32(1),
98 .lang_count = htole32(1),
99 },
100 .lang0 = {
101 htole16(0x0409), /* en-us */
102 STR_INTERFACE,
103 },
104};
105
106/******************** Endpoints handling *******************************/
107
108static void display_event(struct usb_functionfs_event *event)
109{
110 static const char *const names[] = {
111 [FUNCTIONFS_BIND] = "BIND",
112 [FUNCTIONFS_UNBIND] = "UNBIND",
113 [FUNCTIONFS_ENABLE] = "ENABLE",
114 [FUNCTIONFS_DISABLE] = "DISABLE",
115 [FUNCTIONFS_SETUP] = "SETUP",
116 [FUNCTIONFS_SUSPEND] = "SUSPEND",
117 [FUNCTIONFS_RESUME] = "RESUME",
118 };
119 switch (event->type) {
120 case FUNCTIONFS_BIND:
121 case FUNCTIONFS_UNBIND:
122 case FUNCTIONFS_ENABLE:
123 case FUNCTIONFS_DISABLE:
124 case FUNCTIONFS_SETUP:
125 case FUNCTIONFS_SUSPEND:
126 case FUNCTIONFS_RESUME:
127 printf("Event %s\n", names[event->type]);
128 }
129}
130
131static void handle_ep0(int ep0, bool *ready)
132{
133 struct usb_functionfs_event event;
134 int ret;
135
136 struct pollfd pfds[1];
137 pfds[0].fd = ep0;
138 pfds[0].events = POLLIN;
139
140 ret = poll(pfds, 1, 0);
141
142 if (ret && (pfds[0].revents & POLLIN)) {
143 ret = read(ep0, &event, sizeof(event));
144 if (!ret) {
145 perror("unable to read event from ep0");
146 return;
147 }
148 display_event(&event);
149 switch (event.type) {
150 case FUNCTIONFS_SETUP:
151 if (event.u.setup.bRequestType & USB_DIR_IN)
152 write(ep0, NULL, 0);
153 else
154 read(ep0, NULL, 0);
155 break;
156
157 case FUNCTIONFS_ENABLE:
158 *ready = true;
159 break;
160
161 case FUNCTIONFS_DISABLE:
162 *ready = false;
163 break;
164
165 default:
166 break;
167 }
168 }
169}
170
171int main(int argc, char *argv[])
172{
173 int i, ret;
174 char *ep_path;
175
176 int ep0;
177 int ep[2];
178
179 io_context_t ctx;
180
181 int evfd;
182 fd_set rfds;
183
184 char *buf_in, *buf_out;
185 struct iocb *iocb_in, *iocb_out;
186 int req_in = 0, req_out = 0;
187 bool ready;
188
189 if (argc != 2) {
190 printf("ffs directory not specified!\n");
191 return 1;
192 }
193
194 ep_path = malloc(strlen(argv[1]) + 4 /* "/ep#" */ + 1 /* '\0' */);
195 if (!ep_path) {
196 perror("malloc");
197 return 1;
198 }
199
200 /* open endpoint files */
201 sprintf(ep_path, "%s/ep0", argv[1]);
202 ep0 = open(ep_path, O_RDWR);
203 if (ep0 < 0) {
204 perror("unable to open ep0");
205 return 1;
206 }
207 if (write(ep0, &descriptors, sizeof(descriptors)) < 0) {
208 perror("unable do write descriptors");
209 return 1;
210 }
211 if (write(ep0, &strings, sizeof(strings)) < 0) {
212 perror("unable to write strings");
213 return 1;
214 }
215 for (i = 0; i < 2; ++i) {
216 sprintf(ep_path, "%s/ep%d", argv[1], i+1);
217 ep[i] = open(ep_path, O_RDWR);
218 if (ep[i] < 0) {
219 printf("unable to open ep%d: %s\n", i+1,
220 strerror(errno));
221 return 1;
222 }
223 }
224
225 free(ep_path);
226
227 memset(&ctx, 0, sizeof(ctx));
228 /* setup aio context to handle up to 2 requests */
229 if (io_setup(2, &ctx) < 0) {
230 perror("unable to setup aio");
231 return 1;
232 }
233
234 evfd = eventfd(0, 0);
235 if (evfd < 0) {
236 perror("unable to open eventfd");
237 return 1;
238 }
239
240 /* alloc buffers and requests */
241 buf_in = malloc(BUF_LEN);
242 buf_out = malloc(BUF_LEN);
243 iocb_in = malloc(sizeof(*iocb_in));
244 iocb_out = malloc(sizeof(*iocb_out));
245
246 while (1) {
247 FD_ZERO(&rfds);
248 FD_SET(ep0, &rfds);
249 FD_SET(evfd, &rfds);
250
251 ret = select(((ep0 > evfd) ? ep0 : evfd)+1,
252 &rfds, NULL, NULL, NULL);
253 if (ret < 0) {
254 if (errno == EINTR)
255 continue;
256 perror("select");
257 break;
258 }
259
260 if (FD_ISSET(ep0, &rfds))
261 handle_ep0(ep0, &ready);
262
263 /* we are waiting for function ENABLE */
264 if (!ready)
265 continue;
266
267 /* if something was submitted we wait for event */
268 if (FD_ISSET(evfd, &rfds)) {
269 uint64_t ev_cnt;
270 ret = read(evfd, &ev_cnt, sizeof(ev_cnt));
271 if (ret < 0) {
272 perror("unable to read eventfd");
273 break;
274 }
275
276 struct io_event e[2];
277 /* we wait for one event */
278 ret = io_getevents(ctx, 1, 2, e, NULL);
279 /* if we got event */
280 for (i = 0; i < ret; ++i) {
281 if (e[i].obj->aio_fildes == ep[0]) {
282 printf("ev=in; ret=%lu\n", e[i].res);
283 req_in = 0;
284 } else if (e[i].obj->aio_fildes == ep[1]) {
285 printf("ev=out; ret=%lu\n", e[i].res);
286 req_out = 0;
287 }
288 }
289 }
290
291 if (!req_in) { /* if IN transfer not requested*/
292 /* prepare write request */
293 io_prep_pwrite(iocb_in, ep[0], buf_in, BUF_LEN, 0);
294 /* enable eventfd notification */
295 iocb_in->u.c.flags |= IOCB_FLAG_RESFD;
296 iocb_in->u.c.resfd = evfd;
297 /* submit table of requests */
298 ret = io_submit(ctx, 1, &iocb_in);
299 if (ret >= 0) { /* if ret > 0 request is queued */
300 req_in = 1;
301 printf("submit: in\n");
302 } else
303 perror("unable to submit request");
304 }
305 if (!req_out) { /* if OUT transfer not requested */
306 /* prepare read request */
307 io_prep_pread(iocb_out, ep[1], buf_out, BUF_LEN, 0);
308 /* enable eventfs notification */
309 iocb_out->u.c.flags |= IOCB_FLAG_RESFD;
310 iocb_out->u.c.resfd = evfd;
311 /* submit table of requests */
312 ret = io_submit(ctx, 1, &iocb_out);
313 if (ret >= 0) { /* if ret > 0 request is queued */
314 req_out = 1;
315 printf("submit: out\n");
316 } else
317 perror("unable to submit request");
318 }
319 }
320
321 /* free resources */
322
323 io_destroy(ctx);
324
325 free(buf_in);
326 free(buf_out);
327 free(iocb_in);
328 free(iocb_out);
329
330 for (i = 0; i < 2; ++i)
331 close(ep[i]);
332 close(ep0);
333
334 return 0;
335}
diff --git a/tools/usb/ffs-aio-example/simple/host_app/Makefile b/tools/usb/ffs-aio-example/simple/host_app/Makefile
new file mode 100644
index 000000000000..8c4a6f0aa82d
--- /dev/null
+++ b/tools/usb/ffs-aio-example/simple/host_app/Makefile
@@ -0,0 +1,13 @@
1CC = gcc
2LIBUSB_CFLAGS = $(shell pkg-config --cflags libusb-1.0)
3LIBUSB_LIBS = $(shell pkg-config --libs libusb-1.0)
4WARNINGS = -Wall -Wextra
5CFLAGS = $(LIBUSB_CFLAGS) $(WARNINGS)
6LDFLAGS = $(LIBUSB_LIBS)
7
8all: test
9%: %.c
10 $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
11
12clean:
13 $(RM) test
diff --git a/tools/usb/ffs-aio-example/simple/host_app/test.c b/tools/usb/ffs-aio-example/simple/host_app/test.c
new file mode 100644
index 000000000000..64b6a57d8ca3
--- /dev/null
+++ b/tools/usb/ffs-aio-example/simple/host_app/test.c
@@ -0,0 +1,148 @@
1#include <libusb.h>
2#include <stdio.h>
3#include <string.h>
4#include <unistd.h>
5
6#define VENDOR 0x1d6b
7#define PRODUCT 0x0105
8
9/* endpoints indexes */
10
11#define EP_BULK_IN (1 | LIBUSB_ENDPOINT_IN)
12#define EP_BULK_OUT (2 | LIBUSB_ENDPOINT_OUT)
13
14#define BUF_LEN 8192
15
16/*
17 * struct test_state - describes test program state
18 * @list: list of devices returned by libusb_get_device_list function
19 * @found: pointer to struct describing tested device
20 * @ctx: context, set to NULL
21 * @handle: handle of tested device
22 * @attached: indicates that device was attached to kernel, and has to be
23 * reattached at the end of test program
24 */
25
26struct test_state {
27 libusb_device *found;
28 libusb_context *ctx;
29 libusb_device_handle *handle;
30 int attached;
31};
32
33/*
34 * test_init - initialize test program
35 */
36
37int test_init(struct test_state *state)
38{
39 int i, ret;
40 ssize_t cnt;
41 libusb_device **list;
42
43 state->found = NULL;
44 state->ctx = NULL;
45 state->handle = NULL;
46 state->attached = 0;
47
48 ret = libusb_init(&state->ctx);
49 if (ret) {
50 printf("cannot init libusb: %s\n", libusb_error_name(ret));
51 return 1;
52 }
53
54 cnt = libusb_get_device_list(state->ctx, &list);
55 if (cnt <= 0) {
56 printf("no devices found\n");
57 goto error1;
58 }
59
60 for (i = 0; i < cnt; ++i) {
61 libusb_device *dev = list[i];
62 struct libusb_device_descriptor desc;
63 ret = libusb_get_device_descriptor(dev, &desc);
64 if (ret) {
65 printf("unable to get device descriptor: %s\n",
66 libusb_error_name(ret));
67 goto error2;
68 }
69 if (desc.idVendor == VENDOR && desc.idProduct == PRODUCT) {
70 state->found = dev;
71 break;
72 }
73 }
74
75 if (!state->found) {
76 printf("no devices found\n");
77 goto error2;
78 }
79
80 ret = libusb_open(state->found, &state->handle);
81 if (ret) {
82 printf("cannot open device: %s\n", libusb_error_name(ret));
83 goto error2;
84 }
85
86 if (libusb_claim_interface(state->handle, 0)) {
87 ret = libusb_detach_kernel_driver(state->handle, 0);
88 if (ret) {
89 printf("unable to detach kernel driver: %s\n",
90 libusb_error_name(ret));
91 goto error3;
92 }
93 state->attached = 1;
94 ret = libusb_claim_interface(state->handle, 0);
95 if (ret) {
96 printf("cannot claim interface: %s\n",
97 libusb_error_name(ret));
98 goto error4;
99 }
100 }
101
102 return 0;
103
104error4:
105 if (state->attached == 1)
106 libusb_attach_kernel_driver(state->handle, 0);
107
108error3:
109 libusb_close(state->handle);
110
111error2:
112 libusb_free_device_list(list, 1);
113
114error1:
115 libusb_exit(state->ctx);
116 return 1;
117}
118
119/*
120 * test_exit - cleanup test program
121 */
122
123void test_exit(struct test_state *state)
124{
125 libusb_release_interface(state->handle, 0);
126 if (state->attached == 1)
127 libusb_attach_kernel_driver(state->handle, 0);
128 libusb_close(state->handle);
129 libusb_exit(state->ctx);
130}
131
132int main(void)
133{
134 struct test_state state;
135
136 if (test_init(&state))
137 return 1;
138
139 while (1) {
140 static unsigned char buffer[BUF_LEN];
141 int bytes;
142 libusb_bulk_transfer(state.handle, EP_BULK_IN, buffer, BUF_LEN,
143 &bytes, 500);
144 libusb_bulk_transfer(state.handle, EP_BULK_OUT, buffer, BUF_LEN,
145 &bytes, 500);
146 }
147 test_exit(&state);
148}
diff --git a/tools/usb/ffs-test.c b/tools/usb/ffs-test.c
index fe1e66b6ef40..a87e99f37c52 100644
--- a/tools/usb/ffs-test.c
+++ b/tools/usb/ffs-test.c
@@ -116,8 +116,8 @@ static const struct {
116 .header = { 116 .header = {
117 .magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC), 117 .magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC),
118 .length = cpu_to_le32(sizeof descriptors), 118 .length = cpu_to_le32(sizeof descriptors),
119 .fs_count = 3, 119 .fs_count = cpu_to_le32(3),
120 .hs_count = 3, 120 .hs_count = cpu_to_le32(3),
121 }, 121 },
122 .fs_descs = { 122 .fs_descs = {
123 .intf = { 123 .intf = {
diff --git a/tools/virtio/Makefile b/tools/virtio/Makefile
index 3187c62d9814..9325f4693821 100644
--- a/tools/virtio/Makefile
+++ b/tools/virtio/Makefile
@@ -3,7 +3,7 @@ test: virtio_test vringh_test
3virtio_test: virtio_ring.o virtio_test.o 3virtio_test: virtio_ring.o virtio_test.o
4vringh_test: vringh_test.o vringh.o virtio_ring.o 4vringh_test: vringh_test.o vringh.o virtio_ring.o
5 5
6CFLAGS += -g -O2 -Wall -I. -I ../../usr/include/ -Wno-pointer-sign -fno-strict-overflow -fno-strict-aliasing -fno-common -MMD -U_FORTIFY_SOURCE 6CFLAGS += -g -O2 -Wall -I. -I../include/ -I ../../usr/include/ -Wno-pointer-sign -fno-strict-overflow -fno-strict-aliasing -fno-common -MMD -U_FORTIFY_SOURCE
7vpath %.c ../../drivers/virtio ../../drivers/vhost 7vpath %.c ../../drivers/virtio ../../drivers/vhost
8mod: 8mod:
9 ${MAKE} -C `pwd`/../.. M=`pwd`/vhost_test 9 ${MAKE} -C `pwd`/../.. M=`pwd`/vhost_test
diff --git a/tools/virtio/linux/kernel.h b/tools/virtio/linux/kernel.h
index fba705963968..1e8ce6979c1e 100644
--- a/tools/virtio/linux/kernel.h
+++ b/tools/virtio/linux/kernel.h
@@ -38,13 +38,6 @@ struct page {
38 38
39#define __printf(a,b) __attribute__((format(printf,a,b))) 39#define __printf(a,b) __attribute__((format(printf,a,b)))
40 40
41typedef enum {
42 GFP_KERNEL,
43 GFP_ATOMIC,
44 __GFP_HIGHMEM,
45 __GFP_HIGH
46} gfp_t;
47
48#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) 41#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
49 42
50extern void *__kmalloc_fake, *__kfree_ignore_start, *__kfree_ignore_end; 43extern void *__kmalloc_fake, *__kfree_ignore_start, *__kfree_ignore_end;
diff --git a/tools/virtio/linux/types.h b/tools/virtio/linux/types.h
deleted file mode 100644
index f8ebb9a2b3d6..000000000000
--- a/tools/virtio/linux/types.h
+++ /dev/null
@@ -1,28 +0,0 @@
1#ifndef TYPES_H
2#define TYPES_H
3#include <stdint.h>
4
5#define __force
6#define __user
7#define __must_check
8#define __cold
9
10typedef uint64_t u64;
11typedef int64_t s64;
12typedef uint32_t u32;
13typedef int32_t s32;
14typedef uint16_t u16;
15typedef int16_t s16;
16typedef uint8_t u8;
17typedef int8_t s8;
18
19typedef uint64_t __u64;
20typedef int64_t __s64;
21typedef uint32_t __u32;
22typedef int32_t __s32;
23typedef uint16_t __u16;
24typedef int16_t __s16;
25typedef uint8_t __u8;
26typedef int8_t __s8;
27
28#endif /* TYPES_H */
diff --git a/tools/vm/page-types.c b/tools/vm/page-types.c
index 05654f5e48d5..c4d6d2e20e0d 100644
--- a/tools/vm/page-types.c
+++ b/tools/vm/page-types.c
@@ -32,6 +32,8 @@
32#include <assert.h> 32#include <assert.h>
33#include <ftw.h> 33#include <ftw.h>
34#include <time.h> 34#include <time.h>
35#include <setjmp.h>
36#include <signal.h>
35#include <sys/types.h> 37#include <sys/types.h>
36#include <sys/errno.h> 38#include <sys/errno.h>
37#include <sys/fcntl.h> 39#include <sys/fcntl.h>
@@ -824,21 +826,38 @@ static void show_file(const char *name, const struct stat *st)
824 atime, now - st->st_atime); 826 atime, now - st->st_atime);
825} 827}
826 828
829static sigjmp_buf sigbus_jmp;
830
831static void * volatile sigbus_addr;
832
833static void sigbus_handler(int sig, siginfo_t *info, void *ucontex)
834{
835 (void)sig;
836 (void)ucontex;
837 sigbus_addr = info ? info->si_addr : NULL;
838 siglongjmp(sigbus_jmp, 1);
839}
840
841static struct sigaction sigbus_action = {
842 .sa_sigaction = sigbus_handler,
843 .sa_flags = SA_SIGINFO,
844};
845
827static void walk_file(const char *name, const struct stat *st) 846static void walk_file(const char *name, const struct stat *st)
828{ 847{
829 uint8_t vec[PAGEMAP_BATCH]; 848 uint8_t vec[PAGEMAP_BATCH];
830 uint64_t buf[PAGEMAP_BATCH], flags; 849 uint64_t buf[PAGEMAP_BATCH], flags;
831 unsigned long nr_pages, pfn, i; 850 unsigned long nr_pages, pfn, i;
851 off_t off, end = st->st_size;
832 int fd; 852 int fd;
833 off_t off;
834 ssize_t len; 853 ssize_t len;
835 void *ptr; 854 void *ptr;
836 int first = 1; 855 int first = 1;
837 856
838 fd = checked_open(name, O_RDONLY|O_NOATIME|O_NOFOLLOW); 857 fd = checked_open(name, O_RDONLY|O_NOATIME|O_NOFOLLOW);
839 858
840 for (off = 0; off < st->st_size; off += len) { 859 for (off = 0; off < end; off += len) {
841 nr_pages = (st->st_size - off + page_size - 1) / page_size; 860 nr_pages = (end - off + page_size - 1) / page_size;
842 if (nr_pages > PAGEMAP_BATCH) 861 if (nr_pages > PAGEMAP_BATCH)
843 nr_pages = PAGEMAP_BATCH; 862 nr_pages = PAGEMAP_BATCH;
844 len = nr_pages * page_size; 863 len = nr_pages * page_size;
@@ -855,11 +874,19 @@ static void walk_file(const char *name, const struct stat *st)
855 if (madvise(ptr, len, MADV_RANDOM)) 874 if (madvise(ptr, len, MADV_RANDOM))
856 fatal("madvice failed: %s", name); 875 fatal("madvice failed: %s", name);
857 876
877 if (sigsetjmp(sigbus_jmp, 1)) {
878 end = off + sigbus_addr ? sigbus_addr - ptr : 0;
879 fprintf(stderr, "got sigbus at offset %lld: %s\n",
880 (long long)end, name);
881 goto got_sigbus;
882 }
883
858 /* populate ptes */ 884 /* populate ptes */
859 for (i = 0; i < nr_pages ; i++) { 885 for (i = 0; i < nr_pages ; i++) {
860 if (vec[i] & 1) 886 if (vec[i] & 1)
861 (void)*(volatile int *)(ptr + i * page_size); 887 (void)*(volatile int *)(ptr + i * page_size);
862 } 888 }
889got_sigbus:
863 890
864 /* turn off harvesting reference bits */ 891 /* turn off harvesting reference bits */
865 if (madvise(ptr, len, MADV_SEQUENTIAL)) 892 if (madvise(ptr, len, MADV_SEQUENTIAL))
@@ -910,6 +937,7 @@ static void walk_page_cache(void)
910 937
911 kpageflags_fd = checked_open(PROC_KPAGEFLAGS, O_RDONLY); 938 kpageflags_fd = checked_open(PROC_KPAGEFLAGS, O_RDONLY);
912 pagemap_fd = checked_open("/proc/self/pagemap", O_RDONLY); 939 pagemap_fd = checked_open("/proc/self/pagemap", O_RDONLY);
940 sigaction(SIGBUS, &sigbus_action, NULL);
913 941
914 if (stat(opt_file, &st)) 942 if (stat(opt_file, &st))
915 fatal("stat failed: %s\n", opt_file); 943 fatal("stat failed: %s\n", opt_file);
@@ -925,6 +953,7 @@ static void walk_page_cache(void)
925 953
926 close(kpageflags_fd); 954 close(kpageflags_fd);
927 close(pagemap_fd); 955 close(pagemap_fd);
956 signal(SIGBUS, SIG_DFL);
928} 957}
929 958
930static void parse_file(const char *name) 959static void parse_file(const char *name)