aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/hv/hv_fcopy_daemon.c3
-rw-r--r--tools/lib/traceevent/event-parse.c6
-rw-r--r--tools/lib/traceevent/plugin_cfg80211.c3
-rw-r--r--tools/lib/traceevent/plugin_jbd2.c6
-rw-r--r--tools/lib/traceevent/plugin_kvm.c64
-rw-r--r--tools/perf/Documentation/perf-bench.txt4
-rw-r--r--tools/perf/Documentation/perf-inject.txt3
-rw-r--r--tools/perf/Documentation/perf-kvm.txt16
-rw-r--r--tools/perf/Documentation/perf-timechart.txt38
-rw-r--r--tools/perf/Documentation/perf-trace.txt46
-rw-r--r--tools/perf/Documentation/perf.txt10
-rw-r--r--tools/perf/MANIFEST3
-rw-r--r--tools/perf/Makefile.perf4
-rw-r--r--tools/perf/arch/powerpc/Makefile1
-rw-r--r--tools/perf/arch/powerpc/util/header.c4
-rw-r--r--tools/perf/arch/powerpc/util/skip-callchain-idx.c266
-rw-r--r--tools/perf/arch/s390/Makefile3
-rw-r--r--tools/perf/arch/s390/util/header.c28
-rw-r--r--tools/perf/arch/s390/util/kvm-stat.c105
-rw-r--r--tools/perf/arch/x86/Makefile2
-rw-r--r--tools/perf/arch/x86/tests/dwarf-unwind.c1
-rw-r--r--tools/perf/arch/x86/util/kvm-stat.c156
-rw-r--r--tools/perf/arch/x86/util/tsc.c31
-rw-r--r--tools/perf/arch/x86/util/tsc.h3
-rw-r--r--tools/perf/arch/x86/util/unwind-libunwind.c1
-rw-r--r--tools/perf/bench/bench.h1
-rw-r--r--tools/perf/bench/futex-requeue.c10
-rw-r--r--tools/perf/bench/futex-wake.c12
-rw-r--r--tools/perf/bench/mem-memcpy.c9
-rw-r--r--tools/perf/bench/mem-memset.c9
-rw-r--r--tools/perf/bench/sched-messaging.c47
-rw-r--r--tools/perf/builtin-bench.c7
-rw-r--r--tools/perf/builtin-buildid-cache.c8
-rw-r--r--tools/perf/builtin-evlist.c1
-rw-r--r--tools/perf/builtin-help.c1
-rw-r--r--tools/perf/builtin-inject.c5
-rw-r--r--tools/perf/builtin-kvm.c414
-rw-r--r--tools/perf/builtin-record.c7
-rw-r--r--tools/perf/builtin-sched.c16
-rw-r--r--tools/perf/builtin-script.c60
-rw-r--r--tools/perf/builtin-stat.c2
-rw-r--r--tools/perf/builtin-timechart.c694
-rw-r--r--tools/perf/builtin-trace.c266
-rw-r--r--tools/perf/config/Makefile14
-rw-r--r--tools/perf/config/feature-checks/Makefile4
-rw-r--r--tools/perf/config/feature-checks/test-all.c5
-rw-r--r--tools/perf/config/feature-checks/test-sync-compare-and-swap.c14
-rw-r--r--tools/perf/perf-sys.h1
-rw-r--r--tools/perf/perf.c13
-rw-r--r--tools/perf/scripts/perl/bin/failed-syscalls-record3
-rw-r--r--tools/perf/scripts/perl/failed-syscalls.pl5
-rw-r--r--tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py3
-rw-r--r--tools/perf/scripts/python/bin/failed-syscalls-by-pid-record3
-rw-r--r--tools/perf/scripts/python/bin/sctop-record3
-rw-r--r--tools/perf/scripts/python/bin/syscall-counts-by-pid-record3
-rw-r--r--tools/perf/scripts/python/bin/syscall-counts-record3
-rw-r--r--tools/perf/scripts/python/check-perf-trace.py4
-rw-r--r--tools/perf/scripts/python/failed-syscalls-by-pid.py7
-rw-r--r--tools/perf/scripts/python/futex-contention.py4
-rwxr-xr-xtools/perf/scripts/python/net_dropmonitor.py2
-rw-r--r--tools/perf/scripts/python/netdev-times.py26
-rw-r--r--tools/perf/scripts/python/sched-migration.py41
-rw-r--r--tools/perf/scripts/python/sctop.py7
-rw-r--r--tools/perf/scripts/python/syscall-counts-by-pid.py7
-rw-r--r--tools/perf/scripts/python/syscall-counts.py7
-rw-r--r--tools/perf/tests/attr/base-record3
-rw-r--r--tools/perf/tests/attr/base-stat3
-rw-r--r--tools/perf/tests/bp_signal.c4
-rw-r--r--tools/perf/tests/bp_signal_overflow.c4
-rw-r--r--tools/perf/tests/dso-data.c1
-rw-r--r--tools/perf/tests/evsel-roundtrip-name.c1
-rw-r--r--tools/perf/tests/evsel-tp-sched.c1
-rw-r--r--tools/perf/tests/open-syscall-tp-fields.c1
-rw-r--r--tools/perf/tests/parse-events.c1
-rw-r--r--tools/perf/tests/parse-no-sample-id-all.c1
-rw-r--r--tools/perf/tests/perf-time-to-tsc.c12
-rw-r--r--tools/perf/tests/rdpmc.c4
-rw-r--r--tools/perf/tests/sample-parsing.c1
-rw-r--r--tools/perf/tests/thread-mg-share.c1
-rw-r--r--tools/perf/ui/browser.c39
-rw-r--r--tools/perf/ui/browser.h3
-rw-r--r--tools/perf/ui/browsers/hists.c153
-rw-r--r--tools/perf/ui/stdio/hist.c2
-rw-r--r--tools/perf/util/callchain.c2
-rw-r--r--tools/perf/util/callchain.h13
-rw-r--r--tools/perf/util/cloexec.c57
-rw-r--r--tools/perf/util/cloexec.h6
-rw-r--r--tools/perf/util/config.c13
-rw-r--r--tools/perf/util/data.c3
-rw-r--r--tools/perf/util/debug.c56
-rw-r--r--tools/perf/util/debug.h22
-rw-r--r--tools/perf/util/dso.c71
-rw-r--r--tools/perf/util/dso.h26
-rw-r--r--tools/perf/util/event.c52
-rw-r--r--tools/perf/util/event.h10
-rw-r--r--tools/perf/util/evlist.c51
-rw-r--r--tools/perf/util/evsel.c26
-rw-r--r--tools/perf/util/evsel.h2
-rw-r--r--tools/perf/util/header.c51
-rw-r--r--tools/perf/util/header.h2
-rw-r--r--tools/perf/util/include/linux/kernel.h21
-rw-r--r--tools/perf/util/kvm-stat.h140
-rw-r--r--tools/perf/util/machine.c139
-rw-r--r--tools/perf/util/machine.h8
-rw-r--r--tools/perf/util/map.c47
-rw-r--r--tools/perf/util/map.h15
-rw-r--r--tools/perf/util/parse-options.h5
-rw-r--r--tools/perf/util/probe-finder.c1
-rw-r--r--tools/perf/util/pstack.c1
-rw-r--r--tools/perf/util/python.c4
-rw-r--r--tools/perf/util/record.c27
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c1
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c197
-rw-r--r--tools/perf/util/session.c39
-rw-r--r--tools/perf/util/session.h3
-rw-r--r--tools/perf/util/sort.c2
-rw-r--r--tools/perf/util/svghelper.c168
-rw-r--r--tools/perf/util/svghelper.h6
-rw-r--r--tools/perf/util/symbol-elf.c41
-rw-r--r--tools/perf/util/symbol-minimal.c43
-rw-r--r--tools/perf/util/symbol.c21
-rw-r--r--tools/perf/util/symbol.h9
-rw-r--r--tools/perf/util/thread.c13
-rw-r--r--tools/perf/util/thread.h1
-rw-r--r--tools/perf/util/trace-event-info.c13
-rw-r--r--tools/perf/util/trace-event-read.c2
-rw-r--r--tools/perf/util/tsc.c30
-rw-r--r--tools/perf/util/tsc.h12
-rw-r--r--tools/perf/util/unwind-libdw.c1
-rw-r--r--tools/perf/util/unwind-libunwind.c1
-rw-r--r--tools/perf/util/util.c10
-rw-r--r--tools/perf/util/vdso.c97
-rw-r--r--tools/perf/util/vdso.h13
-rw-r--r--tools/power/acpi/Makefile5
-rw-r--r--tools/power/acpi/common/cmfsize.c20
-rw-r--r--tools/power/acpi/common/getopt.c14
-rw-r--r--tools/power/acpi/os_specific/service_layers/oslibcfs.c214
-rw-r--r--tools/power/acpi/os_specific/service_layers/oslinuxtbl.c48
-rw-r--r--tools/power/acpi/os_specific/service_layers/osunixxf.c1311
-rw-r--r--tools/power/acpi/tools/acpidump/acpidump.h3
-rw-r--r--tools/power/acpi/tools/acpidump/apdump.c108
-rw-r--r--tools/power/acpi/tools/acpidump/apfiles.c92
-rw-r--r--tools/power/acpi/tools/acpidump/apmain.c96
-rw-r--r--tools/power/cpupower/bench/parse.c39
-rw-r--r--tools/power/cpupower/utils/cpufreq-set.c11
-rw-r--r--tools/power/cpupower/utils/helpers/sysfs.c2
-rw-r--r--tools/power/cpupower/utils/idle_monitor/mperf_monitor.c2
-rwxr-xr-xtools/testing/ktest/ktest.pl581
-rw-r--r--tools/testing/ktest/sample.conf65
-rw-r--r--tools/testing/selftests/Makefile21
-rw-r--r--tools/testing/selftests/README.txt27
-rw-r--r--tools/testing/selftests/cpu-hotplug/Makefile3
-rw-r--r--tools/testing/selftests/cpu-hotplug/on-off-test.sh52
-rw-r--r--tools/testing/selftests/firmware/Makefile27
-rw-r--r--tools/testing/selftests/firmware/fw_filesystem.sh62
-rw-r--r--tools/testing/selftests/firmware/fw_userhelper.sh89
-rw-r--r--tools/testing/selftests/kcmp/kcmp_test.c2
-rw-r--r--tools/testing/selftests/memfd/.gitignore4
-rw-r--r--tools/testing/selftests/memfd/Makefile41
-rw-r--r--tools/testing/selftests/memfd/fuse_mnt.c110
-rw-r--r--tools/testing/selftests/memfd/fuse_test.c311
-rw-r--r--tools/testing/selftests/memfd/memfd_test.c913
-rw-r--r--tools/testing/selftests/memfd/run_fuse_test.sh14
-rw-r--r--tools/testing/selftests/memory-hotplug/Makefile3
-rw-r--r--tools/testing/selftests/memory-hotplug/on-off-test.sh8
-rw-r--r--tools/testing/selftests/mount/Makefile17
-rw-r--r--tools/testing/selftests/mount/unprivileged-remount-test.c242
-rw-r--r--tools/testing/selftests/mqueue/Makefile4
-rw-r--r--tools/testing/selftests/mqueue/mq_open_tests.c20
-rw-r--r--tools/testing/selftests/mqueue/mq_perf_tests.c40
-rw-r--r--tools/testing/selftests/powerpc/Makefile10
-rw-r--r--tools/testing/selftests/powerpc/pmu/Makefile19
-rw-r--r--tools/testing/selftests/powerpc/pmu/count_instructions.c30
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/Makefile5
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/busy_loop.S271
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/cycles_with_mmcr2_test.c91
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/ebb.c261
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/ebb.h1
-rw-r--r--tools/testing/selftests/powerpc/pmu/l3_bank_test.c48
-rw-r--r--tools/testing/selftests/powerpc/pmu/lib.c50
-rw-r--r--tools/testing/selftests/powerpc/pmu/lib.h1
-rw-r--r--tools/testing/selftests/powerpc/pmu/per_event_excludes.c114
-rw-r--r--tools/testing/selftests/ptrace/peeksiginfo.c4
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-recheck.sh8
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh9
-rw-r--r--tools/testing/selftests/rcutorture/bin/kvm.sh21
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE011
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE021
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE02-T1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE031
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE041
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE051
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE061
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE071
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE081
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE08-T1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE091
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/P5-U-T-NH-sd-SMP-hp1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/P5-U-T-NH-sd-SMP-hp1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/P5-U-T-NH-sd-SMP-hp1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/P5-U-T-NH-sd-SMP-hp1
-rw-r--r--tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt1
-rwxr-xr-xtools/time/udelay_test.sh66
-rw-r--r--tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c39
-rw-r--r--tools/usb/ffs-aio-example/multibuff/host_app/test.c27
-rw-r--r--tools/usb/ffs-aio-example/simple/device_app/aio_simple.c39
-rw-r--r--tools/usb/ffs-aio-example/simple/host_app/test.c27
207 files changed, 8396 insertions, 1766 deletions
diff --git a/tools/hv/hv_fcopy_daemon.c b/tools/hv/hv_fcopy_daemon.c
index fba1c75aa484..8f96b3ee0724 100644
--- a/tools/hv/hv_fcopy_daemon.c
+++ b/tools/hv/hv_fcopy_daemon.c
@@ -88,7 +88,8 @@ static int hv_start_fcopy(struct hv_start_fcopy *smsg)
88 } 88 }
89 } 89 }
90 90
91 target_fd = open(target_fname, O_RDWR | O_CREAT | O_CLOEXEC, 0744); 91 target_fd = open(target_fname,
92 O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0744);
92 if (target_fd == -1) { 93 if (target_fd == -1) {
93 syslog(LOG_INFO, "Open Failed: %s", strerror(errno)); 94 syslog(LOG_INFO, "Open Failed: %s", strerror(errno));
94 goto done; 95 goto done;
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c
index 93825a17dcce..cf3a44bf1ec3 100644
--- a/tools/lib/traceevent/event-parse.c
+++ b/tools/lib/traceevent/event-parse.c
@@ -2395,7 +2395,7 @@ process_flags(struct event_format *event, struct print_arg *arg, char **tok)
2395{ 2395{
2396 struct print_arg *field; 2396 struct print_arg *field;
2397 enum event_type type; 2397 enum event_type type;
2398 char *token; 2398 char *token = NULL;
2399 2399
2400 memset(arg, 0, sizeof(*arg)); 2400 memset(arg, 0, sizeof(*arg));
2401 arg->type = PRINT_FLAGS; 2401 arg->type = PRINT_FLAGS;
@@ -2448,7 +2448,7 @@ process_symbols(struct event_format *event, struct print_arg *arg, char **tok)
2448{ 2448{
2449 struct print_arg *field; 2449 struct print_arg *field;
2450 enum event_type type; 2450 enum event_type type;
2451 char *token; 2451 char *token = NULL;
2452 2452
2453 memset(arg, 0, sizeof(*arg)); 2453 memset(arg, 0, sizeof(*arg));
2454 arg->type = PRINT_SYMBOL; 2454 arg->type = PRINT_SYMBOL;
@@ -2487,7 +2487,7 @@ process_hex(struct event_format *event, struct print_arg *arg, char **tok)
2487{ 2487{
2488 struct print_arg *field; 2488 struct print_arg *field;
2489 enum event_type type; 2489 enum event_type type;
2490 char *token; 2490 char *token = NULL;
2491 2491
2492 memset(arg, 0, sizeof(*arg)); 2492 memset(arg, 0, sizeof(*arg));
2493 arg->type = PRINT_HEX; 2493 arg->type = PRINT_HEX;
diff --git a/tools/lib/traceevent/plugin_cfg80211.c b/tools/lib/traceevent/plugin_cfg80211.c
index c066b25905f8..4592d8438318 100644
--- a/tools/lib/traceevent/plugin_cfg80211.c
+++ b/tools/lib/traceevent/plugin_cfg80211.c
@@ -5,8 +5,7 @@
5#include "event-parse.h" 5#include "event-parse.h"
6 6
7static unsigned long long 7static unsigned long long
8process___le16_to_cpup(struct trace_seq *s, 8process___le16_to_cpup(struct trace_seq *s, unsigned long long *args)
9 unsigned long long *args)
10{ 9{
11 uint16_t *val = (uint16_t *) (unsigned long) args[0]; 10 uint16_t *val = (uint16_t *) (unsigned long) args[0];
12 return val ? (long long) le16toh(*val) : 0; 11 return val ? (long long) le16toh(*val) : 0;
diff --git a/tools/lib/traceevent/plugin_jbd2.c b/tools/lib/traceevent/plugin_jbd2.c
index 0db714c721be..5c23d5bd27ce 100644
--- a/tools/lib/traceevent/plugin_jbd2.c
+++ b/tools/lib/traceevent/plugin_jbd2.c
@@ -30,8 +30,7 @@
30#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK)) 30#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK))
31 31
32static unsigned long long 32static unsigned long long
33process_jbd2_dev_to_name(struct trace_seq *s, 33process_jbd2_dev_to_name(struct trace_seq *s, unsigned long long *args)
34 unsigned long long *args)
35{ 34{
36 unsigned int dev = args[0]; 35 unsigned int dev = args[0];
37 36
@@ -40,8 +39,7 @@ process_jbd2_dev_to_name(struct trace_seq *s,
40} 39}
41 40
42static unsigned long long 41static unsigned long long
43process_jiffies_to_msecs(struct trace_seq *s, 42process_jiffies_to_msecs(struct trace_seq *s, unsigned long long *args)
44 unsigned long long *args)
45{ 43{
46 unsigned long long jiffies = args[0]; 44 unsigned long long jiffies = args[0];
47 45
diff --git a/tools/lib/traceevent/plugin_kvm.c b/tools/lib/traceevent/plugin_kvm.c
index 9e0e8c61b43b..88fe83dff7cd 100644
--- a/tools/lib/traceevent/plugin_kvm.c
+++ b/tools/lib/traceevent/plugin_kvm.c
@@ -240,25 +240,38 @@ static const char *find_exit_reason(unsigned isa, int val)
240 for (i = 0; strings[i].val >= 0; i++) 240 for (i = 0; strings[i].val >= 0; i++)
241 if (strings[i].val == val) 241 if (strings[i].val == val)
242 break; 242 break;
243 if (strings[i].str) 243
244 return strings[i].str; 244 return strings[i].str;
245 return "UNKNOWN";
246} 245}
247 246
248static int kvm_exit_handler(struct trace_seq *s, struct pevent_record *record, 247static int print_exit_reason(struct trace_seq *s, struct pevent_record *record,
249 struct event_format *event, void *context) 248 struct event_format *event, const char *field)
250{ 249{
251 unsigned long long isa; 250 unsigned long long isa;
252 unsigned long long val; 251 unsigned long long val;
253 unsigned long long info1 = 0, info2 = 0; 252 const char *reason;
254 253
255 if (pevent_get_field_val(s, event, "exit_reason", record, &val, 1) < 0) 254 if (pevent_get_field_val(s, event, field, record, &val, 1) < 0)
256 return -1; 255 return -1;
257 256
258 if (pevent_get_field_val(s, event, "isa", record, &isa, 0) < 0) 257 if (pevent_get_field_val(s, event, "isa", record, &isa, 0) < 0)
259 isa = 1; 258 isa = 1;
260 259
261 trace_seq_printf(s, "reason %s", find_exit_reason(isa, val)); 260 reason = find_exit_reason(isa, val);
261 if (reason)
262 trace_seq_printf(s, "reason %s", reason);
263 else
264 trace_seq_printf(s, "reason UNKNOWN (%llu)", val);
265 return 0;
266}
267
268static int kvm_exit_handler(struct trace_seq *s, struct pevent_record *record,
269 struct event_format *event, void *context)
270{
271 unsigned long long info1 = 0, info2 = 0;
272
273 if (print_exit_reason(s, record, event, "exit_reason") < 0)
274 return -1;
262 275
263 pevent_print_num_field(s, " rip 0x%lx", event, "guest_rip", record, 1); 276 pevent_print_num_field(s, " rip 0x%lx", event, "guest_rip", record, 1);
264 277
@@ -313,6 +326,29 @@ static int kvm_emulate_insn_handler(struct trace_seq *s,
313 return 0; 326 return 0;
314} 327}
315 328
329
330static int kvm_nested_vmexit_inject_handler(struct trace_seq *s, struct pevent_record *record,
331 struct event_format *event, void *context)
332{
333 if (print_exit_reason(s, record, event, "exit_code") < 0)
334 return -1;
335
336 pevent_print_num_field(s, " info1 %llx", event, "exit_info1", record, 1);
337 pevent_print_num_field(s, " info2 %llx", event, "exit_info2", record, 1);
338 pevent_print_num_field(s, " int_info %llx", event, "exit_int_info", record, 1);
339 pevent_print_num_field(s, " int_info_err %llx", event, "exit_int_info_err", record, 1);
340
341 return 0;
342}
343
344static int kvm_nested_vmexit_handler(struct trace_seq *s, struct pevent_record *record,
345 struct event_format *event, void *context)
346{
347 pevent_print_num_field(s, "rip %llx ", event, "rip", record, 1);
348
349 return kvm_nested_vmexit_inject_handler(s, record, event, context);
350}
351
316union kvm_mmu_page_role { 352union kvm_mmu_page_role {
317 unsigned word; 353 unsigned word;
318 struct { 354 struct {
@@ -409,6 +445,12 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
409 pevent_register_event_handler(pevent, -1, "kvm", "kvm_emulate_insn", 445 pevent_register_event_handler(pevent, -1, "kvm", "kvm_emulate_insn",
410 kvm_emulate_insn_handler, NULL); 446 kvm_emulate_insn_handler, NULL);
411 447
448 pevent_register_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit",
449 kvm_nested_vmexit_handler, NULL);
450
451 pevent_register_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit_inject",
452 kvm_nested_vmexit_inject_handler, NULL);
453
412 pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_get_page", 454 pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_get_page",
413 kvm_mmu_get_page_handler, NULL); 455 kvm_mmu_get_page_handler, NULL);
414 456
@@ -443,6 +485,12 @@ void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
443 pevent_unregister_event_handler(pevent, -1, "kvm", "kvm_emulate_insn", 485 pevent_unregister_event_handler(pevent, -1, "kvm", "kvm_emulate_insn",
444 kvm_emulate_insn_handler, NULL); 486 kvm_emulate_insn_handler, NULL);
445 487
488 pevent_unregister_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit",
489 kvm_nested_vmexit_handler, NULL);
490
491 pevent_unregister_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit_inject",
492 kvm_nested_vmexit_inject_handler, NULL);
493
446 pevent_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_get_page", 494 pevent_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_get_page",
447 kvm_mmu_get_page_handler, NULL); 495 kvm_mmu_get_page_handler, NULL);
448 496
diff --git a/tools/perf/Documentation/perf-bench.txt b/tools/perf/Documentation/perf-bench.txt
index 4464ad770d51..f6480cbf309b 100644
--- a/tools/perf/Documentation/perf-bench.txt
+++ b/tools/perf/Documentation/perf-bench.txt
@@ -16,6 +16,10 @@ This 'perf bench' command is a general framework for benchmark suites.
16 16
17COMMON OPTIONS 17COMMON OPTIONS
18-------------- 18--------------
19-r::
20--repeat=::
21Specify amount of times to repeat the run (default 10).
22
19-f:: 23-f::
20--format=:: 24--format=::
21Specify format style. 25Specify format style.
diff --git a/tools/perf/Documentation/perf-inject.txt b/tools/perf/Documentation/perf-inject.txt
index a00a34276c54..dc7442cf3d7f 100644
--- a/tools/perf/Documentation/perf-inject.txt
+++ b/tools/perf/Documentation/perf-inject.txt
@@ -41,6 +41,9 @@ OPTIONS
41 tasks slept. sched_switch contains a callchain where a task slept and 41 tasks slept. sched_switch contains a callchain where a task slept and
42 sched_stat contains a timeslice how long a task slept. 42 sched_stat contains a timeslice how long a task slept.
43 43
44--kallsyms=<file>::
45 kallsyms pathname
46
44SEE ALSO 47SEE ALSO
45-------- 48--------
46linkperf:perf-record[1], linkperf:perf-report[1], linkperf:perf-archive[1] 49linkperf:perf-record[1], linkperf:perf-report[1], linkperf:perf-archive[1]
diff --git a/tools/perf/Documentation/perf-kvm.txt b/tools/perf/Documentation/perf-kvm.txt
index 52276a6d2b75..6e689dc89a2f 100644
--- a/tools/perf/Documentation/perf-kvm.txt
+++ b/tools/perf/Documentation/perf-kvm.txt
@@ -51,9 +51,9 @@ There are a couple of variants of perf kvm:
51 'perf kvm stat <command>' to run a command and gather performance counter 51 'perf kvm stat <command>' to run a command and gather performance counter
52 statistics. 52 statistics.
53 Especially, perf 'kvm stat record/report' generates a statistical analysis 53 Especially, perf 'kvm stat record/report' generates a statistical analysis
54 of KVM events. Currently, vmexit, mmio and ioport events are supported. 54 of KVM events. Currently, vmexit, mmio (x86 only) and ioport (x86 only)
55 'perf kvm stat record <command>' records kvm events and the events between 55 events are supported. 'perf kvm stat record <command>' records kvm events
56 start and end <command>. 56 and the events between start and end <command>.
57 And this command produces a file which contains tracing results of kvm 57 And this command produces a file which contains tracing results of kvm
58 events. 58 events.
59 59
@@ -103,8 +103,8 @@ STAT REPORT OPTIONS
103 analyze events which occures on this vcpu. (default: all vcpus) 103 analyze events which occures on this vcpu. (default: all vcpus)
104 104
105--event=<value>:: 105--event=<value>::
106 event to be analyzed. Possible values: vmexit, mmio, ioport. 106 event to be analyzed. Possible values: vmexit, mmio (x86 only),
107 (default: vmexit) 107 ioport (x86 only). (default: vmexit)
108-k:: 108-k::
109--key=<value>:: 109--key=<value>::
110 Sorting key. Possible values: sample (default, sort by samples 110 Sorting key. Possible values: sample (default, sort by samples
@@ -138,7 +138,8 @@ STAT LIVE OPTIONS
138 138
139 139
140--event=<value>:: 140--event=<value>::
141 event to be analyzed. Possible values: vmexit, mmio, ioport. 141 event to be analyzed. Possible values: vmexit,
142 mmio (x86 only), ioport (x86 only).
142 (default: vmexit) 143 (default: vmexit)
143 144
144-k:: 145-k::
@@ -147,7 +148,8 @@ STAT LIVE OPTIONS
147 number), time (sort by average time). 148 number), time (sort by average time).
148 149
149--duration=<value>:: 150--duration=<value>::
150 Show events other than HLT that take longer than duration usecs. 151 Show events other than HLT (x86 only) or Wait state (s390 only)
152 that take longer than duration usecs.
151 153
152SEE ALSO 154SEE ALSO
153-------- 155--------
diff --git a/tools/perf/Documentation/perf-timechart.txt b/tools/perf/Documentation/perf-timechart.txt
index 5e0f986dff38..df98d1c82688 100644
--- a/tools/perf/Documentation/perf-timechart.txt
+++ b/tools/perf/Documentation/perf-timechart.txt
@@ -15,10 +15,20 @@ DESCRIPTION
15There are two variants of perf timechart: 15There are two variants of perf timechart:
16 16
17 'perf timechart record <command>' to record the system level events 17 'perf timechart record <command>' to record the system level events
18 of an arbitrary workload. 18 of an arbitrary workload. By default timechart records only scheduler
19 and CPU events (task switches, running times, CPU power states, etc),
20 but it's possible to record IO (disk, network) activity using -I argument.
19 21
20 'perf timechart' to turn a trace into a Scalable Vector Graphics file, 22 'perf timechart' to turn a trace into a Scalable Vector Graphics file,
21 that can be viewed with popular SVG viewers such as 'Inkscape'. 23 that can be viewed with popular SVG viewers such as 'Inkscape'. Depending
24 on the events in the perf.data file, timechart will contain scheduler/cpu
25 events or IO events.
26
27 In IO mode, every bar has two charts: upper and lower.
28 Upper bar shows incoming events (disk reads, ingress network packets).
29 Lower bar shows outgoing events (disk writes, egress network packets).
30 There are also poll bars which show how much time application spent
31 in poll/epoll/select syscalls.
22 32
23TIMECHART OPTIONS 33TIMECHART OPTIONS
24----------------- 34-----------------
@@ -54,6 +64,19 @@ TIMECHART OPTIONS
54 duration or tasks with given name. If number is given it's interpreted 64 duration or tasks with given name. If number is given it's interpreted
55 as number of nanoseconds. If non-numeric string is given it's 65 as number of nanoseconds. If non-numeric string is given it's
56 interpreted as task name. 66 interpreted as task name.
67--io-skip-eagain::
68 Don't draw EAGAIN IO events.
69--io-min-time=<nsecs>::
70 Draw small events as if they lasted min-time. Useful when you need
71 to see very small and fast IO. It's possible to specify ms or us
72 suffix to specify time in milliseconds or microseconds.
73 Default value is 1ms.
74--io-merge-dist=<nsecs>::
75 Merge events that are merge-dist nanoseconds apart.
76 Reduces number of figures on the SVG and makes it more render-friendly.
77 It's possible to specify ms or us suffix to specify time in
78 milliseconds or microseconds.
79 Default value is 1us.
57 80
58RECORD OPTIONS 81RECORD OPTIONS
59-------------- 82--------------
@@ -63,6 +86,9 @@ RECORD OPTIONS
63-T:: 86-T::
64--tasks-only:: 87--tasks-only::
65 Record only tasks-related events 88 Record only tasks-related events
89-I::
90--io-only::
91 Record only io-related events
66-g:: 92-g::
67--callchain:: 93--callchain::
68 Do call-graph (stack chain/backtrace) recording 94 Do call-graph (stack chain/backtrace) recording
@@ -87,6 +113,14 @@ Record system-wide timechart:
87 113
88 $ perf timechart --highlight gcc 114 $ perf timechart --highlight gcc
89 115
116Record system-wide IO events:
117
118 $ perf timechart record -I
119
120 then generate timechart:
121
122 $ perf timechart
123
90SEE ALSO 124SEE ALSO
91-------- 125--------
92linkperf:perf-record[1] 126linkperf:perf-record[1]
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt
index fae38d9a44a4..02aac831bdd9 100644
--- a/tools/perf/Documentation/perf-trace.txt
+++ b/tools/perf/Documentation/perf-trace.txt
@@ -107,6 +107,52 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs.
107 Show tool stats such as number of times fd->pathname was discovered thru 107 Show tool stats such as number of times fd->pathname was discovered thru
108 hooking the open syscall return + vfs_getname or via reading /proc/pid/fd, etc. 108 hooking the open syscall return + vfs_getname or via reading /proc/pid/fd, etc.
109 109
110-F=[all|min|maj]::
111--pf=[all|min|maj]::
112 Trace pagefaults. Optionally, you can specify whether you want minor,
113 major or all pagefaults. Default value is maj.
114
115--syscalls::
116 Trace system calls. This options is enabled by default.
117
118PAGEFAULTS
119----------
120
121When tracing pagefaults, the format of the trace is as follows:
122
123<min|maj>fault [<ip.symbol>+<ip.offset>] => <addr.dso@addr.offset> (<map type><addr level>).
124
125- min/maj indicates whether fault event is minor or major;
126- ip.symbol shows symbol for instruction pointer (the code that generated the
127 fault); if no debug symbols available, perf trace will print raw IP;
128- addr.dso shows DSO for the faulted address;
129- map type is either 'd' for non-executable maps or 'x' for executable maps;
130- addr level is either 'k' for kernel dso or '.' for user dso.
131
132For symbols resolution you may need to install debugging symbols.
133
134Please be aware that duration is currently always 0 and doesn't reflect actual
135time it took for fault to be handled!
136
137When --verbose specified, perf trace tries to print all available information
138for both IP and fault address in the form of dso@symbol+offset.
139
140EXAMPLES
141--------
142
143Trace only major pagefaults:
144
145 $ perf trace --no-syscalls -F
146
147Trace syscalls, major and minor pagefaults:
148
149 $ perf trace -F all
150
151 1416.547 ( 0.000 ms): python/20235 majfault [CRYPTO_push_info_+0x0] => /lib/x86_64-linux-gnu/libcrypto.so.1.0.0@0x61be0 (x.)
152
153 As you can see, there was major pagefault in python process, from
154 CRYPTO_push_info_ routine which faulted somewhere in libcrypto.so.
155
110SEE ALSO 156SEE ALSO
111-------- 157--------
112linkperf:perf-record[1], linkperf:perf-script[1] 158linkperf:perf-record[1], linkperf:perf-script[1]
diff --git a/tools/perf/Documentation/perf.txt b/tools/perf/Documentation/perf.txt
index 0eeb247dc7d2..d240bb2e5b22 100644
--- a/tools/perf/Documentation/perf.txt
+++ b/tools/perf/Documentation/perf.txt
@@ -8,7 +8,15 @@ perf - Performance analysis tools for Linux
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf' [--version] [--help] COMMAND [ARGS] 11'perf' [--version] [--help] [OPTIONS] COMMAND [ARGS]
12
13OPTIONS
14-------
15--debug::
16 Setup debug variable (just verbose for now) in value
17 range (0, 10). Use like:
18 --debug verbose # sets verbose = 1
19 --debug verbose=2 # sets verbose = 2
12 20
13DESCRIPTION 21DESCRIPTION
14----------- 22-----------
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST
index 45da209b6ed3..344c4d3d0a4a 100644
--- a/tools/perf/MANIFEST
+++ b/tools/perf/MANIFEST
@@ -37,3 +37,6 @@ arch/x86/include/asm/kvm_host.h
37arch/x86/include/uapi/asm/svm.h 37arch/x86/include/uapi/asm/svm.h
38arch/x86/include/uapi/asm/vmx.h 38arch/x86/include/uapi/asm/vmx.h
39arch/x86/include/uapi/asm/kvm.h 39arch/x86/include/uapi/asm/kvm.h
40arch/x86/include/uapi/asm/kvm_perf.h
41arch/s390/include/uapi/asm/sie.h
42arch/s390/include/uapi/asm/kvm_perf.h
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 9670a16fa577..2240974b7745 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -295,11 +295,13 @@ LIB_H += util/intlist.h
295LIB_H += util/perf_regs.h 295LIB_H += util/perf_regs.h
296LIB_H += util/unwind.h 296LIB_H += util/unwind.h
297LIB_H += util/vdso.h 297LIB_H += util/vdso.h
298LIB_H += util/tsc.h
298LIB_H += ui/helpline.h 299LIB_H += ui/helpline.h
299LIB_H += ui/progress.h 300LIB_H += ui/progress.h
300LIB_H += ui/util.h 301LIB_H += ui/util.h
301LIB_H += ui/ui.h 302LIB_H += ui/ui.h
302LIB_H += util/data.h 303LIB_H += util/data.h
304LIB_H += util/kvm-stat.h
303 305
304LIB_OBJS += $(OUTPUT)util/abspath.o 306LIB_OBJS += $(OUTPUT)util/abspath.o
305LIB_OBJS += $(OUTPUT)util/alias.o 307LIB_OBJS += $(OUTPUT)util/alias.o
@@ -373,6 +375,8 @@ LIB_OBJS += $(OUTPUT)util/stat.o
373LIB_OBJS += $(OUTPUT)util/record.o 375LIB_OBJS += $(OUTPUT)util/record.o
374LIB_OBJS += $(OUTPUT)util/srcline.o 376LIB_OBJS += $(OUTPUT)util/srcline.o
375LIB_OBJS += $(OUTPUT)util/data.o 377LIB_OBJS += $(OUTPUT)util/data.o
378LIB_OBJS += $(OUTPUT)util/tsc.o
379LIB_OBJS += $(OUTPUT)util/cloexec.o
376 380
377LIB_OBJS += $(OUTPUT)ui/setup.o 381LIB_OBJS += $(OUTPUT)ui/setup.o
378LIB_OBJS += $(OUTPUT)ui/helpline.o 382LIB_OBJS += $(OUTPUT)ui/helpline.o
diff --git a/tools/perf/arch/powerpc/Makefile b/tools/perf/arch/powerpc/Makefile
index 744e629797be..b92219b1900d 100644
--- a/tools/perf/arch/powerpc/Makefile
+++ b/tools/perf/arch/powerpc/Makefile
@@ -3,3 +3,4 @@ PERF_HAVE_DWARF_REGS := 1
3LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o 3LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
4endif 4endif
5LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o 5LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
6LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/skip-callchain-idx.o
diff --git a/tools/perf/arch/powerpc/util/header.c b/tools/perf/arch/powerpc/util/header.c
index 2f7073d107fd..6c1b8a75db09 100644
--- a/tools/perf/arch/powerpc/util/header.c
+++ b/tools/perf/arch/powerpc/util/header.c
@@ -5,9 +5,7 @@
5#include <string.h> 5#include <string.h>
6 6
7#include "../../util/header.h" 7#include "../../util/header.h"
8 8#include "../../util/util.h"
9#define __stringify_1(x) #x
10#define __stringify(x) __stringify_1(x)
11 9
12#define mfspr(rn) ({unsigned long rval; \ 10#define mfspr(rn) ({unsigned long rval; \
13 asm volatile("mfspr %0," __stringify(rn) \ 11 asm volatile("mfspr %0," __stringify(rn) \
diff --git a/tools/perf/arch/powerpc/util/skip-callchain-idx.c b/tools/perf/arch/powerpc/util/skip-callchain-idx.c
new file mode 100644
index 000000000000..a7c23a4b3778
--- /dev/null
+++ b/tools/perf/arch/powerpc/util/skip-callchain-idx.c
@@ -0,0 +1,266 @@
1/*
2 * Use DWARF Debug information to skip unnecessary callchain entries.
3 *
4 * Copyright (C) 2014 Sukadev Bhattiprolu, IBM Corporation.
5 * Copyright (C) 2014 Ulrich Weigand, IBM Corporation.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 */
12#include <inttypes.h>
13#include <dwarf.h>
14#include <elfutils/libdwfl.h>
15
16#include "util/thread.h"
17#include "util/callchain.h"
18
19/*
20 * When saving the callchain on Power, the kernel conservatively saves
21 * excess entries in the callchain. A few of these entries are needed
22 * in some cases but not others. If the unnecessary entries are not
23 * ignored, we end up with duplicate arcs in the call-graphs. Use
24 * DWARF debug information to skip over any unnecessary callchain
25 * entries.
26 *
27 * See function header for arch_adjust_callchain() below for more details.
28 *
29 * The libdwfl code in this file is based on code from elfutils
30 * (libdwfl/argp-std.c, libdwfl/tests/addrcfi.c, etc).
31 */
32static char *debuginfo_path;
33
34static const Dwfl_Callbacks offline_callbacks = {
35 .debuginfo_path = &debuginfo_path,
36 .find_debuginfo = dwfl_standard_find_debuginfo,
37 .section_address = dwfl_offline_section_address,
38};
39
40
41/*
42 * Use the DWARF expression for the Call-frame-address and determine
43 * if return address is in LR and if a new frame was allocated.
44 */
45static int check_return_reg(int ra_regno, Dwarf_Frame *frame)
46{
47 Dwarf_Op ops_mem[2];
48 Dwarf_Op dummy;
49 Dwarf_Op *ops = &dummy;
50 size_t nops;
51 int result;
52
53 result = dwarf_frame_register(frame, ra_regno, ops_mem, &ops, &nops);
54 if (result < 0) {
55 pr_debug("dwarf_frame_register() %s\n", dwarf_errmsg(-1));
56 return -1;
57 }
58
59 /*
60 * Check if return address is on the stack.
61 */
62 if (nops != 0 || ops != NULL)
63 return 0;
64
65 /*
66 * Return address is in LR. Check if a frame was allocated
67 * but not-yet used.
68 */
69 result = dwarf_frame_cfa(frame, &ops, &nops);
70 if (result < 0) {
71 pr_debug("dwarf_frame_cfa() returns %d, %s\n", result,
72 dwarf_errmsg(-1));
73 return -1;
74 }
75
76 /*
77 * If call frame address is in r1, no new frame was allocated.
78 */
79 if (nops == 1 && ops[0].atom == DW_OP_bregx && ops[0].number == 1 &&
80 ops[0].number2 == 0)
81 return 1;
82
83 /*
84 * A new frame was allocated but has not yet been used.
85 */
86 return 2;
87}
88
89/*
90 * Get the DWARF frame from the .eh_frame section.
91 */
92static Dwarf_Frame *get_eh_frame(Dwfl_Module *mod, Dwarf_Addr pc)
93{
94 int result;
95 Dwarf_Addr bias;
96 Dwarf_CFI *cfi;
97 Dwarf_Frame *frame;
98
99 cfi = dwfl_module_eh_cfi(mod, &bias);
100 if (!cfi) {
101 pr_debug("%s(): no CFI - %s\n", __func__, dwfl_errmsg(-1));
102 return NULL;
103 }
104
105 result = dwarf_cfi_addrframe(cfi, pc, &frame);
106 if (result) {
107 pr_debug("%s(): %s\n", __func__, dwfl_errmsg(-1));
108 return NULL;
109 }
110
111 return frame;
112}
113
114/*
115 * Get the DWARF frame from the .debug_frame section.
116 */
117static Dwarf_Frame *get_dwarf_frame(Dwfl_Module *mod, Dwarf_Addr pc)
118{
119 Dwarf_CFI *cfi;
120 Dwarf_Addr bias;
121 Dwarf_Frame *frame;
122 int result;
123
124 cfi = dwfl_module_dwarf_cfi(mod, &bias);
125 if (!cfi) {
126 pr_debug("%s(): no CFI - %s\n", __func__, dwfl_errmsg(-1));
127 return NULL;
128 }
129
130 result = dwarf_cfi_addrframe(cfi, pc, &frame);
131 if (result) {
132 pr_debug("%s(): %s\n", __func__, dwfl_errmsg(-1));
133 return NULL;
134 }
135
136 return frame;
137}
138
139/*
140 * Return:
141 * 0 if return address for the program counter @pc is on stack
142 * 1 if return address is in LR and no new stack frame was allocated
143 * 2 if return address is in LR and a new frame was allocated (but not
144 * yet used)
145 * -1 in case of errors
146 */
147static int check_return_addr(const char *exec_file, Dwarf_Addr pc)
148{
149 int rc = -1;
150 Dwfl *dwfl;
151 Dwfl_Module *mod;
152 Dwarf_Frame *frame;
153 int ra_regno;
154 Dwarf_Addr start = pc;
155 Dwarf_Addr end = pc;
156 bool signalp;
157
158 dwfl = dwfl_begin(&offline_callbacks);
159 if (!dwfl) {
160 pr_debug("dwfl_begin() failed: %s\n", dwarf_errmsg(-1));
161 return -1;
162 }
163
164 if (dwfl_report_offline(dwfl, "", exec_file, -1) == NULL) {
165 pr_debug("dwfl_report_offline() failed %s\n", dwarf_errmsg(-1));
166 goto out;
167 }
168
169 mod = dwfl_addrmodule(dwfl, pc);
170 if (!mod) {
171 pr_debug("dwfl_addrmodule() failed, %s\n", dwarf_errmsg(-1));
172 goto out;
173 }
174
175 /*
176 * To work with split debug info files (eg: glibc), check both
177 * .eh_frame and .debug_frame sections of the ELF header.
178 */
179 frame = get_eh_frame(mod, pc);
180 if (!frame) {
181 frame = get_dwarf_frame(mod, pc);
182 if (!frame)
183 goto out;
184 }
185
186 ra_regno = dwarf_frame_info(frame, &start, &end, &signalp);
187 if (ra_regno < 0) {
188 pr_debug("Return address register unavailable: %s\n",
189 dwarf_errmsg(-1));
190 goto out;
191 }
192
193 rc = check_return_reg(ra_regno, frame);
194
195out:
196 dwfl_end(dwfl);
197 return rc;
198}
199
200/*
201 * The callchain saved by the kernel always includes the link register (LR).
202 *
203 * 0: PERF_CONTEXT_USER
204 * 1: Program counter (Next instruction pointer)
205 * 2: LR value
206 * 3: Caller's caller
207 * 4: ...
208 *
209 * The value in LR is only needed when it holds a return address. If the
210 * return address is on the stack, we should ignore the LR value.
211 *
212 * Further, when the return address is in the LR, if a new frame was just
213 * allocated but the LR was not saved into it, then the LR contains the
214 * caller, slot 4: contains the caller's caller and the contents of slot 3:
215 * (chain->ips[3]) is undefined and must be ignored.
216 *
217 * Use DWARF debug information to determine if any entries need to be skipped.
218 *
219 * Return:
220 * index: of callchain entry that needs to be ignored (if any)
221 * -1 if no entry needs to be ignored or in case of errors
222 */
223int arch_skip_callchain_idx(struct machine *machine, struct thread *thread,
224 struct ip_callchain *chain)
225{
226 struct addr_location al;
227 struct dso *dso = NULL;
228 int rc;
229 u64 ip;
230 u64 skip_slot = -1;
231
232 if (chain->nr < 3)
233 return skip_slot;
234
235 ip = chain->ips[2];
236
237 thread__find_addr_location(thread, machine, PERF_RECORD_MISC_USER,
238 MAP__FUNCTION, ip, &al);
239
240 if (al.map)
241 dso = al.map->dso;
242
243 if (!dso) {
244 pr_debug("%" PRIx64 " dso is NULL\n", ip);
245 return skip_slot;
246 }
247
248 rc = check_return_addr(dso->long_name, ip);
249
250 pr_debug("DSO %s, nr %" PRIx64 ", ip 0x%" PRIx64 "rc %d\n",
251 dso->long_name, chain->nr, ip, rc);
252
253 if (rc == 0) {
254 /*
255 * Return address on stack. Ignore LR value in callchain
256 */
257 skip_slot = 2;
258 } else if (rc == 2) {
259 /*
260 * New frame allocated but return address still in LR.
261 * Ignore the caller's caller entry in callchain.
262 */
263 skip_slot = 3;
264 }
265 return skip_slot;
266}
diff --git a/tools/perf/arch/s390/Makefile b/tools/perf/arch/s390/Makefile
index 15130b50dfe3..798ac7379c5f 100644
--- a/tools/perf/arch/s390/Makefile
+++ b/tools/perf/arch/s390/Makefile
@@ -2,3 +2,6 @@ ifndef NO_DWARF
2PERF_HAVE_DWARF_REGS := 1 2PERF_HAVE_DWARF_REGS := 1
3LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o 3LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
4endif 4endif
5LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
6HAVE_KVM_STAT_SUPPORT := 1
7LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/kvm-stat.o
diff --git a/tools/perf/arch/s390/util/header.c b/tools/perf/arch/s390/util/header.c
new file mode 100644
index 000000000000..9fa6c3e5782c
--- /dev/null
+++ b/tools/perf/arch/s390/util/header.c
@@ -0,0 +1,28 @@
1/*
2 * Implementation of get_cpuid().
3 *
4 * Copyright 2014 IBM Corp.
5 * Author(s): Alexander Yarygin <yarygin@linux.vnet.ibm.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License (version 2 only)
9 * as published by the Free Software Foundation.
10 */
11
12#include <sys/types.h>
13#include <unistd.h>
14#include <stdio.h>
15#include <string.h>
16
17#include "../../util/header.h"
18
19int get_cpuid(char *buffer, size_t sz)
20{
21 const char *cpuid = "IBM/S390";
22
23 if (strlen(cpuid) + 1 > sz)
24 return -1;
25
26 strcpy(buffer, cpuid);
27 return 0;
28}
diff --git a/tools/perf/arch/s390/util/kvm-stat.c b/tools/perf/arch/s390/util/kvm-stat.c
new file mode 100644
index 000000000000..a5dbc07ec9dc
--- /dev/null
+++ b/tools/perf/arch/s390/util/kvm-stat.c
@@ -0,0 +1,105 @@
1/*
2 * Arch specific functions for perf kvm stat.
3 *
4 * Copyright 2014 IBM Corp.
5 * Author(s): Alexander Yarygin <yarygin@linux.vnet.ibm.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License (version 2 only)
9 * as published by the Free Software Foundation.
10 */
11
12#include "../../util/kvm-stat.h"
13#include <asm/kvm_perf.h>
14
15define_exit_reasons_table(sie_exit_reasons, sie_intercept_code);
16define_exit_reasons_table(sie_icpt_insn_codes, icpt_insn_codes);
17define_exit_reasons_table(sie_sigp_order_codes, sigp_order_codes);
18define_exit_reasons_table(sie_diagnose_codes, diagnose_codes);
19define_exit_reasons_table(sie_icpt_prog_codes, icpt_prog_codes);
20
21static void event_icpt_insn_get_key(struct perf_evsel *evsel,
22 struct perf_sample *sample,
23 struct event_key *key)
24{
25 unsigned long insn;
26
27 insn = perf_evsel__intval(evsel, sample, "instruction");
28 key->key = icpt_insn_decoder(insn);
29 key->exit_reasons = sie_icpt_insn_codes;
30}
31
32static void event_sigp_get_key(struct perf_evsel *evsel,
33 struct perf_sample *sample,
34 struct event_key *key)
35{
36 key->key = perf_evsel__intval(evsel, sample, "order_code");
37 key->exit_reasons = sie_sigp_order_codes;
38}
39
40static void event_diag_get_key(struct perf_evsel *evsel,
41 struct perf_sample *sample,
42 struct event_key *key)
43{
44 key->key = perf_evsel__intval(evsel, sample, "code");
45 key->exit_reasons = sie_diagnose_codes;
46}
47
48static void event_icpt_prog_get_key(struct perf_evsel *evsel,
49 struct perf_sample *sample,
50 struct event_key *key)
51{
52 key->key = perf_evsel__intval(evsel, sample, "code");
53 key->exit_reasons = sie_icpt_prog_codes;
54}
55
56static struct child_event_ops child_events[] = {
57 { .name = "kvm:kvm_s390_intercept_instruction",
58 .get_key = event_icpt_insn_get_key },
59 { .name = "kvm:kvm_s390_handle_sigp",
60 .get_key = event_sigp_get_key },
61 { .name = "kvm:kvm_s390_handle_diag",
62 .get_key = event_diag_get_key },
63 { .name = "kvm:kvm_s390_intercept_prog",
64 .get_key = event_icpt_prog_get_key },
65 { NULL, NULL },
66};
67
68static struct kvm_events_ops exit_events = {
69 .is_begin_event = exit_event_begin,
70 .is_end_event = exit_event_end,
71 .child_ops = child_events,
72 .decode_key = exit_event_decode_key,
73 .name = "VM-EXIT"
74};
75
76const char * const kvm_events_tp[] = {
77 "kvm:kvm_s390_sie_enter",
78 "kvm:kvm_s390_sie_exit",
79 "kvm:kvm_s390_intercept_instruction",
80 "kvm:kvm_s390_handle_sigp",
81 "kvm:kvm_s390_handle_diag",
82 "kvm:kvm_s390_intercept_prog",
83 NULL,
84};
85
86struct kvm_reg_events_ops kvm_reg_events_ops[] = {
87 { .name = "vmexit", .ops = &exit_events },
88 { NULL, NULL },
89};
90
91const char * const kvm_skip_events[] = {
92 "Wait state",
93 NULL,
94};
95
96int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid)
97{
98 if (strstr(cpuid, "IBM/S390")) {
99 kvm->exit_reasons = sie_exit_reasons;
100 kvm->exit_reasons_isa = "SIE";
101 } else
102 return -ENOTSUP;
103
104 return 0;
105}
diff --git a/tools/perf/arch/x86/Makefile b/tools/perf/arch/x86/Makefile
index 1641542e3636..9b21881db52f 100644
--- a/tools/perf/arch/x86/Makefile
+++ b/tools/perf/arch/x86/Makefile
@@ -15,3 +15,5 @@ endif
15LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o 15LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
16LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/tsc.o 16LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/tsc.o
17LIB_H += arch/$(ARCH)/util/tsc.h 17LIB_H += arch/$(ARCH)/util/tsc.h
18HAVE_KVM_STAT_SUPPORT := 1
19LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/kvm-stat.o
diff --git a/tools/perf/arch/x86/tests/dwarf-unwind.c b/tools/perf/arch/x86/tests/dwarf-unwind.c
index 9f89f899ccc7..d8bbf7ad1681 100644
--- a/tools/perf/arch/x86/tests/dwarf-unwind.c
+++ b/tools/perf/arch/x86/tests/dwarf-unwind.c
@@ -3,6 +3,7 @@
3#include "thread.h" 3#include "thread.h"
4#include "map.h" 4#include "map.h"
5#include "event.h" 5#include "event.h"
6#include "debug.h"
6#include "tests/tests.h" 7#include "tests/tests.h"
7 8
8#define STACK_SIZE 8192 9#define STACK_SIZE 8192
diff --git a/tools/perf/arch/x86/util/kvm-stat.c b/tools/perf/arch/x86/util/kvm-stat.c
new file mode 100644
index 000000000000..14e4e668fad7
--- /dev/null
+++ b/tools/perf/arch/x86/util/kvm-stat.c
@@ -0,0 +1,156 @@
1#include "../../util/kvm-stat.h"
2#include <asm/kvm_perf.h>
3
4define_exit_reasons_table(vmx_exit_reasons, VMX_EXIT_REASONS);
5define_exit_reasons_table(svm_exit_reasons, SVM_EXIT_REASONS);
6
7static struct kvm_events_ops exit_events = {
8 .is_begin_event = exit_event_begin,
9 .is_end_event = exit_event_end,
10 .decode_key = exit_event_decode_key,
11 .name = "VM-EXIT"
12};
13
14/*
15 * For the mmio events, we treat:
16 * the time of MMIO write: kvm_mmio(KVM_TRACE_MMIO_WRITE...) -> kvm_entry
17 * the time of MMIO read: kvm_exit -> kvm_mmio(KVM_TRACE_MMIO_READ...).
18 */
19static void mmio_event_get_key(struct perf_evsel *evsel, struct perf_sample *sample,
20 struct event_key *key)
21{
22 key->key = perf_evsel__intval(evsel, sample, "gpa");
23 key->info = perf_evsel__intval(evsel, sample, "type");
24}
25
26#define KVM_TRACE_MMIO_READ_UNSATISFIED 0
27#define KVM_TRACE_MMIO_READ 1
28#define KVM_TRACE_MMIO_WRITE 2
29
30static bool mmio_event_begin(struct perf_evsel *evsel,
31 struct perf_sample *sample, struct event_key *key)
32{
33 /* MMIO read begin event in kernel. */
34 if (kvm_exit_event(evsel))
35 return true;
36
37 /* MMIO write begin event in kernel. */
38 if (!strcmp(evsel->name, "kvm:kvm_mmio") &&
39 perf_evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_WRITE) {
40 mmio_event_get_key(evsel, sample, key);
41 return true;
42 }
43
44 return false;
45}
46
47static bool mmio_event_end(struct perf_evsel *evsel, struct perf_sample *sample,
48 struct event_key *key)
49{
50 /* MMIO write end event in kernel. */
51 if (kvm_entry_event(evsel))
52 return true;
53
54 /* MMIO read end event in kernel.*/
55 if (!strcmp(evsel->name, "kvm:kvm_mmio") &&
56 perf_evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_READ) {
57 mmio_event_get_key(evsel, sample, key);
58 return true;
59 }
60
61 return false;
62}
63
64static void mmio_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
65 struct event_key *key,
66 char *decode)
67{
68 scnprintf(decode, DECODE_STR_LEN, "%#lx:%s",
69 (unsigned long)key->key,
70 key->info == KVM_TRACE_MMIO_WRITE ? "W" : "R");
71}
72
73static struct kvm_events_ops mmio_events = {
74 .is_begin_event = mmio_event_begin,
75 .is_end_event = mmio_event_end,
76 .decode_key = mmio_event_decode_key,
77 .name = "MMIO Access"
78};
79
80 /* The time of emulation pio access is from kvm_pio to kvm_entry. */
81static void ioport_event_get_key(struct perf_evsel *evsel,
82 struct perf_sample *sample,
83 struct event_key *key)
84{
85 key->key = perf_evsel__intval(evsel, sample, "port");
86 key->info = perf_evsel__intval(evsel, sample, "rw");
87}
88
89static bool ioport_event_begin(struct perf_evsel *evsel,
90 struct perf_sample *sample,
91 struct event_key *key)
92{
93 if (!strcmp(evsel->name, "kvm:kvm_pio")) {
94 ioport_event_get_key(evsel, sample, key);
95 return true;
96 }
97
98 return false;
99}
100
101static bool ioport_event_end(struct perf_evsel *evsel,
102 struct perf_sample *sample __maybe_unused,
103 struct event_key *key __maybe_unused)
104{
105 return kvm_entry_event(evsel);
106}
107
108static void ioport_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
109 struct event_key *key,
110 char *decode)
111{
112 scnprintf(decode, DECODE_STR_LEN, "%#llx:%s",
113 (unsigned long long)key->key,
114 key->info ? "POUT" : "PIN");
115}
116
117static struct kvm_events_ops ioport_events = {
118 .is_begin_event = ioport_event_begin,
119 .is_end_event = ioport_event_end,
120 .decode_key = ioport_event_decode_key,
121 .name = "IO Port Access"
122};
123
124const char * const kvm_events_tp[] = {
125 "kvm:kvm_entry",
126 "kvm:kvm_exit",
127 "kvm:kvm_mmio",
128 "kvm:kvm_pio",
129 NULL,
130};
131
132struct kvm_reg_events_ops kvm_reg_events_ops[] = {
133 { .name = "vmexit", .ops = &exit_events },
134 { .name = "mmio", .ops = &mmio_events },
135 { .name = "ioport", .ops = &ioport_events },
136 { NULL, NULL },
137};
138
139const char * const kvm_skip_events[] = {
140 "HLT",
141 NULL,
142};
143
144int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid)
145{
146 if (strstr(cpuid, "Intel")) {
147 kvm->exit_reasons = vmx_exit_reasons;
148 kvm->exit_reasons_isa = "VMX";
149 } else if (strstr(cpuid, "AMD")) {
150 kvm->exit_reasons = svm_exit_reasons;
151 kvm->exit_reasons_isa = "SVM";
152 } else
153 return -ENOTSUP;
154
155 return 0;
156}
diff --git a/tools/perf/arch/x86/util/tsc.c b/tools/perf/arch/x86/util/tsc.c
index 40021fa3129b..fd2868490d00 100644
--- a/tools/perf/arch/x86/util/tsc.c
+++ b/tools/perf/arch/x86/util/tsc.c
@@ -6,29 +6,9 @@
6#include "../../perf.h" 6#include "../../perf.h"
7#include <linux/types.h> 7#include <linux/types.h>
8#include "../../util/debug.h" 8#include "../../util/debug.h"
9#include "../../util/tsc.h"
9#include "tsc.h" 10#include "tsc.h"
10 11
11u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc)
12{
13 u64 t, quot, rem;
14
15 t = ns - tc->time_zero;
16 quot = t / tc->time_mult;
17 rem = t % tc->time_mult;
18 return (quot << tc->time_shift) +
19 (rem << tc->time_shift) / tc->time_mult;
20}
21
22u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc)
23{
24 u64 quot, rem;
25
26 quot = cyc >> tc->time_shift;
27 rem = cyc & ((1 << tc->time_shift) - 1);
28 return tc->time_zero + quot * tc->time_mult +
29 ((rem * tc->time_mult) >> tc->time_shift);
30}
31
32int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc, 12int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
33 struct perf_tsc_conversion *tc) 13 struct perf_tsc_conversion *tc)
34{ 14{
@@ -57,3 +37,12 @@ int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
57 37
58 return 0; 38 return 0;
59} 39}
40
41u64 rdtsc(void)
42{
43 unsigned int low, high;
44
45 asm volatile("rdtsc" : "=a" (low), "=d" (high));
46
47 return low | ((u64)high) << 32;
48}
diff --git a/tools/perf/arch/x86/util/tsc.h b/tools/perf/arch/x86/util/tsc.h
index 2affe0366b59..2edc4d31065c 100644
--- a/tools/perf/arch/x86/util/tsc.h
+++ b/tools/perf/arch/x86/util/tsc.h
@@ -14,7 +14,4 @@ struct perf_event_mmap_page;
14int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc, 14int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
15 struct perf_tsc_conversion *tc); 15 struct perf_tsc_conversion *tc);
16 16
17u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc);
18u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc);
19
20#endif /* TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ */ 17#endif /* TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ */
diff --git a/tools/perf/arch/x86/util/unwind-libunwind.c b/tools/perf/arch/x86/util/unwind-libunwind.c
index 3261f68c6a7c..db25e93d989c 100644
--- a/tools/perf/arch/x86/util/unwind-libunwind.c
+++ b/tools/perf/arch/x86/util/unwind-libunwind.c
@@ -3,6 +3,7 @@
3#include <libunwind.h> 3#include <libunwind.h>
4#include "perf_regs.h" 4#include "perf_regs.h"
5#include "../../util/unwind.h" 5#include "../../util/unwind.h"
6#include "../../util/debug.h"
6 7
7#ifdef HAVE_ARCH_X86_64_SUPPORT 8#ifdef HAVE_ARCH_X86_64_SUPPORT
8int libunwind__arch_reg_id(int regnum) 9int libunwind__arch_reg_id(int regnum)
diff --git a/tools/perf/bench/bench.h b/tools/perf/bench/bench.h
index eba46709b279..3c4dd44d45cb 100644
--- a/tools/perf/bench/bench.h
+++ b/tools/perf/bench/bench.h
@@ -43,5 +43,6 @@ extern int bench_futex_requeue(int argc, const char **argv, const char *prefix);
43#define BENCH_FORMAT_UNKNOWN -1 43#define BENCH_FORMAT_UNKNOWN -1
44 44
45extern int bench_format; 45extern int bench_format;
46extern unsigned int bench_repeat;
46 47
47#endif 48#endif
diff --git a/tools/perf/bench/futex-requeue.c b/tools/perf/bench/futex-requeue.c
index a16255876f1d..732403bfd31a 100644
--- a/tools/perf/bench/futex-requeue.c
+++ b/tools/perf/bench/futex-requeue.c
@@ -29,13 +29,6 @@ static u_int32_t futex1 = 0, futex2 = 0;
29 */ 29 */
30static unsigned int nrequeue = 1; 30static unsigned int nrequeue = 1;
31 31
32/*
33 * There can be significant variance from run to run,
34 * the more repeats, the more exact the overall avg and
35 * the better idea of the futex latency.
36 */
37static unsigned int repeat = 10;
38
39static pthread_t *worker; 32static pthread_t *worker;
40static bool done = 0, silent = 0; 33static bool done = 0, silent = 0;
41static pthread_mutex_t thread_lock; 34static pthread_mutex_t thread_lock;
@@ -46,7 +39,6 @@ static unsigned int ncpus, threads_starting, nthreads = 0;
46static const struct option options[] = { 39static const struct option options[] = {
47 OPT_UINTEGER('t', "threads", &nthreads, "Specify amount of threads"), 40 OPT_UINTEGER('t', "threads", &nthreads, "Specify amount of threads"),
48 OPT_UINTEGER('q', "nrequeue", &nrequeue, "Specify amount of threads to requeue at once"), 41 OPT_UINTEGER('q', "nrequeue", &nrequeue, "Specify amount of threads to requeue at once"),
49 OPT_UINTEGER('r', "repeat", &repeat, "Specify amount of times to repeat the run"),
50 OPT_BOOLEAN( 's', "silent", &silent, "Silent mode: do not display data/details"), 42 OPT_BOOLEAN( 's', "silent", &silent, "Silent mode: do not display data/details"),
51 OPT_END() 43 OPT_END()
52}; 44};
@@ -146,7 +138,7 @@ int bench_futex_requeue(int argc, const char **argv,
146 pthread_cond_init(&thread_parent, NULL); 138 pthread_cond_init(&thread_parent, NULL);
147 pthread_cond_init(&thread_worker, NULL); 139 pthread_cond_init(&thread_worker, NULL);
148 140
149 for (j = 0; j < repeat && !done; j++) { 141 for (j = 0; j < bench_repeat && !done; j++) {
150 unsigned int nrequeued = 0; 142 unsigned int nrequeued = 0;
151 struct timeval start, end, runtime; 143 struct timeval start, end, runtime;
152 144
diff --git a/tools/perf/bench/futex-wake.c b/tools/perf/bench/futex-wake.c
index d096169b161e..50022cbce87e 100644
--- a/tools/perf/bench/futex-wake.c
+++ b/tools/perf/bench/futex-wake.c
@@ -30,15 +30,8 @@ static u_int32_t futex1 = 0;
30 */ 30 */
31static unsigned int nwakes = 1; 31static unsigned int nwakes = 1;
32 32
33/*
34 * There can be significant variance from run to run,
35 * the more repeats, the more exact the overall avg and
36 * the better idea of the futex latency.
37 */
38static unsigned int repeat = 10;
39
40pthread_t *worker; 33pthread_t *worker;
41static bool done = 0, silent = 0; 34static bool done = false, silent = false;
42static pthread_mutex_t thread_lock; 35static pthread_mutex_t thread_lock;
43static pthread_cond_t thread_parent, thread_worker; 36static pthread_cond_t thread_parent, thread_worker;
44static struct stats waketime_stats, wakeup_stats; 37static struct stats waketime_stats, wakeup_stats;
@@ -47,7 +40,6 @@ static unsigned int ncpus, threads_starting, nthreads = 0;
47static const struct option options[] = { 40static const struct option options[] = {
48 OPT_UINTEGER('t', "threads", &nthreads, "Specify amount of threads"), 41 OPT_UINTEGER('t', "threads", &nthreads, "Specify amount of threads"),
49 OPT_UINTEGER('w', "nwakes", &nwakes, "Specify amount of threads to wake at once"), 42 OPT_UINTEGER('w', "nwakes", &nwakes, "Specify amount of threads to wake at once"),
50 OPT_UINTEGER('r', "repeat", &repeat, "Specify amount of times to repeat the run"),
51 OPT_BOOLEAN( 's', "silent", &silent, "Silent mode: do not display data/details"), 43 OPT_BOOLEAN( 's', "silent", &silent, "Silent mode: do not display data/details"),
52 OPT_END() 44 OPT_END()
53}; 45};
@@ -149,7 +141,7 @@ int bench_futex_wake(int argc, const char **argv,
149 pthread_cond_init(&thread_parent, NULL); 141 pthread_cond_init(&thread_parent, NULL);
150 pthread_cond_init(&thread_worker, NULL); 142 pthread_cond_init(&thread_worker, NULL);
151 143
152 for (j = 0; j < repeat && !done; j++) { 144 for (j = 0; j < bench_repeat && !done; j++) {
153 unsigned int nwoken = 0; 145 unsigned int nwoken = 0;
154 struct timeval start, end, runtime; 146 struct timeval start, end, runtime;
155 147
diff --git a/tools/perf/bench/mem-memcpy.c b/tools/perf/bench/mem-memcpy.c
index 5ce71d3b72cf..2465141b554b 100644
--- a/tools/perf/bench/mem-memcpy.c
+++ b/tools/perf/bench/mem-memcpy.c
@@ -10,6 +10,7 @@
10#include "../util/util.h" 10#include "../util/util.h"
11#include "../util/parse-options.h" 11#include "../util/parse-options.h"
12#include "../util/header.h" 12#include "../util/header.h"
13#include "../util/cloexec.h"
13#include "bench.h" 14#include "bench.h"
14#include "mem-memcpy-arch.h" 15#include "mem-memcpy-arch.h"
15 16
@@ -83,7 +84,8 @@ static struct perf_event_attr cycle_attr = {
83 84
84static void init_cycle(void) 85static void init_cycle(void)
85{ 86{
86 cycle_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1, 0); 87 cycle_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1,
88 perf_event_open_cloexec_flag());
87 89
88 if (cycle_fd < 0 && errno == ENOSYS) 90 if (cycle_fd < 0 && errno == ENOSYS)
89 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); 91 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
@@ -189,6 +191,11 @@ int bench_mem_memcpy(int argc, const char **argv,
189 argc = parse_options(argc, argv, options, 191 argc = parse_options(argc, argv, options,
190 bench_mem_memcpy_usage, 0); 192 bench_mem_memcpy_usage, 0);
191 193
194 if (no_prefault && only_prefault) {
195 fprintf(stderr, "Invalid options: -o and -n are mutually exclusive\n");
196 return 1;
197 }
198
192 if (use_cycle) 199 if (use_cycle)
193 init_cycle(); 200 init_cycle();
194 201
diff --git a/tools/perf/bench/mem-memset.c b/tools/perf/bench/mem-memset.c
index 9af79d2b18e5..75fc3e65fb2a 100644
--- a/tools/perf/bench/mem-memset.c
+++ b/tools/perf/bench/mem-memset.c
@@ -10,6 +10,7 @@
10#include "../util/util.h" 10#include "../util/util.h"
11#include "../util/parse-options.h" 11#include "../util/parse-options.h"
12#include "../util/header.h" 12#include "../util/header.h"
13#include "../util/cloexec.h"
13#include "bench.h" 14#include "bench.h"
14#include "mem-memset-arch.h" 15#include "mem-memset-arch.h"
15 16
@@ -83,7 +84,8 @@ static struct perf_event_attr cycle_attr = {
83 84
84static void init_cycle(void) 85static void init_cycle(void)
85{ 86{
86 cycle_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1, 0); 87 cycle_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1,
88 perf_event_open_cloexec_flag());
87 89
88 if (cycle_fd < 0 && errno == ENOSYS) 90 if (cycle_fd < 0 && errno == ENOSYS)
89 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); 91 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
@@ -181,6 +183,11 @@ int bench_mem_memset(int argc, const char **argv,
181 argc = parse_options(argc, argv, options, 183 argc = parse_options(argc, argv, options,
182 bench_mem_memset_usage, 0); 184 bench_mem_memset_usage, 0);
183 185
186 if (no_prefault && only_prefault) {
187 fprintf(stderr, "Invalid options: -o and -n are mutually exclusive\n");
188 return 1;
189 }
190
184 if (use_cycle) 191 if (use_cycle)
185 init_cycle(); 192 init_cycle();
186 193
diff --git a/tools/perf/bench/sched-messaging.c b/tools/perf/bench/sched-messaging.c
index cc1190a0849b..52a56599a543 100644
--- a/tools/perf/bench/sched-messaging.c
+++ b/tools/perf/bench/sched-messaging.c
@@ -28,6 +28,7 @@
28#include <sys/time.h> 28#include <sys/time.h>
29#include <sys/poll.h> 29#include <sys/poll.h>
30#include <limits.h> 30#include <limits.h>
31#include <err.h>
31 32
32#define DATASIZE 100 33#define DATASIZE 100
33 34
@@ -50,12 +51,6 @@ struct receiver_context {
50 int wakefd; 51 int wakefd;
51}; 52};
52 53
53static void barf(const char *msg)
54{
55 fprintf(stderr, "%s (error: %s)\n", msg, strerror(errno));
56 exit(1);
57}
58
59static void fdpair(int fds[2]) 54static void fdpair(int fds[2])
60{ 55{
61 if (use_pipes) { 56 if (use_pipes) {
@@ -66,7 +61,7 @@ static void fdpair(int fds[2])
66 return; 61 return;
67 } 62 }
68 63
69 barf(use_pipes ? "pipe()" : "socketpair()"); 64 err(EXIT_FAILURE, use_pipes ? "pipe()" : "socketpair()");
70} 65}
71 66
72/* Block until we're ready to go */ 67/* Block until we're ready to go */
@@ -77,11 +72,11 @@ static void ready(int ready_out, int wakefd)
77 72
78 /* Tell them we're ready. */ 73 /* Tell them we're ready. */
79 if (write(ready_out, &dummy, 1) != 1) 74 if (write(ready_out, &dummy, 1) != 1)
80 barf("CLIENT: ready write"); 75 err(EXIT_FAILURE, "CLIENT: ready write");
81 76
82 /* Wait for "GO" signal */ 77 /* Wait for "GO" signal */
83 if (poll(&pollfd, 1, -1) != 1) 78 if (poll(&pollfd, 1, -1) != 1)
84 barf("poll"); 79 err(EXIT_FAILURE, "poll");
85} 80}
86 81
87/* Sender sprays loops messages down each file descriptor */ 82/* Sender sprays loops messages down each file descriptor */
@@ -101,7 +96,7 @@ again:
101 ret = write(ctx->out_fds[j], data + done, 96 ret = write(ctx->out_fds[j], data + done,
102 sizeof(data)-done); 97 sizeof(data)-done);
103 if (ret < 0) 98 if (ret < 0)
104 barf("SENDER: write"); 99 err(EXIT_FAILURE, "SENDER: write");
105 done += ret; 100 done += ret;
106 if (done < DATASIZE) 101 if (done < DATASIZE)
107 goto again; 102 goto again;
@@ -131,7 +126,7 @@ static void *receiver(struct receiver_context* ctx)
131again: 126again:
132 ret = read(ctx->in_fds[0], data + done, DATASIZE - done); 127 ret = read(ctx->in_fds[0], data + done, DATASIZE - done);
133 if (ret < 0) 128 if (ret < 0)
134 barf("SERVER: read"); 129 err(EXIT_FAILURE, "SERVER: read");
135 done += ret; 130 done += ret;
136 if (done < DATASIZE) 131 if (done < DATASIZE)
137 goto again; 132 goto again;
@@ -144,14 +139,14 @@ static pthread_t create_worker(void *ctx, void *(*func)(void *))
144{ 139{
145 pthread_attr_t attr; 140 pthread_attr_t attr;
146 pthread_t childid; 141 pthread_t childid;
147 int err; 142 int ret;
148 143
149 if (!thread_mode) { 144 if (!thread_mode) {
150 /* process mode */ 145 /* process mode */
151 /* Fork the receiver. */ 146 /* Fork the receiver. */
152 switch (fork()) { 147 switch (fork()) {
153 case -1: 148 case -1:
154 barf("fork()"); 149 err(EXIT_FAILURE, "fork()");
155 break; 150 break;
156 case 0: 151 case 0:
157 (*func) (ctx); 152 (*func) (ctx);
@@ -165,19 +160,17 @@ static pthread_t create_worker(void *ctx, void *(*func)(void *))
165 } 160 }
166 161
167 if (pthread_attr_init(&attr) != 0) 162 if (pthread_attr_init(&attr) != 0)
168 barf("pthread_attr_init:"); 163 err(EXIT_FAILURE, "pthread_attr_init:");
169 164
170#ifndef __ia64__ 165#ifndef __ia64__
171 if (pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN) != 0) 166 if (pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN) != 0)
172 barf("pthread_attr_setstacksize"); 167 err(EXIT_FAILURE, "pthread_attr_setstacksize");
173#endif 168#endif
174 169
175 err = pthread_create(&childid, &attr, func, ctx); 170 ret = pthread_create(&childid, &attr, func, ctx);
176 if (err != 0) { 171 if (ret != 0)
177 fprintf(stderr, "pthread_create failed: %s (%d)\n", 172 err(EXIT_FAILURE, "pthread_create failed");
178 strerror(err), err); 173
179 exit(-1);
180 }
181 return childid; 174 return childid;
182} 175}
183 176
@@ -207,14 +200,14 @@ static unsigned int group(pthread_t *pth,
207 + num_fds * sizeof(int)); 200 + num_fds * sizeof(int));
208 201
209 if (!snd_ctx) 202 if (!snd_ctx)
210 barf("malloc()"); 203 err(EXIT_FAILURE, "malloc()");
211 204
212 for (i = 0; i < num_fds; i++) { 205 for (i = 0; i < num_fds; i++) {
213 int fds[2]; 206 int fds[2];
214 struct receiver_context *ctx = malloc(sizeof(*ctx)); 207 struct receiver_context *ctx = malloc(sizeof(*ctx));
215 208
216 if (!ctx) 209 if (!ctx)
217 barf("malloc()"); 210 err(EXIT_FAILURE, "malloc()");
218 211
219 212
220 /* Create the pipe between client and server */ 213 /* Create the pipe between client and server */
@@ -281,7 +274,7 @@ int bench_sched_messaging(int argc, const char **argv,
281 274
282 pth_tab = malloc(num_fds * 2 * num_groups * sizeof(pthread_t)); 275 pth_tab = malloc(num_fds * 2 * num_groups * sizeof(pthread_t));
283 if (!pth_tab) 276 if (!pth_tab)
284 barf("main:malloc()"); 277 err(EXIT_FAILURE, "main:malloc()");
285 278
286 fdpair(readyfds); 279 fdpair(readyfds);
287 fdpair(wakefds); 280 fdpair(wakefds);
@@ -294,13 +287,13 @@ int bench_sched_messaging(int argc, const char **argv,
294 /* Wait for everyone to be ready */ 287 /* Wait for everyone to be ready */
295 for (i = 0; i < total_children; i++) 288 for (i = 0; i < total_children; i++)
296 if (read(readyfds[0], &dummy, 1) != 1) 289 if (read(readyfds[0], &dummy, 1) != 1)
297 barf("Reading for readyfds"); 290 err(EXIT_FAILURE, "Reading for readyfds");
298 291
299 gettimeofday(&start, NULL); 292 gettimeofday(&start, NULL);
300 293
301 /* Kick them off */ 294 /* Kick them off */
302 if (write(wakefds[1], &dummy, 1) != 1) 295 if (write(wakefds[1], &dummy, 1) != 1)
303 barf("Writing to start them"); 296 err(EXIT_FAILURE, "Writing to start them");
304 297
305 /* Reap them all */ 298 /* Reap them all */
306 for (i = 0; i < total_children; i++) 299 for (i = 0; i < total_children; i++)
@@ -332,5 +325,7 @@ int bench_sched_messaging(int argc, const char **argv,
332 break; 325 break;
333 } 326 }
334 327
328 free(pth_tab);
329
335 return 0; 330 return 0;
336} 331}
diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c
index 1e6e77710545..b9a56fa83330 100644
--- a/tools/perf/builtin-bench.c
+++ b/tools/perf/builtin-bench.c
@@ -104,9 +104,11 @@ static const char *bench_format_str;
104 104
105/* Output/formatting style, exported to benchmark modules: */ 105/* Output/formatting style, exported to benchmark modules: */
106int bench_format = BENCH_FORMAT_DEFAULT; 106int bench_format = BENCH_FORMAT_DEFAULT;
107unsigned int bench_repeat = 10; /* default number of times to repeat the run */
107 108
108static const struct option bench_options[] = { 109static const struct option bench_options[] = {
109 OPT_STRING('f', "format", &bench_format_str, "default", "Specify format style"), 110 OPT_STRING('f', "format", &bench_format_str, "default", "Specify format style"),
111 OPT_UINTEGER('r', "repeat", &bench_repeat, "Specify amount of times to repeat the run"),
110 OPT_END() 112 OPT_END()
111}; 113};
112 114
@@ -226,6 +228,11 @@ int cmd_bench(int argc, const char **argv, const char *prefix __maybe_unused)
226 goto end; 228 goto end;
227 } 229 }
228 230
231 if (bench_repeat == 0) {
232 printf("Invalid repeat option: Must specify a positive value\n");
233 goto end;
234 }
235
229 if (argc < 1) { 236 if (argc < 1) {
230 print_usage(); 237 print_usage();
231 goto end; 238 goto end;
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c
index b22dbb16f877..2a2c78f80876 100644
--- a/tools/perf/builtin-buildid-cache.c
+++ b/tools/perf/builtin-buildid-cache.c
@@ -125,7 +125,8 @@ static int build_id_cache__kcore_existing(const char *from_dir, char *to_dir,
125 return ret; 125 return ret;
126} 126}
127 127
128static int build_id_cache__add_kcore(const char *filename, const char *debugdir) 128static int build_id_cache__add_kcore(const char *filename, const char *debugdir,
129 bool force)
129{ 130{
130 char dir[32], sbuildid[BUILD_ID_SIZE * 2 + 1]; 131 char dir[32], sbuildid[BUILD_ID_SIZE * 2 + 1];
131 char from_dir[PATH_MAX], to_dir[PATH_MAX]; 132 char from_dir[PATH_MAX], to_dir[PATH_MAX];
@@ -144,7 +145,8 @@ static int build_id_cache__add_kcore(const char *filename, const char *debugdir)
144 scnprintf(to_dir, sizeof(to_dir), "%s/[kernel.kcore]/%s", 145 scnprintf(to_dir, sizeof(to_dir), "%s/[kernel.kcore]/%s",
145 debugdir, sbuildid); 146 debugdir, sbuildid);
146 147
147 if (!build_id_cache__kcore_existing(from_dir, to_dir, sizeof(to_dir))) { 148 if (!force &&
149 !build_id_cache__kcore_existing(from_dir, to_dir, sizeof(to_dir))) {
148 pr_debug("same kcore found in %s\n", to_dir); 150 pr_debug("same kcore found in %s\n", to_dir);
149 return 0; 151 return 0;
150 } 152 }
@@ -389,7 +391,7 @@ int cmd_buildid_cache(int argc, const char **argv,
389 } 391 }
390 392
391 if (kcore_filename && 393 if (kcore_filename &&
392 build_id_cache__add_kcore(kcore_filename, debugdir)) 394 build_id_cache__add_kcore(kcore_filename, debugdir, force))
393 pr_warning("Couldn't add %s\n", kcore_filename); 395 pr_warning("Couldn't add %s\n", kcore_filename);
394 396
395 return ret; 397 return ret;
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c
index c99e0de7e54a..66e12f55c052 100644
--- a/tools/perf/builtin-evlist.c
+++ b/tools/perf/builtin-evlist.c
@@ -15,6 +15,7 @@
15#include "util/parse-options.h" 15#include "util/parse-options.h"
16#include "util/session.h" 16#include "util/session.h"
17#include "util/data.h" 17#include "util/data.h"
18#include "util/debug.h"
18 19
19static int __cmd_evlist(const char *file_name, struct perf_attr_details *details) 20static int __cmd_evlist(const char *file_name, struct perf_attr_details *details)
20{ 21{
diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c
index 178b88ae3d2f..0384d930480b 100644
--- a/tools/perf/builtin-help.c
+++ b/tools/perf/builtin-help.c
@@ -11,6 +11,7 @@
11#include "util/parse-options.h" 11#include "util/parse-options.h"
12#include "util/run-command.h" 12#include "util/run-command.h"
13#include "util/help.h" 13#include "util/help.h"
14#include "util/debug.h"
14 15
15static struct man_viewer_list { 16static struct man_viewer_list {
16 struct man_viewer_list *next; 17 struct man_viewer_list *next;
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 16c7c11ad06e..9a02807387d6 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -389,6 +389,9 @@ static int __cmd_inject(struct perf_inject *inject)
389 ret = perf_session__process_events(session, &inject->tool); 389 ret = perf_session__process_events(session, &inject->tool);
390 390
391 if (!file_out->is_pipe) { 391 if (!file_out->is_pipe) {
392 if (inject->build_ids)
393 perf_header__set_feat(&session->header,
394 HEADER_BUILD_ID);
392 session->header.data_size = inject->bytes_written; 395 session->header.data_size = inject->bytes_written;
393 perf_session__write_header(session, session->evlist, file_out->fd, true); 396 perf_session__write_header(session, session->evlist, file_out->fd, true);
394 } 397 }
@@ -436,6 +439,8 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
436 "where and how long tasks slept"), 439 "where and how long tasks slept"),
437 OPT_INCR('v', "verbose", &verbose, 440 OPT_INCR('v', "verbose", &verbose,
438 "be more verbose (show build ids, etc)"), 441 "be more verbose (show build ids, etc)"),
442 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file",
443 "kallsyms pathname"),
439 OPT_END() 444 OPT_END()
440 }; 445 };
441 const char * const inject_usage[] = { 446 const char * const inject_usage[] = {
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index 0f1e5a2f6ad7..43367eb00510 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -29,114 +29,25 @@
29#include <pthread.h> 29#include <pthread.h>
30#include <math.h> 30#include <math.h>
31 31
32#if defined(__i386__) || defined(__x86_64__) 32#ifdef HAVE_KVM_STAT_SUPPORT
33#include <asm/svm.h> 33#include <asm/kvm_perf.h>
34#include <asm/vmx.h> 34#include "util/kvm-stat.h"
35#include <asm/kvm.h>
36
37struct event_key {
38 #define INVALID_KEY (~0ULL)
39 u64 key;
40 int info;
41};
42
43struct kvm_event_stats {
44 u64 time;
45 struct stats stats;
46};
47
48struct kvm_event {
49 struct list_head hash_entry;
50 struct rb_node rb;
51
52 struct event_key key;
53
54 struct kvm_event_stats total;
55
56 #define DEFAULT_VCPU_NUM 8
57 int max_vcpu;
58 struct kvm_event_stats *vcpu;
59};
60
61typedef int (*key_cmp_fun)(struct kvm_event*, struct kvm_event*, int);
62
63struct kvm_event_key {
64 const char *name;
65 key_cmp_fun key;
66};
67
68
69struct perf_kvm_stat;
70
71struct kvm_events_ops {
72 bool (*is_begin_event)(struct perf_evsel *evsel,
73 struct perf_sample *sample,
74 struct event_key *key);
75 bool (*is_end_event)(struct perf_evsel *evsel,
76 struct perf_sample *sample, struct event_key *key);
77 void (*decode_key)(struct perf_kvm_stat *kvm, struct event_key *key,
78 char decode[20]);
79 const char *name;
80};
81
82struct exit_reasons_table {
83 unsigned long exit_code;
84 const char *reason;
85};
86 35
87#define EVENTS_BITS 12 36void exit_event_get_key(struct perf_evsel *evsel,
88#define EVENTS_CACHE_SIZE (1UL << EVENTS_BITS) 37 struct perf_sample *sample,
89 38 struct event_key *key)
90struct perf_kvm_stat {
91 struct perf_tool tool;
92 struct record_opts opts;
93 struct perf_evlist *evlist;
94 struct perf_session *session;
95
96 const char *file_name;
97 const char *report_event;
98 const char *sort_key;
99 int trace_vcpu;
100
101 struct exit_reasons_table *exit_reasons;
102 int exit_reasons_size;
103 const char *exit_reasons_isa;
104
105 struct kvm_events_ops *events_ops;
106 key_cmp_fun compare;
107 struct list_head kvm_events_cache[EVENTS_CACHE_SIZE];
108
109 u64 total_time;
110 u64 total_count;
111 u64 lost_events;
112 u64 duration;
113
114 const char *pid_str;
115 struct intlist *pid_list;
116
117 struct rb_root result;
118
119 int timerfd;
120 unsigned int display_time;
121 bool live;
122};
123
124
125static void exit_event_get_key(struct perf_evsel *evsel,
126 struct perf_sample *sample,
127 struct event_key *key)
128{ 39{
129 key->info = 0; 40 key->info = 0;
130 key->key = perf_evsel__intval(evsel, sample, "exit_reason"); 41 key->key = perf_evsel__intval(evsel, sample, KVM_EXIT_REASON);
131} 42}
132 43
133static bool kvm_exit_event(struct perf_evsel *evsel) 44bool kvm_exit_event(struct perf_evsel *evsel)
134{ 45{
135 return !strcmp(evsel->name, "kvm:kvm_exit"); 46 return !strcmp(evsel->name, KVM_EXIT_TRACE);
136} 47}
137 48
138static bool exit_event_begin(struct perf_evsel *evsel, 49bool exit_event_begin(struct perf_evsel *evsel,
139 struct perf_sample *sample, struct event_key *key) 50 struct perf_sample *sample, struct event_key *key)
140{ 51{
141 if (kvm_exit_event(evsel)) { 52 if (kvm_exit_event(evsel)) {
142 exit_event_get_key(evsel, sample, key); 53 exit_event_get_key(evsel, sample, key);
@@ -146,32 +57,23 @@ static bool exit_event_begin(struct perf_evsel *evsel,
146 return false; 57 return false;
147} 58}
148 59
149static bool kvm_entry_event(struct perf_evsel *evsel) 60bool kvm_entry_event(struct perf_evsel *evsel)
150{ 61{
151 return !strcmp(evsel->name, "kvm:kvm_entry"); 62 return !strcmp(evsel->name, KVM_ENTRY_TRACE);
152} 63}
153 64
154static bool exit_event_end(struct perf_evsel *evsel, 65bool exit_event_end(struct perf_evsel *evsel,
155 struct perf_sample *sample __maybe_unused, 66 struct perf_sample *sample __maybe_unused,
156 struct event_key *key __maybe_unused) 67 struct event_key *key __maybe_unused)
157{ 68{
158 return kvm_entry_event(evsel); 69 return kvm_entry_event(evsel);
159} 70}
160 71
161static struct exit_reasons_table vmx_exit_reasons[] = { 72static const char *get_exit_reason(struct perf_kvm_stat *kvm,
162 VMX_EXIT_REASONS 73 struct exit_reasons_table *tbl,
163}; 74 u64 exit_code)
164
165static struct exit_reasons_table svm_exit_reasons[] = {
166 SVM_EXIT_REASONS
167};
168
169static const char *get_exit_reason(struct perf_kvm_stat *kvm, u64 exit_code)
170{ 75{
171 int i = kvm->exit_reasons_size; 76 while (tbl->reason != NULL) {
172 struct exit_reasons_table *tbl = kvm->exit_reasons;
173
174 while (i--) {
175 if (tbl->exit_code == exit_code) 77 if (tbl->exit_code == exit_code)
176 return tbl->reason; 78 return tbl->reason;
177 tbl++; 79 tbl++;
@@ -182,148 +84,30 @@ static const char *get_exit_reason(struct perf_kvm_stat *kvm, u64 exit_code)
182 return "UNKNOWN"; 84 return "UNKNOWN";
183} 85}
184 86
185static void exit_event_decode_key(struct perf_kvm_stat *kvm, 87void exit_event_decode_key(struct perf_kvm_stat *kvm,
186 struct event_key *key, 88 struct event_key *key,
187 char decode[20]) 89 char *decode)
188{ 90{
189 const char *exit_reason = get_exit_reason(kvm, key->key); 91 const char *exit_reason = get_exit_reason(kvm, key->exit_reasons,
92 key->key);
190 93
191 scnprintf(decode, 20, "%s", exit_reason); 94 scnprintf(decode, DECODE_STR_LEN, "%s", exit_reason);
192} 95}
193 96
194static struct kvm_events_ops exit_events = { 97static bool register_kvm_events_ops(struct perf_kvm_stat *kvm)
195 .is_begin_event = exit_event_begin,
196 .is_end_event = exit_event_end,
197 .decode_key = exit_event_decode_key,
198 .name = "VM-EXIT"
199};
200
201/*
202 * For the mmio events, we treat:
203 * the time of MMIO write: kvm_mmio(KVM_TRACE_MMIO_WRITE...) -> kvm_entry
204 * the time of MMIO read: kvm_exit -> kvm_mmio(KVM_TRACE_MMIO_READ...).
205 */
206static void mmio_event_get_key(struct perf_evsel *evsel, struct perf_sample *sample,
207 struct event_key *key)
208{
209 key->key = perf_evsel__intval(evsel, sample, "gpa");
210 key->info = perf_evsel__intval(evsel, sample, "type");
211}
212
213#define KVM_TRACE_MMIO_READ_UNSATISFIED 0
214#define KVM_TRACE_MMIO_READ 1
215#define KVM_TRACE_MMIO_WRITE 2
216
217static bool mmio_event_begin(struct perf_evsel *evsel,
218 struct perf_sample *sample, struct event_key *key)
219{
220 /* MMIO read begin event in kernel. */
221 if (kvm_exit_event(evsel))
222 return true;
223
224 /* MMIO write begin event in kernel. */
225 if (!strcmp(evsel->name, "kvm:kvm_mmio") &&
226 perf_evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_WRITE) {
227 mmio_event_get_key(evsel, sample, key);
228 return true;
229 }
230
231 return false;
232}
233
234static bool mmio_event_end(struct perf_evsel *evsel, struct perf_sample *sample,
235 struct event_key *key)
236{
237 /* MMIO write end event in kernel. */
238 if (kvm_entry_event(evsel))
239 return true;
240
241 /* MMIO read end event in kernel.*/
242 if (!strcmp(evsel->name, "kvm:kvm_mmio") &&
243 perf_evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_READ) {
244 mmio_event_get_key(evsel, sample, key);
245 return true;
246 }
247
248 return false;
249}
250
251static void mmio_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
252 struct event_key *key,
253 char decode[20])
254{
255 scnprintf(decode, 20, "%#lx:%s", (unsigned long)key->key,
256 key->info == KVM_TRACE_MMIO_WRITE ? "W" : "R");
257}
258
259static struct kvm_events_ops mmio_events = {
260 .is_begin_event = mmio_event_begin,
261 .is_end_event = mmio_event_end,
262 .decode_key = mmio_event_decode_key,
263 .name = "MMIO Access"
264};
265
266 /* The time of emulation pio access is from kvm_pio to kvm_entry. */
267static void ioport_event_get_key(struct perf_evsel *evsel,
268 struct perf_sample *sample,
269 struct event_key *key)
270{ 98{
271 key->key = perf_evsel__intval(evsel, sample, "port"); 99 struct kvm_reg_events_ops *events_ops = kvm_reg_events_ops;
272 key->info = perf_evsel__intval(evsel, sample, "rw");
273}
274 100
275static bool ioport_event_begin(struct perf_evsel *evsel, 101 for (events_ops = kvm_reg_events_ops; events_ops->name; events_ops++) {
276 struct perf_sample *sample, 102 if (!strcmp(events_ops->name, kvm->report_event)) {
277 struct event_key *key) 103 kvm->events_ops = events_ops->ops;
278{ 104 return true;
279 if (!strcmp(evsel->name, "kvm:kvm_pio")) { 105 }
280 ioport_event_get_key(evsel, sample, key);
281 return true;
282 } 106 }
283 107
284 return false; 108 return false;
285} 109}
286 110
287static bool ioport_event_end(struct perf_evsel *evsel,
288 struct perf_sample *sample __maybe_unused,
289 struct event_key *key __maybe_unused)
290{
291 return kvm_entry_event(evsel);
292}
293
294static void ioport_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
295 struct event_key *key,
296 char decode[20])
297{
298 scnprintf(decode, 20, "%#llx:%s", (unsigned long long)key->key,
299 key->info ? "POUT" : "PIN");
300}
301
302static struct kvm_events_ops ioport_events = {
303 .is_begin_event = ioport_event_begin,
304 .is_end_event = ioport_event_end,
305 .decode_key = ioport_event_decode_key,
306 .name = "IO Port Access"
307};
308
309static bool register_kvm_events_ops(struct perf_kvm_stat *kvm)
310{
311 bool ret = true;
312
313 if (!strcmp(kvm->report_event, "vmexit"))
314 kvm->events_ops = &exit_events;
315 else if (!strcmp(kvm->report_event, "mmio"))
316 kvm->events_ops = &mmio_events;
317 else if (!strcmp(kvm->report_event, "ioport"))
318 kvm->events_ops = &ioport_events;
319 else {
320 pr_err("Unknown report event:%s\n", kvm->report_event);
321 ret = false;
322 }
323
324 return ret;
325}
326
327struct vcpu_event_record { 111struct vcpu_event_record {
328 int vcpu_id; 112 int vcpu_id;
329 u64 start_time; 113 u64 start_time;
@@ -477,6 +261,54 @@ static bool update_kvm_event(struct kvm_event *event, int vcpu_id,
477 return true; 261 return true;
478} 262}
479 263
264static bool is_child_event(struct perf_kvm_stat *kvm,
265 struct perf_evsel *evsel,
266 struct perf_sample *sample,
267 struct event_key *key)
268{
269 struct child_event_ops *child_ops;
270
271 child_ops = kvm->events_ops->child_ops;
272
273 if (!child_ops)
274 return false;
275
276 for (; child_ops->name; child_ops++) {
277 if (!strcmp(evsel->name, child_ops->name)) {
278 child_ops->get_key(evsel, sample, key);
279 return true;
280 }
281 }
282
283 return false;
284}
285
286static bool handle_child_event(struct perf_kvm_stat *kvm,
287 struct vcpu_event_record *vcpu_record,
288 struct event_key *key,
289 struct perf_sample *sample __maybe_unused)
290{
291 struct kvm_event *event = NULL;
292
293 if (key->key != INVALID_KEY)
294 event = find_create_kvm_event(kvm, key);
295
296 vcpu_record->last_event = event;
297
298 return true;
299}
300
301static bool skip_event(const char *event)
302{
303 const char * const *skip_events;
304
305 for (skip_events = kvm_skip_events; *skip_events; skip_events++)
306 if (!strcmp(event, *skip_events))
307 return true;
308
309 return false;
310}
311
480static bool handle_end_event(struct perf_kvm_stat *kvm, 312static bool handle_end_event(struct perf_kvm_stat *kvm,
481 struct vcpu_event_record *vcpu_record, 313 struct vcpu_event_record *vcpu_record,
482 struct event_key *key, 314 struct event_key *key,
@@ -525,10 +357,10 @@ static bool handle_end_event(struct perf_kvm_stat *kvm,
525 time_diff = sample->time - time_begin; 357 time_diff = sample->time - time_begin;
526 358
527 if (kvm->duration && time_diff > kvm->duration) { 359 if (kvm->duration && time_diff > kvm->duration) {
528 char decode[32]; 360 char decode[DECODE_STR_LEN];
529 361
530 kvm->events_ops->decode_key(kvm, &event->key, decode); 362 kvm->events_ops->decode_key(kvm, &event->key, decode);
531 if (strcmp(decode, "HLT")) { 363 if (!skip_event(decode)) {
532 pr_info("%" PRIu64 " VM %d, vcpu %d: %s event took %" PRIu64 "usec\n", 364 pr_info("%" PRIu64 " VM %d, vcpu %d: %s event took %" PRIu64 "usec\n",
533 sample->time, sample->pid, vcpu_record->vcpu_id, 365 sample->time, sample->pid, vcpu_record->vcpu_id,
534 decode, time_diff/1000); 366 decode, time_diff/1000);
@@ -553,7 +385,7 @@ struct vcpu_event_record *per_vcpu_record(struct thread *thread,
553 return NULL; 385 return NULL;
554 } 386 }
555 387
556 vcpu_record->vcpu_id = perf_evsel__intval(evsel, sample, "vcpu_id"); 388 vcpu_record->vcpu_id = perf_evsel__intval(evsel, sample, VCPU_ID);
557 thread->priv = vcpu_record; 389 thread->priv = vcpu_record;
558 } 390 }
559 391
@@ -566,7 +398,8 @@ static bool handle_kvm_event(struct perf_kvm_stat *kvm,
566 struct perf_sample *sample) 398 struct perf_sample *sample)
567{ 399{
568 struct vcpu_event_record *vcpu_record; 400 struct vcpu_event_record *vcpu_record;
569 struct event_key key = {.key = INVALID_KEY}; 401 struct event_key key = { .key = INVALID_KEY,
402 .exit_reasons = kvm->exit_reasons };
570 403
571 vcpu_record = per_vcpu_record(thread, evsel, sample); 404 vcpu_record = per_vcpu_record(thread, evsel, sample);
572 if (!vcpu_record) 405 if (!vcpu_record)
@@ -580,6 +413,9 @@ static bool handle_kvm_event(struct perf_kvm_stat *kvm,
580 if (kvm->events_ops->is_begin_event(evsel, sample, &key)) 413 if (kvm->events_ops->is_begin_event(evsel, sample, &key))
581 return handle_begin_event(kvm, vcpu_record, &key, sample->time); 414 return handle_begin_event(kvm, vcpu_record, &key, sample->time);
582 415
416 if (is_child_event(kvm, evsel, sample, &key))
417 return handle_child_event(kvm, vcpu_record, &key, sample);
418
583 if (kvm->events_ops->is_end_event(evsel, sample, &key)) 419 if (kvm->events_ops->is_end_event(evsel, sample, &key))
584 return handle_end_event(kvm, vcpu_record, &key, sample); 420 return handle_end_event(kvm, vcpu_record, &key, sample);
585 421
@@ -740,7 +576,7 @@ static void show_timeofday(void)
740 576
741static void print_result(struct perf_kvm_stat *kvm) 577static void print_result(struct perf_kvm_stat *kvm)
742{ 578{
743 char decode[20]; 579 char decode[DECODE_STR_LEN];
744 struct kvm_event *event; 580 struct kvm_event *event;
745 int vcpu = kvm->trace_vcpu; 581 int vcpu = kvm->trace_vcpu;
746 582
@@ -751,7 +587,7 @@ static void print_result(struct perf_kvm_stat *kvm)
751 587
752 pr_info("\n\n"); 588 pr_info("\n\n");
753 print_vcpu_info(kvm); 589 print_vcpu_info(kvm);
754 pr_info("%20s ", kvm->events_ops->name); 590 pr_info("%*s ", DECODE_STR_LEN, kvm->events_ops->name);
755 pr_info("%10s ", "Samples"); 591 pr_info("%10s ", "Samples");
756 pr_info("%9s ", "Samples%"); 592 pr_info("%9s ", "Samples%");
757 593
@@ -770,7 +606,7 @@ static void print_result(struct perf_kvm_stat *kvm)
770 min = get_event_min(event, vcpu); 606 min = get_event_min(event, vcpu);
771 607
772 kvm->events_ops->decode_key(kvm, &event->key, decode); 608 kvm->events_ops->decode_key(kvm, &event->key, decode);
773 pr_info("%20s ", decode); 609 pr_info("%*s ", DECODE_STR_LEN, decode);
774 pr_info("%10llu ", (unsigned long long)ecount); 610 pr_info("%10llu ", (unsigned long long)ecount);
775 pr_info("%8.2f%% ", (double)ecount / kvm->total_count * 100); 611 pr_info("%8.2f%% ", (double)ecount / kvm->total_count * 100);
776 pr_info("%8.2f%% ", (double)etime / kvm->total_time * 100); 612 pr_info("%8.2f%% ", (double)etime / kvm->total_time * 100);
@@ -839,34 +675,28 @@ static int process_sample_event(struct perf_tool *tool,
839static int cpu_isa_config(struct perf_kvm_stat *kvm) 675static int cpu_isa_config(struct perf_kvm_stat *kvm)
840{ 676{
841 char buf[64], *cpuid; 677 char buf[64], *cpuid;
842 int err, isa; 678 int err;
843 679
844 if (kvm->live) { 680 if (kvm->live) {
845 err = get_cpuid(buf, sizeof(buf)); 681 err = get_cpuid(buf, sizeof(buf));
846 if (err != 0) { 682 if (err != 0) {
847 pr_err("Failed to look up CPU type (Intel or AMD)\n"); 683 pr_err("Failed to look up CPU type\n");
848 return err; 684 return err;
849 } 685 }
850 cpuid = buf; 686 cpuid = buf;
851 } else 687 } else
852 cpuid = kvm->session->header.env.cpuid; 688 cpuid = kvm->session->header.env.cpuid;
853 689
854 if (strstr(cpuid, "Intel")) 690 if (!cpuid) {
855 isa = 1; 691 pr_err("Failed to look up CPU type\n");
856 else if (strstr(cpuid, "AMD")) 692 return -EINVAL;
857 isa = 0;
858 else {
859 pr_err("CPU %s is not supported.\n", cpuid);
860 return -ENOTSUP;
861 } 693 }
862 694
863 if (isa == 1) { 695 err = cpu_isa_init(kvm, cpuid);
864 kvm->exit_reasons = vmx_exit_reasons; 696 if (err == -ENOTSUP)
865 kvm->exit_reasons_size = ARRAY_SIZE(vmx_exit_reasons); 697 pr_err("CPU %s is not supported.\n", cpuid);
866 kvm->exit_reasons_isa = "VMX";
867 }
868 698
869 return 0; 699 return err;
870} 700}
871 701
872static bool verify_vcpu(int vcpu) 702static bool verify_vcpu(int vcpu)
@@ -1300,13 +1130,6 @@ exit:
1300 return ret; 1130 return ret;
1301} 1131}
1302 1132
1303static const char * const kvm_events_tp[] = {
1304 "kvm:kvm_entry",
1305 "kvm:kvm_exit",
1306 "kvm:kvm_mmio",
1307 "kvm:kvm_pio",
1308};
1309
1310#define STRDUP_FAIL_EXIT(s) \ 1133#define STRDUP_FAIL_EXIT(s) \
1311 ({ char *_p; \ 1134 ({ char *_p; \
1312 _p = strdup(s); \ 1135 _p = strdup(s); \
@@ -1318,7 +1141,7 @@ static const char * const kvm_events_tp[] = {
1318static int 1141static int
1319kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv) 1142kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv)
1320{ 1143{
1321 unsigned int rec_argc, i, j; 1144 unsigned int rec_argc, i, j, events_tp_size;
1322 const char **rec_argv; 1145 const char **rec_argv;
1323 const char * const record_args[] = { 1146 const char * const record_args[] = {
1324 "record", 1147 "record",
@@ -1326,9 +1149,14 @@ kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv)
1326 "-m", "1024", 1149 "-m", "1024",
1327 "-c", "1", 1150 "-c", "1",
1328 }; 1151 };
1152 const char * const *events_tp;
1153 events_tp_size = 0;
1154
1155 for (events_tp = kvm_events_tp; *events_tp; events_tp++)
1156 events_tp_size++;
1329 1157
1330 rec_argc = ARRAY_SIZE(record_args) + argc + 2 + 1158 rec_argc = ARRAY_SIZE(record_args) + argc + 2 +
1331 2 * ARRAY_SIZE(kvm_events_tp); 1159 2 * events_tp_size;
1332 rec_argv = calloc(rec_argc + 1, sizeof(char *)); 1160 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1333 1161
1334 if (rec_argv == NULL) 1162 if (rec_argv == NULL)
@@ -1337,7 +1165,7 @@ kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv)
1337 for (i = 0; i < ARRAY_SIZE(record_args); i++) 1165 for (i = 0; i < ARRAY_SIZE(record_args); i++)
1338 rec_argv[i] = STRDUP_FAIL_EXIT(record_args[i]); 1166 rec_argv[i] = STRDUP_FAIL_EXIT(record_args[i]);
1339 1167
1340 for (j = 0; j < ARRAY_SIZE(kvm_events_tp); j++) { 1168 for (j = 0; j < events_tp_size; j++) {
1341 rec_argv[i++] = "-e"; 1169 rec_argv[i++] = "-e";
1342 rec_argv[i++] = STRDUP_FAIL_EXIT(kvm_events_tp[j]); 1170 rec_argv[i++] = STRDUP_FAIL_EXIT(kvm_events_tp[j]);
1343 } 1171 }
@@ -1356,7 +1184,8 @@ kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv)
1356{ 1184{
1357 const struct option kvm_events_report_options[] = { 1185 const struct option kvm_events_report_options[] = {
1358 OPT_STRING(0, "event", &kvm->report_event, "report event", 1186 OPT_STRING(0, "event", &kvm->report_event, "report event",
1359 "event for reporting: vmexit, mmio, ioport"), 1187 "event for reporting: vmexit, "
1188 "mmio (x86 only), ioport (x86 only)"),
1360 OPT_INTEGER(0, "vcpu", &kvm->trace_vcpu, 1189 OPT_INTEGER(0, "vcpu", &kvm->trace_vcpu,
1361 "vcpu id to report"), 1190 "vcpu id to report"),
1362 OPT_STRING('k', "key", &kvm->sort_key, "sort-key", 1191 OPT_STRING('k', "key", &kvm->sort_key, "sort-key",
@@ -1391,16 +1220,16 @@ static struct perf_evlist *kvm_live_event_list(void)
1391{ 1220{
1392 struct perf_evlist *evlist; 1221 struct perf_evlist *evlist;
1393 char *tp, *name, *sys; 1222 char *tp, *name, *sys;
1394 unsigned int j;
1395 int err = -1; 1223 int err = -1;
1224 const char * const *events_tp;
1396 1225
1397 evlist = perf_evlist__new(); 1226 evlist = perf_evlist__new();
1398 if (evlist == NULL) 1227 if (evlist == NULL)
1399 return NULL; 1228 return NULL;
1400 1229
1401 for (j = 0; j < ARRAY_SIZE(kvm_events_tp); j++) { 1230 for (events_tp = kvm_events_tp; *events_tp; events_tp++) {
1402 1231
1403 tp = strdup(kvm_events_tp[j]); 1232 tp = strdup(*events_tp);
1404 if (tp == NULL) 1233 if (tp == NULL)
1405 goto out; 1234 goto out;
1406 1235
@@ -1409,7 +1238,7 @@ static struct perf_evlist *kvm_live_event_list(void)
1409 name = strchr(tp, ':'); 1238 name = strchr(tp, ':');
1410 if (name == NULL) { 1239 if (name == NULL) {
1411 pr_err("Error parsing %s tracepoint: subsystem delimiter not found\n", 1240 pr_err("Error parsing %s tracepoint: subsystem delimiter not found\n",
1412 kvm_events_tp[j]); 1241 *events_tp);
1413 free(tp); 1242 free(tp);
1414 goto out; 1243 goto out;
1415 } 1244 }
@@ -1417,7 +1246,7 @@ static struct perf_evlist *kvm_live_event_list(void)
1417 name++; 1246 name++;
1418 1247
1419 if (perf_evlist__add_newtp(evlist, sys, name, NULL)) { 1248 if (perf_evlist__add_newtp(evlist, sys, name, NULL)) {
1420 pr_err("Failed to add %s tracepoint to the list\n", kvm_events_tp[j]); 1249 pr_err("Failed to add %s tracepoint to the list\n", *events_tp);
1421 free(tp); 1250 free(tp);
1422 goto out; 1251 goto out;
1423 } 1252 }
@@ -1462,7 +1291,9 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
1462 "key for sorting: sample(sort by samples number)" 1291 "key for sorting: sample(sort by samples number)"
1463 " time (sort by avg time)"), 1292 " time (sort by avg time)"),
1464 OPT_U64(0, "duration", &kvm->duration, 1293 OPT_U64(0, "duration", &kvm->duration,
1465 "show events other than HALT that take longer than duration usecs"), 1294 "show events other than"
1295 " HLT (x86 only) or Wait state (s390 only)"
1296 " that take longer than duration usecs"),
1466 OPT_END() 1297 OPT_END()
1467 }; 1298 };
1468 const char * const live_usage[] = { 1299 const char * const live_usage[] = {
@@ -1585,9 +1416,6 @@ static int kvm_cmd_stat(const char *file_name, int argc, const char **argv)
1585 .report_event = "vmexit", 1416 .report_event = "vmexit",
1586 .sort_key = "sample", 1417 .sort_key = "sample",
1587 1418
1588 .exit_reasons = svm_exit_reasons,
1589 .exit_reasons_size = ARRAY_SIZE(svm_exit_reasons),
1590 .exit_reasons_isa = "SVM",
1591 }; 1419 };
1592 1420
1593 if (argc == 1) { 1421 if (argc == 1) {
@@ -1609,7 +1437,7 @@ static int kvm_cmd_stat(const char *file_name, int argc, const char **argv)
1609perf_stat: 1437perf_stat:
1610 return cmd_stat(argc, argv, NULL); 1438 return cmd_stat(argc, argv, NULL);
1611} 1439}
1612#endif 1440#endif /* HAVE_KVM_STAT_SUPPORT */
1613 1441
1614static int __cmd_record(const char *file_name, int argc, const char **argv) 1442static int __cmd_record(const char *file_name, int argc, const char **argv)
1615{ 1443{
@@ -1726,7 +1554,7 @@ int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused)
1726 return cmd_top(argc, argv, NULL); 1554 return cmd_top(argc, argv, NULL);
1727 else if (!strncmp(argv[0], "buildid-list", 12)) 1555 else if (!strncmp(argv[0], "buildid-list", 12))
1728 return __cmd_buildid_list(file_name, argc, argv); 1556 return __cmd_buildid_list(file_name, argc, argv);
1729#if defined(__i386__) || defined(__x86_64__) 1557#ifdef HAVE_KVM_STAT_SUPPORT
1730 else if (!strncmp(argv[0], "stat", 4)) 1558 else if (!strncmp(argv[0], "stat", 4))
1731 return kvm_cmd_stat(file_name, argc, argv); 1559 return kvm_cmd_stat(file_name, argc, argv);
1732#endif 1560#endif
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 378b85b731a7..4869050e7194 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -238,6 +238,7 @@ static struct perf_event_header finished_round_event = {
238 238
239static int record__mmap_read_all(struct record *rec) 239static int record__mmap_read_all(struct record *rec)
240{ 240{
241 u64 bytes_written = rec->bytes_written;
241 int i; 242 int i;
242 int rc = 0; 243 int rc = 0;
243 244
@@ -250,7 +251,11 @@ static int record__mmap_read_all(struct record *rec)
250 } 251 }
251 } 252 }
252 253
253 if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA)) 254 /*
255 * Mark the round finished in case we wrote
256 * at least one event.
257 */
258 if (bytes_written != rec->bytes_written)
254 rc = record__write(rec, &finished_round_event, sizeof(finished_round_event)); 259 rc = record__write(rec, &finished_round_event, sizeof(finished_round_event));
255 260
256out: 261out:
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index c38d06c04775..f83c08c0dd87 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -10,6 +10,7 @@
10#include "util/header.h" 10#include "util/header.h"
11#include "util/session.h" 11#include "util/session.h"
12#include "util/tool.h" 12#include "util/tool.h"
13#include "util/cloexec.h"
13 14
14#include "util/parse-options.h" 15#include "util/parse-options.h"
15#include "util/trace-event.h" 16#include "util/trace-event.h"
@@ -434,7 +435,8 @@ static int self_open_counters(void)
434 attr.type = PERF_TYPE_SOFTWARE; 435 attr.type = PERF_TYPE_SOFTWARE;
435 attr.config = PERF_COUNT_SW_TASK_CLOCK; 436 attr.config = PERF_COUNT_SW_TASK_CLOCK;
436 437
437 fd = sys_perf_event_open(&attr, 0, -1, -1, 0); 438 fd = sys_perf_event_open(&attr, 0, -1, -1,
439 perf_event_open_cloexec_flag());
438 440
439 if (fd < 0) 441 if (fd < 0)
440 pr_err("Error: sys_perf_event_open() syscall returned " 442 pr_err("Error: sys_perf_event_open() syscall returned "
@@ -935,8 +937,8 @@ static int latency_switch_event(struct perf_sched *sched,
935 return -1; 937 return -1;
936 } 938 }
937 939
938 sched_out = machine__findnew_thread(machine, 0, prev_pid); 940 sched_out = machine__findnew_thread(machine, -1, prev_pid);
939 sched_in = machine__findnew_thread(machine, 0, next_pid); 941 sched_in = machine__findnew_thread(machine, -1, next_pid);
940 942
941 out_events = thread_atoms_search(&sched->atom_root, sched_out, &sched->cmp_pid); 943 out_events = thread_atoms_search(&sched->atom_root, sched_out, &sched->cmp_pid);
942 if (!out_events) { 944 if (!out_events) {
@@ -979,7 +981,7 @@ static int latency_runtime_event(struct perf_sched *sched,
979{ 981{
980 const u32 pid = perf_evsel__intval(evsel, sample, "pid"); 982 const u32 pid = perf_evsel__intval(evsel, sample, "pid");
981 const u64 runtime = perf_evsel__intval(evsel, sample, "runtime"); 983 const u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
982 struct thread *thread = machine__findnew_thread(machine, 0, pid); 984 struct thread *thread = machine__findnew_thread(machine, -1, pid);
983 struct work_atoms *atoms = thread_atoms_search(&sched->atom_root, thread, &sched->cmp_pid); 985 struct work_atoms *atoms = thread_atoms_search(&sched->atom_root, thread, &sched->cmp_pid);
984 u64 timestamp = sample->time; 986 u64 timestamp = sample->time;
985 int cpu = sample->cpu; 987 int cpu = sample->cpu;
@@ -1012,7 +1014,7 @@ static int latency_wakeup_event(struct perf_sched *sched,
1012 struct thread *wakee; 1014 struct thread *wakee;
1013 u64 timestamp = sample->time; 1015 u64 timestamp = sample->time;
1014 1016
1015 wakee = machine__findnew_thread(machine, 0, pid); 1017 wakee = machine__findnew_thread(machine, -1, pid);
1016 atoms = thread_atoms_search(&sched->atom_root, wakee, &sched->cmp_pid); 1018 atoms = thread_atoms_search(&sched->atom_root, wakee, &sched->cmp_pid);
1017 if (!atoms) { 1019 if (!atoms) {
1018 if (thread_atoms_insert(sched, wakee)) 1020 if (thread_atoms_insert(sched, wakee))
@@ -1072,7 +1074,7 @@ static int latency_migrate_task_event(struct perf_sched *sched,
1072 if (sched->profile_cpu == -1) 1074 if (sched->profile_cpu == -1)
1073 return 0; 1075 return 0;
1074 1076
1075 migrant = machine__findnew_thread(machine, 0, pid); 1077 migrant = machine__findnew_thread(machine, -1, pid);
1076 atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid); 1078 atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid);
1077 if (!atoms) { 1079 if (!atoms) {
1078 if (thread_atoms_insert(sched, migrant)) 1080 if (thread_atoms_insert(sched, migrant))
@@ -1290,7 +1292,7 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,
1290 return -1; 1292 return -1;
1291 } 1293 }
1292 1294
1293 sched_in = machine__findnew_thread(machine, 0, next_pid); 1295 sched_in = machine__findnew_thread(machine, -1, next_pid);
1294 1296
1295 sched->curr_thread[this_cpu] = sched_in; 1297 sched->curr_thread[this_cpu] = sched_in;
1296 1298
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 9e9c91f5b7fa..f57035b89c15 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -358,27 +358,6 @@ static void print_sample_start(struct perf_sample *sample,
358 } 358 }
359} 359}
360 360
361static bool is_bts_event(struct perf_event_attr *attr)
362{
363 return ((attr->type == PERF_TYPE_HARDWARE) &&
364 (attr->config & PERF_COUNT_HW_BRANCH_INSTRUCTIONS) &&
365 (attr->sample_period == 1));
366}
367
368static bool sample_addr_correlates_sym(struct perf_event_attr *attr)
369{
370 if ((attr->type == PERF_TYPE_SOFTWARE) &&
371 ((attr->config == PERF_COUNT_SW_PAGE_FAULTS) ||
372 (attr->config == PERF_COUNT_SW_PAGE_FAULTS_MIN) ||
373 (attr->config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)))
374 return true;
375
376 if (is_bts_event(attr))
377 return true;
378
379 return false;
380}
381
382static void print_sample_addr(union perf_event *event, 361static void print_sample_addr(union perf_event *event,
383 struct perf_sample *sample, 362 struct perf_sample *sample,
384 struct machine *machine, 363 struct machine *machine,
@@ -386,24 +365,13 @@ static void print_sample_addr(union perf_event *event,
386 struct perf_event_attr *attr) 365 struct perf_event_attr *attr)
387{ 366{
388 struct addr_location al; 367 struct addr_location al;
389 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
390 368
391 printf("%16" PRIx64, sample->addr); 369 printf("%16" PRIx64, sample->addr);
392 370
393 if (!sample_addr_correlates_sym(attr)) 371 if (!sample_addr_correlates_sym(attr))
394 return; 372 return;
395 373
396 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, 374 perf_event__preprocess_sample_addr(event, sample, machine, thread, &al);
397 sample->addr, &al);
398 if (!al.map)
399 thread__find_addr_map(thread, machine, cpumode, MAP__VARIABLE,
400 sample->addr, &al);
401
402 al.cpu = sample->cpu;
403 al.sym = NULL;
404
405 if (al.map)
406 al.sym = map__find_symbol(al.map, al.addr, NULL);
407 375
408 if (PRINT_FIELD(SYM)) { 376 if (PRINT_FIELD(SYM)) {
409 printf(" "); 377 printf(" ");
@@ -427,25 +395,35 @@ static void print_sample_bts(union perf_event *event,
427 struct addr_location *al) 395 struct addr_location *al)
428{ 396{
429 struct perf_event_attr *attr = &evsel->attr; 397 struct perf_event_attr *attr = &evsel->attr;
398 bool print_srcline_last = false;
430 399
431 /* print branch_from information */ 400 /* print branch_from information */
432 if (PRINT_FIELD(IP)) { 401 if (PRINT_FIELD(IP)) {
433 if (!symbol_conf.use_callchain) 402 unsigned int print_opts = output[attr->type].print_ip_opts;
434 printf(" "); 403
435 else 404 if (symbol_conf.use_callchain && sample->callchain) {
436 printf("\n"); 405 printf("\n");
437 perf_evsel__print_ip(evsel, sample, al, 406 } else {
438 output[attr->type].print_ip_opts, 407 printf(" ");
408 if (print_opts & PRINT_IP_OPT_SRCLINE) {
409 print_srcline_last = true;
410 print_opts &= ~PRINT_IP_OPT_SRCLINE;
411 }
412 }
413 perf_evsel__print_ip(evsel, sample, al, print_opts,
439 PERF_MAX_STACK_DEPTH); 414 PERF_MAX_STACK_DEPTH);
440 } 415 }
441 416
442 printf(" => ");
443
444 /* print branch_to information */ 417 /* print branch_to information */
445 if (PRINT_FIELD(ADDR) || 418 if (PRINT_FIELD(ADDR) ||
446 ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) && 419 ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) &&
447 !output[attr->type].user_set)) 420 !output[attr->type].user_set)) {
421 printf(" => ");
448 print_sample_addr(event, sample, al->machine, thread, attr); 422 print_sample_addr(event, sample, al->machine, thread, attr);
423 }
424
425 if (print_srcline_last)
426 map__fprintf_srcline(al->map, al->addr, "\n ", stdout);
449 427
450 printf("\n"); 428 printf("\n");
451} 429}
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 65a151e36067..3e80aa10cfd8 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -184,7 +184,7 @@ static void perf_evsel__reset_stat_priv(struct perf_evsel *evsel)
184static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel) 184static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel)
185{ 185{
186 evsel->priv = zalloc(sizeof(struct perf_stat)); 186 evsel->priv = zalloc(sizeof(struct perf_stat));
187 if (evsel == NULL) 187 if (evsel->priv == NULL)
188 return -ENOMEM; 188 return -ENOMEM;
189 perf_evsel__reset_stat_priv(evsel); 189 perf_evsel__reset_stat_priv(evsel);
190 return 0; 190 return 0;
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 74db2568b867..2f1a5220c090 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -37,6 +37,7 @@
37#include "util/svghelper.h" 37#include "util/svghelper.h"
38#include "util/tool.h" 38#include "util/tool.h"
39#include "util/data.h" 39#include "util/data.h"
40#include "util/debug.h"
40 41
41#define SUPPORT_OLD_POWER_EVENTS 1 42#define SUPPORT_OLD_POWER_EVENTS 1
42#define PWR_EVENT_EXIT -1 43#define PWR_EVENT_EXIT -1
@@ -60,10 +61,17 @@ struct timechart {
60 tasks_only, 61 tasks_only,
61 with_backtrace, 62 with_backtrace,
62 topology; 63 topology;
64 /* IO related settings */
65 u64 io_events;
66 bool io_only,
67 skip_eagain;
68 u64 min_time,
69 merge_dist;
63}; 70};
64 71
65struct per_pidcomm; 72struct per_pidcomm;
66struct cpu_sample; 73struct cpu_sample;
74struct io_sample;
67 75
68/* 76/*
69 * Datastructure layout: 77 * Datastructure layout:
@@ -84,6 +92,7 @@ struct per_pid {
84 u64 start_time; 92 u64 start_time;
85 u64 end_time; 93 u64 end_time;
86 u64 total_time; 94 u64 total_time;
95 u64 total_bytes;
87 int display; 96 int display;
88 97
89 struct per_pidcomm *all; 98 struct per_pidcomm *all;
@@ -97,6 +106,8 @@ struct per_pidcomm {
97 u64 start_time; 106 u64 start_time;
98 u64 end_time; 107 u64 end_time;
99 u64 total_time; 108 u64 total_time;
109 u64 max_bytes;
110 u64 total_bytes;
100 111
101 int Y; 112 int Y;
102 int display; 113 int display;
@@ -107,6 +118,7 @@ struct per_pidcomm {
107 char *comm; 118 char *comm;
108 119
109 struct cpu_sample *samples; 120 struct cpu_sample *samples;
121 struct io_sample *io_samples;
110}; 122};
111 123
112struct sample_wrapper { 124struct sample_wrapper {
@@ -131,6 +143,27 @@ struct cpu_sample {
131 const char *backtrace; 143 const char *backtrace;
132}; 144};
133 145
146enum {
147 IOTYPE_READ,
148 IOTYPE_WRITE,
149 IOTYPE_SYNC,
150 IOTYPE_TX,
151 IOTYPE_RX,
152 IOTYPE_POLL,
153};
154
155struct io_sample {
156 struct io_sample *next;
157
158 u64 start_time;
159 u64 end_time;
160 u64 bytes;
161 int type;
162 int fd;
163 int err;
164 int merges;
165};
166
134#define CSTATE 1 167#define CSTATE 1
135#define PSTATE 2 168#define PSTATE 2
136 169
@@ -213,7 +246,7 @@ static void pid_fork(struct timechart *tchart, int pid, int ppid, u64 timestamp)
213 pid_set_comm(tchart, pid, pp->current->comm); 246 pid_set_comm(tchart, pid, pp->current->comm);
214 247
215 p->start_time = timestamp; 248 p->start_time = timestamp;
216 if (p->current) { 249 if (p->current && !p->current->start_time) {
217 p->current->start_time = timestamp; 250 p->current->start_time = timestamp;
218 p->current->state_since = timestamp; 251 p->current->state_since = timestamp;
219 } 252 }
@@ -682,6 +715,249 @@ static void end_sample_processing(struct timechart *tchart)
682 } 715 }
683} 716}
684 717
718static int pid_begin_io_sample(struct timechart *tchart, int pid, int type,
719 u64 start, int fd)
720{
721 struct per_pid *p = find_create_pid(tchart, pid);
722 struct per_pidcomm *c = p->current;
723 struct io_sample *sample;
724 struct io_sample *prev;
725
726 if (!c) {
727 c = zalloc(sizeof(*c));
728 if (!c)
729 return -ENOMEM;
730 p->current = c;
731 c->next = p->all;
732 p->all = c;
733 }
734
735 prev = c->io_samples;
736
737 if (prev && prev->start_time && !prev->end_time) {
738 pr_warning("Skip invalid start event: "
739 "previous event already started!\n");
740
741 /* remove previous event that has been started,
742 * we are not sure we will ever get an end for it */
743 c->io_samples = prev->next;
744 free(prev);
745 return 0;
746 }
747
748 sample = zalloc(sizeof(*sample));
749 if (!sample)
750 return -ENOMEM;
751 sample->start_time = start;
752 sample->type = type;
753 sample->fd = fd;
754 sample->next = c->io_samples;
755 c->io_samples = sample;
756
757 if (c->start_time == 0 || c->start_time > start)
758 c->start_time = start;
759
760 return 0;
761}
762
763static int pid_end_io_sample(struct timechart *tchart, int pid, int type,
764 u64 end, long ret)
765{
766 struct per_pid *p = find_create_pid(tchart, pid);
767 struct per_pidcomm *c = p->current;
768 struct io_sample *sample, *prev;
769
770 if (!c) {
771 pr_warning("Invalid pidcomm!\n");
772 return -1;
773 }
774
775 sample = c->io_samples;
776
777 if (!sample) /* skip partially captured events */
778 return 0;
779
780 if (sample->end_time) {
781 pr_warning("Skip invalid end event: "
782 "previous event already ended!\n");
783 return 0;
784 }
785
786 if (sample->type != type) {
787 pr_warning("Skip invalid end event: invalid event type!\n");
788 return 0;
789 }
790
791 sample->end_time = end;
792 prev = sample->next;
793
794 /* we want to be able to see small and fast transfers, so make them
795 * at least min_time long, but don't overlap them */
796 if (sample->end_time - sample->start_time < tchart->min_time)
797 sample->end_time = sample->start_time + tchart->min_time;
798 if (prev && sample->start_time < prev->end_time) {
799 if (prev->err) /* try to make errors more visible */
800 sample->start_time = prev->end_time;
801 else
802 prev->end_time = sample->start_time;
803 }
804
805 if (ret < 0) {
806 sample->err = ret;
807 } else if (type == IOTYPE_READ || type == IOTYPE_WRITE ||
808 type == IOTYPE_TX || type == IOTYPE_RX) {
809
810 if ((u64)ret > c->max_bytes)
811 c->max_bytes = ret;
812
813 c->total_bytes += ret;
814 p->total_bytes += ret;
815 sample->bytes = ret;
816 }
817
818 /* merge two requests to make svg smaller and render-friendly */
819 if (prev &&
820 prev->type == sample->type &&
821 prev->err == sample->err &&
822 prev->fd == sample->fd &&
823 prev->end_time + tchart->merge_dist >= sample->start_time) {
824
825 sample->bytes += prev->bytes;
826 sample->merges += prev->merges + 1;
827
828 sample->start_time = prev->start_time;
829 sample->next = prev->next;
830 free(prev);
831
832 if (!sample->err && sample->bytes > c->max_bytes)
833 c->max_bytes = sample->bytes;
834 }
835
836 tchart->io_events++;
837
838 return 0;
839}
840
841static int
842process_enter_read(struct timechart *tchart,
843 struct perf_evsel *evsel,
844 struct perf_sample *sample)
845{
846 long fd = perf_evsel__intval(evsel, sample, "fd");
847 return pid_begin_io_sample(tchart, sample->tid, IOTYPE_READ,
848 sample->time, fd);
849}
850
851static int
852process_exit_read(struct timechart *tchart,
853 struct perf_evsel *evsel,
854 struct perf_sample *sample)
855{
856 long ret = perf_evsel__intval(evsel, sample, "ret");
857 return pid_end_io_sample(tchart, sample->tid, IOTYPE_READ,
858 sample->time, ret);
859}
860
861static int
862process_enter_write(struct timechart *tchart,
863 struct perf_evsel *evsel,
864 struct perf_sample *sample)
865{
866 long fd = perf_evsel__intval(evsel, sample, "fd");
867 return pid_begin_io_sample(tchart, sample->tid, IOTYPE_WRITE,
868 sample->time, fd);
869}
870
871static int
872process_exit_write(struct timechart *tchart,
873 struct perf_evsel *evsel,
874 struct perf_sample *sample)
875{
876 long ret = perf_evsel__intval(evsel, sample, "ret");
877 return pid_end_io_sample(tchart, sample->tid, IOTYPE_WRITE,
878 sample->time, ret);
879}
880
881static int
882process_enter_sync(struct timechart *tchart,
883 struct perf_evsel *evsel,
884 struct perf_sample *sample)
885{
886 long fd = perf_evsel__intval(evsel, sample, "fd");
887 return pid_begin_io_sample(tchart, sample->tid, IOTYPE_SYNC,
888 sample->time, fd);
889}
890
891static int
892process_exit_sync(struct timechart *tchart,
893 struct perf_evsel *evsel,
894 struct perf_sample *sample)
895{
896 long ret = perf_evsel__intval(evsel, sample, "ret");
897 return pid_end_io_sample(tchart, sample->tid, IOTYPE_SYNC,
898 sample->time, ret);
899}
900
901static int
902process_enter_tx(struct timechart *tchart,
903 struct perf_evsel *evsel,
904 struct perf_sample *sample)
905{
906 long fd = perf_evsel__intval(evsel, sample, "fd");
907 return pid_begin_io_sample(tchart, sample->tid, IOTYPE_TX,
908 sample->time, fd);
909}
910
911static int
912process_exit_tx(struct timechart *tchart,
913 struct perf_evsel *evsel,
914 struct perf_sample *sample)
915{
916 long ret = perf_evsel__intval(evsel, sample, "ret");
917 return pid_end_io_sample(tchart, sample->tid, IOTYPE_TX,
918 sample->time, ret);
919}
920
921static int
922process_enter_rx(struct timechart *tchart,
923 struct perf_evsel *evsel,
924 struct perf_sample *sample)
925{
926 long fd = perf_evsel__intval(evsel, sample, "fd");
927 return pid_begin_io_sample(tchart, sample->tid, IOTYPE_RX,
928 sample->time, fd);
929}
930
931static int
932process_exit_rx(struct timechart *tchart,
933 struct perf_evsel *evsel,
934 struct perf_sample *sample)
935{
936 long ret = perf_evsel__intval(evsel, sample, "ret");
937 return pid_end_io_sample(tchart, sample->tid, IOTYPE_RX,
938 sample->time, ret);
939}
940
941static int
942process_enter_poll(struct timechart *tchart,
943 struct perf_evsel *evsel,
944 struct perf_sample *sample)
945{
946 long fd = perf_evsel__intval(evsel, sample, "fd");
947 return pid_begin_io_sample(tchart, sample->tid, IOTYPE_POLL,
948 sample->time, fd);
949}
950
951static int
952process_exit_poll(struct timechart *tchart,
953 struct perf_evsel *evsel,
954 struct perf_sample *sample)
955{
956 long ret = perf_evsel__intval(evsel, sample, "ret");
957 return pid_end_io_sample(tchart, sample->tid, IOTYPE_POLL,
958 sample->time, ret);
959}
960
685/* 961/*
686 * Sort the pid datastructure 962 * Sort the pid datastructure
687 */ 963 */
@@ -852,6 +1128,121 @@ static void draw_cpu_usage(struct timechart *tchart)
852 } 1128 }
853} 1129}
854 1130
1131static void draw_io_bars(struct timechart *tchart)
1132{
1133 const char *suf;
1134 double bytes;
1135 char comm[256];
1136 struct per_pid *p;
1137 struct per_pidcomm *c;
1138 struct io_sample *sample;
1139 int Y = 1;
1140
1141 p = tchart->all_data;
1142 while (p) {
1143 c = p->all;
1144 while (c) {
1145 if (!c->display) {
1146 c->Y = 0;
1147 c = c->next;
1148 continue;
1149 }
1150
1151 svg_box(Y, c->start_time, c->end_time, "process3");
1152 sample = c->io_samples;
1153 for (sample = c->io_samples; sample; sample = sample->next) {
1154 double h = (double)sample->bytes / c->max_bytes;
1155
1156 if (tchart->skip_eagain &&
1157 sample->err == -EAGAIN)
1158 continue;
1159
1160 if (sample->err)
1161 h = 1;
1162
1163 if (sample->type == IOTYPE_SYNC)
1164 svg_fbox(Y,
1165 sample->start_time,
1166 sample->end_time,
1167 1,
1168 sample->err ? "error" : "sync",
1169 sample->fd,
1170 sample->err,
1171 sample->merges);
1172 else if (sample->type == IOTYPE_POLL)
1173 svg_fbox(Y,
1174 sample->start_time,
1175 sample->end_time,
1176 1,
1177 sample->err ? "error" : "poll",
1178 sample->fd,
1179 sample->err,
1180 sample->merges);
1181 else if (sample->type == IOTYPE_READ)
1182 svg_ubox(Y,
1183 sample->start_time,
1184 sample->end_time,
1185 h,
1186 sample->err ? "error" : "disk",
1187 sample->fd,
1188 sample->err,
1189 sample->merges);
1190 else if (sample->type == IOTYPE_WRITE)
1191 svg_lbox(Y,
1192 sample->start_time,
1193 sample->end_time,
1194 h,
1195 sample->err ? "error" : "disk",
1196 sample->fd,
1197 sample->err,
1198 sample->merges);
1199 else if (sample->type == IOTYPE_RX)
1200 svg_ubox(Y,
1201 sample->start_time,
1202 sample->end_time,
1203 h,
1204 sample->err ? "error" : "net",
1205 sample->fd,
1206 sample->err,
1207 sample->merges);
1208 else if (sample->type == IOTYPE_TX)
1209 svg_lbox(Y,
1210 sample->start_time,
1211 sample->end_time,
1212 h,
1213 sample->err ? "error" : "net",
1214 sample->fd,
1215 sample->err,
1216 sample->merges);
1217 }
1218
1219 suf = "";
1220 bytes = c->total_bytes;
1221 if (bytes > 1024) {
1222 bytes = bytes / 1024;
1223 suf = "K";
1224 }
1225 if (bytes > 1024) {
1226 bytes = bytes / 1024;
1227 suf = "M";
1228 }
1229 if (bytes > 1024) {
1230 bytes = bytes / 1024;
1231 suf = "G";
1232 }
1233
1234
1235 sprintf(comm, "%s:%i (%3.1f %sbytes)", c->comm ?: "", p->pid, bytes, suf);
1236 svg_text(Y, c->start_time, comm);
1237
1238 c->Y = Y;
1239 Y++;
1240 c = c->next;
1241 }
1242 p = p->next;
1243 }
1244}
1245
855static void draw_process_bars(struct timechart *tchart) 1246static void draw_process_bars(struct timechart *tchart)
856{ 1247{
857 struct per_pid *p; 1248 struct per_pid *p;
@@ -987,9 +1378,6 @@ static int determine_display_tasks(struct timechart *tchart, u64 threshold)
987 struct per_pidcomm *c; 1378 struct per_pidcomm *c;
988 int count = 0; 1379 int count = 0;
989 1380
990 if (process_filter)
991 return determine_display_tasks_filtered(tchart);
992
993 p = tchart->all_data; 1381 p = tchart->all_data;
994 while (p) { 1382 while (p) {
995 p->display = 0; 1383 p->display = 0;
@@ -1025,15 +1413,46 @@ static int determine_display_tasks(struct timechart *tchart, u64 threshold)
1025 return count; 1413 return count;
1026} 1414}
1027 1415
1416static int determine_display_io_tasks(struct timechart *timechart, u64 threshold)
1417{
1418 struct per_pid *p;
1419 struct per_pidcomm *c;
1420 int count = 0;
1421
1422 p = timechart->all_data;
1423 while (p) {
1424 /* no exit marker, task kept running to the end */
1425 if (p->end_time == 0)
1426 p->end_time = timechart->last_time;
1028 1427
1428 c = p->all;
1029 1429
1430 while (c) {
1431 c->display = 0;
1432
1433 if (c->total_bytes >= threshold) {
1434 c->display = 1;
1435 count++;
1436 }
1437
1438 if (c->end_time == 0)
1439 c->end_time = timechart->last_time;
1440
1441 c = c->next;
1442 }
1443 p = p->next;
1444 }
1445 return count;
1446}
1447
1448#define BYTES_THRESH (1 * 1024 * 1024)
1030#define TIME_THRESH 10000000 1449#define TIME_THRESH 10000000
1031 1450
1032static void write_svg_file(struct timechart *tchart, const char *filename) 1451static void write_svg_file(struct timechart *tchart, const char *filename)
1033{ 1452{
1034 u64 i; 1453 u64 i;
1035 int count; 1454 int count;
1036 int thresh = TIME_THRESH; 1455 int thresh = tchart->io_events ? BYTES_THRESH : TIME_THRESH;
1037 1456
1038 if (tchart->power_only) 1457 if (tchart->power_only)
1039 tchart->proc_num = 0; 1458 tchart->proc_num = 0;
@@ -1041,28 +1460,43 @@ static void write_svg_file(struct timechart *tchart, const char *filename)
1041 /* We'd like to show at least proc_num tasks; 1460 /* We'd like to show at least proc_num tasks;
1042 * be less picky if we have fewer */ 1461 * be less picky if we have fewer */
1043 do { 1462 do {
1044 count = determine_display_tasks(tchart, thresh); 1463 if (process_filter)
1464 count = determine_display_tasks_filtered(tchart);
1465 else if (tchart->io_events)
1466 count = determine_display_io_tasks(tchart, thresh);
1467 else
1468 count = determine_display_tasks(tchart, thresh);
1045 thresh /= 10; 1469 thresh /= 10;
1046 } while (!process_filter && thresh && count < tchart->proc_num); 1470 } while (!process_filter && thresh && count < tchart->proc_num);
1047 1471
1048 if (!tchart->proc_num) 1472 if (!tchart->proc_num)
1049 count = 0; 1473 count = 0;
1050 1474
1051 open_svg(filename, tchart->numcpus, count, tchart->first_time, tchart->last_time); 1475 if (tchart->io_events) {
1476 open_svg(filename, 0, count, tchart->first_time, tchart->last_time);
1052 1477
1053 svg_time_grid(); 1478 svg_time_grid(0.5);
1054 svg_legenda(); 1479 svg_io_legenda();
1480
1481 draw_io_bars(tchart);
1482 } else {
1483 open_svg(filename, tchart->numcpus, count, tchart->first_time, tchart->last_time);
1055 1484
1056 for (i = 0; i < tchart->numcpus; i++) 1485 svg_time_grid(0);
1057 svg_cpu_box(i, tchart->max_freq, tchart->turbo_frequency);
1058 1486
1059 draw_cpu_usage(tchart); 1487 svg_legenda();
1060 if (tchart->proc_num) 1488
1061 draw_process_bars(tchart); 1489 for (i = 0; i < tchart->numcpus; i++)
1062 if (!tchart->tasks_only) 1490 svg_cpu_box(i, tchart->max_freq, tchart->turbo_frequency);
1063 draw_c_p_states(tchart); 1491
1064 if (tchart->proc_num) 1492 draw_cpu_usage(tchart);
1065 draw_wakeups(tchart); 1493 if (tchart->proc_num)
1494 draw_process_bars(tchart);
1495 if (!tchart->tasks_only)
1496 draw_c_p_states(tchart);
1497 if (tchart->proc_num)
1498 draw_wakeups(tchart);
1499 }
1066 1500
1067 svg_close(); 1501 svg_close();
1068} 1502}
@@ -1110,6 +1544,56 @@ static int __cmd_timechart(struct timechart *tchart, const char *output_name)
1110 { "power:power_end", process_sample_power_end }, 1544 { "power:power_end", process_sample_power_end },
1111 { "power:power_frequency", process_sample_power_frequency }, 1545 { "power:power_frequency", process_sample_power_frequency },
1112#endif 1546#endif
1547
1548 { "syscalls:sys_enter_read", process_enter_read },
1549 { "syscalls:sys_enter_pread64", process_enter_read },
1550 { "syscalls:sys_enter_readv", process_enter_read },
1551 { "syscalls:sys_enter_preadv", process_enter_read },
1552 { "syscalls:sys_enter_write", process_enter_write },
1553 { "syscalls:sys_enter_pwrite64", process_enter_write },
1554 { "syscalls:sys_enter_writev", process_enter_write },
1555 { "syscalls:sys_enter_pwritev", process_enter_write },
1556 { "syscalls:sys_enter_sync", process_enter_sync },
1557 { "syscalls:sys_enter_sync_file_range", process_enter_sync },
1558 { "syscalls:sys_enter_fsync", process_enter_sync },
1559 { "syscalls:sys_enter_msync", process_enter_sync },
1560 { "syscalls:sys_enter_recvfrom", process_enter_rx },
1561 { "syscalls:sys_enter_recvmmsg", process_enter_rx },
1562 { "syscalls:sys_enter_recvmsg", process_enter_rx },
1563 { "syscalls:sys_enter_sendto", process_enter_tx },
1564 { "syscalls:sys_enter_sendmsg", process_enter_tx },
1565 { "syscalls:sys_enter_sendmmsg", process_enter_tx },
1566 { "syscalls:sys_enter_epoll_pwait", process_enter_poll },
1567 { "syscalls:sys_enter_epoll_wait", process_enter_poll },
1568 { "syscalls:sys_enter_poll", process_enter_poll },
1569 { "syscalls:sys_enter_ppoll", process_enter_poll },
1570 { "syscalls:sys_enter_pselect6", process_enter_poll },
1571 { "syscalls:sys_enter_select", process_enter_poll },
1572
1573 { "syscalls:sys_exit_read", process_exit_read },
1574 { "syscalls:sys_exit_pread64", process_exit_read },
1575 { "syscalls:sys_exit_readv", process_exit_read },
1576 { "syscalls:sys_exit_preadv", process_exit_read },
1577 { "syscalls:sys_exit_write", process_exit_write },
1578 { "syscalls:sys_exit_pwrite64", process_exit_write },
1579 { "syscalls:sys_exit_writev", process_exit_write },
1580 { "syscalls:sys_exit_pwritev", process_exit_write },
1581 { "syscalls:sys_exit_sync", process_exit_sync },
1582 { "syscalls:sys_exit_sync_file_range", process_exit_sync },
1583 { "syscalls:sys_exit_fsync", process_exit_sync },
1584 { "syscalls:sys_exit_msync", process_exit_sync },
1585 { "syscalls:sys_exit_recvfrom", process_exit_rx },
1586 { "syscalls:sys_exit_recvmmsg", process_exit_rx },
1587 { "syscalls:sys_exit_recvmsg", process_exit_rx },
1588 { "syscalls:sys_exit_sendto", process_exit_tx },
1589 { "syscalls:sys_exit_sendmsg", process_exit_tx },
1590 { "syscalls:sys_exit_sendmmsg", process_exit_tx },
1591 { "syscalls:sys_exit_epoll_pwait", process_exit_poll },
1592 { "syscalls:sys_exit_epoll_wait", process_exit_poll },
1593 { "syscalls:sys_exit_poll", process_exit_poll },
1594 { "syscalls:sys_exit_ppoll", process_exit_poll },
1595 { "syscalls:sys_exit_pselect6", process_exit_poll },
1596 { "syscalls:sys_exit_select", process_exit_poll },
1113 }; 1597 };
1114 struct perf_data_file file = { 1598 struct perf_data_file file = {
1115 .path = input_name, 1599 .path = input_name,
@@ -1154,6 +1638,139 @@ out_delete:
1154 return ret; 1638 return ret;
1155} 1639}
1156 1640
1641static int timechart__io_record(int argc, const char **argv)
1642{
1643 unsigned int rec_argc, i;
1644 const char **rec_argv;
1645 const char **p;
1646 char *filter = NULL;
1647
1648 const char * const common_args[] = {
1649 "record", "-a", "-R", "-c", "1",
1650 };
1651 unsigned int common_args_nr = ARRAY_SIZE(common_args);
1652
1653 const char * const disk_events[] = {
1654 "syscalls:sys_enter_read",
1655 "syscalls:sys_enter_pread64",
1656 "syscalls:sys_enter_readv",
1657 "syscalls:sys_enter_preadv",
1658 "syscalls:sys_enter_write",
1659 "syscalls:sys_enter_pwrite64",
1660 "syscalls:sys_enter_writev",
1661 "syscalls:sys_enter_pwritev",
1662 "syscalls:sys_enter_sync",
1663 "syscalls:sys_enter_sync_file_range",
1664 "syscalls:sys_enter_fsync",
1665 "syscalls:sys_enter_msync",
1666
1667 "syscalls:sys_exit_read",
1668 "syscalls:sys_exit_pread64",
1669 "syscalls:sys_exit_readv",
1670 "syscalls:sys_exit_preadv",
1671 "syscalls:sys_exit_write",
1672 "syscalls:sys_exit_pwrite64",
1673 "syscalls:sys_exit_writev",
1674 "syscalls:sys_exit_pwritev",
1675 "syscalls:sys_exit_sync",
1676 "syscalls:sys_exit_sync_file_range",
1677 "syscalls:sys_exit_fsync",
1678 "syscalls:sys_exit_msync",
1679 };
1680 unsigned int disk_events_nr = ARRAY_SIZE(disk_events);
1681
1682 const char * const net_events[] = {
1683 "syscalls:sys_enter_recvfrom",
1684 "syscalls:sys_enter_recvmmsg",
1685 "syscalls:sys_enter_recvmsg",
1686 "syscalls:sys_enter_sendto",
1687 "syscalls:sys_enter_sendmsg",
1688 "syscalls:sys_enter_sendmmsg",
1689
1690 "syscalls:sys_exit_recvfrom",
1691 "syscalls:sys_exit_recvmmsg",
1692 "syscalls:sys_exit_recvmsg",
1693 "syscalls:sys_exit_sendto",
1694 "syscalls:sys_exit_sendmsg",
1695 "syscalls:sys_exit_sendmmsg",
1696 };
1697 unsigned int net_events_nr = ARRAY_SIZE(net_events);
1698
1699 const char * const poll_events[] = {
1700 "syscalls:sys_enter_epoll_pwait",
1701 "syscalls:sys_enter_epoll_wait",
1702 "syscalls:sys_enter_poll",
1703 "syscalls:sys_enter_ppoll",
1704 "syscalls:sys_enter_pselect6",
1705 "syscalls:sys_enter_select",
1706
1707 "syscalls:sys_exit_epoll_pwait",
1708 "syscalls:sys_exit_epoll_wait",
1709 "syscalls:sys_exit_poll",
1710 "syscalls:sys_exit_ppoll",
1711 "syscalls:sys_exit_pselect6",
1712 "syscalls:sys_exit_select",
1713 };
1714 unsigned int poll_events_nr = ARRAY_SIZE(poll_events);
1715
1716 rec_argc = common_args_nr +
1717 disk_events_nr * 4 +
1718 net_events_nr * 4 +
1719 poll_events_nr * 4 +
1720 argc;
1721 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1722
1723 if (rec_argv == NULL)
1724 return -ENOMEM;
1725
1726 if (asprintf(&filter, "common_pid != %d", getpid()) < 0)
1727 return -ENOMEM;
1728
1729 p = rec_argv;
1730 for (i = 0; i < common_args_nr; i++)
1731 *p++ = strdup(common_args[i]);
1732
1733 for (i = 0; i < disk_events_nr; i++) {
1734 if (!is_valid_tracepoint(disk_events[i])) {
1735 rec_argc -= 4;
1736 continue;
1737 }
1738
1739 *p++ = "-e";
1740 *p++ = strdup(disk_events[i]);
1741 *p++ = "--filter";
1742 *p++ = filter;
1743 }
1744 for (i = 0; i < net_events_nr; i++) {
1745 if (!is_valid_tracepoint(net_events[i])) {
1746 rec_argc -= 4;
1747 continue;
1748 }
1749
1750 *p++ = "-e";
1751 *p++ = strdup(net_events[i]);
1752 *p++ = "--filter";
1753 *p++ = filter;
1754 }
1755 for (i = 0; i < poll_events_nr; i++) {
1756 if (!is_valid_tracepoint(poll_events[i])) {
1757 rec_argc -= 4;
1758 continue;
1759 }
1760
1761 *p++ = "-e";
1762 *p++ = strdup(poll_events[i]);
1763 *p++ = "--filter";
1764 *p++ = filter;
1765 }
1766
1767 for (i = 0; i < (unsigned int)argc; i++)
1768 *p++ = argv[i];
1769
1770 return cmd_record(rec_argc, rec_argv, NULL);
1771}
1772
1773
1157static int timechart__record(struct timechart *tchart, int argc, const char **argv) 1774static int timechart__record(struct timechart *tchart, int argc, const char **argv)
1158{ 1775{
1159 unsigned int rec_argc, i, j; 1776 unsigned int rec_argc, i, j;
@@ -1270,6 +1887,30 @@ parse_highlight(const struct option *opt __maybe_unused, const char *arg,
1270 return 0; 1887 return 0;
1271} 1888}
1272 1889
1890static int
1891parse_time(const struct option *opt, const char *arg, int __maybe_unused unset)
1892{
1893 char unit = 'n';
1894 u64 *value = opt->value;
1895
1896 if (sscanf(arg, "%" PRIu64 "%cs", value, &unit) > 0) {
1897 switch (unit) {
1898 case 'm':
1899 *value *= 1000000;
1900 break;
1901 case 'u':
1902 *value *= 1000;
1903 break;
1904 case 'n':
1905 break;
1906 default:
1907 return -1;
1908 }
1909 }
1910
1911 return 0;
1912}
1913
1273int cmd_timechart(int argc, const char **argv, 1914int cmd_timechart(int argc, const char **argv,
1274 const char *prefix __maybe_unused) 1915 const char *prefix __maybe_unused)
1275{ 1916{
@@ -1282,6 +1923,8 @@ int cmd_timechart(int argc, const char **argv,
1282 .ordered_samples = true, 1923 .ordered_samples = true,
1283 }, 1924 },
1284 .proc_num = 15, 1925 .proc_num = 15,
1926 .min_time = 1000000,
1927 .merge_dist = 1000,
1285 }; 1928 };
1286 const char *output_name = "output.svg"; 1929 const char *output_name = "output.svg";
1287 const struct option timechart_options[] = { 1930 const struct option timechart_options[] = {
@@ -1303,6 +1946,14 @@ int cmd_timechart(int argc, const char **argv,
1303 "min. number of tasks to print"), 1946 "min. number of tasks to print"),
1304 OPT_BOOLEAN('t', "topology", &tchart.topology, 1947 OPT_BOOLEAN('t', "topology", &tchart.topology,
1305 "sort CPUs according to topology"), 1948 "sort CPUs according to topology"),
1949 OPT_BOOLEAN(0, "io-skip-eagain", &tchart.skip_eagain,
1950 "skip EAGAIN errors"),
1951 OPT_CALLBACK(0, "io-min-time", &tchart.min_time, "time",
1952 "all IO faster than min-time will visually appear longer",
1953 parse_time),
1954 OPT_CALLBACK(0, "io-merge-dist", &tchart.merge_dist, "time",
1955 "merge events that are merge-dist us apart",
1956 parse_time),
1306 OPT_END() 1957 OPT_END()
1307 }; 1958 };
1308 const char * const timechart_usage[] = { 1959 const char * const timechart_usage[] = {
@@ -1314,6 +1965,8 @@ int cmd_timechart(int argc, const char **argv,
1314 OPT_BOOLEAN('P', "power-only", &tchart.power_only, "output power data only"), 1965 OPT_BOOLEAN('P', "power-only", &tchart.power_only, "output power data only"),
1315 OPT_BOOLEAN('T', "tasks-only", &tchart.tasks_only, 1966 OPT_BOOLEAN('T', "tasks-only", &tchart.tasks_only,
1316 "output processes data only"), 1967 "output processes data only"),
1968 OPT_BOOLEAN('I', "io-only", &tchart.io_only,
1969 "record only IO data"),
1317 OPT_BOOLEAN('g', "callchain", &tchart.with_backtrace, "record callchain"), 1970 OPT_BOOLEAN('g', "callchain", &tchart.with_backtrace, "record callchain"),
1318 OPT_END() 1971 OPT_END()
1319 }; 1972 };
@@ -1340,7 +1993,10 @@ int cmd_timechart(int argc, const char **argv,
1340 return -1; 1993 return -1;
1341 } 1994 }
1342 1995
1343 return timechart__record(&tchart, argc, argv); 1996 if (tchart.io_only)
1997 return timechart__io_record(argc, argv);
1998 else
1999 return timechart__record(&tchart, argc, argv);
1344 } else if (argc) 2000 } else if (argc)
1345 usage_with_options(timechart_usage, timechart_options); 2001 usage_with_options(timechart_usage, timechart_options);
1346 2002
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index f954c26de231..a6c375224f46 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -1108,6 +1108,7 @@ struct syscall {
1108 struct event_format *tp_format; 1108 struct event_format *tp_format;
1109 const char *name; 1109 const char *name;
1110 bool filtered; 1110 bool filtered;
1111 bool is_exit;
1111 struct syscall_fmt *fmt; 1112 struct syscall_fmt *fmt;
1112 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg); 1113 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
1113 void **arg_parm; 1114 void **arg_parm;
@@ -1132,6 +1133,7 @@ struct thread_trace {
1132 u64 exit_time; 1133 u64 exit_time;
1133 bool entry_pending; 1134 bool entry_pending;
1134 unsigned long nr_events; 1135 unsigned long nr_events;
1136 unsigned long pfmaj, pfmin;
1135 char *entry_str; 1137 char *entry_str;
1136 double runtime_ms; 1138 double runtime_ms;
1137 struct { 1139 struct {
@@ -1177,6 +1179,9 @@ fail:
1177 return NULL; 1179 return NULL;
1178} 1180}
1179 1181
1182#define TRACE_PFMAJ (1 << 0)
1183#define TRACE_PFMIN (1 << 1)
1184
1180struct trace { 1185struct trace {
1181 struct perf_tool tool; 1186 struct perf_tool tool;
1182 struct { 1187 struct {
@@ -1211,6 +1216,8 @@ struct trace {
1211 bool summary_only; 1216 bool summary_only;
1212 bool show_comm; 1217 bool show_comm;
1213 bool show_tool_stats; 1218 bool show_tool_stats;
1219 bool trace_syscalls;
1220 int trace_pgfaults;
1214}; 1221};
1215 1222
1216static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname) 1223static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
@@ -1276,11 +1283,11 @@ static const char *thread__fd_path(struct thread *thread, int fd,
1276 if (fd < 0) 1283 if (fd < 0)
1277 return NULL; 1284 return NULL;
1278 1285
1279 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) 1286 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
1280 if (!trace->live) 1287 if (!trace->live)
1281 return NULL; 1288 return NULL;
1282 ++trace->stats.proc_getname; 1289 ++trace->stats.proc_getname;
1283 if (thread__read_fd_path(thread, fd)) { 1290 if (thread__read_fd_path(thread, fd))
1284 return NULL; 1291 return NULL;
1285 } 1292 }
1286 1293
@@ -1473,6 +1480,8 @@ static int trace__read_syscall_info(struct trace *trace, int id)
1473 if (sc->tp_format == NULL) 1480 if (sc->tp_format == NULL)
1474 return -1; 1481 return -1;
1475 1482
1483 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1484
1476 return syscall__set_arg_fmts(sc); 1485 return syscall__set_arg_fmts(sc);
1477} 1486}
1478 1487
@@ -1535,6 +1544,7 @@ static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
1535} 1544}
1536 1545
1537typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel, 1546typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
1547 union perf_event *event,
1538 struct perf_sample *sample); 1548 struct perf_sample *sample);
1539 1549
1540static struct syscall *trace__syscall_info(struct trace *trace, 1550static struct syscall *trace__syscall_info(struct trace *trace,
@@ -1607,6 +1617,7 @@ static void thread__update_stats(struct thread_trace *ttrace,
1607} 1617}
1608 1618
1609static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel, 1619static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1620 union perf_event *event __maybe_unused,
1610 struct perf_sample *sample) 1621 struct perf_sample *sample)
1611{ 1622{
1612 char *msg; 1623 char *msg;
@@ -1629,7 +1640,6 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1629 return -1; 1640 return -1;
1630 1641
1631 args = perf_evsel__sc_tp_ptr(evsel, args, sample); 1642 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
1632 ttrace = thread->priv;
1633 1643
1634 if (ttrace->entry_str == NULL) { 1644 if (ttrace->entry_str == NULL) {
1635 ttrace->entry_str = malloc(1024); 1645 ttrace->entry_str = malloc(1024);
@@ -1644,7 +1654,7 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1644 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed, 1654 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed,
1645 args, trace, thread); 1655 args, trace, thread);
1646 1656
1647 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) { 1657 if (sc->is_exit) {
1648 if (!trace->duration_filter && !trace->summary_only) { 1658 if (!trace->duration_filter && !trace->summary_only) {
1649 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output); 1659 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1650 fprintf(trace->output, "%-70s\n", ttrace->entry_str); 1660 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
@@ -1656,6 +1666,7 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1656} 1666}
1657 1667
1658static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, 1668static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1669 union perf_event *event __maybe_unused,
1659 struct perf_sample *sample) 1670 struct perf_sample *sample)
1660{ 1671{
1661 int ret; 1672 int ret;
@@ -1687,8 +1698,6 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1687 ++trace->stats.vfs_getname; 1698 ++trace->stats.vfs_getname;
1688 } 1699 }
1689 1700
1690 ttrace = thread->priv;
1691
1692 ttrace->exit_time = sample->time; 1701 ttrace->exit_time = sample->time;
1693 1702
1694 if (ttrace->entry_time) { 1703 if (ttrace->entry_time) {
@@ -1735,6 +1744,7 @@ out:
1735} 1744}
1736 1745
1737static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel, 1746static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
1747 union perf_event *event __maybe_unused,
1738 struct perf_sample *sample) 1748 struct perf_sample *sample)
1739{ 1749{
1740 trace->last_vfs_getname = perf_evsel__rawptr(evsel, sample, "pathname"); 1750 trace->last_vfs_getname = perf_evsel__rawptr(evsel, sample, "pathname");
@@ -1742,6 +1752,7 @@ static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
1742} 1752}
1743 1753
1744static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel, 1754static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
1755 union perf_event *event __maybe_unused,
1745 struct perf_sample *sample) 1756 struct perf_sample *sample)
1746{ 1757{
1747 u64 runtime = perf_evsel__intval(evsel, sample, "runtime"); 1758 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
@@ -1768,6 +1779,80 @@ out_dump:
1768 return 0; 1779 return 0;
1769} 1780}
1770 1781
1782static void print_location(FILE *f, struct perf_sample *sample,
1783 struct addr_location *al,
1784 bool print_dso, bool print_sym)
1785{
1786
1787 if ((verbose || print_dso) && al->map)
1788 fprintf(f, "%s@", al->map->dso->long_name);
1789
1790 if ((verbose || print_sym) && al->sym)
1791 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
1792 al->addr - al->sym->start);
1793 else if (al->map)
1794 fprintf(f, "0x%" PRIx64, al->addr);
1795 else
1796 fprintf(f, "0x%" PRIx64, sample->addr);
1797}
1798
1799static int trace__pgfault(struct trace *trace,
1800 struct perf_evsel *evsel,
1801 union perf_event *event,
1802 struct perf_sample *sample)
1803{
1804 struct thread *thread;
1805 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
1806 struct addr_location al;
1807 char map_type = 'd';
1808 struct thread_trace *ttrace;
1809
1810 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1811 ttrace = thread__trace(thread, trace->output);
1812 if (ttrace == NULL)
1813 return -1;
1814
1815 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
1816 ttrace->pfmaj++;
1817 else
1818 ttrace->pfmin++;
1819
1820 if (trace->summary_only)
1821 return 0;
1822
1823 thread__find_addr_location(thread, trace->host, cpumode, MAP__FUNCTION,
1824 sample->ip, &al);
1825
1826 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
1827
1828 fprintf(trace->output, "%sfault [",
1829 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
1830 "maj" : "min");
1831
1832 print_location(trace->output, sample, &al, false, true);
1833
1834 fprintf(trace->output, "] => ");
1835
1836 thread__find_addr_location(thread, trace->host, cpumode, MAP__VARIABLE,
1837 sample->addr, &al);
1838
1839 if (!al.map) {
1840 thread__find_addr_location(thread, trace->host, cpumode,
1841 MAP__FUNCTION, sample->addr, &al);
1842
1843 if (al.map)
1844 map_type = 'x';
1845 else
1846 map_type = '?';
1847 }
1848
1849 print_location(trace->output, sample, &al, true, false);
1850
1851 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
1852
1853 return 0;
1854}
1855
1771static bool skip_sample(struct trace *trace, struct perf_sample *sample) 1856static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1772{ 1857{
1773 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) || 1858 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
@@ -1781,7 +1866,7 @@ static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1781} 1866}
1782 1867
1783static int trace__process_sample(struct perf_tool *tool, 1868static int trace__process_sample(struct perf_tool *tool,
1784 union perf_event *event __maybe_unused, 1869 union perf_event *event,
1785 struct perf_sample *sample, 1870 struct perf_sample *sample,
1786 struct perf_evsel *evsel, 1871 struct perf_evsel *evsel,
1787 struct machine *machine __maybe_unused) 1872 struct machine *machine __maybe_unused)
@@ -1799,7 +1884,7 @@ static int trace__process_sample(struct perf_tool *tool,
1799 1884
1800 if (handler) { 1885 if (handler) {
1801 ++trace->nr_events; 1886 ++trace->nr_events;
1802 handler(trace, evsel, sample); 1887 handler(trace, evsel, event, sample);
1803 } 1888 }
1804 1889
1805 return err; 1890 return err;
@@ -1826,7 +1911,7 @@ static int parse_target_str(struct trace *trace)
1826 return 0; 1911 return 0;
1827} 1912}
1828 1913
1829static int trace__record(int argc, const char **argv) 1914static int trace__record(struct trace *trace, int argc, const char **argv)
1830{ 1915{
1831 unsigned int rec_argc, i, j; 1916 unsigned int rec_argc, i, j;
1832 const char **rec_argv; 1917 const char **rec_argv;
@@ -1835,34 +1920,54 @@ static int trace__record(int argc, const char **argv)
1835 "-R", 1920 "-R",
1836 "-m", "1024", 1921 "-m", "1024",
1837 "-c", "1", 1922 "-c", "1",
1838 "-e",
1839 }; 1923 };
1840 1924
1925 const char * const sc_args[] = { "-e", };
1926 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
1927 const char * const majpf_args[] = { "-e", "major-faults" };
1928 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
1929 const char * const minpf_args[] = { "-e", "minor-faults" };
1930 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
1931
1841 /* +1 is for the event string below */ 1932 /* +1 is for the event string below */
1842 rec_argc = ARRAY_SIZE(record_args) + 1 + argc; 1933 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
1934 majpf_args_nr + minpf_args_nr + argc;
1843 rec_argv = calloc(rec_argc + 1, sizeof(char *)); 1935 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1844 1936
1845 if (rec_argv == NULL) 1937 if (rec_argv == NULL)
1846 return -ENOMEM; 1938 return -ENOMEM;
1847 1939
1940 j = 0;
1848 for (i = 0; i < ARRAY_SIZE(record_args); i++) 1941 for (i = 0; i < ARRAY_SIZE(record_args); i++)
1849 rec_argv[i] = record_args[i]; 1942 rec_argv[j++] = record_args[i];
1850 1943
1851 /* event string may be different for older kernels - e.g., RHEL6 */ 1944 if (trace->trace_syscalls) {
1852 if (is_valid_tracepoint("raw_syscalls:sys_enter")) 1945 for (i = 0; i < sc_args_nr; i++)
1853 rec_argv[i] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit"; 1946 rec_argv[j++] = sc_args[i];
1854 else if (is_valid_tracepoint("syscalls:sys_enter")) 1947
1855 rec_argv[i] = "syscalls:sys_enter,syscalls:sys_exit"; 1948 /* event string may be different for older kernels - e.g., RHEL6 */
1856 else { 1949 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
1857 pr_err("Neither raw_syscalls nor syscalls events exist.\n"); 1950 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
1858 return -1; 1951 else if (is_valid_tracepoint("syscalls:sys_enter"))
1952 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
1953 else {
1954 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
1955 return -1;
1956 }
1859 } 1957 }
1860 i++;
1861 1958
1862 for (j = 0; j < (unsigned int)argc; j++, i++) 1959 if (trace->trace_pgfaults & TRACE_PFMAJ)
1863 rec_argv[i] = argv[j]; 1960 for (i = 0; i < majpf_args_nr; i++)
1961 rec_argv[j++] = majpf_args[i];
1962
1963 if (trace->trace_pgfaults & TRACE_PFMIN)
1964 for (i = 0; i < minpf_args_nr; i++)
1965 rec_argv[j++] = minpf_args[i];
1966
1967 for (i = 0; i < (unsigned int)argc; i++)
1968 rec_argv[j++] = argv[i];
1864 1969
1865 return cmd_record(i, rec_argv, NULL); 1970 return cmd_record(j, rec_argv, NULL);
1866} 1971}
1867 1972
1868static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp); 1973static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
@@ -1882,6 +1987,30 @@ static void perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
1882 perf_evlist__add(evlist, evsel); 1987 perf_evlist__add(evlist, evsel);
1883} 1988}
1884 1989
1990static int perf_evlist__add_pgfault(struct perf_evlist *evlist,
1991 u64 config)
1992{
1993 struct perf_evsel *evsel;
1994 struct perf_event_attr attr = {
1995 .type = PERF_TYPE_SOFTWARE,
1996 .mmap_data = 1,
1997 };
1998
1999 attr.config = config;
2000 attr.sample_period = 1;
2001
2002 event_attr_init(&attr);
2003
2004 evsel = perf_evsel__new(&attr);
2005 if (!evsel)
2006 return -ENOMEM;
2007
2008 evsel->handler = trace__pgfault;
2009 perf_evlist__add(evlist, evsel);
2010
2011 return 0;
2012}
2013
1885static int trace__run(struct trace *trace, int argc, const char **argv) 2014static int trace__run(struct trace *trace, int argc, const char **argv)
1886{ 2015{
1887 struct perf_evlist *evlist = perf_evlist__new(); 2016 struct perf_evlist *evlist = perf_evlist__new();
@@ -1897,10 +2026,21 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
1897 goto out; 2026 goto out;
1898 } 2027 }
1899 2028
1900 if (perf_evlist__add_syscall_newtp(evlist, trace__sys_enter, trace__sys_exit)) 2029 if (trace->trace_syscalls &&
2030 perf_evlist__add_syscall_newtp(evlist, trace__sys_enter,
2031 trace__sys_exit))
1901 goto out_error_tp; 2032 goto out_error_tp;
1902 2033
1903 perf_evlist__add_vfs_getname(evlist); 2034 if (trace->trace_syscalls)
2035 perf_evlist__add_vfs_getname(evlist);
2036
2037 if ((trace->trace_pgfaults & TRACE_PFMAJ) &&
2038 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ))
2039 goto out_error_tp;
2040
2041 if ((trace->trace_pgfaults & TRACE_PFMIN) &&
2042 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN))
2043 goto out_error_tp;
1904 2044
1905 if (trace->sched && 2045 if (trace->sched &&
1906 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime", 2046 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
@@ -1982,7 +2122,8 @@ again:
1982 goto next_event; 2122 goto next_event;
1983 } 2123 }
1984 2124
1985 if (sample.raw_data == NULL) { 2125 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2126 sample.raw_data == NULL) {
1986 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n", 2127 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
1987 perf_evsel__name(evsel), sample.tid, 2128 perf_evsel__name(evsel), sample.tid,
1988 sample.cpu, sample.raw_size); 2129 sample.cpu, sample.raw_size);
@@ -1990,7 +2131,7 @@ again:
1990 } 2131 }
1991 2132
1992 handler = evsel->handler; 2133 handler = evsel->handler;
1993 handler(trace, evsel, &sample); 2134 handler(trace, evsel, event, &sample);
1994next_event: 2135next_event:
1995 perf_evlist__mmap_consume(evlist, i); 2136 perf_evlist__mmap_consume(evlist, i);
1996 2137
@@ -2093,13 +2234,10 @@ static int trace__replay(struct trace *trace)
2093 if (evsel == NULL) 2234 if (evsel == NULL)
2094 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, 2235 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2095 "syscalls:sys_enter"); 2236 "syscalls:sys_enter");
2096 if (evsel == NULL) {
2097 pr_err("Data file does not have raw_syscalls:sys_enter event\n");
2098 goto out;
2099 }
2100 2237
2101 if (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 || 2238 if (evsel &&
2102 perf_evsel__init_sc_tp_ptr_field(evsel, args)) { 2239 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2240 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
2103 pr_err("Error during initialize raw_syscalls:sys_enter event\n"); 2241 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2104 goto out; 2242 goto out;
2105 } 2243 }
@@ -2109,15 +2247,19 @@ static int trace__replay(struct trace *trace)
2109 if (evsel == NULL) 2247 if (evsel == NULL)
2110 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, 2248 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2111 "syscalls:sys_exit"); 2249 "syscalls:sys_exit");
2112 if (evsel == NULL) { 2250 if (evsel &&
2113 pr_err("Data file does not have raw_syscalls:sys_exit event\n"); 2251 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2252 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
2253 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
2114 goto out; 2254 goto out;
2115 } 2255 }
2116 2256
2117 if (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 || 2257 evlist__for_each(session->evlist, evsel) {
2118 perf_evsel__init_sc_tp_uint_field(evsel, ret)) { 2258 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2119 pr_err("Error during initialize raw_syscalls:sys_exit event\n"); 2259 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2120 goto out; 2260 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2261 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2262 evsel->handler = trace__pgfault;
2121 } 2263 }
2122 2264
2123 err = parse_target_str(trace); 2265 err = parse_target_str(trace);
@@ -2217,6 +2359,10 @@ static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2217 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid); 2359 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
2218 printed += fprintf(fp, "%lu events, ", ttrace->nr_events); 2360 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
2219 printed += fprintf(fp, "%.1f%%", ratio); 2361 printed += fprintf(fp, "%.1f%%", ratio);
2362 if (ttrace->pfmaj)
2363 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2364 if (ttrace->pfmin)
2365 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
2220 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms); 2366 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2221 printed += thread__dump_stats(ttrace, trace, fp); 2367 printed += thread__dump_stats(ttrace, trace, fp);
2222 2368
@@ -2264,6 +2410,23 @@ static int trace__open_output(struct trace *trace, const char *filename)
2264 return trace->output == NULL ? -errno : 0; 2410 return trace->output == NULL ? -errno : 0;
2265} 2411}
2266 2412
2413static int parse_pagefaults(const struct option *opt, const char *str,
2414 int unset __maybe_unused)
2415{
2416 int *trace_pgfaults = opt->value;
2417
2418 if (strcmp(str, "all") == 0)
2419 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2420 else if (strcmp(str, "maj") == 0)
2421 *trace_pgfaults |= TRACE_PFMAJ;
2422 else if (strcmp(str, "min") == 0)
2423 *trace_pgfaults |= TRACE_PFMIN;
2424 else
2425 return -1;
2426
2427 return 0;
2428}
2429
2267int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) 2430int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2268{ 2431{
2269 const char * const trace_usage[] = { 2432 const char * const trace_usage[] = {
@@ -2293,6 +2456,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2293 }, 2456 },
2294 .output = stdout, 2457 .output = stdout,
2295 .show_comm = true, 2458 .show_comm = true,
2459 .trace_syscalls = true,
2296 }; 2460 };
2297 const char *output_name = NULL; 2461 const char *output_name = NULL;
2298 const char *ev_qualifier_str = NULL; 2462 const char *ev_qualifier_str = NULL;
@@ -2330,20 +2494,34 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2330 "Show only syscall summary with statistics"), 2494 "Show only syscall summary with statistics"),
2331 OPT_BOOLEAN('S', "with-summary", &trace.summary, 2495 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2332 "Show all syscalls and summary with statistics"), 2496 "Show all syscalls and summary with statistics"),
2497 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
2498 "Trace pagefaults", parse_pagefaults, "maj"),
2499 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
2333 OPT_END() 2500 OPT_END()
2334 }; 2501 };
2335 int err; 2502 int err;
2336 char bf[BUFSIZ]; 2503 char bf[BUFSIZ];
2337 2504
2338 if ((argc > 1) && (strcmp(argv[1], "record") == 0)) 2505 argc = parse_options(argc, argv, trace_options, trace_usage,
2339 return trace__record(argc-2, &argv[2]); 2506 PARSE_OPT_STOP_AT_NON_OPTION);
2340 2507
2341 argc = parse_options(argc, argv, trace_options, trace_usage, 0); 2508 if (trace.trace_pgfaults) {
2509 trace.opts.sample_address = true;
2510 trace.opts.sample_time = true;
2511 }
2512
2513 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
2514 return trace__record(&trace, argc-1, &argv[1]);
2342 2515
2343 /* summary_only implies summary option, but don't overwrite summary if set */ 2516 /* summary_only implies summary option, but don't overwrite summary if set */
2344 if (trace.summary_only) 2517 if (trace.summary_only)
2345 trace.summary = trace.summary_only; 2518 trace.summary = trace.summary_only;
2346 2519
2520 if (!trace.trace_syscalls && !trace.trace_pgfaults) {
2521 pr_err("Please specify something to trace.\n");
2522 return -1;
2523 }
2524
2347 if (output_name != NULL) { 2525 if (output_name != NULL) {
2348 err = trace__open_output(&trace, output_name); 2526 err = trace__open_output(&trace, output_name);
2349 if (err < 0) { 2527 if (err < 0) {
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index f30ac5e5d271..1f67aa02d240 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -48,6 +48,10 @@ ifneq ($(ARCH),$(filter $(ARCH),x86 arm))
48 NO_LIBDW_DWARF_UNWIND := 1 48 NO_LIBDW_DWARF_UNWIND := 1
49endif 49endif
50 50
51ifeq ($(ARCH),powerpc)
52 CFLAGS += -DHAVE_SKIP_CALLCHAIN_IDX
53endif
54
51ifeq ($(LIBUNWIND_LIBS),) 55ifeq ($(LIBUNWIND_LIBS),)
52 NO_LIBUNWIND := 1 56 NO_LIBUNWIND := 1
53else 57else
@@ -160,6 +164,7 @@ CORE_FEATURE_TESTS = \
160 backtrace \ 164 backtrace \
161 dwarf \ 165 dwarf \
162 fortify-source \ 166 fortify-source \
167 sync-compare-and-swap \
163 glibc \ 168 glibc \
164 gtk2 \ 169 gtk2 \
165 gtk2-infobar \ 170 gtk2-infobar \
@@ -195,6 +200,7 @@ LIB_FEATURE_TESTS = \
195VF_FEATURE_TESTS = \ 200VF_FEATURE_TESTS = \
196 backtrace \ 201 backtrace \
197 fortify-source \ 202 fortify-source \
203 sync-compare-and-swap \
198 gtk2-infobar \ 204 gtk2-infobar \
199 libelf-getphdrnum \ 205 libelf-getphdrnum \
200 libelf-mmap \ 206 libelf-mmap \
@@ -268,6 +274,10 @@ CFLAGS += -I$(LIB_INCLUDE)
268 274
269CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE 275CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
270 276
277ifeq ($(feature-sync-compare-and-swap), 1)
278 CFLAGS += -DHAVE_SYNC_COMPARE_AND_SWAP_SUPPORT
279endif
280
271ifndef NO_BIONIC 281ifndef NO_BIONIC
272 $(call feature_check,bionic) 282 $(call feature_check,bionic)
273 ifeq ($(feature-bionic), 1) 283 ifeq ($(feature-bionic), 1)
@@ -590,6 +600,10 @@ ifndef NO_LIBNUMA
590 endif 600 endif
591endif 601endif
592 602
603ifdef HAVE_KVM_STAT_SUPPORT
604 CFLAGS += -DHAVE_KVM_STAT_SUPPORT
605endif
606
593# Among the variables below, these: 607# Among the variables below, these:
594# perfexecdir 608# perfexecdir
595# template_dir 609# template_dir
diff --git a/tools/perf/config/feature-checks/Makefile b/tools/perf/config/feature-checks/Makefile
index 64c84e5f0514..6088f8d8a434 100644
--- a/tools/perf/config/feature-checks/Makefile
+++ b/tools/perf/config/feature-checks/Makefile
@@ -5,6 +5,7 @@ FILES= \
5 test-bionic.bin \ 5 test-bionic.bin \
6 test-dwarf.bin \ 6 test-dwarf.bin \
7 test-fortify-source.bin \ 7 test-fortify-source.bin \
8 test-sync-compare-and-swap.bin \
8 test-glibc.bin \ 9 test-glibc.bin \
9 test-gtk2.bin \ 10 test-gtk2.bin \
10 test-gtk2-infobar.bin \ 11 test-gtk2-infobar.bin \
@@ -141,6 +142,9 @@ test-timerfd.bin:
141test-libdw-dwarf-unwind.bin: 142test-libdw-dwarf-unwind.bin:
142 $(BUILD) 143 $(BUILD)
143 144
145test-sync-compare-and-swap.bin:
146 $(BUILD) -Werror
147
144-include *.d 148-include *.d
145 149
146############################### 150###############################
diff --git a/tools/perf/config/feature-checks/test-all.c b/tools/perf/config/feature-checks/test-all.c
index fe5c1e5c952f..a7d022e161c0 100644
--- a/tools/perf/config/feature-checks/test-all.c
+++ b/tools/perf/config/feature-checks/test-all.c
@@ -89,6 +89,10 @@
89# include "test-libdw-dwarf-unwind.c" 89# include "test-libdw-dwarf-unwind.c"
90#undef main 90#undef main
91 91
92#define main main_test_sync_compare_and_swap
93# include "test-sync-compare-and-swap.c"
94#undef main
95
92int main(int argc, char *argv[]) 96int main(int argc, char *argv[])
93{ 97{
94 main_test_libpython(); 98 main_test_libpython();
@@ -111,6 +115,7 @@ int main(int argc, char *argv[])
111 main_test_timerfd(); 115 main_test_timerfd();
112 main_test_stackprotector_all(); 116 main_test_stackprotector_all();
113 main_test_libdw_dwarf_unwind(); 117 main_test_libdw_dwarf_unwind();
118 main_test_sync_compare_and_swap(argc, argv);
114 119
115 return 0; 120 return 0;
116} 121}
diff --git a/tools/perf/config/feature-checks/test-sync-compare-and-swap.c b/tools/perf/config/feature-checks/test-sync-compare-and-swap.c
new file mode 100644
index 000000000000..c34d4ca4af56
--- /dev/null
+++ b/tools/perf/config/feature-checks/test-sync-compare-and-swap.c
@@ -0,0 +1,14 @@
1#include <stdint.h>
2
3volatile uint64_t x;
4
5int main(int argc, char *argv[])
6{
7 uint64_t old, new = argc;
8
9 argv = argv;
10 do {
11 old = __sync_val_compare_and_swap(&x, 0, 0);
12 } while (!__sync_bool_compare_and_swap(&x, old, new));
13 return old == new;
14}
diff --git a/tools/perf/perf-sys.h b/tools/perf/perf-sys.h
index 5268a1481d23..937e4324ad94 100644
--- a/tools/perf/perf-sys.h
+++ b/tools/perf/perf-sys.h
@@ -54,6 +54,7 @@
54#define mb() asm volatile("bcr 15,0" ::: "memory") 54#define mb() asm volatile("bcr 15,0" ::: "memory")
55#define wmb() asm volatile("bcr 15,0" ::: "memory") 55#define wmb() asm volatile("bcr 15,0" ::: "memory")
56#define rmb() asm volatile("bcr 15,0" ::: "memory") 56#define rmb() asm volatile("bcr 15,0" ::: "memory")
57#define CPUINFO_PROC "vendor_id"
57#endif 58#endif
58 59
59#ifdef __sh__ 60#ifdef __sh__
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 95c58fc15284..2282d41879a2 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -13,11 +13,12 @@
13#include "util/quote.h" 13#include "util/quote.h"
14#include "util/run-command.h" 14#include "util/run-command.h"
15#include "util/parse-events.h" 15#include "util/parse-events.h"
16#include "util/debug.h"
16#include <api/fs/debugfs.h> 17#include <api/fs/debugfs.h>
17#include <pthread.h> 18#include <pthread.h>
18 19
19const char perf_usage_string[] = 20const char perf_usage_string[] =
20 "perf [--version] [--help] COMMAND [ARGS]"; 21 "perf [--version] [--help] [OPTIONS] COMMAND [ARGS]";
21 22
22const char perf_more_info_string[] = 23const char perf_more_info_string[] =
23 "See 'perf help COMMAND' for more information on a specific command."; 24 "See 'perf help COMMAND' for more information on a specific command.";
@@ -212,6 +213,16 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
212 printf("%s ", p->cmd); 213 printf("%s ", p->cmd);
213 } 214 }
214 exit(0); 215 exit(0);
216 } else if (!strcmp(cmd, "--debug")) {
217 if (*argc < 2) {
218 fprintf(stderr, "No variable specified for --debug.\n");
219 usage(perf_usage_string);
220 }
221 if (perf_debug_option((*argv)[1]))
222 usage(perf_usage_string);
223
224 (*argv)++;
225 (*argc)--;
215 } else { 226 } else {
216 fprintf(stderr, "Unknown option: %s\n", cmd); 227 fprintf(stderr, "Unknown option: %s\n", cmd);
217 usage(perf_usage_string); 228 usage(perf_usage_string);
diff --git a/tools/perf/scripts/perl/bin/failed-syscalls-record b/tools/perf/scripts/perl/bin/failed-syscalls-record
index 8104895a7b67..74685f318379 100644
--- a/tools/perf/scripts/perl/bin/failed-syscalls-record
+++ b/tools/perf/scripts/perl/bin/failed-syscalls-record
@@ -1,2 +1,3 @@
1#!/bin/bash 1#!/bin/bash
2perf record -e raw_syscalls:sys_exit $@ 2(perf record -e raw_syscalls:sys_exit $@ || \
3 perf record -e syscalls:sys_exit $@) 2> /dev/null
diff --git a/tools/perf/scripts/perl/failed-syscalls.pl b/tools/perf/scripts/perl/failed-syscalls.pl
index 94bc25a347eb..55e7ae4c5c88 100644
--- a/tools/perf/scripts/perl/failed-syscalls.pl
+++ b/tools/perf/scripts/perl/failed-syscalls.pl
@@ -26,6 +26,11 @@ sub raw_syscalls::sys_exit
26 } 26 }
27} 27}
28 28
29sub syscalls::sys_exit
30{
31 raw_syscalls::sys_exit(@_)
32}
33
29sub trace_end 34sub trace_end
30{ 35{
31 printf("\nfailed syscalls by comm:\n\n"); 36 printf("\nfailed syscalls by comm:\n\n");
diff --git a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py
index de7211e4fa47..38dfb720fb6f 100644
--- a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py
+++ b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py
@@ -107,12 +107,13 @@ def taskState(state):
107 107
108class EventHeaders: 108class EventHeaders:
109 def __init__(self, common_cpu, common_secs, common_nsecs, 109 def __init__(self, common_cpu, common_secs, common_nsecs,
110 common_pid, common_comm): 110 common_pid, common_comm, common_callchain):
111 self.cpu = common_cpu 111 self.cpu = common_cpu
112 self.secs = common_secs 112 self.secs = common_secs
113 self.nsecs = common_nsecs 113 self.nsecs = common_nsecs
114 self.pid = common_pid 114 self.pid = common_pid
115 self.comm = common_comm 115 self.comm = common_comm
116 self.callchain = common_callchain
116 117
117 def ts(self): 118 def ts(self):
118 return (self.secs * (10 ** 9)) + self.nsecs 119 return (self.secs * (10 ** 9)) + self.nsecs
diff --git a/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record b/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record
index 8104895a7b67..74685f318379 100644
--- a/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record
+++ b/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record
@@ -1,2 +1,3 @@
1#!/bin/bash 1#!/bin/bash
2perf record -e raw_syscalls:sys_exit $@ 2(perf record -e raw_syscalls:sys_exit $@ || \
3 perf record -e syscalls:sys_exit $@) 2> /dev/null
diff --git a/tools/perf/scripts/python/bin/sctop-record b/tools/perf/scripts/python/bin/sctop-record
index 4efbfaa7f6a5..d6940841e54f 100644
--- a/tools/perf/scripts/python/bin/sctop-record
+++ b/tools/perf/scripts/python/bin/sctop-record
@@ -1,2 +1,3 @@
1#!/bin/bash 1#!/bin/bash
2perf record -e raw_syscalls:sys_enter $@ 2(perf record -e raw_syscalls:sys_enter $@ || \
3 perf record -e syscalls:sys_enter $@) 2> /dev/null
diff --git a/tools/perf/scripts/python/bin/syscall-counts-by-pid-record b/tools/perf/scripts/python/bin/syscall-counts-by-pid-record
index 4efbfaa7f6a5..d6940841e54f 100644
--- a/tools/perf/scripts/python/bin/syscall-counts-by-pid-record
+++ b/tools/perf/scripts/python/bin/syscall-counts-by-pid-record
@@ -1,2 +1,3 @@
1#!/bin/bash 1#!/bin/bash
2perf record -e raw_syscalls:sys_enter $@ 2(perf record -e raw_syscalls:sys_enter $@ || \
3 perf record -e syscalls:sys_enter $@) 2> /dev/null
diff --git a/tools/perf/scripts/python/bin/syscall-counts-record b/tools/perf/scripts/python/bin/syscall-counts-record
index 4efbfaa7f6a5..d6940841e54f 100644
--- a/tools/perf/scripts/python/bin/syscall-counts-record
+++ b/tools/perf/scripts/python/bin/syscall-counts-record
@@ -1,2 +1,3 @@
1#!/bin/bash 1#!/bin/bash
2perf record -e raw_syscalls:sys_enter $@ 2(perf record -e raw_syscalls:sys_enter $@ || \
3 perf record -e syscalls:sys_enter $@) 2> /dev/null
diff --git a/tools/perf/scripts/python/check-perf-trace.py b/tools/perf/scripts/python/check-perf-trace.py
index 4647a7694cf6..334599c6032c 100644
--- a/tools/perf/scripts/python/check-perf-trace.py
+++ b/tools/perf/scripts/python/check-perf-trace.py
@@ -27,7 +27,7 @@ def trace_end():
27 27
28def irq__softirq_entry(event_name, context, common_cpu, 28def irq__softirq_entry(event_name, context, common_cpu,
29 common_secs, common_nsecs, common_pid, common_comm, 29 common_secs, common_nsecs, common_pid, common_comm,
30 vec): 30 common_callchain, vec):
31 print_header(event_name, common_cpu, common_secs, common_nsecs, 31 print_header(event_name, common_cpu, common_secs, common_nsecs,
32 common_pid, common_comm) 32 common_pid, common_comm)
33 33
@@ -38,7 +38,7 @@ def irq__softirq_entry(event_name, context, common_cpu,
38 38
39def kmem__kmalloc(event_name, context, common_cpu, 39def kmem__kmalloc(event_name, context, common_cpu,
40 common_secs, common_nsecs, common_pid, common_comm, 40 common_secs, common_nsecs, common_pid, common_comm,
41 call_site, ptr, bytes_req, bytes_alloc, 41 common_callchain, call_site, ptr, bytes_req, bytes_alloc,
42 gfp_flags): 42 gfp_flags):
43 print_header(event_name, common_cpu, common_secs, common_nsecs, 43 print_header(event_name, common_cpu, common_secs, common_nsecs,
44 common_pid, common_comm) 44 common_pid, common_comm)
diff --git a/tools/perf/scripts/python/failed-syscalls-by-pid.py b/tools/perf/scripts/python/failed-syscalls-by-pid.py
index 85805fac4116..cafeff3d74db 100644
--- a/tools/perf/scripts/python/failed-syscalls-by-pid.py
+++ b/tools/perf/scripts/python/failed-syscalls-by-pid.py
@@ -39,7 +39,7 @@ def trace_end():
39 39
40def raw_syscalls__sys_exit(event_name, context, common_cpu, 40def raw_syscalls__sys_exit(event_name, context, common_cpu,
41 common_secs, common_nsecs, common_pid, common_comm, 41 common_secs, common_nsecs, common_pid, common_comm,
42 id, ret): 42 common_callchain, id, ret):
43 if (for_comm and common_comm != for_comm) or \ 43 if (for_comm and common_comm != for_comm) or \
44 (for_pid and common_pid != for_pid ): 44 (for_pid and common_pid != for_pid ):
45 return 45 return
@@ -50,6 +50,11 @@ def raw_syscalls__sys_exit(event_name, context, common_cpu,
50 except TypeError: 50 except TypeError:
51 syscalls[common_comm][common_pid][id][ret] = 1 51 syscalls[common_comm][common_pid][id][ret] = 1
52 52
53def syscalls__sys_exit(event_name, context, common_cpu,
54 common_secs, common_nsecs, common_pid, common_comm,
55 id, ret):
56 raw_syscalls__sys_exit(**locals())
57
53def print_error_totals(): 58def print_error_totals():
54 if for_comm is not None: 59 if for_comm is not None:
55 print "\nsyscall errors for %s:\n\n" % (for_comm), 60 print "\nsyscall errors for %s:\n\n" % (for_comm),
diff --git a/tools/perf/scripts/python/futex-contention.py b/tools/perf/scripts/python/futex-contention.py
index 11e70a388d41..0f5cf437b602 100644
--- a/tools/perf/scripts/python/futex-contention.py
+++ b/tools/perf/scripts/python/futex-contention.py
@@ -21,7 +21,7 @@ thread_blocktime = {}
21lock_waits = {} # long-lived stats on (tid,lock) blockage elapsed time 21lock_waits = {} # long-lived stats on (tid,lock) blockage elapsed time
22process_names = {} # long-lived pid-to-execname mapping 22process_names = {} # long-lived pid-to-execname mapping
23 23
24def syscalls__sys_enter_futex(event, ctxt, cpu, s, ns, tid, comm, 24def syscalls__sys_enter_futex(event, ctxt, cpu, s, ns, tid, comm, callchain,
25 nr, uaddr, op, val, utime, uaddr2, val3): 25 nr, uaddr, op, val, utime, uaddr2, val3):
26 cmd = op & FUTEX_CMD_MASK 26 cmd = op & FUTEX_CMD_MASK
27 if cmd != FUTEX_WAIT: 27 if cmd != FUTEX_WAIT:
@@ -31,7 +31,7 @@ def syscalls__sys_enter_futex(event, ctxt, cpu, s, ns, tid, comm,
31 thread_thislock[tid] = uaddr 31 thread_thislock[tid] = uaddr
32 thread_blocktime[tid] = nsecs(s, ns) 32 thread_blocktime[tid] = nsecs(s, ns)
33 33
34def syscalls__sys_exit_futex(event, ctxt, cpu, s, ns, tid, comm, 34def syscalls__sys_exit_futex(event, ctxt, cpu, s, ns, tid, comm, callchain,
35 nr, ret): 35 nr, ret):
36 if thread_blocktime.has_key(tid): 36 if thread_blocktime.has_key(tid):
37 elapsed = nsecs(s, ns) - thread_blocktime[tid] 37 elapsed = nsecs(s, ns) - thread_blocktime[tid]
diff --git a/tools/perf/scripts/python/net_dropmonitor.py b/tools/perf/scripts/python/net_dropmonitor.py
index b5740599aabd..0b6ce8c253e8 100755
--- a/tools/perf/scripts/python/net_dropmonitor.py
+++ b/tools/perf/scripts/python/net_dropmonitor.py
@@ -66,7 +66,7 @@ def trace_end():
66 print_drop_table() 66 print_drop_table()
67 67
68# called from perf, when it finds a correspoinding event 68# called from perf, when it finds a correspoinding event
69def skb__kfree_skb(name, context, cpu, sec, nsec, pid, comm, 69def skb__kfree_skb(name, context, cpu, sec, nsec, pid, comm, callchain,
70 skbaddr, location, protocol): 70 skbaddr, location, protocol):
71 slocation = str(location) 71 slocation = str(location)
72 try: 72 try:
diff --git a/tools/perf/scripts/python/netdev-times.py b/tools/perf/scripts/python/netdev-times.py
index 9aa0a32972e8..4d21ef2d601d 100644
--- a/tools/perf/scripts/python/netdev-times.py
+++ b/tools/perf/scripts/python/netdev-times.py
@@ -224,75 +224,75 @@ def trace_end():
224 (len(rx_skb_list), of_count_rx_skb_list) 224 (len(rx_skb_list), of_count_rx_skb_list)
225 225
226# called from perf, when it finds a correspoinding event 226# called from perf, when it finds a correspoinding event
227def irq__softirq_entry(name, context, cpu, sec, nsec, pid, comm, vec): 227def irq__softirq_entry(name, context, cpu, sec, nsec, pid, comm, callchain, vec):
228 if symbol_str("irq__softirq_entry", "vec", vec) != "NET_RX": 228 if symbol_str("irq__softirq_entry", "vec", vec) != "NET_RX":
229 return 229 return
230 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, vec) 230 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, vec)
231 all_event_list.append(event_info) 231 all_event_list.append(event_info)
232 232
233def irq__softirq_exit(name, context, cpu, sec, nsec, pid, comm, vec): 233def irq__softirq_exit(name, context, cpu, sec, nsec, pid, comm, callchain, vec):
234 if symbol_str("irq__softirq_entry", "vec", vec) != "NET_RX": 234 if symbol_str("irq__softirq_entry", "vec", vec) != "NET_RX":
235 return 235 return
236 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, vec) 236 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, vec)
237 all_event_list.append(event_info) 237 all_event_list.append(event_info)
238 238
239def irq__softirq_raise(name, context, cpu, sec, nsec, pid, comm, vec): 239def irq__softirq_raise(name, context, cpu, sec, nsec, pid, comm, callchain, vec):
240 if symbol_str("irq__softirq_entry", "vec", vec) != "NET_RX": 240 if symbol_str("irq__softirq_entry", "vec", vec) != "NET_RX":
241 return 241 return
242 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, vec) 242 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, vec)
243 all_event_list.append(event_info) 243 all_event_list.append(event_info)
244 244
245def irq__irq_handler_entry(name, context, cpu, sec, nsec, pid, comm, 245def irq__irq_handler_entry(name, context, cpu, sec, nsec, pid, comm,
246 irq, irq_name): 246 callchain, irq, irq_name):
247 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, 247 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
248 irq, irq_name) 248 irq, irq_name)
249 all_event_list.append(event_info) 249 all_event_list.append(event_info)
250 250
251def irq__irq_handler_exit(name, context, cpu, sec, nsec, pid, comm, irq, ret): 251def irq__irq_handler_exit(name, context, cpu, sec, nsec, pid, comm, callchain, irq, ret):
252 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, irq, ret) 252 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, irq, ret)
253 all_event_list.append(event_info) 253 all_event_list.append(event_info)
254 254
255def napi__napi_poll(name, context, cpu, sec, nsec, pid, comm, napi, dev_name): 255def napi__napi_poll(name, context, cpu, sec, nsec, pid, comm, callchain, napi, dev_name):
256 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, 256 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
257 napi, dev_name) 257 napi, dev_name)
258 all_event_list.append(event_info) 258 all_event_list.append(event_info)
259 259
260def net__netif_receive_skb(name, context, cpu, sec, nsec, pid, comm, skbaddr, 260def net__netif_receive_skb(name, context, cpu, sec, nsec, pid, comm, callchain, skbaddr,
261 skblen, dev_name): 261 skblen, dev_name):
262 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, 262 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
263 skbaddr, skblen, dev_name) 263 skbaddr, skblen, dev_name)
264 all_event_list.append(event_info) 264 all_event_list.append(event_info)
265 265
266def net__netif_rx(name, context, cpu, sec, nsec, pid, comm, skbaddr, 266def net__netif_rx(name, context, cpu, sec, nsec, pid, comm, callchain, skbaddr,
267 skblen, dev_name): 267 skblen, dev_name):
268 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, 268 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
269 skbaddr, skblen, dev_name) 269 skbaddr, skblen, dev_name)
270 all_event_list.append(event_info) 270 all_event_list.append(event_info)
271 271
272def net__net_dev_queue(name, context, cpu, sec, nsec, pid, comm, 272def net__net_dev_queue(name, context, cpu, sec, nsec, pid, comm, callchain,
273 skbaddr, skblen, dev_name): 273 skbaddr, skblen, dev_name):
274 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, 274 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
275 skbaddr, skblen, dev_name) 275 skbaddr, skblen, dev_name)
276 all_event_list.append(event_info) 276 all_event_list.append(event_info)
277 277
278def net__net_dev_xmit(name, context, cpu, sec, nsec, pid, comm, 278def net__net_dev_xmit(name, context, cpu, sec, nsec, pid, comm, callchain,
279 skbaddr, skblen, rc, dev_name): 279 skbaddr, skblen, rc, dev_name):
280 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, 280 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
281 skbaddr, skblen, rc ,dev_name) 281 skbaddr, skblen, rc ,dev_name)
282 all_event_list.append(event_info) 282 all_event_list.append(event_info)
283 283
284def skb__kfree_skb(name, context, cpu, sec, nsec, pid, comm, 284def skb__kfree_skb(name, context, cpu, sec, nsec, pid, comm, callchain,
285 skbaddr, protocol, location): 285 skbaddr, protocol, location):
286 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, 286 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
287 skbaddr, protocol, location) 287 skbaddr, protocol, location)
288 all_event_list.append(event_info) 288 all_event_list.append(event_info)
289 289
290def skb__consume_skb(name, context, cpu, sec, nsec, pid, comm, skbaddr): 290def skb__consume_skb(name, context, cpu, sec, nsec, pid, comm, callchain, skbaddr):
291 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, 291 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
292 skbaddr) 292 skbaddr)
293 all_event_list.append(event_info) 293 all_event_list.append(event_info)
294 294
295def skb__skb_copy_datagram_iovec(name, context, cpu, sec, nsec, pid, comm, 295def skb__skb_copy_datagram_iovec(name, context, cpu, sec, nsec, pid, comm, callchain,
296 skbaddr, skblen): 296 skbaddr, skblen):
297 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, 297 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
298 skbaddr, skblen) 298 skbaddr, skblen)
diff --git a/tools/perf/scripts/python/sched-migration.py b/tools/perf/scripts/python/sched-migration.py
index 74d55ec08aed..de66cb3b72c9 100644
--- a/tools/perf/scripts/python/sched-migration.py
+++ b/tools/perf/scripts/python/sched-migration.py
@@ -369,93 +369,92 @@ def trace_end():
369 369
370def sched__sched_stat_runtime(event_name, context, common_cpu, 370def sched__sched_stat_runtime(event_name, context, common_cpu,
371 common_secs, common_nsecs, common_pid, common_comm, 371 common_secs, common_nsecs, common_pid, common_comm,
372 comm, pid, runtime, vruntime): 372 common_callchain, comm, pid, runtime, vruntime):
373 pass 373 pass
374 374
375def sched__sched_stat_iowait(event_name, context, common_cpu, 375def sched__sched_stat_iowait(event_name, context, common_cpu,
376 common_secs, common_nsecs, common_pid, common_comm, 376 common_secs, common_nsecs, common_pid, common_comm,
377 comm, pid, delay): 377 common_callchain, comm, pid, delay):
378 pass 378 pass
379 379
380def sched__sched_stat_sleep(event_name, context, common_cpu, 380def sched__sched_stat_sleep(event_name, context, common_cpu,
381 common_secs, common_nsecs, common_pid, common_comm, 381 common_secs, common_nsecs, common_pid, common_comm,
382 comm, pid, delay): 382 common_callchain, comm, pid, delay):
383 pass 383 pass
384 384
385def sched__sched_stat_wait(event_name, context, common_cpu, 385def sched__sched_stat_wait(event_name, context, common_cpu,
386 common_secs, common_nsecs, common_pid, common_comm, 386 common_secs, common_nsecs, common_pid, common_comm,
387 comm, pid, delay): 387 common_callchain, comm, pid, delay):
388 pass 388 pass
389 389
390def sched__sched_process_fork(event_name, context, common_cpu, 390def sched__sched_process_fork(event_name, context, common_cpu,
391 common_secs, common_nsecs, common_pid, common_comm, 391 common_secs, common_nsecs, common_pid, common_comm,
392 parent_comm, parent_pid, child_comm, child_pid): 392 common_callchain, parent_comm, parent_pid, child_comm, child_pid):
393 pass 393 pass
394 394
395def sched__sched_process_wait(event_name, context, common_cpu, 395def sched__sched_process_wait(event_name, context, common_cpu,
396 common_secs, common_nsecs, common_pid, common_comm, 396 common_secs, common_nsecs, common_pid, common_comm,
397 comm, pid, prio): 397 common_callchain, comm, pid, prio):
398 pass 398 pass
399 399
400def sched__sched_process_exit(event_name, context, common_cpu, 400def sched__sched_process_exit(event_name, context, common_cpu,
401 common_secs, common_nsecs, common_pid, common_comm, 401 common_secs, common_nsecs, common_pid, common_comm,
402 comm, pid, prio): 402 common_callchain, comm, pid, prio):
403 pass 403 pass
404 404
405def sched__sched_process_free(event_name, context, common_cpu, 405def sched__sched_process_free(event_name, context, common_cpu,
406 common_secs, common_nsecs, common_pid, common_comm, 406 common_secs, common_nsecs, common_pid, common_comm,
407 comm, pid, prio): 407 common_callchain, comm, pid, prio):
408 pass 408 pass
409 409
410def sched__sched_migrate_task(event_name, context, common_cpu, 410def sched__sched_migrate_task(event_name, context, common_cpu,
411 common_secs, common_nsecs, common_pid, common_comm, 411 common_secs, common_nsecs, common_pid, common_comm,
412 comm, pid, prio, orig_cpu, 412 common_callchain, comm, pid, prio, orig_cpu,
413 dest_cpu): 413 dest_cpu):
414 headers = EventHeaders(common_cpu, common_secs, common_nsecs, 414 headers = EventHeaders(common_cpu, common_secs, common_nsecs,
415 common_pid, common_comm) 415 common_pid, common_comm, common_callchain)
416 parser.migrate(headers, pid, prio, orig_cpu, dest_cpu) 416 parser.migrate(headers, pid, prio, orig_cpu, dest_cpu)
417 417
418def sched__sched_switch(event_name, context, common_cpu, 418def sched__sched_switch(event_name, context, common_cpu,
419 common_secs, common_nsecs, common_pid, common_comm, 419 common_secs, common_nsecs, common_pid, common_comm, common_callchain,
420 prev_comm, prev_pid, prev_prio, prev_state, 420 prev_comm, prev_pid, prev_prio, prev_state,
421 next_comm, next_pid, next_prio): 421 next_comm, next_pid, next_prio):
422 422
423 headers = EventHeaders(common_cpu, common_secs, common_nsecs, 423 headers = EventHeaders(common_cpu, common_secs, common_nsecs,
424 common_pid, common_comm) 424 common_pid, common_comm, common_callchain)
425 parser.sched_switch(headers, prev_comm, prev_pid, prev_prio, prev_state, 425 parser.sched_switch(headers, prev_comm, prev_pid, prev_prio, prev_state,
426 next_comm, next_pid, next_prio) 426 next_comm, next_pid, next_prio)
427 427
428def sched__sched_wakeup_new(event_name, context, common_cpu, 428def sched__sched_wakeup_new(event_name, context, common_cpu,
429 common_secs, common_nsecs, common_pid, common_comm, 429 common_secs, common_nsecs, common_pid, common_comm,
430 comm, pid, prio, success, 430 common_callchain, comm, pid, prio, success,
431 target_cpu): 431 target_cpu):
432 headers = EventHeaders(common_cpu, common_secs, common_nsecs, 432 headers = EventHeaders(common_cpu, common_secs, common_nsecs,
433 common_pid, common_comm) 433 common_pid, common_comm, common_callchain)
434 parser.wake_up(headers, comm, pid, success, target_cpu, 1) 434 parser.wake_up(headers, comm, pid, success, target_cpu, 1)
435 435
436def sched__sched_wakeup(event_name, context, common_cpu, 436def sched__sched_wakeup(event_name, context, common_cpu,
437 common_secs, common_nsecs, common_pid, common_comm, 437 common_secs, common_nsecs, common_pid, common_comm,
438 comm, pid, prio, success, 438 common_callchain, comm, pid, prio, success,
439 target_cpu): 439 target_cpu):
440 headers = EventHeaders(common_cpu, common_secs, common_nsecs, 440 headers = EventHeaders(common_cpu, common_secs, common_nsecs,
441 common_pid, common_comm) 441 common_pid, common_comm, common_callchain)
442 parser.wake_up(headers, comm, pid, success, target_cpu, 0) 442 parser.wake_up(headers, comm, pid, success, target_cpu, 0)
443 443
444def sched__sched_wait_task(event_name, context, common_cpu, 444def sched__sched_wait_task(event_name, context, common_cpu,
445 common_secs, common_nsecs, common_pid, common_comm, 445 common_secs, common_nsecs, common_pid, common_comm,
446 comm, pid, prio): 446 common_callchain, comm, pid, prio):
447 pass 447 pass
448 448
449def sched__sched_kthread_stop_ret(event_name, context, common_cpu, 449def sched__sched_kthread_stop_ret(event_name, context, common_cpu,
450 common_secs, common_nsecs, common_pid, common_comm, 450 common_secs, common_nsecs, common_pid, common_comm,
451 ret): 451 common_callchain, ret):
452 pass 452 pass
453 453
454def sched__sched_kthread_stop(event_name, context, common_cpu, 454def sched__sched_kthread_stop(event_name, context, common_cpu,
455 common_secs, common_nsecs, common_pid, common_comm, 455 common_secs, common_nsecs, common_pid, common_comm,
456 comm, pid): 456 common_callchain, comm, pid):
457 pass 457 pass
458 458
459def trace_unhandled(event_name, context, common_cpu, common_secs, common_nsecs, 459def trace_unhandled(event_name, context, event_fields_dict):
460 common_pid, common_comm):
461 pass 460 pass
diff --git a/tools/perf/scripts/python/sctop.py b/tools/perf/scripts/python/sctop.py
index 42c267e292fa..61621b93affb 100644
--- a/tools/perf/scripts/python/sctop.py
+++ b/tools/perf/scripts/python/sctop.py
@@ -44,7 +44,7 @@ def trace_begin():
44 44
45def raw_syscalls__sys_enter(event_name, context, common_cpu, 45def raw_syscalls__sys_enter(event_name, context, common_cpu,
46 common_secs, common_nsecs, common_pid, common_comm, 46 common_secs, common_nsecs, common_pid, common_comm,
47 id, args): 47 common_callchain, id, args):
48 if for_comm is not None: 48 if for_comm is not None:
49 if common_comm != for_comm: 49 if common_comm != for_comm:
50 return 50 return
@@ -53,6 +53,11 @@ def raw_syscalls__sys_enter(event_name, context, common_cpu,
53 except TypeError: 53 except TypeError:
54 syscalls[id] = 1 54 syscalls[id] = 1
55 55
56def syscalls__sys_enter(event_name, context, common_cpu,
57 common_secs, common_nsecs, common_pid, common_comm,
58 id, args):
59 raw_syscalls__sys_enter(**locals())
60
56def print_syscall_totals(interval): 61def print_syscall_totals(interval):
57 while 1: 62 while 1:
58 clear_term() 63 clear_term()
diff --git a/tools/perf/scripts/python/syscall-counts-by-pid.py b/tools/perf/scripts/python/syscall-counts-by-pid.py
index c64d1c55d745..daf314cc5dd3 100644
--- a/tools/perf/scripts/python/syscall-counts-by-pid.py
+++ b/tools/perf/scripts/python/syscall-counts-by-pid.py
@@ -38,7 +38,7 @@ def trace_end():
38 38
39def raw_syscalls__sys_enter(event_name, context, common_cpu, 39def raw_syscalls__sys_enter(event_name, context, common_cpu,
40 common_secs, common_nsecs, common_pid, common_comm, 40 common_secs, common_nsecs, common_pid, common_comm,
41 id, args): 41 common_callchain, id, args):
42 42
43 if (for_comm and common_comm != for_comm) or \ 43 if (for_comm and common_comm != for_comm) or \
44 (for_pid and common_pid != for_pid ): 44 (for_pid and common_pid != for_pid ):
@@ -48,6 +48,11 @@ def raw_syscalls__sys_enter(event_name, context, common_cpu,
48 except TypeError: 48 except TypeError:
49 syscalls[common_comm][common_pid][id] = 1 49 syscalls[common_comm][common_pid][id] = 1
50 50
51def syscalls__sys_enter(event_name, context, common_cpu,
52 common_secs, common_nsecs, common_pid, common_comm,
53 id, args):
54 raw_syscalls__sys_enter(**locals())
55
51def print_syscall_totals(): 56def print_syscall_totals():
52 if for_comm is not None: 57 if for_comm is not None:
53 print "\nsyscall events for %s:\n\n" % (for_comm), 58 print "\nsyscall events for %s:\n\n" % (for_comm),
diff --git a/tools/perf/scripts/python/syscall-counts.py b/tools/perf/scripts/python/syscall-counts.py
index b435d3f188e8..e66a7730aeb5 100644
--- a/tools/perf/scripts/python/syscall-counts.py
+++ b/tools/perf/scripts/python/syscall-counts.py
@@ -35,7 +35,7 @@ def trace_end():
35 35
36def raw_syscalls__sys_enter(event_name, context, common_cpu, 36def raw_syscalls__sys_enter(event_name, context, common_cpu,
37 common_secs, common_nsecs, common_pid, common_comm, 37 common_secs, common_nsecs, common_pid, common_comm,
38 id, args): 38 common_callchain, id, args):
39 if for_comm is not None: 39 if for_comm is not None:
40 if common_comm != for_comm: 40 if common_comm != for_comm:
41 return 41 return
@@ -44,6 +44,11 @@ def raw_syscalls__sys_enter(event_name, context, common_cpu,
44 except TypeError: 44 except TypeError:
45 syscalls[id] = 1 45 syscalls[id] = 1
46 46
47def syscalls__sys_enter(event_name, context, common_cpu,
48 common_secs, common_nsecs, common_pid, common_comm,
49 id, args):
50 raw_syscalls__sys_enter(**locals())
51
47def print_syscall_totals(): 52def print_syscall_totals():
48 if for_comm is not None: 53 if for_comm is not None:
49 print "\nsyscall events for %s:\n\n" % (for_comm), 54 print "\nsyscall events for %s:\n\n" % (for_comm),
diff --git a/tools/perf/tests/attr/base-record b/tools/perf/tests/attr/base-record
index e9bd6391f2ae..f710b92ccff6 100644
--- a/tools/perf/tests/attr/base-record
+++ b/tools/perf/tests/attr/base-record
@@ -1,7 +1,8 @@
1[event] 1[event]
2fd=1 2fd=1
3group_fd=-1 3group_fd=-1
4flags=0 4# 0 or PERF_FLAG_FD_CLOEXEC flag
5flags=0|8
5cpu=* 6cpu=*
6type=0|1 7type=0|1
7size=96 8size=96
diff --git a/tools/perf/tests/attr/base-stat b/tools/perf/tests/attr/base-stat
index 91cd48b399f3..dc3ada2470c0 100644
--- a/tools/perf/tests/attr/base-stat
+++ b/tools/perf/tests/attr/base-stat
@@ -1,7 +1,8 @@
1[event] 1[event]
2fd=1 2fd=1
3group_fd=-1 3group_fd=-1
4flags=0 4# 0 or PERF_FLAG_FD_CLOEXEC flag
5flags=0|8
5cpu=* 6cpu=*
6type=0 7type=0
7size=96 8size=96
diff --git a/tools/perf/tests/bp_signal.c b/tools/perf/tests/bp_signal.c
index aba095489193..a02b035fd5aa 100644
--- a/tools/perf/tests/bp_signal.c
+++ b/tools/perf/tests/bp_signal.c
@@ -25,6 +25,7 @@
25#include "tests.h" 25#include "tests.h"
26#include "debug.h" 26#include "debug.h"
27#include "perf.h" 27#include "perf.h"
28#include "cloexec.h"
28 29
29static int fd1; 30static int fd1;
30static int fd2; 31static int fd2;
@@ -78,7 +79,8 @@ static int bp_event(void *fn, int setup_signal)
78 pe.exclude_kernel = 1; 79 pe.exclude_kernel = 1;
79 pe.exclude_hv = 1; 80 pe.exclude_hv = 1;
80 81
81 fd = sys_perf_event_open(&pe, 0, -1, -1, 0); 82 fd = sys_perf_event_open(&pe, 0, -1, -1,
83 perf_event_open_cloexec_flag());
82 if (fd < 0) { 84 if (fd < 0) {
83 pr_debug("failed opening event %llx\n", pe.config); 85 pr_debug("failed opening event %llx\n", pe.config);
84 return TEST_FAIL; 86 return TEST_FAIL;
diff --git a/tools/perf/tests/bp_signal_overflow.c b/tools/perf/tests/bp_signal_overflow.c
index 44ac82179708..e76537724491 100644
--- a/tools/perf/tests/bp_signal_overflow.c
+++ b/tools/perf/tests/bp_signal_overflow.c
@@ -24,6 +24,7 @@
24#include "tests.h" 24#include "tests.h"
25#include "debug.h" 25#include "debug.h"
26#include "perf.h" 26#include "perf.h"
27#include "cloexec.h"
27 28
28static int overflows; 29static int overflows;
29 30
@@ -91,7 +92,8 @@ int test__bp_signal_overflow(void)
91 pe.exclude_kernel = 1; 92 pe.exclude_kernel = 1;
92 pe.exclude_hv = 1; 93 pe.exclude_hv = 1;
93 94
94 fd = sys_perf_event_open(&pe, 0, -1, -1, 0); 95 fd = sys_perf_event_open(&pe, 0, -1, -1,
96 perf_event_open_cloexec_flag());
95 if (fd < 0) { 97 if (fd < 0) {
96 pr_debug("failed opening event %llx\n", pe.config); 98 pr_debug("failed opening event %llx\n", pe.config);
97 return TEST_FAIL; 99 return TEST_FAIL;
diff --git a/tools/perf/tests/dso-data.c b/tools/perf/tests/dso-data.c
index 630808cd7cc2..caaf37f079b1 100644
--- a/tools/perf/tests/dso-data.c
+++ b/tools/perf/tests/dso-data.c
@@ -10,6 +10,7 @@
10#include "machine.h" 10#include "machine.h"
11#include "symbol.h" 11#include "symbol.h"
12#include "tests.h" 12#include "tests.h"
13#include "debug.h"
13 14
14static char *test_file(int size) 15static char *test_file(int size)
15{ 16{
diff --git a/tools/perf/tests/evsel-roundtrip-name.c b/tools/perf/tests/evsel-roundtrip-name.c
index 465cdbc345cf..b8d8341b383e 100644
--- a/tools/perf/tests/evsel-roundtrip-name.c
+++ b/tools/perf/tests/evsel-roundtrip-name.c
@@ -2,6 +2,7 @@
2#include "evsel.h" 2#include "evsel.h"
3#include "parse-events.h" 3#include "parse-events.h"
4#include "tests.h" 4#include "tests.h"
5#include "debug.h"
5 6
6static int perf_evsel__roundtrip_cache_name_test(void) 7static int perf_evsel__roundtrip_cache_name_test(void)
7{ 8{
diff --git a/tools/perf/tests/evsel-tp-sched.c b/tools/perf/tests/evsel-tp-sched.c
index 35d7fdb2328d..52162425c969 100644
--- a/tools/perf/tests/evsel-tp-sched.c
+++ b/tools/perf/tests/evsel-tp-sched.c
@@ -1,6 +1,7 @@
1#include <traceevent/event-parse.h> 1#include <traceevent/event-parse.h>
2#include "evsel.h" 2#include "evsel.h"
3#include "tests.h" 3#include "tests.h"
4#include "debug.h"
4 5
5static int perf_evsel__test_field(struct perf_evsel *evsel, const char *name, 6static int perf_evsel__test_field(struct perf_evsel *evsel, const char *name,
6 int size, bool should_be_signed) 7 int size, bool should_be_signed)
diff --git a/tools/perf/tests/open-syscall-tp-fields.c b/tools/perf/tests/open-syscall-tp-fields.c
index c505ef2af245..0785b64ffd6c 100644
--- a/tools/perf/tests/open-syscall-tp-fields.c
+++ b/tools/perf/tests/open-syscall-tp-fields.c
@@ -3,6 +3,7 @@
3#include "evsel.h" 3#include "evsel.h"
4#include "thread_map.h" 4#include "thread_map.h"
5#include "tests.h" 5#include "tests.h"
6#include "debug.h"
6 7
7int test__syscall_open_tp_fields(void) 8int test__syscall_open_tp_fields(void)
8{ 9{
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
index deba66955f8c..5941927a4b7f 100644
--- a/tools/perf/tests/parse-events.c
+++ b/tools/perf/tests/parse-events.c
@@ -5,6 +5,7 @@
5#include <api/fs/fs.h> 5#include <api/fs/fs.h>
6#include <api/fs/debugfs.h> 6#include <api/fs/debugfs.h>
7#include "tests.h" 7#include "tests.h"
8#include "debug.h"
8#include <linux/hw_breakpoint.h> 9#include <linux/hw_breakpoint.h>
9 10
10#define PERF_TP_SAMPLE_TYPE (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | \ 11#define PERF_TP_SAMPLE_TYPE (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | \
diff --git a/tools/perf/tests/parse-no-sample-id-all.c b/tools/perf/tests/parse-no-sample-id-all.c
index 905019f9b740..2c63ea658541 100644
--- a/tools/perf/tests/parse-no-sample-id-all.c
+++ b/tools/perf/tests/parse-no-sample-id-all.c
@@ -7,6 +7,7 @@
7#include "evlist.h" 7#include "evlist.h"
8#include "header.h" 8#include "header.h"
9#include "util.h" 9#include "util.h"
10#include "debug.h"
10 11
11static int process_event(struct perf_evlist **pevlist, union perf_event *event) 12static int process_event(struct perf_evlist **pevlist, union perf_event *event)
12{ 13{
diff --git a/tools/perf/tests/perf-time-to-tsc.c b/tools/perf/tests/perf-time-to-tsc.c
index 3b7cd4d32dcb..f238442b238a 100644
--- a/tools/perf/tests/perf-time-to-tsc.c
+++ b/tools/perf/tests/perf-time-to-tsc.c
@@ -8,10 +8,9 @@
8#include "evsel.h" 8#include "evsel.h"
9#include "thread_map.h" 9#include "thread_map.h"
10#include "cpumap.h" 10#include "cpumap.h"
11#include "tsc.h"
11#include "tests.h" 12#include "tests.h"
12 13
13#include "../arch/x86/util/tsc.h"
14
15#define CHECK__(x) { \ 14#define CHECK__(x) { \
16 while ((x) < 0) { \ 15 while ((x) < 0) { \
17 pr_debug(#x " failed!\n"); \ 16 pr_debug(#x " failed!\n"); \
@@ -26,15 +25,6 @@
26 } \ 25 } \
27} 26}
28 27
29static u64 rdtsc(void)
30{
31 unsigned int low, high;
32
33 asm volatile("rdtsc" : "=a" (low), "=d" (high));
34
35 return low | ((u64)high) << 32;
36}
37
38/** 28/**
39 * test__perf_time_to_tsc - test converting perf time to TSC. 29 * test__perf_time_to_tsc - test converting perf time to TSC.
40 * 30 *
diff --git a/tools/perf/tests/rdpmc.c b/tools/perf/tests/rdpmc.c
index e59143fd9e71..c04d1f268576 100644
--- a/tools/perf/tests/rdpmc.c
+++ b/tools/perf/tests/rdpmc.c
@@ -6,6 +6,7 @@
6#include "perf.h" 6#include "perf.h"
7#include "debug.h" 7#include "debug.h"
8#include "tests.h" 8#include "tests.h"
9#include "cloexec.h"
9 10
10#if defined(__x86_64__) || defined(__i386__) 11#if defined(__x86_64__) || defined(__i386__)
11 12
@@ -104,7 +105,8 @@ static int __test__rdpmc(void)
104 sa.sa_sigaction = segfault_handler; 105 sa.sa_sigaction = segfault_handler;
105 sigaction(SIGSEGV, &sa, NULL); 106 sigaction(SIGSEGV, &sa, NULL);
106 107
107 fd = sys_perf_event_open(&attr, 0, -1, -1, 0); 108 fd = sys_perf_event_open(&attr, 0, -1, -1,
109 perf_event_open_cloexec_flag());
108 if (fd < 0) { 110 if (fd < 0) {
109 pr_err("Error: sys_perf_event_open() syscall returned " 111 pr_err("Error: sys_perf_event_open() syscall returned "
110 "with %d (%s)\n", fd, strerror(errno)); 112 "with %d (%s)\n", fd, strerror(errno));
diff --git a/tools/perf/tests/sample-parsing.c b/tools/perf/tests/sample-parsing.c
index 7ae8d17db3d9..ca292f9a4ae2 100644
--- a/tools/perf/tests/sample-parsing.c
+++ b/tools/perf/tests/sample-parsing.c
@@ -4,6 +4,7 @@
4#include "util.h" 4#include "util.h"
5#include "event.h" 5#include "event.h"
6#include "evsel.h" 6#include "evsel.h"
7#include "debug.h"
7 8
8#include "tests.h" 9#include "tests.h"
9 10
diff --git a/tools/perf/tests/thread-mg-share.c b/tools/perf/tests/thread-mg-share.c
index 2b2e0dbe114f..b028499dd3cf 100644
--- a/tools/perf/tests/thread-mg-share.c
+++ b/tools/perf/tests/thread-mg-share.c
@@ -2,6 +2,7 @@
2#include "machine.h" 2#include "machine.h"
3#include "thread.h" 3#include "thread.h"
4#include "map.h" 4#include "map.h"
5#include "debug.h"
5 6
6int test__thread_mg_share(void) 7int test__thread_mg_share(void)
7{ 8{
diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c
index 3ccf6e14f89b..6680fa5cb9dd 100644
--- a/tools/perf/ui/browser.c
+++ b/tools/perf/ui/browser.c
@@ -150,7 +150,7 @@ unsigned int ui_browser__rb_tree_refresh(struct ui_browser *browser)
150 while (nd != NULL) { 150 while (nd != NULL) {
151 ui_browser__gotorc(browser, row, 0); 151 ui_browser__gotorc(browser, row, 0);
152 browser->write(browser, nd, row); 152 browser->write(browser, nd, row);
153 if (++row == browser->height) 153 if (++row == browser->rows)
154 break; 154 break;
155 nd = rb_next(nd); 155 nd = rb_next(nd);
156 } 156 }
@@ -166,7 +166,7 @@ bool ui_browser__is_current_entry(struct ui_browser *browser, unsigned row)
166void ui_browser__refresh_dimensions(struct ui_browser *browser) 166void ui_browser__refresh_dimensions(struct ui_browser *browser)
167{ 167{
168 browser->width = SLtt_Screen_Cols - 1; 168 browser->width = SLtt_Screen_Cols - 1;
169 browser->height = SLtt_Screen_Rows - 2; 169 browser->height = browser->rows = SLtt_Screen_Rows - 2;
170 browser->y = 1; 170 browser->y = 1;
171 browser->x = 0; 171 browser->x = 0;
172} 172}
@@ -250,7 +250,10 @@ int ui_browser__show(struct ui_browser *browser, const char *title,
250 int err; 250 int err;
251 va_list ap; 251 va_list ap;
252 252
253 ui_browser__refresh_dimensions(browser); 253 if (browser->refresh_dimensions == NULL)
254 browser->refresh_dimensions = ui_browser__refresh_dimensions;
255
256 browser->refresh_dimensions(browser);
254 257
255 pthread_mutex_lock(&ui__lock); 258 pthread_mutex_lock(&ui__lock);
256 __ui_browser__show_title(browser, title); 259 __ui_browser__show_title(browser, title);
@@ -279,7 +282,7 @@ static void ui_browser__scrollbar_set(struct ui_browser *browser)
279{ 282{
280 int height = browser->height, h = 0, pct = 0, 283 int height = browser->height, h = 0, pct = 0,
281 col = browser->width, 284 col = browser->width,
282 row = browser->y - 1; 285 row = 0;
283 286
284 if (browser->nr_entries > 1) { 287 if (browser->nr_entries > 1) {
285 pct = ((browser->index * (browser->height - 1)) / 288 pct = ((browser->index * (browser->height - 1)) /
@@ -367,7 +370,7 @@ int ui_browser__run(struct ui_browser *browser, int delay_secs)
367 370
368 if (key == K_RESIZE) { 371 if (key == K_RESIZE) {
369 ui__refresh_dimensions(false); 372 ui__refresh_dimensions(false);
370 ui_browser__refresh_dimensions(browser); 373 browser->refresh_dimensions(browser);
371 __ui_browser__show_title(browser, browser->title); 374 __ui_browser__show_title(browser, browser->title);
372 ui_helpline__puts(browser->helpline); 375 ui_helpline__puts(browser->helpline);
373 continue; 376 continue;
@@ -389,7 +392,7 @@ int ui_browser__run(struct ui_browser *browser, int delay_secs)
389 if (browser->index == browser->nr_entries - 1) 392 if (browser->index == browser->nr_entries - 1)
390 break; 393 break;
391 ++browser->index; 394 ++browser->index;
392 if (browser->index == browser->top_idx + browser->height) { 395 if (browser->index == browser->top_idx + browser->rows) {
393 ++browser->top_idx; 396 ++browser->top_idx;
394 browser->seek(browser, +1, SEEK_CUR); 397 browser->seek(browser, +1, SEEK_CUR);
395 } 398 }
@@ -405,10 +408,10 @@ int ui_browser__run(struct ui_browser *browser, int delay_secs)
405 break; 408 break;
406 case K_PGDN: 409 case K_PGDN:
407 case ' ': 410 case ' ':
408 if (browser->top_idx + browser->height > browser->nr_entries - 1) 411 if (browser->top_idx + browser->rows > browser->nr_entries - 1)
409 break; 412 break;
410 413
411 offset = browser->height; 414 offset = browser->rows;
412 if (browser->index + offset > browser->nr_entries - 1) 415 if (browser->index + offset > browser->nr_entries - 1)
413 offset = browser->nr_entries - 1 - browser->index; 416 offset = browser->nr_entries - 1 - browser->index;
414 browser->index += offset; 417 browser->index += offset;
@@ -419,10 +422,10 @@ int ui_browser__run(struct ui_browser *browser, int delay_secs)
419 if (browser->top_idx == 0) 422 if (browser->top_idx == 0)
420 break; 423 break;
421 424
422 if (browser->top_idx < browser->height) 425 if (browser->top_idx < browser->rows)
423 offset = browser->top_idx; 426 offset = browser->top_idx;
424 else 427 else
425 offset = browser->height; 428 offset = browser->rows;
426 429
427 browser->index -= offset; 430 browser->index -= offset;
428 browser->top_idx -= offset; 431 browser->top_idx -= offset;
@@ -432,7 +435,7 @@ int ui_browser__run(struct ui_browser *browser, int delay_secs)
432 ui_browser__reset_index(browser); 435 ui_browser__reset_index(browser);
433 break; 436 break;
434 case K_END: 437 case K_END:
435 offset = browser->height - 1; 438 offset = browser->rows - 1;
436 if (offset >= browser->nr_entries) 439 if (offset >= browser->nr_entries)
437 offset = browser->nr_entries - 1; 440 offset = browser->nr_entries - 1;
438 441
@@ -462,7 +465,7 @@ unsigned int ui_browser__list_head_refresh(struct ui_browser *browser)
462 if (!browser->filter || !browser->filter(browser, pos)) { 465 if (!browser->filter || !browser->filter(browser, pos)) {
463 ui_browser__gotorc(browser, row, 0); 466 ui_browser__gotorc(browser, row, 0);
464 browser->write(browser, pos, row); 467 browser->write(browser, pos, row);
465 if (++row == browser->height) 468 if (++row == browser->rows)
466 break; 469 break;
467 } 470 }
468 } 471 }
@@ -587,7 +590,7 @@ unsigned int ui_browser__argv_refresh(struct ui_browser *browser)
587 if (!browser->filter || !browser->filter(browser, *pos)) { 590 if (!browser->filter || !browser->filter(browser, *pos)) {
588 ui_browser__gotorc(browser, row, 0); 591 ui_browser__gotorc(browser, row, 0);
589 browser->write(browser, pos, row); 592 browser->write(browser, pos, row);
590 if (++row == browser->height) 593 if (++row == browser->rows)
591 break; 594 break;
592 } 595 }
593 596
@@ -623,7 +626,7 @@ static void __ui_browser__line_arrow_up(struct ui_browser *browser,
623 626
624 SLsmg_set_char_set(1); 627 SLsmg_set_char_set(1);
625 628
626 if (start < browser->top_idx + browser->height) { 629 if (start < browser->top_idx + browser->rows) {
627 row = start - browser->top_idx; 630 row = start - browser->top_idx;
628 ui_browser__gotorc(browser, row, column); 631 ui_browser__gotorc(browser, row, column);
629 SLsmg_write_char(SLSMG_LLCORN_CHAR); 632 SLsmg_write_char(SLSMG_LLCORN_CHAR);
@@ -633,7 +636,7 @@ static void __ui_browser__line_arrow_up(struct ui_browser *browser,
633 if (row-- == 0) 636 if (row-- == 0)
634 goto out; 637 goto out;
635 } else 638 } else
636 row = browser->height - 1; 639 row = browser->rows - 1;
637 640
638 if (end > browser->top_idx) 641 if (end > browser->top_idx)
639 end_row = end - browser->top_idx; 642 end_row = end - browser->top_idx;
@@ -675,8 +678,8 @@ static void __ui_browser__line_arrow_down(struct ui_browser *browser,
675 } else 678 } else
676 row = 0; 679 row = 0;
677 680
678 if (end >= browser->top_idx + browser->height) 681 if (end >= browser->top_idx + browser->rows)
679 end_row = browser->height - 1; 682 end_row = browser->rows - 1;
680 else 683 else
681 end_row = end - browser->top_idx; 684 end_row = end - browser->top_idx;
682 685
@@ -684,7 +687,7 @@ static void __ui_browser__line_arrow_down(struct ui_browser *browser,
684 SLsmg_draw_vline(end_row - row + 1); 687 SLsmg_draw_vline(end_row - row + 1);
685 688
686 ui_browser__gotorc(browser, end_row, column); 689 ui_browser__gotorc(browser, end_row, column);
687 if (end < browser->top_idx + browser->height) { 690 if (end < browser->top_idx + browser->rows) {
688 SLsmg_write_char(SLSMG_LLCORN_CHAR); 691 SLsmg_write_char(SLSMG_LLCORN_CHAR);
689 ui_browser__gotorc(browser, end_row, column + 1); 692 ui_browser__gotorc(browser, end_row, column + 1);
690 SLsmg_write_char(SLSMG_HLINE_CHAR); 693 SLsmg_write_char(SLSMG_HLINE_CHAR);
diff --git a/tools/perf/ui/browser.h b/tools/perf/ui/browser.h
index 03d4d6295f10..92ae72113965 100644
--- a/tools/perf/ui/browser.h
+++ b/tools/perf/ui/browser.h
@@ -14,11 +14,12 @@
14struct ui_browser { 14struct ui_browser {
15 u64 index, top_idx; 15 u64 index, top_idx;
16 void *top, *entries; 16 void *top, *entries;
17 u16 y, x, width, height; 17 u16 y, x, width, height, rows;
18 int current_color; 18 int current_color;
19 void *priv; 19 void *priv;
20 const char *title; 20 const char *title;
21 char *helpline; 21 char *helpline;
22 void (*refresh_dimensions)(struct ui_browser *browser);
22 unsigned int (*refresh)(struct ui_browser *browser); 23 unsigned int (*refresh)(struct ui_browser *browser);
23 void (*write)(struct ui_browser *browser, void *entry, int row); 24 void (*write)(struct ui_browser *browser, void *entry, int row);
24 void (*seek)(struct ui_browser *browser, off_t offset, int whence); 25 void (*seek)(struct ui_browser *browser, off_t offset, int whence);
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index 04a229aa5c0f..a94b11fc5e00 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -26,6 +26,7 @@ struct hist_browser {
26 struct map_symbol *selection; 26 struct map_symbol *selection;
27 int print_seq; 27 int print_seq;
28 bool show_dso; 28 bool show_dso;
29 bool show_headers;
29 float min_pcnt; 30 float min_pcnt;
30 u64 nr_non_filtered_entries; 31 u64 nr_non_filtered_entries;
31 u64 nr_callchain_rows; 32 u64 nr_callchain_rows;
@@ -33,8 +34,7 @@ struct hist_browser {
33 34
34extern void hist_browser__init_hpp(void); 35extern void hist_browser__init_hpp(void);
35 36
36static int hists__browser_title(struct hists *hists, char *bf, size_t size, 37static int hists__browser_title(struct hists *hists, char *bf, size_t size);
37 const char *ev_name);
38static void hist_browser__update_nr_entries(struct hist_browser *hb); 38static void hist_browser__update_nr_entries(struct hist_browser *hb);
39 39
40static struct rb_node *hists__filter_entries(struct rb_node *nd, 40static struct rb_node *hists__filter_entries(struct rb_node *nd,
@@ -57,11 +57,42 @@ static u32 hist_browser__nr_entries(struct hist_browser *hb)
57 return nr_entries + hb->nr_callchain_rows; 57 return nr_entries + hb->nr_callchain_rows;
58} 58}
59 59
60static void hist_browser__refresh_dimensions(struct hist_browser *browser) 60static void hist_browser__update_rows(struct hist_browser *hb)
61{ 61{
62 struct ui_browser *browser = &hb->b;
63 u16 header_offset = hb->show_headers ? 1 : 0, index_row;
64
65 browser->rows = browser->height - header_offset;
66 /*
67 * Verify if we were at the last line and that line isn't
68 * visibe because we now show the header line(s).
69 */
70 index_row = browser->index - browser->top_idx;
71 if (index_row >= browser->rows)
72 browser->index -= index_row - browser->rows + 1;
73}
74
75static void hist_browser__refresh_dimensions(struct ui_browser *browser)
76{
77 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
78
62 /* 3 == +/- toggle symbol before actual hist_entry rendering */ 79 /* 3 == +/- toggle symbol before actual hist_entry rendering */
63 browser->b.width = 3 + (hists__sort_list_width(browser->hists) + 80 browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]"));
64 sizeof("[k]")); 81 /*
82 * FIXME: Just keeping existing behaviour, but this really should be
83 * before updating browser->width, as it will invalidate the
84 * calculation above. Fix this and the fallout in another
85 * changeset.
86 */
87 ui_browser__refresh_dimensions(browser);
88 hist_browser__update_rows(hb);
89}
90
91static void hist_browser__gotorc(struct hist_browser *browser, int row, int column)
92{
93 u16 header_offset = browser->show_headers ? 1 : 0;
94
95 ui_browser__gotorc(&browser->b, row + header_offset, column);
65} 96}
66 97
67static void hist_browser__reset(struct hist_browser *browser) 98static void hist_browser__reset(struct hist_browser *browser)
@@ -74,7 +105,7 @@ static void hist_browser__reset(struct hist_browser *browser)
74 105
75 hist_browser__update_nr_entries(browser); 106 hist_browser__update_nr_entries(browser);
76 browser->b.nr_entries = hist_browser__nr_entries(browser); 107 browser->b.nr_entries = hist_browser__nr_entries(browser);
77 hist_browser__refresh_dimensions(browser); 108 hist_browser__refresh_dimensions(&browser->b);
78 ui_browser__reset_index(&browser->b); 109 ui_browser__reset_index(&browser->b);
79} 110}
80 111
@@ -346,7 +377,7 @@ static void ui_browser__warn_lost_events(struct ui_browser *browser)
346 "Or reduce the sampling frequency."); 377 "Or reduce the sampling frequency.");
347} 378}
348 379
349static int hist_browser__run(struct hist_browser *browser, const char *ev_name, 380static int hist_browser__run(struct hist_browser *browser,
350 struct hist_browser_timer *hbt) 381 struct hist_browser_timer *hbt)
351{ 382{
352 int key; 383 int key;
@@ -356,8 +387,7 @@ static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
356 browser->b.entries = &browser->hists->entries; 387 browser->b.entries = &browser->hists->entries;
357 browser->b.nr_entries = hist_browser__nr_entries(browser); 388 browser->b.nr_entries = hist_browser__nr_entries(browser);
358 389
359 hist_browser__refresh_dimensions(browser); 390 hists__browser_title(browser->hists, title, sizeof(title));
360 hists__browser_title(browser->hists, title, sizeof(title), ev_name);
361 391
362 if (ui_browser__show(&browser->b, title, 392 if (ui_browser__show(&browser->b, title,
363 "Press '?' for help on key bindings") < 0) 393 "Press '?' for help on key bindings") < 0)
@@ -384,7 +414,7 @@ static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
384 ui_browser__warn_lost_events(&browser->b); 414 ui_browser__warn_lost_events(&browser->b);
385 } 415 }
386 416
387 hists__browser_title(browser->hists, title, sizeof(title), ev_name); 417 hists__browser_title(browser->hists, title, sizeof(title));
388 ui_browser__show_title(&browser->b, title); 418 ui_browser__show_title(&browser->b, title);
389 continue; 419 continue;
390 } 420 }
@@ -393,10 +423,10 @@ static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
393 struct hist_entry *h = rb_entry(browser->b.top, 423 struct hist_entry *h = rb_entry(browser->b.top,
394 struct hist_entry, rb_node); 424 struct hist_entry, rb_node);
395 ui_helpline__pop(); 425 ui_helpline__pop();
396 ui_helpline__fpush("%d: nr_ent=(%d,%d), height=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d", 426 ui_helpline__fpush("%d: nr_ent=(%d,%d), rows=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d",
397 seq++, browser->b.nr_entries, 427 seq++, browser->b.nr_entries,
398 browser->hists->nr_entries, 428 browser->hists->nr_entries,
399 browser->b.height, 429 browser->b.rows,
400 browser->b.index, 430 browser->b.index,
401 browser->b.top_idx, 431 browser->b.top_idx,
402 h->row_offset, h->nr_rows); 432 h->row_offset, h->nr_rows);
@@ -410,6 +440,10 @@ static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
410 /* Expand the whole world. */ 440 /* Expand the whole world. */
411 hist_browser__set_folding(browser, true); 441 hist_browser__set_folding(browser, true);
412 break; 442 break;
443 case 'H':
444 browser->show_headers = !browser->show_headers;
445 hist_browser__update_rows(browser);
446 break;
413 case K_ENTER: 447 case K_ENTER:
414 if (hist_browser__toggle_fold(browser)) 448 if (hist_browser__toggle_fold(browser))
415 break; 449 break;
@@ -509,13 +543,13 @@ static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browse
509 } 543 }
510 544
511 ui_browser__set_color(&browser->b, color); 545 ui_browser__set_color(&browser->b, color);
512 ui_browser__gotorc(&browser->b, row, 0); 546 hist_browser__gotorc(browser, row, 0);
513 slsmg_write_nstring(" ", offset + extra_offset); 547 slsmg_write_nstring(" ", offset + extra_offset);
514 slsmg_printf("%c ", folded_sign); 548 slsmg_printf("%c ", folded_sign);
515 slsmg_write_nstring(str, width); 549 slsmg_write_nstring(str, width);
516 free(alloc_str); 550 free(alloc_str);
517 551
518 if (++row == browser->b.height) 552 if (++row == browser->b.rows)
519 goto out; 553 goto out;
520do_next: 554do_next:
521 if (folded_sign == '+') 555 if (folded_sign == '+')
@@ -528,7 +562,7 @@ do_next:
528 new_level, row, row_offset, 562 new_level, row, row_offset,
529 is_current_entry); 563 is_current_entry);
530 } 564 }
531 if (row == browser->b.height) 565 if (row == browser->b.rows)
532 goto out; 566 goto out;
533 node = next; 567 node = next;
534 } 568 }
@@ -568,13 +602,13 @@ static int hist_browser__show_callchain_node(struct hist_browser *browser,
568 602
569 s = callchain_list__sym_name(chain, bf, sizeof(bf), 603 s = callchain_list__sym_name(chain, bf, sizeof(bf),
570 browser->show_dso); 604 browser->show_dso);
571 ui_browser__gotorc(&browser->b, row, 0); 605 hist_browser__gotorc(browser, row, 0);
572 ui_browser__set_color(&browser->b, color); 606 ui_browser__set_color(&browser->b, color);
573 slsmg_write_nstring(" ", offset); 607 slsmg_write_nstring(" ", offset);
574 slsmg_printf("%c ", folded_sign); 608 slsmg_printf("%c ", folded_sign);
575 slsmg_write_nstring(s, width - 2); 609 slsmg_write_nstring(s, width - 2);
576 610
577 if (++row == browser->b.height) 611 if (++row == browser->b.rows)
578 goto out; 612 goto out;
579 } 613 }
580 614
@@ -603,7 +637,7 @@ static int hist_browser__show_callchain(struct hist_browser *browser,
603 row += hist_browser__show_callchain_node(browser, node, level, 637 row += hist_browser__show_callchain_node(browser, node, level,
604 row, row_offset, 638 row, row_offset,
605 is_current_entry); 639 is_current_entry);
606 if (row == browser->b.height) 640 if (row == browser->b.rows)
607 break; 641 break;
608 } 642 }
609 643
@@ -733,7 +767,7 @@ static int hist_browser__show_entry(struct hist_browser *browser,
733 .ptr = &arg, 767 .ptr = &arg,
734 }; 768 };
735 769
736 ui_browser__gotorc(&browser->b, row, 0); 770 hist_browser__gotorc(browser, row, 0);
737 771
738 perf_hpp__for_each_format(fmt) { 772 perf_hpp__for_each_format(fmt) {
739 if (perf_hpp__should_skip(fmt)) 773 if (perf_hpp__should_skip(fmt))
@@ -777,7 +811,7 @@ static int hist_browser__show_entry(struct hist_browser *browser,
777 } else 811 } else
778 --row_offset; 812 --row_offset;
779 813
780 if (folded_sign == '-' && row != browser->b.height) { 814 if (folded_sign == '-' && row != browser->b.rows) {
781 printed += hist_browser__show_callchain(browser, &entry->sorted_chain, 815 printed += hist_browser__show_callchain(browser, &entry->sorted_chain,
782 1, row, &row_offset, 816 1, row, &row_offset,
783 &current_entry); 817 &current_entry);
@@ -788,6 +822,56 @@ static int hist_browser__show_entry(struct hist_browser *browser,
788 return printed; 822 return printed;
789} 823}
790 824
825static int advance_hpp_check(struct perf_hpp *hpp, int inc)
826{
827 advance_hpp(hpp, inc);
828 return hpp->size <= 0;
829}
830
831static int hists__scnprintf_headers(char *buf, size_t size, struct hists *hists)
832{
833 struct perf_hpp dummy_hpp = {
834 .buf = buf,
835 .size = size,
836 };
837 struct perf_hpp_fmt *fmt;
838 size_t ret = 0;
839
840 if (symbol_conf.use_callchain) {
841 ret = scnprintf(buf, size, " ");
842 if (advance_hpp_check(&dummy_hpp, ret))
843 return ret;
844 }
845
846 perf_hpp__for_each_format(fmt) {
847 if (perf_hpp__should_skip(fmt))
848 continue;
849
850 /* We need to add the length of the columns header. */
851 perf_hpp__reset_width(fmt, hists);
852
853 ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
854 if (advance_hpp_check(&dummy_hpp, ret))
855 break;
856
857 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
858 if (advance_hpp_check(&dummy_hpp, ret))
859 break;
860 }
861
862 return ret;
863}
864
865static void hist_browser__show_headers(struct hist_browser *browser)
866{
867 char headers[1024];
868
869 hists__scnprintf_headers(headers, sizeof(headers), browser->hists);
870 ui_browser__gotorc(&browser->b, 0, 0);
871 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
872 slsmg_write_nstring(headers, browser->b.width + 1);
873}
874
791static void ui_browser__hists_init_top(struct ui_browser *browser) 875static void ui_browser__hists_init_top(struct ui_browser *browser)
792{ 876{
793 if (browser->top == NULL) { 877 if (browser->top == NULL) {
@@ -801,9 +885,15 @@ static void ui_browser__hists_init_top(struct ui_browser *browser)
801static unsigned int hist_browser__refresh(struct ui_browser *browser) 885static unsigned int hist_browser__refresh(struct ui_browser *browser)
802{ 886{
803 unsigned row = 0; 887 unsigned row = 0;
888 u16 header_offset = 0;
804 struct rb_node *nd; 889 struct rb_node *nd;
805 struct hist_browser *hb = container_of(browser, struct hist_browser, b); 890 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
806 891
892 if (hb->show_headers) {
893 hist_browser__show_headers(hb);
894 header_offset = 1;
895 }
896
807 ui_browser__hists_init_top(browser); 897 ui_browser__hists_init_top(browser);
808 898
809 for (nd = browser->top; nd; nd = rb_next(nd)) { 899 for (nd = browser->top; nd; nd = rb_next(nd)) {
@@ -818,11 +908,11 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)
818 continue; 908 continue;
819 909
820 row += hist_browser__show_entry(hb, h, row); 910 row += hist_browser__show_entry(hb, h, row);
821 if (row == browser->height) 911 if (row == browser->rows)
822 break; 912 break;
823 } 913 }
824 914
825 return row; 915 return row + header_offset;
826} 916}
827 917
828static struct rb_node *hists__filter_entries(struct rb_node *nd, 918static struct rb_node *hists__filter_entries(struct rb_node *nd,
@@ -1191,8 +1281,10 @@ static struct hist_browser *hist_browser__new(struct hists *hists)
1191 if (browser) { 1281 if (browser) {
1192 browser->hists = hists; 1282 browser->hists = hists;
1193 browser->b.refresh = hist_browser__refresh; 1283 browser->b.refresh = hist_browser__refresh;
1284 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
1194 browser->b.seek = ui_browser__hists_seek; 1285 browser->b.seek = ui_browser__hists_seek;
1195 browser->b.use_navkeypressed = true; 1286 browser->b.use_navkeypressed = true;
1287 browser->show_headers = symbol_conf.show_hist_headers;
1196 } 1288 }
1197 1289
1198 return browser; 1290 return browser;
@@ -1213,8 +1305,7 @@ static struct thread *hist_browser__selected_thread(struct hist_browser *browser
1213 return browser->he_selection->thread; 1305 return browser->he_selection->thread;
1214} 1306}
1215 1307
1216static int hists__browser_title(struct hists *hists, char *bf, size_t size, 1308static int hists__browser_title(struct hists *hists, char *bf, size_t size)
1217 const char *ev_name)
1218{ 1309{
1219 char unit; 1310 char unit;
1220 int printed; 1311 int printed;
@@ -1223,6 +1314,7 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size,
1223 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE]; 1314 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1224 u64 nr_events = hists->stats.total_period; 1315 u64 nr_events = hists->stats.total_period;
1225 struct perf_evsel *evsel = hists_to_evsel(hists); 1316 struct perf_evsel *evsel = hists_to_evsel(hists);
1317 const char *ev_name = perf_evsel__name(evsel);
1226 char buf[512]; 1318 char buf[512];
1227 size_t buflen = sizeof(buf); 1319 size_t buflen = sizeof(buf);
1228 1320
@@ -1390,7 +1482,7 @@ static void hist_browser__update_nr_entries(struct hist_browser *hb)
1390} 1482}
1391 1483
1392static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, 1484static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1393 const char *helpline, const char *ev_name, 1485 const char *helpline,
1394 bool left_exits, 1486 bool left_exits,
1395 struct hist_browser_timer *hbt, 1487 struct hist_browser_timer *hbt,
1396 float min_pcnt, 1488 float min_pcnt,
@@ -1422,6 +1514,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1422 "d Zoom into current DSO\n" \ 1514 "d Zoom into current DSO\n" \
1423 "E Expand all callchains\n" \ 1515 "E Expand all callchains\n" \
1424 "F Toggle percentage of filtered entries\n" \ 1516 "F Toggle percentage of filtered entries\n" \
1517 "H Display column headers\n" \
1425 1518
1426 /* help messages are sorted by lexical order of the hotkey */ 1519 /* help messages are sorted by lexical order of the hotkey */
1427 const char report_help[] = HIST_BROWSER_HELP_COMMON 1520 const char report_help[] = HIST_BROWSER_HELP_COMMON
@@ -1465,7 +1558,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1465 1558
1466 nr_options = 0; 1559 nr_options = 0;
1467 1560
1468 key = hist_browser__run(browser, ev_name, hbt); 1561 key = hist_browser__run(browser, hbt);
1469 1562
1470 if (browser->he_selection != NULL) { 1563 if (browser->he_selection != NULL) {
1471 thread = hist_browser__selected_thread(browser); 1564 thread = hist_browser__selected_thread(browser);
@@ -1843,7 +1936,7 @@ static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1843{ 1936{
1844 struct perf_evlist *evlist = menu->b.priv; 1937 struct perf_evlist *evlist = menu->b.priv;
1845 struct perf_evsel *pos; 1938 struct perf_evsel *pos;
1846 const char *ev_name, *title = "Available samples"; 1939 const char *title = "Available samples";
1847 int delay_secs = hbt ? hbt->refresh : 0; 1940 int delay_secs = hbt ? hbt->refresh : 0;
1848 int key; 1941 int key;
1849 1942
@@ -1876,9 +1969,8 @@ browse_hists:
1876 */ 1969 */
1877 if (hbt) 1970 if (hbt)
1878 hbt->timer(hbt->arg); 1971 hbt->timer(hbt->arg);
1879 ev_name = perf_evsel__name(pos);
1880 key = perf_evsel__hists_browse(pos, nr_events, help, 1972 key = perf_evsel__hists_browse(pos, nr_events, help,
1881 ev_name, true, hbt, 1973 true, hbt,
1882 menu->min_pcnt, 1974 menu->min_pcnt,
1883 menu->env); 1975 menu->env);
1884 ui_browser__show_title(&menu->b, title); 1976 ui_browser__show_title(&menu->b, title);
@@ -1982,10 +2074,9 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
1982single_entry: 2074single_entry:
1983 if (nr_entries == 1) { 2075 if (nr_entries == 1) {
1984 struct perf_evsel *first = perf_evlist__first(evlist); 2076 struct perf_evsel *first = perf_evlist__first(evlist);
1985 const char *ev_name = perf_evsel__name(first);
1986 2077
1987 return perf_evsel__hists_browse(first, nr_entries, help, 2078 return perf_evsel__hists_browse(first, nr_entries, help,
1988 ev_name, false, hbt, min_pcnt, 2079 false, hbt, min_pcnt,
1989 env); 2080 env);
1990 } 2081 }
1991 2082
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index 90122abd3721..40af0acb4fe9 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -479,7 +479,7 @@ print_entries:
479 479
480 if (h->ms.map == NULL && verbose > 1) { 480 if (h->ms.map == NULL && verbose > 1) {
481 __map_groups__fprintf_maps(h->thread->mg, 481 __map_groups__fprintf_maps(h->thread->mg,
482 MAP__FUNCTION, verbose, fp); 482 MAP__FUNCTION, fp);
483 fprintf(fp, "%.10s end\n", graph_dotted_line); 483 fprintf(fp, "%.10s end\n", graph_dotted_line);
484 } 484 }
485 } 485 }
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 48b6d3f50012..437ee09727e6 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -626,7 +626,7 @@ int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent
626 626
627int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample) 627int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample)
628{ 628{
629 if (!symbol_conf.use_callchain) 629 if (!symbol_conf.use_callchain || sample->callchain == NULL)
630 return 0; 630 return 0;
631 return callchain_append(he->callchain, &callchain_cursor, sample->period); 631 return callchain_append(he->callchain, &callchain_cursor, sample->period);
632} 632}
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 8f84423a75da..da43619d6173 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -176,4 +176,17 @@ static inline void callchain_cursor_snapshot(struct callchain_cursor *dest,
176 dest->first = src->curr; 176 dest->first = src->curr;
177 dest->nr -= src->pos; 177 dest->nr -= src->pos;
178} 178}
179
180#ifdef HAVE_SKIP_CALLCHAIN_IDX
181extern int arch_skip_callchain_idx(struct machine *machine,
182 struct thread *thread, struct ip_callchain *chain);
183#else
184static inline int arch_skip_callchain_idx(struct machine *machine __maybe_unused,
185 struct thread *thread __maybe_unused,
186 struct ip_callchain *chain __maybe_unused)
187{
188 return -1;
189}
190#endif
191
179#endif /* __PERF_CALLCHAIN_H */ 192#endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/cloexec.c b/tools/perf/util/cloexec.c
new file mode 100644
index 000000000000..c5d05ec17220
--- /dev/null
+++ b/tools/perf/util/cloexec.c
@@ -0,0 +1,57 @@
1#include "util.h"
2#include "../perf.h"
3#include "cloexec.h"
4#include "asm/bug.h"
5
6static unsigned long flag = PERF_FLAG_FD_CLOEXEC;
7
8static int perf_flag_probe(void)
9{
10 /* use 'safest' configuration as used in perf_evsel__fallback() */
11 struct perf_event_attr attr = {
12 .type = PERF_COUNT_SW_CPU_CLOCK,
13 .config = PERF_COUNT_SW_CPU_CLOCK,
14 };
15 int fd;
16 int err;
17
18 /* check cloexec flag */
19 fd = sys_perf_event_open(&attr, 0, -1, -1,
20 PERF_FLAG_FD_CLOEXEC);
21 err = errno;
22
23 if (fd >= 0) {
24 close(fd);
25 return 1;
26 }
27
28 WARN_ONCE(err != EINVAL,
29 "perf_event_open(..., PERF_FLAG_FD_CLOEXEC) failed with unexpected error %d (%s)\n",
30 err, strerror(err));
31
32 /* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */
33 fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
34 err = errno;
35
36 if (WARN_ONCE(fd < 0,
37 "perf_event_open(..., 0) failed unexpectedly with error %d (%s)\n",
38 err, strerror(err)))
39 return -1;
40
41 close(fd);
42
43 return 0;
44}
45
46unsigned long perf_event_open_cloexec_flag(void)
47{
48 static bool probed;
49
50 if (!probed) {
51 if (perf_flag_probe() <= 0)
52 flag = 0;
53 probed = true;
54 }
55
56 return flag;
57}
diff --git a/tools/perf/util/cloexec.h b/tools/perf/util/cloexec.h
new file mode 100644
index 000000000000..94a5a7d829d5
--- /dev/null
+++ b/tools/perf/util/cloexec.h
@@ -0,0 +1,6 @@
1#ifndef __PERF_CLOEXEC_H
2#define __PERF_CLOEXEC_H
3
4unsigned long perf_event_open_cloexec_flag(void);
5
6#endif /* __PERF_CLOEXEC_H */
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index 24519e14ac56..1e5e2e5af6b1 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -350,6 +350,16 @@ static int perf_default_core_config(const char *var __maybe_unused,
350 return 0; 350 return 0;
351} 351}
352 352
353static int perf_ui_config(const char *var, const char *value)
354{
355 /* Add other config variables here. */
356 if (!strcmp(var, "ui.show-headers")) {
357 symbol_conf.show_hist_headers = perf_config_bool(var, value);
358 return 0;
359 }
360 return 0;
361}
362
353int perf_default_config(const char *var, const char *value, 363int perf_default_config(const char *var, const char *value,
354 void *dummy __maybe_unused) 364 void *dummy __maybe_unused)
355{ 365{
@@ -359,6 +369,9 @@ int perf_default_config(const char *var, const char *value,
359 if (!prefixcmp(var, "hist.")) 369 if (!prefixcmp(var, "hist."))
360 return perf_hist_config(var, value); 370 return perf_hist_config(var, value);
361 371
372 if (!prefixcmp(var, "ui."))
373 return perf_ui_config(var, value);
374
362 /* Add other config variables here. */ 375 /* Add other config variables here. */
363 return 0; 376 return 0;
364} 377}
diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c
index 55de44ecebef..29d720cf5844 100644
--- a/tools/perf/util/data.c
+++ b/tools/perf/util/data.c
@@ -7,6 +7,7 @@
7 7
8#include "data.h" 8#include "data.h"
9#include "util.h" 9#include "util.h"
10#include "debug.h"
10 11
11static bool check_pipe(struct perf_data_file *file) 12static bool check_pipe(struct perf_data_file *file)
12{ 13{
@@ -65,7 +66,7 @@ static int open_file_read(struct perf_data_file *file)
65 goto out_close; 66 goto out_close;
66 67
67 if (!file->force && st.st_uid && (st.st_uid != geteuid())) { 68 if (!file->force && st.st_uid && (st.st_uid != geteuid())) {
68 pr_err("file %s not owned by current user or root\n", 69 pr_err("File %s not owned by current user or root (use -f to override)\n",
69 file->path); 70 file->path);
70 goto out_close; 71 goto out_close;
71 } 72 }
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index 299b55586502..71d419362634 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -16,11 +16,11 @@
16int verbose; 16int verbose;
17bool dump_trace = false, quiet = false; 17bool dump_trace = false, quiet = false;
18 18
19static int _eprintf(int level, const char *fmt, va_list args) 19static int _eprintf(int level, int var, const char *fmt, va_list args)
20{ 20{
21 int ret = 0; 21 int ret = 0;
22 22
23 if (verbose >= level) { 23 if (var >= level) {
24 if (use_browser >= 1) 24 if (use_browser >= 1)
25 ui_helpline__vshow(fmt, args); 25 ui_helpline__vshow(fmt, args);
26 else 26 else
@@ -30,13 +30,13 @@ static int _eprintf(int level, const char *fmt, va_list args)
30 return ret; 30 return ret;
31} 31}
32 32
33int eprintf(int level, const char *fmt, ...) 33int eprintf(int level, int var, const char *fmt, ...)
34{ 34{
35 va_list args; 35 va_list args;
36 int ret; 36 int ret;
37 37
38 va_start(args, fmt); 38 va_start(args, fmt);
39 ret = _eprintf(level, fmt, args); 39 ret = _eprintf(level, var, fmt, args);
40 va_end(args); 40 va_end(args);
41 41
42 return ret; 42 return ret;
@@ -51,9 +51,9 @@ void pr_stat(const char *fmt, ...)
51 va_list args; 51 va_list args;
52 52
53 va_start(args, fmt); 53 va_start(args, fmt);
54 _eprintf(1, fmt, args); 54 _eprintf(1, verbose, fmt, args);
55 va_end(args); 55 va_end(args);
56 eprintf(1, "\n"); 56 eprintf(1, verbose, "\n");
57} 57}
58 58
59int dump_printf(const char *fmt, ...) 59int dump_printf(const char *fmt, ...)
@@ -105,3 +105,47 @@ void trace_event(union perf_event *event)
105 } 105 }
106 printf(".\n"); 106 printf(".\n");
107} 107}
108
109static struct debug_variable {
110 const char *name;
111 int *ptr;
112} debug_variables[] = {
113 { .name = "verbose", .ptr = &verbose },
114 { .name = NULL, }
115};
116
117int perf_debug_option(const char *str)
118{
119 struct debug_variable *var = &debug_variables[0];
120 char *vstr, *s = strdup(str);
121 int v = 1;
122
123 vstr = strchr(s, '=');
124 if (vstr)
125 *vstr++ = 0;
126
127 while (var->name) {
128 if (!strcmp(s, var->name))
129 break;
130 var++;
131 }
132
133 if (!var->name) {
134 pr_err("Unknown debug variable name '%s'\n", s);
135 free(s);
136 return -1;
137 }
138
139 if (vstr) {
140 v = atoi(vstr);
141 /*
142 * Allow only values in range (0, 10),
143 * otherwise set 0.
144 */
145 v = (v < 0) || (v > 10) ? 0 : v;
146 }
147
148 *var->ptr = v;
149 free(s);
150 return 0;
151}
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index 443694c36b03..89fb6b0f7ab2 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -11,6 +11,24 @@
11extern int verbose; 11extern int verbose;
12extern bool quiet, dump_trace; 12extern bool quiet, dump_trace;
13 13
14#ifndef pr_fmt
15#define pr_fmt(fmt) fmt
16#endif
17
18#define pr_err(fmt, ...) \
19 eprintf(0, verbose, pr_fmt(fmt), ##__VA_ARGS__)
20#define pr_warning(fmt, ...) \
21 eprintf(0, verbose, pr_fmt(fmt), ##__VA_ARGS__)
22#define pr_info(fmt, ...) \
23 eprintf(0, verbose, pr_fmt(fmt), ##__VA_ARGS__)
24#define pr_debug(fmt, ...) \
25 eprintf(1, verbose, pr_fmt(fmt), ##__VA_ARGS__)
26#define pr_debugN(n, fmt, ...) \
27 eprintf(n, verbose, pr_fmt(fmt), ##__VA_ARGS__)
28#define pr_debug2(fmt, ...) pr_debugN(2, pr_fmt(fmt), ##__VA_ARGS__)
29#define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__)
30#define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__)
31
14int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); 32int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
15void trace_event(union perf_event *event); 33void trace_event(union perf_event *event);
16 34
@@ -19,4 +37,8 @@ int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2)));
19 37
20void pr_stat(const char *fmt, ...); 38void pr_stat(const char *fmt, ...);
21 39
40int eprintf(int level, int var, const char *fmt, ...) __attribute__((format(printf, 3, 4)));
41
42int perf_debug_option(const char *str);
43
22#endif /* __PERF_DEBUG_H */ 44#endif /* __PERF_DEBUG_H */
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index 819f10414f08..90d02c661dd4 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -216,7 +216,7 @@ static int open_dso(struct dso *dso, struct machine *machine)
216{ 216{
217 int fd = __open_dso(dso, machine); 217 int fd = __open_dso(dso, machine);
218 218
219 if (fd > 0) { 219 if (fd >= 0) {
220 dso__list_add(dso); 220 dso__list_add(dso);
221 /* 221 /*
222 * Check if we crossed the allowed number 222 * Check if we crossed the allowed number
@@ -331,26 +331,44 @@ int dso__data_fd(struct dso *dso, struct machine *machine)
331 }; 331 };
332 int i = 0; 332 int i = 0;
333 333
334 if (dso->data.status == DSO_DATA_STATUS_ERROR)
335 return -1;
336
334 if (dso->data.fd >= 0) 337 if (dso->data.fd >= 0)
335 return dso->data.fd; 338 goto out;
336 339
337 if (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND) { 340 if (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND) {
338 dso->data.fd = open_dso(dso, machine); 341 dso->data.fd = open_dso(dso, machine);
339 return dso->data.fd; 342 goto out;
340 } 343 }
341 344
342 do { 345 do {
343 int fd;
344
345 dso->binary_type = binary_type_data[i++]; 346 dso->binary_type = binary_type_data[i++];
346 347
347 fd = open_dso(dso, machine); 348 dso->data.fd = open_dso(dso, machine);
348 if (fd >= 0) 349 if (dso->data.fd >= 0)
349 return dso->data.fd = fd; 350 goto out;
350 351
351 } while (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND); 352 } while (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND);
353out:
354 if (dso->data.fd >= 0)
355 dso->data.status = DSO_DATA_STATUS_OK;
356 else
357 dso->data.status = DSO_DATA_STATUS_ERROR;
352 358
353 return -EINVAL; 359 return dso->data.fd;
360}
361
362bool dso__data_status_seen(struct dso *dso, enum dso_data_status_seen by)
363{
364 u32 flag = 1 << by;
365
366 if (dso->data.status_seen & flag)
367 return true;
368
369 dso->data.status_seen |= flag;
370
371 return false;
354} 372}
355 373
356static void 374static void
@@ -526,6 +544,28 @@ static int data_file_size(struct dso *dso)
526 return 0; 544 return 0;
527} 545}
528 546
547/**
548 * dso__data_size - Return dso data size
549 * @dso: dso object
550 * @machine: machine object
551 *
552 * Return: dso data size
553 */
554off_t dso__data_size(struct dso *dso, struct machine *machine)
555{
556 int fd;
557
558 fd = dso__data_fd(dso, machine);
559 if (fd < 0)
560 return fd;
561
562 if (data_file_size(dso))
563 return -1;
564
565 /* For now just estimate dso data size is close to file size */
566 return dso->data.file_size;
567}
568
529static ssize_t data_read_offset(struct dso *dso, u64 offset, 569static ssize_t data_read_offset(struct dso *dso, u64 offset,
530 u8 *data, ssize_t size) 570 u8 *data, ssize_t size)
531{ 571{
@@ -701,8 +741,10 @@ struct dso *dso__new(const char *name)
701 dso->symbols[i] = dso->symbol_names[i] = RB_ROOT; 741 dso->symbols[i] = dso->symbol_names[i] = RB_ROOT;
702 dso->data.cache = RB_ROOT; 742 dso->data.cache = RB_ROOT;
703 dso->data.fd = -1; 743 dso->data.fd = -1;
744 dso->data.status = DSO_DATA_STATUS_UNKNOWN;
704 dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND; 745 dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND;
705 dso->binary_type = DSO_BINARY_TYPE__NOT_FOUND; 746 dso->binary_type = DSO_BINARY_TYPE__NOT_FOUND;
747 dso->is_64_bit = (sizeof(void *) == 8);
706 dso->loaded = 0; 748 dso->loaded = 0;
707 dso->rel = 0; 749 dso->rel = 0;
708 dso->sorted_by_name = 0; 750 dso->sorted_by_name = 0;
@@ -898,3 +940,14 @@ size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp)
898 940
899 return ret; 941 return ret;
900} 942}
943
944enum dso_type dso__type(struct dso *dso, struct machine *machine)
945{
946 int fd;
947
948 fd = dso__data_fd(dso, machine);
949 if (fd < 0)
950 return DSO__TYPE_UNKNOWN;
951
952 return dso__type_fd(fd);
953}
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index ad553ba257bf..5e463c0964d4 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -5,6 +5,7 @@
5#include <linux/rbtree.h> 5#include <linux/rbtree.h>
6#include <stdbool.h> 6#include <stdbool.h>
7#include <linux/types.h> 7#include <linux/types.h>
8#include <linux/bitops.h>
8#include "map.h" 9#include "map.h"
9#include "build-id.h" 10#include "build-id.h"
10 11
@@ -40,6 +41,23 @@ enum dso_swap_type {
40 DSO_SWAP__YES, 41 DSO_SWAP__YES,
41}; 42};
42 43
44enum dso_data_status {
45 DSO_DATA_STATUS_ERROR = -1,
46 DSO_DATA_STATUS_UNKNOWN = 0,
47 DSO_DATA_STATUS_OK = 1,
48};
49
50enum dso_data_status_seen {
51 DSO_DATA_STATUS_SEEN_ITRACE,
52};
53
54enum dso_type {
55 DSO__TYPE_UNKNOWN,
56 DSO__TYPE_64BIT,
57 DSO__TYPE_32BIT,
58 DSO__TYPE_X32BIT,
59};
60
43#define DSO__SWAP(dso, type, val) \ 61#define DSO__SWAP(dso, type, val) \
44({ \ 62({ \
45 type ____r = val; \ 63 type ____r = val; \
@@ -90,6 +108,7 @@ struct dso {
90 u8 annotate_warned:1; 108 u8 annotate_warned:1;
91 u8 short_name_allocated:1; 109 u8 short_name_allocated:1;
92 u8 long_name_allocated:1; 110 u8 long_name_allocated:1;
111 u8 is_64_bit:1;
93 u8 sorted_by_name; 112 u8 sorted_by_name;
94 u8 loaded; 113 u8 loaded;
95 u8 rel; 114 u8 rel;
@@ -103,6 +122,8 @@ struct dso {
103 struct { 122 struct {
104 struct rb_root cache; 123 struct rb_root cache;
105 int fd; 124 int fd;
125 int status;
126 u32 status_seen;
106 size_t file_size; 127 size_t file_size;
107 struct list_head open_entry; 128 struct list_head open_entry;
108 } data; 129 } data;
@@ -153,6 +174,7 @@ int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type t
153 * The dso__data_* external interface provides following functions: 174 * The dso__data_* external interface provides following functions:
154 * dso__data_fd 175 * dso__data_fd
155 * dso__data_close 176 * dso__data_close
177 * dso__data_size
156 * dso__data_read_offset 178 * dso__data_read_offset
157 * dso__data_read_addr 179 * dso__data_read_addr
158 * 180 *
@@ -190,11 +212,13 @@ int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type t
190int dso__data_fd(struct dso *dso, struct machine *machine); 212int dso__data_fd(struct dso *dso, struct machine *machine);
191void dso__data_close(struct dso *dso); 213void dso__data_close(struct dso *dso);
192 214
215off_t dso__data_size(struct dso *dso, struct machine *machine);
193ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, 216ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
194 u64 offset, u8 *data, ssize_t size); 217 u64 offset, u8 *data, ssize_t size);
195ssize_t dso__data_read_addr(struct dso *dso, struct map *map, 218ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
196 struct machine *machine, u64 addr, 219 struct machine *machine, u64 addr,
197 u8 *data, ssize_t size); 220 u8 *data, ssize_t size);
221bool dso__data_status_seen(struct dso *dso, enum dso_data_status_seen by);
198 222
199struct map *dso__new_map(const char *name); 223struct map *dso__new_map(const char *name);
200struct dso *dso__kernel_findnew(struct machine *machine, const char *name, 224struct dso *dso__kernel_findnew(struct machine *machine, const char *name,
@@ -229,4 +253,6 @@ static inline bool dso__is_kcore(struct dso *dso)
229 253
230void dso__free_a2l(struct dso *dso); 254void dso__free_a2l(struct dso *dso);
231 255
256enum dso_type dso__type(struct dso *dso, struct machine *machine);
257
232#endif /* __PERF_DSO */ 258#endif /* __PERF_DSO */
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index d0281bdfa582..1398c83d896d 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -603,7 +603,14 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
603 603
604size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp) 604size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp)
605{ 605{
606 return fprintf(fp, ": %s:%d\n", event->comm.comm, event->comm.tid); 606 const char *s;
607
608 if (event->header.misc & PERF_RECORD_MISC_COMM_EXEC)
609 s = " exec";
610 else
611 s = "";
612
613 return fprintf(fp, "%s: %s:%d\n", s, event->comm.comm, event->comm.tid);
607} 614}
608 615
609int perf_event__process_comm(struct perf_tool *tool __maybe_unused, 616int perf_event__process_comm(struct perf_tool *tool __maybe_unused,
@@ -781,6 +788,7 @@ try_again:
781 cpumode == PERF_RECORD_MISC_USER && 788 cpumode == PERF_RECORD_MISC_USER &&
782 machine && mg != &machine->kmaps) { 789 machine && mg != &machine->kmaps) {
783 mg = &machine->kmaps; 790 mg = &machine->kmaps;
791 load_map = true;
784 goto try_again; 792 goto try_again;
785 } 793 }
786 } else { 794 } else {
@@ -866,3 +874,45 @@ int perf_event__preprocess_sample(const union perf_event *event,
866 874
867 return 0; 875 return 0;
868} 876}
877
878bool is_bts_event(struct perf_event_attr *attr)
879{
880 return attr->type == PERF_TYPE_HARDWARE &&
881 (attr->config & PERF_COUNT_HW_BRANCH_INSTRUCTIONS) &&
882 attr->sample_period == 1;
883}
884
885bool sample_addr_correlates_sym(struct perf_event_attr *attr)
886{
887 if (attr->type == PERF_TYPE_SOFTWARE &&
888 (attr->config == PERF_COUNT_SW_PAGE_FAULTS ||
889 attr->config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
890 attr->config == PERF_COUNT_SW_PAGE_FAULTS_MAJ))
891 return true;
892
893 if (is_bts_event(attr))
894 return true;
895
896 return false;
897}
898
899void perf_event__preprocess_sample_addr(union perf_event *event,
900 struct perf_sample *sample,
901 struct machine *machine,
902 struct thread *thread,
903 struct addr_location *al)
904{
905 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
906
907 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
908 sample->addr, al);
909 if (!al->map)
910 thread__find_addr_map(thread, machine, cpumode, MAP__VARIABLE,
911 sample->addr, al);
912
913 al->cpu = sample->cpu;
914 al->sym = NULL;
915
916 if (al->map)
917 al->sym = map__find_symbol(al->map, al->addr, NULL);
918}
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index e5dd40addb30..94d6976180da 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -288,6 +288,16 @@ int perf_event__preprocess_sample(const union perf_event *event,
288 struct addr_location *al, 288 struct addr_location *al,
289 struct perf_sample *sample); 289 struct perf_sample *sample);
290 290
291struct thread;
292
293bool is_bts_event(struct perf_event_attr *attr);
294bool sample_addr_correlates_sym(struct perf_event_attr *attr);
295void perf_event__preprocess_sample_addr(union perf_event *event,
296 struct perf_sample *sample,
297 struct machine *machine,
298 struct thread *thread,
299 struct addr_location *al);
300
291const char *perf_event__name(unsigned int id); 301const char *perf_event__name(unsigned int id);
292 302
293size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, 303size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 59ef2802fcf6..814e954c1318 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -606,12 +606,17 @@ static int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
606 return evlist->mmap != NULL ? 0 : -ENOMEM; 606 return evlist->mmap != NULL ? 0 : -ENOMEM;
607} 607}
608 608
609static int __perf_evlist__mmap(struct perf_evlist *evlist, 609struct mmap_params {
610 int idx, int prot, int mask, int fd) 610 int prot;
611 int mask;
612};
613
614static int __perf_evlist__mmap(struct perf_evlist *evlist, int idx,
615 struct mmap_params *mp, int fd)
611{ 616{
612 evlist->mmap[idx].prev = 0; 617 evlist->mmap[idx].prev = 0;
613 evlist->mmap[idx].mask = mask; 618 evlist->mmap[idx].mask = mp->mask;
614 evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, prot, 619 evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, mp->prot,
615 MAP_SHARED, fd, 0); 620 MAP_SHARED, fd, 0);
616 if (evlist->mmap[idx].base == MAP_FAILED) { 621 if (evlist->mmap[idx].base == MAP_FAILED) {
617 pr_debug2("failed to mmap perf event ring buffer, error %d\n", 622 pr_debug2("failed to mmap perf event ring buffer, error %d\n",
@@ -625,8 +630,8 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist,
625} 630}
626 631
627static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, 632static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
628 int prot, int mask, int cpu, int thread, 633 struct mmap_params *mp, int cpu,
629 int *output) 634 int thread, int *output)
630{ 635{
631 struct perf_evsel *evsel; 636 struct perf_evsel *evsel;
632 637
@@ -635,8 +640,7 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
635 640
636 if (*output == -1) { 641 if (*output == -1) {
637 *output = fd; 642 *output = fd;
638 if (__perf_evlist__mmap(evlist, idx, prot, mask, 643 if (__perf_evlist__mmap(evlist, idx, mp, *output) < 0)
639 *output) < 0)
640 return -1; 644 return -1;
641 } else { 645 } else {
642 if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, *output) != 0) 646 if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, *output) != 0)
@@ -651,8 +655,8 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
651 return 0; 655 return 0;
652} 656}
653 657
654static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, 658static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist,
655 int mask) 659 struct mmap_params *mp)
656{ 660{
657 int cpu, thread; 661 int cpu, thread;
658 int nr_cpus = cpu_map__nr(evlist->cpus); 662 int nr_cpus = cpu_map__nr(evlist->cpus);
@@ -663,8 +667,8 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot,
663 int output = -1; 667 int output = -1;
664 668
665 for (thread = 0; thread < nr_threads; thread++) { 669 for (thread = 0; thread < nr_threads; thread++) {
666 if (perf_evlist__mmap_per_evsel(evlist, cpu, prot, mask, 670 if (perf_evlist__mmap_per_evsel(evlist, cpu, mp, cpu,
667 cpu, thread, &output)) 671 thread, &output))
668 goto out_unmap; 672 goto out_unmap;
669 } 673 }
670 } 674 }
@@ -677,8 +681,8 @@ out_unmap:
677 return -1; 681 return -1;
678} 682}
679 683
680static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, 684static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist,
681 int mask) 685 struct mmap_params *mp)
682{ 686{
683 int thread; 687 int thread;
684 int nr_threads = thread_map__nr(evlist->threads); 688 int nr_threads = thread_map__nr(evlist->threads);
@@ -687,8 +691,8 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot,
687 for (thread = 0; thread < nr_threads; thread++) { 691 for (thread = 0; thread < nr_threads; thread++) {
688 int output = -1; 692 int output = -1;
689 693
690 if (perf_evlist__mmap_per_evsel(evlist, thread, prot, mask, 0, 694 if (perf_evlist__mmap_per_evsel(evlist, thread, mp, 0, thread,
691 thread, &output)) 695 &output))
692 goto out_unmap; 696 goto out_unmap;
693 } 697 }
694 698
@@ -793,7 +797,9 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
793 struct perf_evsel *evsel; 797 struct perf_evsel *evsel;
794 const struct cpu_map *cpus = evlist->cpus; 798 const struct cpu_map *cpus = evlist->cpus;
795 const struct thread_map *threads = evlist->threads; 799 const struct thread_map *threads = evlist->threads;
796 int prot = PROT_READ | (overwrite ? 0 : PROT_WRITE), mask; 800 struct mmap_params mp = {
801 .prot = PROT_READ | (overwrite ? 0 : PROT_WRITE),
802 };
797 803
798 if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0) 804 if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0)
799 return -ENOMEM; 805 return -ENOMEM;
@@ -804,7 +810,7 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
804 evlist->overwrite = overwrite; 810 evlist->overwrite = overwrite;
805 evlist->mmap_len = perf_evlist__mmap_size(pages); 811 evlist->mmap_len = perf_evlist__mmap_size(pages);
806 pr_debug("mmap size %zuB\n", evlist->mmap_len); 812 pr_debug("mmap size %zuB\n", evlist->mmap_len);
807 mask = evlist->mmap_len - page_size - 1; 813 mp.mask = evlist->mmap_len - page_size - 1;
808 814
809 evlist__for_each(evlist, evsel) { 815 evlist__for_each(evlist, evsel) {
810 if ((evsel->attr.read_format & PERF_FORMAT_ID) && 816 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
@@ -814,9 +820,9 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
814 } 820 }
815 821
816 if (cpu_map__empty(cpus)) 822 if (cpu_map__empty(cpus))
817 return perf_evlist__mmap_per_thread(evlist, prot, mask); 823 return perf_evlist__mmap_per_thread(evlist, &mp);
818 824
819 return perf_evlist__mmap_per_cpu(evlist, prot, mask); 825 return perf_evlist__mmap_per_cpu(evlist, &mp);
820} 826}
821 827
822int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target) 828int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target)
@@ -1214,10 +1220,11 @@ int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused,
1214 "For your workloads it needs to be <= 1\nHint:\t"); 1220 "For your workloads it needs to be <= 1\nHint:\t");
1215 } 1221 }
1216 printed += scnprintf(buf + printed, size - printed, 1222 printed += scnprintf(buf + printed, size - printed,
1217 "For system wide tracing it needs to be set to -1"); 1223 "For system wide tracing it needs to be set to -1.\n");
1218 1224
1219 printed += scnprintf(buf + printed, size - printed, 1225 printed += scnprintf(buf + printed, size - printed,
1220 ".\nHint:\tThe current value is %d.", value); 1226 "Hint:\tTry: 'sudo sh -c \"echo -1 > /proc/sys/kernel/perf_event_paranoid\"'\n"
1227 "Hint:\tThe current value is %d.", value);
1221 break; 1228 break;
1222 default: 1229 default:
1223 scnprintf(buf, size, "%s", emsg); 1230 scnprintf(buf, size, "%s", emsg);
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 8606175fe1e8..21a373ebea22 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -29,6 +29,7 @@ static struct {
29 bool sample_id_all; 29 bool sample_id_all;
30 bool exclude_guest; 30 bool exclude_guest;
31 bool mmap2; 31 bool mmap2;
32 bool cloexec;
32} perf_missing_features; 33} perf_missing_features;
33 34
34#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) 35#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
@@ -623,7 +624,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
623 attr->mmap_data = track; 624 attr->mmap_data = track;
624 } 625 }
625 626
626 if (opts->call_graph_enabled) 627 if (opts->call_graph_enabled && !evsel->no_aux_samples)
627 perf_evsel__config_callgraph(evsel, opts); 628 perf_evsel__config_callgraph(evsel, opts);
628 629
629 if (target__has_cpu(&opts->target)) 630 if (target__has_cpu(&opts->target))
@@ -637,7 +638,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
637 target__has_cpu(&opts->target) || per_cpu)) 638 target__has_cpu(&opts->target) || per_cpu))
638 perf_evsel__set_sample_bit(evsel, TIME); 639 perf_evsel__set_sample_bit(evsel, TIME);
639 640
640 if (opts->raw_samples) { 641 if (opts->raw_samples && !evsel->no_aux_samples) {
641 perf_evsel__set_sample_bit(evsel, TIME); 642 perf_evsel__set_sample_bit(evsel, TIME);
642 perf_evsel__set_sample_bit(evsel, RAW); 643 perf_evsel__set_sample_bit(evsel, RAW);
643 perf_evsel__set_sample_bit(evsel, CPU); 644 perf_evsel__set_sample_bit(evsel, CPU);
@@ -650,7 +651,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
650 attr->watermark = 0; 651 attr->watermark = 0;
651 attr->wakeup_events = 1; 652 attr->wakeup_events = 1;
652 } 653 }
653 if (opts->branch_stack) { 654 if (opts->branch_stack && !evsel->no_aux_samples) {
654 perf_evsel__set_sample_bit(evsel, BRANCH_STACK); 655 perf_evsel__set_sample_bit(evsel, BRANCH_STACK);
655 attr->branch_sample_type = opts->branch_stack; 656 attr->branch_sample_type = opts->branch_stack;
656 } 657 }
@@ -681,6 +682,11 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
681 if (target__none(&opts->target) && perf_evsel__is_group_leader(evsel) && 682 if (target__none(&opts->target) && perf_evsel__is_group_leader(evsel) &&
682 !opts->initial_delay) 683 !opts->initial_delay)
683 attr->enable_on_exec = 1; 684 attr->enable_on_exec = 1;
685
686 if (evsel->immediate) {
687 attr->disabled = 0;
688 attr->enable_on_exec = 0;
689 }
684} 690}
685 691
686int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) 692int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
@@ -960,6 +966,7 @@ static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp)
960 ret += PRINT_ATTR2(exclude_user, exclude_kernel); 966 ret += PRINT_ATTR2(exclude_user, exclude_kernel);
961 ret += PRINT_ATTR2(exclude_hv, exclude_idle); 967 ret += PRINT_ATTR2(exclude_hv, exclude_idle);
962 ret += PRINT_ATTR2(mmap, comm); 968 ret += PRINT_ATTR2(mmap, comm);
969 ret += PRINT_ATTR2(mmap2, comm_exec);
963 ret += PRINT_ATTR2(freq, inherit_stat); 970 ret += PRINT_ATTR2(freq, inherit_stat);
964 ret += PRINT_ATTR2(enable_on_exec, task); 971 ret += PRINT_ATTR2(enable_on_exec, task);
965 ret += PRINT_ATTR2(watermark, precise_ip); 972 ret += PRINT_ATTR2(watermark, precise_ip);
@@ -967,7 +974,6 @@ static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp)
967 ret += PRINT_ATTR2(exclude_host, exclude_guest); 974 ret += PRINT_ATTR2(exclude_host, exclude_guest);
968 ret += PRINT_ATTR2N("excl.callchain_kern", exclude_callchain_kernel, 975 ret += PRINT_ATTR2N("excl.callchain_kern", exclude_callchain_kernel,
969 "excl.callchain_user", exclude_callchain_user); 976 "excl.callchain_user", exclude_callchain_user);
970 ret += PRINT_ATTR_U32(mmap2);
971 977
972 ret += PRINT_ATTR_U32(wakeup_events); 978 ret += PRINT_ATTR_U32(wakeup_events);
973 ret += PRINT_ATTR_U32(wakeup_watermark); 979 ret += PRINT_ATTR_U32(wakeup_watermark);
@@ -989,7 +995,7 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
989 struct thread_map *threads) 995 struct thread_map *threads)
990{ 996{
991 int cpu, thread; 997 int cpu, thread;
992 unsigned long flags = 0; 998 unsigned long flags = PERF_FLAG_FD_CLOEXEC;
993 int pid = -1, err; 999 int pid = -1, err;
994 enum { NO_CHANGE, SET_TO_MAX, INCREASED_MAX } set_rlimit = NO_CHANGE; 1000 enum { NO_CHANGE, SET_TO_MAX, INCREASED_MAX } set_rlimit = NO_CHANGE;
995 1001
@@ -998,11 +1004,13 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
998 return -ENOMEM; 1004 return -ENOMEM;
999 1005
1000 if (evsel->cgrp) { 1006 if (evsel->cgrp) {
1001 flags = PERF_FLAG_PID_CGROUP; 1007 flags |= PERF_FLAG_PID_CGROUP;
1002 pid = evsel->cgrp->fd; 1008 pid = evsel->cgrp->fd;
1003 } 1009 }
1004 1010
1005fallback_missing_features: 1011fallback_missing_features:
1012 if (perf_missing_features.cloexec)
1013 flags &= ~(unsigned long)PERF_FLAG_FD_CLOEXEC;
1006 if (perf_missing_features.mmap2) 1014 if (perf_missing_features.mmap2)
1007 evsel->attr.mmap2 = 0; 1015 evsel->attr.mmap2 = 0;
1008 if (perf_missing_features.exclude_guest) 1016 if (perf_missing_features.exclude_guest)
@@ -1071,7 +1079,10 @@ try_fallback:
1071 if (err != -EINVAL || cpu > 0 || thread > 0) 1079 if (err != -EINVAL || cpu > 0 || thread > 0)
1072 goto out_close; 1080 goto out_close;
1073 1081
1074 if (!perf_missing_features.mmap2 && evsel->attr.mmap2) { 1082 if (!perf_missing_features.cloexec && (flags & PERF_FLAG_FD_CLOEXEC)) {
1083 perf_missing_features.cloexec = true;
1084 goto fallback_missing_features;
1085 } else if (!perf_missing_features.mmap2 && evsel->attr.mmap2) {
1075 perf_missing_features.mmap2 = true; 1086 perf_missing_features.mmap2 = true;
1076 goto fallback_missing_features; 1087 goto fallback_missing_features;
1077 } else if (!perf_missing_features.exclude_guest && 1088 } else if (!perf_missing_features.exclude_guest &&
@@ -1940,6 +1951,7 @@ int perf_evsel__fprintf(struct perf_evsel *evsel,
1940 if_print(mmap); 1951 if_print(mmap);
1941 if_print(mmap2); 1952 if_print(mmap2);
1942 if_print(comm); 1953 if_print(comm);
1954 if_print(comm_exec);
1943 if_print(freq); 1955 if_print(freq);
1944 if_print(inherit_stat); 1956 if_print(inherit_stat);
1945 if_print(enable_on_exec); 1957 if_print(enable_on_exec);
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index a52e9a5bb2d0..d7f93ce0ebc1 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -83,6 +83,8 @@ struct perf_evsel {
83 int is_pos; 83 int is_pos;
84 bool supported; 84 bool supported;
85 bool needs_swap; 85 bool needs_swap;
86 bool no_aux_samples;
87 bool immediate;
86 /* parse modifier helper */ 88 /* parse modifier helper */
87 int exclude_GH; 89 int exclude_GH;
88 int nr_members; 90 int nr_members;
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 893f8e2df928..158c787ce0c4 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -200,6 +200,47 @@ static int write_buildid(const char *name, size_t name_len, u8 *build_id,
200 return write_padded(fd, name, name_len + 1, len); 200 return write_padded(fd, name, name_len + 1, len);
201} 201}
202 202
203static int __dsos__hit_all(struct list_head *head)
204{
205 struct dso *pos;
206
207 list_for_each_entry(pos, head, node)
208 pos->hit = true;
209
210 return 0;
211}
212
213static int machine__hit_all_dsos(struct machine *machine)
214{
215 int err;
216
217 err = __dsos__hit_all(&machine->kernel_dsos);
218 if (err)
219 return err;
220
221 return __dsos__hit_all(&machine->user_dsos);
222}
223
224int dsos__hit_all(struct perf_session *session)
225{
226 struct rb_node *nd;
227 int err;
228
229 err = machine__hit_all_dsos(&session->machines.host);
230 if (err)
231 return err;
232
233 for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
234 struct machine *pos = rb_entry(nd, struct machine, rb_node);
235
236 err = machine__hit_all_dsos(pos);
237 if (err)
238 return err;
239 }
240
241 return 0;
242}
243
203static int __dsos__write_buildid_table(struct list_head *head, 244static int __dsos__write_buildid_table(struct list_head *head,
204 struct machine *machine, 245 struct machine *machine,
205 pid_t pid, u16 misc, int fd) 246 pid_t pid, u16 misc, int fd)
@@ -215,9 +256,9 @@ static int __dsos__write_buildid_table(struct list_head *head,
215 if (!pos->hit) 256 if (!pos->hit)
216 continue; 257 continue;
217 258
218 if (is_vdso_map(pos->short_name)) { 259 if (dso__is_vdso(pos)) {
219 name = (char *) VDSO__MAP_NAME; 260 name = pos->short_name;
220 name_len = sizeof(VDSO__MAP_NAME) + 1; 261 name_len = pos->short_name_len + 1;
221 } else if (dso__is_kcore(pos)) { 262 } else if (dso__is_kcore(pos)) {
222 machine__mmap_name(machine, nm, sizeof(nm)); 263 machine__mmap_name(machine, nm, sizeof(nm));
223 name = nm; 264 name = nm;
@@ -298,7 +339,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
298 339
299 len = scnprintf(filename, size, "%s%s%s", 340 len = scnprintf(filename, size, "%s%s%s",
300 debugdir, slash ? "/" : "", 341 debugdir, slash ? "/" : "",
301 is_vdso ? VDSO__MAP_NAME : realname); 342 is_vdso ? DSO__NAME_VDSO : realname);
302 if (mkdir_p(filename, 0755)) 343 if (mkdir_p(filename, 0755))
303 goto out_free; 344 goto out_free;
304 345
@@ -386,7 +427,7 @@ static int dso__cache_build_id(struct dso *dso, struct machine *machine,
386 const char *debugdir) 427 const char *debugdir)
387{ 428{
388 bool is_kallsyms = dso->kernel && dso->long_name[0] != '/'; 429 bool is_kallsyms = dso->kernel && dso->long_name[0] != '/';
389 bool is_vdso = is_vdso_map(dso->short_name); 430 bool is_vdso = dso__is_vdso(dso);
390 const char *name = dso->long_name; 431 const char *name = dso->long_name;
391 char nm[PATH_MAX]; 432 char nm[PATH_MAX];
392 433
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index d08cfe499404..8f5cbaea64a5 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -151,6 +151,8 @@ int perf_event__process_build_id(struct perf_tool *tool,
151 struct perf_session *session); 151 struct perf_session *session);
152bool is_perf_magic(u64 magic); 152bool is_perf_magic(u64 magic);
153 153
154int dsos__hit_all(struct perf_session *session);
155
154/* 156/*
155 * arch specific callback 157 * arch specific callback
156 */ 158 */
diff --git a/tools/perf/util/include/linux/kernel.h b/tools/perf/util/include/linux/kernel.h
index 9844c31b7c2b..09e8e7aea7c6 100644
--- a/tools/perf/util/include/linux/kernel.h
+++ b/tools/perf/util/include/linux/kernel.h
@@ -94,27 +94,6 @@ static inline int scnprintf(char * buf, size_t size, const char * fmt, ...)
94 return (i >= ssize) ? (ssize - 1) : i; 94 return (i >= ssize) ? (ssize - 1) : i;
95} 95}
96 96
97int eprintf(int level,
98 const char *fmt, ...) __attribute__((format(printf, 2, 3)));
99
100#ifndef pr_fmt
101#define pr_fmt(fmt) fmt
102#endif
103
104#define pr_err(fmt, ...) \
105 eprintf(0, pr_fmt(fmt), ##__VA_ARGS__)
106#define pr_warning(fmt, ...) \
107 eprintf(0, pr_fmt(fmt), ##__VA_ARGS__)
108#define pr_info(fmt, ...) \
109 eprintf(0, pr_fmt(fmt), ##__VA_ARGS__)
110#define pr_debug(fmt, ...) \
111 eprintf(1, pr_fmt(fmt), ##__VA_ARGS__)
112#define pr_debugN(n, fmt, ...) \
113 eprintf(n, pr_fmt(fmt), ##__VA_ARGS__)
114#define pr_debug2(fmt, ...) pr_debugN(2, pr_fmt(fmt), ##__VA_ARGS__)
115#define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__)
116#define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__)
117
118/* 97/*
119 * This looks more complex than it should be. But we need to 98 * This looks more complex than it should be. But we need to
120 * get the type for the ~ right in round_down (it needs to be 99 * get the type for the ~ right in round_down (it needs to be
diff --git a/tools/perf/util/kvm-stat.h b/tools/perf/util/kvm-stat.h
new file mode 100644
index 000000000000..0b5a8cd2ee79
--- /dev/null
+++ b/tools/perf/util/kvm-stat.h
@@ -0,0 +1,140 @@
1#ifndef __PERF_KVM_STAT_H
2#define __PERF_KVM_STAT_H
3
4#include "../perf.h"
5#include "evsel.h"
6#include "evlist.h"
7#include "session.h"
8#include "tool.h"
9#include "stat.h"
10
11struct event_key {
12 #define INVALID_KEY (~0ULL)
13 u64 key;
14 int info;
15 struct exit_reasons_table *exit_reasons;
16};
17
18struct kvm_event_stats {
19 u64 time;
20 struct stats stats;
21};
22
23struct kvm_event {
24 struct list_head hash_entry;
25 struct rb_node rb;
26
27 struct event_key key;
28
29 struct kvm_event_stats total;
30
31 #define DEFAULT_VCPU_NUM 8
32 int max_vcpu;
33 struct kvm_event_stats *vcpu;
34};
35
36typedef int (*key_cmp_fun)(struct kvm_event*, struct kvm_event*, int);
37
38struct kvm_event_key {
39 const char *name;
40 key_cmp_fun key;
41};
42
43struct perf_kvm_stat;
44
45struct child_event_ops {
46 void (*get_key)(struct perf_evsel *evsel,
47 struct perf_sample *sample,
48 struct event_key *key);
49 const char *name;
50};
51
52struct kvm_events_ops {
53 bool (*is_begin_event)(struct perf_evsel *evsel,
54 struct perf_sample *sample,
55 struct event_key *key);
56 bool (*is_end_event)(struct perf_evsel *evsel,
57 struct perf_sample *sample, struct event_key *key);
58 struct child_event_ops *child_ops;
59 void (*decode_key)(struct perf_kvm_stat *kvm, struct event_key *key,
60 char *decode);
61 const char *name;
62};
63
64struct exit_reasons_table {
65 unsigned long exit_code;
66 const char *reason;
67};
68
69#define EVENTS_BITS 12
70#define EVENTS_CACHE_SIZE (1UL << EVENTS_BITS)
71
72struct perf_kvm_stat {
73 struct perf_tool tool;
74 struct record_opts opts;
75 struct perf_evlist *evlist;
76 struct perf_session *session;
77
78 const char *file_name;
79 const char *report_event;
80 const char *sort_key;
81 int trace_vcpu;
82
83 struct exit_reasons_table *exit_reasons;
84 const char *exit_reasons_isa;
85
86 struct kvm_events_ops *events_ops;
87 key_cmp_fun compare;
88 struct list_head kvm_events_cache[EVENTS_CACHE_SIZE];
89
90 u64 total_time;
91 u64 total_count;
92 u64 lost_events;
93 u64 duration;
94
95 const char *pid_str;
96 struct intlist *pid_list;
97
98 struct rb_root result;
99
100 int timerfd;
101 unsigned int display_time;
102 bool live;
103};
104
105struct kvm_reg_events_ops {
106 const char *name;
107 struct kvm_events_ops *ops;
108};
109
110void exit_event_get_key(struct perf_evsel *evsel,
111 struct perf_sample *sample,
112 struct event_key *key);
113bool exit_event_begin(struct perf_evsel *evsel,
114 struct perf_sample *sample,
115 struct event_key *key);
116bool exit_event_end(struct perf_evsel *evsel,
117 struct perf_sample *sample,
118 struct event_key *key);
119void exit_event_decode_key(struct perf_kvm_stat *kvm,
120 struct event_key *key,
121 char *decode);
122
123bool kvm_exit_event(struct perf_evsel *evsel);
124bool kvm_entry_event(struct perf_evsel *evsel);
125
126#define define_exit_reasons_table(name, symbols) \
127 static struct exit_reasons_table name[] = { \
128 symbols, { -1, NULL } \
129 }
130
131/*
132 * arch specific callbacks and data structures
133 */
134int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid);
135
136extern const char * const kvm_events_tp[];
137extern struct kvm_reg_events_ops kvm_reg_events_ops[];
138extern const char * const kvm_skip_events[];
139
140#endif /* __PERF_KVM_STAT_H */
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index c73e1fc12e53..16bba9fff2c8 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -8,6 +8,7 @@
8#include "sort.h" 8#include "sort.h"
9#include "strlist.h" 9#include "strlist.h"
10#include "thread.h" 10#include "thread.h"
11#include "vdso.h"
11#include <stdbool.h> 12#include <stdbool.h>
12#include <symbol/kallsyms.h> 13#include <symbol/kallsyms.h>
13#include "unwind.h" 14#include "unwind.h"
@@ -23,6 +24,8 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
23 INIT_LIST_HEAD(&machine->dead_threads); 24 INIT_LIST_HEAD(&machine->dead_threads);
24 machine->last_match = NULL; 25 machine->last_match = NULL;
25 26
27 machine->vdso_info = NULL;
28
26 machine->kmaps.machine = machine; 29 machine->kmaps.machine = machine;
27 machine->pid = pid; 30 machine->pid = pid;
28 31
@@ -34,7 +37,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
34 return -ENOMEM; 37 return -ENOMEM;
35 38
36 if (pid != HOST_KERNEL_ID) { 39 if (pid != HOST_KERNEL_ID) {
37 struct thread *thread = machine__findnew_thread(machine, 0, 40 struct thread *thread = machine__findnew_thread(machine, -1,
38 pid); 41 pid);
39 char comm[64]; 42 char comm[64];
40 43
@@ -45,6 +48,8 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
45 thread__set_comm(thread, comm, 0); 48 thread__set_comm(thread, comm, 0);
46 } 49 }
47 50
51 machine->current_tid = NULL;
52
48 return 0; 53 return 0;
49} 54}
50 55
@@ -103,7 +108,9 @@ void machine__exit(struct machine *machine)
103 map_groups__exit(&machine->kmaps); 108 map_groups__exit(&machine->kmaps);
104 dsos__delete(&machine->user_dsos); 109 dsos__delete(&machine->user_dsos);
105 dsos__delete(&machine->kernel_dsos); 110 dsos__delete(&machine->kernel_dsos);
111 vdso__exit(machine);
106 zfree(&machine->root_dir); 112 zfree(&machine->root_dir);
113 zfree(&machine->current_tid);
107} 114}
108 115
109void machine__delete(struct machine *machine) 116void machine__delete(struct machine *machine)
@@ -272,6 +279,52 @@ void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size)
272 return; 279 return;
273} 280}
274 281
282static void machine__update_thread_pid(struct machine *machine,
283 struct thread *th, pid_t pid)
284{
285 struct thread *leader;
286
287 if (pid == th->pid_ || pid == -1 || th->pid_ != -1)
288 return;
289
290 th->pid_ = pid;
291
292 if (th->pid_ == th->tid)
293 return;
294
295 leader = machine__findnew_thread(machine, th->pid_, th->pid_);
296 if (!leader)
297 goto out_err;
298
299 if (!leader->mg)
300 leader->mg = map_groups__new();
301
302 if (!leader->mg)
303 goto out_err;
304
305 if (th->mg == leader->mg)
306 return;
307
308 if (th->mg) {
309 /*
310 * Maps are created from MMAP events which provide the pid and
311 * tid. Consequently there never should be any maps on a thread
312 * with an unknown pid. Just print an error if there are.
313 */
314 if (!map_groups__empty(th->mg))
315 pr_err("Discarding thread maps for %d:%d\n",
316 th->pid_, th->tid);
317 map_groups__delete(th->mg);
318 }
319
320 th->mg = map_groups__get(leader->mg);
321
322 return;
323
324out_err:
325 pr_err("Failed to join map groups for %d:%d\n", th->pid_, th->tid);
326}
327
275static struct thread *__machine__findnew_thread(struct machine *machine, 328static struct thread *__machine__findnew_thread(struct machine *machine,
276 pid_t pid, pid_t tid, 329 pid_t pid, pid_t tid,
277 bool create) 330 bool create)
@@ -285,10 +338,10 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
285 * so most of the time we dont have to look up 338 * so most of the time we dont have to look up
286 * the full rbtree: 339 * the full rbtree:
287 */ 340 */
288 if (machine->last_match && machine->last_match->tid == tid) { 341 th = machine->last_match;
289 if (pid && pid != machine->last_match->pid_) 342 if (th && th->tid == tid) {
290 machine->last_match->pid_ = pid; 343 machine__update_thread_pid(machine, th, pid);
291 return machine->last_match; 344 return th;
292 } 345 }
293 346
294 while (*p != NULL) { 347 while (*p != NULL) {
@@ -297,8 +350,7 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
297 350
298 if (th->tid == tid) { 351 if (th->tid == tid) {
299 machine->last_match = th; 352 machine->last_match = th;
300 if (pid && pid != th->pid_) 353 machine__update_thread_pid(machine, th, pid);
301 th->pid_ = pid;
302 return th; 354 return th;
303 } 355 }
304 356
@@ -325,8 +377,10 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
325 * within thread__init_map_groups to find the thread 377 * within thread__init_map_groups to find the thread
326 * leader and that would screwed the rb tree. 378 * leader and that would screwed the rb tree.
327 */ 379 */
328 if (thread__init_map_groups(th, machine)) 380 if (thread__init_map_groups(th, machine)) {
381 thread__delete(th);
329 return NULL; 382 return NULL;
383 }
330 } 384 }
331 385
332 return th; 386 return th;
@@ -1045,14 +1099,14 @@ int machine__process_mmap2_event(struct machine *machine,
1045 else 1099 else
1046 type = MAP__FUNCTION; 1100 type = MAP__FUNCTION;
1047 1101
1048 map = map__new(&machine->user_dsos, event->mmap2.start, 1102 map = map__new(machine, event->mmap2.start,
1049 event->mmap2.len, event->mmap2.pgoff, 1103 event->mmap2.len, event->mmap2.pgoff,
1050 event->mmap2.pid, event->mmap2.maj, 1104 event->mmap2.pid, event->mmap2.maj,
1051 event->mmap2.min, event->mmap2.ino, 1105 event->mmap2.min, event->mmap2.ino,
1052 event->mmap2.ino_generation, 1106 event->mmap2.ino_generation,
1053 event->mmap2.prot, 1107 event->mmap2.prot,
1054 event->mmap2.flags, 1108 event->mmap2.flags,
1055 event->mmap2.filename, type); 1109 event->mmap2.filename, type, thread);
1056 1110
1057 if (map == NULL) 1111 if (map == NULL)
1058 goto out_problem; 1112 goto out_problem;
@@ -1095,11 +1149,11 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
1095 else 1149 else
1096 type = MAP__FUNCTION; 1150 type = MAP__FUNCTION;
1097 1151
1098 map = map__new(&machine->user_dsos, event->mmap.start, 1152 map = map__new(machine, event->mmap.start,
1099 event->mmap.len, event->mmap.pgoff, 1153 event->mmap.len, event->mmap.pgoff,
1100 event->mmap.pid, 0, 0, 0, 0, 0, 0, 1154 event->mmap.pid, 0, 0, 0, 0, 0, 0,
1101 event->mmap.filename, 1155 event->mmap.filename,
1102 type); 1156 type, thread);
1103 1157
1104 if (map == NULL) 1158 if (map == NULL)
1105 goto out_problem; 1159 goto out_problem;
@@ -1281,7 +1335,9 @@ static int machine__resolve_callchain_sample(struct machine *machine,
1281 u8 cpumode = PERF_RECORD_MISC_USER; 1335 u8 cpumode = PERF_RECORD_MISC_USER;
1282 int chain_nr = min(max_stack, (int)chain->nr); 1336 int chain_nr = min(max_stack, (int)chain->nr);
1283 int i; 1337 int i;
1338 int j;
1284 int err; 1339 int err;
1340 int skip_idx __maybe_unused;
1285 1341
1286 callchain_cursor_reset(&callchain_cursor); 1342 callchain_cursor_reset(&callchain_cursor);
1287 1343
@@ -1290,14 +1346,26 @@ static int machine__resolve_callchain_sample(struct machine *machine,
1290 return 0; 1346 return 0;
1291 } 1347 }
1292 1348
1349 /*
1350 * Based on DWARF debug information, some architectures skip
1351 * a callchain entry saved by the kernel.
1352 */
1353 skip_idx = arch_skip_callchain_idx(machine, thread, chain);
1354
1293 for (i = 0; i < chain_nr; i++) { 1355 for (i = 0; i < chain_nr; i++) {
1294 u64 ip; 1356 u64 ip;
1295 struct addr_location al; 1357 struct addr_location al;
1296 1358
1297 if (callchain_param.order == ORDER_CALLEE) 1359 if (callchain_param.order == ORDER_CALLEE)
1298 ip = chain->ips[i]; 1360 j = i;
1299 else 1361 else
1300 ip = chain->ips[chain->nr - i - 1]; 1362 j = chain->nr - i - 1;
1363
1364#ifdef HAVE_SKIP_CALLCHAIN_IDX
1365 if (j == skip_idx)
1366 continue;
1367#endif
1368 ip = chain->ips[j];
1301 1369
1302 if (ip >= PERF_CONTEXT_MAX) { 1370 if (ip >= PERF_CONTEXT_MAX) {
1303 switch (ip) { 1371 switch (ip) {
@@ -1420,3 +1488,46 @@ int __machine__synthesize_threads(struct machine *machine, struct perf_tool *too
1420 /* command specified */ 1488 /* command specified */
1421 return 0; 1489 return 0;
1422} 1490}
1491
1492pid_t machine__get_current_tid(struct machine *machine, int cpu)
1493{
1494 if (cpu < 0 || cpu >= MAX_NR_CPUS || !machine->current_tid)
1495 return -1;
1496
1497 return machine->current_tid[cpu];
1498}
1499
1500int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid,
1501 pid_t tid)
1502{
1503 struct thread *thread;
1504
1505 if (cpu < 0)
1506 return -EINVAL;
1507
1508 if (!machine->current_tid) {
1509 int i;
1510
1511 machine->current_tid = calloc(MAX_NR_CPUS, sizeof(pid_t));
1512 if (!machine->current_tid)
1513 return -ENOMEM;
1514 for (i = 0; i < MAX_NR_CPUS; i++)
1515 machine->current_tid[i] = -1;
1516 }
1517
1518 if (cpu >= MAX_NR_CPUS) {
1519 pr_err("Requested CPU %d too large. ", cpu);
1520 pr_err("Consider raising MAX_NR_CPUS\n");
1521 return -EINVAL;
1522 }
1523
1524 machine->current_tid[cpu] = tid;
1525
1526 thread = machine__findnew_thread(machine, pid, tid);
1527 if (!thread)
1528 return -ENOMEM;
1529
1530 thread->cpu = cpu;
1531
1532 return 0;
1533}
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index c8c74a119398..b972824e6294 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -20,6 +20,8 @@ union perf_event;
20 20
21extern const char *ref_reloc_sym_names[]; 21extern const char *ref_reloc_sym_names[];
22 22
23struct vdso_info;
24
23struct machine { 25struct machine {
24 struct rb_node rb_node; 26 struct rb_node rb_node;
25 pid_t pid; 27 pid_t pid;
@@ -28,11 +30,13 @@ struct machine {
28 struct rb_root threads; 30 struct rb_root threads;
29 struct list_head dead_threads; 31 struct list_head dead_threads;
30 struct thread *last_match; 32 struct thread *last_match;
33 struct vdso_info *vdso_info;
31 struct list_head user_dsos; 34 struct list_head user_dsos;
32 struct list_head kernel_dsos; 35 struct list_head kernel_dsos;
33 struct map_groups kmaps; 36 struct map_groups kmaps;
34 struct map *vmlinux_maps[MAP__NR_TYPES]; 37 struct map *vmlinux_maps[MAP__NR_TYPES];
35 symbol_filter_t symbol_filter; 38 symbol_filter_t symbol_filter;
39 pid_t *current_tid;
36}; 40};
37 41
38static inline 42static inline
@@ -191,4 +195,8 @@ int machine__synthesize_threads(struct machine *machine, struct target *target,
191 perf_event__process, data_mmap); 195 perf_event__process, data_mmap);
192} 196}
193 197
198pid_t machine__get_current_tid(struct machine *machine, int cpu);
199int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid,
200 pid_t tid);
201
194#endif /* __PERF_MACHINE_H */ 202#endif /* __PERF_MACHINE_H */
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 25c571f4cba6..31b8905dd863 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -12,6 +12,8 @@
12#include "vdso.h" 12#include "vdso.h"
13#include "build-id.h" 13#include "build-id.h"
14#include "util.h" 14#include "util.h"
15#include "debug.h"
16#include "machine.h"
15#include <linux/string.h> 17#include <linux/string.h>
16 18
17const char *map_type__name[MAP__NR_TYPES] = { 19const char *map_type__name[MAP__NR_TYPES] = {
@@ -136,10 +138,10 @@ void map__init(struct map *map, enum map_type type,
136 map->erange_warned = false; 138 map->erange_warned = false;
137} 139}
138 140
139struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, 141struct map *map__new(struct machine *machine, u64 start, u64 len,
140 u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino, 142 u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
141 u64 ino_gen, u32 prot, u32 flags, char *filename, 143 u64 ino_gen, u32 prot, u32 flags, char *filename,
142 enum map_type type) 144 enum map_type type, struct thread *thread)
143{ 145{
144 struct map *map = malloc(sizeof(*map)); 146 struct map *map = malloc(sizeof(*map));
145 147
@@ -172,9 +174,9 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
172 174
173 if (vdso) { 175 if (vdso) {
174 pgoff = 0; 176 pgoff = 0;
175 dso = vdso__dso_findnew(dsos__list); 177 dso = vdso__dso_findnew(machine, thread);
176 } else 178 } else
177 dso = __dsos__findnew(dsos__list, filename); 179 dso = __dsos__findnew(&machine->user_dsos, filename);
178 180
179 if (dso == NULL) 181 if (dso == NULL)
180 goto out_delete; 182 goto out_delete;
@@ -454,6 +456,20 @@ void map_groups__exit(struct map_groups *mg)
454 } 456 }
455} 457}
456 458
459bool map_groups__empty(struct map_groups *mg)
460{
461 int i;
462
463 for (i = 0; i < MAP__NR_TYPES; ++i) {
464 if (maps__first(&mg->maps[i]))
465 return false;
466 if (!list_empty(&mg->removed_maps[i]))
467 return false;
468 }
469
470 return true;
471}
472
457struct map_groups *map_groups__new(void) 473struct map_groups *map_groups__new(void)
458{ 474{
459 struct map_groups *mg = malloc(sizeof(*mg)); 475 struct map_groups *mg = malloc(sizeof(*mg));
@@ -554,8 +570,8 @@ int map_groups__find_ams(struct addr_map_symbol *ams, symbol_filter_t filter)
554 return ams->sym ? 0 : -1; 570 return ams->sym ? 0 : -1;
555} 571}
556 572
557size_t __map_groups__fprintf_maps(struct map_groups *mg, 573size_t __map_groups__fprintf_maps(struct map_groups *mg, enum map_type type,
558 enum map_type type, int verbose, FILE *fp) 574 FILE *fp)
559{ 575{
560 size_t printed = fprintf(fp, "%s:\n", map_type__name[type]); 576 size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);
561 struct rb_node *nd; 577 struct rb_node *nd;
@@ -573,17 +589,16 @@ size_t __map_groups__fprintf_maps(struct map_groups *mg,
573 return printed; 589 return printed;
574} 590}
575 591
576size_t map_groups__fprintf_maps(struct map_groups *mg, int verbose, FILE *fp) 592static size_t map_groups__fprintf_maps(struct map_groups *mg, FILE *fp)
577{ 593{
578 size_t printed = 0, i; 594 size_t printed = 0, i;
579 for (i = 0; i < MAP__NR_TYPES; ++i) 595 for (i = 0; i < MAP__NR_TYPES; ++i)
580 printed += __map_groups__fprintf_maps(mg, i, verbose, fp); 596 printed += __map_groups__fprintf_maps(mg, i, fp);
581 return printed; 597 return printed;
582} 598}
583 599
584static size_t __map_groups__fprintf_removed_maps(struct map_groups *mg, 600static size_t __map_groups__fprintf_removed_maps(struct map_groups *mg,
585 enum map_type type, 601 enum map_type type, FILE *fp)
586 int verbose, FILE *fp)
587{ 602{
588 struct map *pos; 603 struct map *pos;
589 size_t printed = 0; 604 size_t printed = 0;
@@ -600,23 +615,23 @@ static size_t __map_groups__fprintf_removed_maps(struct map_groups *mg,
600} 615}
601 616
602static size_t map_groups__fprintf_removed_maps(struct map_groups *mg, 617static size_t map_groups__fprintf_removed_maps(struct map_groups *mg,
603 int verbose, FILE *fp) 618 FILE *fp)
604{ 619{
605 size_t printed = 0, i; 620 size_t printed = 0, i;
606 for (i = 0; i < MAP__NR_TYPES; ++i) 621 for (i = 0; i < MAP__NR_TYPES; ++i)
607 printed += __map_groups__fprintf_removed_maps(mg, i, verbose, fp); 622 printed += __map_groups__fprintf_removed_maps(mg, i, fp);
608 return printed; 623 return printed;
609} 624}
610 625
611size_t map_groups__fprintf(struct map_groups *mg, int verbose, FILE *fp) 626size_t map_groups__fprintf(struct map_groups *mg, FILE *fp)
612{ 627{
613 size_t printed = map_groups__fprintf_maps(mg, verbose, fp); 628 size_t printed = map_groups__fprintf_maps(mg, fp);
614 printed += fprintf(fp, "Removed maps:\n"); 629 printed += fprintf(fp, "Removed maps:\n");
615 return printed + map_groups__fprintf_removed_maps(mg, verbose, fp); 630 return printed + map_groups__fprintf_removed_maps(mg, fp);
616} 631}
617 632
618int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, 633int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map,
619 int verbose, FILE *fp) 634 FILE *fp)
620{ 635{
621 struct rb_root *root = &mg->maps[map->type]; 636 struct rb_root *root = &mg->maps[map->type];
622 struct rb_node *next = rb_first(root); 637 struct rb_node *next = rb_first(root);
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index 7758c72522ef..2f83954af050 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -66,6 +66,7 @@ struct map_groups {
66 66
67struct map_groups *map_groups__new(void); 67struct map_groups *map_groups__new(void);
68void map_groups__delete(struct map_groups *mg); 68void map_groups__delete(struct map_groups *mg);
69bool map_groups__empty(struct map_groups *mg);
69 70
70static inline struct map_groups *map_groups__get(struct map_groups *mg) 71static inline struct map_groups *map_groups__get(struct map_groups *mg)
71{ 72{
@@ -103,6 +104,7 @@ u64 map__rip_2objdump(struct map *map, u64 rip);
103u64 map__objdump_2mem(struct map *map, u64 ip); 104u64 map__objdump_2mem(struct map *map, u64 ip);
104 105
105struct symbol; 106struct symbol;
107struct thread;
106 108
107/* map__for_each_symbol - iterate over the symbols in the given map 109/* map__for_each_symbol - iterate over the symbols in the given map
108 * 110 *
@@ -118,10 +120,10 @@ typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
118 120
119void map__init(struct map *map, enum map_type type, 121void map__init(struct map *map, enum map_type type,
120 u64 start, u64 end, u64 pgoff, struct dso *dso); 122 u64 start, u64 end, u64 pgoff, struct dso *dso);
121struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, 123struct map *map__new(struct machine *machine, u64 start, u64 len,
122 u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino, 124 u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
123 u64 ino_gen, u32 prot, u32 flags, 125 u64 ino_gen, u32 prot, u32 flags,
124 char *filename, enum map_type type); 126 char *filename, enum map_type type, struct thread *thread);
125struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 127struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
126void map__delete(struct map *map); 128void map__delete(struct map *map);
127struct map *map__clone(struct map *map); 129struct map *map__clone(struct map *map);
@@ -141,8 +143,8 @@ void map__fixup_end(struct map *map);
141 143
142void map__reloc_vmlinux(struct map *map); 144void map__reloc_vmlinux(struct map *map);
143 145
144size_t __map_groups__fprintf_maps(struct map_groups *mg, 146size_t __map_groups__fprintf_maps(struct map_groups *mg, enum map_type type,
145 enum map_type type, int verbose, FILE *fp); 147 FILE *fp);
146void maps__insert(struct rb_root *maps, struct map *map); 148void maps__insert(struct rb_root *maps, struct map *map);
147void maps__remove(struct rb_root *maps, struct map *map); 149void maps__remove(struct rb_root *maps, struct map *map);
148struct map *maps__find(struct rb_root *maps, u64 addr); 150struct map *maps__find(struct rb_root *maps, u64 addr);
@@ -152,8 +154,7 @@ void map_groups__init(struct map_groups *mg);
152void map_groups__exit(struct map_groups *mg); 154void map_groups__exit(struct map_groups *mg);
153int map_groups__clone(struct map_groups *mg, 155int map_groups__clone(struct map_groups *mg,
154 struct map_groups *parent, enum map_type type); 156 struct map_groups *parent, enum map_type type);
155size_t map_groups__fprintf(struct map_groups *mg, int verbose, FILE *fp); 157size_t map_groups__fprintf(struct map_groups *mg, FILE *fp);
156size_t map_groups__fprintf_maps(struct map_groups *mg, int verbose, FILE *fp);
157 158
158int maps__set_kallsyms_ref_reloc_sym(struct map **maps, const char *symbol_name, 159int maps__set_kallsyms_ref_reloc_sym(struct map **maps, const char *symbol_name,
159 u64 addr); 160 u64 addr);
@@ -210,7 +211,7 @@ struct symbol *map_groups__find_function_by_name(struct map_groups *mg,
210} 211}
211 212
212int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, 213int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map,
213 int verbose, FILE *fp); 214 FILE *fp);
214 215
215struct map *map_groups__find_by_name(struct map_groups *mg, 216struct map *map_groups__find_by_name(struct map_groups *mg,
216 enum map_type type, const char *name); 217 enum map_type type, const char *name);
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h
index d8dac8ac5f37..b59ba858e73d 100644
--- a/tools/perf/util/parse-options.h
+++ b/tools/perf/util/parse-options.h
@@ -98,6 +98,7 @@ struct option {
98 parse_opt_cb *callback; 98 parse_opt_cb *callback;
99 intptr_t defval; 99 intptr_t defval;
100 bool *set; 100 bool *set;
101 void *data;
101}; 102};
102 103
103#define check_vtype(v, type) ( BUILD_BUG_ON_ZERO(!__builtin_types_compatible_p(typeof(v), type)) + v ) 104#define check_vtype(v, type) ( BUILD_BUG_ON_ZERO(!__builtin_types_compatible_p(typeof(v), type)) + v )
@@ -131,6 +132,10 @@ struct option {
131 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l),\ 132 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l),\
132 .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d,\ 133 .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d,\
133 .flags = PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NOARG} 134 .flags = PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NOARG}
135#define OPT_CALLBACK_OPTARG(s, l, v, d, a, h, f) \
136 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), \
137 .value = (v), (a), .help = (h), .callback = (f), \
138 .flags = PARSE_OPT_OPTARG, .data = (d) }
134 139
135/* parse_options() will filter out the processed options and leave the 140/* parse_options() will filter out the processed options and leave the
136 * non-option argments in argv[]. 141 * non-option argments in argv[].
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 98e304766416..dca9145d704c 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -26,7 +26,6 @@
26#include <errno.h> 26#include <errno.h>
27#include <stdio.h> 27#include <stdio.h>
28#include <unistd.h> 28#include <unistd.h>
29#include <getopt.h>
30#include <stdlib.h> 29#include <stdlib.h>
31#include <string.h> 30#include <string.h>
32#include <stdarg.h> 31#include <stdarg.h>
diff --git a/tools/perf/util/pstack.c b/tools/perf/util/pstack.c
index daa17aeb6c63..a126e6cc6e73 100644
--- a/tools/perf/util/pstack.c
+++ b/tools/perf/util/pstack.c
@@ -6,6 +6,7 @@
6 6
7#include "util.h" 7#include "util.h"
8#include "pstack.h" 8#include "pstack.h"
9#include "debug.h"
9#include <linux/kernel.h> 10#include <linux/kernel.h>
10#include <stdlib.h> 11#include <stdlib.h>
11 12
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index 122669c18ff4..12aa9b0d0ba1 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -14,12 +14,12 @@
14 */ 14 */
15int verbose; 15int verbose;
16 16
17int eprintf(int level, const char *fmt, ...) 17int eprintf(int level, int var, const char *fmt, ...)
18{ 18{
19 va_list args; 19 va_list args;
20 int ret = 0; 20 int ret = 0;
21 21
22 if (verbose >= level) { 22 if (var >= level) {
23 va_start(args, fmt); 23 va_start(args, fmt);
24 ret = vfprintf(stderr, fmt, args); 24 ret = vfprintf(stderr, fmt, args);
25 va_end(args); 25 va_end(args);
diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c
index 049e0a09ccd3..fe8079edbdc1 100644
--- a/tools/perf/util/record.c
+++ b/tools/perf/util/record.c
@@ -4,6 +4,7 @@
4#include "parse-events.h" 4#include "parse-events.h"
5#include <api/fs/fs.h> 5#include <api/fs/fs.h>
6#include "util.h" 6#include "util.h"
7#include "cloexec.h"
7 8
8typedef void (*setup_probe_fn_t)(struct perf_evsel *evsel); 9typedef void (*setup_probe_fn_t)(struct perf_evsel *evsel);
9 10
@@ -11,6 +12,7 @@ static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str)
11{ 12{
12 struct perf_evlist *evlist; 13 struct perf_evlist *evlist;
13 struct perf_evsel *evsel; 14 struct perf_evsel *evsel;
15 unsigned long flags = perf_event_open_cloexec_flag();
14 int err = -EAGAIN, fd; 16 int err = -EAGAIN, fd;
15 17
16 evlist = perf_evlist__new(); 18 evlist = perf_evlist__new();
@@ -22,14 +24,14 @@ static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str)
22 24
23 evsel = perf_evlist__first(evlist); 25 evsel = perf_evlist__first(evlist);
24 26
25 fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0); 27 fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, flags);
26 if (fd < 0) 28 if (fd < 0)
27 goto out_delete; 29 goto out_delete;
28 close(fd); 30 close(fd);
29 31
30 fn(evsel); 32 fn(evsel);
31 33
32 fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0); 34 fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, flags);
33 if (fd < 0) { 35 if (fd < 0) {
34 if (errno == EINVAL) 36 if (errno == EINVAL)
35 err = -EINVAL; 37 err = -EINVAL;
@@ -69,15 +71,26 @@ static void perf_probe_sample_identifier(struct perf_evsel *evsel)
69 evsel->attr.sample_type |= PERF_SAMPLE_IDENTIFIER; 71 evsel->attr.sample_type |= PERF_SAMPLE_IDENTIFIER;
70} 72}
71 73
74static void perf_probe_comm_exec(struct perf_evsel *evsel)
75{
76 evsel->attr.comm_exec = 1;
77}
78
72bool perf_can_sample_identifier(void) 79bool perf_can_sample_identifier(void)
73{ 80{
74 return perf_probe_api(perf_probe_sample_identifier); 81 return perf_probe_api(perf_probe_sample_identifier);
75} 82}
76 83
84static bool perf_can_comm_exec(void)
85{
86 return perf_probe_api(perf_probe_comm_exec);
87}
88
77void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts) 89void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts)
78{ 90{
79 struct perf_evsel *evsel; 91 struct perf_evsel *evsel;
80 bool use_sample_identifier = false; 92 bool use_sample_identifier = false;
93 bool use_comm_exec;
81 94
82 /* 95 /*
83 * Set the evsel leader links before we configure attributes, 96 * Set the evsel leader links before we configure attributes,
@@ -89,8 +102,13 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts)
89 if (evlist->cpus->map[0] < 0) 102 if (evlist->cpus->map[0] < 0)
90 opts->no_inherit = true; 103 opts->no_inherit = true;
91 104
92 evlist__for_each(evlist, evsel) 105 use_comm_exec = perf_can_comm_exec();
106
107 evlist__for_each(evlist, evsel) {
93 perf_evsel__config(evsel, opts); 108 perf_evsel__config(evsel, opts);
109 if (!evsel->idx && use_comm_exec)
110 evsel->attr.comm_exec = 1;
111 }
94 112
95 if (evlist->nr_entries > 1) { 113 if (evlist->nr_entries > 1) {
96 struct perf_evsel *first = perf_evlist__first(evlist); 114 struct perf_evsel *first = perf_evlist__first(evlist);
@@ -203,7 +221,8 @@ bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str)
203 cpu = evlist->cpus->map[0]; 221 cpu = evlist->cpus->map[0];
204 } 222 }
205 223
206 fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0); 224 fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1,
225 perf_event_open_cloexec_flag());
207 if (fd >= 0) { 226 if (fd >= 0) {
208 close(fd); 227 close(fd);
209 ret = true; 228 ret = true;
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index af7da565a750..b2dba9c0a3a1 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -34,6 +34,7 @@
34#include "../event.h" 34#include "../event.h"
35#include "../trace-event.h" 35#include "../trace-event.h"
36#include "../evsel.h" 36#include "../evsel.h"
37#include "../debug.h"
37 38
38void boot_Perf__Trace__Context(pTHX_ CV *cv); 39void boot_Perf__Trace__Context(pTHX_ CV *cv);
39void boot_DynaLoader(pTHX_ CV *cv); 40void boot_DynaLoader(pTHX_ CV *cv);
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index 1c419321f707..cbce2545da45 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -27,11 +27,13 @@
27#include <errno.h> 27#include <errno.h>
28 28
29#include "../../perf.h" 29#include "../../perf.h"
30#include "../debug.h"
30#include "../evsel.h" 31#include "../evsel.h"
31#include "../util.h" 32#include "../util.h"
32#include "../event.h" 33#include "../event.h"
33#include "../thread.h" 34#include "../thread.h"
34#include "../trace-event.h" 35#include "../trace-event.h"
36#include "../machine.h"
35 37
36PyMODINIT_FUNC initperf_trace_context(void); 38PyMODINIT_FUNC initperf_trace_context(void);
37 39
@@ -50,10 +52,14 @@ static int zero_flag_atom;
50 52
51static PyObject *main_module, *main_dict; 53static PyObject *main_module, *main_dict;
52 54
55static void handler_call_die(const char *handler_name) NORETURN;
53static void handler_call_die(const char *handler_name) 56static void handler_call_die(const char *handler_name)
54{ 57{
55 PyErr_Print(); 58 PyErr_Print();
56 Py_FatalError("problem in Python trace event handler"); 59 Py_FatalError("problem in Python trace event handler");
60 // Py_FatalError does not return
61 // but we have to make the compiler happy
62 abort();
57} 63}
58 64
59/* 65/*
@@ -97,6 +103,7 @@ static void define_value(enum print_arg_type field_type,
97 retval = PyObject_CallObject(handler, t); 103 retval = PyObject_CallObject(handler, t);
98 if (retval == NULL) 104 if (retval == NULL)
99 handler_call_die(handler_name); 105 handler_call_die(handler_name);
106 Py_DECREF(retval);
100 } 107 }
101 108
102 Py_DECREF(t); 109 Py_DECREF(t);
@@ -143,6 +150,7 @@ static void define_field(enum print_arg_type field_type,
143 retval = PyObject_CallObject(handler, t); 150 retval = PyObject_CallObject(handler, t);
144 if (retval == NULL) 151 if (retval == NULL)
145 handler_call_die(handler_name); 152 handler_call_die(handler_name);
153 Py_DECREF(retval);
146 } 154 }
147 155
148 Py_DECREF(t); 156 Py_DECREF(t);
@@ -231,15 +239,133 @@ static inline struct event_format *find_cache_event(struct perf_evsel *evsel)
231 return event; 239 return event;
232} 240}
233 241
242static PyObject *get_field_numeric_entry(struct event_format *event,
243 struct format_field *field, void *data)
244{
245 bool is_array = field->flags & FIELD_IS_ARRAY;
246 PyObject *obj, *list = NULL;
247 unsigned long long val;
248 unsigned int item_size, n_items, i;
249
250 if (is_array) {
251 list = PyList_New(field->arraylen);
252 item_size = field->size / field->arraylen;
253 n_items = field->arraylen;
254 } else {
255 item_size = field->size;
256 n_items = 1;
257 }
258
259 for (i = 0; i < n_items; i++) {
260
261 val = read_size(event, data + field->offset + i * item_size,
262 item_size);
263 if (field->flags & FIELD_IS_SIGNED) {
264 if ((long long)val >= LONG_MIN &&
265 (long long)val <= LONG_MAX)
266 obj = PyInt_FromLong(val);
267 else
268 obj = PyLong_FromLongLong(val);
269 } else {
270 if (val <= LONG_MAX)
271 obj = PyInt_FromLong(val);
272 else
273 obj = PyLong_FromUnsignedLongLong(val);
274 }
275 if (is_array)
276 PyList_SET_ITEM(list, i, obj);
277 }
278 if (is_array)
279 obj = list;
280 return obj;
281}
282
283
284static PyObject *python_process_callchain(struct perf_sample *sample,
285 struct perf_evsel *evsel,
286 struct addr_location *al)
287{
288 PyObject *pylist;
289
290 pylist = PyList_New(0);
291 if (!pylist)
292 Py_FatalError("couldn't create Python list");
293
294 if (!symbol_conf.use_callchain || !sample->callchain)
295 goto exit;
296
297 if (machine__resolve_callchain(al->machine, evsel, al->thread,
298 sample, NULL, NULL,
299 PERF_MAX_STACK_DEPTH) != 0) {
300 pr_err("Failed to resolve callchain. Skipping\n");
301 goto exit;
302 }
303 callchain_cursor_commit(&callchain_cursor);
304
305
306 while (1) {
307 PyObject *pyelem;
308 struct callchain_cursor_node *node;
309 node = callchain_cursor_current(&callchain_cursor);
310 if (!node)
311 break;
312
313 pyelem = PyDict_New();
314 if (!pyelem)
315 Py_FatalError("couldn't create Python dictionary");
316
317
318 pydict_set_item_string_decref(pyelem, "ip",
319 PyLong_FromUnsignedLongLong(node->ip));
320
321 if (node->sym) {
322 PyObject *pysym = PyDict_New();
323 if (!pysym)
324 Py_FatalError("couldn't create Python dictionary");
325 pydict_set_item_string_decref(pysym, "start",
326 PyLong_FromUnsignedLongLong(node->sym->start));
327 pydict_set_item_string_decref(pysym, "end",
328 PyLong_FromUnsignedLongLong(node->sym->end));
329 pydict_set_item_string_decref(pysym, "binding",
330 PyInt_FromLong(node->sym->binding));
331 pydict_set_item_string_decref(pysym, "name",
332 PyString_FromStringAndSize(node->sym->name,
333 node->sym->namelen));
334 pydict_set_item_string_decref(pyelem, "sym", pysym);
335 }
336
337 if (node->map) {
338 struct map *map = node->map;
339 const char *dsoname = "[unknown]";
340 if (map && map->dso && (map->dso->name || map->dso->long_name)) {
341 if (symbol_conf.show_kernel_path && map->dso->long_name)
342 dsoname = map->dso->long_name;
343 else if (map->dso->name)
344 dsoname = map->dso->name;
345 }
346 pydict_set_item_string_decref(pyelem, "dso",
347 PyString_FromString(dsoname));
348 }
349
350 callchain_cursor_advance(&callchain_cursor);
351 PyList_Append(pylist, pyelem);
352 Py_DECREF(pyelem);
353 }
354
355exit:
356 return pylist;
357}
358
359
234static void python_process_tracepoint(struct perf_sample *sample, 360static void python_process_tracepoint(struct perf_sample *sample,
235 struct perf_evsel *evsel, 361 struct perf_evsel *evsel,
236 struct thread *thread, 362 struct thread *thread,
237 struct addr_location *al) 363 struct addr_location *al)
238{ 364{
239 PyObject *handler, *retval, *context, *t, *obj, *dict = NULL; 365 PyObject *handler, *retval, *context, *t, *obj, *callchain;
366 PyObject *dict = NULL;
240 static char handler_name[256]; 367 static char handler_name[256];
241 struct format_field *field; 368 struct format_field *field;
242 unsigned long long val;
243 unsigned long s, ns; 369 unsigned long s, ns;
244 struct event_format *event; 370 struct event_format *event;
245 unsigned n = 0; 371 unsigned n = 0;
@@ -280,18 +406,23 @@ static void python_process_tracepoint(struct perf_sample *sample,
280 PyTuple_SetItem(t, n++, PyString_FromString(handler_name)); 406 PyTuple_SetItem(t, n++, PyString_FromString(handler_name));
281 PyTuple_SetItem(t, n++, context); 407 PyTuple_SetItem(t, n++, context);
282 408
409 /* ip unwinding */
410 callchain = python_process_callchain(sample, evsel, al);
411
283 if (handler) { 412 if (handler) {
284 PyTuple_SetItem(t, n++, PyInt_FromLong(cpu)); 413 PyTuple_SetItem(t, n++, PyInt_FromLong(cpu));
285 PyTuple_SetItem(t, n++, PyInt_FromLong(s)); 414 PyTuple_SetItem(t, n++, PyInt_FromLong(s));
286 PyTuple_SetItem(t, n++, PyInt_FromLong(ns)); 415 PyTuple_SetItem(t, n++, PyInt_FromLong(ns));
287 PyTuple_SetItem(t, n++, PyInt_FromLong(pid)); 416 PyTuple_SetItem(t, n++, PyInt_FromLong(pid));
288 PyTuple_SetItem(t, n++, PyString_FromString(comm)); 417 PyTuple_SetItem(t, n++, PyString_FromString(comm));
418 PyTuple_SetItem(t, n++, callchain);
289 } else { 419 } else {
290 pydict_set_item_string_decref(dict, "common_cpu", PyInt_FromLong(cpu)); 420 pydict_set_item_string_decref(dict, "common_cpu", PyInt_FromLong(cpu));
291 pydict_set_item_string_decref(dict, "common_s", PyInt_FromLong(s)); 421 pydict_set_item_string_decref(dict, "common_s", PyInt_FromLong(s));
292 pydict_set_item_string_decref(dict, "common_ns", PyInt_FromLong(ns)); 422 pydict_set_item_string_decref(dict, "common_ns", PyInt_FromLong(ns));
293 pydict_set_item_string_decref(dict, "common_pid", PyInt_FromLong(pid)); 423 pydict_set_item_string_decref(dict, "common_pid", PyInt_FromLong(pid));
294 pydict_set_item_string_decref(dict, "common_comm", PyString_FromString(comm)); 424 pydict_set_item_string_decref(dict, "common_comm", PyString_FromString(comm));
425 pydict_set_item_string_decref(dict, "common_callchain", callchain);
295 } 426 }
296 for (field = event->format.fields; field; field = field->next) { 427 for (field = event->format.fields; field; field = field->next) {
297 if (field->flags & FIELD_IS_STRING) { 428 if (field->flags & FIELD_IS_STRING) {
@@ -303,20 +434,7 @@ static void python_process_tracepoint(struct perf_sample *sample,
303 offset = field->offset; 434 offset = field->offset;
304 obj = PyString_FromString((char *)data + offset); 435 obj = PyString_FromString((char *)data + offset);
305 } else { /* FIELD_IS_NUMERIC */ 436 } else { /* FIELD_IS_NUMERIC */
306 val = read_size(event, data + field->offset, 437 obj = get_field_numeric_entry(event, field, data);
307 field->size);
308 if (field->flags & FIELD_IS_SIGNED) {
309 if ((long long)val >= LONG_MIN &&
310 (long long)val <= LONG_MAX)
311 obj = PyInt_FromLong(val);
312 else
313 obj = PyLong_FromLongLong(val);
314 } else {
315 if (val <= LONG_MAX)
316 obj = PyInt_FromLong(val);
317 else
318 obj = PyLong_FromUnsignedLongLong(val);
319 }
320 } 438 }
321 if (handler) 439 if (handler)
322 PyTuple_SetItem(t, n++, obj); 440 PyTuple_SetItem(t, n++, obj);
@@ -324,6 +442,7 @@ static void python_process_tracepoint(struct perf_sample *sample,
324 pydict_set_item_string_decref(dict, field->name, obj); 442 pydict_set_item_string_decref(dict, field->name, obj);
325 443
326 } 444 }
445
327 if (!handler) 446 if (!handler)
328 PyTuple_SetItem(t, n++, dict); 447 PyTuple_SetItem(t, n++, dict);
329 448
@@ -334,6 +453,7 @@ static void python_process_tracepoint(struct perf_sample *sample,
334 retval = PyObject_CallObject(handler, t); 453 retval = PyObject_CallObject(handler, t);
335 if (retval == NULL) 454 if (retval == NULL)
336 handler_call_die(handler_name); 455 handler_call_die(handler_name);
456 Py_DECREF(retval);
337 } else { 457 } else {
338 handler = PyDict_GetItemString(main_dict, "trace_unhandled"); 458 handler = PyDict_GetItemString(main_dict, "trace_unhandled");
339 if (handler && PyCallable_Check(handler)) { 459 if (handler && PyCallable_Check(handler)) {
@@ -341,6 +461,7 @@ static void python_process_tracepoint(struct perf_sample *sample,
341 retval = PyObject_CallObject(handler, t); 461 retval = PyObject_CallObject(handler, t);
342 if (retval == NULL) 462 if (retval == NULL)
343 handler_call_die("trace_unhandled"); 463 handler_call_die("trace_unhandled");
464 Py_DECREF(retval);
344 } 465 }
345 Py_DECREF(dict); 466 Py_DECREF(dict);
346 } 467 }
@@ -353,7 +474,7 @@ static void python_process_general_event(struct perf_sample *sample,
353 struct thread *thread, 474 struct thread *thread,
354 struct addr_location *al) 475 struct addr_location *al)
355{ 476{
356 PyObject *handler, *retval, *t, *dict; 477 PyObject *handler, *retval, *t, *dict, *callchain, *dict_sample;
357 static char handler_name[64]; 478 static char handler_name[64];
358 unsigned n = 0; 479 unsigned n = 0;
359 480
@@ -369,6 +490,10 @@ static void python_process_general_event(struct perf_sample *sample,
369 if (!dict) 490 if (!dict)
370 Py_FatalError("couldn't create Python dictionary"); 491 Py_FatalError("couldn't create Python dictionary");
371 492
493 dict_sample = PyDict_New();
494 if (!dict_sample)
495 Py_FatalError("couldn't create Python dictionary");
496
372 snprintf(handler_name, sizeof(handler_name), "%s", "process_event"); 497 snprintf(handler_name, sizeof(handler_name), "%s", "process_event");
373 498
374 handler = PyDict_GetItemString(main_dict, handler_name); 499 handler = PyDict_GetItemString(main_dict, handler_name);
@@ -378,8 +503,21 @@ static void python_process_general_event(struct perf_sample *sample,
378 pydict_set_item_string_decref(dict, "ev_name", PyString_FromString(perf_evsel__name(evsel))); 503 pydict_set_item_string_decref(dict, "ev_name", PyString_FromString(perf_evsel__name(evsel)));
379 pydict_set_item_string_decref(dict, "attr", PyString_FromStringAndSize( 504 pydict_set_item_string_decref(dict, "attr", PyString_FromStringAndSize(
380 (const char *)&evsel->attr, sizeof(evsel->attr))); 505 (const char *)&evsel->attr, sizeof(evsel->attr)));
381 pydict_set_item_string_decref(dict, "sample", PyString_FromStringAndSize( 506
382 (const char *)sample, sizeof(*sample))); 507 pydict_set_item_string_decref(dict_sample, "pid",
508 PyInt_FromLong(sample->pid));
509 pydict_set_item_string_decref(dict_sample, "tid",
510 PyInt_FromLong(sample->tid));
511 pydict_set_item_string_decref(dict_sample, "cpu",
512 PyInt_FromLong(sample->cpu));
513 pydict_set_item_string_decref(dict_sample, "ip",
514 PyLong_FromUnsignedLongLong(sample->ip));
515 pydict_set_item_string_decref(dict_sample, "time",
516 PyLong_FromUnsignedLongLong(sample->time));
517 pydict_set_item_string_decref(dict_sample, "period",
518 PyLong_FromUnsignedLongLong(sample->period));
519 pydict_set_item_string_decref(dict, "sample", dict_sample);
520
383 pydict_set_item_string_decref(dict, "raw_buf", PyString_FromStringAndSize( 521 pydict_set_item_string_decref(dict, "raw_buf", PyString_FromStringAndSize(
384 (const char *)sample->raw_data, sample->raw_size)); 522 (const char *)sample->raw_data, sample->raw_size));
385 pydict_set_item_string_decref(dict, "comm", 523 pydict_set_item_string_decref(dict, "comm",
@@ -393,6 +531,10 @@ static void python_process_general_event(struct perf_sample *sample,
393 PyString_FromString(al->sym->name)); 531 PyString_FromString(al->sym->name));
394 } 532 }
395 533
534 /* ip unwinding */
535 callchain = python_process_callchain(sample, evsel, al);
536 pydict_set_item_string_decref(dict, "callchain", callchain);
537
396 PyTuple_SetItem(t, n++, dict); 538 PyTuple_SetItem(t, n++, dict);
397 if (_PyTuple_Resize(&t, n) == -1) 539 if (_PyTuple_Resize(&t, n) == -1)
398 Py_FatalError("error resizing Python tuple"); 540 Py_FatalError("error resizing Python tuple");
@@ -400,6 +542,7 @@ static void python_process_general_event(struct perf_sample *sample,
400 retval = PyObject_CallObject(handler, t); 542 retval = PyObject_CallObject(handler, t);
401 if (retval == NULL) 543 if (retval == NULL)
402 handler_call_die(handler_name); 544 handler_call_die(handler_name);
545 Py_DECREF(retval);
403exit: 546exit:
404 Py_DECREF(dict); 547 Py_DECREF(dict);
405 Py_DECREF(t); 548 Py_DECREF(t);
@@ -521,8 +664,7 @@ static int python_stop_script(void)
521 retval = PyObject_CallObject(handler, NULL); 664 retval = PyObject_CallObject(handler, NULL);
522 if (retval == NULL) 665 if (retval == NULL)
523 handler_call_die("trace_end"); 666 handler_call_die("trace_end");
524 else 667 Py_DECREF(retval);
525 Py_DECREF(retval);
526out: 668out:
527 Py_XDECREF(main_dict); 669 Py_XDECREF(main_dict);
528 Py_XDECREF(main_module); 670 Py_XDECREF(main_module);
@@ -589,6 +731,7 @@ static int python_generate_script(struct pevent *pevent, const char *outfile)
589 fprintf(ofp, "common_nsecs, "); 731 fprintf(ofp, "common_nsecs, ");
590 fprintf(ofp, "common_pid, "); 732 fprintf(ofp, "common_pid, ");
591 fprintf(ofp, "common_comm,\n\t"); 733 fprintf(ofp, "common_comm,\n\t");
734 fprintf(ofp, "common_callchain, ");
592 735
593 not_first = 0; 736 not_first = 0;
594 count = 0; 737 count = 0;
@@ -632,7 +775,7 @@ static int python_generate_script(struct pevent *pevent, const char *outfile)
632 fprintf(ofp, "%%u"); 775 fprintf(ofp, "%%u");
633 } 776 }
634 777
635 fprintf(ofp, "\\n\" %% \\\n\t\t("); 778 fprintf(ofp, "\" %% \\\n\t\t(");
636 779
637 not_first = 0; 780 not_first = 0;
638 count = 0; 781 count = 0;
@@ -668,7 +811,15 @@ static int python_generate_script(struct pevent *pevent, const char *outfile)
668 fprintf(ofp, "%s", f->name); 811 fprintf(ofp, "%s", f->name);
669 } 812 }
670 813
671 fprintf(ofp, "),\n\n"); 814 fprintf(ofp, ")\n\n");
815
816 fprintf(ofp, "\t\tfor node in common_callchain:");
817 fprintf(ofp, "\n\t\t\tif 'sym' in node:");
818 fprintf(ofp, "\n\t\t\t\tprint \"\\t[%%x] %%s\" %% (node['ip'], node['sym']['name'])");
819 fprintf(ofp, "\n\t\t\telse:");
820 fprintf(ofp, "\n\t\t\t\tprint \"\t[%%x]\" %% (node['ip'])\n\n");
821 fprintf(ofp, "\t\tprint \"\\n\"\n\n");
822
672 } 823 }
673 824
674 fprintf(ofp, "def trace_unhandled(event_name, context, " 825 fprintf(ofp, "def trace_unhandled(event_name, context, "
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 64a186edc7be..88dfef70c13d 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -14,7 +14,6 @@
14#include "util.h" 14#include "util.h"
15#include "cpumap.h" 15#include "cpumap.h"
16#include "perf_regs.h" 16#include "perf_regs.h"
17#include "vdso.h"
18 17
19static int perf_session__open(struct perf_session *session) 18static int perf_session__open(struct perf_session *session)
20{ 19{
@@ -156,7 +155,6 @@ void perf_session__delete(struct perf_session *session)
156 if (session->file) 155 if (session->file)
157 perf_data_file__close(session->file); 156 perf_data_file__close(session->file);
158 free(session); 157 free(session);
159 vdso__exit();
160} 158}
161 159
162static int process_event_synth_tracing_data_stub(struct perf_tool *tool 160static int process_event_synth_tracing_data_stub(struct perf_tool *tool
@@ -511,6 +509,7 @@ static int flush_sample_queue(struct perf_session *s,
511 os->last_flush = iter->timestamp; 509 os->last_flush = iter->timestamp;
512 list_del(&iter->list); 510 list_del(&iter->list);
513 list_add(&iter->list, &os->sample_cache); 511 list_add(&iter->list, &os->sample_cache);
512 os->nr_samples--;
514 513
515 if (show_progress) 514 if (show_progress)
516 ui_progress__update(&prog, 1); 515 ui_progress__update(&prog, 1);
@@ -523,8 +522,6 @@ static int flush_sample_queue(struct perf_session *s,
523 list_entry(head->prev, struct sample_queue, list); 522 list_entry(head->prev, struct sample_queue, list);
524 } 523 }
525 524
526 os->nr_samples = 0;
527
528 return 0; 525 return 0;
529} 526}
530 527
@@ -994,8 +991,10 @@ static int perf_session_deliver_event(struct perf_session *session,
994 } 991 }
995} 992}
996 993
997static int perf_session__process_user_event(struct perf_session *session, union perf_event *event, 994static s64 perf_session__process_user_event(struct perf_session *session,
998 struct perf_tool *tool, u64 file_offset) 995 union perf_event *event,
996 struct perf_tool *tool,
997 u64 file_offset)
999{ 998{
1000 int fd = perf_data_file__fd(session->file); 999 int fd = perf_data_file__fd(session->file);
1001 int err; 1000 int err;
@@ -1037,7 +1036,7 @@ static void event_swap(union perf_event *event, bool sample_id_all)
1037 swap(event, sample_id_all); 1036 swap(event, sample_id_all);
1038} 1037}
1039 1038
1040static int perf_session__process_event(struct perf_session *session, 1039static s64 perf_session__process_event(struct perf_session *session,
1041 union perf_event *event, 1040 union perf_event *event,
1042 struct perf_tool *tool, 1041 struct perf_tool *tool,
1043 u64 file_offset) 1042 u64 file_offset)
@@ -1083,13 +1082,14 @@ void perf_event_header__bswap(struct perf_event_header *hdr)
1083 1082
1084struct thread *perf_session__findnew(struct perf_session *session, pid_t pid) 1083struct thread *perf_session__findnew(struct perf_session *session, pid_t pid)
1085{ 1084{
1086 return machine__findnew_thread(&session->machines.host, 0, pid); 1085 return machine__findnew_thread(&session->machines.host, -1, pid);
1087} 1086}
1088 1087
1089static struct thread *perf_session__register_idle_thread(struct perf_session *session) 1088static struct thread *perf_session__register_idle_thread(struct perf_session *session)
1090{ 1089{
1091 struct thread *thread = perf_session__findnew(session, 0); 1090 struct thread *thread;
1092 1091
1092 thread = machine__findnew_thread(&session->machines.host, 0, 0);
1093 if (thread == NULL || thread__set_comm(thread, "swapper", 0)) { 1093 if (thread == NULL || thread__set_comm(thread, "swapper", 0)) {
1094 pr_err("problem inserting idle task.\n"); 1094 pr_err("problem inserting idle task.\n");
1095 thread = NULL; 1095 thread = NULL;
@@ -1147,7 +1147,7 @@ static int __perf_session__process_pipe_events(struct perf_session *session,
1147 union perf_event *event; 1147 union perf_event *event;
1148 uint32_t size, cur_size = 0; 1148 uint32_t size, cur_size = 0;
1149 void *buf = NULL; 1149 void *buf = NULL;
1150 int skip = 0; 1150 s64 skip = 0;
1151 u64 head; 1151 u64 head;
1152 ssize_t err; 1152 ssize_t err;
1153 void *p; 1153 void *p;
@@ -1276,13 +1276,13 @@ int __perf_session__process_events(struct perf_session *session,
1276 u64 file_size, struct perf_tool *tool) 1276 u64 file_size, struct perf_tool *tool)
1277{ 1277{
1278 int fd = perf_data_file__fd(session->file); 1278 int fd = perf_data_file__fd(session->file);
1279 u64 head, page_offset, file_offset, file_pos; 1279 u64 head, page_offset, file_offset, file_pos, size;
1280 int err, mmap_prot, mmap_flags, map_idx = 0; 1280 int err, mmap_prot, mmap_flags, map_idx = 0;
1281 size_t mmap_size; 1281 size_t mmap_size;
1282 char *buf, *mmaps[NUM_MMAPS]; 1282 char *buf, *mmaps[NUM_MMAPS];
1283 union perf_event *event; 1283 union perf_event *event;
1284 uint32_t size;
1285 struct ui_progress prog; 1284 struct ui_progress prog;
1285 s64 skip;
1286 1286
1287 perf_tool__fill_defaults(tool); 1287 perf_tool__fill_defaults(tool);
1288 1288
@@ -1296,8 +1296,10 @@ int __perf_session__process_events(struct perf_session *session,
1296 ui_progress__init(&prog, file_size, "Processing events..."); 1296 ui_progress__init(&prog, file_size, "Processing events...");
1297 1297
1298 mmap_size = MMAP_SIZE; 1298 mmap_size = MMAP_SIZE;
1299 if (mmap_size > file_size) 1299 if (mmap_size > file_size) {
1300 mmap_size = file_size; 1300 mmap_size = file_size;
1301 session->one_mmap = true;
1302 }
1301 1303
1302 memset(mmaps, 0, sizeof(mmaps)); 1304 memset(mmaps, 0, sizeof(mmaps));
1303 1305
@@ -1319,6 +1321,10 @@ remap:
1319 mmaps[map_idx] = buf; 1321 mmaps[map_idx] = buf;
1320 map_idx = (map_idx + 1) & (ARRAY_SIZE(mmaps) - 1); 1322 map_idx = (map_idx + 1) & (ARRAY_SIZE(mmaps) - 1);
1321 file_pos = file_offset + head; 1323 file_pos = file_offset + head;
1324 if (session->one_mmap) {
1325 session->one_mmap_addr = buf;
1326 session->one_mmap_offset = file_offset;
1327 }
1322 1328
1323more: 1329more:
1324 event = fetch_mmaped_event(session, head, mmap_size, buf); 1330 event = fetch_mmaped_event(session, head, mmap_size, buf);
@@ -1337,7 +1343,8 @@ more:
1337 size = event->header.size; 1343 size = event->header.size;
1338 1344
1339 if (size < sizeof(struct perf_event_header) || 1345 if (size < sizeof(struct perf_event_header) ||
1340 perf_session__process_event(session, event, tool, file_pos) < 0) { 1346 (skip = perf_session__process_event(session, event, tool, file_pos))
1347 < 0) {
1341 pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n", 1348 pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n",
1342 file_offset + head, event->header.size, 1349 file_offset + head, event->header.size,
1343 event->header.type); 1350 event->header.type);
@@ -1345,6 +1352,9 @@ more:
1345 goto out_err; 1352 goto out_err;
1346 } 1353 }
1347 1354
1355 if (skip)
1356 size += skip;
1357
1348 head += size; 1358 head += size;
1349 file_pos += size; 1359 file_pos += size;
1350 1360
@@ -1364,6 +1374,7 @@ out_err:
1364 ui_progress__finish(); 1374 ui_progress__finish();
1365 perf_session__warn_about_errors(session, tool); 1375 perf_session__warn_about_errors(session, tool);
1366 perf_session_free_sample_buffers(session); 1376 perf_session_free_sample_buffers(session);
1377 session->one_mmap = false;
1367 return err; 1378 return err;
1368} 1379}
1369 1380
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 3140f8ae6148..0321013bd9fd 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -36,6 +36,9 @@ struct perf_session {
36 struct trace_event tevent; 36 struct trace_event tevent;
37 struct events_stats stats; 37 struct events_stats stats;
38 bool repipe; 38 bool repipe;
39 bool one_mmap;
40 void *one_mmap_addr;
41 u64 one_mmap_offset;
39 struct ordered_samples ordered_samples; 42 struct ordered_samples ordered_samples;
40 struct perf_data_file *file; 43 struct perf_data_file *file;
41}; 44};
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 1ec57dd82284..14e5a039bc45 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -1215,7 +1215,7 @@ static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1215 hse = container_of(fmt, struct hpp_sort_entry, hpp); 1215 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1216 len = hists__col_len(&evsel->hists, hse->se->se_width_idx); 1216 len = hists__col_len(&evsel->hists, hse->se->se_width_idx);
1217 1217
1218 return scnprintf(hpp->buf, hpp->size, "%*s", len, hse->se->se_header); 1218 return scnprintf(hpp->buf, hpp->size, "%-*s", len, hse->se->se_header);
1219} 1219}
1220 1220
1221static int __sort__hpp_width(struct perf_hpp_fmt *fmt, 1221static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
diff --git a/tools/perf/util/svghelper.c b/tools/perf/util/svghelper.c
index 6a0a13d07a28..283d3e73e2f2 100644
--- a/tools/perf/util/svghelper.c
+++ b/tools/perf/util/svghelper.c
@@ -30,6 +30,7 @@ static u64 turbo_frequency, max_freq;
30 30
31#define SLOT_MULT 30.0 31#define SLOT_MULT 30.0
32#define SLOT_HEIGHT 25.0 32#define SLOT_HEIGHT 25.0
33#define SLOT_HALF (SLOT_HEIGHT / 2)
33 34
34int svg_page_width = 1000; 35int svg_page_width = 1000;
35u64 svg_highlight; 36u64 svg_highlight;
@@ -114,8 +115,14 @@ void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end)
114 fprintf(svgfile, " rect { stroke-width: 1; }\n"); 115 fprintf(svgfile, " rect { stroke-width: 1; }\n");
115 fprintf(svgfile, " rect.process { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:1; stroke:rgb( 0, 0, 0); } \n"); 116 fprintf(svgfile, " rect.process { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:1; stroke:rgb( 0, 0, 0); } \n");
116 fprintf(svgfile, " rect.process2 { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 117 fprintf(svgfile, " rect.process2 { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
118 fprintf(svgfile, " rect.process3 { fill:rgb(180,180,180); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
117 fprintf(svgfile, " rect.sample { fill:rgb( 0, 0,255); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 119 fprintf(svgfile, " rect.sample { fill:rgb( 0, 0,255); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
118 fprintf(svgfile, " rect.sample_hi{ fill:rgb(255,128, 0); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 120 fprintf(svgfile, " rect.sample_hi{ fill:rgb(255,128, 0); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
121 fprintf(svgfile, " rect.error { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
122 fprintf(svgfile, " rect.net { fill:rgb( 0,128, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
123 fprintf(svgfile, " rect.disk { fill:rgb( 0, 0,255); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
124 fprintf(svgfile, " rect.sync { fill:rgb(128,128, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
125 fprintf(svgfile, " rect.poll { fill:rgb( 0,128,128); fill-opacity:0.2; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
119 fprintf(svgfile, " rect.blocked { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 126 fprintf(svgfile, " rect.blocked { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
120 fprintf(svgfile, " rect.waiting { fill:rgb(224,214, 0); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 127 fprintf(svgfile, " rect.waiting { fill:rgb(224,214, 0); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
121 fprintf(svgfile, " rect.WAITING { fill:rgb(255,214, 48); fill-opacity:0.6; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 128 fprintf(svgfile, " rect.WAITING { fill:rgb(255,214, 48); fill-opacity:0.6; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
@@ -132,12 +139,81 @@ void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end)
132 fprintf(svgfile, " ]]>\n </style>\n</defs>\n"); 139 fprintf(svgfile, " ]]>\n </style>\n</defs>\n");
133} 140}
134 141
142static double normalize_height(double height)
143{
144 if (height < 0.25)
145 return 0.25;
146 else if (height < 0.50)
147 return 0.50;
148 else if (height < 0.75)
149 return 0.75;
150 else
151 return 0.100;
152}
153
154void svg_ubox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges)
155{
156 double w = time2pixels(end) - time2pixels(start);
157 height = normalize_height(height);
158
159 if (!svgfile)
160 return;
161
162 fprintf(svgfile, "<g>\n");
163 fprintf(svgfile, "<title>fd=%d error=%d merges=%d</title>\n", fd, err, merges);
164 fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"%s\"/>\n",
165 time2pixels(start),
166 w,
167 Yslot * SLOT_MULT,
168 SLOT_HALF * height,
169 type);
170 fprintf(svgfile, "</g>\n");
171}
172
173void svg_lbox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges)
174{
175 double w = time2pixels(end) - time2pixels(start);
176 height = normalize_height(height);
177
178 if (!svgfile)
179 return;
180
181 fprintf(svgfile, "<g>\n");
182 fprintf(svgfile, "<title>fd=%d error=%d merges=%d</title>\n", fd, err, merges);
183 fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"%s\"/>\n",
184 time2pixels(start),
185 w,
186 Yslot * SLOT_MULT + SLOT_HEIGHT - SLOT_HALF * height,
187 SLOT_HALF * height,
188 type);
189 fprintf(svgfile, "</g>\n");
190}
191
192void svg_fbox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges)
193{
194 double w = time2pixels(end) - time2pixels(start);
195 height = normalize_height(height);
196
197 if (!svgfile)
198 return;
199
200 fprintf(svgfile, "<g>\n");
201 fprintf(svgfile, "<title>fd=%d error=%d merges=%d</title>\n", fd, err, merges);
202 fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"%s\"/>\n",
203 time2pixels(start),
204 w,
205 Yslot * SLOT_MULT + SLOT_HEIGHT - SLOT_HEIGHT * height,
206 SLOT_HEIGHT * height,
207 type);
208 fprintf(svgfile, "</g>\n");
209}
210
135void svg_box(int Yslot, u64 start, u64 end, const char *type) 211void svg_box(int Yslot, u64 start, u64 end, const char *type)
136{ 212{
137 if (!svgfile) 213 if (!svgfile)
138 return; 214 return;
139 215
140 fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"%s\"/>\n", 216 fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"%s\"/>\n",
141 time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT, type); 217 time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT, type);
142} 218}
143 219
@@ -174,7 +250,7 @@ void svg_running(int Yslot, int cpu, u64 start, u64 end, const char *backtrace)
174 cpu, time_to_string(end - start)); 250 cpu, time_to_string(end - start));
175 if (backtrace) 251 if (backtrace)
176 fprintf(svgfile, "<desc>Switched because:\n%s</desc>\n", backtrace); 252 fprintf(svgfile, "<desc>Switched because:\n%s</desc>\n", backtrace);
177 fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"%s\"/>\n", 253 fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"%s\"/>\n",
178 time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT, 254 time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT,
179 type); 255 type);
180 256
@@ -186,7 +262,7 @@ void svg_running(int Yslot, int cpu, u64 start, u64 end, const char *backtrace)
186 text_size = round_text_size(text_size); 262 text_size = round_text_size(text_size);
187 263
188 if (text_size > MIN_TEXT_SIZE) 264 if (text_size > MIN_TEXT_SIZE)
189 fprintf(svgfile, "<text x=\"%1.8f\" y=\"%1.8f\" font-size=\"%1.8fpt\">%i</text>\n", 265 fprintf(svgfile, "<text x=\"%.8f\" y=\"%.8f\" font-size=\"%.8fpt\">%i</text>\n",
190 time2pixels(start), Yslot * SLOT_MULT + SLOT_HEIGHT - 1, text_size, cpu + 1); 266 time2pixels(start), Yslot * SLOT_MULT + SLOT_HEIGHT - 1, text_size, cpu + 1);
191 267
192 fprintf(svgfile, "</g>\n"); 268 fprintf(svgfile, "</g>\n");
@@ -202,10 +278,10 @@ static char *time_to_string(u64 duration)
202 return text; 278 return text;
203 279
204 if (duration < 1000 * 1000) { /* less than 1 msec */ 280 if (duration < 1000 * 1000) { /* less than 1 msec */
205 sprintf(text, "%4.1f us", duration / 1000.0); 281 sprintf(text, "%.1f us", duration / 1000.0);
206 return text; 282 return text;
207 } 283 }
208 sprintf(text, "%4.1f ms", duration / 1000.0 / 1000); 284 sprintf(text, "%.1f ms", duration / 1000.0 / 1000);
209 285
210 return text; 286 return text;
211} 287}
@@ -233,14 +309,14 @@ void svg_waiting(int Yslot, int cpu, u64 start, u64 end, const char *backtrace)
233 309
234 font_size = round_text_size(font_size); 310 font_size = round_text_size(font_size);
235 311
236 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\">\n", time2pixels(start), Yslot * SLOT_MULT); 312 fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\">\n", time2pixels(start), Yslot * SLOT_MULT);
237 fprintf(svgfile, "<title>#%d waiting %s</title>\n", cpu, time_to_string(end - start)); 313 fprintf(svgfile, "<title>#%d waiting %s</title>\n", cpu, time_to_string(end - start));
238 if (backtrace) 314 if (backtrace)
239 fprintf(svgfile, "<desc>Waiting on:\n%s</desc>\n", backtrace); 315 fprintf(svgfile, "<desc>Waiting on:\n%s</desc>\n", backtrace);
240 fprintf(svgfile, "<rect x=\"0\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n", 316 fprintf(svgfile, "<rect x=\"0\" width=\"%.8f\" y=\"0\" height=\"%.1f\" class=\"%s\"/>\n",
241 time2pixels(end)-time2pixels(start), SLOT_HEIGHT, style); 317 time2pixels(end)-time2pixels(start), SLOT_HEIGHT, style);
242 if (font_size > MIN_TEXT_SIZE) 318 if (font_size > MIN_TEXT_SIZE)
243 fprintf(svgfile, "<text transform=\"rotate(90)\" font-size=\"%1.8fpt\"> %s</text>\n", 319 fprintf(svgfile, "<text transform=\"rotate(90)\" font-size=\"%.8fpt\"> %s</text>\n",
244 font_size, text); 320 font_size, text);
245 fprintf(svgfile, "</g>\n"); 321 fprintf(svgfile, "</g>\n");
246} 322}
@@ -289,16 +365,16 @@ void svg_cpu_box(int cpu, u64 __max_freq, u64 __turbo_freq)
289 365
290 fprintf(svgfile, "<g>\n"); 366 fprintf(svgfile, "<g>\n");
291 367
292 fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"cpu\"/>\n", 368 fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"cpu\"/>\n",
293 time2pixels(first_time), 369 time2pixels(first_time),
294 time2pixels(last_time)-time2pixels(first_time), 370 time2pixels(last_time)-time2pixels(first_time),
295 cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT); 371 cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT);
296 372
297 sprintf(cpu_string, "CPU %i", (int)cpu); 373 sprintf(cpu_string, "CPU %i", (int)cpu);
298 fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\">%s</text>\n", 374 fprintf(svgfile, "<text x=\"%.8f\" y=\"%.8f\">%s</text>\n",
299 10+time2pixels(first_time), cpu2y(cpu) + SLOT_HEIGHT/2, cpu_string); 375 10+time2pixels(first_time), cpu2y(cpu) + SLOT_HEIGHT/2, cpu_string);
300 376
301 fprintf(svgfile, "<text transform=\"translate(%4.8f,%4.8f)\" font-size=\"1.25pt\">%s</text>\n", 377 fprintf(svgfile, "<text transform=\"translate(%.8f,%.8f)\" font-size=\"1.25pt\">%s</text>\n",
302 10+time2pixels(first_time), cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - 4, cpu_model()); 378 10+time2pixels(first_time), cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - 4, cpu_model());
303 379
304 fprintf(svgfile, "</g>\n"); 380 fprintf(svgfile, "</g>\n");
@@ -319,11 +395,11 @@ void svg_process(int cpu, u64 start, u64 end, int pid, const char *name, const c
319 else 395 else
320 type = "sample"; 396 type = "sample";
321 397
322 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\">\n", time2pixels(start), cpu2y(cpu)); 398 fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\">\n", time2pixels(start), cpu2y(cpu));
323 fprintf(svgfile, "<title>%d %s running %s</title>\n", pid, name, time_to_string(end - start)); 399 fprintf(svgfile, "<title>%d %s running %s</title>\n", pid, name, time_to_string(end - start));
324 if (backtrace) 400 if (backtrace)
325 fprintf(svgfile, "<desc>Switched because:\n%s</desc>\n", backtrace); 401 fprintf(svgfile, "<desc>Switched because:\n%s</desc>\n", backtrace);
326 fprintf(svgfile, "<rect x=\"0\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n", 402 fprintf(svgfile, "<rect x=\"0\" width=\"%.8f\" y=\"0\" height=\"%.1f\" class=\"%s\"/>\n",
327 time2pixels(end)-time2pixels(start), SLOT_MULT+SLOT_HEIGHT, type); 403 time2pixels(end)-time2pixels(start), SLOT_MULT+SLOT_HEIGHT, type);
328 width = time2pixels(end)-time2pixels(start); 404 width = time2pixels(end)-time2pixels(start);
329 if (width > 6) 405 if (width > 6)
@@ -332,7 +408,7 @@ void svg_process(int cpu, u64 start, u64 end, int pid, const char *name, const c
332 width = round_text_size(width); 408 width = round_text_size(width);
333 409
334 if (width > MIN_TEXT_SIZE) 410 if (width > MIN_TEXT_SIZE)
335 fprintf(svgfile, "<text transform=\"rotate(90)\" font-size=\"%3.8fpt\">%s</text>\n", 411 fprintf(svgfile, "<text transform=\"rotate(90)\" font-size=\"%.8fpt\">%s</text>\n",
336 width, name); 412 width, name);
337 413
338 fprintf(svgfile, "</g>\n"); 414 fprintf(svgfile, "</g>\n");
@@ -353,7 +429,7 @@ void svg_cstate(int cpu, u64 start, u64 end, int type)
353 type = 6; 429 type = 6;
354 sprintf(style, "c%i", type); 430 sprintf(style, "c%i", type);
355 431
356 fprintf(svgfile, "<rect class=\"%s\" x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\"/>\n", 432 fprintf(svgfile, "<rect class=\"%s\" x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\"/>\n",
357 style, 433 style,
358 time2pixels(start), time2pixels(end)-time2pixels(start), 434 time2pixels(start), time2pixels(end)-time2pixels(start),
359 cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT); 435 cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT);
@@ -365,7 +441,7 @@ void svg_cstate(int cpu, u64 start, u64 end, int type)
365 width = round_text_size(width); 441 width = round_text_size(width);
366 442
367 if (width > MIN_TEXT_SIZE) 443 if (width > MIN_TEXT_SIZE)
368 fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\" font-size=\"%3.8fpt\">C%i</text>\n", 444 fprintf(svgfile, "<text x=\"%.8f\" y=\"%.8f\" font-size=\"%.8fpt\">C%i</text>\n",
369 time2pixels(start), cpu2y(cpu)+width, width, type); 445 time2pixels(start), cpu2y(cpu)+width, width, type);
370 446
371 fprintf(svgfile, "</g>\n"); 447 fprintf(svgfile, "</g>\n");
@@ -407,9 +483,9 @@ void svg_pstate(int cpu, u64 start, u64 end, u64 freq)
407 if (max_freq) 483 if (max_freq)
408 height = freq * 1.0 / max_freq * (SLOT_HEIGHT + SLOT_MULT); 484 height = freq * 1.0 / max_freq * (SLOT_HEIGHT + SLOT_MULT);
409 height = 1 + cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - height; 485 height = 1 + cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - height;
410 fprintf(svgfile, "<line x1=\"%4.8f\" x2=\"%4.8f\" y1=\"%4.1f\" y2=\"%4.1f\" class=\"pstate\"/>\n", 486 fprintf(svgfile, "<line x1=\"%.8f\" x2=\"%.8f\" y1=\"%.1f\" y2=\"%.1f\" class=\"pstate\"/>\n",
411 time2pixels(start), time2pixels(end), height, height); 487 time2pixels(start), time2pixels(end), height, height);
412 fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\" font-size=\"0.25pt\">%s</text>\n", 488 fprintf(svgfile, "<text x=\"%.8f\" y=\"%.8f\" font-size=\"0.25pt\">%s</text>\n",
413 time2pixels(start), height+0.9, HzToHuman(freq)); 489 time2pixels(start), height+0.9, HzToHuman(freq));
414 490
415 fprintf(svgfile, "</g>\n"); 491 fprintf(svgfile, "</g>\n");
@@ -435,32 +511,32 @@ void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc
435 511
436 if (row1 < row2) { 512 if (row1 < row2) {
437 if (row1) { 513 if (row1) {
438 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 514 fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
439 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/32); 515 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/32);
440 if (desc2) 516 if (desc2)
441 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &gt;</text></g>\n", 517 fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &gt;</text></g>\n",
442 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT + SLOT_HEIGHT/48, desc2); 518 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT + SLOT_HEIGHT/48, desc2);
443 } 519 }
444 if (row2) { 520 if (row2) {
445 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 521 fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
446 time2pixels(start), row2 * SLOT_MULT - SLOT_MULT/32, time2pixels(start), row2 * SLOT_MULT); 522 time2pixels(start), row2 * SLOT_MULT - SLOT_MULT/32, time2pixels(start), row2 * SLOT_MULT);
447 if (desc1) 523 if (desc1)
448 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &gt;</text></g>\n", 524 fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &gt;</text></g>\n",
449 time2pixels(start), row2 * SLOT_MULT - SLOT_MULT/32, desc1); 525 time2pixels(start), row2 * SLOT_MULT - SLOT_MULT/32, desc1);
450 } 526 }
451 } else { 527 } else {
452 if (row2) { 528 if (row2) {
453 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 529 fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
454 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/32); 530 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/32);
455 if (desc1) 531 if (desc1)
456 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &lt;</text></g>\n", 532 fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &lt;</text></g>\n",
457 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/48, desc1); 533 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/48, desc1);
458 } 534 }
459 if (row1) { 535 if (row1) {
460 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 536 fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
461 time2pixels(start), row1 * SLOT_MULT - SLOT_MULT/32, time2pixels(start), row1 * SLOT_MULT); 537 time2pixels(start), row1 * SLOT_MULT - SLOT_MULT/32, time2pixels(start), row1 * SLOT_MULT);
462 if (desc2) 538 if (desc2)
463 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &lt;</text></g>\n", 539 fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &lt;</text></g>\n",
464 time2pixels(start), row1 * SLOT_MULT - SLOT_HEIGHT/32, desc2); 540 time2pixels(start), row1 * SLOT_MULT - SLOT_HEIGHT/32, desc2);
465 } 541 }
466 } 542 }
@@ -468,7 +544,7 @@ void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc
468 if (row2 > row1) 544 if (row2 > row1)
469 height += SLOT_HEIGHT; 545 height += SLOT_HEIGHT;
470 if (row1) 546 if (row1)
471 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n", 547 fprintf(svgfile, "<circle cx=\"%.8f\" cy=\"%.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n",
472 time2pixels(start), height); 548 time2pixels(start), height);
473 549
474 fprintf(svgfile, "</g>\n"); 550 fprintf(svgfile, "</g>\n");
@@ -488,16 +564,16 @@ void svg_wakeline(u64 start, int row1, int row2, const char *backtrace)
488 fprintf(svgfile, "<desc>%s</desc>\n", backtrace); 564 fprintf(svgfile, "<desc>%s</desc>\n", backtrace);
489 565
490 if (row1 < row2) 566 if (row1 < row2)
491 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 567 fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
492 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT); 568 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT);
493 else 569 else
494 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 570 fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
495 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row1 * SLOT_MULT); 571 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row1 * SLOT_MULT);
496 572
497 height = row1 * SLOT_MULT; 573 height = row1 * SLOT_MULT;
498 if (row2 > row1) 574 if (row2 > row1)
499 height += SLOT_HEIGHT; 575 height += SLOT_HEIGHT;
500 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n", 576 fprintf(svgfile, "<circle cx=\"%.8f\" cy=\"%.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n",
501 time2pixels(start), height); 577 time2pixels(start), height);
502 578
503 fprintf(svgfile, "</g>\n"); 579 fprintf(svgfile, "</g>\n");
@@ -515,9 +591,9 @@ void svg_interrupt(u64 start, int row, const char *backtrace)
515 if (backtrace) 591 if (backtrace)
516 fprintf(svgfile, "<desc>%s</desc>\n", backtrace); 592 fprintf(svgfile, "<desc>%s</desc>\n", backtrace);
517 593
518 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n", 594 fprintf(svgfile, "<circle cx=\"%.8f\" cy=\"%.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n",
519 time2pixels(start), row * SLOT_MULT); 595 time2pixels(start), row * SLOT_MULT);
520 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n", 596 fprintf(svgfile, "<circle cx=\"%.8f\" cy=\"%.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n",
521 time2pixels(start), row * SLOT_MULT + SLOT_HEIGHT); 597 time2pixels(start), row * SLOT_MULT + SLOT_HEIGHT);
522 598
523 fprintf(svgfile, "</g>\n"); 599 fprintf(svgfile, "</g>\n");
@@ -528,7 +604,7 @@ void svg_text(int Yslot, u64 start, const char *text)
528 if (!svgfile) 604 if (!svgfile)
529 return; 605 return;
530 606
531 fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\">%s</text>\n", 607 fprintf(svgfile, "<text x=\"%.8f\" y=\"%.8f\">%s</text>\n",
532 time2pixels(start), Yslot * SLOT_MULT+SLOT_HEIGHT/2, text); 608 time2pixels(start), Yslot * SLOT_MULT+SLOT_HEIGHT/2, text);
533} 609}
534 610
@@ -537,12 +613,26 @@ static void svg_legenda_box(int X, const char *text, const char *style)
537 double boxsize; 613 double boxsize;
538 boxsize = SLOT_HEIGHT / 2; 614 boxsize = SLOT_HEIGHT / 2;
539 615
540 fprintf(svgfile, "<rect x=\"%i\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n", 616 fprintf(svgfile, "<rect x=\"%i\" width=\"%.8f\" y=\"0\" height=\"%.1f\" class=\"%s\"/>\n",
541 X, boxsize, boxsize, style); 617 X, boxsize, boxsize, style);
542 fprintf(svgfile, "<text transform=\"translate(%4.8f, %4.8f)\" font-size=\"%4.8fpt\">%s</text>\n", 618 fprintf(svgfile, "<text transform=\"translate(%.8f, %.8f)\" font-size=\"%.8fpt\">%s</text>\n",
543 X + boxsize + 5, boxsize, 0.8 * boxsize, text); 619 X + boxsize + 5, boxsize, 0.8 * boxsize, text);
544} 620}
545 621
622void svg_io_legenda(void)
623{
624 if (!svgfile)
625 return;
626
627 fprintf(svgfile, "<g>\n");
628 svg_legenda_box(0, "Disk", "disk");
629 svg_legenda_box(100, "Network", "net");
630 svg_legenda_box(200, "Sync", "sync");
631 svg_legenda_box(300, "Poll", "poll");
632 svg_legenda_box(400, "Error", "error");
633 fprintf(svgfile, "</g>\n");
634}
635
546void svg_legenda(void) 636void svg_legenda(void)
547{ 637{
548 if (!svgfile) 638 if (!svgfile)
@@ -559,7 +649,7 @@ void svg_legenda(void)
559 fprintf(svgfile, "</g>\n"); 649 fprintf(svgfile, "</g>\n");
560} 650}
561 651
562void svg_time_grid(void) 652void svg_time_grid(double min_thickness)
563{ 653{
564 u64 i; 654 u64 i;
565 655
@@ -579,8 +669,10 @@ void svg_time_grid(void)
579 color = 128; 669 color = 128;
580 } 670 }
581 671
582 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%" PRIu64 "\" style=\"stroke:rgb(%i,%i,%i);stroke-width:%1.3f\"/>\n", 672 if (thickness >= min_thickness)
583 time2pixels(i), SLOT_MULT/2, time2pixels(i), total_height, color, color, color, thickness); 673 fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%" PRIu64 "\" style=\"stroke:rgb(%i,%i,%i);stroke-width:%.3f\"/>\n",
674 time2pixels(i), SLOT_MULT/2, time2pixels(i),
675 total_height, color, color, color, thickness);
584 676
585 i += 10000000; 677 i += 10000000;
586 } 678 }
diff --git a/tools/perf/util/svghelper.h b/tools/perf/util/svghelper.h
index e3aff5332e30..9292a5291445 100644
--- a/tools/perf/util/svghelper.h
+++ b/tools/perf/util/svghelper.h
@@ -4,6 +4,9 @@
4#include <linux/types.h> 4#include <linux/types.h>
5 5
6extern void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end); 6extern void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end);
7extern void svg_ubox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges);
8extern void svg_lbox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges);
9extern void svg_fbox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges);
7extern void svg_box(int Yslot, u64 start, u64 end, const char *type); 10extern void svg_box(int Yslot, u64 start, u64 end, const char *type);
8extern void svg_blocked(int Yslot, int cpu, u64 start, u64 end, const char *backtrace); 11extern void svg_blocked(int Yslot, int cpu, u64 start, u64 end, const char *backtrace);
9extern void svg_running(int Yslot, int cpu, u64 start, u64 end, const char *backtrace); 12extern void svg_running(int Yslot, int cpu, u64 start, u64 end, const char *backtrace);
@@ -16,7 +19,8 @@ extern void svg_cstate(int cpu, u64 start, u64 end, int type);
16extern void svg_pstate(int cpu, u64 start, u64 end, u64 freq); 19extern void svg_pstate(int cpu, u64 start, u64 end, u64 freq);
17 20
18 21
19extern void svg_time_grid(void); 22extern void svg_time_grid(double min_thickness);
23extern void svg_io_legenda(void);
20extern void svg_legenda(void); 24extern void svg_legenda(void);
21extern void svg_wakeline(u64 start, int row1, int row2, const char *backtrace); 25extern void svg_wakeline(u64 start, int row1, int row2, const char *backtrace);
22extern void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2, const char *backtrace); 26extern void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2, const char *backtrace);
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 6864661a79dd..d75349979e65 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -49,7 +49,8 @@ static inline uint8_t elf_sym__type(const GElf_Sym *sym)
49 49
50static inline int elf_sym__is_function(const GElf_Sym *sym) 50static inline int elf_sym__is_function(const GElf_Sym *sym)
51{ 51{
52 return elf_sym__type(sym) == STT_FUNC && 52 return (elf_sym__type(sym) == STT_FUNC ||
53 elf_sym__type(sym) == STT_GNU_IFUNC) &&
53 sym->st_name != 0 && 54 sym->st_name != 0 &&
54 sym->st_shndx != SHN_UNDEF; 55 sym->st_shndx != SHN_UNDEF;
55} 56}
@@ -598,6 +599,8 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
598 goto out_elf_end; 599 goto out_elf_end;
599 } 600 }
600 601
602 ss->is_64_bit = (gelf_getclass(elf) == ELFCLASS64);
603
601 ss->symtab = elf_section_by_name(elf, &ehdr, &ss->symshdr, ".symtab", 604 ss->symtab = elf_section_by_name(elf, &ehdr, &ss->symshdr, ".symtab",
602 NULL); 605 NULL);
603 if (ss->symshdr.sh_type != SHT_SYMTAB) 606 if (ss->symshdr.sh_type != SHT_SYMTAB)
@@ -619,7 +622,7 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
619 GElf_Shdr shdr; 622 GElf_Shdr shdr;
620 ss->adjust_symbols = (ehdr.e_type == ET_EXEC || 623 ss->adjust_symbols = (ehdr.e_type == ET_EXEC ||
621 ehdr.e_type == ET_REL || 624 ehdr.e_type == ET_REL ||
622 is_vdso_map(dso->short_name) || 625 dso__is_vdso(dso) ||
623 elf_section_by_name(elf, &ehdr, &shdr, 626 elf_section_by_name(elf, &ehdr, &shdr,
624 ".gnu.prelink_undo", 627 ".gnu.prelink_undo",
625 NULL) != NULL); 628 NULL) != NULL);
@@ -698,6 +701,7 @@ int dso__load_sym(struct dso *dso, struct map *map,
698 bool remap_kernel = false, adjust_kernel_syms = false; 701 bool remap_kernel = false, adjust_kernel_syms = false;
699 702
700 dso->symtab_type = syms_ss->type; 703 dso->symtab_type = syms_ss->type;
704 dso->is_64_bit = syms_ss->is_64_bit;
701 dso->rel = syms_ss->ehdr.e_type == ET_REL; 705 dso->rel = syms_ss->ehdr.e_type == ET_REL;
702 706
703 /* 707 /*
@@ -1024,6 +1028,39 @@ int file__read_maps(int fd, bool exe, mapfn_t mapfn, void *data,
1024 return err; 1028 return err;
1025} 1029}
1026 1030
1031enum dso_type dso__type_fd(int fd)
1032{
1033 enum dso_type dso_type = DSO__TYPE_UNKNOWN;
1034 GElf_Ehdr ehdr;
1035 Elf_Kind ek;
1036 Elf *elf;
1037
1038 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
1039 if (elf == NULL)
1040 goto out;
1041
1042 ek = elf_kind(elf);
1043 if (ek != ELF_K_ELF)
1044 goto out_end;
1045
1046 if (gelf_getclass(elf) == ELFCLASS64) {
1047 dso_type = DSO__TYPE_64BIT;
1048 goto out_end;
1049 }
1050
1051 if (gelf_getehdr(elf, &ehdr) == NULL)
1052 goto out_end;
1053
1054 if (ehdr.e_machine == EM_X86_64)
1055 dso_type = DSO__TYPE_X32BIT;
1056 else
1057 dso_type = DSO__TYPE_32BIT;
1058out_end:
1059 elf_end(elf);
1060out:
1061 return dso_type;
1062}
1063
1027static int copy_bytes(int from, off_t from_offs, int to, off_t to_offs, u64 len) 1064static int copy_bytes(int from, off_t from_offs, int to, off_t to_offs, u64 len)
1028{ 1065{
1029 ssize_t r; 1066 ssize_t r;
diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c
index bd15f490d04f..c9541fea9514 100644
--- a/tools/perf/util/symbol-minimal.c
+++ b/tools/perf/util/symbol-minimal.c
@@ -288,6 +288,44 @@ int dso__synthesize_plt_symbols(struct dso *dso __maybe_unused,
288 return 0; 288 return 0;
289} 289}
290 290
291static int fd__is_64_bit(int fd)
292{
293 u8 e_ident[EI_NIDENT];
294
295 if (lseek(fd, 0, SEEK_SET))
296 return -1;
297
298 if (readn(fd, e_ident, sizeof(e_ident)) != sizeof(e_ident))
299 return -1;
300
301 if (memcmp(e_ident, ELFMAG, SELFMAG) ||
302 e_ident[EI_VERSION] != EV_CURRENT)
303 return -1;
304
305 return e_ident[EI_CLASS] == ELFCLASS64;
306}
307
308enum dso_type dso__type_fd(int fd)
309{
310 Elf64_Ehdr ehdr;
311 int ret;
312
313 ret = fd__is_64_bit(fd);
314 if (ret < 0)
315 return DSO__TYPE_UNKNOWN;
316
317 if (ret)
318 return DSO__TYPE_64BIT;
319
320 if (readn(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr))
321 return DSO__TYPE_UNKNOWN;
322
323 if (ehdr.e_machine == EM_X86_64)
324 return DSO__TYPE_X32BIT;
325
326 return DSO__TYPE_32BIT;
327}
328
291int dso__load_sym(struct dso *dso, struct map *map __maybe_unused, 329int dso__load_sym(struct dso *dso, struct map *map __maybe_unused,
292 struct symsrc *ss, 330 struct symsrc *ss,
293 struct symsrc *runtime_ss __maybe_unused, 331 struct symsrc *runtime_ss __maybe_unused,
@@ -295,6 +333,11 @@ int dso__load_sym(struct dso *dso, struct map *map __maybe_unused,
295 int kmodule __maybe_unused) 333 int kmodule __maybe_unused)
296{ 334{
297 unsigned char *build_id[BUILD_ID_SIZE]; 335 unsigned char *build_id[BUILD_ID_SIZE];
336 int ret;
337
338 ret = fd__is_64_bit(ss->fd);
339 if (ret >= 0)
340 dso->is_64_bit = ret;
298 341
299 if (filename__read_build_id(ss->name, build_id, BUILD_ID_SIZE) > 0) { 342 if (filename__read_build_id(ss->name, build_id, BUILD_ID_SIZE) > 0) {
300 dso__set_build_id(dso, build_id); 343 dso__set_build_id(dso, build_id);
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 7b9096f29cdb..eb06746b06b2 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -34,6 +34,7 @@ struct symbol_conf symbol_conf = {
34 .annotate_src = true, 34 .annotate_src = true,
35 .demangle = true, 35 .demangle = true,
36 .cumulate_callchain = true, 36 .cumulate_callchain = true,
37 .show_hist_headers = true,
37 .symfs = "", 38 .symfs = "",
38}; 39};
39 40
@@ -341,6 +342,16 @@ static struct symbol *symbols__first(struct rb_root *symbols)
341 return NULL; 342 return NULL;
342} 343}
343 344
345static struct symbol *symbols__next(struct symbol *sym)
346{
347 struct rb_node *n = rb_next(&sym->rb_node);
348
349 if (n)
350 return rb_entry(n, struct symbol, rb_node);
351
352 return NULL;
353}
354
344struct symbol_name_rb_node { 355struct symbol_name_rb_node {
345 struct rb_node rb_node; 356 struct rb_node rb_node;
346 struct symbol sym; 357 struct symbol sym;
@@ -411,11 +422,16 @@ struct symbol *dso__find_symbol(struct dso *dso,
411 return symbols__find(&dso->symbols[type], addr); 422 return symbols__find(&dso->symbols[type], addr);
412} 423}
413 424
414static struct symbol *dso__first_symbol(struct dso *dso, enum map_type type) 425struct symbol *dso__first_symbol(struct dso *dso, enum map_type type)
415{ 426{
416 return symbols__first(&dso->symbols[type]); 427 return symbols__first(&dso->symbols[type]);
417} 428}
418 429
430struct symbol *dso__next_symbol(struct symbol *sym)
431{
432 return symbols__next(sym);
433}
434
419struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, 435struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
420 const char *name) 436 const char *name)
421{ 437{
@@ -1064,6 +1080,7 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
1064 &is_64_bit); 1080 &is_64_bit);
1065 if (err) 1081 if (err)
1066 goto out_err; 1082 goto out_err;
1083 dso->is_64_bit = is_64_bit;
1067 1084
1068 if (list_empty(&md.maps)) { 1085 if (list_empty(&md.maps)) {
1069 err = -EINVAL; 1086 err = -EINVAL;
@@ -1662,6 +1679,7 @@ do_kallsyms:
1662 free(kallsyms_allocated_filename); 1679 free(kallsyms_allocated_filename);
1663 1680
1664 if (err > 0 && !dso__is_kcore(dso)) { 1681 if (err > 0 && !dso__is_kcore(dso)) {
1682 dso->binary_type = DSO_BINARY_TYPE__KALLSYMS;
1665 dso__set_long_name(dso, "[kernel.kallsyms]", false); 1683 dso__set_long_name(dso, "[kernel.kallsyms]", false);
1666 map__fixup_start(map); 1684 map__fixup_start(map);
1667 map__fixup_end(map); 1685 map__fixup_end(map);
@@ -1709,6 +1727,7 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
1709 if (err > 0) 1727 if (err > 0)
1710 pr_debug("Using %s for symbols\n", kallsyms_filename); 1728 pr_debug("Using %s for symbols\n", kallsyms_filename);
1711 if (err > 0 && !dso__is_kcore(dso)) { 1729 if (err > 0 && !dso__is_kcore(dso)) {
1730 dso->binary_type = DSO_BINARY_TYPE__GUEST_KALLSYMS;
1712 machine__mmap_name(machine, path, sizeof(path)); 1731 machine__mmap_name(machine, path, sizeof(path));
1713 dso__set_long_name(dso, strdup(path), true); 1732 dso__set_long_name(dso, strdup(path), true);
1714 map__fixup_start(map); 1733 map__fixup_start(map);
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 615c752dd767..e7295e93cff9 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -118,7 +118,8 @@ struct symbol_conf {
118 annotate_src, 118 annotate_src,
119 event_group, 119 event_group,
120 demangle, 120 demangle,
121 filter_relative; 121 filter_relative,
122 show_hist_headers;
122 const char *vmlinux_name, 123 const char *vmlinux_name,
123 *kallsyms_name, 124 *kallsyms_name,
124 *source_prefix, 125 *source_prefix,
@@ -215,6 +216,7 @@ struct symsrc {
215 GElf_Shdr dynshdr; 216 GElf_Shdr dynshdr;
216 217
217 bool adjust_symbols; 218 bool adjust_symbols;
219 bool is_64_bit;
218#endif 220#endif
219}; 221};
220 222
@@ -238,6 +240,11 @@ struct symbol *dso__find_symbol(struct dso *dso, enum map_type type,
238struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, 240struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
239 const char *name); 241 const char *name);
240 242
243struct symbol *dso__first_symbol(struct dso *dso, enum map_type type);
244struct symbol *dso__next_symbol(struct symbol *sym);
245
246enum dso_type dso__type_fd(int fd);
247
241int filename__read_build_id(const char *filename, void *bf, size_t size); 248int filename__read_build_id(const char *filename, void *bf, size_t size);
242int sysfs__read_build_id(const char *filename, void *bf, size_t size); 249int sysfs__read_build_id(const char *filename, void *bf, size_t size);
243int modules__parse(const char *filename, void *arg, 250int modules__parse(const char *filename, void *arg,
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 2fde0d5e40b5..12c7a253a63c 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -13,7 +13,7 @@ int thread__init_map_groups(struct thread *thread, struct machine *machine)
13 struct thread *leader; 13 struct thread *leader;
14 pid_t pid = thread->pid_; 14 pid_t pid = thread->pid_;
15 15
16 if (pid == thread->tid) { 16 if (pid == thread->tid || pid == -1) {
17 thread->mg = map_groups__new(); 17 thread->mg = map_groups__new();
18 } else { 18 } else {
19 leader = machine__findnew_thread(machine, pid, pid); 19 leader = machine__findnew_thread(machine, pid, pid);
@@ -34,6 +34,7 @@ struct thread *thread__new(pid_t pid, pid_t tid)
34 thread->pid_ = pid; 34 thread->pid_ = pid;
35 thread->tid = tid; 35 thread->tid = tid;
36 thread->ppid = -1; 36 thread->ppid = -1;
37 thread->cpu = -1;
37 INIT_LIST_HEAD(&thread->comm_list); 38 INIT_LIST_HEAD(&thread->comm_list);
38 39
39 comm_str = malloc(32); 40 comm_str = malloc(32);
@@ -60,8 +61,10 @@ void thread__delete(struct thread *thread)
60{ 61{
61 struct comm *comm, *tmp; 62 struct comm *comm, *tmp;
62 63
63 map_groups__put(thread->mg); 64 if (thread->mg) {
64 thread->mg = NULL; 65 map_groups__put(thread->mg);
66 thread->mg = NULL;
67 }
65 list_for_each_entry_safe(comm, tmp, &thread->comm_list, list) { 68 list_for_each_entry_safe(comm, tmp, &thread->comm_list, list) {
66 list_del(&comm->list); 69 list_del(&comm->list);
67 comm__free(comm); 70 comm__free(comm);
@@ -127,12 +130,12 @@ int thread__comm_len(struct thread *thread)
127size_t thread__fprintf(struct thread *thread, FILE *fp) 130size_t thread__fprintf(struct thread *thread, FILE *fp)
128{ 131{
129 return fprintf(fp, "Thread %d %s\n", thread->tid, thread__comm_str(thread)) + 132 return fprintf(fp, "Thread %d %s\n", thread->tid, thread__comm_str(thread)) +
130 map_groups__fprintf(thread->mg, verbose, fp); 133 map_groups__fprintf(thread->mg, fp);
131} 134}
132 135
133void thread__insert_map(struct thread *thread, struct map *map) 136void thread__insert_map(struct thread *thread, struct map *map)
134{ 137{
135 map_groups__fixup_overlappings(thread->mg, map, verbose, stderr); 138 map_groups__fixup_overlappings(thread->mg, map, stderr);
136 map_groups__insert(thread->mg, map); 139 map_groups__insert(thread->mg, map);
137} 140}
138 141
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 3c0c2724f82c..716b7723cce2 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -17,6 +17,7 @@ struct thread {
17 pid_t pid_; /* Not all tools update this */ 17 pid_t pid_; /* Not all tools update this */
18 pid_t tid; 18 pid_t tid;
19 pid_t ppid; 19 pid_t ppid;
20 int cpu;
20 char shortname[3]; 21 char shortname[3];
21 bool comm_set; 22 bool comm_set;
22 bool dead; /* if set thread has exited */ 23 bool dead; /* if set thread has exited */
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index 7e6fcfe8b438..eb72716017ac 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -40,6 +40,7 @@
40#include "trace-event.h" 40#include "trace-event.h"
41#include <api/fs/debugfs.h> 41#include <api/fs/debugfs.h>
42#include "evsel.h" 42#include "evsel.h"
43#include "debug.h"
43 44
44#define VERSION "0.5" 45#define VERSION "0.5"
45 46
@@ -191,12 +192,10 @@ static int copy_event_system(const char *sys, struct tracepoint_path *tps)
191 strcmp(dent->d_name, "..") == 0 || 192 strcmp(dent->d_name, "..") == 0 ||
192 !name_in_tp_list(dent->d_name, tps)) 193 !name_in_tp_list(dent->d_name, tps))
193 continue; 194 continue;
194 format = malloc(strlen(sys) + strlen(dent->d_name) + 10); 195 if (asprintf(&format, "%s/%s/format", sys, dent->d_name) < 0) {
195 if (!format) {
196 err = -ENOMEM; 196 err = -ENOMEM;
197 goto out; 197 goto out;
198 } 198 }
199 sprintf(format, "%s/%s/format", sys, dent->d_name);
200 ret = stat(format, &st); 199 ret = stat(format, &st);
201 free(format); 200 free(format);
202 if (ret < 0) 201 if (ret < 0)
@@ -217,12 +216,10 @@ static int copy_event_system(const char *sys, struct tracepoint_path *tps)
217 strcmp(dent->d_name, "..") == 0 || 216 strcmp(dent->d_name, "..") == 0 ||
218 !name_in_tp_list(dent->d_name, tps)) 217 !name_in_tp_list(dent->d_name, tps))
219 continue; 218 continue;
220 format = malloc(strlen(sys) + strlen(dent->d_name) + 10); 219 if (asprintf(&format, "%s/%s/format", sys, dent->d_name) < 0) {
221 if (!format) {
222 err = -ENOMEM; 220 err = -ENOMEM;
223 goto out; 221 goto out;
224 } 222 }
225 sprintf(format, "%s/%s/format", sys, dent->d_name);
226 ret = stat(format, &st); 223 ret = stat(format, &st);
227 224
228 if (ret >= 0) { 225 if (ret >= 0) {
@@ -317,12 +314,10 @@ static int record_event_files(struct tracepoint_path *tps)
317 strcmp(dent->d_name, "ftrace") == 0 || 314 strcmp(dent->d_name, "ftrace") == 0 ||
318 !system_in_tp_list(dent->d_name, tps)) 315 !system_in_tp_list(dent->d_name, tps))
319 continue; 316 continue;
320 sys = malloc(strlen(path) + strlen(dent->d_name) + 2); 317 if (asprintf(&sys, "%s/%s", path, dent->d_name) < 0) {
321 if (!sys) {
322 err = -ENOMEM; 318 err = -ENOMEM;
323 goto out; 319 goto out;
324 } 320 }
325 sprintf(sys, "%s/%s", path, dent->d_name);
326 ret = stat(sys, &st); 321 ret = stat(sys, &st);
327 if (ret >= 0) { 322 if (ret >= 0) {
328 ssize_t size = strlen(dent->d_name) + 1; 323 ssize_t size = strlen(dent->d_name) + 1;
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index e113e180c48f..54d9e9b548a8 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -22,7 +22,6 @@
22#include <stdio.h> 22#include <stdio.h>
23#include <stdlib.h> 23#include <stdlib.h>
24#include <string.h> 24#include <string.h>
25#include <getopt.h>
26#include <stdarg.h> 25#include <stdarg.h>
27#include <sys/types.h> 26#include <sys/types.h>
28#include <sys/stat.h> 27#include <sys/stat.h>
@@ -36,6 +35,7 @@
36#include "../perf.h" 35#include "../perf.h"
37#include "util.h" 36#include "util.h"
38#include "trace-event.h" 37#include "trace-event.h"
38#include "debug.h"
39 39
40static int input_fd; 40static int input_fd;
41 41
diff --git a/tools/perf/util/tsc.c b/tools/perf/util/tsc.c
new file mode 100644
index 000000000000..4d4210d4e13d
--- /dev/null
+++ b/tools/perf/util/tsc.c
@@ -0,0 +1,30 @@
1#include <linux/compiler.h>
2#include <linux/types.h>
3
4#include "tsc.h"
5
6u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc)
7{
8 u64 t, quot, rem;
9
10 t = ns - tc->time_zero;
11 quot = t / tc->time_mult;
12 rem = t % tc->time_mult;
13 return (quot << tc->time_shift) +
14 (rem << tc->time_shift) / tc->time_mult;
15}
16
17u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc)
18{
19 u64 quot, rem;
20
21 quot = cyc >> tc->time_shift;
22 rem = cyc & ((1 << tc->time_shift) - 1);
23 return tc->time_zero + quot * tc->time_mult +
24 ((rem * tc->time_mult) >> tc->time_shift);
25}
26
27u64 __weak rdtsc(void)
28{
29 return 0;
30}
diff --git a/tools/perf/util/tsc.h b/tools/perf/util/tsc.h
new file mode 100644
index 000000000000..a8b78f1b3243
--- /dev/null
+++ b/tools/perf/util/tsc.h
@@ -0,0 +1,12 @@
1#ifndef __PERF_TSC_H
2#define __PERF_TSC_H
3
4#include <linux/types.h>
5
6#include "../arch/x86/util/tsc.h"
7
8u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc);
9u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc);
10u64 rdtsc(void);
11
12#endif
diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
index 5ec80a575b50..7419768c38b1 100644
--- a/tools/perf/util/unwind-libdw.c
+++ b/tools/perf/util/unwind-libdw.c
@@ -3,6 +3,7 @@
3#include <elfutils/libdwfl.h> 3#include <elfutils/libdwfl.h>
4#include <inttypes.h> 4#include <inttypes.h>
5#include <errno.h> 5#include <errno.h>
6#include "debug.h"
6#include "unwind.h" 7#include "unwind.h"
7#include "unwind-libdw.h" 8#include "unwind-libdw.h"
8#include "machine.h" 9#include "machine.h"
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
index 25578b98f5c5..92b56db52471 100644
--- a/tools/perf/util/unwind-libunwind.c
+++ b/tools/perf/util/unwind-libunwind.c
@@ -30,6 +30,7 @@
30#include "unwind.h" 30#include "unwind.h"
31#include "symbol.h" 31#include "symbol.h"
32#include "util.h" 32#include "util.h"
33#include "debug.h"
33 34
34extern int 35extern int
35UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, 36UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 95aefa78bb07..e52e7461911b 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -1,5 +1,6 @@
1#include "../perf.h" 1#include "../perf.h"
2#include "util.h" 2#include "util.h"
3#include "debug.h"
3#include <api/fs/fs.h> 4#include <api/fs/fs.h>
4#include <sys/mman.h> 5#include <sys/mman.h>
5#ifdef HAVE_BACKTRACE_SUPPORT 6#ifdef HAVE_BACKTRACE_SUPPORT
@@ -333,12 +334,9 @@ const char *find_tracing_dir(void)
333 if (!debugfs) 334 if (!debugfs)
334 return NULL; 335 return NULL;
335 336
336 tracing = malloc(strlen(debugfs) + 9); 337 if (asprintf(&tracing, "%s/tracing", debugfs) < 0)
337 if (!tracing)
338 return NULL; 338 return NULL;
339 339
340 sprintf(tracing, "%s/tracing", debugfs);
341
342 tracing_found = 1; 340 tracing_found = 1;
343 return tracing; 341 return tracing;
344} 342}
@@ -352,11 +350,9 @@ char *get_tracing_file(const char *name)
352 if (!tracing) 350 if (!tracing)
353 return NULL; 351 return NULL;
354 352
355 file = malloc(strlen(tracing) + strlen(name) + 2); 353 if (asprintf(&file, "%s/%s", tracing, name) < 0)
356 if (!file)
357 return NULL; 354 return NULL;
358 355
359 sprintf(file, "%s/%s", tracing, name);
360 return file; 356 return file;
361} 357}
362 358
diff --git a/tools/perf/util/vdso.c b/tools/perf/util/vdso.c
index 0ddb3b8a89ec..adca69384fcc 100644
--- a/tools/perf/util/vdso.c
+++ b/tools/perf/util/vdso.c
@@ -11,10 +11,34 @@
11#include "vdso.h" 11#include "vdso.h"
12#include "util.h" 12#include "util.h"
13#include "symbol.h" 13#include "symbol.h"
14#include "machine.h"
14#include "linux/string.h" 15#include "linux/string.h"
16#include "debug.h"
15 17
16static bool vdso_found; 18#define VDSO__TEMP_FILE_NAME "/tmp/perf-vdso.so-XXXXXX"
17static char vdso_file[] = "/tmp/perf-vdso.so-XXXXXX"; 19
20struct vdso_file {
21 bool found;
22 bool error;
23 char temp_file_name[sizeof(VDSO__TEMP_FILE_NAME)];
24 const char *dso_name;
25};
26
27struct vdso_info {
28 struct vdso_file vdso;
29};
30
31static struct vdso_info *vdso_info__new(void)
32{
33 static const struct vdso_info vdso_info_init = {
34 .vdso = {
35 .temp_file_name = VDSO__TEMP_FILE_NAME,
36 .dso_name = DSO__NAME_VDSO,
37 },
38 };
39
40 return memdup(&vdso_info_init, sizeof(vdso_info_init));
41}
18 42
19static int find_vdso_map(void **start, void **end) 43static int find_vdso_map(void **start, void **end)
20{ 44{
@@ -47,7 +71,7 @@ static int find_vdso_map(void **start, void **end)
47 return !found; 71 return !found;
48} 72}
49 73
50static char *get_file(void) 74static char *get_file(struct vdso_file *vdso_file)
51{ 75{
52 char *vdso = NULL; 76 char *vdso = NULL;
53 char *buf = NULL; 77 char *buf = NULL;
@@ -55,10 +79,10 @@ static char *get_file(void)
55 size_t size; 79 size_t size;
56 int fd; 80 int fd;
57 81
58 if (vdso_found) 82 if (vdso_file->found)
59 return vdso_file; 83 return vdso_file->temp_file_name;
60 84
61 if (find_vdso_map(&start, &end)) 85 if (vdso_file->error || find_vdso_map(&start, &end))
62 return NULL; 86 return NULL;
63 87
64 size = end - start; 88 size = end - start;
@@ -67,45 +91,78 @@ static char *get_file(void)
67 if (!buf) 91 if (!buf)
68 return NULL; 92 return NULL;
69 93
70 fd = mkstemp(vdso_file); 94 fd = mkstemp(vdso_file->temp_file_name);
71 if (fd < 0) 95 if (fd < 0)
72 goto out; 96 goto out;
73 97
74 if (size == (size_t) write(fd, buf, size)) 98 if (size == (size_t) write(fd, buf, size))
75 vdso = vdso_file; 99 vdso = vdso_file->temp_file_name;
76 100
77 close(fd); 101 close(fd);
78 102
79 out: 103 out:
80 free(buf); 104 free(buf);
81 105
82 vdso_found = (vdso != NULL); 106 vdso_file->found = (vdso != NULL);
107 vdso_file->error = !vdso_file->found;
83 return vdso; 108 return vdso;
84} 109}
85 110
86void vdso__exit(void) 111void vdso__exit(struct machine *machine)
87{ 112{
88 if (vdso_found) 113 struct vdso_info *vdso_info = machine->vdso_info;
89 unlink(vdso_file); 114
115 if (!vdso_info)
116 return;
117
118 if (vdso_info->vdso.found)
119 unlink(vdso_info->vdso.temp_file_name);
120
121 zfree(&machine->vdso_info);
90} 122}
91 123
92struct dso *vdso__dso_findnew(struct list_head *head) 124static struct dso *vdso__new(struct machine *machine, const char *short_name,
125 const char *long_name)
93{ 126{
94 struct dso *dso = dsos__find(head, VDSO__MAP_NAME, true); 127 struct dso *dso;
95 128
129 dso = dso__new(short_name);
130 if (dso != NULL) {
131 dsos__add(&machine->user_dsos, dso);
132 dso__set_long_name(dso, long_name, false);
133 }
134
135 return dso;
136}
137
138struct dso *vdso__dso_findnew(struct machine *machine,
139 struct thread *thread __maybe_unused)
140{
141 struct vdso_info *vdso_info;
142 struct dso *dso;
143
144 if (!machine->vdso_info)
145 machine->vdso_info = vdso_info__new();
146
147 vdso_info = machine->vdso_info;
148 if (!vdso_info)
149 return NULL;
150
151 dso = dsos__find(&machine->user_dsos, DSO__NAME_VDSO, true);
96 if (!dso) { 152 if (!dso) {
97 char *file; 153 char *file;
98 154
99 file = get_file(); 155 file = get_file(&vdso_info->vdso);
100 if (!file) 156 if (!file)
101 return NULL; 157 return NULL;
102 158
103 dso = dso__new(VDSO__MAP_NAME); 159 dso = vdso__new(machine, DSO__NAME_VDSO, file);
104 if (dso != NULL) {
105 dsos__add(head, dso);
106 dso__set_long_name(dso, file, false);
107 }
108 } 160 }
109 161
110 return dso; 162 return dso;
111} 163}
164
165bool dso__is_vdso(struct dso *dso)
166{
167 return !strcmp(dso->short_name, DSO__NAME_VDSO);
168}
diff --git a/tools/perf/util/vdso.h b/tools/perf/util/vdso.h
index 0f76e7caf6f8..af9d6929a215 100644
--- a/tools/perf/util/vdso.h
+++ b/tools/perf/util/vdso.h
@@ -7,12 +7,21 @@
7 7
8#define VDSO__MAP_NAME "[vdso]" 8#define VDSO__MAP_NAME "[vdso]"
9 9
10#define DSO__NAME_VDSO "[vdso]"
11
10static inline bool is_vdso_map(const char *filename) 12static inline bool is_vdso_map(const char *filename)
11{ 13{
12 return !strcmp(filename, VDSO__MAP_NAME); 14 return !strcmp(filename, VDSO__MAP_NAME);
13} 15}
14 16
15struct dso *vdso__dso_findnew(struct list_head *head); 17struct dso;
16void vdso__exit(void); 18
19bool dso__is_vdso(struct dso *dso);
20
21struct machine;
22struct thread;
23
24struct dso *vdso__dso_findnew(struct machine *machine, struct thread *thread);
25void vdso__exit(struct machine *machine);
17 26
18#endif /* __PERF_VDSO__ */ 27#endif /* __PERF_VDSO__ */
diff --git a/tools/power/acpi/Makefile b/tools/power/acpi/Makefile
index e5a3c4be2a10..3d1537b93c64 100644
--- a/tools/power/acpi/Makefile
+++ b/tools/power/acpi/Makefile
@@ -108,13 +108,18 @@ DUMP_OBJS = \
108 apmain.o\ 108 apmain.o\
109 osunixdir.o\ 109 osunixdir.o\
110 osunixmap.o\ 110 osunixmap.o\
111 osunixxf.o\
111 tbprint.o\ 112 tbprint.o\
112 tbxfroot.o\ 113 tbxfroot.o\
113 utbuffer.o\ 114 utbuffer.o\
115 utdebug.o\
114 utexcep.o\ 116 utexcep.o\
117 utglobal.o\
115 utmath.o\ 118 utmath.o\
119 utprint.o\
116 utstring.o\ 120 utstring.o\
117 utxferror.o\ 121 utxferror.o\
122 oslibcfs.o\
118 oslinuxtbl.o\ 123 oslinuxtbl.o\
119 cmfsize.o\ 124 cmfsize.o\
120 getopt.o 125 getopt.o
diff --git a/tools/power/acpi/common/cmfsize.c b/tools/power/acpi/common/cmfsize.c
index 5140e5edae1f..f4b953354ff7 100644
--- a/tools/power/acpi/common/cmfsize.c
+++ b/tools/power/acpi/common/cmfsize.c
@@ -58,44 +58,46 @@ ACPI_MODULE_NAME("cmfsize")
58 * RETURN: File Size. On error, -1 (ACPI_UINT32_MAX) 58 * RETURN: File Size. On error, -1 (ACPI_UINT32_MAX)
59 * 59 *
60 * DESCRIPTION: Get the size of a file. Uses seek-to-EOF. File must be open. 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 61 * Does not disturb the current file pointer.
62 * error messages.
63 * 62 *
64 ******************************************************************************/ 63 ******************************************************************************/
65u32 cm_get_file_size(FILE * file) 64u32 cm_get_file_size(ACPI_FILE file)
66{ 65{
67 long file_size; 66 long file_size;
68 long current_offset; 67 long current_offset;
68 acpi_status status;
69 69
70 /* Save the current file pointer, seek to EOF to obtain file size */ 70 /* Save the current file pointer, seek to EOF to obtain file size */
71 71
72 current_offset = ftell(file); 72 current_offset = acpi_os_get_file_offset(file);
73 if (current_offset < 0) { 73 if (current_offset < 0) {
74 goto offset_error; 74 goto offset_error;
75 } 75 }
76 76
77 if (fseek(file, 0, SEEK_END)) { 77 status = acpi_os_set_file_offset(file, 0, ACPI_FILE_END);
78 if (ACPI_FAILURE(status)) {
78 goto seek_error; 79 goto seek_error;
79 } 80 }
80 81
81 file_size = ftell(file); 82 file_size = acpi_os_get_file_offset(file);
82 if (file_size < 0) { 83 if (file_size < 0) {
83 goto offset_error; 84 goto offset_error;
84 } 85 }
85 86
86 /* Restore original file pointer */ 87 /* Restore original file pointer */
87 88
88 if (fseek(file, current_offset, SEEK_SET)) { 89 status = acpi_os_set_file_offset(file, current_offset, ACPI_FILE_BEGIN);
90 if (ACPI_FAILURE(status)) {
89 goto seek_error; 91 goto seek_error;
90 } 92 }
91 93
92 return ((u32)file_size); 94 return ((u32)file_size);
93 95
94offset_error: 96offset_error:
95 perror("Could not get file offset"); 97 acpi_log_error("Could not get file offset");
96 return (ACPI_UINT32_MAX); 98 return (ACPI_UINT32_MAX);
97 99
98seek_error: 100seek_error:
99 perror("Could not seek file"); 101 acpi_log_error("Could not set file offset");
100 return (ACPI_UINT32_MAX); 102 return (ACPI_UINT32_MAX);
101} 103}
diff --git a/tools/power/acpi/common/getopt.c b/tools/power/acpi/common/getopt.c
index a302f52e4fd3..2f0f34a36db4 100644
--- a/tools/power/acpi/common/getopt.c
+++ b/tools/power/acpi/common/getopt.c
@@ -51,14 +51,12 @@
51 * "f|" - Option has required single-char sub-options 51 * "f|" - Option has required single-char sub-options
52 */ 52 */
53 53
54#include <stdio.h>
55#include <string.h>
56#include <acpi/acpi.h> 54#include <acpi/acpi.h>
57#include "accommon.h" 55#include "accommon.h"
58#include "acapps.h" 56#include "acapps.h"
59 57
60#define ACPI_OPTION_ERROR(msg, badchar) \ 58#define ACPI_OPTION_ERROR(msg, badchar) \
61 if (acpi_gbl_opterr) {fprintf (stderr, "%s%c\n", msg, badchar);} 59 if (acpi_gbl_opterr) {acpi_log_error ("%s%c\n", msg, badchar);}
62 60
63int acpi_gbl_opterr = 1; 61int acpi_gbl_opterr = 1;
64int acpi_gbl_optind = 1; 62int acpi_gbl_optind = 1;
@@ -113,7 +111,7 @@ int acpi_getopt_argument(int argc, char **argv)
113 * PARAMETERS: argc, argv - from main 111 * PARAMETERS: argc, argv - from main
114 * opts - options info list 112 * opts - options info list
115 * 113 *
116 * RETURN: Option character or EOF 114 * RETURN: Option character or ACPI_OPT_END
117 * 115 *
118 * DESCRIPTION: Get the next option 116 * DESCRIPTION: Get the next option
119 * 117 *
@@ -128,10 +126,10 @@ int acpi_getopt(int argc, char **argv, char *opts)
128 if (acpi_gbl_optind >= argc || 126 if (acpi_gbl_optind >= argc ||
129 argv[acpi_gbl_optind][0] != '-' || 127 argv[acpi_gbl_optind][0] != '-' ||
130 argv[acpi_gbl_optind][1] == '\0') { 128 argv[acpi_gbl_optind][1] == '\0') {
131 return (EOF); 129 return (ACPI_OPT_END);
132 } else if (strcmp(argv[acpi_gbl_optind], "--") == 0) { 130 } else if (ACPI_STRCMP(argv[acpi_gbl_optind], "--") == 0) {
133 acpi_gbl_optind++; 131 acpi_gbl_optind++;
134 return (EOF); 132 return (ACPI_OPT_END);
135 } 133 }
136 } 134 }
137 135
@@ -142,7 +140,7 @@ int acpi_getopt(int argc, char **argv, char *opts)
142 /* Make sure that the option is legal */ 140 /* Make sure that the option is legal */
143 141
144 if (current_char == ':' || 142 if (current_char == ':' ||
145 (opts_ptr = strchr(opts, current_char)) == NULL) { 143 (opts_ptr = ACPI_STRCHR(opts, current_char)) == NULL) {
146 ACPI_OPTION_ERROR("Illegal option: -", current_char); 144 ACPI_OPTION_ERROR("Illegal option: -", current_char);
147 145
148 if (argv[acpi_gbl_optind][++current_char_ptr] == '\0') { 146 if (argv[acpi_gbl_optind][++current_char_ptr] == '\0') {
diff --git a/tools/power/acpi/os_specific/service_layers/oslibcfs.c b/tools/power/acpi/os_specific/service_layers/oslibcfs.c
new file mode 100644
index 000000000000..c13ff9c51d74
--- /dev/null
+++ b/tools/power/acpi/os_specific/service_layers/oslibcfs.c
@@ -0,0 +1,214 @@
1/******************************************************************************
2 *
3 * Module Name: oslibcfs - C library OSL for file I/O
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 <stdio.h>
46#include <stdarg.h>
47
48#define _COMPONENT ACPI_OS_SERVICES
49ACPI_MODULE_NAME("oslibcfs")
50
51/*******************************************************************************
52 *
53 * FUNCTION: acpi_os_open_file
54 *
55 * PARAMETERS: path - File path
56 * modes - File operation type
57 *
58 * RETURN: File descriptor.
59 *
60 * DESCRIPTION: Open a file for reading (ACPI_FILE_READING) or/and writing
61 * (ACPI_FILE_WRITING).
62 *
63 ******************************************************************************/
64ACPI_FILE acpi_os_open_file(const char *path, u8 modes)
65{
66 ACPI_FILE file;
67 u32 i = 0;
68 char modes_str[4];
69
70 if (modes & ACPI_FILE_READING) {
71 modes_str[i++] = 'r';
72 }
73 if (modes & ACPI_FILE_WRITING) {
74 modes_str[i++] = 'w';
75 }
76 if (modes & ACPI_FILE_BINARY) {
77 modes_str[i++] = 'b';
78 }
79
80 modes_str[i++] = '\0';
81
82 file = fopen(path, modes_str);
83 if (!file) {
84 perror("Could not open file");
85 }
86
87 return (file);
88}
89
90/*******************************************************************************
91 *
92 * FUNCTION: acpi_os_close_file
93 *
94 * PARAMETERS: file - An open file descriptor
95 *
96 * RETURN: None.
97 *
98 * DESCRIPTION: Close a file opened via acpi_os_open_file.
99 *
100 ******************************************************************************/
101
102void acpi_os_close_file(ACPI_FILE file)
103{
104 fclose(file);
105}
106
107/*******************************************************************************
108 *
109 * FUNCTION: acpi_os_read_file
110 *
111 * PARAMETERS: file - An open file descriptor
112 * buffer - Data buffer
113 * size - Data block size
114 * count - Number of data blocks
115 *
116 * RETURN: Number of bytes actually read.
117 *
118 * DESCRIPTION: Read from a file.
119 *
120 ******************************************************************************/
121
122int
123acpi_os_read_file(ACPI_FILE file, void *buffer, acpi_size size, acpi_size count)
124{
125 int length;
126
127 length = fread(buffer, size, count, file);
128 if (length < 0) {
129 perror("Error reading file");
130 }
131
132 return (length);
133}
134
135/*******************************************************************************
136 *
137 * FUNCTION: acpi_os_write_file
138 *
139 * PARAMETERS: file - An open file descriptor
140 * buffer - Data buffer
141 * size - Data block size
142 * count - Number of data blocks
143 *
144 * RETURN: Number of bytes actually written.
145 *
146 * DESCRIPTION: Write to a file.
147 *
148 ******************************************************************************/
149
150int
151acpi_os_write_file(ACPI_FILE file,
152 void *buffer, acpi_size size, acpi_size count)
153{
154 int length;
155
156 length = fwrite(buffer, size, count, file);
157 if (length < 0) {
158 perror("Error writing file");
159 }
160
161 return (length);
162}
163
164/*******************************************************************************
165 *
166 * FUNCTION: acpi_os_get_file_offset
167 *
168 * PARAMETERS: file - An open file descriptor
169 *
170 * RETURN: Current file pointer position.
171 *
172 * DESCRIPTION: Get current file offset.
173 *
174 ******************************************************************************/
175
176long acpi_os_get_file_offset(ACPI_FILE file)
177{
178 long offset;
179
180 offset = ftell(file);
181 return (offset);
182}
183
184/*******************************************************************************
185 *
186 * FUNCTION: acpi_os_set_file_offset
187 *
188 * PARAMETERS: file - An open file descriptor
189 * offset - New file offset
190 * from - From begin/end of file
191 *
192 * RETURN: Status
193 *
194 * DESCRIPTION: Set current file offset.
195 *
196 ******************************************************************************/
197
198acpi_status acpi_os_set_file_offset(ACPI_FILE file, long offset, u8 from)
199{
200 int ret = 0;
201
202 if (from == ACPI_FILE_BEGIN) {
203 ret = fseek(file, offset, SEEK_SET);
204 }
205 if (from == ACPI_FILE_END) {
206 ret = fseek(file, offset, SEEK_END);
207 }
208
209 if (ret < 0) {
210 return (AE_ERROR);
211 } else {
212 return (AE_OK);
213 }
214}
diff --git a/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c
index 28c52008e854..0dc2485dedf5 100644
--- a/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c
+++ b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c
@@ -77,6 +77,9 @@ osl_map_table(acpi_size address,
77 77
78static void osl_unmap_table(struct acpi_table_header *table); 78static void osl_unmap_table(struct acpi_table_header *table);
79 79
80static acpi_physical_address
81osl_find_rsdp_via_efi_by_keyword(FILE * file, const char *keyword);
82
80static acpi_physical_address osl_find_rsdp_via_efi(void); 83static acpi_physical_address osl_find_rsdp_via_efi(void);
81 84
82static acpi_status osl_load_rsdp(void); 85static acpi_status osl_load_rsdp(void);
@@ -417,6 +420,38 @@ acpi_os_get_table_by_index(u32 index,
417 420
418/****************************************************************************** 421/******************************************************************************
419 * 422 *
423 * FUNCTION: osl_find_rsdp_via_efi_by_keyword
424 *
425 * PARAMETERS: keyword - Character string indicating ACPI GUID version
426 * in the EFI table
427 *
428 * RETURN: RSDP address if found
429 *
430 * DESCRIPTION: Find RSDP address via EFI using keyword indicating the ACPI
431 * GUID version.
432 *
433 *****************************************************************************/
434
435static acpi_physical_address
436osl_find_rsdp_via_efi_by_keyword(FILE * file, const char *keyword)
437{
438 char buffer[80];
439 unsigned long long address = 0;
440 char format[32];
441
442 snprintf(format, 32, "%s=%s", keyword, "%llx");
443 fseek(file, 0, SEEK_SET);
444 while (fgets(buffer, 80, file)) {
445 if (sscanf(buffer, format, &address) == 1) {
446 break;
447 }
448 }
449
450 return ((acpi_physical_address) (address));
451}
452
453/******************************************************************************
454 *
420 * FUNCTION: osl_find_rsdp_via_efi 455 * FUNCTION: osl_find_rsdp_via_efi
421 * 456 *
422 * PARAMETERS: None 457 * PARAMETERS: None
@@ -430,20 +465,19 @@ acpi_os_get_table_by_index(u32 index,
430static acpi_physical_address osl_find_rsdp_via_efi(void) 465static acpi_physical_address osl_find_rsdp_via_efi(void)
431{ 466{
432 FILE *file; 467 FILE *file;
433 char buffer[80]; 468 acpi_physical_address address = 0;
434 unsigned long address = 0;
435 469
436 file = fopen(EFI_SYSTAB, "r"); 470 file = fopen(EFI_SYSTAB, "r");
437 if (file) { 471 if (file) {
438 while (fgets(buffer, 80, file)) { 472 address = osl_find_rsdp_via_efi_by_keyword(file, "ACPI20");
439 if (sscanf(buffer, "ACPI20=0x%lx", &address) == 1) { 473 if (!address) {
440 break; 474 address =
441 } 475 osl_find_rsdp_via_efi_by_keyword(file, "ACPI");
442 } 476 }
443 fclose(file); 477 fclose(file);
444 } 478 }
445 479
446 return ((acpi_physical_address) (address)); 480 return (address);
447} 481}
448 482
449/****************************************************************************** 483/******************************************************************************
diff --git a/tools/power/acpi/os_specific/service_layers/osunixxf.c b/tools/power/acpi/os_specific/service_layers/osunixxf.c
new file mode 100644
index 000000000000..60b58cd18410
--- /dev/null
+++ b/tools/power/acpi/os_specific/service_layers/osunixxf.c
@@ -0,0 +1,1311 @@
1/******************************************************************************
2 *
3 * Module Name: osunixxf - UNIX OSL 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/*
45 * These interfaces are required in order to compile the ASL compiler and the
46 * various ACPICA tools under Linux or other Unix-like system.
47 */
48#include <acpi/acpi.h>
49#include "accommon.h"
50#include "amlcode.h"
51#include "acparser.h"
52#include "acdebug.h"
53
54#include <stdio.h>
55#include <stdlib.h>
56#include <stdarg.h>
57#include <unistd.h>
58#include <sys/time.h>
59#include <semaphore.h>
60#include <pthread.h>
61#include <errno.h>
62
63#define _COMPONENT ACPI_OS_SERVICES
64ACPI_MODULE_NAME("osunixxf")
65
66u8 acpi_gbl_debug_timeout = FALSE;
67
68/* Upcalls to acpi_exec */
69
70void
71ae_table_override(struct acpi_table_header *existing_table,
72 struct acpi_table_header **new_table);
73
74typedef void *(*PTHREAD_CALLBACK) (void *);
75
76/* Buffer used by acpi_os_vprintf */
77
78#define ACPI_VPRINTF_BUFFER_SIZE 512
79#define _ASCII_NEWLINE '\n'
80
81/* Terminal support for acpi_exec only */
82
83#ifdef ACPI_EXEC_APP
84#include <termios.h>
85
86struct termios original_term_attributes;
87int term_attributes_were_set = 0;
88
89acpi_status acpi_ut_read_line(char *buffer, u32 buffer_length, u32 *bytes_read);
90
91static void os_enter_line_edit_mode(void);
92
93static void os_exit_line_edit_mode(void);
94
95/******************************************************************************
96 *
97 * FUNCTION: os_enter_line_edit_mode, os_exit_line_edit_mode
98 *
99 * PARAMETERS: None
100 *
101 * RETURN: None
102 *
103 * DESCRIPTION: Enter/Exit the raw character input mode for the terminal.
104 *
105 * Interactive line-editing support for the AML debugger. Used with the
106 * common/acgetline module.
107 *
108 * readline() is not used because of non-portability. It is not available
109 * on all systems, and if it is, often the package must be manually installed.
110 *
111 * Therefore, we use the POSIX tcgetattr/tcsetattr and do the minimal line
112 * editing that we need in acpi_os_get_line.
113 *
114 * If the POSIX tcgetattr/tcsetattr interfaces are unavailable, these
115 * calls will also work:
116 * For os_enter_line_edit_mode: system ("stty cbreak -echo")
117 * For os_exit_line_edit_mode: system ("stty cooked echo")
118 *
119 *****************************************************************************/
120
121static void os_enter_line_edit_mode(void)
122{
123 struct termios local_term_attributes;
124
125 /* Get and keep the original attributes */
126
127 if (tcgetattr(STDIN_FILENO, &original_term_attributes)) {
128 fprintf(stderr, "Could not get terminal attributes!\n");
129 return;
130 }
131
132 /* Set the new attributes to enable raw character input */
133
134 memcpy(&local_term_attributes, &original_term_attributes,
135 sizeof(struct termios));
136
137 local_term_attributes.c_lflag &= ~(ICANON | ECHO);
138 local_term_attributes.c_cc[VMIN] = 1;
139 local_term_attributes.c_cc[VTIME] = 0;
140
141 if (tcsetattr(STDIN_FILENO, TCSANOW, &local_term_attributes)) {
142 fprintf(stderr, "Could not set terminal attributes!\n");
143 return;
144 }
145
146 term_attributes_were_set = 1;
147}
148
149static void os_exit_line_edit_mode(void)
150{
151
152 if (!term_attributes_were_set) {
153 return;
154 }
155
156 /* Set terminal attributes back to the original values */
157
158 if (tcsetattr(STDIN_FILENO, TCSANOW, &original_term_attributes)) {
159 fprintf(stderr, "Could not restore terminal attributes!\n");
160 }
161}
162
163#else
164
165/* These functions are not needed for other ACPICA utilities */
166
167#define os_enter_line_edit_mode()
168#define os_exit_line_edit_mode()
169#endif
170
171/******************************************************************************
172 *
173 * FUNCTION: acpi_os_initialize, acpi_os_terminate
174 *
175 * PARAMETERS: None
176 *
177 * RETURN: Status
178 *
179 * DESCRIPTION: Initialize and terminate this module.
180 *
181 *****************************************************************************/
182
183acpi_status acpi_os_initialize(void)
184{
185 acpi_status status;
186
187 acpi_gbl_output_file = stdout;
188
189 os_enter_line_edit_mode();
190
191 status = acpi_os_create_lock(&acpi_gbl_print_lock);
192 if (ACPI_FAILURE(status)) {
193 return (status);
194 }
195
196 return (AE_OK);
197}
198
199acpi_status acpi_os_terminate(void)
200{
201
202 os_exit_line_edit_mode();
203 return (AE_OK);
204}
205
206#ifndef ACPI_USE_NATIVE_RSDP_POINTER
207/******************************************************************************
208 *
209 * FUNCTION: acpi_os_get_root_pointer
210 *
211 * PARAMETERS: None
212 *
213 * RETURN: RSDP physical address
214 *
215 * DESCRIPTION: Gets the ACPI root pointer (RSDP)
216 *
217 *****************************************************************************/
218
219acpi_physical_address acpi_os_get_root_pointer(void)
220{
221
222 return (0);
223}
224#endif
225
226/******************************************************************************
227 *
228 * FUNCTION: acpi_os_predefined_override
229 *
230 * PARAMETERS: init_val - Initial value of the predefined object
231 * new_val - The new value for the object
232 *
233 * RETURN: Status, pointer to value. Null pointer returned if not
234 * overriding.
235 *
236 * DESCRIPTION: Allow the OS to override predefined names
237 *
238 *****************************************************************************/
239
240acpi_status
241acpi_os_predefined_override(const struct acpi_predefined_names * init_val,
242 acpi_string * new_val)
243{
244
245 if (!init_val || !new_val) {
246 return (AE_BAD_PARAMETER);
247 }
248
249 *new_val = NULL;
250 return (AE_OK);
251}
252
253/******************************************************************************
254 *
255 * FUNCTION: acpi_os_table_override
256 *
257 * PARAMETERS: existing_table - Header of current table (probably
258 * firmware)
259 * new_table - Where an entire new table is returned.
260 *
261 * RETURN: Status, pointer to new table. Null pointer returned if no
262 * table is available to override
263 *
264 * DESCRIPTION: Return a different version of a table if one is available
265 *
266 *****************************************************************************/
267
268acpi_status
269acpi_os_table_override(struct acpi_table_header * existing_table,
270 struct acpi_table_header ** new_table)
271{
272
273 if (!existing_table || !new_table) {
274 return (AE_BAD_PARAMETER);
275 }
276
277 *new_table = NULL;
278
279#ifdef ACPI_EXEC_APP
280
281 ae_table_override(existing_table, new_table);
282 return (AE_OK);
283#else
284
285 return (AE_NO_ACPI_TABLES);
286#endif
287}
288
289/******************************************************************************
290 *
291 * FUNCTION: acpi_os_physical_table_override
292 *
293 * PARAMETERS: existing_table - Header of current table (probably firmware)
294 * new_address - Where new table address is returned
295 * (Physical address)
296 * new_table_length - Where new table length is returned
297 *
298 * RETURN: Status, address/length of new table. Null pointer returned
299 * if no table is available to override.
300 *
301 * DESCRIPTION: Returns AE_SUPPORT, function not used in user space.
302 *
303 *****************************************************************************/
304
305acpi_status
306acpi_os_physical_table_override(struct acpi_table_header * existing_table,
307 acpi_physical_address * new_address,
308 u32 *new_table_length)
309{
310
311 return (AE_SUPPORT);
312}
313
314/******************************************************************************
315 *
316 * FUNCTION: acpi_os_redirect_output
317 *
318 * PARAMETERS: destination - An open file handle/pointer
319 *
320 * RETURN: None
321 *
322 * DESCRIPTION: Causes redirect of acpi_os_printf and acpi_os_vprintf
323 *
324 *****************************************************************************/
325
326void acpi_os_redirect_output(void *destination)
327{
328
329 acpi_gbl_output_file = destination;
330}
331
332/******************************************************************************
333 *
334 * FUNCTION: acpi_os_printf
335 *
336 * PARAMETERS: fmt, ... - Standard printf format
337 *
338 * RETURN: None
339 *
340 * DESCRIPTION: Formatted output. Note: very similar to acpi_os_vprintf
341 * (performance), changes should be tracked in both functions.
342 *
343 *****************************************************************************/
344
345void ACPI_INTERNAL_VAR_XFACE acpi_os_printf(const char *fmt, ...)
346{
347 va_list args;
348 u8 flags;
349
350 flags = acpi_gbl_db_output_flags;
351 if (flags & ACPI_DB_REDIRECTABLE_OUTPUT) {
352
353 /* Output is directable to either a file (if open) or the console */
354
355 if (acpi_gbl_debug_file) {
356
357 /* Output file is open, send the output there */
358
359 va_start(args, fmt);
360 vfprintf(acpi_gbl_debug_file, fmt, args);
361 va_end(args);
362 } else {
363 /* No redirection, send output to console (once only!) */
364
365 flags |= ACPI_DB_CONSOLE_OUTPUT;
366 }
367 }
368
369 if (flags & ACPI_DB_CONSOLE_OUTPUT) {
370 va_start(args, fmt);
371 vfprintf(acpi_gbl_output_file, fmt, args);
372 va_end(args);
373 }
374}
375
376/******************************************************************************
377 *
378 * FUNCTION: acpi_os_vprintf
379 *
380 * PARAMETERS: fmt - Standard printf format
381 * args - Argument list
382 *
383 * RETURN: None
384 *
385 * DESCRIPTION: Formatted output with argument list pointer. Note: very
386 * similar to acpi_os_printf, changes should be tracked in both
387 * functions.
388 *
389 *****************************************************************************/
390
391void acpi_os_vprintf(const char *fmt, va_list args)
392{
393 u8 flags;
394 char buffer[ACPI_VPRINTF_BUFFER_SIZE];
395
396 /*
397 * We build the output string in a local buffer because we may be
398 * outputting the buffer twice. Using vfprintf is problematic because
399 * some implementations modify the args pointer/structure during
400 * execution. Thus, we use the local buffer for portability.
401 *
402 * Note: Since this module is intended for use by the various ACPICA
403 * utilities/applications, we can safely declare the buffer on the stack.
404 * Also, This function is used for relatively small error messages only.
405 */
406 vsnprintf(buffer, ACPI_VPRINTF_BUFFER_SIZE, fmt, args);
407
408 flags = acpi_gbl_db_output_flags;
409 if (flags & ACPI_DB_REDIRECTABLE_OUTPUT) {
410
411 /* Output is directable to either a file (if open) or the console */
412
413 if (acpi_gbl_debug_file) {
414
415 /* Output file is open, send the output there */
416
417 fputs(buffer, acpi_gbl_debug_file);
418 } else {
419 /* No redirection, send output to console (once only!) */
420
421 flags |= ACPI_DB_CONSOLE_OUTPUT;
422 }
423 }
424
425 if (flags & ACPI_DB_CONSOLE_OUTPUT) {
426 fputs(buffer, acpi_gbl_output_file);
427 }
428}
429
430#ifndef ACPI_EXEC_APP
431/******************************************************************************
432 *
433 * FUNCTION: acpi_os_get_line
434 *
435 * PARAMETERS: buffer - Where to return the command line
436 * buffer_length - Maximum length of Buffer
437 * bytes_read - Where the actual byte count is returned
438 *
439 * RETURN: Status and actual bytes read
440 *
441 * DESCRIPTION: Get the next input line from the terminal. NOTE: For the
442 * acpi_exec utility, we use the acgetline module instead to
443 * provide line-editing and history support.
444 *
445 *****************************************************************************/
446
447acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read)
448{
449 int input_char;
450 u32 end_of_line;
451
452 /* Standard acpi_os_get_line for all utilities except acpi_exec */
453
454 for (end_of_line = 0;; end_of_line++) {
455 if (end_of_line >= buffer_length) {
456 return (AE_BUFFER_OVERFLOW);
457 }
458
459 if ((input_char = getchar()) == EOF) {
460 return (AE_ERROR);
461 }
462
463 if (!input_char || input_char == _ASCII_NEWLINE) {
464 break;
465 }
466
467 buffer[end_of_line] = (char)input_char;
468 }
469
470 /* Null terminate the buffer */
471
472 buffer[end_of_line] = 0;
473
474 /* Return the number of bytes in the string */
475
476 if (bytes_read) {
477 *bytes_read = end_of_line;
478 }
479
480 return (AE_OK);
481}
482#endif
483
484#ifndef ACPI_USE_NATIVE_MEMORY_MAPPING
485/******************************************************************************
486 *
487 * FUNCTION: acpi_os_map_memory
488 *
489 * PARAMETERS: where - Physical address of memory to be mapped
490 * length - How much memory to map
491 *
492 * RETURN: Pointer to mapped memory. Null on error.
493 *
494 * DESCRIPTION: Map physical memory into caller's address space
495 *
496 *****************************************************************************/
497
498void *acpi_os_map_memory(acpi_physical_address where, acpi_size length)
499{
500
501 return (ACPI_TO_POINTER((acpi_size) where));
502}
503
504/******************************************************************************
505 *
506 * FUNCTION: acpi_os_unmap_memory
507 *
508 * PARAMETERS: where - Logical address of memory to be unmapped
509 * length - How much memory to unmap
510 *
511 * RETURN: None.
512 *
513 * DESCRIPTION: Delete a previously created mapping. Where and Length must
514 * correspond to a previous mapping exactly.
515 *
516 *****************************************************************************/
517
518void acpi_os_unmap_memory(void *where, acpi_size length)
519{
520
521 return;
522}
523#endif
524
525/******************************************************************************
526 *
527 * FUNCTION: acpi_os_allocate
528 *
529 * PARAMETERS: size - Amount to allocate, in bytes
530 *
531 * RETURN: Pointer to the new allocation. Null on error.
532 *
533 * DESCRIPTION: Allocate memory. Algorithm is dependent on the OS.
534 *
535 *****************************************************************************/
536
537void *acpi_os_allocate(acpi_size size)
538{
539 void *mem;
540
541 mem = (void *)malloc((size_t) size);
542 return (mem);
543}
544
545#ifdef USE_NATIVE_ALLOCATE_ZEROED
546/******************************************************************************
547 *
548 * FUNCTION: acpi_os_allocate_zeroed
549 *
550 * PARAMETERS: size - Amount to allocate, in bytes
551 *
552 * RETURN: Pointer to the new allocation. Null on error.
553 *
554 * DESCRIPTION: Allocate and zero memory. Algorithm is dependent on the OS.
555 *
556 *****************************************************************************/
557
558void *acpi_os_allocate_zeroed(acpi_size size)
559{
560 void *mem;
561
562 mem = (void *)calloc(1, (size_t) size);
563 return (mem);
564}
565#endif
566
567/******************************************************************************
568 *
569 * FUNCTION: acpi_os_free
570 *
571 * PARAMETERS: mem - Pointer to previously allocated memory
572 *
573 * RETURN: None.
574 *
575 * DESCRIPTION: Free memory allocated via acpi_os_allocate
576 *
577 *****************************************************************************/
578
579void acpi_os_free(void *mem)
580{
581
582 free(mem);
583}
584
585#ifdef ACPI_SINGLE_THREADED
586/******************************************************************************
587 *
588 * FUNCTION: Semaphore stub functions
589 *
590 * DESCRIPTION: Stub functions used for single-thread applications that do
591 * not require semaphore synchronization. Full implementations
592 * of these functions appear after the stubs.
593 *
594 *****************************************************************************/
595
596acpi_status
597acpi_os_create_semaphore(u32 max_units,
598 u32 initial_units, acpi_handle * out_handle)
599{
600 *out_handle = (acpi_handle) 1;
601 return (AE_OK);
602}
603
604acpi_status acpi_os_delete_semaphore(acpi_handle handle)
605{
606 return (AE_OK);
607}
608
609acpi_status acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 timeout)
610{
611 return (AE_OK);
612}
613
614acpi_status acpi_os_signal_semaphore(acpi_handle handle, u32 units)
615{
616 return (AE_OK);
617}
618
619#else
620/******************************************************************************
621 *
622 * FUNCTION: acpi_os_create_semaphore
623 *
624 * PARAMETERS: initial_units - Units to be assigned to the new semaphore
625 * out_handle - Where a handle will be returned
626 *
627 * RETURN: Status
628 *
629 * DESCRIPTION: Create an OS semaphore
630 *
631 *****************************************************************************/
632
633acpi_status
634acpi_os_create_semaphore(u32 max_units,
635 u32 initial_units, acpi_handle * out_handle)
636{
637 sem_t *sem;
638
639 if (!out_handle) {
640 return (AE_BAD_PARAMETER);
641 }
642#ifdef __APPLE__
643 {
644 char *semaphore_name = tmpnam(NULL);
645
646 sem =
647 sem_open(semaphore_name, O_EXCL | O_CREAT, 0755,
648 initial_units);
649 if (!sem) {
650 return (AE_NO_MEMORY);
651 }
652 sem_unlink(semaphore_name); /* This just deletes the name */
653 }
654
655#else
656 sem = acpi_os_allocate(sizeof(sem_t));
657 if (!sem) {
658 return (AE_NO_MEMORY);
659 }
660
661 if (sem_init(sem, 0, initial_units) == -1) {
662 acpi_os_free(sem);
663 return (AE_BAD_PARAMETER);
664 }
665#endif
666
667 *out_handle = (acpi_handle) sem;
668 return (AE_OK);
669}
670
671/******************************************************************************
672 *
673 * FUNCTION: acpi_os_delete_semaphore
674 *
675 * PARAMETERS: handle - Handle returned by acpi_os_create_semaphore
676 *
677 * RETURN: Status
678 *
679 * DESCRIPTION: Delete an OS semaphore
680 *
681 *****************************************************************************/
682
683acpi_status acpi_os_delete_semaphore(acpi_handle handle)
684{
685 sem_t *sem = (sem_t *) handle;
686
687 if (!sem) {
688 return (AE_BAD_PARAMETER);
689 }
690
691 if (sem_destroy(sem) == -1) {
692 return (AE_BAD_PARAMETER);
693 }
694
695 return (AE_OK);
696}
697
698/******************************************************************************
699 *
700 * FUNCTION: acpi_os_wait_semaphore
701 *
702 * PARAMETERS: handle - Handle returned by acpi_os_create_semaphore
703 * units - How many units to wait for
704 * msec_timeout - How long to wait (milliseconds)
705 *
706 * RETURN: Status
707 *
708 * DESCRIPTION: Wait for units
709 *
710 *****************************************************************************/
711
712acpi_status
713acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 msec_timeout)
714{
715 acpi_status status = AE_OK;
716 sem_t *sem = (sem_t *) handle;
717#ifndef ACPI_USE_ALTERNATE_TIMEOUT
718 struct timespec time;
719 int ret_val;
720#endif
721
722 if (!sem) {
723 return (AE_BAD_PARAMETER);
724 }
725
726 switch (msec_timeout) {
727 /*
728 * No Wait:
729 * --------
730 * A zero timeout value indicates that we shouldn't wait - just
731 * acquire the semaphore if available otherwise return AE_TIME
732 * (a.k.a. 'would block').
733 */
734 case 0:
735
736 if (sem_trywait(sem) == -1) {
737 status = (AE_TIME);
738 }
739 break;
740
741 /* Wait Indefinitely */
742
743 case ACPI_WAIT_FOREVER:
744
745 if (sem_wait(sem)) {
746 status = (AE_TIME);
747 }
748 break;
749
750 /* Wait with msec_timeout */
751
752 default:
753
754#ifdef ACPI_USE_ALTERNATE_TIMEOUT
755 /*
756 * Alternate timeout mechanism for environments where
757 * sem_timedwait is not available or does not work properly.
758 */
759 while (msec_timeout) {
760 if (sem_trywait(sem) == 0) {
761
762 /* Got the semaphore */
763 return (AE_OK);
764 }
765
766 if (msec_timeout >= 10) {
767 msec_timeout -= 10;
768 usleep(10 * ACPI_USEC_PER_MSEC); /* ten milliseconds */
769 } else {
770 msec_timeout--;
771 usleep(ACPI_USEC_PER_MSEC); /* one millisecond */
772 }
773 }
774 status = (AE_TIME);
775#else
776 /*
777 * The interface to sem_timedwait is an absolute time, so we need to
778 * get the current time, then add in the millisecond Timeout value.
779 */
780 if (clock_gettime(CLOCK_REALTIME, &time) == -1) {
781 perror("clock_gettime");
782 return (AE_TIME);
783 }
784
785 time.tv_sec += (msec_timeout / ACPI_MSEC_PER_SEC);
786 time.tv_nsec +=
787 ((msec_timeout % ACPI_MSEC_PER_SEC) * ACPI_NSEC_PER_MSEC);
788
789 /* Handle nanosecond overflow (field must be less than one second) */
790
791 if (time.tv_nsec >= ACPI_NSEC_PER_SEC) {
792 time.tv_sec += (time.tv_nsec / ACPI_NSEC_PER_SEC);
793 time.tv_nsec = (time.tv_nsec % ACPI_NSEC_PER_SEC);
794 }
795
796 while (((ret_val = sem_timedwait(sem, &time)) == -1)
797 && (errno == EINTR)) {
798 continue;
799 }
800
801 if (ret_val != 0) {
802 if (errno != ETIMEDOUT) {
803 perror("sem_timedwait");
804 }
805 status = (AE_TIME);
806 }
807#endif
808 break;
809 }
810
811 return (status);
812}
813
814/******************************************************************************
815 *
816 * FUNCTION: acpi_os_signal_semaphore
817 *
818 * PARAMETERS: handle - Handle returned by acpi_os_create_semaphore
819 * units - Number of units to send
820 *
821 * RETURN: Status
822 *
823 * DESCRIPTION: Send units
824 *
825 *****************************************************************************/
826
827acpi_status acpi_os_signal_semaphore(acpi_handle handle, u32 units)
828{
829 sem_t *sem = (sem_t *) handle;
830
831 if (!sem) {
832 return (AE_BAD_PARAMETER);
833 }
834
835 if (sem_post(sem) == -1) {
836 return (AE_LIMIT);
837 }
838
839 return (AE_OK);
840}
841
842#endif /* ACPI_SINGLE_THREADED */
843
844/******************************************************************************
845 *
846 * FUNCTION: Spinlock interfaces
847 *
848 * DESCRIPTION: Map these interfaces to semaphore interfaces
849 *
850 *****************************************************************************/
851
852acpi_status acpi_os_create_lock(acpi_spinlock * out_handle)
853{
854
855 return (acpi_os_create_semaphore(1, 1, out_handle));
856}
857
858void acpi_os_delete_lock(acpi_spinlock handle)
859{
860 acpi_os_delete_semaphore(handle);
861}
862
863acpi_cpu_flags acpi_os_acquire_lock(acpi_handle handle)
864{
865 acpi_os_wait_semaphore(handle, 1, 0xFFFF);
866 return (0);
867}
868
869void acpi_os_release_lock(acpi_spinlock handle, acpi_cpu_flags flags)
870{
871 acpi_os_signal_semaphore(handle, 1);
872}
873
874/******************************************************************************
875 *
876 * FUNCTION: acpi_os_install_interrupt_handler
877 *
878 * PARAMETERS: interrupt_number - Level handler should respond to.
879 * isr - Address of the ACPI interrupt handler
880 * except_ptr - Where status is returned
881 *
882 * RETURN: Handle to the newly installed handler.
883 *
884 * DESCRIPTION: Install an interrupt handler. Used to install the ACPI
885 * OS-independent handler.
886 *
887 *****************************************************************************/
888
889u32
890acpi_os_install_interrupt_handler(u32 interrupt_number,
891 acpi_osd_handler service_routine,
892 void *context)
893{
894
895 return (AE_OK);
896}
897
898/******************************************************************************
899 *
900 * FUNCTION: acpi_os_remove_interrupt_handler
901 *
902 * PARAMETERS: handle - Returned when handler was installed
903 *
904 * RETURN: Status
905 *
906 * DESCRIPTION: Uninstalls an interrupt handler.
907 *
908 *****************************************************************************/
909
910acpi_status
911acpi_os_remove_interrupt_handler(u32 interrupt_number,
912 acpi_osd_handler service_routine)
913{
914
915 return (AE_OK);
916}
917
918/******************************************************************************
919 *
920 * FUNCTION: acpi_os_stall
921 *
922 * PARAMETERS: microseconds - Time to sleep
923 *
924 * RETURN: Blocks until sleep is completed.
925 *
926 * DESCRIPTION: Sleep at microsecond granularity
927 *
928 *****************************************************************************/
929
930void acpi_os_stall(u32 microseconds)
931{
932
933 if (microseconds) {
934 usleep(microseconds);
935 }
936}
937
938/******************************************************************************
939 *
940 * FUNCTION: acpi_os_sleep
941 *
942 * PARAMETERS: milliseconds - Time to sleep
943 *
944 * RETURN: Blocks until sleep is completed.
945 *
946 * DESCRIPTION: Sleep at millisecond granularity
947 *
948 *****************************************************************************/
949
950void acpi_os_sleep(u64 milliseconds)
951{
952
953 /* Sleep for whole seconds */
954
955 sleep(milliseconds / ACPI_MSEC_PER_SEC);
956
957 /*
958 * Sleep for remaining microseconds.
959 * Arg to usleep() is in usecs and must be less than 1,000,000 (1 second).
960 */
961 usleep((milliseconds % ACPI_MSEC_PER_SEC) * ACPI_USEC_PER_MSEC);
962}
963
964/******************************************************************************
965 *
966 * FUNCTION: acpi_os_get_timer
967 *
968 * PARAMETERS: None
969 *
970 * RETURN: Current time in 100 nanosecond units
971 *
972 * DESCRIPTION: Get the current system time
973 *
974 *****************************************************************************/
975
976u64 acpi_os_get_timer(void)
977{
978 struct timeval time;
979
980 /* This timer has sufficient resolution for user-space application code */
981
982 gettimeofday(&time, NULL);
983
984 /* (Seconds * 10^7 = 100ns(10^-7)) + (Microseconds(10^-6) * 10^1 = 100ns) */
985
986 return (((u64)time.tv_sec * ACPI_100NSEC_PER_SEC) +
987 ((u64)time.tv_usec * ACPI_100NSEC_PER_USEC));
988}
989
990/******************************************************************************
991 *
992 * FUNCTION: acpi_os_read_pci_configuration
993 *
994 * PARAMETERS: pci_id - Seg/Bus/Dev
995 * pci_register - Device Register
996 * value - Buffer where value is placed
997 * width - Number of bits
998 *
999 * RETURN: Status
1000 *
1001 * DESCRIPTION: Read data from PCI configuration space
1002 *
1003 *****************************************************************************/
1004
1005acpi_status
1006acpi_os_read_pci_configuration(struct acpi_pci_id *pci_id,
1007 u32 pci_register, u64 *value, u32 width)
1008{
1009
1010 *value = 0;
1011 return (AE_OK);
1012}
1013
1014/******************************************************************************
1015 *
1016 * FUNCTION: acpi_os_write_pci_configuration
1017 *
1018 * PARAMETERS: pci_id - Seg/Bus/Dev
1019 * pci_register - Device Register
1020 * value - Value to be written
1021 * width - Number of bits
1022 *
1023 * RETURN: Status.
1024 *
1025 * DESCRIPTION: Write data to PCI configuration space
1026 *
1027 *****************************************************************************/
1028
1029acpi_status
1030acpi_os_write_pci_configuration(struct acpi_pci_id * pci_id,
1031 u32 pci_register, u64 value, u32 width)
1032{
1033
1034 return (AE_OK);
1035}
1036
1037/******************************************************************************
1038 *
1039 * FUNCTION: acpi_os_read_port
1040 *
1041 * PARAMETERS: address - Address of I/O port/register to read
1042 * value - Where value is placed
1043 * width - Number of bits
1044 *
1045 * RETURN: Value read from port
1046 *
1047 * DESCRIPTION: Read data from an I/O port or register
1048 *
1049 *****************************************************************************/
1050
1051acpi_status acpi_os_read_port(acpi_io_address address, u32 *value, u32 width)
1052{
1053
1054 switch (width) {
1055 case 8:
1056
1057 *value = 0xFF;
1058 break;
1059
1060 case 16:
1061
1062 *value = 0xFFFF;
1063 break;
1064
1065 case 32:
1066
1067 *value = 0xFFFFFFFF;
1068 break;
1069
1070 default:
1071
1072 return (AE_BAD_PARAMETER);
1073 }
1074
1075 return (AE_OK);
1076}
1077
1078/******************************************************************************
1079 *
1080 * FUNCTION: acpi_os_write_port
1081 *
1082 * PARAMETERS: address - Address of I/O port/register to write
1083 * value - Value to write
1084 * width - Number of bits
1085 *
1086 * RETURN: None
1087 *
1088 * DESCRIPTION: Write data to an I/O port or register
1089 *
1090 *****************************************************************************/
1091
1092acpi_status acpi_os_write_port(acpi_io_address address, u32 value, u32 width)
1093{
1094
1095 return (AE_OK);
1096}
1097
1098/******************************************************************************
1099 *
1100 * FUNCTION: acpi_os_read_memory
1101 *
1102 * PARAMETERS: address - Physical Memory Address to read
1103 * value - Where value is placed
1104 * width - Number of bits (8,16,32, or 64)
1105 *
1106 * RETURN: Value read from physical memory address. Always returned
1107 * as a 64-bit integer, regardless of the read width.
1108 *
1109 * DESCRIPTION: Read data from a physical memory address
1110 *
1111 *****************************************************************************/
1112
1113acpi_status
1114acpi_os_read_memory(acpi_physical_address address, u64 *value, u32 width)
1115{
1116
1117 switch (width) {
1118 case 8:
1119 case 16:
1120 case 32:
1121 case 64:
1122
1123 *value = 0;
1124 break;
1125
1126 default:
1127
1128 return (AE_BAD_PARAMETER);
1129 }
1130 return (AE_OK);
1131}
1132
1133/******************************************************************************
1134 *
1135 * FUNCTION: acpi_os_write_memory
1136 *
1137 * PARAMETERS: address - Physical Memory Address to write
1138 * value - Value to write
1139 * width - Number of bits (8,16,32, or 64)
1140 *
1141 * RETURN: None
1142 *
1143 * DESCRIPTION: Write data to a physical memory address
1144 *
1145 *****************************************************************************/
1146
1147acpi_status
1148acpi_os_write_memory(acpi_physical_address address, u64 value, u32 width)
1149{
1150
1151 return (AE_OK);
1152}
1153
1154/******************************************************************************
1155 *
1156 * FUNCTION: acpi_os_readable
1157 *
1158 * PARAMETERS: pointer - Area to be verified
1159 * length - Size of area
1160 *
1161 * RETURN: TRUE if readable for entire length
1162 *
1163 * DESCRIPTION: Verify that a pointer is valid for reading
1164 *
1165 *****************************************************************************/
1166
1167u8 acpi_os_readable(void *pointer, acpi_size length)
1168{
1169
1170 return (TRUE);
1171}
1172
1173/******************************************************************************
1174 *
1175 * FUNCTION: acpi_os_writable
1176 *
1177 * PARAMETERS: pointer - Area to be verified
1178 * length - Size of area
1179 *
1180 * RETURN: TRUE if writable for entire length
1181 *
1182 * DESCRIPTION: Verify that a pointer is valid for writing
1183 *
1184 *****************************************************************************/
1185
1186u8 acpi_os_writable(void *pointer, acpi_size length)
1187{
1188
1189 return (TRUE);
1190}
1191
1192/******************************************************************************
1193 *
1194 * FUNCTION: acpi_os_signal
1195 *
1196 * PARAMETERS: function - ACPI A signal function code
1197 * info - Pointer to function-dependent structure
1198 *
1199 * RETURN: Status
1200 *
1201 * DESCRIPTION: Miscellaneous functions. Example implementation only.
1202 *
1203 *****************************************************************************/
1204
1205acpi_status acpi_os_signal(u32 function, void *info)
1206{
1207
1208 switch (function) {
1209 case ACPI_SIGNAL_FATAL:
1210
1211 break;
1212
1213 case ACPI_SIGNAL_BREAKPOINT:
1214
1215 break;
1216
1217 default:
1218
1219 break;
1220 }
1221
1222 return (AE_OK);
1223}
1224
1225/* Optional multi-thread support */
1226
1227#ifndef ACPI_SINGLE_THREADED
1228/******************************************************************************
1229 *
1230 * FUNCTION: acpi_os_get_thread_id
1231 *
1232 * PARAMETERS: None
1233 *
1234 * RETURN: Id of the running thread
1235 *
1236 * DESCRIPTION: Get the ID of the current (running) thread
1237 *
1238 *****************************************************************************/
1239
1240acpi_thread_id acpi_os_get_thread_id(void)
1241{
1242 pthread_t thread;
1243
1244 thread = pthread_self();
1245 return (ACPI_CAST_PTHREAD_T(thread));
1246}
1247
1248/******************************************************************************
1249 *
1250 * FUNCTION: acpi_os_execute
1251 *
1252 * PARAMETERS: type - Type of execution
1253 * function - Address of the function to execute
1254 * context - Passed as a parameter to the function
1255 *
1256 * RETURN: Status.
1257 *
1258 * DESCRIPTION: Execute a new thread
1259 *
1260 *****************************************************************************/
1261
1262acpi_status
1263acpi_os_execute(acpi_execute_type type,
1264 acpi_osd_exec_callback function, void *context)
1265{
1266 pthread_t thread;
1267 int ret;
1268
1269 ret =
1270 pthread_create(&thread, NULL, (PTHREAD_CALLBACK) function, context);
1271 if (ret) {
1272 acpi_os_printf("Create thread failed");
1273 }
1274 return (0);
1275}
1276
1277#else /* ACPI_SINGLE_THREADED */
1278acpi_thread_id acpi_os_get_thread_id(void)
1279{
1280 return (1);
1281}
1282
1283acpi_status
1284acpi_os_execute(acpi_execute_type type,
1285 acpi_osd_exec_callback function, void *context)
1286{
1287
1288 function(context);
1289
1290 return (AE_OK);
1291}
1292
1293#endif /* ACPI_SINGLE_THREADED */
1294
1295/******************************************************************************
1296 *
1297 * FUNCTION: acpi_os_wait_events_complete
1298 *
1299 * PARAMETERS: None
1300 *
1301 * RETURN: None
1302 *
1303 * DESCRIPTION: Wait for all asynchronous events to complete. This
1304 * implementation does nothing.
1305 *
1306 *****************************************************************************/
1307
1308void acpi_os_wait_events_complete(void)
1309{
1310 return;
1311}
diff --git a/tools/power/acpi/tools/acpidump/acpidump.h b/tools/power/acpi/tools/acpidump/acpidump.h
index 46f519597fe5..a2d37d610639 100644
--- a/tools/power/acpi/tools/acpidump/acpidump.h
+++ b/tools/power/acpi/tools/acpidump/acpidump.h
@@ -47,7 +47,6 @@
47#ifdef _DECLARE_GLOBALS 47#ifdef _DECLARE_GLOBALS
48#define EXTERN 48#define EXTERN
49#define INIT_GLOBAL(a,b) a=b 49#define INIT_GLOBAL(a,b) a=b
50#define DEFINE_ACPI_GLOBALS 1
51#else 50#else
52#define EXTERN extern 51#define EXTERN extern
53#define INIT_GLOBAL(a,b) a 52#define INIT_GLOBAL(a,b) a
@@ -69,7 +68,7 @@ EXTERN u8 INIT_GLOBAL(gbl_verbose_mode, FALSE);
69EXTERN u8 INIT_GLOBAL(gbl_binary_mode, FALSE); 68EXTERN u8 INIT_GLOBAL(gbl_binary_mode, FALSE);
70EXTERN u8 INIT_GLOBAL(gbl_dump_customized_tables, FALSE); 69EXTERN u8 INIT_GLOBAL(gbl_dump_customized_tables, FALSE);
71EXTERN u8 INIT_GLOBAL(gbl_do_not_dump_xsdt, FALSE); 70EXTERN u8 INIT_GLOBAL(gbl_do_not_dump_xsdt, FALSE);
72EXTERN FILE INIT_GLOBAL(*gbl_output_file, NULL); 71EXTERN ACPI_FILE INIT_GLOBAL(gbl_output_file, NULL);
73EXTERN char INIT_GLOBAL(*gbl_output_filename, NULL); 72EXTERN char INIT_GLOBAL(*gbl_output_filename, NULL);
74EXTERN u64 INIT_GLOBAL(gbl_rsdp_base, 0); 73EXTERN u64 INIT_GLOBAL(gbl_rsdp_base, 0);
75 74
diff --git a/tools/power/acpi/tools/acpidump/apdump.c b/tools/power/acpi/tools/acpidump/apdump.c
index 3cac12378366..53cee781e24e 100644
--- a/tools/power/acpi/tools/acpidump/apdump.c
+++ b/tools/power/acpi/tools/acpidump/apdump.c
@@ -69,17 +69,16 @@ u8 ap_is_valid_header(struct acpi_table_header *table)
69 /* Make sure signature is all ASCII and a valid ACPI name */ 69 /* Make sure signature is all ASCII and a valid ACPI name */
70 70
71 if (!acpi_ut_valid_acpi_name(table->signature)) { 71 if (!acpi_ut_valid_acpi_name(table->signature)) {
72 fprintf(stderr, 72 acpi_log_error("Table signature (0x%8.8X) is invalid\n",
73 "Table signature (0x%8.8X) is invalid\n", 73 *(u32 *)table->signature);
74 *(u32 *)table->signature);
75 return (FALSE); 74 return (FALSE);
76 } 75 }
77 76
78 /* Check for minimum table length */ 77 /* Check for minimum table length */
79 78
80 if (table->length < sizeof(struct acpi_table_header)) { 79 if (table->length < sizeof(struct acpi_table_header)) {
81 fprintf(stderr, "Table length (0x%8.8X) is invalid\n", 80 acpi_log_error("Table length (0x%8.8X) is invalid\n",
82 table->length); 81 table->length);
83 return (FALSE); 82 return (FALSE);
84 } 83 }
85 } 84 }
@@ -116,8 +115,8 @@ u8 ap_is_valid_checksum(struct acpi_table_header *table)
116 } 115 }
117 116
118 if (ACPI_FAILURE(status)) { 117 if (ACPI_FAILURE(status)) {
119 fprintf(stderr, "%4.4s: Warning: wrong checksum in table\n", 118 acpi_log_error("%4.4s: Warning: wrong checksum in table\n",
120 table->signature); 119 table->signature);
121 } 120 }
122 121
123 return (AE_OK); 122 return (AE_OK);
@@ -196,12 +195,13 @@ ap_dump_table_buffer(struct acpi_table_header *table,
196 * Note: simplest to just always emit a 64-bit address. acpi_xtract 195 * Note: simplest to just always emit a 64-bit address. acpi_xtract
197 * utility can handle this. 196 * utility can handle this.
198 */ 197 */
199 printf("%4.4s @ 0x%8.8X%8.8X\n", table->signature, 198 acpi_ut_file_printf(gbl_output_file, "%4.4s @ 0x%8.8X%8.8X\n",
200 ACPI_FORMAT_UINT64(address)); 199 table->signature, ACPI_FORMAT_UINT64(address));
201 200
202 acpi_ut_dump_buffer(ACPI_CAST_PTR(u8, table), table_length, 201 acpi_ut_dump_buffer_to_file(gbl_output_file,
203 DB_BYTE_DISPLAY, 0); 202 ACPI_CAST_PTR(u8, table), table_length,
204 printf("\n"); 203 DB_BYTE_DISPLAY, 0);
204 acpi_ut_file_printf(gbl_output_file, "\n");
205 return (0); 205 return (0);
206} 206}
207 207
@@ -239,20 +239,20 @@ int ap_dump_all_tables(void)
239 if (status == AE_LIMIT) { 239 if (status == AE_LIMIT) {
240 return (0); 240 return (0);
241 } else if (i == 0) { 241 } else if (i == 0) {
242 fprintf(stderr, 242 acpi_log_error
243 "Could not get ACPI tables, %s\n", 243 ("Could not get ACPI tables, %s\n",
244 acpi_format_exception(status)); 244 acpi_format_exception(status));
245 return (-1); 245 return (-1);
246 } else { 246 } else {
247 fprintf(stderr, 247 acpi_log_error
248 "Could not get ACPI table at index %u, %s\n", 248 ("Could not get ACPI table at index %u, %s\n",
249 i, acpi_format_exception(status)); 249 i, acpi_format_exception(status));
250 continue; 250 continue;
251 } 251 }
252 } 252 }
253 253
254 table_status = ap_dump_table_buffer(table, instance, address); 254 table_status = ap_dump_table_buffer(table, instance, address);
255 free(table); 255 ACPI_FREE(table);
256 256
257 if (table_status) { 257 if (table_status) {
258 break; 258 break;
@@ -288,22 +288,22 @@ int ap_dump_table_by_address(char *ascii_address)
288 288
289 status = acpi_ut_strtoul64(ascii_address, 0, &long_address); 289 status = acpi_ut_strtoul64(ascii_address, 0, &long_address);
290 if (ACPI_FAILURE(status)) { 290 if (ACPI_FAILURE(status)) {
291 fprintf(stderr, "%s: Could not convert to a physical address\n", 291 acpi_log_error("%s: Could not convert to a physical address\n",
292 ascii_address); 292 ascii_address);
293 return (-1); 293 return (-1);
294 } 294 }
295 295
296 address = (acpi_physical_address) long_address; 296 address = (acpi_physical_address) long_address;
297 status = acpi_os_get_table_by_address(address, &table); 297 status = acpi_os_get_table_by_address(address, &table);
298 if (ACPI_FAILURE(status)) { 298 if (ACPI_FAILURE(status)) {
299 fprintf(stderr, "Could not get table at 0x%8.8X%8.8X, %s\n", 299 acpi_log_error("Could not get table at 0x%8.8X%8.8X, %s\n",
300 ACPI_FORMAT_UINT64(address), 300 ACPI_FORMAT_UINT64(address),
301 acpi_format_exception(status)); 301 acpi_format_exception(status));
302 return (-1); 302 return (-1);
303 } 303 }
304 304
305 table_status = ap_dump_table_buffer(table, 0, address); 305 table_status = ap_dump_table_buffer(table, 0, address);
306 free(table); 306 ACPI_FREE(table);
307 return (table_status); 307 return (table_status);
308} 308}
309 309
@@ -329,24 +329,24 @@ int ap_dump_table_by_name(char *signature)
329 acpi_status status; 329 acpi_status status;
330 int table_status; 330 int table_status;
331 331
332 if (strlen(signature) != ACPI_NAME_SIZE) { 332 if (ACPI_STRLEN(signature) != ACPI_NAME_SIZE) {
333 fprintf(stderr, 333 acpi_log_error
334 "Invalid table signature [%s]: must be exactly 4 characters\n", 334 ("Invalid table signature [%s]: must be exactly 4 characters\n",
335 signature); 335 signature);
336 return (-1); 336 return (-1);
337 } 337 }
338 338
339 /* Table signatures are expected to be uppercase */ 339 /* Table signatures are expected to be uppercase */
340 340
341 strcpy(local_signature, signature); 341 ACPI_STRCPY(local_signature, signature);
342 acpi_ut_strupr(local_signature); 342 acpi_ut_strupr(local_signature);
343 343
344 /* To be friendly, handle tables whose signatures do not match the name */ 344 /* To be friendly, handle tables whose signatures do not match the name */
345 345
346 if (ACPI_COMPARE_NAME(local_signature, "FADT")) { 346 if (ACPI_COMPARE_NAME(local_signature, "FADT")) {
347 strcpy(local_signature, ACPI_SIG_FADT); 347 ACPI_STRCPY(local_signature, ACPI_SIG_FADT);
348 } else if (ACPI_COMPARE_NAME(local_signature, "MADT")) { 348 } else if (ACPI_COMPARE_NAME(local_signature, "MADT")) {
349 strcpy(local_signature, ACPI_SIG_MADT); 349 ACPI_STRCPY(local_signature, ACPI_SIG_MADT);
350 } 350 }
351 351
352 /* Dump all instances of this signature (to handle multiple SSDTs) */ 352 /* Dump all instances of this signature (to handle multiple SSDTs) */
@@ -362,14 +362,14 @@ int ap_dump_table_by_name(char *signature)
362 return (0); 362 return (0);
363 } 363 }
364 364
365 fprintf(stderr, 365 acpi_log_error
366 "Could not get ACPI table with signature [%s], %s\n", 366 ("Could not get ACPI table with signature [%s], %s\n",
367 local_signature, acpi_format_exception(status)); 367 local_signature, acpi_format_exception(status));
368 return (-1); 368 return (-1);
369 } 369 }
370 370
371 table_status = ap_dump_table_buffer(table, instance, address); 371 table_status = ap_dump_table_buffer(table, instance, address);
372 free(table); 372 ACPI_FREE(table);
373 373
374 if (table_status) { 374 if (table_status) {
375 break; 375 break;
@@ -409,43 +409,21 @@ int ap_dump_table_from_file(char *pathname)
409 /* File must be at least as long as the table length */ 409 /* File must be at least as long as the table length */
410 410
411 if (table->length > file_size) { 411 if (table->length > file_size) {
412 fprintf(stderr, 412 acpi_log_error
413 "Table length (0x%X) is too large for input file (0x%X) %s\n", 413 ("Table length (0x%X) is too large for input file (0x%X) %s\n",
414 table->length, file_size, pathname); 414 table->length, file_size, pathname);
415 goto exit; 415 goto exit;
416 } 416 }
417 417
418 if (gbl_verbose_mode) { 418 if (gbl_verbose_mode) {
419 fprintf(stderr, 419 acpi_log_error
420 "Input file: %s contains table [%4.4s], 0x%X (%u) bytes\n", 420 ("Input file: %s contains table [%4.4s], 0x%X (%u) bytes\n",
421 pathname, table->signature, file_size, file_size); 421 pathname, table->signature, file_size, file_size);
422 } 422 }
423 423
424 table_status = ap_dump_table_buffer(table, 0, 0); 424 table_status = ap_dump_table_buffer(table, 0, 0);
425 425
426exit: 426exit:
427 free(table); 427 ACPI_FREE(table);
428 return (table_status); 428 return (table_status);
429} 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
index 4488accc010b..d470046a6d81 100644
--- a/tools/power/acpi/tools/acpidump/apfiles.c
+++ b/tools/power/acpi/tools/acpidump/apfiles.c
@@ -44,6 +44,27 @@
44#include "acpidump.h" 44#include "acpidump.h"
45#include "acapps.h" 45#include "acapps.h"
46 46
47/* Local prototypes */
48
49static int ap_is_existing_file(char *pathname);
50
51static int ap_is_existing_file(char *pathname)
52{
53#ifndef _GNU_EFI
54 struct stat stat_info;
55
56 if (!stat(pathname, &stat_info)) {
57 acpi_log_error("Target path already exists, overwrite? [y|n] ");
58
59 if (getchar() != 'y') {
60 return (-1);
61 }
62 }
63#endif
64
65 return 0;
66}
67
47/****************************************************************************** 68/******************************************************************************
48 * 69 *
49 * FUNCTION: ap_open_output_file 70 * FUNCTION: ap_open_output_file
@@ -59,25 +80,19 @@
59 80
60int ap_open_output_file(char *pathname) 81int ap_open_output_file(char *pathname)
61{ 82{
62 struct stat stat_info; 83 ACPI_FILE file;
63 FILE *file;
64 84
65 /* If file exists, prompt for overwrite */ 85 /* If file exists, prompt for overwrite */
66 86
67 if (!stat(pathname, &stat_info)) { 87 if (ap_is_existing_file(pathname) != 0) {
68 fprintf(stderr, 88 return (-1);
69 "Target path already exists, overwrite? [y|n] ");
70
71 if (getchar() != 'y') {
72 return (-1);
73 }
74 } 89 }
75 90
76 /* Point stdout to the file */ 91 /* Point stdout to the file */
77 92
78 file = freopen(pathname, "w", stdout); 93 file = acpi_os_open_file(pathname, ACPI_FILE_WRITING);
79 if (!file) { 94 if (!file) {
80 perror("Could not open output file"); 95 acpi_log_error("Could not open output file: %s\n", pathname);
81 return (-1); 96 return (-1);
82 } 97 }
83 98
@@ -106,7 +121,7 @@ int ap_write_to_binary_file(struct acpi_table_header *table, u32 instance)
106{ 121{
107 char filename[ACPI_NAME_SIZE + 16]; 122 char filename[ACPI_NAME_SIZE + 16];
108 char instance_str[16]; 123 char instance_str[16];
109 FILE *file; 124 ACPI_FILE file;
110 size_t actual; 125 size_t actual;
111 u32 table_length; 126 u32 table_length;
112 127
@@ -130,35 +145,37 @@ int ap_write_to_binary_file(struct acpi_table_header *table, u32 instance)
130 /* Handle multiple SSDts - create different filenames for each */ 145 /* Handle multiple SSDts - create different filenames for each */
131 146
132 if (instance > 0) { 147 if (instance > 0) {
133 sprintf(instance_str, "%u", instance); 148 acpi_ut_snprintf(instance_str, sizeof(instance_str), "%u",
134 strcat(filename, instance_str); 149 instance);
150 ACPI_STRCAT(filename, instance_str);
135 } 151 }
136 152
137 strcat(filename, ACPI_TABLE_FILE_SUFFIX); 153 ACPI_STRCAT(filename, ACPI_TABLE_FILE_SUFFIX);
138 154
139 if (gbl_verbose_mode) { 155 if (gbl_verbose_mode) {
140 fprintf(stderr, 156 acpi_log_error
141 "Writing [%4.4s] to binary file: %s 0x%X (%u) bytes\n", 157 ("Writing [%4.4s] to binary file: %s 0x%X (%u) bytes\n",
142 table->signature, filename, table->length, 158 table->signature, filename, table->length, table->length);
143 table->length);
144 } 159 }
145 160
146 /* Open the file and dump the entire table in binary mode */ 161 /* Open the file and dump the entire table in binary mode */
147 162
148 file = fopen(filename, "wb"); 163 file = acpi_os_open_file(filename,
164 ACPI_FILE_WRITING | ACPI_FILE_BINARY);
149 if (!file) { 165 if (!file) {
150 perror("Could not open output file"); 166 acpi_log_error("Could not open output file: %s\n", filename);
151 return (-1); 167 return (-1);
152 } 168 }
153 169
154 actual = fwrite(table, 1, table_length, file); 170 actual = acpi_os_write_file(file, table, 1, table_length);
155 if (actual != table_length) { 171 if (actual != table_length) {
156 perror("Error writing binary output file"); 172 acpi_log_error("Error writing binary output file: %s\n",
157 fclose(file); 173 filename);
174 acpi_os_close_file(file);
158 return (-1); 175 return (-1);
159 } 176 }
160 177
161 fclose(file); 178 acpi_os_close_file(file);
162 return (0); 179 return (0);
163} 180}
164 181
@@ -179,15 +196,16 @@ struct acpi_table_header *ap_get_table_from_file(char *pathname,
179 u32 *out_file_size) 196 u32 *out_file_size)
180{ 197{
181 struct acpi_table_header *buffer = NULL; 198 struct acpi_table_header *buffer = NULL;
182 FILE *file; 199 ACPI_FILE file;
183 u32 file_size; 200 u32 file_size;
184 size_t actual; 201 size_t actual;
185 202
186 /* Must use binary mode */ 203 /* Must use binary mode */
187 204
188 file = fopen(pathname, "rb"); 205 file =
206 acpi_os_open_file(pathname, ACPI_FILE_READING | ACPI_FILE_BINARY);
189 if (!file) { 207 if (!file) {
190 perror("Could not open input file"); 208 acpi_log_error("Could not open input file: %s\n", pathname);
191 return (NULL); 209 return (NULL);
192 } 210 }
193 211
@@ -195,27 +213,25 @@ struct acpi_table_header *ap_get_table_from_file(char *pathname,
195 213
196 file_size = cm_get_file_size(file); 214 file_size = cm_get_file_size(file);
197 if (file_size == ACPI_UINT32_MAX) { 215 if (file_size == ACPI_UINT32_MAX) {
198 fprintf(stderr, 216 acpi_log_error("Could not get input file size: %s\n", pathname);
199 "Could not get input file size: %s\n", pathname);
200 goto cleanup; 217 goto cleanup;
201 } 218 }
202 219
203 /* Allocate a buffer for the entire file */ 220 /* Allocate a buffer for the entire file */
204 221
205 buffer = calloc(1, file_size); 222 buffer = ACPI_ALLOCATE_ZEROED(file_size);
206 if (!buffer) { 223 if (!buffer) {
207 fprintf(stderr, 224 acpi_log_error("Could not allocate file buffer of size: %u\n",
208 "Could not allocate file buffer of size: %u\n", 225 file_size);
209 file_size);
210 goto cleanup; 226 goto cleanup;
211 } 227 }
212 228
213 /* Read the entire file */ 229 /* Read the entire file */
214 230
215 actual = fread(buffer, 1, file_size, file); 231 actual = acpi_os_read_file(file, buffer, 1, file_size);
216 if (actual != file_size) { 232 if (actual != file_size) {
217 fprintf(stderr, "Could not read input file: %s\n", pathname); 233 acpi_log_error("Could not read input file: %s\n", pathname);
218 free(buffer); 234 ACPI_FREE(buffer);
219 buffer = NULL; 235 buffer = NULL;
220 goto cleanup; 236 goto cleanup;
221 } 237 }
@@ -223,6 +239,6 @@ struct acpi_table_header *ap_get_table_from_file(char *pathname,
223 *out_file_size = file_size; 239 *out_file_size = file_size;
224 240
225cleanup: 241cleanup:
226 fclose(file); 242 acpi_os_close_file(file);
227 return (buffer); 243 return (buffer);
228} 244}
diff --git a/tools/power/acpi/tools/acpidump/apmain.c b/tools/power/acpi/tools/acpidump/apmain.c
index 51e8d638db18..853b4da22c3e 100644
--- a/tools/power/acpi/tools/acpidump/apmain.c
+++ b/tools/power/acpi/tools/acpidump/apmain.c
@@ -72,7 +72,7 @@ static void ap_display_usage(void);
72 72
73static int ap_do_options(int argc, char **argv); 73static int ap_do_options(int argc, char **argv);
74 74
75static void ap_insert_action(char *argument, u32 to_be_done); 75static int ap_insert_action(char *argument, u32 to_be_done);
76 76
77/* Table for deferred actions from command line options */ 77/* Table for deferred actions from command line options */
78 78
@@ -104,7 +104,7 @@ static void ap_display_usage(void)
104 ACPI_OPTION("-v", "Display version information"); 104 ACPI_OPTION("-v", "Display version information");
105 ACPI_OPTION("-z", "Verbose mode"); 105 ACPI_OPTION("-z", "Verbose mode");
106 106
107 printf("\nTable Options:\n"); 107 ACPI_USAGE_TEXT("\nTable Options:\n");
108 108
109 ACPI_OPTION("-a <Address>", "Get table via a physical address"); 109 ACPI_OPTION("-a <Address>", "Get table via a physical address");
110 ACPI_OPTION("-f <BinaryFile>", "Get table via a binary file"); 110 ACPI_OPTION("-f <BinaryFile>", "Get table via a binary file");
@@ -112,9 +112,9 @@ static void ap_display_usage(void)
112 ACPI_OPTION("-x", "Do not use but dump XSDT"); 112 ACPI_OPTION("-x", "Do not use but dump XSDT");
113 ACPI_OPTION("-x -x", "Do not use or dump XSDT"); 113 ACPI_OPTION("-x -x", "Do not use or dump XSDT");
114 114
115 printf("\n" 115 ACPI_USAGE_TEXT("\n"
116 "Invocation without parameters dumps all available tables\n" 116 "Invocation without parameters dumps all available tables\n"
117 "Multiple mixed instances of -a, -f, and -n are supported\n\n"); 117 "Multiple mixed instances of -a, -f, and -n are supported\n\n");
118} 118}
119 119
120/****************************************************************************** 120/******************************************************************************
@@ -124,13 +124,13 @@ static void ap_display_usage(void)
124 * PARAMETERS: argument - Pointer to the argument for this action 124 * PARAMETERS: argument - Pointer to the argument for this action
125 * to_be_done - What to do to process this action 125 * to_be_done - What to do to process this action
126 * 126 *
127 * RETURN: None. Exits program if action table becomes full. 127 * RETURN: Status
128 * 128 *
129 * DESCRIPTION: Add an action item to the action table 129 * DESCRIPTION: Add an action item to the action table
130 * 130 *
131 ******************************************************************************/ 131 ******************************************************************************/
132 132
133static void ap_insert_action(char *argument, u32 to_be_done) 133static int ap_insert_action(char *argument, u32 to_be_done)
134{ 134{
135 135
136 /* Insert action and check for table overflow */ 136 /* Insert action and check for table overflow */
@@ -140,10 +140,12 @@ static void ap_insert_action(char *argument, u32 to_be_done)
140 140
141 current_action++; 141 current_action++;
142 if (current_action > AP_MAX_ACTIONS) { 142 if (current_action > AP_MAX_ACTIONS) {
143 fprintf(stderr, "Too many table options (max %u)\n", 143 acpi_log_error("Too many table options (max %u)\n",
144 AP_MAX_ACTIONS); 144 AP_MAX_ACTIONS);
145 exit(-1); 145 return (-1);
146 } 146 }
147
148 return (0);
147} 149}
148 150
149/****************************************************************************** 151/******************************************************************************
@@ -166,7 +168,8 @@ static int ap_do_options(int argc, char **argv)
166 168
167 /* Command line options */ 169 /* Command line options */
168 170
169 while ((j = acpi_getopt(argc, argv, AP_SUPPORTED_OPTIONS)) != EOF) 171 while ((j =
172 acpi_getopt(argc, argv, AP_SUPPORTED_OPTIONS)) != ACPI_OPT_END)
170 switch (j) { 173 switch (j) {
171 /* 174 /*
172 * Global options 175 * Global options
@@ -185,12 +188,12 @@ static int ap_do_options(int argc, char **argv)
185 case '?': 188 case '?':
186 189
187 ap_display_usage(); 190 ap_display_usage();
188 exit(0); 191 return (1);
189 192
190 case 'o': /* Redirect output to a single file */ 193 case 'o': /* Redirect output to a single file */
191 194
192 if (ap_open_output_file(acpi_gbl_optarg)) { 195 if (ap_open_output_file(acpi_gbl_optarg)) {
193 exit(-1); 196 return (-1);
194 } 197 }
195 continue; 198 continue;
196 199
@@ -200,10 +203,10 @@ static int ap_do_options(int argc, char **argv)
200 acpi_ut_strtoul64(acpi_gbl_optarg, 0, 203 acpi_ut_strtoul64(acpi_gbl_optarg, 0,
201 &gbl_rsdp_base); 204 &gbl_rsdp_base);
202 if (ACPI_FAILURE(status)) { 205 if (ACPI_FAILURE(status)) {
203 fprintf(stderr, 206 acpi_log_error
204 "%s: Could not convert to a physical address\n", 207 ("%s: Could not convert to a physical address\n",
205 acpi_gbl_optarg); 208 acpi_gbl_optarg);
206 exit(-1); 209 return (-1);
207 } 210 }
208 continue; 211 continue;
209 212
@@ -223,13 +226,13 @@ static int ap_do_options(int argc, char **argv)
223 226
224 case 'v': /* Revision/version */ 227 case 'v': /* Revision/version */
225 228
226 printf(ACPI_COMMON_SIGNON(AP_UTILITY_NAME)); 229 acpi_os_printf(ACPI_COMMON_SIGNON(AP_UTILITY_NAME));
227 exit(0); 230 return (1);
228 231
229 case 'z': /* Verbose mode */ 232 case 'z': /* Verbose mode */
230 233
231 gbl_verbose_mode = TRUE; 234 gbl_verbose_mode = TRUE;
232 fprintf(stderr, ACPI_COMMON_SIGNON(AP_UTILITY_NAME)); 235 acpi_log_error(ACPI_COMMON_SIGNON(AP_UTILITY_NAME));
233 continue; 236 continue;
234 237
235 /* 238 /*
@@ -237,32 +240,40 @@ static int ap_do_options(int argc, char **argv)
237 */ 240 */
238 case 'a': /* Get table by physical address */ 241 case 'a': /* Get table by physical address */
239 242
240 ap_insert_action(acpi_gbl_optarg, 243 if (ap_insert_action
241 AP_DUMP_TABLE_BY_ADDRESS); 244 (acpi_gbl_optarg, AP_DUMP_TABLE_BY_ADDRESS)) {
245 return (-1);
246 }
242 break; 247 break;
243 248
244 case 'f': /* Get table from a file */ 249 case 'f': /* Get table from a file */
245 250
246 ap_insert_action(acpi_gbl_optarg, 251 if (ap_insert_action
247 AP_DUMP_TABLE_BY_FILE); 252 (acpi_gbl_optarg, AP_DUMP_TABLE_BY_FILE)) {
253 return (-1);
254 }
248 break; 255 break;
249 256
250 case 'n': /* Get table by input name (signature) */ 257 case 'n': /* Get table by input name (signature) */
251 258
252 ap_insert_action(acpi_gbl_optarg, 259 if (ap_insert_action
253 AP_DUMP_TABLE_BY_NAME); 260 (acpi_gbl_optarg, AP_DUMP_TABLE_BY_NAME)) {
261 return (-1);
262 }
254 break; 263 break;
255 264
256 default: 265 default:
257 266
258 ap_display_usage(); 267 ap_display_usage();
259 exit(-1); 268 return (-1);
260 } 269 }
261 270
262 /* If there are no actions, this means "get/dump all tables" */ 271 /* If there are no actions, this means "get/dump all tables" */
263 272
264 if (current_action == 0) { 273 if (current_action == 0) {
265 ap_insert_action(NULL, AP_DUMP_ALL_TABLES); 274 if (ap_insert_action(NULL, AP_DUMP_ALL_TABLES)) {
275 return (-1);
276 }
266 } 277 }
267 278
268 return (0); 279 return (0);
@@ -280,7 +291,11 @@ static int ap_do_options(int argc, char **argv)
280 * 291 *
281 ******************************************************************************/ 292 ******************************************************************************/
282 293
294#ifndef _GNU_EFI
283int ACPI_SYSTEM_XFACE main(int argc, char *argv[]) 295int ACPI_SYSTEM_XFACE main(int argc, char *argv[])
296#else
297int ACPI_SYSTEM_XFACE acpi_main(int argc, char *argv[])
298#endif
284{ 299{
285 int status = 0; 300 int status = 0;
286 struct ap_dump_action *action; 301 struct ap_dump_action *action;
@@ -288,11 +303,17 @@ int ACPI_SYSTEM_XFACE main(int argc, char *argv[])
288 u32 i; 303 u32 i;
289 304
290 ACPI_DEBUG_INITIALIZE(); /* For debug version only */ 305 ACPI_DEBUG_INITIALIZE(); /* For debug version only */
306 acpi_os_initialize();
307 gbl_output_file = ACPI_FILE_OUT;
291 308
292 /* Process command line options */ 309 /* Process command line options */
293 310
294 if (ap_do_options(argc, argv)) { 311 status = ap_do_options(argc, argv);
295 return (-1); 312 if (status > 0) {
313 return (0);
314 }
315 if (status < 0) {
316 return (status);
296 } 317 }
297 318
298 /* Get/dump ACPI table(s) as requested */ 319 /* Get/dump ACPI table(s) as requested */
@@ -322,9 +343,8 @@ int ACPI_SYSTEM_XFACE main(int argc, char *argv[])
322 343
323 default: 344 default:
324 345
325 fprintf(stderr, 346 acpi_log_error("Internal error, invalid action: 0x%X\n",
326 "Internal error, invalid action: 0x%X\n", 347 action->to_be_done);
327 action->to_be_done);
328 return (-1); 348 return (-1);
329 } 349 }
330 350
@@ -333,18 +353,18 @@ int ACPI_SYSTEM_XFACE main(int argc, char *argv[])
333 } 353 }
334 } 354 }
335 355
336 if (gbl_output_file) { 356 if (gbl_output_filename) {
337 if (gbl_verbose_mode) { 357 if (gbl_verbose_mode) {
338 358
339 /* Summary for the output file */ 359 /* Summary for the output file */
340 360
341 file_size = cm_get_file_size(gbl_output_file); 361 file_size = cm_get_file_size(gbl_output_file);
342 fprintf(stderr, 362 acpi_log_error
343 "Output file %s contains 0x%X (%u) bytes\n\n", 363 ("Output file %s contains 0x%X (%u) bytes\n\n",
344 gbl_output_filename, file_size, file_size); 364 gbl_output_filename, file_size, file_size);
345 } 365 }
346 366
347 fclose(gbl_output_file); 367 acpi_os_close_file(gbl_output_file);
348 } 368 }
349 369
350 return (status); 370 return (status);
diff --git a/tools/power/cpupower/bench/parse.c b/tools/power/cpupower/bench/parse.c
index 543bba14ae2c..f503fb53824e 100644
--- a/tools/power/cpupower/bench/parse.c
+++ b/tools/power/cpupower/bench/parse.c
@@ -158,14 +158,15 @@ struct config *prepare_default_config()
158int prepare_config(const char *path, struct config *config) 158int prepare_config(const char *path, struct config *config)
159{ 159{
160 size_t len = 0; 160 size_t len = 0;
161 char *opt, *val, *line = NULL; 161 char opt[16], val[32], *line = NULL;
162 FILE *configfile = fopen(path, "r"); 162 FILE *configfile;
163 163
164 if (config == NULL) { 164 if (config == NULL) {
165 fprintf(stderr, "error: config is NULL\n"); 165 fprintf(stderr, "error: config is NULL\n");
166 return 1; 166 return 1;
167 } 167 }
168 168
169 configfile = fopen(path, "r");
169 if (configfile == NULL) { 170 if (configfile == NULL) {
170 perror("fopen"); 171 perror("fopen");
171 fprintf(stderr, "error: unable to read configfile\n"); 172 fprintf(stderr, "error: unable to read configfile\n");
@@ -174,52 +175,54 @@ int prepare_config(const char *path, struct config *config)
174 } 175 }
175 176
176 while (getline(&line, &len, configfile) != -1) { 177 while (getline(&line, &len, configfile) != -1) {
177 if (line[0] == '#' || line[0] == ' ') 178 if (line[0] == '#' || line[0] == ' ' || line[0] == '\n')
178 continue; 179 continue;
179 180
180 sscanf(line, "%as = %as", &opt, &val); 181 if (sscanf(line, "%14s = %30s", opt, val) < 2)
182 continue;
181 183
182 dprintf("parsing: %s -> %s\n", opt, val); 184 dprintf("parsing: %s -> %s\n", opt, val);
183 185
184 if (strncmp("sleep", opt, strlen(opt)) == 0) 186 if (strcmp("sleep", opt) == 0)
185 sscanf(val, "%li", &config->sleep); 187 sscanf(val, "%li", &config->sleep);
186 188
187 else if (strncmp("load", opt, strlen(opt)) == 0) 189 else if (strcmp("load", opt) == 0)
188 sscanf(val, "%li", &config->load); 190 sscanf(val, "%li", &config->load);
189 191
190 else if (strncmp("load_step", opt, strlen(opt)) == 0) 192 else if (strcmp("load_step", opt) == 0)
191 sscanf(val, "%li", &config->load_step); 193 sscanf(val, "%li", &config->load_step);
192 194
193 else if (strncmp("sleep_step", opt, strlen(opt)) == 0) 195 else if (strcmp("sleep_step", opt) == 0)
194 sscanf(val, "%li", &config->sleep_step); 196 sscanf(val, "%li", &config->sleep_step);
195 197
196 else if (strncmp("cycles", opt, strlen(opt)) == 0) 198 else if (strcmp("cycles", opt) == 0)
197 sscanf(val, "%u", &config->cycles); 199 sscanf(val, "%u", &config->cycles);
198 200
199 else if (strncmp("rounds", opt, strlen(opt)) == 0) 201 else if (strcmp("rounds", opt) == 0)
200 sscanf(val, "%u", &config->rounds); 202 sscanf(val, "%u", &config->rounds);
201 203
202 else if (strncmp("verbose", opt, strlen(opt)) == 0) 204 else if (strcmp("verbose", opt) == 0)
203 sscanf(val, "%u", &config->verbose); 205 sscanf(val, "%u", &config->verbose);
204 206
205 else if (strncmp("output", opt, strlen(opt)) == 0) 207 else if (strcmp("output", opt) == 0)
206 config->output = prepare_output(val); 208 config->output = prepare_output(val);
207 209
208 else if (strncmp("cpu", opt, strlen(opt)) == 0) 210 else if (strcmp("cpu", opt) == 0)
209 sscanf(val, "%u", &config->cpu); 211 sscanf(val, "%u", &config->cpu);
210 212
211 else if (strncmp("governor", opt, 14) == 0) 213 else if (strcmp("governor", opt) == 0) {
212 strncpy(config->governor, val, 14); 214 strncpy(config->governor, val,
215 sizeof(config->governor));
216 config->governor[sizeof(config->governor) - 1] = '\0';
217 }
213 218
214 else if (strncmp("priority", opt, strlen(opt)) == 0) { 219 else if (strcmp("priority", opt) == 0) {
215 if (string_to_prio(val) != SCHED_ERR) 220 if (string_to_prio(val) != SCHED_ERR)
216 config->prio = string_to_prio(val); 221 config->prio = string_to_prio(val);
217 } 222 }
218 } 223 }
219 224
220 free(line); 225 free(line);
221 free(opt);
222 free(val);
223 226
224 return 0; 227 return 0;
225} 228}
diff --git a/tools/power/cpupower/utils/cpufreq-set.c b/tools/power/cpupower/utils/cpufreq-set.c
index a416de80c55e..f656e585ed45 100644
--- a/tools/power/cpupower/utils/cpufreq-set.c
+++ b/tools/power/cpupower/utils/cpufreq-set.c
@@ -320,12 +320,11 @@ int cmd_freq_set(int argc, char **argv)
320 320
321 printf(_("Setting cpu: %d\n"), cpu); 321 printf(_("Setting cpu: %d\n"), cpu);
322 ret = do_one_cpu(cpu, &new_pol, freq, policychange); 322 ret = do_one_cpu(cpu, &new_pol, freq, policychange);
323 if (ret) 323 if (ret) {
324 break; 324 print_error();
325 return ret;
326 }
325 } 327 }
326 328
327 if (ret) 329 return 0;
328 print_error();
329
330 return ret;
331} 330}
diff --git a/tools/power/cpupower/utils/helpers/sysfs.c b/tools/power/cpupower/utils/helpers/sysfs.c
index 851c7a16ca49..09afe5d87f2b 100644
--- a/tools/power/cpupower/utils/helpers/sysfs.c
+++ b/tools/power/cpupower/utils/helpers/sysfs.c
@@ -81,7 +81,7 @@ int sysfs_is_cpu_online(unsigned int cpu)
81 close(fd); 81 close(fd);
82 82
83 value = strtoull(linebuf, &endp, 0); 83 value = strtoull(linebuf, &endp, 0);
84 if (value > 1 || value < 0) 84 if (value > 1)
85 return -EINVAL; 85 return -EINVAL;
86 86
87 return value; 87 return value;
diff --git a/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c b/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c
index 5650ab5a2c20..90a8c4f071e7 100644
--- a/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c
+++ b/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c
@@ -237,7 +237,7 @@ static int init_maxfreq_mode(void)
237 unsigned long long hwcr; 237 unsigned long long hwcr;
238 unsigned long min; 238 unsigned long min;
239 239
240 if (!cpupower_cpu_info.caps & CPUPOWER_CAP_INV_TSC) 240 if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_INV_TSC))
241 goto use_sysfs; 241 goto use_sysfs;
242 242
243 if (cpupower_cpu_info.vendor == X86_VENDOR_AMD) { 243 if (cpupower_cpu_info.vendor == X86_VENDOR_AMD) {
diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl
index 40631569a0fd..55ab700f6ba5 100755
--- a/tools/testing/ktest/ktest.pl
+++ b/tools/testing/ktest/ktest.pl
@@ -72,7 +72,7 @@ my %default = (
72 "IGNORE_UNUSED" => 0, 72 "IGNORE_UNUSED" => 0,
73); 73);
74 74
75my $ktest_config; 75my $ktest_config = "ktest.conf";
76my $version; 76my $version;
77my $have_version = 0; 77my $have_version = 0;
78my $machine; 78my $machine;
@@ -149,7 +149,6 @@ my $bisect_ret_abort;
149my $bisect_ret_default; 149my $bisect_ret_default;
150my $in_patchcheck = 0; 150my $in_patchcheck = 0;
151my $run_test; 151my $run_test;
152my $redirect;
153my $buildlog; 152my $buildlog;
154my $testlog; 153my $testlog;
155my $dmesg; 154my $dmesg;
@@ -522,7 +521,7 @@ sub read_ync {
522 return read_prompt 1, $prompt; 521 return read_prompt 1, $prompt;
523} 522}
524 523
525sub get_ktest_config { 524sub get_mandatory_config {
526 my ($config) = @_; 525 my ($config) = @_;
527 my $ans; 526 my $ans;
528 527
@@ -553,29 +552,29 @@ sub get_ktest_config {
553 } 552 }
554} 553}
555 554
556sub get_ktest_configs { 555sub get_mandatory_configs {
557 get_ktest_config("MACHINE"); 556 get_mandatory_config("MACHINE");
558 get_ktest_config("BUILD_DIR"); 557 get_mandatory_config("BUILD_DIR");
559 get_ktest_config("OUTPUT_DIR"); 558 get_mandatory_config("OUTPUT_DIR");
560 559
561 if ($newconfig) { 560 if ($newconfig) {
562 get_ktest_config("BUILD_OPTIONS"); 561 get_mandatory_config("BUILD_OPTIONS");
563 } 562 }
564 563
565 # options required for other than just building a kernel 564 # options required for other than just building a kernel
566 if (!$buildonly) { 565 if (!$buildonly) {
567 get_ktest_config("POWER_CYCLE"); 566 get_mandatory_config("POWER_CYCLE");
568 get_ktest_config("CONSOLE"); 567 get_mandatory_config("CONSOLE");
569 } 568 }
570 569
571 # options required for install and more 570 # options required for install and more
572 if ($buildonly != 1) { 571 if ($buildonly != 1) {
573 get_ktest_config("SSH_USER"); 572 get_mandatory_config("SSH_USER");
574 get_ktest_config("BUILD_TARGET"); 573 get_mandatory_config("BUILD_TARGET");
575 get_ktest_config("TARGET_IMAGE"); 574 get_mandatory_config("TARGET_IMAGE");
576 } 575 }
577 576
578 get_ktest_config("LOCALVERSION"); 577 get_mandatory_config("LOCALVERSION");
579 578
580 return if ($buildonly); 579 return if ($buildonly);
581 580
@@ -583,7 +582,7 @@ sub get_ktest_configs {
583 582
584 if (!defined($rtype)) { 583 if (!defined($rtype)) {
585 if (!defined($opt{"GRUB_MENU"})) { 584 if (!defined($opt{"GRUB_MENU"})) {
586 get_ktest_config("REBOOT_TYPE"); 585 get_mandatory_config("REBOOT_TYPE");
587 $rtype = $entered_configs{"REBOOT_TYPE"}; 586 $rtype = $entered_configs{"REBOOT_TYPE"};
588 } else { 587 } else {
589 $rtype = "grub"; 588 $rtype = "grub";
@@ -591,16 +590,16 @@ sub get_ktest_configs {
591 } 590 }
592 591
593 if ($rtype eq "grub") { 592 if ($rtype eq "grub") {
594 get_ktest_config("GRUB_MENU"); 593 get_mandatory_config("GRUB_MENU");
595 } 594 }
596 595
597 if ($rtype eq "grub2") { 596 if ($rtype eq "grub2") {
598 get_ktest_config("GRUB_MENU"); 597 get_mandatory_config("GRUB_MENU");
599 get_ktest_config("GRUB_FILE"); 598 get_mandatory_config("GRUB_FILE");
600 } 599 }
601 600
602 if ($rtype eq "syslinux") { 601 if ($rtype eq "syslinux") {
603 get_ktest_config("SYSLINUX_LABEL"); 602 get_mandatory_config("SYSLINUX_LABEL");
604 } 603 }
605} 604}
606 605
@@ -1090,7 +1089,7 @@ sub read_config {
1090 $test_case = __read_config $config, \$test_num; 1089 $test_case = __read_config $config, \$test_num;
1091 1090
1092 # make sure we have all mandatory configs 1091 # make sure we have all mandatory configs
1093 get_ktest_configs; 1092 get_mandatory_configs;
1094 1093
1095 # was a test specified? 1094 # was a test specified?
1096 if (!$test_case) { 1095 if (!$test_case) {
@@ -1529,7 +1528,7 @@ sub fail {
1529} 1528}
1530 1529
1531sub run_command { 1530sub run_command {
1532 my ($command) = @_; 1531 my ($command, $redirect) = @_;
1533 my $dolog = 0; 1532 my $dolog = 0;
1534 my $dord = 0; 1533 my $dord = 0;
1535 my $pid; 1534 my $pid;
@@ -2265,9 +2264,7 @@ sub build {
2265 # Run old config regardless, to enforce min configurations 2264 # Run old config regardless, to enforce min configurations
2266 make_oldconfig; 2265 make_oldconfig;
2267 2266
2268 $redirect = "$buildlog"; 2267 my $build_ret = run_command "$make $build_options", $buildlog;
2269 my $build_ret = run_command "$make $build_options";
2270 undef $redirect;
2271 2268
2272 if (defined($post_build)) { 2269 if (defined($post_build)) {
2273 # Because a post build may change the kernel version 2270 # Because a post build may change the kernel version
@@ -2360,9 +2357,7 @@ sub child_run_test {
2360 $poweroff_on_error = 0; 2357 $poweroff_on_error = 0;
2361 $die_on_failure = 1; 2358 $die_on_failure = 1;
2362 2359
2363 $redirect = "$testlog"; 2360 run_command $run_test, $testlog or $failed = 1;
2364 run_command $run_test or $failed = 1;
2365 undef $redirect;
2366 2361
2367 exit $failed; 2362 exit $failed;
2368} 2363}
@@ -2789,12 +2784,17 @@ my %dependency;
2789sub assign_configs { 2784sub assign_configs {
2790 my ($hash, $config) = @_; 2785 my ($hash, $config) = @_;
2791 2786
2787 doprint "Reading configs from $config\n";
2788
2792 open (IN, $config) 2789 open (IN, $config)
2793 or dodie "Failed to read $config"; 2790 or dodie "Failed to read $config";
2794 2791
2795 while (<IN>) { 2792 while (<IN>) {
2793 chomp;
2796 if (/^((CONFIG\S*)=.*)/) { 2794 if (/^((CONFIG\S*)=.*)/) {
2797 ${$hash}{$2} = $1; 2795 ${$hash}{$2} = $1;
2796 } elsif (/^(# (CONFIG\S*) is not set)/) {
2797 ${$hash}{$2} = $1;
2798 } 2798 }
2799 } 2799 }
2800 2800
@@ -2807,27 +2807,6 @@ sub process_config_ignore {
2807 assign_configs \%config_ignore, $config; 2807 assign_configs \%config_ignore, $config;
2808} 2808}
2809 2809
2810sub read_current_config {
2811 my ($config_ref) = @_;
2812
2813 %{$config_ref} = ();
2814 undef %{$config_ref};
2815
2816 my @key = keys %{$config_ref};
2817 if ($#key >= 0) {
2818 print "did not delete!\n";
2819 exit;
2820 }
2821 open (IN, "$output_config");
2822
2823 while (<IN>) {
2824 if (/^(CONFIG\S+)=(.*)/) {
2825 ${$config_ref}{$1} = $2;
2826 }
2827 }
2828 close(IN);
2829}
2830
2831sub get_dependencies { 2810sub get_dependencies {
2832 my ($config) = @_; 2811 my ($config) = @_;
2833 2812
@@ -2846,53 +2825,97 @@ sub get_dependencies {
2846 return @deps; 2825 return @deps;
2847} 2826}
2848 2827
2828sub save_config {
2829 my ($pc, $file) = @_;
2830
2831 my %configs = %{$pc};
2832
2833 doprint "Saving configs into $file\n";
2834
2835 open(OUT, ">$file") or dodie "Can not write to $file";
2836
2837 foreach my $config (keys %configs) {
2838 print OUT "$configs{$config}\n";
2839 }
2840 close(OUT);
2841}
2842
2849sub create_config { 2843sub create_config {
2850 my @configs = @_; 2844 my ($name, $pc) = @_;
2851 2845
2852 open(OUT, ">$output_config") or dodie "Can not write to $output_config"; 2846 doprint "Creating old config from $name configs\n";
2853 2847
2854 foreach my $config (@configs) { 2848 save_config $pc, $output_config;
2855 print OUT "$config_set{$config}\n"; 2849
2856 my @deps = get_dependencies $config; 2850 make_oldconfig;
2857 foreach my $dep (@deps) { 2851}
2858 print OUT "$config_set{$dep}\n"; 2852
2853# compare two config hashes, and return configs with different vals.
2854# It returns B's config values, but you can use A to see what A was.
2855sub diff_config_vals {
2856 my ($pa, $pb) = @_;
2857
2858 # crappy Perl way to pass in hashes.
2859 my %a = %{$pa};
2860 my %b = %{$pb};
2861
2862 my %ret;
2863
2864 foreach my $item (keys %a) {
2865 if (defined($b{$item}) && $b{$item} ne $a{$item}) {
2866 $ret{$item} = $b{$item};
2859 } 2867 }
2860 } 2868 }
2861 2869
2862 # turn off configs to keep off 2870 return %ret;
2863 foreach my $config (keys %config_off) { 2871}
2864 print OUT "# $config is not set\n";
2865 }
2866 2872
2867 # turn off configs that should be off for now 2873# compare two config hashes and return the configs in B but not A
2868 foreach my $config (@config_off_tmp) { 2874sub diff_configs {
2869 print OUT "# $config is not set\n"; 2875 my ($pa, $pb) = @_;
2870 } 2876
2877 my %ret;
2878
2879 # crappy Perl way to pass in hashes.
2880 my %a = %{$pa};
2881 my %b = %{$pb};
2871 2882
2872 foreach my $config (keys %config_ignore) { 2883 foreach my $item (keys %b) {
2873 print OUT "$config_ignore{$config}\n"; 2884 if (!defined($a{$item})) {
2885 $ret{$item} = $b{$item};
2886 }
2874 } 2887 }
2875 close(OUT);
2876 2888
2877 make_oldconfig; 2889 return %ret;
2878} 2890}
2879 2891
2892# return if two configs are equal or not
2893# 0 is equal +1 b has something a does not
2894# +1 if a and b have a different item.
2895# -1 if a has something b does not
2880sub compare_configs { 2896sub compare_configs {
2881 my (%a, %b) = @_; 2897 my ($pa, $pb) = @_;
2882 2898
2883 foreach my $item (keys %a) { 2899 my %ret;
2884 if (!defined($b{$item})) { 2900
2885 print "diff $item\n"; 2901 # crappy Perl way to pass in hashes.
2902 my %a = %{$pa};
2903 my %b = %{$pb};
2904
2905 foreach my $item (keys %b) {
2906 if (!defined($a{$item})) {
2907 return 1;
2908 }
2909 if ($a{$item} ne $b{$item}) {
2886 return 1; 2910 return 1;
2887 } 2911 }
2888 delete $b{$item};
2889 } 2912 }
2890 2913
2891 my @keys = keys %b; 2914 foreach my $item (keys %a) {
2892 if ($#keys) { 2915 if (!defined($b{$item})) {
2893 print "diff2 $keys[0]\n"; 2916 return -1;
2917 }
2894 } 2918 }
2895 return -1 if ($#keys >= 0);
2896 2919
2897 return 0; 2920 return 0;
2898} 2921}
@@ -2900,24 +2923,13 @@ sub compare_configs {
2900sub run_config_bisect_test { 2923sub run_config_bisect_test {
2901 my ($type) = @_; 2924 my ($type) = @_;
2902 2925
2903 return run_bisect_test $type, "oldconfig"; 2926 my $ret = run_bisect_test $type, "oldconfig";
2904}
2905 2927
2906sub process_passed { 2928 if ($bisect_manual) {
2907 my (%configs) = @_; 2929 $ret = answer_bisect;
2908
2909 doprint "These configs had no failure: (Enabling them for further compiles)\n";
2910 # Passed! All these configs are part of a good compile.
2911 # Add them to the min options.
2912 foreach my $config (keys %configs) {
2913 if (defined($config_list{$config})) {
2914 doprint " removing $config\n";
2915 $config_ignore{$config} = $config_list{$config};
2916 delete $config_list{$config};
2917 }
2918 } 2930 }
2919 doprint "config copied to $outputdir/config_good\n"; 2931
2920 run_command "cp -f $output_config $outputdir/config_good"; 2932 return $ret;
2921} 2933}
2922 2934
2923sub process_failed { 2935sub process_failed {
@@ -2928,253 +2940,225 @@ sub process_failed {
2928 doprint "***************************************\n\n"; 2940 doprint "***************************************\n\n";
2929} 2941}
2930 2942
2931sub run_config_bisect { 2943# used for config bisecting
2944my $good_config;
2945my $bad_config;
2932 2946
2933 my @start_list = keys %config_list; 2947sub process_new_config {
2948 my ($tc, $nc, $gc, $bc) = @_;
2934 2949
2935 if ($#start_list < 0) { 2950 my %tmp_config = %{$tc};
2936 doprint "No more configs to test!!!\n"; 2951 my %good_configs = %{$gc};
2937 return -1; 2952 my %bad_configs = %{$bc};
2953
2954 my %new_configs;
2955
2956 my $runtest = 1;
2957 my $ret;
2958
2959 create_config "tmp_configs", \%tmp_config;
2960 assign_configs \%new_configs, $output_config;
2961
2962 $ret = compare_configs \%new_configs, \%bad_configs;
2963 if (!$ret) {
2964 doprint "New config equals bad config, try next test\n";
2965 $runtest = 0;
2966 }
2967
2968 if ($runtest) {
2969 $ret = compare_configs \%new_configs, \%good_configs;
2970 if (!$ret) {
2971 doprint "New config equals good config, try next test\n";
2972 $runtest = 0;
2973 }
2938 } 2974 }
2939 2975
2940 doprint "***** RUN TEST ***\n"; 2976 %{$nc} = %new_configs;
2977
2978 return $runtest;
2979}
2980
2981sub run_config_bisect {
2982 my ($pgood, $pbad) = @_;
2983
2941 my $type = $config_bisect_type; 2984 my $type = $config_bisect_type;
2985
2986 my %good_configs = %{$pgood};
2987 my %bad_configs = %{$pbad};
2988
2989 my %diff_configs = diff_config_vals \%good_configs, \%bad_configs;
2990 my %b_configs = diff_configs \%good_configs, \%bad_configs;
2991 my %g_configs = diff_configs \%bad_configs, \%good_configs;
2992
2993 my @diff_arr = keys %diff_configs;
2994 my $len_diff = $#diff_arr + 1;
2995
2996 my @b_arr = keys %b_configs;
2997 my $len_b = $#b_arr + 1;
2998
2999 my @g_arr = keys %g_configs;
3000 my $len_g = $#g_arr + 1;
3001
3002 my $runtest = 1;
3003 my %new_configs;
2942 my $ret; 3004 my $ret;
2943 my %current_config;
2944 3005
2945 my $count = $#start_list + 1; 3006 # First, lets get it down to a single subset.
2946 doprint " $count configs to test\n"; 3007 # Is the problem with a difference in values?
3008 # Is the problem with a missing config?
3009 # Is the problem with a config that breaks things?
2947 3010
2948 my $half = int($#start_list / 2); 3011 # Enable all of one set and see if we get a new bad
3012 # or good config.
2949 3013
2950 do { 3014 # first set the good config to the bad values.
2951 my @tophalf = @start_list[0 .. $half];
2952 3015
2953 # keep the bottom half off 3016 doprint "d=$len_diff g=$len_g b=$len_b\n";
2954 if ($half < $#start_list) {
2955 @config_off_tmp = @start_list[$half + 1 .. $#start_list];
2956 } else {
2957 @config_off_tmp = ();
2958 }
2959 3017
2960 create_config @tophalf; 3018 # first lets enable things in bad config that are enabled in good config
2961 read_current_config \%current_config; 3019
2962 3020 if ($len_diff > 0) {
2963 $count = $#tophalf + 1; 3021 if ($len_b > 0 || $len_g > 0) {
2964 doprint "Testing $count configs\n"; 3022 my %tmp_config = %bad_configs;
2965 my $found = 0; 3023
2966 # make sure we test something 3024 doprint "Set tmp config to be bad config with good config values\n";
2967 foreach my $config (@tophalf) { 3025 foreach my $item (@diff_arr) {
2968 if (defined($current_config{$config})) { 3026 $tmp_config{$item} = $good_configs{$item};
2969 logit " $config\n";
2970 $found = 1;
2971 }
2972 }
2973 if (!$found) {
2974 # try the other half
2975 doprint "Top half produced no set configs, trying bottom half\n";
2976
2977 # keep the top half off
2978 @config_off_tmp = @tophalf;
2979 @tophalf = @start_list[$half + 1 .. $#start_list];
2980
2981 create_config @tophalf;
2982 read_current_config \%current_config;
2983 foreach my $config (@tophalf) {
2984 if (defined($current_config{$config})) {
2985 logit " $config\n";
2986 $found = 1;
2987 }
2988 }
2989 if (!$found) {
2990 doprint "Failed: Can't make new config with current configs\n";
2991 foreach my $config (@start_list) {
2992 doprint " CONFIG: $config\n";
2993 }
2994 return -1;
2995 } 3027 }
2996 $count = $#tophalf + 1;
2997 doprint "Testing $count configs\n";
2998 }
2999 3028
3000 $ret = run_config_bisect_test $type; 3029 $runtest = process_new_config \%tmp_config, \%new_configs,
3001 if ($bisect_manual) { 3030 \%good_configs, \%bad_configs;
3002 $ret = answer_bisect;
3003 }
3004 if ($ret) {
3005 process_passed %current_config;
3006 return 0;
3007 } 3031 }
3032 }
3008 3033
3009 doprint "This config had a failure.\n"; 3034 if (!$runtest && $len_diff > 0) {
3010 doprint "Removing these configs that were not set in this config:\n";
3011 doprint "config copied to $outputdir/config_bad\n";
3012 run_command "cp -f $output_config $outputdir/config_bad";
3013 3035
3014 # A config exists in this group that was bad. 3036 if ($len_diff == 1) {
3015 foreach my $config (keys %config_list) { 3037 process_failed $diff_arr[0];
3016 if (!defined($current_config{$config})) { 3038 return 1;
3017 doprint " removing $config\n";
3018 delete $config_list{$config};
3019 }
3020 } 3039 }
3040 my %tmp_config = %bad_configs;
3021 3041
3022 @start_list = @tophalf; 3042 my $half = int($#diff_arr / 2);
3043 my @tophalf = @diff_arr[0 .. $half];
3023 3044
3024 if ($#start_list == 0) { 3045 doprint "Settings bisect with top half:\n";
3025 process_failed $start_list[0]; 3046 doprint "Set tmp config to be bad config with some good config values\n";
3026 return 1; 3047 foreach my $item (@tophalf) {
3048 $tmp_config{$item} = $good_configs{$item};
3027 } 3049 }
3028 3050
3029 # remove half the configs we are looking at and see if 3051 $runtest = process_new_config \%tmp_config, \%new_configs,
3030 # they are good. 3052 \%good_configs, \%bad_configs;
3031 $half = int($#start_list / 2);
3032 } while ($#start_list > 0);
3033 3053
3034 # we found a single config, try it again unless we are running manually 3054 if (!$runtest) {
3055 my %tmp_config = %bad_configs;
3035 3056
3036 if ($bisect_manual) { 3057 doprint "Try bottom half\n";
3037 process_failed $start_list[0];
3038 return 1;
3039 }
3040 3058
3041 my @tophalf = @start_list[0 .. 0]; 3059 my @bottomhalf = @diff_arr[$half+1 .. $#diff_arr];
3042 3060
3043 $ret = run_config_bisect_test $type; 3061 foreach my $item (@bottomhalf) {
3044 if ($ret) { 3062 $tmp_config{$item} = $good_configs{$item};
3045 process_passed %current_config; 3063 }
3064
3065 $runtest = process_new_config \%tmp_config, \%new_configs,
3066 \%good_configs, \%bad_configs;
3067 }
3068 }
3069
3070 if ($runtest) {
3071 $ret = run_config_bisect_test $type;
3072 if ($ret) {
3073 doprint "NEW GOOD CONFIG\n";
3074 %good_configs = %new_configs;
3075 run_command "mv $good_config ${good_config}.last";
3076 save_config \%good_configs, $good_config;
3077 %{$pgood} = %good_configs;
3078 } else {
3079 doprint "NEW BAD CONFIG\n";
3080 %bad_configs = %new_configs;
3081 run_command "mv $bad_config ${bad_config}.last";
3082 save_config \%bad_configs, $bad_config;
3083 %{$pbad} = %bad_configs;
3084 }
3046 return 0; 3085 return 0;
3047 } 3086 }
3048 3087
3049 process_failed $start_list[0]; 3088 fail "Hmm, need to do a mix match?\n";
3050 return 1; 3089 return -1;
3051} 3090}
3052 3091
3053sub config_bisect { 3092sub config_bisect {
3054 my ($i) = @_; 3093 my ($i) = @_;
3055 3094
3056 my $start_config = $config_bisect; 3095 my $type = $config_bisect_type;
3096 my $ret;
3057 3097
3058 my $tmpconfig = "$tmpdir/use_config"; 3098 $bad_config = $config_bisect;
3059 3099
3060 if (defined($config_bisect_good)) { 3100 if (defined($config_bisect_good)) {
3061 process_config_ignore $config_bisect_good; 3101 $good_config = $config_bisect_good;
3062 } 3102 } elsif (defined($minconfig)) {
3063 3103 $good_config = $minconfig;
3064 # Make the file with the bad config and the min config
3065 if (defined($minconfig)) {
3066 # read the min config for things to ignore
3067 run_command "cp $minconfig $tmpconfig" or
3068 dodie "failed to copy $minconfig to $tmpconfig";
3069 } else { 3104 } else {
3070 unlink $tmpconfig; 3105 doprint "No config specified, checking if defconfig works";
3071 } 3106 $ret = run_bisect_test $type, "defconfig";
3072 3107 if (!$ret) {
3073 if (-f $tmpconfig) { 3108 fail "Have no good config to compare with, please set CONFIG_BISECT_GOOD";
3074 load_force_config($tmpconfig); 3109 return 1;
3075 process_config_ignore $tmpconfig;
3076 }
3077
3078 # now process the start config
3079 run_command "cp $start_config $output_config" or
3080 dodie "failed to copy $start_config to $output_config";
3081
3082 # read directly what we want to check
3083 my %config_check;
3084 open (IN, $output_config)
3085 or dodie "failed to open $output_config";
3086
3087 while (<IN>) {
3088 if (/^((CONFIG\S*)=.*)/) {
3089 $config_check{$2} = $1;
3090 } 3110 }
3111 $good_config = $output_config;
3091 } 3112 }
3092 close(IN);
3093 3113
3094 # Now run oldconfig with the minconfig 3114 # we don't want min configs to cause issues here.
3095 make_oldconfig; 3115 doprint "Disabling 'MIN_CONFIG' for this test\n";
3116 undef $minconfig;
3096 3117
3097 # check to see what we lost (or gained) 3118 my %good_configs;
3098 open (IN, $output_config) 3119 my %bad_configs;
3099 or dodie "Failed to read $start_config"; 3120 my %tmp_configs;
3100 3121
3101 my %removed_configs; 3122 doprint "Run good configs through make oldconfig\n";
3102 my %added_configs; 3123 assign_configs \%tmp_configs, $good_config;
3124 create_config "$good_config", \%tmp_configs;
3125 assign_configs \%good_configs, $output_config;
3103 3126
3104 while (<IN>) { 3127 doprint "Run bad configs through make oldconfig\n";
3105 if (/^((CONFIG\S*)=.*)/) { 3128 assign_configs \%tmp_configs, $bad_config;
3106 # save off all options 3129 create_config "$bad_config", \%tmp_configs;
3107 $config_set{$2} = $1; 3130 assign_configs \%bad_configs, $output_config;
3108 if (defined($config_check{$2})) {
3109 if (defined($config_ignore{$2})) {
3110 $removed_configs{$2} = $1;
3111 } else {
3112 $config_list{$2} = $1;
3113 }
3114 } elsif (!defined($config_ignore{$2})) {
3115 $added_configs{$2} = $1;
3116 $config_list{$2} = $1;
3117 }
3118 } elsif (/^# ((CONFIG\S*).*)/) {
3119 # Keep these configs disabled
3120 $config_set{$2} = $1;
3121 $config_off{$2} = $1;
3122 }
3123 }
3124 close(IN);
3125 3131
3126 my @confs = keys %removed_configs; 3132 $good_config = "$tmpdir/good_config";
3127 if ($#confs >= 0) { 3133 $bad_config = "$tmpdir/bad_config";
3128 doprint "Configs overridden by default configs and removed from check:\n"; 3134
3129 foreach my $config (@confs) { 3135 save_config \%good_configs, $good_config;
3130 doprint " $config\n"; 3136 save_config \%bad_configs, $bad_config;
3131 }
3132 }
3133 @confs = keys %added_configs;
3134 if ($#confs >= 0) {
3135 doprint "Configs appearing in make oldconfig and added:\n";
3136 foreach my $config (@confs) {
3137 doprint " $config\n";
3138 }
3139 }
3140 3137
3141 my %config_test;
3142 my $once = 0;
3143 3138
3144 @config_off_tmp = (); 3139 if (defined($config_bisect_check) && $config_bisect_check ne "0") {
3140 if ($config_bisect_check ne "good") {
3141 doprint "Testing bad config\n";
3145 3142
3146 # Sometimes kconfig does weird things. We must make sure 3143 $ret = run_bisect_test $type, "useconfig:$bad_config";
3147 # that the config we autocreate has everything we need 3144 if ($ret) {
3148 # to test, otherwise we may miss testing configs, or 3145 fail "Bad config succeeded when expected to fail!";
3149 # may not be able to create a new config. 3146 return 0;
3150 # Here we create a config with everything set.
3151 create_config (keys %config_list);
3152 read_current_config \%config_test;
3153 foreach my $config (keys %config_list) {
3154 if (!defined($config_test{$config})) {
3155 if (!$once) {
3156 $once = 1;
3157 doprint "Configs not produced by kconfig (will not be checked):\n";
3158 } 3147 }
3159 doprint " $config\n";
3160 delete $config_list{$config};
3161 } 3148 }
3162 } 3149 if ($config_bisect_check ne "bad") {
3163 my $ret; 3150 doprint "Testing good config\n";
3164 3151
3165 if (defined($config_bisect_check) && $config_bisect_check) { 3152 $ret = run_bisect_test $type, "useconfig:$good_config";
3166 doprint " Checking to make sure bad config with min config fails\n"; 3153 if (!$ret) {
3167 create_config keys %config_list; 3154 fail "Good config failed when expected to succeed!";
3168 $ret = run_config_bisect_test $config_bisect_type; 3155 return 0;
3169 if ($ret) { 3156 }
3170 doprint " FAILED! Bad config with min config boots fine\n";
3171 return -1;
3172 } 3157 }
3173 doprint " Bad config with min config fails as expected\n";
3174 } 3158 }
3175 3159
3176 do { 3160 do {
3177 $ret = run_config_bisect; 3161 $ret = run_config_bisect \%good_configs, \%bad_configs;
3178 } while (!$ret); 3162 } while (!$ret);
3179 3163
3180 return $ret if ($ret < 0); 3164 return $ret if ($ret < 0);
@@ -3455,29 +3439,6 @@ sub read_depends {
3455 read_kconfig($kconfig); 3439 read_kconfig($kconfig);
3456} 3440}
3457 3441
3458sub read_config_list {
3459 my ($config) = @_;
3460
3461 open (IN, $config)
3462 or dodie "Failed to read $config";
3463
3464 while (<IN>) {
3465 if (/^((CONFIG\S*)=.*)/) {
3466 if (!defined($config_ignore{$2})) {
3467 $config_list{$2} = $1;
3468 }
3469 }
3470 }
3471
3472 close(IN);
3473}
3474
3475sub read_output_config {
3476 my ($config) = @_;
3477
3478 assign_configs \%config_ignore, $config;
3479}
3480
3481sub make_new_config { 3442sub make_new_config {
3482 my @configs = @_; 3443 my @configs = @_;
3483 3444
@@ -3863,7 +3824,7 @@ sub make_warnings_file {
3863 success $i; 3824 success $i;
3864} 3825}
3865 3826
3866$#ARGV < 1 or die "ktest.pl version: $VERSION\n usage: ktest.pl config-file\n"; 3827$#ARGV < 1 or die "ktest.pl version: $VERSION\n usage: ktest.pl [config-file]\n";
3867 3828
3868if ($#ARGV == 0) { 3829if ($#ARGV == 0) {
3869 $ktest_config = $ARGV[0]; 3830 $ktest_config = $ARGV[0];
@@ -3873,8 +3834,6 @@ if ($#ARGV == 0) {
3873 exit 0; 3834 exit 0;
3874 } 3835 }
3875 } 3836 }
3876} else {
3877 $ktest_config = "ktest.conf";
3878} 3837}
3879 3838
3880if (! -f $ktest_config) { 3839if (! -f $ktest_config) {
diff --git a/tools/testing/ktest/sample.conf b/tools/testing/ktest/sample.conf
index 172eec4517fb..911e45ad657a 100644
--- a/tools/testing/ktest/sample.conf
+++ b/tools/testing/ktest/sample.conf
@@ -1098,49 +1098,35 @@
1098# 1098#
1099# The way it works is this: 1099# The way it works is this:
1100# 1100#
1101# First it finds a config to work with. Since a different version, or 1101# You can specify a good config with CONFIG_BISECT_GOOD, otherwise it
1102# MIN_CONFIG may cause different dependecies, it must run through this 1102# will use the MIN_CONFIG, and if that's not specified, it will use
1103# preparation. 1103# the config that comes with "make defconfig".
1104# 1104#
1105# Overwrites any config set in the bad config with a config set in 1105# It runs both the good and bad configs through a make oldconfig to
1106# either the MIN_CONFIG or ADD_CONFIG. Thus, make sure these configs 1106# make sure that they are set up for the kernel that is checked out.
1107# are minimal and do not disable configs you want to test:
1108# (ie. # CONFIG_FOO is not set).
1109# 1107#
1110# An oldconfig is run on the bad config and any new config that 1108# It then reads the configs that are set, as well as the ones that are
1111# appears will be added to the configs to test. 1109# not set for both the good and bad configs, and then compares them.
1110# It will set half of the good configs within the bad config (note,
1111# "set" means to make the bad config match the good config, a config
1112# in the good config that is off, will be turned off in the bad
1113# config. That is considered a "set").
1112# 1114#
1113# Finally, it generates a config with the above result and runs it 1115# It tests this new config and if it works, it becomes the new good
1114# again through make oldconfig to produce a config that should be 1116# config, otherwise it becomes the new bad config. It continues this
1115# satisfied by kconfig. 1117# process until there's only one config left and it will report that
1118# config.
1116# 1119#
1117# Then it starts the bisect. 1120# The "bad config" can also be a config that is needed to boot but was
1121# disabled because it depended on something that wasn't set.
1118# 1122#
1119# The configs to test are cut in half. If all the configs in this 1123# During this process, it saves the current good and bad configs in
1120# half depend on a config in the other half, then the other half 1124# ${TMP_DIR}/good_config and ${TMP_DIR}/bad_config respectively.
1121# is tested instead. If no configs are enabled by either half, then 1125# If you stop the test, you can copy them to a new location to
1122# this means a circular dependency exists and the test fails. 1126# reuse them again.
1123# 1127#
1124# A config is created with the test half, and the bisect test is run. 1128# Although the MIN_CONFIG may be the config it starts with, the
1125# 1129# MIN_CONFIG is ignored.
1126# If the bisect succeeds, then all configs in the generated config
1127# are removed from the configs to test and added to the configs that
1128# will be enabled for all builds (they will be enabled, but not be part
1129# of the configs to examine).
1130#
1131# If the bisect fails, then all test configs that were not enabled by
1132# the config file are removed from the test. These configs will not
1133# be enabled in future tests. Since current config failed, we consider
1134# this to be a subset of the config that we started with.
1135#
1136# When we are down to one config, it is considered the bad config.
1137#
1138# Note, the config chosen may not be the true bad config. Due to
1139# dependencies and selections of the kbuild system, mulitple
1140# configs may be needed to cause a failure. If you disable the
1141# config that was found and restart the test, if the test fails
1142# again, it is recommended to rerun the config_bisect with a new
1143# bad config without the found config enabled.
1144# 1130#
1145# The option BUILD_TYPE will be ignored. 1131# The option BUILD_TYPE will be ignored.
1146# 1132#
@@ -1160,13 +1146,16 @@
1160# CONFIG_BISECT_GOOD (optional) 1146# CONFIG_BISECT_GOOD (optional)
1161# If you have a good config to start with, then you 1147# If you have a good config to start with, then you
1162# can specify it with CONFIG_BISECT_GOOD. Otherwise 1148# can specify it with CONFIG_BISECT_GOOD. Otherwise
1163# the MIN_CONFIG is the base. 1149# the MIN_CONFIG is the base, if MIN_CONFIG is not set
1150# It will build a config with "make defconfig"
1164# 1151#
1165# CONFIG_BISECT_CHECK (optional) 1152# CONFIG_BISECT_CHECK (optional)
1166# Set this to 1 if you want to confirm that the config ktest 1153# Set this to 1 if you want to confirm that the config ktest
1167# generates (the bad config with the min config) is still bad. 1154# generates (the bad config with the min config) is still bad.
1168# It may be that the min config fixes what broke the bad config 1155# It may be that the min config fixes what broke the bad config
1169# and the test will not return a result. 1156# and the test will not return a result.
1157# Set it to "good" to test only the good config and set it
1158# to "bad" to only test the bad config.
1170# 1159#
1171# Example: 1160# Example:
1172# TEST_START 1161# TEST_START
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index e66e710cc595..36ff2e4c7b6f 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -2,8 +2,10 @@ TARGETS = breakpoints
2TARGETS += cpu-hotplug 2TARGETS += cpu-hotplug
3TARGETS += efivarfs 3TARGETS += efivarfs
4TARGETS += kcmp 4TARGETS += kcmp
5TARGETS += memfd
5TARGETS += memory-hotplug 6TARGETS += memory-hotplug
6TARGETS += mqueue 7TARGETS += mqueue
8TARGETS += mount
7TARGETS += net 9TARGETS += net
8TARGETS += ptrace 10TARGETS += ptrace
9TARGETS += timers 11TARGETS += timers
@@ -11,6 +13,10 @@ TARGETS += vm
11TARGETS += powerpc 13TARGETS += powerpc
12TARGETS += user 14TARGETS += user
13TARGETS += sysctl 15TARGETS += sysctl
16TARGETS += firmware
17
18TARGETS_HOTPLUG = cpu-hotplug
19TARGETS_HOTPLUG += memory-hotplug
14 20
15all: 21all:
16 for TARGET in $(TARGETS); do \ 22 for TARGET in $(TARGETS); do \
@@ -22,6 +28,21 @@ run_tests: all
22 make -C $$TARGET run_tests; \ 28 make -C $$TARGET run_tests; \
23 done; 29 done;
24 30
31hotplug:
32 for TARGET in $(TARGETS_HOTPLUG); do \
33 make -C $$TARGET; \
34 done;
35
36run_hotplug: hotplug
37 for TARGET in $(TARGETS_HOTPLUG); do \
38 make -C $$TARGET run_full_test; \
39 done;
40
41clean_hotplug:
42 for TARGET in $(TARGETS_HOTPLUG); do \
43 make -C $$TARGET clean; \
44 done;
45
25clean: 46clean:
26 for TARGET in $(TARGETS); do \ 47 for TARGET in $(TARGETS); do \
27 make -C $$TARGET clean; \ 48 make -C $$TARGET clean; \
diff --git a/tools/testing/selftests/README.txt b/tools/testing/selftests/README.txt
index 5e2faf9c55d3..2660d5ff9179 100644
--- a/tools/testing/selftests/README.txt
+++ b/tools/testing/selftests/README.txt
@@ -4,8 +4,15 @@ The kernel contains a set of "self tests" under the tools/testing/selftests/
4directory. These are intended to be small unit tests to exercise individual 4directory. These are intended to be small unit tests to exercise individual
5code paths in the kernel. 5code paths in the kernel.
6 6
7Running the selftests 7On some systems, hot-plug tests could hang forever waiting for cpu and
8===================== 8memory to be ready to be offlined. A special hot-plug target is created
9to run full range of hot-plug tests. In default mode, hot-plug tests run
10in safe mode with a limited scope. In limited mode, cpu-hotplug test is
11run on a single cpu as opposed to all hotplug capable cpus, and memory
12hotplug test is run on 2% of hotplug capable memory instead of 10%.
13
14Running the selftests (hotplug tests are run in limited mode)
15=============================================================
9 16
10To build the tests: 17To build the tests:
11 18
@@ -18,14 +25,26 @@ To run the tests:
18 25
19- note that some tests will require root privileges. 26- note that some tests will require root privileges.
20 27
21 28To run only tests targeted for a single subsystem: (including
22To run only tests targetted for a single subsystem: 29hotplug targets in limited mode)
23 30
24 $ make -C tools/testing/selftests TARGETS=cpu-hotplug run_tests 31 $ make -C tools/testing/selftests TARGETS=cpu-hotplug run_tests
25 32
26See the top-level tools/testing/selftests/Makefile for the list of all possible 33See the top-level tools/testing/selftests/Makefile for the list of all possible
27targets. 34targets.
28 35
36Running the full range hotplug selftests
37========================================
38
39To build the tests:
40
41 $ make -C tools/testing/selftests hotplug
42
43To run the tests:
44
45 $ make -C tools/testing/selftests run_hotplug
46
47- note that some tests will require root privileges.
29 48
30Contributing new tests 49Contributing new tests
31====================== 50======================
diff --git a/tools/testing/selftests/cpu-hotplug/Makefile b/tools/testing/selftests/cpu-hotplug/Makefile
index 790c23a9db44..e9c28d8dc84b 100644
--- a/tools/testing/selftests/cpu-hotplug/Makefile
+++ b/tools/testing/selftests/cpu-hotplug/Makefile
@@ -3,4 +3,7 @@ all:
3run_tests: 3run_tests:
4 @/bin/bash ./on-off-test.sh || echo "cpu-hotplug selftests: [FAIL]" 4 @/bin/bash ./on-off-test.sh || echo "cpu-hotplug selftests: [FAIL]"
5 5
6run_full_test:
7 @/bin/bash ./on-off-test.sh -a || echo "cpu-hotplug selftests: [FAIL]"
8
6clean: 9clean:
diff --git a/tools/testing/selftests/cpu-hotplug/on-off-test.sh b/tools/testing/selftests/cpu-hotplug/on-off-test.sh
index bdde7cf428bb..98b1d6565f2c 100644
--- a/tools/testing/selftests/cpu-hotplug/on-off-test.sh
+++ b/tools/testing/selftests/cpu-hotplug/on-off-test.sh
@@ -11,6 +11,8 @@ prerequisite()
11 exit 0 11 exit 0
12 fi 12 fi
13 13
14 taskset -p 01 $$
15
14 SYSFS=`mount -t sysfs | head -1 | awk '{ print $3 }'` 16 SYSFS=`mount -t sysfs | head -1 | awk '{ print $3 }'`
15 17
16 if [ ! -d "$SYSFS" ]; then 18 if [ ! -d "$SYSFS" ]; then
@@ -22,6 +24,19 @@ prerequisite()
22 echo $msg cpu hotplug is not supported >&2 24 echo $msg cpu hotplug is not supported >&2
23 exit 0 25 exit 0
24 fi 26 fi
27
28 echo "CPU online/offline summary:"
29 online_cpus=`cat $SYSFS/devices/system/cpu/online`
30 online_max=${online_cpus##*-}
31 echo -e "\t Cpus in online state: $online_cpus"
32
33 offline_cpus=`cat $SYSFS/devices/system/cpu/offline`
34 if [[ "a$offline_cpus" = "a" ]]; then
35 offline_cpus=0
36 else
37 offline_max=${offline_cpus##*-}
38 fi
39 echo -e "\t Cpus in offline state: $offline_cpus"
25} 40}
26 41
27# 42#
@@ -113,15 +128,25 @@ offline_cpu_expect_fail()
113} 128}
114 129
115error=-12 130error=-12
131allcpus=0
116priority=0 132priority=0
133online_cpus=0
134online_max=0
135offline_cpus=0
136offline_max=0
117 137
118while getopts e:hp: opt; do 138while getopts e:ahp: opt; do
119 case $opt in 139 case $opt in
120 e) 140 e)
121 error=$OPTARG 141 error=$OPTARG
122 ;; 142 ;;
143 a)
144 allcpus=1
145 ;;
123 h) 146 h)
124 echo "Usage $0 [ -e errno ] [ -p notifier-priority ]" 147 echo "Usage $0 [ -a ] [ -e errno ] [ -p notifier-priority ]"
148 echo -e "\t default offline one cpu"
149 echo -e "\t run with -a option to offline all cpus"
125 exit 150 exit
126 ;; 151 ;;
127 p) 152 p)
@@ -138,6 +163,29 @@ fi
138prerequisite 163prerequisite
139 164
140# 165#
166# Safe test (default) - offline and online one cpu
167#
168if [ $allcpus -eq 0 ]; then
169 echo "Limited scope test: one hotplug cpu"
170 echo -e "\t (leaves cpu in the original state):"
171 echo -e "\t online to offline to online: cpu $online_max"
172 offline_cpu_expect_success $online_max
173 online_cpu_expect_success $online_max
174
175 if [[ $offline_cpus -gt 0 ]]; then
176 echo -e "\t offline to online to offline: cpu $offline_max"
177 online_cpu_expect_success $offline_max
178 offline_cpu_expect_success $offline_max
179 fi
180 exit 0
181else
182 echo "Full scope test: all hotplug cpus"
183 echo -e "\t online all offline cpus"
184 echo -e "\t offline all online cpus"
185 echo -e "\t online all offline cpus"
186fi
187
188#
141# Online all hot-pluggable CPUs 189# Online all hot-pluggable CPUs
142# 190#
143for cpu in `hotplaggable_offline_cpus`; do 191for cpu in `hotplaggable_offline_cpus`; do
diff --git a/tools/testing/selftests/firmware/Makefile b/tools/testing/selftests/firmware/Makefile
new file mode 100644
index 000000000000..e23cce0bbc3a
--- /dev/null
+++ b/tools/testing/selftests/firmware/Makefile
@@ -0,0 +1,27 @@
1# Makefile for firmware loading selftests
2
3# No binaries, but make sure arg-less "make" doesn't trigger "run_tests"
4all:
5
6fw_filesystem:
7 @if /bin/sh ./fw_filesystem.sh ; then \
8 echo "fw_filesystem: ok"; \
9 else \
10 echo "fw_filesystem: [FAIL]"; \
11 exit 1; \
12 fi
13
14fw_userhelper:
15 @if /bin/sh ./fw_userhelper.sh ; then \
16 echo "fw_userhelper: ok"; \
17 else \
18 echo "fw_userhelper: [FAIL]"; \
19 exit 1; \
20 fi
21
22run_tests: all fw_filesystem fw_userhelper
23
24# Nothing to clean up.
25clean:
26
27.PHONY: all clean run_tests fw_filesystem fw_userhelper
diff --git a/tools/testing/selftests/firmware/fw_filesystem.sh b/tools/testing/selftests/firmware/fw_filesystem.sh
new file mode 100644
index 000000000000..3fc6c10c2479
--- /dev/null
+++ b/tools/testing/selftests/firmware/fw_filesystem.sh
@@ -0,0 +1,62 @@
1#!/bin/sh
2# This validates that the kernel will load firmware out of its list of
3# firmware locations on disk. Since the user helper does similar work,
4# we reset the custom load directory to a location the user helper doesn't
5# know so we can be sure we're not accidentally testing the user helper.
6set -e
7
8modprobe test_firmware
9
10DIR=/sys/devices/virtual/misc/test_firmware
11
12OLD_TIMEOUT=$(cat /sys/class/firmware/timeout)
13OLD_FWPATH=$(cat /sys/module/firmware_class/parameters/path)
14
15FWPATH=$(mktemp -d)
16FW="$FWPATH/test-firmware.bin"
17
18test_finish()
19{
20 echo "$OLD_TIMEOUT" >/sys/class/firmware/timeout
21 echo -n "$OLD_PATH" >/sys/module/firmware_class/parameters/path
22 rm -f "$FW"
23 rmdir "$FWPATH"
24}
25
26trap "test_finish" EXIT
27
28# Turn down the timeout so failures don't take so long.
29echo 1 >/sys/class/firmware/timeout
30# Set the kernel search path.
31echo -n "$FWPATH" >/sys/module/firmware_class/parameters/path
32
33# This is an unlikely real-world firmware content. :)
34echo "ABCD0123" >"$FW"
35
36NAME=$(basename "$FW")
37
38# Request a firmware that doesn't exist, it should fail.
39echo -n "nope-$NAME" >"$DIR"/trigger_request
40if diff -q "$FW" /dev/test_firmware >/dev/null ; then
41 echo "$0: firmware was not expected to match" >&2
42 exit 1
43else
44 echo "$0: timeout works"
45fi
46
47# This should succeed via kernel load or will fail after 1 second after
48# being handed over to the user helper, which won't find the fw either.
49if ! echo -n "$NAME" >"$DIR"/trigger_request ; then
50 echo "$0: could not trigger request" >&2
51 exit 1
52fi
53
54# Verify the contents are what we expect.
55if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then
56 echo "$0: firmware was not loaded" >&2
57 exit 1
58else
59 echo "$0: filesystem loading works"
60fi
61
62exit 0
diff --git a/tools/testing/selftests/firmware/fw_userhelper.sh b/tools/testing/selftests/firmware/fw_userhelper.sh
new file mode 100644
index 000000000000..6efbade12139
--- /dev/null
+++ b/tools/testing/selftests/firmware/fw_userhelper.sh
@@ -0,0 +1,89 @@
1#!/bin/sh
2# This validates that the kernel will fall back to using the user helper
3# to load firmware it can't find on disk itself. We must request a firmware
4# that the kernel won't find, and any installed helper (e.g. udev) also
5# won't find so that we can do the load ourself manually.
6set -e
7
8modprobe test_firmware
9
10DIR=/sys/devices/virtual/misc/test_firmware
11
12OLD_TIMEOUT=$(cat /sys/class/firmware/timeout)
13
14FWPATH=$(mktemp -d)
15FW="$FWPATH/test-firmware.bin"
16
17test_finish()
18{
19 echo "$OLD_TIMEOUT" >/sys/class/firmware/timeout
20 rm -f "$FW"
21 rmdir "$FWPATH"
22}
23
24load_fw()
25{
26 local name="$1"
27 local file="$2"
28
29 # This will block until our load (below) has finished.
30 echo -n "$name" >"$DIR"/trigger_request &
31
32 # Give kernel a chance to react.
33 local timeout=10
34 while [ ! -e "$DIR"/"$name"/loading ]; do
35 sleep 0.1
36 timeout=$(( $timeout - 1 ))
37 if [ "$timeout" -eq 0 ]; then
38 echo "$0: firmware interface never appeared" >&2
39 exit 1
40 fi
41 done
42
43 echo 1 >"$DIR"/"$name"/loading
44 cat "$file" >"$DIR"/"$name"/data
45 echo 0 >"$DIR"/"$name"/loading
46
47 # Wait for request to finish.
48 wait
49}
50
51trap "test_finish" EXIT
52
53# This is an unlikely real-world firmware content. :)
54echo "ABCD0123" >"$FW"
55NAME=$(basename "$FW")
56
57# Test failure when doing nothing (timeout works).
58echo 1 >/sys/class/firmware/timeout
59echo -n "$NAME" >"$DIR"/trigger_request
60if diff -q "$FW" /dev/test_firmware >/dev/null ; then
61 echo "$0: firmware was not expected to match" >&2
62 exit 1
63else
64 echo "$0: timeout works"
65fi
66
67# Put timeout high enough for us to do work but not so long that failures
68# slow down this test too much.
69echo 4 >/sys/class/firmware/timeout
70
71# Load this script instead of the desired firmware.
72load_fw "$NAME" "$0"
73if diff -q "$FW" /dev/test_firmware >/dev/null ; then
74 echo "$0: firmware was not expected to match" >&2
75 exit 1
76else
77 echo "$0: firmware comparison works"
78fi
79
80# Do a proper load, which should work correctly.
81load_fw "$NAME" "$FW"
82if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then
83 echo "$0: firmware was not loaded" >&2
84 exit 1
85else
86 echo "$0: user helper firmware loading works"
87fi
88
89exit 0
diff --git a/tools/testing/selftests/kcmp/kcmp_test.c b/tools/testing/selftests/kcmp/kcmp_test.c
index fa4f1b37e045..dbba4084869c 100644
--- a/tools/testing/selftests/kcmp/kcmp_test.c
+++ b/tools/testing/selftests/kcmp/kcmp_test.c
@@ -81,7 +81,7 @@ int main(int argc, char **argv)
81 /* Compare with self */ 81 /* Compare with self */
82 ret = sys_kcmp(pid1, pid1, KCMP_VM, 0, 0); 82 ret = sys_kcmp(pid1, pid1, KCMP_VM, 0, 0);
83 if (ret) { 83 if (ret) {
84 printf("FAIL: 0 expected but %li returned (%s)\n", 84 printf("FAIL: 0 expected but %d returned (%s)\n",
85 ret, strerror(errno)); 85 ret, strerror(errno));
86 ret = -1; 86 ret = -1;
87 } else 87 } else
diff --git a/tools/testing/selftests/memfd/.gitignore b/tools/testing/selftests/memfd/.gitignore
new file mode 100644
index 000000000000..afe87c40ac80
--- /dev/null
+++ b/tools/testing/selftests/memfd/.gitignore
@@ -0,0 +1,4 @@
1fuse_mnt
2fuse_test
3memfd_test
4memfd-test-file
diff --git a/tools/testing/selftests/memfd/Makefile b/tools/testing/selftests/memfd/Makefile
new file mode 100644
index 000000000000..6816c491c5ff
--- /dev/null
+++ b/tools/testing/selftests/memfd/Makefile
@@ -0,0 +1,41 @@
1uname_M := $(shell uname -m 2>/dev/null || echo not)
2ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/)
3ifeq ($(ARCH),i386)
4 ARCH := X86
5endif
6ifeq ($(ARCH),x86_64)
7 ARCH := X86
8endif
9
10CFLAGS += -D_FILE_OFFSET_BITS=64
11CFLAGS += -I../../../../arch/x86/include/generated/uapi/
12CFLAGS += -I../../../../arch/x86/include/uapi/
13CFLAGS += -I../../../../include/uapi/
14CFLAGS += -I../../../../include/
15
16all:
17ifeq ($(ARCH),X86)
18 gcc $(CFLAGS) memfd_test.c -o memfd_test
19else
20 echo "Not an x86 target, can't build memfd selftest"
21endif
22
23run_tests: all
24ifeq ($(ARCH),X86)
25 gcc $(CFLAGS) memfd_test.c -o memfd_test
26endif
27 @./memfd_test || echo "memfd_test: [FAIL]"
28
29build_fuse:
30ifeq ($(ARCH),X86)
31 gcc $(CFLAGS) fuse_mnt.c `pkg-config fuse --cflags --libs` -o fuse_mnt
32 gcc $(CFLAGS) fuse_test.c -o fuse_test
33else
34 echo "Not an x86 target, can't build memfd selftest"
35endif
36
37run_fuse: build_fuse
38 @./run_fuse_test.sh || echo "fuse_test: [FAIL]"
39
40clean:
41 $(RM) memfd_test fuse_test
diff --git a/tools/testing/selftests/memfd/fuse_mnt.c b/tools/testing/selftests/memfd/fuse_mnt.c
new file mode 100644
index 000000000000..feacf1280fcd
--- /dev/null
+++ b/tools/testing/selftests/memfd/fuse_mnt.c
@@ -0,0 +1,110 @@
1/*
2 * memfd test file-system
3 * This file uses FUSE to create a dummy file-system with only one file /memfd.
4 * This file is read-only and takes 1s per read.
5 *
6 * This file-system is used by the memfd test-cases to force the kernel to pin
7 * pages during reads(). Due to the 1s delay of this file-system, this is a
8 * nice way to test race-conditions against get_user_pages() in the kernel.
9 *
10 * We use direct_io==1 to force the kernel to use direct-IO for this
11 * file-system.
12 */
13
14#define FUSE_USE_VERSION 26
15
16#include <fuse.h>
17#include <stdio.h>
18#include <string.h>
19#include <errno.h>
20#include <fcntl.h>
21#include <unistd.h>
22
23static const char memfd_content[] = "memfd-example-content";
24static const char memfd_path[] = "/memfd";
25
26static int memfd_getattr(const char *path, struct stat *st)
27{
28 memset(st, 0, sizeof(*st));
29
30 if (!strcmp(path, "/")) {
31 st->st_mode = S_IFDIR | 0755;
32 st->st_nlink = 2;
33 } else if (!strcmp(path, memfd_path)) {
34 st->st_mode = S_IFREG | 0444;
35 st->st_nlink = 1;
36 st->st_size = strlen(memfd_content);
37 } else {
38 return -ENOENT;
39 }
40
41 return 0;
42}
43
44static int memfd_readdir(const char *path,
45 void *buf,
46 fuse_fill_dir_t filler,
47 off_t offset,
48 struct fuse_file_info *fi)
49{
50 if (strcmp(path, "/"))
51 return -ENOENT;
52
53 filler(buf, ".", NULL, 0);
54 filler(buf, "..", NULL, 0);
55 filler(buf, memfd_path + 1, NULL, 0);
56
57 return 0;
58}
59
60static int memfd_open(const char *path, struct fuse_file_info *fi)
61{
62 if (strcmp(path, memfd_path))
63 return -ENOENT;
64
65 if ((fi->flags & 3) != O_RDONLY)
66 return -EACCES;
67
68 /* force direct-IO */
69 fi->direct_io = 1;
70
71 return 0;
72}
73
74static int memfd_read(const char *path,
75 char *buf,
76 size_t size,
77 off_t offset,
78 struct fuse_file_info *fi)
79{
80 size_t len;
81
82 if (strcmp(path, memfd_path) != 0)
83 return -ENOENT;
84
85 sleep(1);
86
87 len = strlen(memfd_content);
88 if (offset < len) {
89 if (offset + size > len)
90 size = len - offset;
91
92 memcpy(buf, memfd_content + offset, size);
93 } else {
94 size = 0;
95 }
96
97 return size;
98}
99
100static struct fuse_operations memfd_ops = {
101 .getattr = memfd_getattr,
102 .readdir = memfd_readdir,
103 .open = memfd_open,
104 .read = memfd_read,
105};
106
107int main(int argc, char *argv[])
108{
109 return fuse_main(argc, argv, &memfd_ops, NULL);
110}
diff --git a/tools/testing/selftests/memfd/fuse_test.c b/tools/testing/selftests/memfd/fuse_test.c
new file mode 100644
index 000000000000..67908b18f035
--- /dev/null
+++ b/tools/testing/selftests/memfd/fuse_test.c
@@ -0,0 +1,311 @@
1/*
2 * memfd GUP test-case
3 * This tests memfd interactions with get_user_pages(). We require the
4 * fuse_mnt.c program to provide a fake direct-IO FUSE mount-point for us. This
5 * file-system delays _all_ reads by 1s and forces direct-IO. This means, any
6 * read() on files in that file-system will pin the receive-buffer pages for at
7 * least 1s via get_user_pages().
8 *
9 * We use this trick to race ADD_SEALS against a write on a memfd object. The
10 * ADD_SEALS must fail if the memfd pages are still pinned. Note that we use
11 * the read() syscall with our memory-mapped memfd object as receive buffer to
12 * force the kernel to write into our memfd object.
13 */
14
15#define _GNU_SOURCE
16#define __EXPORTED_HEADERS__
17
18#include <errno.h>
19#include <inttypes.h>
20#include <limits.h>
21#include <linux/falloc.h>
22#include <linux/fcntl.h>
23#include <linux/memfd.h>
24#include <sched.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <signal.h>
28#include <string.h>
29#include <sys/mman.h>
30#include <sys/stat.h>
31#include <sys/syscall.h>
32#include <sys/wait.h>
33#include <unistd.h>
34
35#define MFD_DEF_SIZE 8192
36#define STACK_SIZE 65535
37
38static int sys_memfd_create(const char *name,
39 unsigned int flags)
40{
41 return syscall(__NR_memfd_create, name, flags);
42}
43
44static int mfd_assert_new(const char *name, loff_t sz, unsigned int flags)
45{
46 int r, fd;
47
48 fd = sys_memfd_create(name, flags);
49 if (fd < 0) {
50 printf("memfd_create(\"%s\", %u) failed: %m\n",
51 name, flags);
52 abort();
53 }
54
55 r = ftruncate(fd, sz);
56 if (r < 0) {
57 printf("ftruncate(%llu) failed: %m\n", (unsigned long long)sz);
58 abort();
59 }
60
61 return fd;
62}
63
64static __u64 mfd_assert_get_seals(int fd)
65{
66 long r;
67
68 r = fcntl(fd, F_GET_SEALS);
69 if (r < 0) {
70 printf("GET_SEALS(%d) failed: %m\n", fd);
71 abort();
72 }
73
74 return r;
75}
76
77static void mfd_assert_has_seals(int fd, __u64 seals)
78{
79 __u64 s;
80
81 s = mfd_assert_get_seals(fd);
82 if (s != seals) {
83 printf("%llu != %llu = GET_SEALS(%d)\n",
84 (unsigned long long)seals, (unsigned long long)s, fd);
85 abort();
86 }
87}
88
89static void mfd_assert_add_seals(int fd, __u64 seals)
90{
91 long r;
92 __u64 s;
93
94 s = mfd_assert_get_seals(fd);
95 r = fcntl(fd, F_ADD_SEALS, seals);
96 if (r < 0) {
97 printf("ADD_SEALS(%d, %llu -> %llu) failed: %m\n",
98 fd, (unsigned long long)s, (unsigned long long)seals);
99 abort();
100 }
101}
102
103static int mfd_busy_add_seals(int fd, __u64 seals)
104{
105 long r;
106 __u64 s;
107
108 r = fcntl(fd, F_GET_SEALS);
109 if (r < 0)
110 s = 0;
111 else
112 s = r;
113
114 r = fcntl(fd, F_ADD_SEALS, seals);
115 if (r < 0 && errno != EBUSY) {
116 printf("ADD_SEALS(%d, %llu -> %llu) didn't fail as expected with EBUSY: %m\n",
117 fd, (unsigned long long)s, (unsigned long long)seals);
118 abort();
119 }
120
121 return r;
122}
123
124static void *mfd_assert_mmap_shared(int fd)
125{
126 void *p;
127
128 p = mmap(NULL,
129 MFD_DEF_SIZE,
130 PROT_READ | PROT_WRITE,
131 MAP_SHARED,
132 fd,
133 0);
134 if (p == MAP_FAILED) {
135 printf("mmap() failed: %m\n");
136 abort();
137 }
138
139 return p;
140}
141
142static void *mfd_assert_mmap_private(int fd)
143{
144 void *p;
145
146 p = mmap(NULL,
147 MFD_DEF_SIZE,
148 PROT_READ | PROT_WRITE,
149 MAP_PRIVATE,
150 fd,
151 0);
152 if (p == MAP_FAILED) {
153 printf("mmap() failed: %m\n");
154 abort();
155 }
156
157 return p;
158}
159
160static int global_mfd = -1;
161static void *global_p = NULL;
162
163static int sealing_thread_fn(void *arg)
164{
165 int sig, r;
166
167 /*
168 * This thread first waits 200ms so any pending operation in the parent
169 * is correctly started. After that, it tries to seal @global_mfd as
170 * SEAL_WRITE. This _must_ fail as the parent thread has a read() into
171 * that memory mapped object still ongoing.
172 * We then wait one more second and try sealing again. This time it
173 * must succeed as there shouldn't be anyone else pinning the pages.
174 */
175
176 /* wait 200ms for FUSE-request to be active */
177 usleep(200000);
178
179 /* unmount mapping before sealing to avoid i_mmap_writable failures */
180 munmap(global_p, MFD_DEF_SIZE);
181
182 /* Try sealing the global file; expect EBUSY or success. Current
183 * kernels will never succeed, but in the future, kernels might
184 * implement page-replacements or other fancy ways to avoid racing
185 * writes. */
186 r = mfd_busy_add_seals(global_mfd, F_SEAL_WRITE);
187 if (r >= 0) {
188 printf("HURRAY! This kernel fixed GUP races!\n");
189 } else {
190 /* wait 1s more so the FUSE-request is done */
191 sleep(1);
192
193 /* try sealing the global file again */
194 mfd_assert_add_seals(global_mfd, F_SEAL_WRITE);
195 }
196
197 return 0;
198}
199
200static pid_t spawn_sealing_thread(void)
201{
202 uint8_t *stack;
203 pid_t pid;
204
205 stack = malloc(STACK_SIZE);
206 if (!stack) {
207 printf("malloc(STACK_SIZE) failed: %m\n");
208 abort();
209 }
210
211 pid = clone(sealing_thread_fn,
212 stack + STACK_SIZE,
213 SIGCHLD | CLONE_FILES | CLONE_FS | CLONE_VM,
214 NULL);
215 if (pid < 0) {
216 printf("clone() failed: %m\n");
217 abort();
218 }
219
220 return pid;
221}
222
223static void join_sealing_thread(pid_t pid)
224{
225 waitpid(pid, NULL, 0);
226}
227
228int main(int argc, char **argv)
229{
230 static const char zero[MFD_DEF_SIZE];
231 int fd, mfd, r;
232 void *p;
233 int was_sealed;
234 pid_t pid;
235
236 if (argc < 2) {
237 printf("error: please pass path to file in fuse_mnt mount-point\n");
238 abort();
239 }
240
241 /* open FUSE memfd file for GUP testing */
242 printf("opening: %s\n", argv[1]);
243 fd = open(argv[1], O_RDONLY | O_CLOEXEC);
244 if (fd < 0) {
245 printf("cannot open(\"%s\"): %m\n", argv[1]);
246 abort();
247 }
248
249 /* create new memfd-object */
250 mfd = mfd_assert_new("kern_memfd_fuse",
251 MFD_DEF_SIZE,
252 MFD_CLOEXEC | MFD_ALLOW_SEALING);
253
254 /* mmap memfd-object for writing */
255 p = mfd_assert_mmap_shared(mfd);
256
257 /* pass mfd+mapping to a separate sealing-thread which tries to seal
258 * the memfd objects with SEAL_WRITE while we write into it */
259 global_mfd = mfd;
260 global_p = p;
261 pid = spawn_sealing_thread();
262
263 /* Use read() on the FUSE file to read into our memory-mapped memfd
264 * object. This races the other thread which tries to seal the
265 * memfd-object.
266 * If @fd is on the memfd-fake-FUSE-FS, the read() is delayed by 1s.
267 * This guarantees that the receive-buffer is pinned for 1s until the
268 * data is written into it. The racing ADD_SEALS should thus fail as
269 * the pages are still pinned. */
270 r = read(fd, p, MFD_DEF_SIZE);
271 if (r < 0) {
272 printf("read() failed: %m\n");
273 abort();
274 } else if (!r) {
275 printf("unexpected EOF on read()\n");
276 abort();
277 }
278
279 was_sealed = mfd_assert_get_seals(mfd) & F_SEAL_WRITE;
280
281 /* Wait for sealing-thread to finish and verify that it
282 * successfully sealed the file after the second try. */
283 join_sealing_thread(pid);
284 mfd_assert_has_seals(mfd, F_SEAL_WRITE);
285
286 /* *IF* the memfd-object was sealed at the time our read() returned,
287 * then the kernel did a page-replacement or canceled the read() (or
288 * whatever magic it did..). In that case, the memfd object is still
289 * all zero.
290 * In case the memfd-object was *not* sealed, the read() was successfull
291 * and the memfd object must *not* be all zero.
292 * Note that in real scenarios, there might be a mixture of both, but
293 * in this test-cases, we have explicit 200ms delays which should be
294 * enough to avoid any in-flight writes. */
295
296 p = mfd_assert_mmap_private(mfd);
297 if (was_sealed && memcmp(p, zero, MFD_DEF_SIZE)) {
298 printf("memfd sealed during read() but data not discarded\n");
299 abort();
300 } else if (!was_sealed && !memcmp(p, zero, MFD_DEF_SIZE)) {
301 printf("memfd sealed after read() but data discarded\n");
302 abort();
303 }
304
305 close(mfd);
306 close(fd);
307
308 printf("fuse: DONE\n");
309
310 return 0;
311}
diff --git a/tools/testing/selftests/memfd/memfd_test.c b/tools/testing/selftests/memfd/memfd_test.c
new file mode 100644
index 000000000000..3634c909b1b0
--- /dev/null
+++ b/tools/testing/selftests/memfd/memfd_test.c
@@ -0,0 +1,913 @@
1#define _GNU_SOURCE
2#define __EXPORTED_HEADERS__
3
4#include <errno.h>
5#include <inttypes.h>
6#include <limits.h>
7#include <linux/falloc.h>
8#include <linux/fcntl.h>
9#include <linux/memfd.h>
10#include <sched.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <signal.h>
14#include <string.h>
15#include <sys/mman.h>
16#include <sys/stat.h>
17#include <sys/syscall.h>
18#include <unistd.h>
19
20#define MFD_DEF_SIZE 8192
21#define STACK_SIZE 65535
22
23static int sys_memfd_create(const char *name,
24 unsigned int flags)
25{
26 return syscall(__NR_memfd_create, name, flags);
27}
28
29static int mfd_assert_new(const char *name, loff_t sz, unsigned int flags)
30{
31 int r, fd;
32
33 fd = sys_memfd_create(name, flags);
34 if (fd < 0) {
35 printf("memfd_create(\"%s\", %u) failed: %m\n",
36 name, flags);
37 abort();
38 }
39
40 r = ftruncate(fd, sz);
41 if (r < 0) {
42 printf("ftruncate(%llu) failed: %m\n", (unsigned long long)sz);
43 abort();
44 }
45
46 return fd;
47}
48
49static void mfd_fail_new(const char *name, unsigned int flags)
50{
51 int r;
52
53 r = sys_memfd_create(name, flags);
54 if (r >= 0) {
55 printf("memfd_create(\"%s\", %u) succeeded, but failure expected\n",
56 name, flags);
57 close(r);
58 abort();
59 }
60}
61
62static __u64 mfd_assert_get_seals(int fd)
63{
64 long r;
65
66 r = fcntl(fd, F_GET_SEALS);
67 if (r < 0) {
68 printf("GET_SEALS(%d) failed: %m\n", fd);
69 abort();
70 }
71
72 return r;
73}
74
75static void mfd_assert_has_seals(int fd, __u64 seals)
76{
77 __u64 s;
78
79 s = mfd_assert_get_seals(fd);
80 if (s != seals) {
81 printf("%llu != %llu = GET_SEALS(%d)\n",
82 (unsigned long long)seals, (unsigned long long)s, fd);
83 abort();
84 }
85}
86
87static void mfd_assert_add_seals(int fd, __u64 seals)
88{
89 long r;
90 __u64 s;
91
92 s = mfd_assert_get_seals(fd);
93 r = fcntl(fd, F_ADD_SEALS, seals);
94 if (r < 0) {
95 printf("ADD_SEALS(%d, %llu -> %llu) failed: %m\n",
96 fd, (unsigned long long)s, (unsigned long long)seals);
97 abort();
98 }
99}
100
101static void mfd_fail_add_seals(int fd, __u64 seals)
102{
103 long r;
104 __u64 s;
105
106 r = fcntl(fd, F_GET_SEALS);
107 if (r < 0)
108 s = 0;
109 else
110 s = r;
111
112 r = fcntl(fd, F_ADD_SEALS, seals);
113 if (r >= 0) {
114 printf("ADD_SEALS(%d, %llu -> %llu) didn't fail as expected\n",
115 fd, (unsigned long long)s, (unsigned long long)seals);
116 abort();
117 }
118}
119
120static void mfd_assert_size(int fd, size_t size)
121{
122 struct stat st;
123 int r;
124
125 r = fstat(fd, &st);
126 if (r < 0) {
127 printf("fstat(%d) failed: %m\n", fd);
128 abort();
129 } else if (st.st_size != size) {
130 printf("wrong file size %lld, but expected %lld\n",
131 (long long)st.st_size, (long long)size);
132 abort();
133 }
134}
135
136static int mfd_assert_dup(int fd)
137{
138 int r;
139
140 r = dup(fd);
141 if (r < 0) {
142 printf("dup(%d) failed: %m\n", fd);
143 abort();
144 }
145
146 return r;
147}
148
149static void *mfd_assert_mmap_shared(int fd)
150{
151 void *p;
152
153 p = mmap(NULL,
154 MFD_DEF_SIZE,
155 PROT_READ | PROT_WRITE,
156 MAP_SHARED,
157 fd,
158 0);
159 if (p == MAP_FAILED) {
160 printf("mmap() failed: %m\n");
161 abort();
162 }
163
164 return p;
165}
166
167static void *mfd_assert_mmap_private(int fd)
168{
169 void *p;
170
171 p = mmap(NULL,
172 MFD_DEF_SIZE,
173 PROT_READ,
174 MAP_PRIVATE,
175 fd,
176 0);
177 if (p == MAP_FAILED) {
178 printf("mmap() failed: %m\n");
179 abort();
180 }
181
182 return p;
183}
184
185static int mfd_assert_open(int fd, int flags, mode_t mode)
186{
187 char buf[512];
188 int r;
189
190 sprintf(buf, "/proc/self/fd/%d", fd);
191 r = open(buf, flags, mode);
192 if (r < 0) {
193 printf("open(%s) failed: %m\n", buf);
194 abort();
195 }
196
197 return r;
198}
199
200static void mfd_fail_open(int fd, int flags, mode_t mode)
201{
202 char buf[512];
203 int r;
204
205 sprintf(buf, "/proc/self/fd/%d", fd);
206 r = open(buf, flags, mode);
207 if (r >= 0) {
208 printf("open(%s) didn't fail as expected\n");
209 abort();
210 }
211}
212
213static void mfd_assert_read(int fd)
214{
215 char buf[16];
216 void *p;
217 ssize_t l;
218
219 l = read(fd, buf, sizeof(buf));
220 if (l != sizeof(buf)) {
221 printf("read() failed: %m\n");
222 abort();
223 }
224
225 /* verify PROT_READ *is* allowed */
226 p = mmap(NULL,
227 MFD_DEF_SIZE,
228 PROT_READ,
229 MAP_PRIVATE,
230 fd,
231 0);
232 if (p == MAP_FAILED) {
233 printf("mmap() failed: %m\n");
234 abort();
235 }
236 munmap(p, MFD_DEF_SIZE);
237
238 /* verify MAP_PRIVATE is *always* allowed (even writable) */
239 p = mmap(NULL,
240 MFD_DEF_SIZE,
241 PROT_READ | PROT_WRITE,
242 MAP_PRIVATE,
243 fd,
244 0);
245 if (p == MAP_FAILED) {
246 printf("mmap() failed: %m\n");
247 abort();
248 }
249 munmap(p, MFD_DEF_SIZE);
250}
251
252static void mfd_assert_write(int fd)
253{
254 ssize_t l;
255 void *p;
256 int r;
257
258 /* verify write() succeeds */
259 l = write(fd, "\0\0\0\0", 4);
260 if (l != 4) {
261 printf("write() failed: %m\n");
262 abort();
263 }
264
265 /* verify PROT_READ | PROT_WRITE is allowed */
266 p = mmap(NULL,
267 MFD_DEF_SIZE,
268 PROT_READ | PROT_WRITE,
269 MAP_SHARED,
270 fd,
271 0);
272 if (p == MAP_FAILED) {
273 printf("mmap() failed: %m\n");
274 abort();
275 }
276 *(char *)p = 0;
277 munmap(p, MFD_DEF_SIZE);
278
279 /* verify PROT_WRITE is allowed */
280 p = mmap(NULL,
281 MFD_DEF_SIZE,
282 PROT_WRITE,
283 MAP_SHARED,
284 fd,
285 0);
286 if (p == MAP_FAILED) {
287 printf("mmap() failed: %m\n");
288 abort();
289 }
290 *(char *)p = 0;
291 munmap(p, MFD_DEF_SIZE);
292
293 /* verify PROT_READ with MAP_SHARED is allowed and a following
294 * mprotect(PROT_WRITE) allows writing */
295 p = mmap(NULL,
296 MFD_DEF_SIZE,
297 PROT_READ,
298 MAP_SHARED,
299 fd,
300 0);
301 if (p == MAP_FAILED) {
302 printf("mmap() failed: %m\n");
303 abort();
304 }
305
306 r = mprotect(p, MFD_DEF_SIZE, PROT_READ | PROT_WRITE);
307 if (r < 0) {
308 printf("mprotect() failed: %m\n");
309 abort();
310 }
311
312 *(char *)p = 0;
313 munmap(p, MFD_DEF_SIZE);
314
315 /* verify PUNCH_HOLE works */
316 r = fallocate(fd,
317 FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
318 0,
319 MFD_DEF_SIZE);
320 if (r < 0) {
321 printf("fallocate(PUNCH_HOLE) failed: %m\n");
322 abort();
323 }
324}
325
326static void mfd_fail_write(int fd)
327{
328 ssize_t l;
329 void *p;
330 int r;
331
332 /* verify write() fails */
333 l = write(fd, "data", 4);
334 if (l != -EPERM) {
335 printf("expected EPERM on write(), but got %d: %m\n", (int)l);
336 abort();
337 }
338
339 /* verify PROT_READ | PROT_WRITE is not allowed */
340 p = mmap(NULL,
341 MFD_DEF_SIZE,
342 PROT_READ | PROT_WRITE,
343 MAP_SHARED,
344 fd,
345 0);
346 if (p != MAP_FAILED) {
347 printf("mmap() didn't fail as expected\n");
348 abort();
349 }
350
351 /* verify PROT_WRITE is not allowed */
352 p = mmap(NULL,
353 MFD_DEF_SIZE,
354 PROT_WRITE,
355 MAP_SHARED,
356 fd,
357 0);
358 if (p != MAP_FAILED) {
359 printf("mmap() didn't fail as expected\n");
360 abort();
361 }
362
363 /* Verify PROT_READ with MAP_SHARED with a following mprotect is not
364 * allowed. Note that for r/w the kernel already prevents the mmap. */
365 p = mmap(NULL,
366 MFD_DEF_SIZE,
367 PROT_READ,
368 MAP_SHARED,
369 fd,
370 0);
371 if (p != MAP_FAILED) {
372 r = mprotect(p, MFD_DEF_SIZE, PROT_READ | PROT_WRITE);
373 if (r >= 0) {
374 printf("mmap()+mprotect() didn't fail as expected\n");
375 abort();
376 }
377 }
378
379 /* verify PUNCH_HOLE fails */
380 r = fallocate(fd,
381 FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
382 0,
383 MFD_DEF_SIZE);
384 if (r >= 0) {
385 printf("fallocate(PUNCH_HOLE) didn't fail as expected\n");
386 abort();
387 }
388}
389
390static void mfd_assert_shrink(int fd)
391{
392 int r, fd2;
393
394 r = ftruncate(fd, MFD_DEF_SIZE / 2);
395 if (r < 0) {
396 printf("ftruncate(SHRINK) failed: %m\n");
397 abort();
398 }
399
400 mfd_assert_size(fd, MFD_DEF_SIZE / 2);
401
402 fd2 = mfd_assert_open(fd,
403 O_RDWR | O_CREAT | O_TRUNC,
404 S_IRUSR | S_IWUSR);
405 close(fd2);
406
407 mfd_assert_size(fd, 0);
408}
409
410static void mfd_fail_shrink(int fd)
411{
412 int r;
413
414 r = ftruncate(fd, MFD_DEF_SIZE / 2);
415 if (r >= 0) {
416 printf("ftruncate(SHRINK) didn't fail as expected\n");
417 abort();
418 }
419
420 mfd_fail_open(fd,
421 O_RDWR | O_CREAT | O_TRUNC,
422 S_IRUSR | S_IWUSR);
423}
424
425static void mfd_assert_grow(int fd)
426{
427 int r;
428
429 r = ftruncate(fd, MFD_DEF_SIZE * 2);
430 if (r < 0) {
431 printf("ftruncate(GROW) failed: %m\n");
432 abort();
433 }
434
435 mfd_assert_size(fd, MFD_DEF_SIZE * 2);
436
437 r = fallocate(fd,
438 0,
439 0,
440 MFD_DEF_SIZE * 4);
441 if (r < 0) {
442 printf("fallocate(ALLOC) failed: %m\n");
443 abort();
444 }
445
446 mfd_assert_size(fd, MFD_DEF_SIZE * 4);
447}
448
449static void mfd_fail_grow(int fd)
450{
451 int r;
452
453 r = ftruncate(fd, MFD_DEF_SIZE * 2);
454 if (r >= 0) {
455 printf("ftruncate(GROW) didn't fail as expected\n");
456 abort();
457 }
458
459 r = fallocate(fd,
460 0,
461 0,
462 MFD_DEF_SIZE * 4);
463 if (r >= 0) {
464 printf("fallocate(ALLOC) didn't fail as expected\n");
465 abort();
466 }
467}
468
469static void mfd_assert_grow_write(int fd)
470{
471 static char buf[MFD_DEF_SIZE * 8];
472 ssize_t l;
473
474 l = pwrite(fd, buf, sizeof(buf), 0);
475 if (l != sizeof(buf)) {
476 printf("pwrite() failed: %m\n");
477 abort();
478 }
479
480 mfd_assert_size(fd, MFD_DEF_SIZE * 8);
481}
482
483static void mfd_fail_grow_write(int fd)
484{
485 static char buf[MFD_DEF_SIZE * 8];
486 ssize_t l;
487
488 l = pwrite(fd, buf, sizeof(buf), 0);
489 if (l == sizeof(buf)) {
490 printf("pwrite() didn't fail as expected\n");
491 abort();
492 }
493}
494
495static int idle_thread_fn(void *arg)
496{
497 sigset_t set;
498 int sig;
499
500 /* dummy waiter; SIGTERM terminates us anyway */
501 sigemptyset(&set);
502 sigaddset(&set, SIGTERM);
503 sigwait(&set, &sig);
504
505 return 0;
506}
507
508static pid_t spawn_idle_thread(unsigned int flags)
509{
510 uint8_t *stack;
511 pid_t pid;
512
513 stack = malloc(STACK_SIZE);
514 if (!stack) {
515 printf("malloc(STACK_SIZE) failed: %m\n");
516 abort();
517 }
518
519 pid = clone(idle_thread_fn,
520 stack + STACK_SIZE,
521 SIGCHLD | flags,
522 NULL);
523 if (pid < 0) {
524 printf("clone() failed: %m\n");
525 abort();
526 }
527
528 return pid;
529}
530
531static void join_idle_thread(pid_t pid)
532{
533 kill(pid, SIGTERM);
534 waitpid(pid, NULL, 0);
535}
536
537/*
538 * Test memfd_create() syscall
539 * Verify syscall-argument validation, including name checks, flag validation
540 * and more.
541 */
542static void test_create(void)
543{
544 char buf[2048];
545 int fd;
546
547 /* test NULL name */
548 mfd_fail_new(NULL, 0);
549
550 /* test over-long name (not zero-terminated) */
551 memset(buf, 0xff, sizeof(buf));
552 mfd_fail_new(buf, 0);
553
554 /* test over-long zero-terminated name */
555 memset(buf, 0xff, sizeof(buf));
556 buf[sizeof(buf) - 1] = 0;
557 mfd_fail_new(buf, 0);
558
559 /* verify "" is a valid name */
560 fd = mfd_assert_new("", 0, 0);
561 close(fd);
562
563 /* verify invalid O_* open flags */
564 mfd_fail_new("", 0x0100);
565 mfd_fail_new("", ~MFD_CLOEXEC);
566 mfd_fail_new("", ~MFD_ALLOW_SEALING);
567 mfd_fail_new("", ~0);
568 mfd_fail_new("", 0x80000000U);
569
570 /* verify MFD_CLOEXEC is allowed */
571 fd = mfd_assert_new("", 0, MFD_CLOEXEC);
572 close(fd);
573
574 /* verify MFD_ALLOW_SEALING is allowed */
575 fd = mfd_assert_new("", 0, MFD_ALLOW_SEALING);
576 close(fd);
577
578 /* verify MFD_ALLOW_SEALING | MFD_CLOEXEC is allowed */
579 fd = mfd_assert_new("", 0, MFD_ALLOW_SEALING | MFD_CLOEXEC);
580 close(fd);
581}
582
583/*
584 * Test basic sealing
585 * A very basic sealing test to see whether setting/retrieving seals works.
586 */
587static void test_basic(void)
588{
589 int fd;
590
591 fd = mfd_assert_new("kern_memfd_basic",
592 MFD_DEF_SIZE,
593 MFD_CLOEXEC | MFD_ALLOW_SEALING);
594
595 /* add basic seals */
596 mfd_assert_has_seals(fd, 0);
597 mfd_assert_add_seals(fd, F_SEAL_SHRINK |
598 F_SEAL_WRITE);
599 mfd_assert_has_seals(fd, F_SEAL_SHRINK |
600 F_SEAL_WRITE);
601
602 /* add them again */
603 mfd_assert_add_seals(fd, F_SEAL_SHRINK |
604 F_SEAL_WRITE);
605 mfd_assert_has_seals(fd, F_SEAL_SHRINK |
606 F_SEAL_WRITE);
607
608 /* add more seals and seal against sealing */
609 mfd_assert_add_seals(fd, F_SEAL_GROW | F_SEAL_SEAL);
610 mfd_assert_has_seals(fd, F_SEAL_SHRINK |
611 F_SEAL_GROW |
612 F_SEAL_WRITE |
613 F_SEAL_SEAL);
614
615 /* verify that sealing no longer works */
616 mfd_fail_add_seals(fd, F_SEAL_GROW);
617 mfd_fail_add_seals(fd, 0);
618
619 close(fd);
620
621 /* verify sealing does not work without MFD_ALLOW_SEALING */
622 fd = mfd_assert_new("kern_memfd_basic",
623 MFD_DEF_SIZE,
624 MFD_CLOEXEC);
625 mfd_assert_has_seals(fd, F_SEAL_SEAL);
626 mfd_fail_add_seals(fd, F_SEAL_SHRINK |
627 F_SEAL_GROW |
628 F_SEAL_WRITE);
629 mfd_assert_has_seals(fd, F_SEAL_SEAL);
630 close(fd);
631}
632
633/*
634 * Test SEAL_WRITE
635 * Test whether SEAL_WRITE actually prevents modifications.
636 */
637static void test_seal_write(void)
638{
639 int fd;
640
641 fd = mfd_assert_new("kern_memfd_seal_write",
642 MFD_DEF_SIZE,
643 MFD_CLOEXEC | MFD_ALLOW_SEALING);
644 mfd_assert_has_seals(fd, 0);
645 mfd_assert_add_seals(fd, F_SEAL_WRITE);
646 mfd_assert_has_seals(fd, F_SEAL_WRITE);
647
648 mfd_assert_read(fd);
649 mfd_fail_write(fd);
650 mfd_assert_shrink(fd);
651 mfd_assert_grow(fd);
652 mfd_fail_grow_write(fd);
653
654 close(fd);
655}
656
657/*
658 * Test SEAL_SHRINK
659 * Test whether SEAL_SHRINK actually prevents shrinking
660 */
661static void test_seal_shrink(void)
662{
663 int fd;
664
665 fd = mfd_assert_new("kern_memfd_seal_shrink",
666 MFD_DEF_SIZE,
667 MFD_CLOEXEC | MFD_ALLOW_SEALING);
668 mfd_assert_has_seals(fd, 0);
669 mfd_assert_add_seals(fd, F_SEAL_SHRINK);
670 mfd_assert_has_seals(fd, F_SEAL_SHRINK);
671
672 mfd_assert_read(fd);
673 mfd_assert_write(fd);
674 mfd_fail_shrink(fd);
675 mfd_assert_grow(fd);
676 mfd_assert_grow_write(fd);
677
678 close(fd);
679}
680
681/*
682 * Test SEAL_GROW
683 * Test whether SEAL_GROW actually prevents growing
684 */
685static void test_seal_grow(void)
686{
687 int fd;
688
689 fd = mfd_assert_new("kern_memfd_seal_grow",
690 MFD_DEF_SIZE,
691 MFD_CLOEXEC | MFD_ALLOW_SEALING);
692 mfd_assert_has_seals(fd, 0);
693 mfd_assert_add_seals(fd, F_SEAL_GROW);
694 mfd_assert_has_seals(fd, F_SEAL_GROW);
695
696 mfd_assert_read(fd);
697 mfd_assert_write(fd);
698 mfd_assert_shrink(fd);
699 mfd_fail_grow(fd);
700 mfd_fail_grow_write(fd);
701
702 close(fd);
703}
704
705/*
706 * Test SEAL_SHRINK | SEAL_GROW
707 * Test whether SEAL_SHRINK | SEAL_GROW actually prevents resizing
708 */
709static void test_seal_resize(void)
710{
711 int fd;
712
713 fd = mfd_assert_new("kern_memfd_seal_resize",
714 MFD_DEF_SIZE,
715 MFD_CLOEXEC | MFD_ALLOW_SEALING);
716 mfd_assert_has_seals(fd, 0);
717 mfd_assert_add_seals(fd, F_SEAL_SHRINK | F_SEAL_GROW);
718 mfd_assert_has_seals(fd, F_SEAL_SHRINK | F_SEAL_GROW);
719
720 mfd_assert_read(fd);
721 mfd_assert_write(fd);
722 mfd_fail_shrink(fd);
723 mfd_fail_grow(fd);
724 mfd_fail_grow_write(fd);
725
726 close(fd);
727}
728
729/*
730 * Test sharing via dup()
731 * Test that seals are shared between dupped FDs and they're all equal.
732 */
733static void test_share_dup(void)
734{
735 int fd, fd2;
736
737 fd = mfd_assert_new("kern_memfd_share_dup",
738 MFD_DEF_SIZE,
739 MFD_CLOEXEC | MFD_ALLOW_SEALING);
740 mfd_assert_has_seals(fd, 0);
741
742 fd2 = mfd_assert_dup(fd);
743 mfd_assert_has_seals(fd2, 0);
744
745 mfd_assert_add_seals(fd, F_SEAL_WRITE);
746 mfd_assert_has_seals(fd, F_SEAL_WRITE);
747 mfd_assert_has_seals(fd2, F_SEAL_WRITE);
748
749 mfd_assert_add_seals(fd2, F_SEAL_SHRINK);
750 mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK);
751 mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK);
752
753 mfd_assert_add_seals(fd, F_SEAL_SEAL);
754 mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL);
755 mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL);
756
757 mfd_fail_add_seals(fd, F_SEAL_GROW);
758 mfd_fail_add_seals(fd2, F_SEAL_GROW);
759 mfd_fail_add_seals(fd, F_SEAL_SEAL);
760 mfd_fail_add_seals(fd2, F_SEAL_SEAL);
761
762 close(fd2);
763
764 mfd_fail_add_seals(fd, F_SEAL_GROW);
765 close(fd);
766}
767
768/*
769 * Test sealing with active mmap()s
770 * Modifying seals is only allowed if no other mmap() refs exist.
771 */
772static void test_share_mmap(void)
773{
774 int fd;
775 void *p;
776
777 fd = mfd_assert_new("kern_memfd_share_mmap",
778 MFD_DEF_SIZE,
779 MFD_CLOEXEC | MFD_ALLOW_SEALING);
780 mfd_assert_has_seals(fd, 0);
781
782 /* shared/writable ref prevents sealing WRITE, but allows others */
783 p = mfd_assert_mmap_shared(fd);
784 mfd_fail_add_seals(fd, F_SEAL_WRITE);
785 mfd_assert_has_seals(fd, 0);
786 mfd_assert_add_seals(fd, F_SEAL_SHRINK);
787 mfd_assert_has_seals(fd, F_SEAL_SHRINK);
788 munmap(p, MFD_DEF_SIZE);
789
790 /* readable ref allows sealing */
791 p = mfd_assert_mmap_private(fd);
792 mfd_assert_add_seals(fd, F_SEAL_WRITE);
793 mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK);
794 munmap(p, MFD_DEF_SIZE);
795
796 close(fd);
797}
798
799/*
800 * Test sealing with open(/proc/self/fd/%d)
801 * Via /proc we can get access to a separate file-context for the same memfd.
802 * This is *not* like dup(), but like a real separate open(). Make sure the
803 * semantics are as expected and we correctly check for RDONLY / WRONLY / RDWR.
804 */
805static void test_share_open(void)
806{
807 int fd, fd2;
808
809 fd = mfd_assert_new("kern_memfd_share_open",
810 MFD_DEF_SIZE,
811 MFD_CLOEXEC | MFD_ALLOW_SEALING);
812 mfd_assert_has_seals(fd, 0);
813
814 fd2 = mfd_assert_open(fd, O_RDWR, 0);
815 mfd_assert_add_seals(fd, F_SEAL_WRITE);
816 mfd_assert_has_seals(fd, F_SEAL_WRITE);
817 mfd_assert_has_seals(fd2, F_SEAL_WRITE);
818
819 mfd_assert_add_seals(fd2, F_SEAL_SHRINK);
820 mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK);
821 mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK);
822
823 close(fd);
824 fd = mfd_assert_open(fd2, O_RDONLY, 0);
825
826 mfd_fail_add_seals(fd, F_SEAL_SEAL);
827 mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK);
828 mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK);
829
830 close(fd2);
831 fd2 = mfd_assert_open(fd, O_RDWR, 0);
832
833 mfd_assert_add_seals(fd2, F_SEAL_SEAL);
834 mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL);
835 mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL);
836
837 close(fd2);
838 close(fd);
839}
840
841/*
842 * Test sharing via fork()
843 * Test whether seal-modifications work as expected with forked childs.
844 */
845static void test_share_fork(void)
846{
847 int fd;
848 pid_t pid;
849
850 fd = mfd_assert_new("kern_memfd_share_fork",
851 MFD_DEF_SIZE,
852 MFD_CLOEXEC | MFD_ALLOW_SEALING);
853 mfd_assert_has_seals(fd, 0);
854
855 pid = spawn_idle_thread(0);
856 mfd_assert_add_seals(fd, F_SEAL_SEAL);
857 mfd_assert_has_seals(fd, F_SEAL_SEAL);
858
859 mfd_fail_add_seals(fd, F_SEAL_WRITE);
860 mfd_assert_has_seals(fd, F_SEAL_SEAL);
861
862 join_idle_thread(pid);
863
864 mfd_fail_add_seals(fd, F_SEAL_WRITE);
865 mfd_assert_has_seals(fd, F_SEAL_SEAL);
866
867 close(fd);
868}
869
870int main(int argc, char **argv)
871{
872 pid_t pid;
873
874 printf("memfd: CREATE\n");
875 test_create();
876 printf("memfd: BASIC\n");
877 test_basic();
878
879 printf("memfd: SEAL-WRITE\n");
880 test_seal_write();
881 printf("memfd: SEAL-SHRINK\n");
882 test_seal_shrink();
883 printf("memfd: SEAL-GROW\n");
884 test_seal_grow();
885 printf("memfd: SEAL-RESIZE\n");
886 test_seal_resize();
887
888 printf("memfd: SHARE-DUP\n");
889 test_share_dup();
890 printf("memfd: SHARE-MMAP\n");
891 test_share_mmap();
892 printf("memfd: SHARE-OPEN\n");
893 test_share_open();
894 printf("memfd: SHARE-FORK\n");
895 test_share_fork();
896
897 /* Run test-suite in a multi-threaded environment with a shared
898 * file-table. */
899 pid = spawn_idle_thread(CLONE_FILES | CLONE_FS | CLONE_VM);
900 printf("memfd: SHARE-DUP (shared file-table)\n");
901 test_share_dup();
902 printf("memfd: SHARE-MMAP (shared file-table)\n");
903 test_share_mmap();
904 printf("memfd: SHARE-OPEN (shared file-table)\n");
905 test_share_open();
906 printf("memfd: SHARE-FORK (shared file-table)\n");
907 test_share_fork();
908 join_idle_thread(pid);
909
910 printf("memfd: DONE\n");
911
912 return 0;
913}
diff --git a/tools/testing/selftests/memfd/run_fuse_test.sh b/tools/testing/selftests/memfd/run_fuse_test.sh
new file mode 100644
index 000000000000..69b930e1e041
--- /dev/null
+++ b/tools/testing/selftests/memfd/run_fuse_test.sh
@@ -0,0 +1,14 @@
1#!/bin/sh
2
3if test -d "./mnt" ; then
4 fusermount -u ./mnt
5 rmdir ./mnt
6fi
7
8set -e
9
10mkdir mnt
11./fuse_mnt ./mnt
12./fuse_test ./mnt/memfd
13fusermount -u ./mnt
14rmdir ./mnt
diff --git a/tools/testing/selftests/memory-hotplug/Makefile b/tools/testing/selftests/memory-hotplug/Makefile
index 058c76f5d102..d46b8d489cd2 100644
--- a/tools/testing/selftests/memory-hotplug/Makefile
+++ b/tools/testing/selftests/memory-hotplug/Makefile
@@ -1,6 +1,9 @@
1all: 1all:
2 2
3run_tests: 3run_tests:
4 @/bin/bash ./on-off-test.sh -r 2 || echo "memory-hotplug selftests: [FAIL]"
5
6run_full_test:
4 @/bin/bash ./on-off-test.sh || echo "memory-hotplug selftests: [FAIL]" 7 @/bin/bash ./on-off-test.sh || echo "memory-hotplug selftests: [FAIL]"
5 8
6clean: 9clean:
diff --git a/tools/testing/selftests/memory-hotplug/on-off-test.sh b/tools/testing/selftests/memory-hotplug/on-off-test.sh
index a2816f631542..6cddde0b96f8 100644
--- a/tools/testing/selftests/memory-hotplug/on-off-test.sh
+++ b/tools/testing/selftests/memory-hotplug/on-off-test.sh
@@ -142,10 +142,16 @@ fi
142 142
143prerequisite 143prerequisite
144 144
145echo "Test scope: $ratio% hotplug memory"
146echo -e "\t online all hotplug memory in offline state"
147echo -e "\t offline $ratio% hotplug memory in online state"
148echo -e "\t online all hotplug memory in offline state"
149
145# 150#
146# Online all hot-pluggable memory 151# Online all hot-pluggable memory
147# 152#
148for memory in `hotplaggable_offline_memory`; do 153for memory in `hotplaggable_offline_memory`; do
154 echo offline-online $memory
149 online_memory_expect_success $memory 155 online_memory_expect_success $memory
150done 156done
151 157
@@ -154,6 +160,7 @@ done
154# 160#
155for memory in `hotpluggable_online_memory`; do 161for memory in `hotpluggable_online_memory`; do
156 if [ $((RANDOM % 100)) -lt $ratio ]; then 162 if [ $((RANDOM % 100)) -lt $ratio ]; then
163 echo online-offline $memory
157 offline_memory_expect_success $memory 164 offline_memory_expect_success $memory
158 fi 165 fi
159done 166done
@@ -162,6 +169,7 @@ done
162# Online all hot-pluggable memory again 169# Online all hot-pluggable memory again
163# 170#
164for memory in `hotplaggable_offline_memory`; do 171for memory in `hotplaggable_offline_memory`; do
172 echo offline-online $memory
165 online_memory_expect_success $memory 173 online_memory_expect_success $memory
166done 174done
167 175
diff --git a/tools/testing/selftests/mount/Makefile b/tools/testing/selftests/mount/Makefile
new file mode 100644
index 000000000000..337d853c2b72
--- /dev/null
+++ b/tools/testing/selftests/mount/Makefile
@@ -0,0 +1,17 @@
1# Makefile for mount selftests.
2
3all: unprivileged-remount-test
4
5unprivileged-remount-test: unprivileged-remount-test.c
6 gcc -Wall -O2 unprivileged-remount-test.c -o unprivileged-remount-test
7
8# Allow specific tests to be selected.
9test_unprivileged_remount: unprivileged-remount-test
10 @if [ -f /proc/self/uid_map ] ; then ./unprivileged-remount-test ; fi
11
12run_tests: all test_unprivileged_remount
13
14clean:
15 rm -f unprivileged-remount-test
16
17.PHONY: all test_unprivileged_remount
diff --git a/tools/testing/selftests/mount/unprivileged-remount-test.c b/tools/testing/selftests/mount/unprivileged-remount-test.c
new file mode 100644
index 000000000000..1b3ff2fda4d0
--- /dev/null
+++ b/tools/testing/selftests/mount/unprivileged-remount-test.c
@@ -0,0 +1,242 @@
1#define _GNU_SOURCE
2#include <sched.h>
3#include <stdio.h>
4#include <errno.h>
5#include <string.h>
6#include <sys/types.h>
7#include <sys/mount.h>
8#include <sys/wait.h>
9#include <stdlib.h>
10#include <unistd.h>
11#include <fcntl.h>
12#include <grp.h>
13#include <stdbool.h>
14#include <stdarg.h>
15
16#ifndef CLONE_NEWNS
17# define CLONE_NEWNS 0x00020000
18#endif
19#ifndef CLONE_NEWUTS
20# define CLONE_NEWUTS 0x04000000
21#endif
22#ifndef CLONE_NEWIPC
23# define CLONE_NEWIPC 0x08000000
24#endif
25#ifndef CLONE_NEWNET
26# define CLONE_NEWNET 0x40000000
27#endif
28#ifndef CLONE_NEWUSER
29# define CLONE_NEWUSER 0x10000000
30#endif
31#ifndef CLONE_NEWPID
32# define CLONE_NEWPID 0x20000000
33#endif
34
35#ifndef MS_RELATIME
36#define MS_RELATIME (1 << 21)
37#endif
38#ifndef MS_STRICTATIME
39#define MS_STRICTATIME (1 << 24)
40#endif
41
42static void die(char *fmt, ...)
43{
44 va_list ap;
45 va_start(ap, fmt);
46 vfprintf(stderr, fmt, ap);
47 va_end(ap);
48 exit(EXIT_FAILURE);
49}
50
51static void write_file(char *filename, char *fmt, ...)
52{
53 char buf[4096];
54 int fd;
55 ssize_t written;
56 int buf_len;
57 va_list ap;
58
59 va_start(ap, fmt);
60 buf_len = vsnprintf(buf, sizeof(buf), fmt, ap);
61 va_end(ap);
62 if (buf_len < 0) {
63 die("vsnprintf failed: %s\n",
64 strerror(errno));
65 }
66 if (buf_len >= sizeof(buf)) {
67 die("vsnprintf output truncated\n");
68 }
69
70 fd = open(filename, O_WRONLY);
71 if (fd < 0) {
72 die("open of %s failed: %s\n",
73 filename, strerror(errno));
74 }
75 written = write(fd, buf, buf_len);
76 if (written != buf_len) {
77 if (written >= 0) {
78 die("short write to %s\n", filename);
79 } else {
80 die("write to %s failed: %s\n",
81 filename, strerror(errno));
82 }
83 }
84 if (close(fd) != 0) {
85 die("close of %s failed: %s\n",
86 filename, strerror(errno));
87 }
88}
89
90static void create_and_enter_userns(void)
91{
92 uid_t uid;
93 gid_t gid;
94
95 uid = getuid();
96 gid = getgid();
97
98 if (unshare(CLONE_NEWUSER) !=0) {
99 die("unshare(CLONE_NEWUSER) failed: %s\n",
100 strerror(errno));
101 }
102
103 write_file("/proc/self/uid_map", "0 %d 1", uid);
104 write_file("/proc/self/gid_map", "0 %d 1", gid);
105
106 if (setgroups(0, NULL) != 0) {
107 die("setgroups failed: %s\n",
108 strerror(errno));
109 }
110 if (setgid(0) != 0) {
111 die ("setgid(0) failed %s\n",
112 strerror(errno));
113 }
114 if (setuid(0) != 0) {
115 die("setuid(0) failed %s\n",
116 strerror(errno));
117 }
118}
119
120static
121bool test_unpriv_remount(int mount_flags, int remount_flags, int invalid_flags)
122{
123 pid_t child;
124
125 child = fork();
126 if (child == -1) {
127 die("fork failed: %s\n",
128 strerror(errno));
129 }
130 if (child != 0) { /* parent */
131 pid_t pid;
132 int status;
133 pid = waitpid(child, &status, 0);
134 if (pid == -1) {
135 die("waitpid failed: %s\n",
136 strerror(errno));
137 }
138 if (pid != child) {
139 die("waited for %d got %d\n",
140 child, pid);
141 }
142 if (!WIFEXITED(status)) {
143 die("child did not terminate cleanly\n");
144 }
145 return WEXITSTATUS(status) == EXIT_SUCCESS ? true : false;
146 }
147
148 create_and_enter_userns();
149 if (unshare(CLONE_NEWNS) != 0) {
150 die("unshare(CLONE_NEWNS) failed: %s\n",
151 strerror(errno));
152 }
153
154 if (mount("testing", "/tmp", "ramfs", mount_flags, NULL) != 0) {
155 die("mount of /tmp failed: %s\n",
156 strerror(errno));
157 }
158
159 create_and_enter_userns();
160
161 if (unshare(CLONE_NEWNS) != 0) {
162 die("unshare(CLONE_NEWNS) failed: %s\n",
163 strerror(errno));
164 }
165
166 if (mount("/tmp", "/tmp", "none",
167 MS_REMOUNT | MS_BIND | remount_flags, NULL) != 0) {
168 /* system("cat /proc/self/mounts"); */
169 die("remount of /tmp failed: %s\n",
170 strerror(errno));
171 }
172
173 if (mount("/tmp", "/tmp", "none",
174 MS_REMOUNT | MS_BIND | invalid_flags, NULL) == 0) {
175 /* system("cat /proc/self/mounts"); */
176 die("remount of /tmp with invalid flags "
177 "succeeded unexpectedly\n");
178 }
179 exit(EXIT_SUCCESS);
180}
181
182static bool test_unpriv_remount_simple(int mount_flags)
183{
184 return test_unpriv_remount(mount_flags, mount_flags, 0);
185}
186
187static bool test_unpriv_remount_atime(int mount_flags, int invalid_flags)
188{
189 return test_unpriv_remount(mount_flags, mount_flags, invalid_flags);
190}
191
192int main(int argc, char **argv)
193{
194 if (!test_unpriv_remount_simple(MS_RDONLY|MS_NODEV)) {
195 die("MS_RDONLY malfunctions\n");
196 }
197 if (!test_unpriv_remount_simple(MS_NODEV)) {
198 die("MS_NODEV malfunctions\n");
199 }
200 if (!test_unpriv_remount_simple(MS_NOSUID|MS_NODEV)) {
201 die("MS_NOSUID malfunctions\n");
202 }
203 if (!test_unpriv_remount_simple(MS_NOEXEC|MS_NODEV)) {
204 die("MS_NOEXEC malfunctions\n");
205 }
206 if (!test_unpriv_remount_atime(MS_RELATIME|MS_NODEV,
207 MS_NOATIME|MS_NODEV))
208 {
209 die("MS_RELATIME malfunctions\n");
210 }
211 if (!test_unpriv_remount_atime(MS_STRICTATIME|MS_NODEV,
212 MS_NOATIME|MS_NODEV))
213 {
214 die("MS_STRICTATIME malfunctions\n");
215 }
216 if (!test_unpriv_remount_atime(MS_NOATIME|MS_NODEV,
217 MS_STRICTATIME|MS_NODEV))
218 {
219 die("MS_RELATIME malfunctions\n");
220 }
221 if (!test_unpriv_remount_atime(MS_RELATIME|MS_NODIRATIME|MS_NODEV,
222 MS_NOATIME|MS_NODEV))
223 {
224 die("MS_RELATIME malfunctions\n");
225 }
226 if (!test_unpriv_remount_atime(MS_STRICTATIME|MS_NODIRATIME|MS_NODEV,
227 MS_NOATIME|MS_NODEV))
228 {
229 die("MS_RELATIME malfunctions\n");
230 }
231 if (!test_unpriv_remount_atime(MS_NOATIME|MS_NODIRATIME|MS_NODEV,
232 MS_STRICTATIME|MS_NODEV))
233 {
234 die("MS_RELATIME malfunctions\n");
235 }
236 if (!test_unpriv_remount(MS_STRICTATIME|MS_NODEV, MS_NODEV,
237 MS_NOATIME|MS_NODEV))
238 {
239 die("Default atime malfunctions\n");
240 }
241 return EXIT_SUCCESS;
242}
diff --git a/tools/testing/selftests/mqueue/Makefile b/tools/testing/selftests/mqueue/Makefile
index 218a122c7951..8056e2e68fa4 100644
--- a/tools/testing/selftests/mqueue/Makefile
+++ b/tools/testing/selftests/mqueue/Makefile
@@ -1,6 +1,6 @@
1all: 1all:
2 gcc -O2 -lrt mq_open_tests.c -o mq_open_tests 2 gcc -O2 mq_open_tests.c -o mq_open_tests -lrt
3 gcc -O2 -lrt -lpthread -lpopt -o mq_perf_tests mq_perf_tests.c 3 gcc -O2 -o mq_perf_tests mq_perf_tests.c -lrt -lpthread -lpopt
4 4
5run_tests: 5run_tests:
6 @./mq_open_tests /test1 || echo "mq_open_tests: [FAIL]" 6 @./mq_open_tests /test1 || echo "mq_open_tests: [FAIL]"
diff --git a/tools/testing/selftests/mqueue/mq_open_tests.c b/tools/testing/selftests/mqueue/mq_open_tests.c
index 711cc2923047..9c1a5d359055 100644
--- a/tools/testing/selftests/mqueue/mq_open_tests.c
+++ b/tools/testing/selftests/mqueue/mq_open_tests.c
@@ -80,7 +80,8 @@ void shutdown(int exit_val, char *err_cause, int line_no)
80 if (in_shutdown++) 80 if (in_shutdown++)
81 return; 81 return;
82 82
83 seteuid(0); 83 if (seteuid(0) == -1)
84 perror("seteuid() failed");
84 85
85 if (queue != -1) 86 if (queue != -1)
86 if (mq_close(queue)) 87 if (mq_close(queue))
@@ -292,8 +293,10 @@ int main(int argc, char *argv[])
292 /* Tell the user our initial state */ 293 /* Tell the user our initial state */
293 printf("\nInitial system state:\n"); 294 printf("\nInitial system state:\n");
294 printf("\tUsing queue path:\t\t%s\n", queue_path); 295 printf("\tUsing queue path:\t\t%s\n", queue_path);
295 printf("\tRLIMIT_MSGQUEUE(soft):\t\t%d\n", saved_limits.rlim_cur); 296 printf("\tRLIMIT_MSGQUEUE(soft):\t\t%ld\n",
296 printf("\tRLIMIT_MSGQUEUE(hard):\t\t%d\n", saved_limits.rlim_max); 297 (long) saved_limits.rlim_cur);
298 printf("\tRLIMIT_MSGQUEUE(hard):\t\t%ld\n",
299 (long) saved_limits.rlim_max);
297 printf("\tMaximum Message Size:\t\t%d\n", saved_max_msgsize); 300 printf("\tMaximum Message Size:\t\t%d\n", saved_max_msgsize);
298 printf("\tMaximum Queue Size:\t\t%d\n", saved_max_msgs); 301 printf("\tMaximum Queue Size:\t\t%d\n", saved_max_msgs);
299 if (default_settings) { 302 if (default_settings) {
@@ -308,8 +311,8 @@ int main(int argc, char *argv[])
308 validate_current_settings(); 311 validate_current_settings();
309 312
310 printf("Adjusted system state for testing:\n"); 313 printf("Adjusted system state for testing:\n");
311 printf("\tRLIMIT_MSGQUEUE(soft):\t\t%d\n", cur_limits.rlim_cur); 314 printf("\tRLIMIT_MSGQUEUE(soft):\t\t%ld\n", (long) cur_limits.rlim_cur);
312 printf("\tRLIMIT_MSGQUEUE(hard):\t\t%d\n", cur_limits.rlim_max); 315 printf("\tRLIMIT_MSGQUEUE(hard):\t\t%ld\n", (long) cur_limits.rlim_max);
313 printf("\tMaximum Message Size:\t\t%d\n", cur_max_msgsize); 316 printf("\tMaximum Message Size:\t\t%d\n", cur_max_msgsize);
314 printf("\tMaximum Queue Size:\t\t%d\n", cur_max_msgs); 317 printf("\tMaximum Queue Size:\t\t%d\n", cur_max_msgs);
315 if (default_settings) { 318 if (default_settings) {
@@ -454,7 +457,12 @@ int main(int argc, char *argv[])
454 else 457 else
455 printf("Queue open with total size > 2GB when euid = 0 " 458 printf("Queue open with total size > 2GB when euid = 0 "
456 "failed:\t\t\tPASS\n"); 459 "failed:\t\t\tPASS\n");
457 seteuid(99); 460
461 if (seteuid(99) == -1) {
462 perror("seteuid() failed");
463 exit(1);
464 }
465
458 attr.mq_maxmsg = cur_max_msgs; 466 attr.mq_maxmsg = cur_max_msgs;
459 attr.mq_msgsize = cur_max_msgsize; 467 attr.mq_msgsize = cur_max_msgsize;
460 if (test_queue_fail(&attr, &result)) 468 if (test_queue_fail(&attr, &result))
diff --git a/tools/testing/selftests/mqueue/mq_perf_tests.c b/tools/testing/selftests/mqueue/mq_perf_tests.c
index 2fadd4b97045..94dae65eea41 100644
--- a/tools/testing/selftests/mqueue/mq_perf_tests.c
+++ b/tools/testing/selftests/mqueue/mq_perf_tests.c
@@ -296,9 +296,9 @@ static inline void open_queue(struct mq_attr *attr)
296 printf("\n\tQueue %s created:\n", queue_path); 296 printf("\n\tQueue %s created:\n", queue_path);
297 printf("\t\tmq_flags:\t\t\t%s\n", result.mq_flags & O_NONBLOCK ? 297 printf("\t\tmq_flags:\t\t\t%s\n", result.mq_flags & O_NONBLOCK ?
298 "O_NONBLOCK" : "(null)"); 298 "O_NONBLOCK" : "(null)");
299 printf("\t\tmq_maxmsg:\t\t\t%d\n", result.mq_maxmsg); 299 printf("\t\tmq_maxmsg:\t\t\t%lu\n", result.mq_maxmsg);
300 printf("\t\tmq_msgsize:\t\t\t%d\n", result.mq_msgsize); 300 printf("\t\tmq_msgsize:\t\t\t%lu\n", result.mq_msgsize);
301 printf("\t\tmq_curmsgs:\t\t\t%d\n", result.mq_curmsgs); 301 printf("\t\tmq_curmsgs:\t\t\t%lu\n", result.mq_curmsgs);
302} 302}
303 303
304void *fake_cont_thread(void *arg) 304void *fake_cont_thread(void *arg)
@@ -440,7 +440,7 @@ void *perf_test_thread(void *arg)
440 shutdown(2, "clock_getres()", __LINE__); 440 shutdown(2, "clock_getres()", __LINE__);
441 441
442 printf("\t\tMax priorities:\t\t\t%d\n", mq_prio_max); 442 printf("\t\tMax priorities:\t\t\t%d\n", mq_prio_max);
443 printf("\t\tClock resolution:\t\t%d nsec%s\n", res.tv_nsec, 443 printf("\t\tClock resolution:\t\t%lu nsec%s\n", res.tv_nsec,
444 res.tv_nsec > 1 ? "s" : ""); 444 res.tv_nsec > 1 ? "s" : "");
445 445
446 446
@@ -454,20 +454,20 @@ void *perf_test_thread(void *arg)
454 recv_total.tv_nsec = 0; 454 recv_total.tv_nsec = 0;
455 for (i = 0; i < TEST1_LOOPS; i++) 455 for (i = 0; i < TEST1_LOOPS; i++)
456 do_send_recv(); 456 do_send_recv();
457 printf("\t\tSend msg:\t\t\t%d.%ds total time\n", 457 printf("\t\tSend msg:\t\t\t%ld.%lus total time\n",
458 send_total.tv_sec, send_total.tv_nsec); 458 send_total.tv_sec, send_total.tv_nsec);
459 nsec = ((unsigned long long)send_total.tv_sec * 1000000000 + 459 nsec = ((unsigned long long)send_total.tv_sec * 1000000000 +
460 send_total.tv_nsec) / TEST1_LOOPS; 460 send_total.tv_nsec) / TEST1_LOOPS;
461 printf("\t\t\t\t\t\t%d nsec/msg\n", nsec); 461 printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec);
462 printf("\t\tRecv msg:\t\t\t%d.%ds total time\n", 462 printf("\t\tRecv msg:\t\t\t%ld.%lus total time\n",
463 recv_total.tv_sec, recv_total.tv_nsec); 463 recv_total.tv_sec, recv_total.tv_nsec);
464 nsec = ((unsigned long long)recv_total.tv_sec * 1000000000 + 464 nsec = ((unsigned long long)recv_total.tv_sec * 1000000000 +
465 recv_total.tv_nsec) / TEST1_LOOPS; 465 recv_total.tv_nsec) / TEST1_LOOPS;
466 printf("\t\t\t\t\t\t%d nsec/msg\n", nsec); 466 printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec);
467 467
468 468
469 for (cur_test = test2; cur_test->desc != NULL; cur_test++) { 469 for (cur_test = test2; cur_test->desc != NULL; cur_test++) {
470 printf(cur_test->desc); 470 printf("%s:\n", cur_test->desc);
471 printf("\t\t(%d iterations)\n", TEST2_LOOPS); 471 printf("\t\t(%d iterations)\n", TEST2_LOOPS);
472 prio_out = 0; 472 prio_out = 0;
473 send_total.tv_sec = 0; 473 send_total.tv_sec = 0;
@@ -493,16 +493,16 @@ void *perf_test_thread(void *arg)
493 cur_test->func(&prio_out); 493 cur_test->func(&prio_out);
494 } 494 }
495 printf("done.\n"); 495 printf("done.\n");
496 printf("\t\tSend msg:\t\t\t%d.%ds total time\n", 496 printf("\t\tSend msg:\t\t\t%ld.%lus total time\n",
497 send_total.tv_sec, send_total.tv_nsec); 497 send_total.tv_sec, send_total.tv_nsec);
498 nsec = ((unsigned long long)send_total.tv_sec * 1000000000 + 498 nsec = ((unsigned long long)send_total.tv_sec * 1000000000 +
499 send_total.tv_nsec) / TEST2_LOOPS; 499 send_total.tv_nsec) / TEST2_LOOPS;
500 printf("\t\t\t\t\t\t%d nsec/msg\n", nsec); 500 printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec);
501 printf("\t\tRecv msg:\t\t\t%d.%ds total time\n", 501 printf("\t\tRecv msg:\t\t\t%ld.%lus total time\n",
502 recv_total.tv_sec, recv_total.tv_nsec); 502 recv_total.tv_sec, recv_total.tv_nsec);
503 nsec = ((unsigned long long)recv_total.tv_sec * 1000000000 + 503 nsec = ((unsigned long long)recv_total.tv_sec * 1000000000 +
504 recv_total.tv_nsec) / TEST2_LOOPS; 504 recv_total.tv_nsec) / TEST2_LOOPS;
505 printf("\t\t\t\t\t\t%d nsec/msg\n", nsec); 505 printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec);
506 printf("\t\tDraining queue..."); 506 printf("\t\tDraining queue...");
507 fflush(stdout); 507 fflush(stdout);
508 clock_gettime(clock, &start); 508 clock_gettime(clock, &start);
@@ -653,8 +653,10 @@ int main(int argc, char *argv[])
653 /* Tell the user our initial state */ 653 /* Tell the user our initial state */
654 printf("\nInitial system state:\n"); 654 printf("\nInitial system state:\n");
655 printf("\tUsing queue path:\t\t\t%s\n", queue_path); 655 printf("\tUsing queue path:\t\t\t%s\n", queue_path);
656 printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t%d\n", saved_limits.rlim_cur); 656 printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t%ld\n",
657 printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%d\n", saved_limits.rlim_max); 657 (long) saved_limits.rlim_cur);
658 printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%ld\n",
659 (long) saved_limits.rlim_max);
658 printf("\tMaximum Message Size:\t\t\t%d\n", saved_max_msgsize); 660 printf("\tMaximum Message Size:\t\t\t%d\n", saved_max_msgsize);
659 printf("\tMaximum Queue Size:\t\t\t%d\n", saved_max_msgs); 661 printf("\tMaximum Queue Size:\t\t\t%d\n", saved_max_msgs);
660 printf("\tNice value:\t\t\t\t%d\n", cur_nice); 662 printf("\tNice value:\t\t\t\t%d\n", cur_nice);
@@ -667,10 +669,10 @@ int main(int argc, char *argv[])
667 printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t(unlimited)\n"); 669 printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t(unlimited)\n");
668 printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t(unlimited)\n"); 670 printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t(unlimited)\n");
669 } else { 671 } else {
670 printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t%d\n", 672 printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t%ld\n",
671 cur_limits.rlim_cur); 673 (long) cur_limits.rlim_cur);
672 printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%d\n", 674 printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%ld\n",
673 cur_limits.rlim_max); 675 (long) cur_limits.rlim_max);
674 } 676 }
675 printf("\tMaximum Message Size:\t\t\t%d\n", cur_max_msgsize); 677 printf("\tMaximum Message Size:\t\t\t%d\n", cur_max_msgsize);
676 printf("\tMaximum Queue Size:\t\t\t%d\n", cur_max_msgs); 678 printf("\tMaximum Queue Size:\t\t\t%d\n", cur_max_msgs);
diff --git a/tools/testing/selftests/powerpc/Makefile b/tools/testing/selftests/powerpc/Makefile
index 54833a791a44..74a78cedce37 100644
--- a/tools/testing/selftests/powerpc/Makefile
+++ b/tools/testing/selftests/powerpc/Makefile
@@ -17,10 +17,10 @@ TARGETS = pmu copyloops mm tm
17 17
18endif 18endif
19 19
20all: 20all: $(TARGETS)
21 @for TARGET in $(TARGETS); do \ 21
22 $(MAKE) -C $$TARGET all; \ 22$(TARGETS):
23 done; 23 $(MAKE) -k -C $@ all
24 24
25run_tests: all 25run_tests: all
26 @for TARGET in $(TARGETS); do \ 26 @for TARGET in $(TARGETS); do \
@@ -36,4 +36,4 @@ clean:
36tags: 36tags:
37 find . -name '*.c' -o -name '*.h' | xargs ctags 37 find . -name '*.c' -o -name '*.h' | xargs ctags
38 38
39.PHONY: all run_tests clean tags 39.PHONY: all run_tests clean tags $(TARGETS)
diff --git a/tools/testing/selftests/powerpc/pmu/Makefile b/tools/testing/selftests/powerpc/pmu/Makefile
index b9ff0db42c79..c9f4263906a5 100644
--- a/tools/testing/selftests/powerpc/pmu/Makefile
+++ b/tools/testing/selftests/powerpc/pmu/Makefile
@@ -1,10 +1,12 @@
1noarg: 1noarg:
2 $(MAKE) -C ../ 2 $(MAKE) -C ../
3 3
4PROGS := count_instructions 4PROGS := count_instructions l3_bank_test per_event_excludes
5EXTRA_SOURCES := ../harness.c event.c 5EXTRA_SOURCES := ../harness.c event.c lib.c
6 6
7all: $(PROGS) sub_all 7SUB_TARGETS = ebb
8
9all: $(PROGS) $(SUB_TARGETS)
8 10
9$(PROGS): $(EXTRA_SOURCES) 11$(PROGS): $(EXTRA_SOURCES)
10 12
@@ -20,13 +22,8 @@ run_tests: all sub_run_tests
20clean: sub_clean 22clean: sub_clean
21 rm -f $(PROGS) loop.o 23 rm -f $(PROGS) loop.o
22 24
23 25$(SUB_TARGETS):
24SUB_TARGETS = ebb 26 $(MAKE) -k -C $@ all
25
26sub_all:
27 @for TARGET in $(SUB_TARGETS); do \
28 $(MAKE) -C $$TARGET all; \
29 done;
30 27
31sub_run_tests: all 28sub_run_tests: all
32 @for TARGET in $(SUB_TARGETS); do \ 29 @for TARGET in $(SUB_TARGETS); do \
@@ -38,4 +35,4 @@ sub_clean:
38 $(MAKE) -C $$TARGET clean; \ 35 $(MAKE) -C $$TARGET clean; \
39 done; 36 done;
40 37
41.PHONY: all run_tests clean sub_all sub_run_tests sub_clean 38.PHONY: all run_tests clean sub_run_tests sub_clean $(SUB_TARGETS)
diff --git a/tools/testing/selftests/powerpc/pmu/count_instructions.c b/tools/testing/selftests/powerpc/pmu/count_instructions.c
index 312b4f0fd27c..4622117b24c0 100644
--- a/tools/testing/selftests/powerpc/pmu/count_instructions.c
+++ b/tools/testing/selftests/powerpc/pmu/count_instructions.c
@@ -12,6 +12,7 @@
12 12
13#include "event.h" 13#include "event.h"
14#include "utils.h" 14#include "utils.h"
15#include "lib.h"
15 16
16extern void thirty_two_instruction_loop(u64 loops); 17extern void thirty_two_instruction_loop(u64 loops);
17 18
@@ -90,7 +91,7 @@ static u64 determine_overhead(struct event *events)
90 return overhead; 91 return overhead;
91} 92}
92 93
93static int count_instructions(void) 94static int test_body(void)
94{ 95{
95 struct event events[2]; 96 struct event events[2];
96 u64 overhead; 97 u64 overhead;
@@ -111,17 +112,23 @@ static int count_instructions(void)
111 overhead = determine_overhead(events); 112 overhead = determine_overhead(events);
112 printf("Overhead of null loop: %llu instructions\n", overhead); 113 printf("Overhead of null loop: %llu instructions\n", overhead);
113 114
114 /* Run for 1M instructions */ 115 /* Run for 1Mi instructions */
115 FAIL_IF(do_count_loop(events, 0x100000, overhead, true)); 116 FAIL_IF(do_count_loop(events, 1000000, overhead, true));
117
118 /* Run for 10Mi instructions */
119 FAIL_IF(do_count_loop(events, 10000000, overhead, true));
120
121 /* Run for 100Mi instructions */
122 FAIL_IF(do_count_loop(events, 100000000, overhead, true));
116 123
117 /* Run for 10M instructions */ 124 /* Run for 1Bi instructions */
118 FAIL_IF(do_count_loop(events, 0xa00000, overhead, true)); 125 FAIL_IF(do_count_loop(events, 1000000000, overhead, true));
119 126
120 /* Run for 100M instructions */ 127 /* Run for 16Bi instructions */
121 FAIL_IF(do_count_loop(events, 0x6400000, overhead, true)); 128 FAIL_IF(do_count_loop(events, 16000000000, overhead, true));
122 129
123 /* Run for 1G instructions */ 130 /* Run for 64Bi instructions */
124 FAIL_IF(do_count_loop(events, 0x40000000, overhead, true)); 131 FAIL_IF(do_count_loop(events, 64000000000, overhead, true));
125 132
126 event_close(&events[0]); 133 event_close(&events[0]);
127 event_close(&events[1]); 134 event_close(&events[1]);
@@ -129,6 +136,11 @@ static int count_instructions(void)
129 return 0; 136 return 0;
130} 137}
131 138
139static int count_instructions(void)
140{
141 return eat_cpu(test_body);
142}
143
132int main(void) 144int main(void)
133{ 145{
134 return test_harness(count_instructions, "count_instructions"); 146 return test_harness(count_instructions, "count_instructions");
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/Makefile b/tools/testing/selftests/powerpc/pmu/ebb/Makefile
index edbba2affc2c..3dc4332698cb 100644
--- a/tools/testing/selftests/powerpc/pmu/ebb/Makefile
+++ b/tools/testing/selftests/powerpc/pmu/ebb/Makefile
@@ -13,11 +13,12 @@ PROGS := reg_access_test event_attributes_test cycles_test \
13 close_clears_pmcc_test instruction_count_test \ 13 close_clears_pmcc_test instruction_count_test \
14 fork_cleanup_test ebb_on_child_test \ 14 fork_cleanup_test ebb_on_child_test \
15 ebb_on_willing_child_test back_to_back_ebbs_test \ 15 ebb_on_willing_child_test back_to_back_ebbs_test \
16 lost_exception_test no_handler_test 16 lost_exception_test no_handler_test \
17 cycles_with_mmcr2_test
17 18
18all: $(PROGS) 19all: $(PROGS)
19 20
20$(PROGS): ../../harness.c ../event.c ../lib.c ebb.c ebb_handler.S trace.c 21$(PROGS): ../../harness.c ../event.c ../lib.c ebb.c ebb_handler.S trace.c busy_loop.S
21 22
22instruction_count_test: ../loop.S 23instruction_count_test: ../loop.S
23 24
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/busy_loop.S b/tools/testing/selftests/powerpc/pmu/ebb/busy_loop.S
new file mode 100644
index 000000000000..c7e4093f1cd3
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/busy_loop.S
@@ -0,0 +1,271 @@
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(core_busy_loop)
11 stdu %r1, -168(%r1)
12 std r14, 160(%r1)
13 std r15, 152(%r1)
14 std r16, 144(%r1)
15 std r17, 136(%r1)
16 std r18, 128(%r1)
17 std r19, 120(%r1)
18 std r20, 112(%r1)
19 std r21, 104(%r1)
20 std r22, 96(%r1)
21 std r23, 88(%r1)
22 std r24, 80(%r1)
23 std r25, 72(%r1)
24 std r26, 64(%r1)
25 std r27, 56(%r1)
26 std r28, 48(%r1)
27 std r29, 40(%r1)
28 std r30, 32(%r1)
29 std r31, 24(%r1)
30
31 li r3, 0x3030
32 std r3, -96(%r1)
33 li r4, 0x4040
34 std r4, -104(%r1)
35 li r5, 0x5050
36 std r5, -112(%r1)
37 li r6, 0x6060
38 std r6, -120(%r1)
39 li r7, 0x7070
40 std r7, -128(%r1)
41 li r8, 0x0808
42 std r8, -136(%r1)
43 li r9, 0x0909
44 std r9, -144(%r1)
45 li r10, 0x1010
46 std r10, -152(%r1)
47 li r11, 0x1111
48 std r11, -160(%r1)
49 li r14, 0x1414
50 std r14, -168(%r1)
51 li r15, 0x1515
52 std r15, -176(%r1)
53 li r16, 0x1616
54 std r16, -184(%r1)
55 li r17, 0x1717
56 std r17, -192(%r1)
57 li r18, 0x1818
58 std r18, -200(%r1)
59 li r19, 0x1919
60 std r19, -208(%r1)
61 li r20, 0x2020
62 std r20, -216(%r1)
63 li r21, 0x2121
64 std r21, -224(%r1)
65 li r22, 0x2222
66 std r22, -232(%r1)
67 li r23, 0x2323
68 std r23, -240(%r1)
69 li r24, 0x2424
70 std r24, -248(%r1)
71 li r25, 0x2525
72 std r25, -256(%r1)
73 li r26, 0x2626
74 std r26, -264(%r1)
75 li r27, 0x2727
76 std r27, -272(%r1)
77 li r28, 0x2828
78 std r28, -280(%r1)
79 li r29, 0x2929
80 std r29, -288(%r1)
81 li r30, 0x3030
82 li r31, 0x3131
83
84 li r3, 0
850: addi r3, r3, 1
86 cmpwi r3, 100
87 blt 0b
88
89 /* Return 1 (fail) unless we get through all the checks */
90 li r3, 1
91
92 /* Check none of our registers have been corrupted */
93 cmpwi r4, 0x4040
94 bne 1f
95 cmpwi r5, 0x5050
96 bne 1f
97 cmpwi r6, 0x6060
98 bne 1f
99 cmpwi r7, 0x7070
100 bne 1f
101 cmpwi r8, 0x0808
102 bne 1f
103 cmpwi r9, 0x0909
104 bne 1f
105 cmpwi r10, 0x1010
106 bne 1f
107 cmpwi r11, 0x1111
108 bne 1f
109 cmpwi r14, 0x1414
110 bne 1f
111 cmpwi r15, 0x1515
112 bne 1f
113 cmpwi r16, 0x1616
114 bne 1f
115 cmpwi r17, 0x1717
116 bne 1f
117 cmpwi r18, 0x1818
118 bne 1f
119 cmpwi r19, 0x1919
120 bne 1f
121 cmpwi r20, 0x2020
122 bne 1f
123 cmpwi r21, 0x2121
124 bne 1f
125 cmpwi r22, 0x2222
126 bne 1f
127 cmpwi r23, 0x2323
128 bne 1f
129 cmpwi r24, 0x2424
130 bne 1f
131 cmpwi r25, 0x2525
132 bne 1f
133 cmpwi r26, 0x2626
134 bne 1f
135 cmpwi r27, 0x2727
136 bne 1f
137 cmpwi r28, 0x2828
138 bne 1f
139 cmpwi r29, 0x2929
140 bne 1f
141 cmpwi r30, 0x3030
142 bne 1f
143 cmpwi r31, 0x3131
144 bne 1f
145
146 /* Load junk into all our registers before we reload them from the stack. */
147 li r3, 0xde
148 li r4, 0xad
149 li r5, 0xbe
150 li r6, 0xef
151 li r7, 0xde
152 li r8, 0xad
153 li r9, 0xbe
154 li r10, 0xef
155 li r11, 0xde
156 li r14, 0xad
157 li r15, 0xbe
158 li r16, 0xef
159 li r17, 0xde
160 li r18, 0xad
161 li r19, 0xbe
162 li r20, 0xef
163 li r21, 0xde
164 li r22, 0xad
165 li r23, 0xbe
166 li r24, 0xef
167 li r25, 0xde
168 li r26, 0xad
169 li r27, 0xbe
170 li r28, 0xef
171 li r29, 0xdd
172
173 ld r3, -96(%r1)
174 cmpwi r3, 0x3030
175 bne 1f
176 ld r4, -104(%r1)
177 cmpwi r4, 0x4040
178 bne 1f
179 ld r5, -112(%r1)
180 cmpwi r5, 0x5050
181 bne 1f
182 ld r6, -120(%r1)
183 cmpwi r6, 0x6060
184 bne 1f
185 ld r7, -128(%r1)
186 cmpwi r7, 0x7070
187 bne 1f
188 ld r8, -136(%r1)
189 cmpwi r8, 0x0808
190 bne 1f
191 ld r9, -144(%r1)
192 cmpwi r9, 0x0909
193 bne 1f
194 ld r10, -152(%r1)
195 cmpwi r10, 0x1010
196 bne 1f
197 ld r11, -160(%r1)
198 cmpwi r11, 0x1111
199 bne 1f
200 ld r14, -168(%r1)
201 cmpwi r14, 0x1414
202 bne 1f
203 ld r15, -176(%r1)
204 cmpwi r15, 0x1515
205 bne 1f
206 ld r16, -184(%r1)
207 cmpwi r16, 0x1616
208 bne 1f
209 ld r17, -192(%r1)
210 cmpwi r17, 0x1717
211 bne 1f
212 ld r18, -200(%r1)
213 cmpwi r18, 0x1818
214 bne 1f
215 ld r19, -208(%r1)
216 cmpwi r19, 0x1919
217 bne 1f
218 ld r20, -216(%r1)
219 cmpwi r20, 0x2020
220 bne 1f
221 ld r21, -224(%r1)
222 cmpwi r21, 0x2121
223 bne 1f
224 ld r22, -232(%r1)
225 cmpwi r22, 0x2222
226 bne 1f
227 ld r23, -240(%r1)
228 cmpwi r23, 0x2323
229 bne 1f
230 ld r24, -248(%r1)
231 cmpwi r24, 0x2424
232 bne 1f
233 ld r25, -256(%r1)
234 cmpwi r25, 0x2525
235 bne 1f
236 ld r26, -264(%r1)
237 cmpwi r26, 0x2626
238 bne 1f
239 ld r27, -272(%r1)
240 cmpwi r27, 0x2727
241 bne 1f
242 ld r28, -280(%r1)
243 cmpwi r28, 0x2828
244 bne 1f
245 ld r29, -288(%r1)
246 cmpwi r29, 0x2929
247 bne 1f
248
249 /* Load 0 (success) to return */
250 li r3, 0
251
2521: ld r14, 160(%r1)
253 ld r15, 152(%r1)
254 ld r16, 144(%r1)
255 ld r17, 136(%r1)
256 ld r18, 128(%r1)
257 ld r19, 120(%r1)
258 ld r20, 112(%r1)
259 ld r21, 104(%r1)
260 ld r22, 96(%r1)
261 ld r23, 88(%r1)
262 ld r24, 80(%r1)
263 ld r25, 72(%r1)
264 ld r26, 64(%r1)
265 ld r27, 56(%r1)
266 ld r28, 48(%r1)
267 ld r29, 40(%r1)
268 ld r30, 32(%r1)
269 ld r31, 24(%r1)
270 addi %r1, %r1, 168
271 blr
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/cycles_with_mmcr2_test.c b/tools/testing/selftests/powerpc/pmu/ebb/cycles_with_mmcr2_test.c
new file mode 100644
index 000000000000..d43029b0800c
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/cycles_with_mmcr2_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 <stdbool.h>
9
10#include "ebb.h"
11
12
13/*
14 * Test of counting cycles while manipulating the user accessible bits in MMCR2.
15 */
16
17/* We use two values because the first freezes PMC1 and so we would get no EBBs */
18#define MMCR2_EXPECTED_1 0x4020100804020000UL /* (FC1P|FC2P|FC3P|FC4P|FC5P|FC6P) */
19#define MMCR2_EXPECTED_2 0x0020100804020000UL /* ( FC2P|FC3P|FC4P|FC5P|FC6P) */
20
21
22int cycles_with_mmcr2(void)
23{
24 struct event event;
25 uint64_t val, expected[2], actual;
26 int i;
27 bool bad_mmcr2;
28
29 event_init_named(&event, 0x1001e, "cycles");
30 event_leader_ebb_init(&event);
31
32 event.attr.exclude_kernel = 1;
33 event.attr.exclude_hv = 1;
34 event.attr.exclude_idle = 1;
35
36 FAIL_IF(event_open(&event));
37
38 ebb_enable_pmc_counting(1);
39 setup_ebb_handler(standard_ebb_callee);
40 ebb_global_enable();
41
42 FAIL_IF(ebb_event_enable(&event));
43
44 mtspr(SPRN_PMC1, pmc_sample_period(sample_period));
45
46 /* XXX Set of MMCR2 must be after enable */
47 expected[0] = MMCR2_EXPECTED_1;
48 expected[1] = MMCR2_EXPECTED_2;
49 i = 0;
50 bad_mmcr2 = false;
51
52 /* Make sure we loop until we take at least one EBB */
53 while ((ebb_state.stats.ebb_count < 20 && !bad_mmcr2) ||
54 ebb_state.stats.ebb_count < 1)
55 {
56 mtspr(SPRN_MMCR2, expected[i % 2]);
57
58 FAIL_IF(core_busy_loop());
59
60 val = mfspr(SPRN_MMCR2);
61 if (val != expected[i % 2]) {
62 bad_mmcr2 = true;
63 actual = val;
64 }
65
66 i++;
67 }
68
69 ebb_global_disable();
70 ebb_freeze_pmcs();
71
72 count_pmc(1, sample_period);
73
74 dump_ebb_state();
75
76 event_close(&event);
77
78 FAIL_IF(ebb_state.stats.ebb_count == 0);
79
80 if (bad_mmcr2)
81 printf("Bad MMCR2 value seen is 0x%lx\n", actual);
82
83 FAIL_IF(bad_mmcr2);
84
85 return 0;
86}
87
88int main(void)
89{
90 return test_harness(cycles_with_mmcr2, "cycles_with_mmcr2");
91}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/ebb.c b/tools/testing/selftests/powerpc/pmu/ebb/ebb.c
index 1b46be94b64c..d7a72ce696b5 100644
--- a/tools/testing/selftests/powerpc/pmu/ebb/ebb.c
+++ b/tools/testing/selftests/powerpc/pmu/ebb/ebb.c
@@ -224,6 +224,7 @@ void dump_ebb_hw_state(void)
224 224
225 printf("HW state:\n" \ 225 printf("HW state:\n" \
226 "MMCR0 0x%016x %s\n" \ 226 "MMCR0 0x%016x %s\n" \
227 "MMCR2 0x%016lx\n" \
227 "EBBHR 0x%016lx\n" \ 228 "EBBHR 0x%016lx\n" \
228 "BESCR 0x%016llx %s\n" \ 229 "BESCR 0x%016llx %s\n" \
229 "PMC1 0x%016lx\n" \ 230 "PMC1 0x%016lx\n" \
@@ -233,10 +234,11 @@ void dump_ebb_hw_state(void)
233 "PMC5 0x%016lx\n" \ 234 "PMC5 0x%016lx\n" \
234 "PMC6 0x%016lx\n" \ 235 "PMC6 0x%016lx\n" \
235 "SIAR 0x%016lx\n", 236 "SIAR 0x%016lx\n",
236 mmcr0, decode_mmcr0(mmcr0), mfspr(SPRN_EBBHR), bescr, 237 mmcr0, decode_mmcr0(mmcr0), mfspr(SPRN_MMCR2),
237 decode_bescr(bescr), mfspr(SPRN_PMC1), mfspr(SPRN_PMC2), 238 mfspr(SPRN_EBBHR), bescr, decode_bescr(bescr),
238 mfspr(SPRN_PMC3), mfspr(SPRN_PMC4), mfspr(SPRN_PMC5), 239 mfspr(SPRN_PMC1), mfspr(SPRN_PMC2), mfspr(SPRN_PMC3),
239 mfspr(SPRN_PMC6), mfspr(SPRN_SIAR)); 240 mfspr(SPRN_PMC4), mfspr(SPRN_PMC5), mfspr(SPRN_PMC6),
241 mfspr(SPRN_SIAR));
240} 242}
241 243
242void dump_ebb_state(void) 244void dump_ebb_state(void)
@@ -335,257 +337,6 @@ void event_leader_ebb_init(struct event *e)
335 e->attr.pinned = 1; 337 e->attr.pinned = 1;
336} 338}
337 339
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) 340int ebb_child(union pipe read_pipe, union pipe write_pipe)
590{ 341{
591 struct event event; 342 struct event event;
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/ebb.h b/tools/testing/selftests/powerpc/pmu/ebb/ebb.h
index e62bde05bf78..e44eee5d97ca 100644
--- a/tools/testing/selftests/powerpc/pmu/ebb/ebb.h
+++ b/tools/testing/selftests/powerpc/pmu/ebb/ebb.h
@@ -70,7 +70,6 @@ int ebb_check_mmcr0(void);
70extern u64 sample_period; 70extern u64 sample_period;
71 71
72int core_busy_loop(void); 72int core_busy_loop(void);
73int core_busy_loop_with_freeze(void);
74int ebb_child(union pipe read_pipe, union pipe write_pipe); 73int ebb_child(union pipe read_pipe, union pipe write_pipe);
75int catch_sigill(void (*func)(void)); 74int catch_sigill(void (*func)(void));
76void write_pmc1(void); 75void write_pmc1(void);
diff --git a/tools/testing/selftests/powerpc/pmu/l3_bank_test.c b/tools/testing/selftests/powerpc/pmu/l3_bank_test.c
new file mode 100644
index 000000000000..77472f31441e
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/l3_bank_test.c
@@ -0,0 +1,48 @@
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 "event.h"
10#include "utils.h"
11
12#define MALLOC_SIZE (0x10000 * 10) /* Ought to be enough .. */
13
14/*
15 * Tests that the L3 bank handling is correct. We fixed it in commit e9aaac1.
16 */
17static int l3_bank_test(void)
18{
19 struct event event;
20 char *p;
21 int i;
22
23 p = malloc(MALLOC_SIZE);
24 FAIL_IF(!p);
25
26 event_init(&event, 0x84918F);
27
28 FAIL_IF(event_open(&event));
29
30 for (i = 0; i < MALLOC_SIZE; i += 0x10000)
31 p[i] = i;
32
33 event_read(&event);
34 event_report(&event);
35
36 FAIL_IF(event.result.running == 0);
37 FAIL_IF(event.result.enabled == 0);
38
39 event_close(&event);
40 free(p);
41
42 return 0;
43}
44
45int main(void)
46{
47 return test_harness(l3_bank_test, "l3_bank_test");
48}
diff --git a/tools/testing/selftests/powerpc/pmu/lib.c b/tools/testing/selftests/powerpc/pmu/lib.c
index 0f6a4731d546..9768dea37bf3 100644
--- a/tools/testing/selftests/powerpc/pmu/lib.c
+++ b/tools/testing/selftests/powerpc/pmu/lib.c
@@ -5,10 +5,15 @@
5 5
6#define _GNU_SOURCE /* For CPU_ZERO etc. */ 6#define _GNU_SOURCE /* For CPU_ZERO etc. */
7 7
8#include <elf.h>
8#include <errno.h> 9#include <errno.h>
10#include <fcntl.h>
11#include <link.h>
9#include <sched.h> 12#include <sched.h>
10#include <setjmp.h> 13#include <setjmp.h>
11#include <stdlib.h> 14#include <stdlib.h>
15#include <sys/stat.h>
16#include <sys/types.h>
12#include <sys/wait.h> 17#include <sys/wait.h>
13 18
14#include "utils.h" 19#include "utils.h"
@@ -177,8 +182,8 @@ struct addr_range libc, vdso;
177 182
178int parse_proc_maps(void) 183int parse_proc_maps(void)
179{ 184{
185 unsigned long start, end;
180 char execute, name[128]; 186 char execute, name[128];
181 uint64_t start, end;
182 FILE *f; 187 FILE *f;
183 int rc; 188 int rc;
184 189
@@ -250,3 +255,46 @@ out_close:
250out: 255out:
251 return rc; 256 return rc;
252} 257}
258
259static char auxv[4096];
260
261void *get_auxv_entry(int type)
262{
263 ElfW(auxv_t) *p;
264 void *result;
265 ssize_t num;
266 int fd;
267
268 fd = open("/proc/self/auxv", O_RDONLY);
269 if (fd == -1) {
270 perror("open");
271 return NULL;
272 }
273
274 result = NULL;
275
276 num = read(fd, auxv, sizeof(auxv));
277 if (num < 0) {
278 perror("read");
279 goto out;
280 }
281
282 if (num > sizeof(auxv)) {
283 printf("Overflowed auxv buffer\n");
284 goto out;
285 }
286
287 p = (ElfW(auxv_t) *)auxv;
288
289 while (p->a_type != AT_NULL) {
290 if (p->a_type == type) {
291 result = (void *)p->a_un.a_val;
292 break;
293 }
294
295 p++;
296 }
297out:
298 close(fd);
299 return result;
300}
diff --git a/tools/testing/selftests/powerpc/pmu/lib.h b/tools/testing/selftests/powerpc/pmu/lib.h
index ca5d72ae3be6..0f0339c8a6f6 100644
--- a/tools/testing/selftests/powerpc/pmu/lib.h
+++ b/tools/testing/selftests/powerpc/pmu/lib.h
@@ -29,6 +29,7 @@ extern int notify_parent(union pipe write_pipe);
29extern int notify_parent_of_error(union pipe write_pipe); 29extern int notify_parent_of_error(union pipe write_pipe);
30extern pid_t eat_cpu(int (test_function)(void)); 30extern pid_t eat_cpu(int (test_function)(void));
31extern bool require_paranoia_below(int level); 31extern bool require_paranoia_below(int level);
32extern void *get_auxv_entry(int type);
32 33
33struct addr_range { 34struct addr_range {
34 uint64_t first, last; 35 uint64_t first, last;
diff --git a/tools/testing/selftests/powerpc/pmu/per_event_excludes.c b/tools/testing/selftests/powerpc/pmu/per_event_excludes.c
new file mode 100644
index 000000000000..fddbbc9cae2f
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/per_event_excludes.c
@@ -0,0 +1,114 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#define _GNU_SOURCE
7
8#include <elf.h>
9#include <limits.h>
10#include <stdio.h>
11#include <stdbool.h>
12#include <string.h>
13#include <sys/prctl.h>
14
15#include "event.h"
16#include "lib.h"
17#include "utils.h"
18
19/*
20 * Test that per-event excludes work.
21 */
22
23static int per_event_excludes(void)
24{
25 struct event *e, events[4];
26 char *platform;
27 int i;
28
29 platform = (char *)get_auxv_entry(AT_BASE_PLATFORM);
30 FAIL_IF(!platform);
31 SKIP_IF(strcmp(platform, "power8") != 0);
32
33 /*
34 * We need to create the events disabled, otherwise the running/enabled
35 * counts don't match up.
36 */
37 e = &events[0];
38 event_init_opts(e, PERF_COUNT_HW_INSTRUCTIONS,
39 PERF_TYPE_HARDWARE, "instructions");
40 e->attr.disabled = 1;
41
42 e = &events[1];
43 event_init_opts(e, PERF_COUNT_HW_INSTRUCTIONS,
44 PERF_TYPE_HARDWARE, "instructions(k)");
45 e->attr.disabled = 1;
46 e->attr.exclude_user = 1;
47 e->attr.exclude_hv = 1;
48
49 e = &events[2];
50 event_init_opts(e, PERF_COUNT_HW_INSTRUCTIONS,
51 PERF_TYPE_HARDWARE, "instructions(h)");
52 e->attr.disabled = 1;
53 e->attr.exclude_user = 1;
54 e->attr.exclude_kernel = 1;
55
56 e = &events[3];
57 event_init_opts(e, PERF_COUNT_HW_INSTRUCTIONS,
58 PERF_TYPE_HARDWARE, "instructions(u)");
59 e->attr.disabled = 1;
60 e->attr.exclude_hv = 1;
61 e->attr.exclude_kernel = 1;
62
63 FAIL_IF(event_open(&events[0]));
64
65 /*
66 * The open here will fail if we don't have per event exclude support,
67 * because the second event has an incompatible set of exclude settings
68 * and we're asking for the events to be in a group.
69 */
70 for (i = 1; i < 4; i++)
71 FAIL_IF(event_open_with_group(&events[i], events[0].fd));
72
73 /*
74 * Even though the above will fail without per-event excludes we keep
75 * testing in order to be thorough.
76 */
77 prctl(PR_TASK_PERF_EVENTS_ENABLE);
78
79 /* Spin for a while */
80 for (i = 0; i < INT_MAX; i++)
81 asm volatile("" : : : "memory");
82
83 prctl(PR_TASK_PERF_EVENTS_DISABLE);
84
85 for (i = 0; i < 4; i++) {
86 FAIL_IF(event_read(&events[i]));
87 event_report(&events[i]);
88 }
89
90 /*
91 * We should see that all events have enabled == running. That
92 * shows that they were all on the PMU at once.
93 */
94 for (i = 0; i < 4; i++)
95 FAIL_IF(events[i].result.running != events[i].result.enabled);
96
97 /*
98 * We can also check that the result for instructions is >= all the
99 * other counts. That's because it is counting all instructions while
100 * the others are counting a subset.
101 */
102 for (i = 1; i < 4; i++)
103 FAIL_IF(events[0].result.value < events[i].result.value);
104
105 for (i = 0; i < 4; i++)
106 event_close(&events[i]);
107
108 return 0;
109}
110
111int main(void)
112{
113 return test_harness(per_event_excludes, "per_event_excludes");
114}
diff --git a/tools/testing/selftests/ptrace/peeksiginfo.c b/tools/testing/selftests/ptrace/peeksiginfo.c
index d46558b1f58d..c34cd8ac8aaa 100644
--- a/tools/testing/selftests/ptrace/peeksiginfo.c
+++ b/tools/testing/selftests/ptrace/peeksiginfo.c
@@ -31,6 +31,10 @@ static int sys_ptrace(int request, pid_t pid, void *addr, void *data)
31#define TEST_SICODE_PRIV -1 31#define TEST_SICODE_PRIV -1
32#define TEST_SICODE_SHARE -2 32#define TEST_SICODE_SHARE -2
33 33
34#ifndef PAGE_SIZE
35#define PAGE_SIZE sysconf(_SC_PAGESIZE)
36#endif
37
34#define err(fmt, ...) \ 38#define err(fmt, ...) \
35 fprintf(stderr, \ 39 fprintf(stderr, \
36 "Error (%s:%d): " fmt, \ 40 "Error (%s:%d): " fmt, \
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh b/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh
index ee1f6cae3d70..3f6c9b78d177 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh
@@ -54,10 +54,16 @@ do
54 if test -f "$i/qemu-cmd" 54 if test -f "$i/qemu-cmd"
55 then 55 then
56 print_bug qemu failed 56 print_bug qemu failed
57 echo " $i"
58 elif test -f "$i/buildonly"
59 then
60 echo Build-only run, no boot/test
61 configcheck.sh $i/.config $i/ConfigFragment
62 parse-build.sh $i/Make.out $configfile
57 else 63 else
58 print_bug Build failed 64 print_bug Build failed
65 echo " $i"
59 fi 66 fi
60 echo " $i"
61 fi 67 fi
62 done 68 done
63done 69done
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 27e544e29510..0f69dcbf9def 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh
@@ -42,6 +42,7 @@ grace=120
42 42
43T=/tmp/kvm-test-1-run.sh.$$ 43T=/tmp/kvm-test-1-run.sh.$$
44trap 'rm -rf $T' 0 44trap 'rm -rf $T' 0
45touch $T
45 46
46. $KVM/bin/functions.sh 47. $KVM/bin/functions.sh
47. $KVPATH/ver_functions.sh 48. $KVPATH/ver_functions.sh
@@ -131,7 +132,10 @@ boot_args=$6
131 132
132cd $KVM 133cd $KVM
133kstarttime=`awk 'BEGIN { print systime() }' < /dev/null` 134kstarttime=`awk 'BEGIN { print systime() }' < /dev/null`
134echo ' ---' `date`: Starting kernel 135if test -z "$TORTURE_BUILDONLY"
136then
137 echo ' ---' `date`: Starting kernel
138fi
135 139
136# Generate -smp qemu argument. 140# Generate -smp qemu argument.
137qemu_args="-nographic $qemu_args" 141qemu_args="-nographic $qemu_args"
@@ -157,12 +161,13 @@ boot_args="`configfrag_boot_params "$boot_args" "$config_template"`"
157# Generate kernel-version-specific boot parameters 161# Generate kernel-version-specific boot parameters
158boot_args="`per_version_boot_params "$boot_args" $builddir/.config $seconds`" 162boot_args="`per_version_boot_params "$boot_args" $builddir/.config $seconds`"
159 163
160echo $QEMU $qemu_args -m 512 -kernel $builddir/$BOOT_IMAGE -append \"$qemu_append $boot_args\" > $resdir/qemu-cmd
161if test -n "$TORTURE_BUILDONLY" 164if test -n "$TORTURE_BUILDONLY"
162then 165then
163 echo Build-only run specified, boot/test omitted. 166 echo Build-only run specified, boot/test omitted.
167 touch $resdir/buildonly
164 exit 0 168 exit 0
165fi 169fi
170echo $QEMU $qemu_args -m 512 -kernel $builddir/$BOOT_IMAGE -append \"$qemu_append $boot_args\" > $resdir/qemu-cmd
166( $QEMU $qemu_args -m 512 -kernel $builddir/$BOOT_IMAGE -append "$qemu_append $boot_args"; echo $? > $resdir/qemu-retval ) & 171( $QEMU $qemu_args -m 512 -kernel $builddir/$BOOT_IMAGE -append "$qemu_append $boot_args"; echo $? > $resdir/qemu-retval ) &
167qemu_pid=$! 172qemu_pid=$!
168commandcompleted=0 173commandcompleted=0
diff --git a/tools/testing/selftests/rcutorture/bin/kvm.sh b/tools/testing/selftests/rcutorture/bin/kvm.sh
index 40285c58653e..589e9c38413b 100644
--- a/tools/testing/selftests/rcutorture/bin/kvm.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm.sh
@@ -340,12 +340,18 @@ function dump(first, pastlast)
340 for (j = 1; j < jn; j++) { 340 for (j = 1; j < jn; j++) {
341 builddir=KVM "/b" j 341 builddir=KVM "/b" j
342 print "rm -f " builddir ".ready" 342 print "rm -f " builddir ".ready"
343 print "echo ----", cfr[j], cpusr[j] ovf ": Starting kernel. `date`"; 343 print "if test -z \"$TORTURE_BUILDONLY\""
344 print "echo ----", cfr[j], cpusr[j] ovf ": Starting kernel. `date` >> " rd "/log"; 344 print "then"
345 print "\techo ----", cfr[j], cpusr[j] ovf ": Starting kernel. `date`";
346 print "\techo ----", cfr[j], cpusr[j] ovf ": Starting kernel. `date` >> " rd "/log";
347 print "fi"
345 } 348 }
346 print "wait" 349 print "wait"
347 print "echo ---- All kernel runs complete. `date`"; 350 print "if test -z \"$TORTURE_BUILDONLY\""
348 print "echo ---- All kernel runs complete. `date` >> " rd "/log"; 351 print "then"
352 print "\techo ---- All kernel runs complete. `date`";
353 print "\techo ---- All kernel runs complete. `date` >> " rd "/log";
354 print "fi"
349 for (j = 1; j < jn; j++) { 355 for (j = 1; j < jn; j++) {
350 builddir=KVM "/b" j 356 builddir=KVM "/b" j
351 print "echo ----", cfr[j], cpusr[j] ovf ": Build/run results:"; 357 print "echo ----", cfr[j], cpusr[j] ovf ": Build/run results:";
@@ -385,10 +391,7 @@ echo
385echo 391echo
386echo " --- `date` Test summary:" 392echo " --- `date` Test summary:"
387echo Results directory: $resdir/$ds 393echo Results directory: $resdir/$ds
388if test -z "$TORTURE_BUILDONLY" 394kvm-recheck.sh $resdir/$ds
389then
390 kvm-recheck.sh $resdir/$ds
391fi
392___EOF___ 395___EOF___
393 396
394if test "$dryrun" = script 397if test "$dryrun" = script
@@ -403,7 +406,7 @@ then
403 sed -e 's/:.*$//' -e 's/^echo //' 406 sed -e 's/:.*$//' -e 's/^echo //'
404 exit 0 407 exit 0
405else 408else
406 # Not a dryru, so run the script. 409 # Not a dryrun, so run the script.
407 sh $T/script 410 sh $T/script
408fi 411fi
409 412
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE01 b/tools/testing/selftests/rcutorture/configs/rcu/TREE01
index 9c827ec59a97..063b7079c621 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE01
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE01
@@ -15,7 +15,6 @@ CONFIG_RCU_FANOUT_EXACT=n
15CONFIG_RCU_NOCB_CPU=y 15CONFIG_RCU_NOCB_CPU=y
16CONFIG_RCU_NOCB_CPU_ZERO=y 16CONFIG_RCU_NOCB_CPU_ZERO=y
17CONFIG_DEBUG_LOCK_ALLOC=n 17CONFIG_DEBUG_LOCK_ALLOC=n
18CONFIG_PROVE_RCU_DELAY=n
19CONFIG_RCU_CPU_STALL_INFO=n 18CONFIG_RCU_CPU_STALL_INFO=n
20CONFIG_RCU_CPU_STALL_VERBOSE=n 19CONFIG_RCU_CPU_STALL_VERBOSE=n
21CONFIG_RCU_BOOST=n 20CONFIG_RCU_BOOST=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE02 b/tools/testing/selftests/rcutorture/configs/rcu/TREE02
index 1a777b5f68b5..ea119ba2f7d4 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE02
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE02
@@ -18,7 +18,6 @@ CONFIG_RCU_FANOUT_EXACT=n
18CONFIG_RCU_NOCB_CPU=n 18CONFIG_RCU_NOCB_CPU=n
19CONFIG_DEBUG_LOCK_ALLOC=y 19CONFIG_DEBUG_LOCK_ALLOC=y
20CONFIG_PROVE_LOCKING=n 20CONFIG_PROVE_LOCKING=n
21CONFIG_PROVE_RCU_DELAY=n
22CONFIG_RCU_CPU_STALL_INFO=n 21CONFIG_RCU_CPU_STALL_INFO=n
23CONFIG_RCU_CPU_STALL_VERBOSE=y 22CONFIG_RCU_CPU_STALL_VERBOSE=y
24CONFIG_RCU_BOOST=n 23CONFIG_RCU_BOOST=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE02-T b/tools/testing/selftests/rcutorture/configs/rcu/TREE02-T
index 61c8d9ce5bb2..19cf9485f48a 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE02-T
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE02-T
@@ -18,7 +18,6 @@ CONFIG_RCU_FANOUT_EXACT=n
18CONFIG_RCU_NOCB_CPU=n 18CONFIG_RCU_NOCB_CPU=n
19CONFIG_DEBUG_LOCK_ALLOC=y 19CONFIG_DEBUG_LOCK_ALLOC=y
20CONFIG_PROVE_LOCKING=n 20CONFIG_PROVE_LOCKING=n
21CONFIG_PROVE_RCU_DELAY=n
22CONFIG_RCU_CPU_STALL_INFO=n 21CONFIG_RCU_CPU_STALL_INFO=n
23CONFIG_RCU_CPU_STALL_VERBOSE=y 22CONFIG_RCU_CPU_STALL_VERBOSE=y
24CONFIG_RCU_BOOST=n 23CONFIG_RCU_BOOST=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE03 b/tools/testing/selftests/rcutorture/configs/rcu/TREE03
index c1f111c1561b..f4567fb3e332 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE03
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE03
@@ -14,7 +14,6 @@ CONFIG_RCU_FANOUT_LEAF=4
14CONFIG_RCU_FANOUT_EXACT=n 14CONFIG_RCU_FANOUT_EXACT=n
15CONFIG_RCU_NOCB_CPU=n 15CONFIG_RCU_NOCB_CPU=n
16CONFIG_DEBUG_LOCK_ALLOC=n 16CONFIG_DEBUG_LOCK_ALLOC=n
17CONFIG_PROVE_RCU_DELAY=n
18CONFIG_RCU_CPU_STALL_INFO=n 17CONFIG_RCU_CPU_STALL_INFO=n
19CONFIG_RCU_CPU_STALL_VERBOSE=n 18CONFIG_RCU_CPU_STALL_VERBOSE=n
20CONFIG_RCU_BOOST=y 19CONFIG_RCU_BOOST=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE04 b/tools/testing/selftests/rcutorture/configs/rcu/TREE04
index 7dbd27ce17a4..0a262fbb0c12 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE04
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE04
@@ -18,7 +18,6 @@ CONFIG_RCU_FANOUT_LEAF=2
18CONFIG_RCU_FANOUT_EXACT=n 18CONFIG_RCU_FANOUT_EXACT=n
19CONFIG_RCU_NOCB_CPU=n 19CONFIG_RCU_NOCB_CPU=n
20CONFIG_DEBUG_LOCK_ALLOC=n 20CONFIG_DEBUG_LOCK_ALLOC=n
21CONFIG_PROVE_RCU_DELAY=n
22CONFIG_RCU_CPU_STALL_INFO=y 21CONFIG_RCU_CPU_STALL_INFO=y
23CONFIG_RCU_CPU_STALL_VERBOSE=y 22CONFIG_RCU_CPU_STALL_VERBOSE=y
24CONFIG_DEBUG_OBJECTS_RCU_HEAD=n 23CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE05 b/tools/testing/selftests/rcutorture/configs/rcu/TREE05
index d0f32e574743..3a06b97e9a73 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE05
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE05
@@ -18,7 +18,6 @@ CONFIG_RCU_NOCB_CPU_NONE=y
18CONFIG_DEBUG_LOCK_ALLOC=y 18CONFIG_DEBUG_LOCK_ALLOC=y
19CONFIG_PROVE_LOCKING=y 19CONFIG_PROVE_LOCKING=y
20CONFIG_PROVE_RCU=y 20CONFIG_PROVE_RCU=y
21CONFIG_PROVE_RCU_DELAY=y
22CONFIG_RCU_CPU_STALL_INFO=n 21CONFIG_RCU_CPU_STALL_INFO=n
23CONFIG_RCU_CPU_STALL_VERBOSE=n 22CONFIG_RCU_CPU_STALL_VERBOSE=n
24CONFIG_DEBUG_OBJECTS_RCU_HEAD=n 23CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE06 b/tools/testing/selftests/rcutorture/configs/rcu/TREE06
index 2e477dfb9c57..8f084cca91bf 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE06
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE06
@@ -19,7 +19,6 @@ CONFIG_RCU_NOCB_CPU=n
19CONFIG_DEBUG_LOCK_ALLOC=y 19CONFIG_DEBUG_LOCK_ALLOC=y
20CONFIG_PROVE_LOCKING=y 20CONFIG_PROVE_LOCKING=y
21CONFIG_PROVE_RCU=y 21CONFIG_PROVE_RCU=y
22CONFIG_PROVE_RCU_DELAY=n
23CONFIG_RCU_CPU_STALL_INFO=n 22CONFIG_RCU_CPU_STALL_INFO=n
24CONFIG_RCU_CPU_STALL_VERBOSE=n 23CONFIG_RCU_CPU_STALL_VERBOSE=n
25CONFIG_DEBUG_OBJECTS_RCU_HEAD=y 24CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE07 b/tools/testing/selftests/rcutorture/configs/rcu/TREE07
index 042f86ef362a..ab6225506909 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE07
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE07
@@ -17,7 +17,6 @@ CONFIG_RCU_FANOUT_LEAF=2
17CONFIG_RCU_FANOUT_EXACT=n 17CONFIG_RCU_FANOUT_EXACT=n
18CONFIG_RCU_NOCB_CPU=n 18CONFIG_RCU_NOCB_CPU=n
19CONFIG_DEBUG_LOCK_ALLOC=n 19CONFIG_DEBUG_LOCK_ALLOC=n
20CONFIG_PROVE_RCU_DELAY=n
21CONFIG_RCU_CPU_STALL_INFO=y 20CONFIG_RCU_CPU_STALL_INFO=y
22CONFIG_RCU_CPU_STALL_VERBOSE=n 21CONFIG_RCU_CPU_STALL_VERBOSE=n
23CONFIG_DEBUG_OBJECTS_RCU_HEAD=n 22CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE08 b/tools/testing/selftests/rcutorture/configs/rcu/TREE08
index 3438cee1e3c5..69a2e255bf98 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE08
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE08
@@ -18,7 +18,6 @@ CONFIG_RCU_FANOUT_LEAF=2
18CONFIG_RCU_NOCB_CPU=y 18CONFIG_RCU_NOCB_CPU=y
19CONFIG_RCU_NOCB_CPU_ALL=y 19CONFIG_RCU_NOCB_CPU_ALL=y
20CONFIG_DEBUG_LOCK_ALLOC=n 20CONFIG_DEBUG_LOCK_ALLOC=n
21CONFIG_PROVE_RCU_DELAY=n
22CONFIG_RCU_CPU_STALL_INFO=n 21CONFIG_RCU_CPU_STALL_INFO=n
23CONFIG_RCU_CPU_STALL_VERBOSE=n 22CONFIG_RCU_CPU_STALL_VERBOSE=n
24CONFIG_RCU_BOOST=n 23CONFIG_RCU_BOOST=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE08-T b/tools/testing/selftests/rcutorture/configs/rcu/TREE08-T
index bf4523d3e44c..a0f32fb8f17e 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE08-T
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE08-T
@@ -18,7 +18,6 @@ CONFIG_RCU_FANOUT_LEAF=2
18CONFIG_RCU_NOCB_CPU=y 18CONFIG_RCU_NOCB_CPU=y
19CONFIG_RCU_NOCB_CPU_ALL=y 19CONFIG_RCU_NOCB_CPU_ALL=y
20CONFIG_DEBUG_LOCK_ALLOC=n 20CONFIG_DEBUG_LOCK_ALLOC=n
21CONFIG_PROVE_RCU_DELAY=n
22CONFIG_RCU_CPU_STALL_INFO=n 21CONFIG_RCU_CPU_STALL_INFO=n
23CONFIG_RCU_CPU_STALL_VERBOSE=n 22CONFIG_RCU_CPU_STALL_VERBOSE=n
24CONFIG_RCU_BOOST=n 23CONFIG_RCU_BOOST=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE09 b/tools/testing/selftests/rcutorture/configs/rcu/TREE09
index 81e4f7c0bf0b..b7a62a540ad1 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE09
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE09
@@ -13,7 +13,6 @@ CONFIG_SUSPEND=n
13CONFIG_HIBERNATION=n 13CONFIG_HIBERNATION=n
14CONFIG_RCU_NOCB_CPU=n 14CONFIG_RCU_NOCB_CPU=n
15CONFIG_DEBUG_LOCK_ALLOC=n 15CONFIG_DEBUG_LOCK_ALLOC=n
16CONFIG_PROVE_RCU_DELAY=n
17CONFIG_RCU_CPU_STALL_INFO=n 16CONFIG_RCU_CPU_STALL_INFO=n
18CONFIG_RCU_CPU_STALL_VERBOSE=n 17CONFIG_RCU_CPU_STALL_VERBOSE=n
19CONFIG_RCU_BOOST=n 18CONFIG_RCU_BOOST=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P5-U-T-NH-sd-SMP-hp
index ef624ce73d8e..a55c00877fe4 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P5-U-T-NH-sd-SMP-hp
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P5-U-T-NH-sd-SMP-hp
@@ -13,7 +13,6 @@ CONFIG_PREEMPT_VOLUNTARY=n
13CONFIG_PREEMPT=y 13CONFIG_PREEMPT=y
14#CHECK#CONFIG_TREE_PREEMPT_RCU=y 14#CHECK#CONFIG_TREE_PREEMPT_RCU=y
15CONFIG_DEBUG_KERNEL=y 15CONFIG_DEBUG_KERNEL=y
16CONFIG_PROVE_RCU_DELAY=y
17CONFIG_DEBUG_OBJECTS=y 16CONFIG_DEBUG_OBJECTS=y
18CONFIG_DEBUG_OBJECTS_RCU_HEAD=y 17CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
19CONFIG_RT_MUTEXES=y 18CONFIG_RT_MUTEXES=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P5-U-T-NH-sd-SMP-hp
index ef624ce73d8e..a55c00877fe4 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P5-U-T-NH-sd-SMP-hp
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P5-U-T-NH-sd-SMP-hp
@@ -13,7 +13,6 @@ CONFIG_PREEMPT_VOLUNTARY=n
13CONFIG_PREEMPT=y 13CONFIG_PREEMPT=y
14#CHECK#CONFIG_TREE_PREEMPT_RCU=y 14#CHECK#CONFIG_TREE_PREEMPT_RCU=y
15CONFIG_DEBUG_KERNEL=y 15CONFIG_DEBUG_KERNEL=y
16CONFIG_PROVE_RCU_DELAY=y
17CONFIG_DEBUG_OBJECTS=y 16CONFIG_DEBUG_OBJECTS=y
18CONFIG_DEBUG_OBJECTS_RCU_HEAD=y 17CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
19CONFIG_RT_MUTEXES=y 18CONFIG_RT_MUTEXES=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P5-U-T-NH-sd-SMP-hp
index ef624ce73d8e..a55c00877fe4 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P5-U-T-NH-sd-SMP-hp
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P5-U-T-NH-sd-SMP-hp
@@ -13,7 +13,6 @@ CONFIG_PREEMPT_VOLUNTARY=n
13CONFIG_PREEMPT=y 13CONFIG_PREEMPT=y
14#CHECK#CONFIG_TREE_PREEMPT_RCU=y 14#CHECK#CONFIG_TREE_PREEMPT_RCU=y
15CONFIG_DEBUG_KERNEL=y 15CONFIG_DEBUG_KERNEL=y
16CONFIG_PROVE_RCU_DELAY=y
17CONFIG_DEBUG_OBJECTS=y 16CONFIG_DEBUG_OBJECTS=y
18CONFIG_DEBUG_OBJECTS_RCU_HEAD=y 17CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
19CONFIG_RT_MUTEXES=y 18CONFIG_RT_MUTEXES=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P5-U-T-NH-sd-SMP-hp
index ef624ce73d8e..a55c00877fe4 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P5-U-T-NH-sd-SMP-hp
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P5-U-T-NH-sd-SMP-hp
@@ -13,7 +13,6 @@ CONFIG_PREEMPT_VOLUNTARY=n
13CONFIG_PREEMPT=y 13CONFIG_PREEMPT=y
14#CHECK#CONFIG_TREE_PREEMPT_RCU=y 14#CHECK#CONFIG_TREE_PREEMPT_RCU=y
15CONFIG_DEBUG_KERNEL=y 15CONFIG_DEBUG_KERNEL=y
16CONFIG_PROVE_RCU_DELAY=y
17CONFIG_DEBUG_OBJECTS=y 16CONFIG_DEBUG_OBJECTS=y
18CONFIG_DEBUG_OBJECTS_RCU_HEAD=y 17CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
19CONFIG_RT_MUTEXES=y 18CONFIG_RT_MUTEXES=y
diff --git a/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt b/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt
index adbb76cffb49..3e588db86a17 100644
--- a/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt
+++ b/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt
@@ -14,7 +14,6 @@ CONFIG_NO_HZ_FULL_SYSIDLE -- Do one.
14CONFIG_PREEMPT -- Do half. (First three and #8.) 14CONFIG_PREEMPT -- Do half. (First three and #8.)
15CONFIG_PROVE_LOCKING -- Do all but two, covering CONFIG_PROVE_RCU and not. 15CONFIG_PROVE_LOCKING -- Do all but two, covering CONFIG_PROVE_RCU and not.
16CONFIG_PROVE_RCU -- Do all but one under CONFIG_PROVE_LOCKING. 16CONFIG_PROVE_RCU -- Do all but one under CONFIG_PROVE_LOCKING.
17CONFIG_PROVE_RCU_DELAY -- Do one.
18CONFIG_RCU_BOOST -- one of TREE_PREEMPT_RCU. 17CONFIG_RCU_BOOST -- one of TREE_PREEMPT_RCU.
19CONFIG_RCU_BOOST_PRIO -- set to 2 for _BOOST testing. 18CONFIG_RCU_BOOST_PRIO -- set to 2 for _BOOST testing.
20CONFIG_RCU_CPU_STALL_INFO -- do one with and without _VERBOSE. 19CONFIG_RCU_CPU_STALL_INFO -- do one with and without _VERBOSE.
diff --git a/tools/time/udelay_test.sh b/tools/time/udelay_test.sh
new file mode 100755
index 000000000000..12d46b926917
--- /dev/null
+++ b/tools/time/udelay_test.sh
@@ -0,0 +1,66 @@
1#!/bin/bash
2
3# udelay() test script
4#
5# Test is executed by writing and reading to /sys/kernel/debug/udelay_test
6# and exercises a variety of delays to ensure that udelay() is delaying
7# at least as long as requested (as compared to ktime).
8#
9# Copyright (C) 2014 Google, Inc.
10#
11# This software is licensed under the terms of the GNU General Public
12# License version 2, as published by the Free Software Foundation, and
13# may be copied, distributed, and modified under those terms.
14#
15# This program is distributed in the hope that it will be useful,
16# but WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18# GNU General Public License for more details.
19
20MODULE_NAME=udelay_test
21UDELAY_PATH=/sys/kernel/debug/udelay_test
22
23setup()
24{
25 /sbin/modprobe -q $MODULE_NAME
26 tmp_file=`mktemp`
27}
28
29test_one()
30{
31 delay=$1
32 echo $delay > $UDELAY_PATH
33 tee -a $tmp_file < $UDELAY_PATH
34}
35
36cleanup()
37{
38 if [ -f $tmp_file ]; then
39 rm $tmp_file
40 fi
41 /sbin/modprobe -q -r $MODULE_NAME
42}
43
44trap cleanup EXIT
45setup
46
47# Delay for a variety of times.
48# 1..200, 200..500 (by 10), 500..2000 (by 100)
49for (( delay = 1; delay < 200; delay += 1 )); do
50 test_one $delay
51done
52for (( delay = 200; delay < 500; delay += 10 )); do
53 test_one $delay
54done
55for (( delay = 500; delay <= 2000; delay += 100 )); do
56 test_one $delay
57done
58
59# Search for failures
60count=`grep -c FAIL $tmp_file`
61if [ $? -eq "0" ]; then
62 echo "ERROR: $count delays failed to delay long enough"
63 retcode=1
64fi
65
66exit $retcode
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
index 87216a0c4a8b..af4b0508be77 100644
--- a/tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c
+++ b/tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c
@@ -1,3 +1,30 @@
1/*
2 * This is free and unencumbered software released into the public domain.
3 *
4 * Anyone is free to copy, modify, publish, use, compile, sell, or
5 * distribute this software, either in source code form or as a compiled
6 * binary, for any purpose, commercial or non-commercial, and by any
7 * means.
8 *
9 * In jurisdictions that recognize copyright laws, the author or authors
10 * of this software dedicate any and all copyright interest in the
11 * software to the public domain. We make this dedication for the benefit
12 * of the public at large and to the detriment of our heirs and
13 * successors. We intend this dedication to be an overt act of
14 * relinquishment in perpetuity of all present and future rights to this
15 * software under copyright law.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 * OTHER DEALINGS IN THE SOFTWARE.
24 *
25 * For more information, please refer to <http://unlicense.org/>
26 */
27
1#define _BSD_SOURCE /* for endian.h */ 28#define _BSD_SOURCE /* for endian.h */
2 29
3#include <endian.h> 30#include <endian.h>
@@ -27,7 +54,9 @@
27/******************** Descriptors and Strings *******************************/ 54/******************** Descriptors and Strings *******************************/
28 55
29static const struct { 56static const struct {
30 struct usb_functionfs_descs_head header; 57 struct usb_functionfs_descs_head_v2 header;
58 __le32 fs_count;
59 __le32 hs_count;
31 struct { 60 struct {
32 struct usb_interface_descriptor intf; 61 struct usb_interface_descriptor intf;
33 struct usb_endpoint_descriptor_no_audio bulk_sink; 62 struct usb_endpoint_descriptor_no_audio bulk_sink;
@@ -35,11 +64,12 @@ static const struct {
35 } __attribute__ ((__packed__)) fs_descs, hs_descs; 64 } __attribute__ ((__packed__)) fs_descs, hs_descs;
36} __attribute__ ((__packed__)) descriptors = { 65} __attribute__ ((__packed__)) descriptors = {
37 .header = { 66 .header = {
38 .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC), 67 .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
68 .flags = htole32(FUNCTIONFS_HAS_FS_DESC |
69 FUNCTIONFS_HAS_HS_DESC),
39 .length = htole32(sizeof(descriptors)), 70 .length = htole32(sizeof(descriptors)),
40 .fs_count = 3,
41 .hs_count = 3,
42 }, 71 },
72 .fs_count = htole32(3),
43 .fs_descs = { 73 .fs_descs = {
44 .intf = { 74 .intf = {
45 .bLength = sizeof(descriptors.fs_descs.intf), 75 .bLength = sizeof(descriptors.fs_descs.intf),
@@ -61,6 +91,7 @@ static const struct {
61 .bmAttributes = USB_ENDPOINT_XFER_BULK, 91 .bmAttributes = USB_ENDPOINT_XFER_BULK,
62 }, 92 },
63 }, 93 },
94 .hs_count = htole32(3),
64 .hs_descs = { 95 .hs_descs = {
65 .intf = { 96 .intf = {
66 .bLength = sizeof(descriptors.hs_descs.intf), 97 .bLength = sizeof(descriptors.hs_descs.intf),
diff --git a/tools/usb/ffs-aio-example/multibuff/host_app/test.c b/tools/usb/ffs-aio-example/multibuff/host_app/test.c
index b0ad8747d03f..daa3abe6bebd 100644
--- a/tools/usb/ffs-aio-example/multibuff/host_app/test.c
+++ b/tools/usb/ffs-aio-example/multibuff/host_app/test.c
@@ -1,3 +1,30 @@
1/*
2 * This is free and unencumbered software released into the public domain.
3 *
4 * Anyone is free to copy, modify, publish, use, compile, sell, or
5 * distribute this software, either in source code form or as a compiled
6 * binary, for any purpose, commercial or non-commercial, and by any
7 * means.
8 *
9 * In jurisdictions that recognize copyright laws, the author or authors
10 * of this software dedicate any and all copyright interest in the
11 * software to the public domain. We make this dedication for the benefit
12 * of the public at large and to the detriment of our heirs and
13 * successors. We intend this dedication to be an overt act of
14 * relinquishment in perpetuity of all present and future rights to this
15 * software under copyright law.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 * OTHER DEALINGS IN THE SOFTWARE.
24 *
25 * For more information, please refer to <http://unlicense.org/>
26 */
27
1#include <libusb.h> 28#include <libusb.h>
2#include <stdio.h> 29#include <stdio.h>
3#include <string.h> 30#include <string.h>
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
index f558664a3317..adc310a6d489 100644
--- a/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c
+++ b/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c
@@ -1,3 +1,30 @@
1/*
2 * This is free and unencumbered software released into the public domain.
3 *
4 * Anyone is free to copy, modify, publish, use, compile, sell, or
5 * distribute this software, either in source code form or as a compiled
6 * binary, for any purpose, commercial or non-commercial, and by any
7 * means.
8 *
9 * In jurisdictions that recognize copyright laws, the author or authors
10 * of this software dedicate any and all copyright interest in the
11 * software to the public domain. We make this dedication for the benefit
12 * of the public at large and to the detriment of our heirs and
13 * successors. We intend this dedication to be an overt act of
14 * relinquishment in perpetuity of all present and future rights to this
15 * software under copyright law.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 * OTHER DEALINGS IN THE SOFTWARE.
24 *
25 * For more information, please refer to <http://unlicense.org/>
26 */
27
1#define _BSD_SOURCE /* for endian.h */ 28#define _BSD_SOURCE /* for endian.h */
2 29
3#include <endian.h> 30#include <endian.h>
@@ -25,7 +52,9 @@
25/******************** Descriptors and Strings *******************************/ 52/******************** Descriptors and Strings *******************************/
26 53
27static const struct { 54static const struct {
28 struct usb_functionfs_descs_head header; 55 struct usb_functionfs_descs_head_v2 header;
56 __le32 fs_count;
57 __le32 hs_count;
29 struct { 58 struct {
30 struct usb_interface_descriptor intf; 59 struct usb_interface_descriptor intf;
31 struct usb_endpoint_descriptor_no_audio bulk_sink; 60 struct usb_endpoint_descriptor_no_audio bulk_sink;
@@ -33,11 +62,12 @@ static const struct {
33 } __attribute__ ((__packed__)) fs_descs, hs_descs; 62 } __attribute__ ((__packed__)) fs_descs, hs_descs;
34} __attribute__ ((__packed__)) descriptors = { 63} __attribute__ ((__packed__)) descriptors = {
35 .header = { 64 .header = {
36 .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC), 65 .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
66 .flags = htole32(FUNCTIONFS_HAS_FS_DESC |
67 FUNCTIONFS_HAS_HS_DESC),
37 .length = htole32(sizeof(descriptors)), 68 .length = htole32(sizeof(descriptors)),
38 .fs_count = 3,
39 .hs_count = 3,
40 }, 69 },
70 .fs_count = htole32(3),
41 .fs_descs = { 71 .fs_descs = {
42 .intf = { 72 .intf = {
43 .bLength = sizeof(descriptors.fs_descs.intf), 73 .bLength = sizeof(descriptors.fs_descs.intf),
@@ -59,6 +89,7 @@ static const struct {
59 .bmAttributes = USB_ENDPOINT_XFER_BULK, 89 .bmAttributes = USB_ENDPOINT_XFER_BULK,
60 }, 90 },
61 }, 91 },
92 .hs_count = htole32(3),
62 .hs_descs = { 93 .hs_descs = {
63 .intf = { 94 .intf = {
64 .bLength = sizeof(descriptors.hs_descs.intf), 95 .bLength = sizeof(descriptors.hs_descs.intf),
diff --git a/tools/usb/ffs-aio-example/simple/host_app/test.c b/tools/usb/ffs-aio-example/simple/host_app/test.c
index 64b6a57d8ca3..acd6332811f3 100644
--- a/tools/usb/ffs-aio-example/simple/host_app/test.c
+++ b/tools/usb/ffs-aio-example/simple/host_app/test.c
@@ -1,3 +1,30 @@
1/*
2 * This is free and unencumbered software released into the public domain.
3 *
4 * Anyone is free to copy, modify, publish, use, compile, sell, or
5 * distribute this software, either in source code form or as a compiled
6 * binary, for any purpose, commercial or non-commercial, and by any
7 * means.
8 *
9 * In jurisdictions that recognize copyright laws, the author or authors
10 * of this software dedicate any and all copyright interest in the
11 * software to the public domain. We make this dedication for the benefit
12 * of the public at large and to the detriment of our heirs and
13 * successors. We intend this dedication to be an overt act of
14 * relinquishment in perpetuity of all present and future rights to this
15 * software under copyright law.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 * OTHER DEALINGS IN THE SOFTWARE.
24 *
25 * For more information, please refer to <http://unlicense.org/>
26 */
27
1#include <libusb.h> 28#include <libusb.h>
2#include <stdio.h> 29#include <stdio.h>
3#include <string.h> 30#include <string.h>